llm-party-cli 0.9.0 → 0.10.1
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/README.md +37 -7
- package/dist/index.js +770 -330
- package/package.json +2 -3
- package/prompts/artifacts.md +49 -93
- package/prompts/base.md +80 -209
- package/prompts/obsidian.md +30 -102
package/dist/index.js
CHANGED
|
@@ -3284,7 +3284,7 @@ var require_main = __commonJS((exports) => {
|
|
|
3284
3284
|
});
|
|
3285
3285
|
|
|
3286
3286
|
// src/index.ts
|
|
3287
|
-
import { readFile as
|
|
3287
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
3288
3288
|
import path11 from "path";
|
|
3289
3289
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3290
3290
|
|
|
@@ -36264,43 +36264,6 @@ function Show(props) {
|
|
|
36264
36264
|
return props.fallback;
|
|
36265
36265
|
}, undefined, undefined);
|
|
36266
36266
|
}
|
|
36267
|
-
function Switch(props) {
|
|
36268
|
-
const chs = children(() => props.children);
|
|
36269
|
-
const switchFunc = createMemo(() => {
|
|
36270
|
-
const ch = chs();
|
|
36271
|
-
const mps = Array.isArray(ch) ? ch : [ch];
|
|
36272
|
-
let func = () => {
|
|
36273
|
-
return;
|
|
36274
|
-
};
|
|
36275
|
-
for (let i = 0;i < mps.length; i++) {
|
|
36276
|
-
const index = i;
|
|
36277
|
-
const mp = mps[i];
|
|
36278
|
-
const prevFunc = func;
|
|
36279
|
-
const conditionValue = createMemo(() => prevFunc() ? undefined : mp.when, undefined, undefined);
|
|
36280
|
-
const condition = mp.keyed ? conditionValue : createMemo(conditionValue, undefined, {
|
|
36281
|
-
equals: (a, b2) => !a === !b2
|
|
36282
|
-
});
|
|
36283
|
-
func = () => prevFunc() || (condition() ? [index, conditionValue, mp] : undefined);
|
|
36284
|
-
}
|
|
36285
|
-
return func;
|
|
36286
|
-
});
|
|
36287
|
-
return createMemo(() => {
|
|
36288
|
-
const sel = switchFunc()();
|
|
36289
|
-
if (!sel)
|
|
36290
|
-
return props.fallback;
|
|
36291
|
-
const [index, conditionValue, mp] = sel;
|
|
36292
|
-
const child = mp.children;
|
|
36293
|
-
const fn = typeof child === "function" && child.length > 0;
|
|
36294
|
-
return fn ? untrack(() => child(mp.keyed ? conditionValue() : () => {
|
|
36295
|
-
if (untrack(switchFunc)()?.[0] !== index)
|
|
36296
|
-
throw narrowedError("Match");
|
|
36297
|
-
return conditionValue();
|
|
36298
|
-
})) : child;
|
|
36299
|
-
}, undefined, undefined);
|
|
36300
|
-
}
|
|
36301
|
-
function Match(props) {
|
|
36302
|
-
return props;
|
|
36303
|
-
}
|
|
36304
36267
|
|
|
36305
36268
|
// node_modules/entities/dist/esm/decode-codepoint.js
|
|
36306
36269
|
var _a;
|
|
@@ -37595,13 +37558,8 @@ class ClaudeBaseAdapter {
|
|
|
37595
37558
|
}
|
|
37596
37559
|
return { ...process.env, ...mapped, ...configEnv };
|
|
37597
37560
|
}
|
|
37598
|
-
async
|
|
37599
|
-
|
|
37600
|
-
}
|
|
37601
|
-
async destroy() {
|
|
37602
|
-
return;
|
|
37603
|
-
}
|
|
37604
|
-
async querySDK(transcript, signal) {
|
|
37561
|
+
async* stream(messages, signal) {
|
|
37562
|
+
const transcript = formatTranscript(messages, this.name, this.humanName);
|
|
37605
37563
|
const executableOpt = this.claudeExecutable ? { pathToClaudeCodeExecutable: this.claudeExecutable } : {};
|
|
37606
37564
|
const options = {
|
|
37607
37565
|
cwd: process.cwd(),
|
|
@@ -37615,24 +37573,69 @@ class ClaudeBaseAdapter {
|
|
|
37615
37573
|
...this.sessionId ? { resume: this.sessionId } : {},
|
|
37616
37574
|
...executableOpt
|
|
37617
37575
|
};
|
|
37576
|
+
yield { type: "activity", activity: "thinking" };
|
|
37618
37577
|
try {
|
|
37619
37578
|
for await (const message of query({ prompt: transcript, options })) {
|
|
37620
37579
|
if (signal?.aborted) {
|
|
37621
|
-
|
|
37580
|
+
yield { type: "error", message: `[Aborted] ${this.name} was cancelled` };
|
|
37581
|
+
return;
|
|
37622
37582
|
}
|
|
37623
|
-
if (message
|
|
37583
|
+
if (!message || typeof message !== "object")
|
|
37584
|
+
continue;
|
|
37585
|
+
if ("type" in message && "subtype" in message && "session_id" in message && message.type === "system" && message.subtype === "init" && typeof message.session_id === "string") {
|
|
37624
37586
|
this.sessionId = message.session_id;
|
|
37625
37587
|
}
|
|
37626
|
-
if (message &&
|
|
37588
|
+
if ("type" in message && message.type === "assistant" && "message" in message) {
|
|
37589
|
+
const msg = message.message;
|
|
37590
|
+
const blocks = msg?.content;
|
|
37591
|
+
if (Array.isArray(blocks)) {
|
|
37592
|
+
for (const block of blocks) {
|
|
37593
|
+
if (block.type === "tool_use" && block.name) {
|
|
37594
|
+
const toolName = String(block.name).toLowerCase();
|
|
37595
|
+
if (toolName === "read" || toolName === "glob") {
|
|
37596
|
+
yield { type: "activity", activity: "reading", detail: block.name };
|
|
37597
|
+
} else if (toolName === "write" || toolName === "edit") {
|
|
37598
|
+
yield { type: "activity", activity: "writing", detail: block.name };
|
|
37599
|
+
} else if (toolName === "bash") {
|
|
37600
|
+
yield { type: "activity", activity: "running", detail: "shell" };
|
|
37601
|
+
} else if (toolName === "grep" || toolName === "search" || toolName === "websearch") {
|
|
37602
|
+
yield { type: "activity", activity: "searching", detail: block.name };
|
|
37603
|
+
} else {
|
|
37604
|
+
yield { type: "activity", activity: "thinking", detail: block.name };
|
|
37605
|
+
}
|
|
37606
|
+
} else if (block.type === "thinking") {
|
|
37607
|
+
yield { type: "activity", activity: "thinking" };
|
|
37608
|
+
}
|
|
37609
|
+
}
|
|
37610
|
+
}
|
|
37611
|
+
}
|
|
37612
|
+
if ("type" in message && message.type === "user") {
|
|
37613
|
+
yield { type: "activity", activity: "thinking" };
|
|
37614
|
+
}
|
|
37615
|
+
if ("result" in message) {
|
|
37627
37616
|
const result = message.result;
|
|
37628
|
-
|
|
37617
|
+
const text = typeof result === "string" && result.length > 0 ? result : `[No text response from ${this.name}]`;
|
|
37618
|
+
yield { type: "activity", activity: "idle" };
|
|
37619
|
+
yield { type: "response", text };
|
|
37620
|
+
return;
|
|
37629
37621
|
}
|
|
37630
37622
|
}
|
|
37631
37623
|
} catch (err) {
|
|
37632
37624
|
console.log(`[${this.name}] SDK error:`, err);
|
|
37633
|
-
|
|
37625
|
+
yield { type: "error", message: err instanceof Error ? err.message : String(err) };
|
|
37626
|
+
return;
|
|
37634
37627
|
}
|
|
37635
|
-
|
|
37628
|
+
yield { type: "activity", activity: "idle" };
|
|
37629
|
+
yield { type: "response", text: `[No text response from ${this.name}]` };
|
|
37630
|
+
}
|
|
37631
|
+
async destroy() {
|
|
37632
|
+
return;
|
|
37633
|
+
}
|
|
37634
|
+
getSdkSessionId() {
|
|
37635
|
+
return this.sessionId;
|
|
37636
|
+
}
|
|
37637
|
+
setSdkSessionId(id) {
|
|
37638
|
+
this.sessionId = id;
|
|
37636
37639
|
}
|
|
37637
37640
|
}
|
|
37638
37641
|
|
|
@@ -38082,6 +38085,8 @@ class CodexAdapter {
|
|
|
38082
38085
|
humanName;
|
|
38083
38086
|
codex;
|
|
38084
38087
|
thread;
|
|
38088
|
+
threadId = "";
|
|
38089
|
+
threadOptions = {};
|
|
38085
38090
|
constructor(name, model, humanName) {
|
|
38086
38091
|
this.name = name;
|
|
38087
38092
|
this.model = model;
|
|
@@ -38095,31 +38100,84 @@ class CodexAdapter {
|
|
|
38095
38100
|
...config.env?.OPENAI_API_KEY ? { apiKey: config.env.OPENAI_API_KEY } : {},
|
|
38096
38101
|
...systemPrompt ? { config: { developer_instructions: systemPrompt } } : {}
|
|
38097
38102
|
});
|
|
38098
|
-
this.
|
|
38103
|
+
this.threadOptions = {
|
|
38099
38104
|
model: this.model,
|
|
38100
38105
|
sandboxMode: "danger-full-access",
|
|
38101
38106
|
workingDirectory: process.cwd(),
|
|
38102
38107
|
approvalPolicy: "never",
|
|
38103
38108
|
skipGitRepoCheck: true
|
|
38104
|
-
}
|
|
38109
|
+
};
|
|
38110
|
+
if (this.threadId) {
|
|
38111
|
+
try {
|
|
38112
|
+
this.thread = this.codex.resumeThread(this.threadId, this.threadOptions);
|
|
38113
|
+
return;
|
|
38114
|
+
} catch (err) {
|
|
38115
|
+
console.error(`[${this.name}] resumeThread failed, starting fresh:`, err);
|
|
38116
|
+
this.threadId = "";
|
|
38117
|
+
}
|
|
38118
|
+
}
|
|
38119
|
+
this.thread = this.codex.startThread(this.threadOptions);
|
|
38120
|
+
this.threadId = this.thread.id ?? "";
|
|
38105
38121
|
}
|
|
38106
|
-
async
|
|
38122
|
+
async* stream(messages, signal) {
|
|
38107
38123
|
if (!this.thread) {
|
|
38108
|
-
|
|
38124
|
+
yield { type: "error", message: "[Codex thread not initialized]" };
|
|
38125
|
+
return;
|
|
38109
38126
|
}
|
|
38110
38127
|
if (signal?.aborted) {
|
|
38111
|
-
|
|
38128
|
+
yield { type: "error", message: "[Aborted] Codex was cancelled" };
|
|
38129
|
+
return;
|
|
38112
38130
|
}
|
|
38113
|
-
|
|
38114
|
-
|
|
38115
|
-
|
|
38131
|
+
yield { type: "activity", activity: "thinking" };
|
|
38132
|
+
try {
|
|
38133
|
+
const result = await this.thread.runStreamed(formatTranscript(messages, this.name, this.humanName));
|
|
38134
|
+
let lastAgentMessage = "";
|
|
38135
|
+
for await (const event of result.events) {
|
|
38136
|
+
if (signal?.aborted) {
|
|
38137
|
+
yield { type: "error", message: "[Aborted] Codex was cancelled" };
|
|
38138
|
+
return;
|
|
38139
|
+
}
|
|
38140
|
+
if (event.type === "item.started" || event.type === "item.updated") {
|
|
38141
|
+
const item = event.item;
|
|
38142
|
+
if (item.type === "command_execution") {
|
|
38143
|
+
yield { type: "activity", activity: "running", detail: item.command };
|
|
38144
|
+
} else if (item.type === "file_change") {
|
|
38145
|
+
yield { type: "activity", activity: "writing", detail: "file changes" };
|
|
38146
|
+
} else if (item.type === "reasoning") {
|
|
38147
|
+
yield { type: "activity", activity: "thinking", detail: "reasoning" };
|
|
38148
|
+
} else if (item.type === "web_search") {
|
|
38149
|
+
yield { type: "activity", activity: "searching", detail: item.query };
|
|
38150
|
+
} else if (item.type === "mcp_tool_call") {
|
|
38151
|
+
yield { type: "activity", activity: "running", detail: `${item.server}:${item.tool}` };
|
|
38152
|
+
}
|
|
38153
|
+
}
|
|
38154
|
+
if (event.type === "item.completed") {
|
|
38155
|
+
const item = event.item;
|
|
38156
|
+
if (item.type === "agent_message" && typeof item.text === "string") {
|
|
38157
|
+
lastAgentMessage = item.text;
|
|
38158
|
+
}
|
|
38159
|
+
}
|
|
38160
|
+
}
|
|
38161
|
+
const text = lastAgentMessage.length > 0 ? lastAgentMessage : `[No text response from ${this.name}]`;
|
|
38162
|
+
if (!this.threadId && this.thread?.id) {
|
|
38163
|
+
this.threadId = this.thread.id;
|
|
38164
|
+
}
|
|
38165
|
+
yield { type: "activity", activity: "idle" };
|
|
38166
|
+
yield { type: "response", text };
|
|
38167
|
+
} catch (err) {
|
|
38168
|
+
yield { type: "error", message: err instanceof Error ? err.message : String(err) };
|
|
38116
38169
|
}
|
|
38117
|
-
return "[No text response from Codex]";
|
|
38118
38170
|
}
|
|
38119
38171
|
async destroy() {
|
|
38120
38172
|
this.thread = undefined;
|
|
38121
38173
|
this.codex = undefined;
|
|
38122
38174
|
}
|
|
38175
|
+
getSdkSessionId() {
|
|
38176
|
+
return this.threadId;
|
|
38177
|
+
}
|
|
38178
|
+
setSdkSessionId(id) {
|
|
38179
|
+
this.threadId = id;
|
|
38180
|
+
}
|
|
38123
38181
|
}
|
|
38124
38182
|
|
|
38125
38183
|
// node_modules/@github/copilot-sdk/dist/client.js
|
|
@@ -39302,6 +39360,7 @@ class CopilotAdapter {
|
|
|
39302
39360
|
systemPrompt = "";
|
|
39303
39361
|
cliPath;
|
|
39304
39362
|
timeout = 600000;
|
|
39363
|
+
copilotSessionId = "";
|
|
39305
39364
|
constructor(name, model, humanName) {
|
|
39306
39365
|
this.name = name;
|
|
39307
39366
|
this.model = model;
|
|
@@ -39315,64 +39374,180 @@ class CopilotAdapter {
|
|
|
39315
39374
|
}
|
|
39316
39375
|
await this.createSession();
|
|
39317
39376
|
}
|
|
39318
|
-
async
|
|
39377
|
+
async* stream(messages, signal) {
|
|
39319
39378
|
if (!this.session) {
|
|
39320
|
-
|
|
39379
|
+
yield { type: "error", message: "[Copilot session not initialized]" };
|
|
39380
|
+
return;
|
|
39321
39381
|
}
|
|
39322
39382
|
if (signal?.aborted) {
|
|
39323
|
-
|
|
39383
|
+
yield { type: "error", message: "[Aborted] Copilot was cancelled" };
|
|
39384
|
+
return;
|
|
39324
39385
|
}
|
|
39386
|
+
yield { type: "activity", activity: "thinking" };
|
|
39325
39387
|
const transcript = formatTranscript(messages, this.name, this.humanName);
|
|
39388
|
+
const eventQueue = [];
|
|
39389
|
+
let resolve4 = null;
|
|
39390
|
+
let done = false;
|
|
39391
|
+
const push = (event) => {
|
|
39392
|
+
eventQueue.push(event);
|
|
39393
|
+
if (resolve4) {
|
|
39394
|
+
resolve4();
|
|
39395
|
+
resolve4 = null;
|
|
39396
|
+
}
|
|
39397
|
+
};
|
|
39398
|
+
const waitForEvent = () => {
|
|
39399
|
+
if (eventQueue.length > 0 || done)
|
|
39400
|
+
return Promise.resolve();
|
|
39401
|
+
return new Promise((r) => {
|
|
39402
|
+
resolve4 = r;
|
|
39403
|
+
});
|
|
39404
|
+
};
|
|
39405
|
+
const timer = setTimeout(() => {
|
|
39406
|
+
push({ type: "error", message: `[Timeout] ${this.name} exceeded ${Math.floor(this.timeout / 1000)}s` });
|
|
39407
|
+
done = true;
|
|
39408
|
+
}, this.timeout);
|
|
39409
|
+
const unsubscribe = this.session.on((event) => {
|
|
39410
|
+
if (signal?.aborted) {
|
|
39411
|
+
push({ type: "error", message: `[Aborted] ${this.name} was cancelled` });
|
|
39412
|
+
done = true;
|
|
39413
|
+
return;
|
|
39414
|
+
}
|
|
39415
|
+
if (event.type === "tool.execution_start") {
|
|
39416
|
+
const toolName = String(event.data?.toolName ?? "").toLowerCase();
|
|
39417
|
+
if (toolName === "view" || toolName === "read" || toolName === "report_intent") {
|
|
39418
|
+
push({ type: "activity", activity: "reading", detail: event.data?.toolName });
|
|
39419
|
+
} else if (toolName === "create" || toolName === "edit" || toolName === "write") {
|
|
39420
|
+
push({ type: "activity", activity: "writing", detail: event.data?.toolName });
|
|
39421
|
+
} else if (toolName === "run" || toolName === "bash" || toolName === "shell") {
|
|
39422
|
+
push({ type: "activity", activity: "running", detail: event.data?.toolName });
|
|
39423
|
+
} else if (toolName === "search" || toolName === "grep" || toolName === "find") {
|
|
39424
|
+
push({ type: "activity", activity: "searching", detail: event.data?.toolName });
|
|
39425
|
+
} else {
|
|
39426
|
+
push({ type: "activity", activity: "thinking", detail: event.data?.toolName });
|
|
39427
|
+
}
|
|
39428
|
+
}
|
|
39429
|
+
if (event.type === "tool.execution_complete") {
|
|
39430
|
+
push({ type: "activity", activity: "thinking" });
|
|
39431
|
+
}
|
|
39432
|
+
if (event.type === "assistant.turn_start") {
|
|
39433
|
+
push({ type: "activity", activity: "thinking" });
|
|
39434
|
+
}
|
|
39435
|
+
if (event.type === "assistant.message") {
|
|
39436
|
+
const content = event.data?.content;
|
|
39437
|
+
if (typeof content === "string" && content.length > 0) {
|
|
39438
|
+
push({ type: "activity", activity: "idle" });
|
|
39439
|
+
push({ type: "response", text: content });
|
|
39440
|
+
done = true;
|
|
39441
|
+
}
|
|
39442
|
+
}
|
|
39443
|
+
if (event.type === "session.error") {
|
|
39444
|
+
push({ type: "error", message: event.data?.message ?? "Unknown Copilot error" });
|
|
39445
|
+
done = true;
|
|
39446
|
+
}
|
|
39447
|
+
});
|
|
39448
|
+
const sendSession = async () => {
|
|
39449
|
+
try {
|
|
39450
|
+
await this.session.send({ prompt: transcript });
|
|
39451
|
+
} catch (err) {
|
|
39452
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39453
|
+
if (message.includes("Session not found")) {
|
|
39454
|
+
await this.createSession();
|
|
39455
|
+
try {
|
|
39456
|
+
await this.session.send({ prompt: transcript });
|
|
39457
|
+
} catch (retryErr) {
|
|
39458
|
+
push({ type: "error", message: retryErr instanceof Error ? retryErr.message : String(retryErr) });
|
|
39459
|
+
done = true;
|
|
39460
|
+
}
|
|
39461
|
+
} else {
|
|
39462
|
+
push({ type: "error", message });
|
|
39463
|
+
done = true;
|
|
39464
|
+
}
|
|
39465
|
+
}
|
|
39466
|
+
};
|
|
39467
|
+
sendSession();
|
|
39326
39468
|
try {
|
|
39327
|
-
|
|
39328
|
-
|
|
39329
|
-
|
|
39330
|
-
|
|
39331
|
-
|
|
39332
|
-
|
|
39469
|
+
while (!done || eventQueue.length > 0) {
|
|
39470
|
+
await waitForEvent();
|
|
39471
|
+
while (eventQueue.length > 0) {
|
|
39472
|
+
const event = eventQueue.shift();
|
|
39473
|
+
yield event;
|
|
39474
|
+
if (event.type === "response" || event.type === "error") {
|
|
39475
|
+
clearTimeout(timer);
|
|
39476
|
+
unsubscribe?.();
|
|
39477
|
+
return;
|
|
39478
|
+
}
|
|
39479
|
+
}
|
|
39333
39480
|
}
|
|
39334
|
-
|
|
39481
|
+
} finally {
|
|
39482
|
+
clearTimeout(timer);
|
|
39483
|
+
unsubscribe?.();
|
|
39335
39484
|
}
|
|
39485
|
+
yield { type: "activity", activity: "idle" };
|
|
39486
|
+
yield { type: "response", text: `[No text response from ${this.name}]` };
|
|
39336
39487
|
}
|
|
39337
39488
|
async destroy() {
|
|
39338
39489
|
if (this.session) {
|
|
39339
|
-
|
|
39490
|
+
try {
|
|
39491
|
+
await this.session.disconnect();
|
|
39492
|
+
} catch (err) {
|
|
39493
|
+
console.error(`[${this.name}] disconnect:`, err);
|
|
39494
|
+
}
|
|
39340
39495
|
}
|
|
39341
39496
|
if (this.client) {
|
|
39342
|
-
|
|
39497
|
+
try {
|
|
39498
|
+
await this.client.stop();
|
|
39499
|
+
} catch (err) {
|
|
39500
|
+
console.error(`[${this.name}] stop:`, err);
|
|
39501
|
+
}
|
|
39343
39502
|
}
|
|
39344
39503
|
}
|
|
39504
|
+
getSdkSessionId() {
|
|
39505
|
+
return this.copilotSessionId;
|
|
39506
|
+
}
|
|
39507
|
+
setSdkSessionId(id) {
|
|
39508
|
+
this.copilotSessionId = id;
|
|
39509
|
+
}
|
|
39345
39510
|
async createSession() {
|
|
39346
39511
|
if (this.session) {
|
|
39347
39512
|
try {
|
|
39348
39513
|
await this.session.disconnect();
|
|
39349
|
-
} catch {
|
|
39514
|
+
} catch (err) {
|
|
39515
|
+
console.error(`[${this.name}] stale session disconnect:`, err);
|
|
39516
|
+
}
|
|
39350
39517
|
}
|
|
39351
39518
|
if (this.client) {
|
|
39352
39519
|
try {
|
|
39353
39520
|
await this.client.stop();
|
|
39354
|
-
} catch {
|
|
39521
|
+
} catch (err) {
|
|
39522
|
+
console.error(`[${this.name}] stale client stop:`, err);
|
|
39523
|
+
}
|
|
39355
39524
|
}
|
|
39356
39525
|
process.env.NODE_NO_WARNINGS = "1";
|
|
39357
39526
|
this.client = new CopilotClient({
|
|
39358
39527
|
...this.cliPath ? { cliPath: this.cliPath } : {}
|
|
39359
39528
|
});
|
|
39360
39529
|
await this.client.start();
|
|
39530
|
+
if (this.copilotSessionId) {
|
|
39531
|
+
try {
|
|
39532
|
+
this.session = await this.client.resumeSession(this.copilotSessionId, {
|
|
39533
|
+
model: this.model,
|
|
39534
|
+
systemMessage: { content: this.systemPrompt },
|
|
39535
|
+
onPermissionRequest: approveAll
|
|
39536
|
+
});
|
|
39537
|
+
return;
|
|
39538
|
+
} catch (err) {
|
|
39539
|
+
console.error(`[${this.name}] resumeSession failed, creating new:`, err);
|
|
39540
|
+
this.copilotSessionId = "";
|
|
39541
|
+
}
|
|
39542
|
+
}
|
|
39543
|
+
const sessionId = `llm-party-${this.name}-${Date.now()}`;
|
|
39361
39544
|
this.session = await this.client.createSession({
|
|
39545
|
+
sessionId,
|
|
39362
39546
|
model: this.model,
|
|
39363
39547
|
systemMessage: { content: this.systemPrompt },
|
|
39364
39548
|
onPermissionRequest: approveAll
|
|
39365
39549
|
});
|
|
39366
|
-
|
|
39367
|
-
async sendToSession(transcript) {
|
|
39368
|
-
if (!this.session) {
|
|
39369
|
-
return "[Copilot session not initialized]";
|
|
39370
|
-
}
|
|
39371
|
-
const response = await this.session.sendAndWait({ prompt: transcript }, this.timeout);
|
|
39372
|
-
if (response && response.data && typeof response.data.content === "string" && response.data.content.length > 0) {
|
|
39373
|
-
return response.data.content;
|
|
39374
|
-
}
|
|
39375
|
-
return "[No text response from Copilot]";
|
|
39550
|
+
this.copilotSessionId = sessionId;
|
|
39376
39551
|
}
|
|
39377
39552
|
}
|
|
39378
39553
|
|
|
@@ -39629,7 +39804,7 @@ async function loadConfig2(configPath) {
|
|
|
39629
39804
|
}
|
|
39630
39805
|
|
|
39631
39806
|
// src/orchestrator.ts
|
|
39632
|
-
import { appendFile, mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
39807
|
+
import { appendFile, mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
39633
39808
|
import { randomBytes } from "crypto";
|
|
39634
39809
|
import path9 from "path";
|
|
39635
39810
|
|
|
@@ -39654,6 +39829,72 @@ var DEFAULT_REMINDERS = [
|
|
|
39654
39829
|
"Self-memory check: did you receive a correction this session? Write it to your agent file now.",
|
|
39655
39830
|
"Global awareness: if this work affects other projects, write a one-liner to projects.yml history."
|
|
39656
39831
|
];
|
|
39832
|
+
var QUEUE_TTL_MS = 5 * 60 * 1000;
|
|
39833
|
+
var MAX_QUEUE_SIZE = 20;
|
|
39834
|
+
|
|
39835
|
+
class AgentQueueManager {
|
|
39836
|
+
queues = new Map;
|
|
39837
|
+
register(agentName) {
|
|
39838
|
+
this.queues.set(agentName, { processing: false, pending: [] });
|
|
39839
|
+
}
|
|
39840
|
+
enqueue(agentName, message, maxSize = MAX_QUEUE_SIZE) {
|
|
39841
|
+
const queue = this.queues.get(agentName);
|
|
39842
|
+
if (!queue)
|
|
39843
|
+
return false;
|
|
39844
|
+
if (queue.pending.length >= maxSize) {
|
|
39845
|
+
queue.pending.shift();
|
|
39846
|
+
}
|
|
39847
|
+
queue.pending.push(message);
|
|
39848
|
+
return true;
|
|
39849
|
+
}
|
|
39850
|
+
drain(agentName, ttlMs = QUEUE_TTL_MS) {
|
|
39851
|
+
const queue = this.queues.get(agentName);
|
|
39852
|
+
if (!queue)
|
|
39853
|
+
return [];
|
|
39854
|
+
const now = Date.now();
|
|
39855
|
+
const valid = queue.pending.filter((m2) => now - new Date(m2.queuedAt).getTime() < ttlMs);
|
|
39856
|
+
queue.pending = [];
|
|
39857
|
+
return valid;
|
|
39858
|
+
}
|
|
39859
|
+
isProcessing(agentName) {
|
|
39860
|
+
return this.queues.get(agentName)?.processing ?? false;
|
|
39861
|
+
}
|
|
39862
|
+
setProcessing(agentName, value) {
|
|
39863
|
+
const queue = this.queues.get(agentName);
|
|
39864
|
+
if (queue)
|
|
39865
|
+
queue.processing = value;
|
|
39866
|
+
}
|
|
39867
|
+
hasPending(agentName) {
|
|
39868
|
+
return (this.queues.get(agentName)?.pending.length ?? 0) > 0;
|
|
39869
|
+
}
|
|
39870
|
+
pendingCount(agentName) {
|
|
39871
|
+
return this.queues.get(agentName)?.pending.length ?? 0;
|
|
39872
|
+
}
|
|
39873
|
+
get anyProcessing() {
|
|
39874
|
+
for (const q2 of this.queues.values()) {
|
|
39875
|
+
if (q2.processing)
|
|
39876
|
+
return true;
|
|
39877
|
+
}
|
|
39878
|
+
return false;
|
|
39879
|
+
}
|
|
39880
|
+
setController(agentName, controller) {
|
|
39881
|
+
const queue = this.queues.get(agentName);
|
|
39882
|
+
if (queue)
|
|
39883
|
+
queue.controller = controller;
|
|
39884
|
+
}
|
|
39885
|
+
abortAll() {
|
|
39886
|
+
for (const q2 of this.queues.values()) {
|
|
39887
|
+
q2.controller?.abort();
|
|
39888
|
+
q2.pending = [];
|
|
39889
|
+
}
|
|
39890
|
+
}
|
|
39891
|
+
clearAll() {
|
|
39892
|
+
for (const q2 of this.queues.values()) {
|
|
39893
|
+
q2.pending = [];
|
|
39894
|
+
q2.processing = false;
|
|
39895
|
+
}
|
|
39896
|
+
}
|
|
39897
|
+
}
|
|
39657
39898
|
|
|
39658
39899
|
class Orchestrator {
|
|
39659
39900
|
agents;
|
|
@@ -39669,7 +39910,16 @@ class Orchestrator {
|
|
|
39669
39910
|
contextWindowSize;
|
|
39670
39911
|
reminderInterval;
|
|
39671
39912
|
reminderCursors = new Map;
|
|
39913
|
+
maxAutoHops;
|
|
39914
|
+
queueTtlMs;
|
|
39915
|
+
maxQueueSize;
|
|
39672
39916
|
messageId = 0;
|
|
39917
|
+
stickyTargets;
|
|
39918
|
+
queueManager = new AgentQueueManager;
|
|
39919
|
+
manifestSavePromise = Promise.resolve();
|
|
39920
|
+
onMessage = () => {};
|
|
39921
|
+
onActivity = () => {};
|
|
39922
|
+
onSystem = () => {};
|
|
39673
39923
|
constructor(agents, humanName = "USER", agentTags, humanTag, defaultTimeout = 600000, agentTimeouts, options) {
|
|
39674
39924
|
this.agents = new Map(agents.map((agent) => [agent.name, agent]));
|
|
39675
39925
|
this.agentTags = new Map(agents.map((agent) => [agent.name, agentTags?.[agent.name] ?? toTag(agent.name)]));
|
|
@@ -39679,12 +39929,21 @@ class Orchestrator {
|
|
|
39679
39929
|
this.agentTimeouts = new Map(Object.entries(agentTimeouts ?? {}));
|
|
39680
39930
|
this.contextWindowSize = options?.contextWindowSize ?? 16;
|
|
39681
39931
|
this.reminderInterval = options?.reminderInterval ?? 8;
|
|
39932
|
+
this.maxAutoHops = options?.maxAutoHops ?? 15;
|
|
39933
|
+
this.queueTtlMs = options?.queueTtlMs ?? QUEUE_TTL_MS;
|
|
39934
|
+
this.maxQueueSize = options?.maxQueueSize ?? MAX_QUEUE_SIZE;
|
|
39682
39935
|
this.sessionId = createSessionId();
|
|
39683
39936
|
this.transcriptPath = path9.resolve(".llm-party", "sessions", `transcript-${this.sessionId}.jsonl`);
|
|
39684
39937
|
for (const agent of agents) {
|
|
39685
39938
|
this.lastSeenByAgent.set(agent.name, 0);
|
|
39939
|
+
this.queueManager.register(agent.name);
|
|
39686
39940
|
}
|
|
39687
39941
|
}
|
|
39942
|
+
setCallbacks(onMessage, onActivity, onSystem) {
|
|
39943
|
+
this.onMessage = onMessage;
|
|
39944
|
+
this.onActivity = onActivity;
|
|
39945
|
+
this.onSystem = onSystem;
|
|
39946
|
+
}
|
|
39688
39947
|
getSessionId() {
|
|
39689
39948
|
return this.sessionId;
|
|
39690
39949
|
}
|
|
@@ -39697,12 +39956,29 @@ class Orchestrator {
|
|
|
39697
39956
|
getHumanTag() {
|
|
39698
39957
|
return this.humanTag;
|
|
39699
39958
|
}
|
|
39959
|
+
get dispatching() {
|
|
39960
|
+
return this.queueManager.anyProcessing;
|
|
39961
|
+
}
|
|
39962
|
+
getStickyTarget() {
|
|
39963
|
+
return this.stickyTargets;
|
|
39964
|
+
}
|
|
39965
|
+
setStickyTarget(targets) {
|
|
39966
|
+
this.stickyTargets = targets;
|
|
39967
|
+
}
|
|
39968
|
+
getQueueStatus() {
|
|
39969
|
+
return this.listAgents().map((a) => ({
|
|
39970
|
+
name: a.name,
|
|
39971
|
+
processing: this.queueManager.isProcessing(a.name),
|
|
39972
|
+
pending: this.queueManager.pendingCount(a.name)
|
|
39973
|
+
}));
|
|
39974
|
+
}
|
|
39700
39975
|
clearConversation() {
|
|
39701
39976
|
this.conversation.length = 0;
|
|
39702
39977
|
this.messageId = 0;
|
|
39703
39978
|
for (const agent of this.agents.keys()) {
|
|
39704
39979
|
this.lastSeenByAgent.set(agent, 0);
|
|
39705
39980
|
}
|
|
39981
|
+
this.queueManager.clearAll();
|
|
39706
39982
|
this.sessionId = createSessionId();
|
|
39707
39983
|
this.transcriptPath = path9.resolve(".llm-party", "sessions", `transcript-${this.sessionId}.jsonl`);
|
|
39708
39984
|
}
|
|
@@ -39739,62 +40015,158 @@ class Orchestrator {
|
|
|
39739
40015
|
const tag = this.agentTags.get(agent.name) ?? toTag(agent.name);
|
|
39740
40016
|
return agent.name.toLowerCase() === normalized || tag.toLowerCase() === normalized;
|
|
39741
40017
|
}).map((agent) => agent.name);
|
|
39742
|
-
if (byName.length > 0)
|
|
40018
|
+
if (byName.length > 0)
|
|
39743
40019
|
return byName;
|
|
39744
|
-
}
|
|
39745
40020
|
return Array.from(this.agents.values()).filter((agent) => agent.provider.toLowerCase() === normalized).map((agent) => agent.name);
|
|
39746
40021
|
}
|
|
39747
|
-
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
const requestedTargets = targetAgentNames && targetAgentNames.length > 0 ? targetAgentNames : Array.from(this.agents.keys());
|
|
39752
|
-
const targets = requestedTargets.map((name) => this.agents.get(name)).filter((agent) => Boolean(agent));
|
|
39753
|
-
const historyMaxId = this.messageId;
|
|
39754
|
-
const settled = await Promise.allSettled(targets.map(async (agent) => {
|
|
39755
|
-
const lastSeen = this.lastSeenByAgent.get(agent.name) ?? 0;
|
|
39756
|
-
const unseen = this.conversation.filter((msg) => msg.id > lastSeen && msg.from.toUpperCase() !== agent.name.toUpperCase());
|
|
39757
|
-
if (unseen.length === 0) {
|
|
39758
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39759
|
-
return null;
|
|
39760
|
-
}
|
|
39761
|
-
const inputMessages = this.buildInputForAgent(agent.name, unseen);
|
|
39762
|
-
const responseText = await this.sendWithTimeout(agent, inputMessages, this.timeoutFor(agent.name));
|
|
39763
|
-
const response = {
|
|
39764
|
-
id: ++this.messageId,
|
|
39765
|
-
from: agent.name.toUpperCase(),
|
|
39766
|
-
text: responseText,
|
|
39767
|
-
createdAt: new Date().toISOString()
|
|
39768
|
-
};
|
|
39769
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39770
|
-
this.conversation.push(response);
|
|
39771
|
-
await this.appendTranscript(response);
|
|
39772
|
-
onMessage(response);
|
|
39773
|
-
return response;
|
|
39774
|
-
}));
|
|
39775
|
-
const results = [];
|
|
39776
|
-
for (let idx = 0;idx < settled.length; idx++) {
|
|
39777
|
-
const item = settled[idx];
|
|
39778
|
-
if (item.status === "fulfilled") {
|
|
39779
|
-
if (item.value) {
|
|
39780
|
-
results.push(item.value);
|
|
39781
|
-
}
|
|
40022
|
+
dispatchToTargets(targetAgentNames, chainHops = 0) {
|
|
40023
|
+
for (const name of targetAgentNames) {
|
|
40024
|
+
const agent = this.agents.get(name);
|
|
40025
|
+
if (!agent)
|
|
39782
40026
|
continue;
|
|
40027
|
+
if (this.queueManager.isProcessing(name)) {
|
|
40028
|
+
this.queueManager.enqueue(name, {
|
|
40029
|
+
from: "dispatch",
|
|
40030
|
+
text: "",
|
|
40031
|
+
queuedAt: new Date().toISOString(),
|
|
40032
|
+
chainHops
|
|
40033
|
+
}, this.maxQueueSize);
|
|
40034
|
+
this.onSystem(`Queued for ${name} (busy, ${this.queueManager.pendingCount(name)} pending)`);
|
|
40035
|
+
} else {
|
|
40036
|
+
this.processAgent(name, chainHops);
|
|
39783
40037
|
}
|
|
39784
|
-
const agent = targets[idx];
|
|
39785
|
-
const response = {
|
|
39786
|
-
id: ++this.messageId,
|
|
39787
|
-
from: agent.name.toUpperCase(),
|
|
39788
|
-
text: `[Adapter Error] ${item.reason instanceof Error ? item.reason.message : String(item.reason)}`,
|
|
39789
|
-
createdAt: new Date().toISOString()
|
|
39790
|
-
};
|
|
39791
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39792
|
-
this.conversation.push(response);
|
|
39793
|
-
await this.appendTranscript(response);
|
|
39794
|
-
onMessage(response);
|
|
39795
|
-
results.push(response);
|
|
39796
40038
|
}
|
|
39797
|
-
|
|
40039
|
+
}
|
|
40040
|
+
async processAgent(agentName, chainHops) {
|
|
40041
|
+
const agent = this.agents.get(agentName);
|
|
40042
|
+
if (!agent)
|
|
40043
|
+
return;
|
|
40044
|
+
this.queueManager.setProcessing(agentName, true);
|
|
40045
|
+
this.onActivity(agentName, "thinking");
|
|
40046
|
+
const historyMaxId = this.messageId;
|
|
40047
|
+
const lastSeen = this.lastSeenByAgent.get(agentName) ?? 0;
|
|
40048
|
+
const unseen = this.conversation.filter((msg) => msg.id > lastSeen && msg.from.toUpperCase() !== agentName.toUpperCase());
|
|
40049
|
+
if (unseen.length === 0) {
|
|
40050
|
+
this.lastSeenByAgent.set(agentName, historyMaxId);
|
|
40051
|
+
this.queueManager.setProcessing(agentName, false);
|
|
40052
|
+
this.onActivity(agentName, "idle");
|
|
40053
|
+
this.drainQueue(agentName);
|
|
40054
|
+
return;
|
|
40055
|
+
}
|
|
40056
|
+
const inputMessages = this.buildInputForAgent(agentName, unseen);
|
|
40057
|
+
const responseText = await this.streamWithTimeout(agentName, agent, inputMessages, this.timeoutFor(agentName));
|
|
40058
|
+
const response = {
|
|
40059
|
+
id: ++this.messageId,
|
|
40060
|
+
from: agentName.toUpperCase(),
|
|
40061
|
+
text: responseText,
|
|
40062
|
+
createdAt: new Date().toISOString()
|
|
40063
|
+
};
|
|
40064
|
+
this.lastSeenByAgent.set(agentName, historyMaxId);
|
|
40065
|
+
this.conversation.push(response);
|
|
40066
|
+
await this.appendTranscript(response);
|
|
40067
|
+
this.onMessage(response);
|
|
40068
|
+
await this.saveManifest();
|
|
40069
|
+
this.queueManager.setProcessing(agentName, false);
|
|
40070
|
+
const isError = responseText.startsWith("[Timeout]") || responseText.startsWith("[Error]") || responseText.startsWith("[Adapter Error]");
|
|
40071
|
+
if (!isError) {
|
|
40072
|
+
this.processHandoffs(response, chainHops);
|
|
40073
|
+
}
|
|
40074
|
+
this.drainQueue(agentName);
|
|
40075
|
+
}
|
|
40076
|
+
processHandoffs(response, currentHops) {
|
|
40077
|
+
const selectors = extractNextSelectors([response]);
|
|
40078
|
+
if (selectors.length === 0)
|
|
40079
|
+
return;
|
|
40080
|
+
const humanTag = this.humanTag.toLowerCase();
|
|
40081
|
+
const humanName = this.humanName.toLowerCase();
|
|
40082
|
+
const agentSelectors = selectors.filter((s) => {
|
|
40083
|
+
const n = s.toLowerCase();
|
|
40084
|
+
return n !== humanTag && n !== humanName;
|
|
40085
|
+
});
|
|
40086
|
+
if (agentSelectors.length === 0)
|
|
40087
|
+
return;
|
|
40088
|
+
const resolvedTargets = Array.from(new Set(agentSelectors.flatMap((s) => this.resolveTargets(s))));
|
|
40089
|
+
if (resolvedTargets.length === 0)
|
|
40090
|
+
return;
|
|
40091
|
+
const nextHops = currentHops + 1;
|
|
40092
|
+
if (nextHops >= this.maxAutoHops) {
|
|
40093
|
+
this.onSystem(`Stopped auto-handoff after ${this.maxAutoHops} hops.`);
|
|
40094
|
+
return;
|
|
40095
|
+
}
|
|
40096
|
+
this.onSystem(`Auto handoff via @next to ${resolvedTargets.join(", ")}`);
|
|
40097
|
+
this.dispatchToTargets(resolvedTargets, nextHops);
|
|
40098
|
+
}
|
|
40099
|
+
drainQueue(agentName) {
|
|
40100
|
+
if (!this.queueManager.hasPending(agentName)) {
|
|
40101
|
+
this.onActivity(agentName, "idle");
|
|
40102
|
+
return;
|
|
40103
|
+
}
|
|
40104
|
+
const pending = this.queueManager.drain(agentName, this.queueTtlMs);
|
|
40105
|
+
if (pending.length === 0) {
|
|
40106
|
+
this.onActivity(agentName, "idle");
|
|
40107
|
+
return;
|
|
40108
|
+
}
|
|
40109
|
+
const maxHops = Math.max(...pending.map((m2) => m2.chainHops));
|
|
40110
|
+
if (maxHops >= this.maxAutoHops) {
|
|
40111
|
+
this.onSystem(`Stopped auto-handoff for ${agentName} after ${this.maxAutoHops} hops.`);
|
|
40112
|
+
this.onActivity(agentName, "idle");
|
|
40113
|
+
return;
|
|
40114
|
+
}
|
|
40115
|
+
this.processAgent(agentName, maxHops);
|
|
40116
|
+
}
|
|
40117
|
+
async streamWithTimeout(agentName, agent, messages, timeoutMs) {
|
|
40118
|
+
const controller = new AbortController;
|
|
40119
|
+
this.queueManager.setController(agentName, controller);
|
|
40120
|
+
let timer;
|
|
40121
|
+
let resolved = false;
|
|
40122
|
+
return new Promise((resolve4) => {
|
|
40123
|
+
timer = setTimeout(() => {
|
|
40124
|
+
if (!resolved) {
|
|
40125
|
+
resolved = true;
|
|
40126
|
+
controller.abort();
|
|
40127
|
+
this.onActivity(agentName, "error", "timeout");
|
|
40128
|
+
resolve4(`[Timeout] ${agentName} exceeded ${Math.floor(timeoutMs / 1000)}s`);
|
|
40129
|
+
}
|
|
40130
|
+
}, timeoutMs);
|
|
40131
|
+
(async () => {
|
|
40132
|
+
try {
|
|
40133
|
+
for await (const event of agent.stream(messages, controller.signal)) {
|
|
40134
|
+
if (resolved)
|
|
40135
|
+
return;
|
|
40136
|
+
if (event.type === "activity") {
|
|
40137
|
+
this.onActivity(agentName, event.activity, event.detail);
|
|
40138
|
+
} else if (event.type === "response") {
|
|
40139
|
+
resolved = true;
|
|
40140
|
+
if (timer)
|
|
40141
|
+
clearTimeout(timer);
|
|
40142
|
+
resolve4(event.text);
|
|
40143
|
+
return;
|
|
40144
|
+
} else if (event.type === "error") {
|
|
40145
|
+
resolved = true;
|
|
40146
|
+
if (timer)
|
|
40147
|
+
clearTimeout(timer);
|
|
40148
|
+
this.onActivity(agentName, "error");
|
|
40149
|
+
resolve4(`[Error] ${agentName}: ${event.message}`);
|
|
40150
|
+
return;
|
|
40151
|
+
}
|
|
40152
|
+
}
|
|
40153
|
+
if (!resolved) {
|
|
40154
|
+
resolved = true;
|
|
40155
|
+
if (timer)
|
|
40156
|
+
clearTimeout(timer);
|
|
40157
|
+
resolve4(`[No text response from ${agentName}]`);
|
|
40158
|
+
}
|
|
40159
|
+
} catch (err) {
|
|
40160
|
+
if (!resolved) {
|
|
40161
|
+
resolved = true;
|
|
40162
|
+
if (timer)
|
|
40163
|
+
clearTimeout(timer);
|
|
40164
|
+
this.onActivity(agentName, "error");
|
|
40165
|
+
resolve4(`[Error] ${agentName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
40166
|
+
}
|
|
40167
|
+
}
|
|
40168
|
+
})();
|
|
40169
|
+
});
|
|
39798
40170
|
}
|
|
39799
40171
|
async appendTranscript(message) {
|
|
39800
40172
|
try {
|
|
@@ -39807,23 +40179,85 @@ class Orchestrator {
|
|
|
39807
40179
|
async saveHistory(targetPath) {
|
|
39808
40180
|
await writeFile5(targetPath, JSON.stringify(this.conversation, null, 2), "utf8");
|
|
39809
40181
|
}
|
|
39810
|
-
async
|
|
39811
|
-
const
|
|
39812
|
-
|
|
39813
|
-
const
|
|
39814
|
-
|
|
39815
|
-
|
|
39816
|
-
|
|
39817
|
-
|
|
40182
|
+
async loadTranscript(sessionId) {
|
|
40183
|
+
const transcriptFile = path9.resolve(".llm-party", "sessions", `transcript-${sessionId}.jsonl`);
|
|
40184
|
+
const content = await readFile5(transcriptFile, "utf8");
|
|
40185
|
+
const lines = content.trim().split(`
|
|
40186
|
+
`).filter(Boolean);
|
|
40187
|
+
const messages = lines.map((line) => JSON.parse(line));
|
|
40188
|
+
this.conversation.length = 0;
|
|
40189
|
+
this.conversation.push(...messages);
|
|
40190
|
+
const maxId = messages.length > 0 ? Math.max(...messages.map((m2) => m2.id)) : 0;
|
|
40191
|
+
this.messageId = maxId;
|
|
40192
|
+
for (const agent of this.agents.keys()) {
|
|
40193
|
+
this.lastSeenByAgent.set(agent, maxId);
|
|
40194
|
+
}
|
|
40195
|
+
this.sessionId = sessionId;
|
|
40196
|
+
this.transcriptPath = transcriptFile;
|
|
40197
|
+
await this.loadManifest();
|
|
40198
|
+
return messages;
|
|
40199
|
+
}
|
|
40200
|
+
hasMessages() {
|
|
40201
|
+
return this.conversation.length > 0;
|
|
40202
|
+
}
|
|
40203
|
+
manifestPath() {
|
|
40204
|
+
const dir = path9.dirname(this.transcriptPath);
|
|
40205
|
+
const base = path9.basename(this.transcriptPath, ".jsonl");
|
|
40206
|
+
return path9.join(dir, `${base}.manifest.json`);
|
|
40207
|
+
}
|
|
40208
|
+
async saveManifest() {
|
|
40209
|
+
this.manifestSavePromise = this.manifestSavePromise.then(async () => {
|
|
40210
|
+
try {
|
|
40211
|
+
const agents = {};
|
|
40212
|
+
for (const [name, adapter] of this.agents) {
|
|
40213
|
+
const sid = adapter.getSdkSessionId();
|
|
40214
|
+
agents[name] = {
|
|
40215
|
+
provider: adapter.provider,
|
|
40216
|
+
sdkSessionId: sid || "",
|
|
40217
|
+
lastSeenId: this.lastSeenByAgent.get(name) ?? 0
|
|
40218
|
+
};
|
|
40219
|
+
}
|
|
40220
|
+
const manifest = {
|
|
40221
|
+
orchestratorSessionId: this.sessionId,
|
|
40222
|
+
messageId: this.messageId,
|
|
40223
|
+
stickyTarget: this.stickyTargets,
|
|
40224
|
+
agents
|
|
40225
|
+
};
|
|
40226
|
+
await writeFile5(this.manifestPath(), JSON.stringify(manifest, null, 2), "utf8");
|
|
40227
|
+
} catch (err) {
|
|
40228
|
+
console.error("[manifest] write failed:", err);
|
|
40229
|
+
}
|
|
39818
40230
|
});
|
|
40231
|
+
return this.manifestSavePromise;
|
|
40232
|
+
}
|
|
40233
|
+
async loadManifest() {
|
|
39819
40234
|
try {
|
|
39820
|
-
|
|
39821
|
-
|
|
39822
|
-
if (
|
|
39823
|
-
|
|
40235
|
+
const content = await readFile5(this.manifestPath(), "utf8");
|
|
40236
|
+
const manifest = JSON.parse(content);
|
|
40237
|
+
if (Array.isArray(manifest.stickyTarget)) {
|
|
40238
|
+
this.stickyTargets = manifest.stickyTarget;
|
|
40239
|
+
}
|
|
40240
|
+
const agentMap = manifest.agents ?? {};
|
|
40241
|
+
for (const [name, data] of Object.entries(agentMap)) {
|
|
40242
|
+
const adapter = this.agents.get(name);
|
|
40243
|
+
const agentData = data;
|
|
40244
|
+
if (!adapter || !agentData)
|
|
40245
|
+
continue;
|
|
40246
|
+
if (typeof agentData.sdkSessionId === "string" && agentData.sdkSessionId) {
|
|
40247
|
+
adapter.setSdkSessionId(agentData.sdkSessionId);
|
|
40248
|
+
}
|
|
40249
|
+
if (typeof agentData.lastSeenId === "number") {
|
|
40250
|
+
this.lastSeenByAgent.set(name, agentData.lastSeenId);
|
|
40251
|
+
}
|
|
39824
40252
|
}
|
|
40253
|
+
} catch (err) {
|
|
40254
|
+
console.error("[manifest] load failed (agents start fresh):", err);
|
|
39825
40255
|
}
|
|
39826
40256
|
}
|
|
40257
|
+
async abortAll() {
|
|
40258
|
+
this.queueManager.abortAll();
|
|
40259
|
+
await this.saveManifest();
|
|
40260
|
+
}
|
|
39827
40261
|
timeoutFor(agentName) {
|
|
39828
40262
|
return this.agentTimeouts.get(agentName) ?? this.defaultTimeout;
|
|
39829
40263
|
}
|
|
@@ -39857,6 +40291,21 @@ function createSessionId() {
|
|
|
39857
40291
|
const rand = randomBytes(4).toString("hex");
|
|
39858
40292
|
return `${timestamp}-${process.pid}-${rand}`;
|
|
39859
40293
|
}
|
|
40294
|
+
function extractNextSelectors(messages) {
|
|
40295
|
+
const selectors = [];
|
|
40296
|
+
for (const msg of messages) {
|
|
40297
|
+
const regex = /@next\s*:\s*([A-Za-z0-9_-]+)/gi;
|
|
40298
|
+
let match = null;
|
|
40299
|
+
while ((match = regex.exec(msg.text)) !== null) {
|
|
40300
|
+
selectors.push(match[1]);
|
|
40301
|
+
}
|
|
40302
|
+
const controlMatch = msg.text.match(/@control[\s\S]*?next\s*:\s*([A-Za-z0-9_-]+)[\s\S]*?@end/i);
|
|
40303
|
+
if (controlMatch?.[1]) {
|
|
40304
|
+
selectors.push(controlMatch[1]);
|
|
40305
|
+
}
|
|
40306
|
+
}
|
|
40307
|
+
return selectors;
|
|
40308
|
+
}
|
|
39860
40309
|
|
|
39861
40310
|
// src/ui/App.tsx
|
|
39862
40311
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -39868,14 +40317,56 @@ function nextSystemId() {
|
|
|
39868
40317
|
systemIdCounter -= 1;
|
|
39869
40318
|
return systemIdCounter;
|
|
39870
40319
|
}
|
|
39871
|
-
function useOrchestrator(orchestrator
|
|
40320
|
+
function useOrchestrator(orchestrator) {
|
|
39872
40321
|
const [messages, setMessages] = createSignal([]);
|
|
39873
40322
|
const [agentStates, setAgentStates] = createSignal(new Map(orchestrator.listAgents().map((a) => [a.name, "idle"])));
|
|
39874
|
-
const [stickyTarget,
|
|
40323
|
+
const [stickyTarget, setStickyTargetSignal] = createSignal(orchestrator.getStickyTarget());
|
|
40324
|
+
const setStickyTarget = (targets) => {
|
|
40325
|
+
setStickyTargetSignal(targets);
|
|
40326
|
+
orchestrator.setStickyTarget(targets);
|
|
40327
|
+
};
|
|
39875
40328
|
const [dispatching, setDispatching] = createSignal(false);
|
|
40329
|
+
const [queueCounts, setQueueCounts] = createSignal(new Map(orchestrator.listAgents().map((a) => [a.name, 0])));
|
|
39876
40330
|
let projectFolderReady = false;
|
|
39877
|
-
|
|
39878
|
-
|
|
40331
|
+
const agentProviders = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.provider]));
|
|
40332
|
+
const agentTagsMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.tag]));
|
|
40333
|
+
const nameMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.name]));
|
|
40334
|
+
const updateQueueCounts = () => {
|
|
40335
|
+
const status = orchestrator.getQueueStatus();
|
|
40336
|
+
setQueueCounts(new Map(status.map((s) => [s.name, s.pending])));
|
|
40337
|
+
};
|
|
40338
|
+
orchestrator.setCallbacks((msg) => {
|
|
40339
|
+
const provider = agentProviders.get(msg.from) ?? "";
|
|
40340
|
+
const tag = agentTagsMap.get(msg.from) ?? "";
|
|
40341
|
+
const display = {
|
|
40342
|
+
...msg,
|
|
40343
|
+
type: "agent",
|
|
40344
|
+
provider,
|
|
40345
|
+
tag
|
|
40346
|
+
};
|
|
40347
|
+
setMessages((prev) => [...prev, display]);
|
|
40348
|
+
const originalName = nameMap.get(msg.from) ?? msg.from;
|
|
40349
|
+
setAgentStates((prev) => {
|
|
40350
|
+
const next = new Map(prev);
|
|
40351
|
+
const isErr = msg.text.startsWith("[Adapter Error]") || msg.text.startsWith("[Error]") || msg.text.startsWith("[Timeout]");
|
|
40352
|
+
next.set(originalName, isErr ? "error" : "idle");
|
|
40353
|
+
return next;
|
|
40354
|
+
});
|
|
40355
|
+
setDispatching(orchestrator.dispatching);
|
|
40356
|
+
updateQueueCounts();
|
|
40357
|
+
}, (agentName, activity) => {
|
|
40358
|
+
const originalName = nameMap.get(agentName.toUpperCase()) ?? agentName;
|
|
40359
|
+
setAgentStates((prev) => {
|
|
40360
|
+
const next = new Map(prev);
|
|
40361
|
+
next.set(originalName, activity);
|
|
40362
|
+
return next;
|
|
40363
|
+
});
|
|
40364
|
+
setDispatching(orchestrator.dispatching);
|
|
40365
|
+
updateQueueCounts();
|
|
40366
|
+
}, (text) => {
|
|
40367
|
+
addSystemMessage(text);
|
|
40368
|
+
updateQueueCounts();
|
|
40369
|
+
});
|
|
39879
40370
|
const dispatch = async (line) => {
|
|
39880
40371
|
if (!line.trim())
|
|
39881
40372
|
return;
|
|
@@ -39889,7 +40380,7 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39889
40380
|
if (explicitTargets && explicitTargets.length > 0) {
|
|
39890
40381
|
setStickyTarget(explicitTargets);
|
|
39891
40382
|
}
|
|
39892
|
-
const targets = explicitTargets ?? stickyTarget();
|
|
40383
|
+
const targets = explicitTargets ?? stickyTarget() ?? Array.from(orchestrator.listAgents().map((a) => a.name));
|
|
39893
40384
|
if (!projectFolderReady) {
|
|
39894
40385
|
await initProjectFolder(process.cwd());
|
|
39895
40386
|
projectFolderReady = true;
|
|
@@ -39902,11 +40393,7 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39902
40393
|
};
|
|
39903
40394
|
setMessages((prev) => [...prev, userDisplay]);
|
|
39904
40395
|
setDispatching(true);
|
|
39905
|
-
|
|
39906
|
-
await dispatchWithHandoffs(orchestrator, targets, maxAutoHops, agentProviders, agentTags, setMessages, setAgentStates);
|
|
39907
|
-
} finally {
|
|
39908
|
-
setDispatching(false);
|
|
39909
|
-
}
|
|
40396
|
+
orchestrator.dispatchToTargets(targets);
|
|
39910
40397
|
};
|
|
39911
40398
|
const addSystemMessage = (text) => {
|
|
39912
40399
|
const msg = {
|
|
@@ -39918,89 +40405,17 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39918
40405
|
};
|
|
39919
40406
|
setMessages((prev) => [...prev, msg]);
|
|
39920
40407
|
};
|
|
40408
|
+
const addDisplayMessage = (msg) => {
|
|
40409
|
+
setMessages((prev) => [...prev, msg]);
|
|
40410
|
+
};
|
|
39921
40411
|
const clearMessages = () => {
|
|
39922
40412
|
orchestrator.clearConversation();
|
|
39923
40413
|
setMessages([]);
|
|
39924
40414
|
};
|
|
39925
|
-
|
|
39926
|
-
|
|
39927
|
-
|
|
39928
|
-
|
|
39929
|
-
let hops = 0;
|
|
39930
|
-
while (true) {
|
|
39931
|
-
const targetNames = targets ?? Array.from(orchestrator.listAgents().map((a) => a.name));
|
|
39932
|
-
setAgentStates((prev) => {
|
|
39933
|
-
const next = new Map(prev);
|
|
39934
|
-
for (const name of targetNames) {
|
|
39935
|
-
next.set(name, "thinking");
|
|
39936
|
-
}
|
|
39937
|
-
return next;
|
|
39938
|
-
});
|
|
39939
|
-
const nameMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.name]));
|
|
39940
|
-
const batch = [];
|
|
39941
|
-
await orchestrator.fanOutWithProgress(targets, (msg) => {
|
|
39942
|
-
batch.push(msg);
|
|
39943
|
-
const provider = agentProviders.get(msg.from) ?? "";
|
|
39944
|
-
const tag = agentTags.get(msg.from) ?? "";
|
|
39945
|
-
const display = {
|
|
39946
|
-
...msg,
|
|
39947
|
-
type: "agent",
|
|
39948
|
-
provider,
|
|
39949
|
-
tag
|
|
39950
|
-
};
|
|
39951
|
-
setMessages((prev) => [...prev, display]);
|
|
39952
|
-
const originalName = nameMap.get(msg.from) ?? msg.from;
|
|
39953
|
-
setAgentStates((prev) => {
|
|
39954
|
-
const next = new Map(prev);
|
|
39955
|
-
next.set(originalName, msg.text.startsWith("[Adapter Error]") ? "error" : "idle");
|
|
39956
|
-
return next;
|
|
39957
|
-
});
|
|
39958
|
-
});
|
|
39959
|
-
setAgentStates((prev) => {
|
|
39960
|
-
const next = new Map(prev);
|
|
39961
|
-
for (const name of targetNames) {
|
|
39962
|
-
if (next.get(name) === "thinking") {
|
|
39963
|
-
next.set(name, "idle");
|
|
39964
|
-
}
|
|
39965
|
-
}
|
|
39966
|
-
return next;
|
|
39967
|
-
});
|
|
39968
|
-
const nextSelectors = extractNextSelectors(batch);
|
|
39969
|
-
if (nextSelectors.length === 0)
|
|
39970
|
-
return;
|
|
39971
|
-
const humanTag = orchestrator.getHumanTag().toLowerCase();
|
|
39972
|
-
const humanName = orchestrator.getHumanName().toLowerCase();
|
|
39973
|
-
const agentSelectors = nextSelectors.filter((s) => {
|
|
39974
|
-
const n = s.toLowerCase();
|
|
39975
|
-
return n !== humanTag && n !== humanName;
|
|
39976
|
-
});
|
|
39977
|
-
if (agentSelectors.length === 0)
|
|
39978
|
-
return;
|
|
39979
|
-
const resolvedTargets = Array.from(new Set(agentSelectors.flatMap((s) => orchestrator.resolveTargets(s))));
|
|
39980
|
-
if (resolvedTargets.length === 0)
|
|
39981
|
-
return;
|
|
39982
|
-
hops += 1;
|
|
39983
|
-
if (Number.isFinite(maxHops) && hops >= maxHops) {
|
|
39984
|
-
const systemMsg = {
|
|
39985
|
-
id: nextSystemId(),
|
|
39986
|
-
from: "SYSTEM",
|
|
39987
|
-
text: `Stopped auto-handoff after ${maxHops} hops.`,
|
|
39988
|
-
createdAt: new Date().toISOString(),
|
|
39989
|
-
type: "system"
|
|
39990
|
-
};
|
|
39991
|
-
setMessages((prev) => [...prev, systemMsg]);
|
|
39992
|
-
return;
|
|
39993
|
-
}
|
|
39994
|
-
const handoffMsg = {
|
|
39995
|
-
id: nextSystemId(),
|
|
39996
|
-
from: "SYSTEM",
|
|
39997
|
-
text: `Auto handoff via @next to ${resolvedTargets.join(", ")}`,
|
|
39998
|
-
createdAt: new Date().toISOString(),
|
|
39999
|
-
type: "system"
|
|
40000
|
-
};
|
|
40001
|
-
setMessages((prev) => [...prev, handoffMsg]);
|
|
40002
|
-
targets = resolvedTargets;
|
|
40003
|
-
}
|
|
40415
|
+
const refreshStickyTarget = () => {
|
|
40416
|
+
setStickyTargetSignal(orchestrator.getStickyTarget());
|
|
40417
|
+
};
|
|
40418
|
+
return { messages, agentStates, queueCounts, stickyTarget, dispatching, dispatch, addSystemMessage, addDisplayMessage, clearMessages, refreshStickyTarget };
|
|
40004
40419
|
}
|
|
40005
40420
|
function getChangedFiles() {
|
|
40006
40421
|
return new Promise((resolve4) => {
|
|
@@ -40015,21 +40430,6 @@ function getChangedFiles() {
|
|
|
40015
40430
|
});
|
|
40016
40431
|
});
|
|
40017
40432
|
}
|
|
40018
|
-
function extractNextSelectors(messages) {
|
|
40019
|
-
const selectors = [];
|
|
40020
|
-
for (const msg of messages) {
|
|
40021
|
-
const regex = /@next\s*:\s*([A-Za-z0-9_-]+)/gi;
|
|
40022
|
-
let match = null;
|
|
40023
|
-
while ((match = regex.exec(msg.text)) !== null) {
|
|
40024
|
-
selectors.push(match[1]);
|
|
40025
|
-
}
|
|
40026
|
-
const controlMatch = msg.text.match(/@control[\s\S]*?next\s*:\s*([A-Za-z0-9_-]+)[\s\S]*?@end/i);
|
|
40027
|
-
if (controlMatch?.[1]) {
|
|
40028
|
-
selectors.push(controlMatch[1]);
|
|
40029
|
-
}
|
|
40030
|
-
}
|
|
40031
|
-
return selectors;
|
|
40032
|
-
}
|
|
40033
40433
|
function parseRouting(line) {
|
|
40034
40434
|
const mentionRegex = /(^|[^A-Za-z0-9_-])@([A-Za-z0-9_-]+)\b/g;
|
|
40035
40435
|
const mentions = [];
|
|
@@ -40118,27 +40518,21 @@ function MessageBubble(props) {
|
|
|
40118
40518
|
}
|
|
40119
40519
|
|
|
40120
40520
|
// src/ui/constants.ts
|
|
40121
|
-
var SPINNER_FRAMES =
|
|
40521
|
+
var SPINNER_FRAMES = "\u280B\u2819\u281A\u281E\u2816\u2826\u2834\u2832\u2833\u2813".split("");
|
|
40522
|
+
var ACTIVITY_SPINNERS = {
|
|
40523
|
+
thinking_bkp: "\u2733\u2734\u2736\u2735\u2737\u2738\u2739\u273A".split(""),
|
|
40524
|
+
thinking: " ..ooOO@@@@@@*".split(""),
|
|
40525
|
+
writing: "\u258F\u258E\u258D\u258C\u258B\u258A\u2589\u2588\u2589\u258A\u258B\u258C\u258D\u258E".split(""),
|
|
40526
|
+
reading: ["\u2801", "\u2809", "\u280B", "\u281B", "\u281F", "\u283F", "\u287F", "\u28FF"],
|
|
40527
|
+
running: [" ", "\u2591", "\u2592", "\u2593", "\u2588"],
|
|
40528
|
+
searching: "\u25D0\u25D3\u25D1\u25D2".split("")
|
|
40529
|
+
};
|
|
40530
|
+
var SUPERSCRIPT_DIGITS = ["\u2070", "\xB9", "\xB2", "\xB3", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079"];
|
|
40122
40531
|
|
|
40123
40532
|
// src/ui/StatusBar.tsx
|
|
40124
40533
|
var PULSE_COLORS = ["#005F87", "#0087AF", "#00AFD7", "#00D7FF", "#5FF", "#00D7FF", "#0087AF"];
|
|
40125
|
-
|
|
40126
|
-
|
|
40127
|
-
createEffect(() => {
|
|
40128
|
-
if (!active()) {
|
|
40129
|
-
setFrame(0);
|
|
40130
|
-
return;
|
|
40131
|
-
}
|
|
40132
|
-
const interval = setInterval(() => {
|
|
40133
|
-
setFrame((f) => (f + 1) % (SPINNER_FRAMES.length * PULSE_COLORS.length));
|
|
40134
|
-
}, 80);
|
|
40135
|
-
onCleanup(() => clearInterval(interval));
|
|
40136
|
-
});
|
|
40137
|
-
return {
|
|
40138
|
-
spinner: () => active() ? SPINNER_FRAMES[frame() % SPINNER_FRAMES.length] : "",
|
|
40139
|
-
color: () => active() ? PULSE_COLORS[frame() % PULSE_COLORS.length] : COLORS.textMuted
|
|
40140
|
-
};
|
|
40141
|
-
}
|
|
40534
|
+
var [globalTick, setGlobalTick] = createSignal(0);
|
|
40535
|
+
setInterval(() => setGlobalTick((t2) => t2 + 1), 80);
|
|
40142
40536
|
function StatusBar(props) {
|
|
40143
40537
|
const targetNames = () => props.stickyTarget ?? props.agents.map((a) => a.name);
|
|
40144
40538
|
const isTargeted = (name) => targetNames().includes(name);
|
|
@@ -40186,65 +40580,59 @@ function StatusBar(props) {
|
|
|
40186
40580
|
}), _el$4);
|
|
40187
40581
|
insertNode(_el$4, createTextNode(`| /info`));
|
|
40188
40582
|
setProp(_el$6, "flexDirection", "row");
|
|
40189
|
-
setProp(_el$6, "gap", 2);
|
|
40190
40583
|
insert(_el$6, createComponent2(For, {
|
|
40191
40584
|
get each() {
|
|
40192
40585
|
return props.agents;
|
|
40193
40586
|
},
|
|
40194
|
-
children: (a) => createComponent2(AgentChip, {
|
|
40587
|
+
children: (a, i) => [createComponent2(AgentChip, {
|
|
40195
40588
|
get name() {
|
|
40196
40589
|
return a.name;
|
|
40197
40590
|
},
|
|
40198
|
-
|
|
40199
|
-
|
|
40200
|
-
|
|
40201
|
-
|
|
40591
|
+
getState: () => props.agentStates.get(a.name) ?? "idle",
|
|
40592
|
+
getQueued: () => props.queueCounts?.get(a.name) ?? 0
|
|
40593
|
+
}), memo2(() => memo2(() => i() < props.agents.length - 1)() ? (() => {
|
|
40594
|
+
var _el$12 = createElement("text");
|
|
40595
|
+
insertNode(_el$12, createTextNode(` \u2502 `));
|
|
40596
|
+
effect((_$p) => setProp(_el$12, "fg", COLORS.textDim, _$p));
|
|
40597
|
+
return _el$12;
|
|
40598
|
+
})() : null)]
|
|
40202
40599
|
}));
|
|
40203
40600
|
effect((_$p) => setProp(_el$4, "fg", COLORS.textDim, _$p));
|
|
40204
40601
|
return _el$;
|
|
40205
40602
|
})();
|
|
40206
40603
|
}
|
|
40604
|
+
function toSuperscript(n) {
|
|
40605
|
+
if (n <= 0)
|
|
40606
|
+
return "";
|
|
40607
|
+
return String(n).split("").map((d2) => SUPERSCRIPT_DIGITS[parseInt(d2, 10)] ?? d2).join("");
|
|
40608
|
+
}
|
|
40207
40609
|
function AgentChip(props) {
|
|
40208
|
-
const {
|
|
40209
|
-
|
|
40210
|
-
|
|
40211
|
-
}
|
|
40212
|
-
|
|
40213
|
-
|
|
40214
|
-
|
|
40215
|
-
|
|
40216
|
-
|
|
40217
|
-
|
|
40218
|
-
|
|
40219
|
-
|
|
40220
|
-
|
|
40221
|
-
|
|
40222
|
-
|
|
40223
|
-
|
|
40224
|
-
|
|
40225
|
-
|
|
40226
|
-
|
|
40227
|
-
|
|
40228
|
-
|
|
40229
|
-
|
|
40230
|
-
|
|
40231
|
-
|
|
40232
|
-
|
|
40233
|
-
|
|
40234
|
-
get when() {
|
|
40235
|
-
return props.state === "thinking";
|
|
40236
|
-
},
|
|
40237
|
-
get children() {
|
|
40238
|
-
var _el$14 = createElement("text"), _el$15 = createTextNode(` `);
|
|
40239
|
-
insertNode(_el$14, _el$15);
|
|
40240
|
-
insert(_el$14, () => props.name, _el$15);
|
|
40241
|
-
insert(_el$14, spinner, null);
|
|
40242
|
-
effect((_$p) => setProp(_el$14, "fg", color(), _$p));
|
|
40243
|
-
return _el$14;
|
|
40244
|
-
}
|
|
40245
|
-
})];
|
|
40246
|
-
}
|
|
40247
|
-
});
|
|
40610
|
+
const isActive = () => {
|
|
40611
|
+
const s = props.getState();
|
|
40612
|
+
return s !== "idle" && s !== "error" && s !== "queued";
|
|
40613
|
+
};
|
|
40614
|
+
const frames = () => ACTIVITY_SPINNERS[props.getState()] ?? SPINNER_FRAMES;
|
|
40615
|
+
const tick = () => globalTick();
|
|
40616
|
+
const spinner = () => isActive() ? frames()[tick() % frames().length] : " ";
|
|
40617
|
+
const pulseColor = () => isActive() ? PULSE_COLORS[tick() % PULSE_COLORS.length] : COLORS.textMuted;
|
|
40618
|
+
const queueSlot = () => props.getQueued() > 0 ? toSuperscript(props.getQueued()) : " ";
|
|
40619
|
+
const stateColor = () => {
|
|
40620
|
+
if (props.getState() === "error")
|
|
40621
|
+
return COLORS.error;
|
|
40622
|
+
if (isActive())
|
|
40623
|
+
return pulseColor();
|
|
40624
|
+
return COLORS.textMuted;
|
|
40625
|
+
};
|
|
40626
|
+
return (() => {
|
|
40627
|
+
var _el$14 = createElement("text"), _el$15 = createTextNode(` `);
|
|
40628
|
+
insertNode(_el$14, _el$15);
|
|
40629
|
+
insert(_el$14, queueSlot, _el$15);
|
|
40630
|
+
insert(_el$14, () => props.name, _el$15);
|
|
40631
|
+
insert(_el$14, spinner, null);
|
|
40632
|
+
insert(_el$14, () => props.getState() === "error" ? " ERR" : "", null);
|
|
40633
|
+
effect((_$p) => setProp(_el$14, "fg", stateColor(), _$p));
|
|
40634
|
+
return _el$14;
|
|
40635
|
+
})();
|
|
40248
40636
|
}
|
|
40249
40637
|
|
|
40250
40638
|
// src/ui/InputLine.tsx
|
|
@@ -40500,7 +40888,7 @@ import { userInfo as userInfo2 } from "os";
|
|
|
40500
40888
|
|
|
40501
40889
|
// src/config/detector.ts
|
|
40502
40890
|
import { spawn as spawn3 } from "child_process";
|
|
40503
|
-
var DETECT_TIMEOUT =
|
|
40891
|
+
var DETECT_TIMEOUT = 1e4;
|
|
40504
40892
|
function detectBinary(command) {
|
|
40505
40893
|
return new Promise((resolve4) => {
|
|
40506
40894
|
const timer = setTimeout(() => resolve4({ available: false }), DETECT_TIMEOUT);
|
|
@@ -42323,12 +42711,15 @@ function App(props) {
|
|
|
42323
42711
|
const {
|
|
42324
42712
|
messages,
|
|
42325
42713
|
agentStates,
|
|
42714
|
+
queueCounts,
|
|
42326
42715
|
stickyTarget,
|
|
42327
42716
|
dispatching,
|
|
42328
42717
|
dispatch,
|
|
42329
42718
|
addSystemMessage,
|
|
42330
|
-
|
|
42331
|
-
|
|
42719
|
+
addDisplayMessage,
|
|
42720
|
+
clearMessages,
|
|
42721
|
+
refreshStickyTarget
|
|
42722
|
+
} = useOrchestrator(props.orchestrator);
|
|
42332
42723
|
const humanName = props.orchestrator.getHumanName();
|
|
42333
42724
|
const agents = props.orchestrator.listAgents();
|
|
42334
42725
|
let scrollRef = null;
|
|
@@ -42336,17 +42727,48 @@ function App(props) {
|
|
|
42336
42727
|
const [freshConfig, setFreshConfig] = createSignal(props.config);
|
|
42337
42728
|
const [showAgents, setShowAgents] = createSignal(false);
|
|
42338
42729
|
const [showInfo, setShowInfo] = createSignal(false);
|
|
42339
|
-
|
|
42340
|
-
|
|
42341
|
-
|
|
42730
|
+
const resumeSession = async (sessionId) => {
|
|
42731
|
+
try {
|
|
42732
|
+
const restored = await props.orchestrator.loadTranscript(sessionId);
|
|
42733
|
+
const displayMsgs = restored.map((msg) => {
|
|
42734
|
+
const isHuman = msg.from.toUpperCase() === humanName.toUpperCase();
|
|
42735
|
+
const agentInfo = agents.find((a) => a.name.toUpperCase() === msg.from.toUpperCase());
|
|
42736
|
+
return {
|
|
42737
|
+
...msg,
|
|
42738
|
+
type: isHuman ? "user" : "agent",
|
|
42739
|
+
provider: agentInfo?.provider ?? "",
|
|
42740
|
+
tag: agentInfo?.tag ?? ""
|
|
42741
|
+
};
|
|
42742
|
+
});
|
|
42743
|
+
for (const msg of displayMsgs) {
|
|
42744
|
+
addDisplayMessage(msg);
|
|
42745
|
+
}
|
|
42746
|
+
refreshStickyTarget();
|
|
42747
|
+
addSystemMessage(`Resumed session ${sessionId} (${restored.length} messages)`);
|
|
42748
|
+
} catch (err) {
|
|
42749
|
+
addSystemMessage(`Failed to resume: ${err instanceof Error ? err.message : String(err)}`);
|
|
42750
|
+
}
|
|
42751
|
+
};
|
|
42752
|
+
onMount(() => {
|
|
42753
|
+
if (props.resumeSessionId) {
|
|
42754
|
+
resumeSession(props.resumeSessionId);
|
|
42755
|
+
}
|
|
42756
|
+
});
|
|
42757
|
+
process.on("SIGINT", () => gracefulExit());
|
|
42758
|
+
process.on("SIGTERM", () => gracefulExit());
|
|
42759
|
+
process.on("SIGHUP", () => gracefulExit());
|
|
42342
42760
|
process.on("SIGTSTP", () => {
|
|
42343
42761
|
process.once("SIGCONT", () => renderer.resume());
|
|
42344
42762
|
renderer.suspend();
|
|
42345
42763
|
});
|
|
42346
|
-
const gracefulExit = () => {
|
|
42764
|
+
const gracefulExit = async () => {
|
|
42765
|
+
await props.orchestrator.abortAll();
|
|
42347
42766
|
renderer.destroy();
|
|
42348
42767
|
const adapters = props.orchestrator.getAdapters();
|
|
42349
|
-
Promise.allSettled(adapters.map((a) => a.destroy()))
|
|
42768
|
+
Promise.allSettled(adapters.map((a) => a.destroy())).finally(() => {
|
|
42769
|
+
process.exit(0);
|
|
42770
|
+
});
|
|
42771
|
+
setTimeout(() => process.exit(0), 2000);
|
|
42350
42772
|
};
|
|
42351
42773
|
useKeyboard((key) => {
|
|
42352
42774
|
if (key.ctrl && key.name === "p") {
|
|
@@ -42425,6 +42847,19 @@ ${files.map((f) => ` ${f}`).join(`
|
|
|
42425
42847
|
setShowInfo(true);
|
|
42426
42848
|
return;
|
|
42427
42849
|
}
|
|
42850
|
+
if (line.startsWith("/resume")) {
|
|
42851
|
+
const sid = line.replace("/resume", "").trim();
|
|
42852
|
+
if (!sid) {
|
|
42853
|
+
addSystemMessage("Usage: /resume <sessionId>");
|
|
42854
|
+
return;
|
|
42855
|
+
}
|
|
42856
|
+
if (props.orchestrator.hasMessages()) {
|
|
42857
|
+
addSystemMessage("Resume only works before the first message.");
|
|
42858
|
+
return;
|
|
42859
|
+
}
|
|
42860
|
+
await resumeSession(sid);
|
|
42861
|
+
return;
|
|
42862
|
+
}
|
|
42428
42863
|
if (line.startsWith("/flood")) {
|
|
42429
42864
|
const args = line.split(/\s+/);
|
|
42430
42865
|
const count = parseInt(args[1], 10) || 50;
|
|
@@ -42489,13 +42924,16 @@ ${lines.join(`
|
|
|
42489
42924
|
},
|
|
42490
42925
|
get stickyTarget() {
|
|
42491
42926
|
return stickyTarget();
|
|
42927
|
+
},
|
|
42928
|
+
get queueCounts() {
|
|
42929
|
+
return queueCounts();
|
|
42492
42930
|
}
|
|
42493
42931
|
}), null);
|
|
42494
42932
|
insert(_el$, createComponent2(InputLine, {
|
|
42495
42933
|
humanName,
|
|
42496
42934
|
onSubmit: handleSubmit,
|
|
42497
42935
|
get disabled() {
|
|
42498
|
-
return
|
|
42936
|
+
return showAgents() || showInfo();
|
|
42499
42937
|
},
|
|
42500
42938
|
get disabledMessage() {
|
|
42501
42939
|
return showAgents() ? "" : undefined;
|
|
@@ -42531,6 +42969,8 @@ ${lines.join(`
|
|
|
42531
42969
|
async function main2() {
|
|
42532
42970
|
const appRoot = path11.resolve(path11.dirname(fileURLToPath3(import.meta.url)), "..");
|
|
42533
42971
|
await initLlmPartyHome(appRoot);
|
|
42972
|
+
const resumeIndex = process.argv.indexOf("--resume");
|
|
42973
|
+
const resumeSessionId = resumeIndex !== -1 ? process.argv[resumeIndex + 1] : undefined;
|
|
42534
42974
|
const rendererConfig = {
|
|
42535
42975
|
exitOnCtrlC: false,
|
|
42536
42976
|
useMouse: true,
|
|
@@ -42541,14 +42981,14 @@ async function main2() {
|
|
|
42541
42981
|
await render(() => ConfigWizard({
|
|
42542
42982
|
isFirstRun: true,
|
|
42543
42983
|
onComplete: async () => {
|
|
42544
|
-
await bootApp(appRoot, rendererConfig);
|
|
42984
|
+
await bootApp(appRoot, rendererConfig, resumeSessionId);
|
|
42545
42985
|
}
|
|
42546
42986
|
}), rendererConfig);
|
|
42547
42987
|
} else {
|
|
42548
|
-
await bootApp(appRoot, rendererConfig);
|
|
42988
|
+
await bootApp(appRoot, rendererConfig, resumeSessionId);
|
|
42549
42989
|
}
|
|
42550
42990
|
}
|
|
42551
|
-
async function bootApp(appRoot, rendererConfig) {
|
|
42991
|
+
async function bootApp(appRoot, rendererConfig, resumeSessionId) {
|
|
42552
42992
|
const configPath = await resolveConfigPath(appRoot);
|
|
42553
42993
|
const config = await loadConfig2(configPath);
|
|
42554
42994
|
const humanName = config.humanName?.trim() || "USER";
|
|
@@ -42594,7 +43034,7 @@ async function bootApp(appRoot, rendererConfig) {
|
|
|
42594
43034
|
const promptParts = [mergedBase];
|
|
42595
43035
|
if (agent.prompts && agent.prompts.length > 0) {
|
|
42596
43036
|
const extraPaths = agent.prompts.map((p) => resolveFromConfig(p));
|
|
42597
|
-
const extraParts = await Promise.all(extraPaths.map((p) =>
|
|
43037
|
+
const extraParts = await Promise.all(extraPaths.map((p) => readFile6(p, "utf8")));
|
|
42598
43038
|
promptParts.push(...extraParts);
|
|
42599
43039
|
}
|
|
42600
43040
|
const promptTemplate = promptParts.join(`
|
|
@@ -42638,8 +43078,8 @@ ${mySkills.map((s) => `- ${s}`).join(`
|
|
|
42638
43078
|
}));
|
|
42639
43079
|
const defaultTimeout = typeof config.timeout === "number" && config.timeout > 0 ? config.timeout * 1000 : 600000;
|
|
42640
43080
|
const agentTimeouts = Object.fromEntries(activeAgents.filter((agent) => typeof agent.timeout === "number" && agent.timeout > 0).map((agent) => [agent.name, agent.timeout * 1000]));
|
|
42641
|
-
const orchestrator = new Orchestrator(adapters, humanName, Object.fromEntries(activeAgents.map((agent) => [agent.name, agent.tag?.trim() || toTag(agent.name)])), humanTag, defaultTimeout, agentTimeouts, { reminderInterval: config.reminderInterval });
|
|
42642
|
-
await render(() => App({ orchestrator,
|
|
43081
|
+
const orchestrator = new Orchestrator(adapters, humanName, Object.fromEntries(activeAgents.map((agent) => [agent.name, agent.tag?.trim() || toTag(agent.name)])), humanTag, defaultTimeout, agentTimeouts, { reminderInterval: config.reminderInterval, maxAutoHops });
|
|
43082
|
+
await render(() => App({ orchestrator, config, configPath, resumeSessionId }), rendererConfig);
|
|
42643
43083
|
}
|
|
42644
43084
|
function resolveMaxAutoHops(value) {
|
|
42645
43085
|
if (typeof value === "number" && value === 0) {
|