wayang-ai 0.6.1 → 0.6.3
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/cli.js +143 -94
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -819,37 +819,6 @@ function formatWorkerTag(ctx) {
|
|
|
819
819
|
|
|
820
820
|
// src/tui/components/chat-area/user-row.tsx
|
|
821
821
|
import { Box, Text } from "ink";
|
|
822
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
823
|
-
function UserRow({ item, width }) {
|
|
824
|
-
const dim = !item.read;
|
|
825
|
-
const text = item.content;
|
|
826
|
-
const padded = text.length < width ? text.padEnd(width) : text;
|
|
827
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
828
|
-
/* @__PURE__ */ jsxs(
|
|
829
|
-
Text,
|
|
830
|
-
{
|
|
831
|
-
backgroundColor: theme.user.bgHex,
|
|
832
|
-
color: theme.user.prefixColor,
|
|
833
|
-
bold: true,
|
|
834
|
-
children: [
|
|
835
|
-
theme.user.prefix,
|
|
836
|
-
" "
|
|
837
|
-
]
|
|
838
|
-
}
|
|
839
|
-
),
|
|
840
|
-
/* @__PURE__ */ jsx2(
|
|
841
|
-
Text,
|
|
842
|
-
{
|
|
843
|
-
backgroundColor: theme.user.bgHex,
|
|
844
|
-
color: dim ? theme.baseToken.color.textSubtle : theme.baseToken.color.textNormal,
|
|
845
|
-
children: padded
|
|
846
|
-
}
|
|
847
|
-
)
|
|
848
|
-
] });
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// src/tui/components/chat-area/assistant-step-row.tsx
|
|
852
|
-
import { Box as Box2, Text as Text2 } from "ink";
|
|
853
822
|
|
|
854
823
|
// src/tui/utils/text-width.ts
|
|
855
824
|
function charWidth(cp) {
|
|
@@ -894,6 +863,43 @@ function shortId(id) {
|
|
|
894
863
|
return id.slice(-4);
|
|
895
864
|
}
|
|
896
865
|
|
|
866
|
+
// src/tui/components/chat-area/user-row.tsx
|
|
867
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
868
|
+
var PREFIX = `${theme.user.prefix} `;
|
|
869
|
+
var PREFIX_WIDTH = stringWidth(PREFIX);
|
|
870
|
+
function fillRow(line, width) {
|
|
871
|
+
const fill = width - stringWidth(line);
|
|
872
|
+
return fill > 0 ? line + " ".repeat(fill) : line;
|
|
873
|
+
}
|
|
874
|
+
function UserRow({ item, width }) {
|
|
875
|
+
const dim = !item.read;
|
|
876
|
+
const rowWidth = Math.max(0, width);
|
|
877
|
+
const textWidth = Math.max(0, rowWidth - PREFIX_WIDTH);
|
|
878
|
+
const body = item.content.split("\n").map((line) => stringWidth(line) <= textWidth ? fillRow(line, textWidth) : line).join("\n");
|
|
879
|
+
return /* @__PURE__ */ jsxs(Box, { width: rowWidth > 0 ? rowWidth : void 0, children: [
|
|
880
|
+
/* @__PURE__ */ jsx2(
|
|
881
|
+
Text,
|
|
882
|
+
{
|
|
883
|
+
backgroundColor: theme.user.bgHex,
|
|
884
|
+
color: theme.user.prefixColor,
|
|
885
|
+
bold: true,
|
|
886
|
+
children: PREFIX
|
|
887
|
+
}
|
|
888
|
+
),
|
|
889
|
+
/* @__PURE__ */ jsx2(
|
|
890
|
+
Text,
|
|
891
|
+
{
|
|
892
|
+
backgroundColor: theme.user.bgHex,
|
|
893
|
+
color: dim ? theme.baseToken.color.textSubtle : theme.baseToken.color.textNormal,
|
|
894
|
+
children: body
|
|
895
|
+
}
|
|
896
|
+
)
|
|
897
|
+
] });
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/tui/components/chat-area/assistant-step-row.tsx
|
|
901
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
902
|
+
|
|
897
903
|
// src/tui/utils/permission-summary.ts
|
|
898
904
|
function shortenPath(p, maxSegments = 3) {
|
|
899
905
|
const segs = p.split("/").filter((s) => s.length > 0);
|
|
@@ -1098,14 +1104,17 @@ function summarizeWorkerMessage(argsJson, width, result, maxLines = 3) {
|
|
|
1098
1104
|
const message = args ? str(args.message) ?? "" : argsJson;
|
|
1099
1105
|
const { lines, hidden } = previewLines(message, maxLines, width);
|
|
1100
1106
|
const failed = result !== void 0 && (result.isError === true || /^\[ERROR\]/.test(result.text));
|
|
1107
|
+
let delivery;
|
|
1108
|
+
if (result !== void 0 && !failed) {
|
|
1109
|
+
delivery = /\bqueued\b/i.test(result.text) ? "queued" : /\bdelivered\b/i.test(result.text) ? "delivered" : void 0;
|
|
1110
|
+
}
|
|
1101
1111
|
return {
|
|
1102
1112
|
...workerId && { workerId },
|
|
1103
1113
|
lines,
|
|
1104
1114
|
hiddenLines: hidden,
|
|
1105
1115
|
outcome: result === void 0 ? "pending" : failed ? "failed" : "ok",
|
|
1106
1116
|
failure: failed ? failureText(result.text, width) : "",
|
|
1107
|
-
...
|
|
1108
|
-
...result !== void 0 && !failed && /\bdelivered\b/.test(result.text) && { delivery: "delivered" }
|
|
1117
|
+
...delivery && { delivery }
|
|
1109
1118
|
};
|
|
1110
1119
|
}
|
|
1111
1120
|
var TASK_ID_RE = /^Task (\S+) (?:added|assigned)/;
|
|
@@ -2442,7 +2451,7 @@ function AppContent() {
|
|
|
2442
2451
|
// package.json
|
|
2443
2452
|
var package_default = {
|
|
2444
2453
|
name: "wayang-ai",
|
|
2445
|
-
version: "0.6.
|
|
2454
|
+
version: "0.6.3",
|
|
2446
2455
|
description: "Multi-agent orchestration platform",
|
|
2447
2456
|
type: "module",
|
|
2448
2457
|
license: "MIT",
|
|
@@ -4531,18 +4540,39 @@ function controllerMessageContent(content) {
|
|
|
4531
4540
|
return `[Controller message] ${content}`;
|
|
4532
4541
|
}
|
|
4533
4542
|
function createInboxInjection(deps) {
|
|
4543
|
+
let baseLength = null;
|
|
4534
4544
|
const injected = [];
|
|
4535
4545
|
return {
|
|
4536
4546
|
prepareStep({ messages }) {
|
|
4537
4547
|
const fresh = deps.drainInbox();
|
|
4538
4548
|
if (fresh.length === 0 && injected.length === 0) return void 0;
|
|
4549
|
+
if (baseLength === null) baseLength = messages.length;
|
|
4550
|
+
const responseCount = Math.max(0, messages.length - baseLength);
|
|
4539
4551
|
for (const m of fresh) {
|
|
4540
|
-
injected.push({
|
|
4552
|
+
injected.push({
|
|
4553
|
+
message: { role: "user", content: controllerMessageContent(m.content) },
|
|
4554
|
+
// After the response messages that exist NOW — i.e. at the tail of
|
|
4555
|
+
// the conversation as this step sees it, before this step's reply.
|
|
4556
|
+
insertAfter: responseCount
|
|
4557
|
+
});
|
|
4541
4558
|
deps.onInject(m.content);
|
|
4542
4559
|
}
|
|
4543
|
-
|
|
4560
|
+
const merged = messages.slice(0, baseLength);
|
|
4561
|
+
let cursor = 0;
|
|
4562
|
+
for (const inj of injected) {
|
|
4563
|
+
while (cursor < Math.min(inj.insertAfter, responseCount)) {
|
|
4564
|
+
merged.push(messages[baseLength + cursor]);
|
|
4565
|
+
cursor++;
|
|
4566
|
+
}
|
|
4567
|
+
merged.push(inj.message);
|
|
4568
|
+
}
|
|
4569
|
+
while (cursor < responseCount) {
|
|
4570
|
+
merged.push(messages[baseLength + cursor]);
|
|
4571
|
+
cursor++;
|
|
4572
|
+
}
|
|
4573
|
+
return { messages: merged };
|
|
4544
4574
|
},
|
|
4545
|
-
injectedMessages: () =>
|
|
4575
|
+
injectedMessages: () => injected.map((i) => i.message)
|
|
4546
4576
|
};
|
|
4547
4577
|
}
|
|
4548
4578
|
|
|
@@ -4797,7 +4827,10 @@ The tool shows task metadata (status, result, error) and recent worker conversat
|
|
|
4797
4827
|
|
|
4798
4828
|
## Sending messages to workers (chat_worker)
|
|
4799
4829
|
|
|
4800
|
-
Use chat_worker(workerId, message) to send guidance to a running worker.
|
|
4830
|
+
Use chat_worker(workerId, message) to send guidance to a running worker.
|
|
4831
|
+
The worker reads it at its next step (puppet) or turn boundary (third-party) \u2014 a tool call in progress is NEVER interrupted; an idle multi-stage worker reads it when its next stage starts.
|
|
4832
|
+
Delivery is blind: "queued" only means the message sits in the worker's inbox until that boundary. A stuck worker never reads it.
|
|
4833
|
+
A third-party worker that already finished its session rejects the message with an explicit [ERROR] \u2014 inspect its output instead of retrying.
|
|
4801
4834
|
Use sparingly \u2014 only when you need to:
|
|
4802
4835
|
- Correct a worker that is going in the wrong direction
|
|
4803
4836
|
- Provide additional context the worker did not have
|
|
@@ -5266,7 +5299,11 @@ var WorkerAgent = class extends BaseAgent {
|
|
|
5266
5299
|
getSnapshot(path7) {
|
|
5267
5300
|
return this.state.get(path7);
|
|
5268
5301
|
}
|
|
5269
|
-
/**
|
|
5302
|
+
/**
|
|
5303
|
+
* Accept a message from the controller — writes to internal inbox. The
|
|
5304
|
+
* puppet reads it at its next LLM step, so a running (or idle) worker
|
|
5305
|
+
* always accepts.
|
|
5306
|
+
*/
|
|
5270
5307
|
acceptMessage(message) {
|
|
5271
5308
|
this.state.append("inbox", {
|
|
5272
5309
|
id: generateId("msg"),
|
|
@@ -5274,6 +5311,7 @@ var WorkerAgent = class extends BaseAgent {
|
|
|
5274
5311
|
timestamp: Date.now()
|
|
5275
5312
|
});
|
|
5276
5313
|
this.logger.info({ workerId: this.id }, "Controller message accepted");
|
|
5314
|
+
return true;
|
|
5277
5315
|
}
|
|
5278
5316
|
/** Unread controller messages (non-destructive) — engine reports these when the run ends. */
|
|
5279
5317
|
pendingMessages() {
|
|
@@ -5370,14 +5408,20 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5370
5408
|
// --- Controller messaging via streamInput ---
|
|
5371
5409
|
_messageQueue = [];
|
|
5372
5410
|
_messageResolve = null;
|
|
5373
|
-
/** Active SDK query — interrupted to deliver controller messages promptly. */
|
|
5374
|
-
_activeQuery = null;
|
|
5375
5411
|
/**
|
|
5376
|
-
*
|
|
5377
|
-
*
|
|
5378
|
-
*
|
|
5412
|
+
* True while run() is executing. Controller messages are rejected once the
|
|
5413
|
+
* run's input has closed (see `_inputClosed`), but idle multi-stage workers
|
|
5414
|
+
* (no run in flight) keep accepting — the next stage folds them into its
|
|
5415
|
+
* opening prompt.
|
|
5416
|
+
*/
|
|
5417
|
+
_runInFlight = false;
|
|
5418
|
+
/**
|
|
5419
|
+
* True once the prompt iterator reported done for the current run: the
|
|
5420
|
+
* session can no longer take input (a turn result arrived with nothing
|
|
5421
|
+
* queued, or the run was aborted). Further acceptMessage calls fail
|
|
5422
|
+
* explicitly instead of pretending to queue.
|
|
5379
5423
|
*/
|
|
5380
|
-
|
|
5424
|
+
_inputClosed = false;
|
|
5381
5425
|
// --- ask_controller via in-process SDK MCP server ---
|
|
5382
5426
|
_askController = null;
|
|
5383
5427
|
// --- Permission control via canUseTool ---
|
|
@@ -5386,31 +5430,17 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5386
5430
|
/** Exposed for engine to resolve pending permission requests. */
|
|
5387
5431
|
permissionHandler = {
|
|
5388
5432
|
resolvePermission: (requestId, approved, reason) => {
|
|
5389
|
-
|
|
5433
|
+
return this._pendingPermissions.resolve(
|
|
5390
5434
|
requestId,
|
|
5391
5435
|
approved ? { behavior: "allow" } : { behavior: "deny", message: reason ?? "Denied by controller" }
|
|
5392
5436
|
);
|
|
5393
|
-
if (ok) this.afterPermissionSettled();
|
|
5394
|
-
return ok;
|
|
5395
5437
|
},
|
|
5396
5438
|
cleanup: () => {
|
|
5397
|
-
this._interruptQueued = false;
|
|
5398
5439
|
this._pendingPermissions.cleanupAll(() => ({ behavior: "deny", message: "Worker aborted" }));
|
|
5399
5440
|
},
|
|
5400
5441
|
wrappedTools: {}
|
|
5401
5442
|
// not used for ClaudeCodeWorker
|
|
5402
5443
|
};
|
|
5403
|
-
/**
|
|
5404
|
-
* A permission settled (approved / denied / timed out). If a controller
|
|
5405
|
-
* message was waiting for the permission window to close, deliver its
|
|
5406
|
-
* interrupt now — this runs on BOTH the resolve and the timeout path.
|
|
5407
|
-
*/
|
|
5408
|
-
afterPermissionSettled() {
|
|
5409
|
-
if (this._interruptQueued && this._pendingPermissions.size === 0) {
|
|
5410
|
-
this._interruptQueued = false;
|
|
5411
|
-
this.requestInterrupt();
|
|
5412
|
-
}
|
|
5413
|
-
}
|
|
5414
5444
|
// Signal context set during run()
|
|
5415
5445
|
_signalQueue = null;
|
|
5416
5446
|
_runContext = null;
|
|
@@ -5457,6 +5487,8 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5457
5487
|
}
|
|
5458
5488
|
async run(task, _tools, onProgress) {
|
|
5459
5489
|
this._terminalResult = null;
|
|
5490
|
+
this._inputClosed = false;
|
|
5491
|
+
this._runInFlight = true;
|
|
5460
5492
|
this.state.set("runtimeState.task", { id: task.id, description: task.description });
|
|
5461
5493
|
const turnEnv = this.buildTurnEnv(task);
|
|
5462
5494
|
this._currentTurnEnv = turnEnv;
|
|
@@ -5514,18 +5546,17 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5514
5546
|
prompt: this.buildPromptIterable(task.description),
|
|
5515
5547
|
options
|
|
5516
5548
|
});
|
|
5517
|
-
this._activeQuery = stream;
|
|
5518
5549
|
try {
|
|
5519
5550
|
for await (const message of stream) {
|
|
5520
5551
|
if (this.abortController.signal.aborted) break;
|
|
5521
5552
|
this.processStreamMessage(message, onProgress);
|
|
5522
|
-
if (this._terminalResult) break;
|
|
5523
5553
|
}
|
|
5524
5554
|
} finally {
|
|
5525
|
-
this.
|
|
5555
|
+
this._inputClosed = true;
|
|
5526
5556
|
}
|
|
5527
5557
|
} catch (err) {
|
|
5528
5558
|
this.logger.error({ err, taskId: task.id }, "ClaudeCodeWorker query error");
|
|
5559
|
+
this._inputClosed = true;
|
|
5529
5560
|
if (!this._terminalResult) {
|
|
5530
5561
|
this._terminalResult = {
|
|
5531
5562
|
status: "failed",
|
|
@@ -5552,6 +5583,7 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5552
5583
|
startedAt: resultTs,
|
|
5553
5584
|
endedAt: resultTs
|
|
5554
5585
|
}, turnEnv));
|
|
5586
|
+
this._runInFlight = false;
|
|
5555
5587
|
return this._terminalResult;
|
|
5556
5588
|
}
|
|
5557
5589
|
/** Set signal context for permission requests. Called by engine before run(). */
|
|
@@ -5580,34 +5612,36 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5580
5612
|
getSnapshot(path7) {
|
|
5581
5613
|
return this.state.get(path7);
|
|
5582
5614
|
}
|
|
5583
|
-
/**
|
|
5615
|
+
/**
|
|
5616
|
+
* Accept a message from the controller. The message is queued and handed
|
|
5617
|
+
* to the SDK only when it pulls the next prompt: the CLI parks pulled
|
|
5618
|
+
* prompts in an internal queue that it drains strictly BETWEEN turns, so
|
|
5619
|
+
* delivery always lands on a turn boundary — a tool call in progress is
|
|
5620
|
+
* never cut off (the v0.6 interrupt delivery did exactly that and killed
|
|
5621
|
+
* the session with an orphaned tool_use; see docs/develop/v0.6-design.md
|
|
5622
|
+
* §6.1 — the hazard is any unclosed tool_use, not just a pending
|
|
5623
|
+
* permission).
|
|
5624
|
+
*
|
|
5625
|
+
* Returns false when delivery is impossible: the run's input has closed
|
|
5626
|
+
* (final result received) or the worker was aborted. Idle multi-stage
|
|
5627
|
+
* workers (no run in flight) always accept — the next stage folds the
|
|
5628
|
+
* message into its opening prompt.
|
|
5629
|
+
*/
|
|
5584
5630
|
acceptMessage(message) {
|
|
5631
|
+
if (this.abortController.signal.aborted) return false;
|
|
5632
|
+
if (this._runInFlight && this._inputClosed) return false;
|
|
5585
5633
|
this._messageQueue.push(message);
|
|
5586
5634
|
if (this._messageResolve) {
|
|
5587
5635
|
this._messageResolve();
|
|
5588
5636
|
this._messageResolve = null;
|
|
5589
5637
|
}
|
|
5590
|
-
if ((this.config.interruptOnMessage ?? "immediate") === "immediate") {
|
|
5591
|
-
this.requestInterrupt();
|
|
5592
|
-
}
|
|
5593
5638
|
this.logger.info({ workerId: this.id }, "Controller message accepted");
|
|
5639
|
+
return true;
|
|
5594
5640
|
}
|
|
5595
5641
|
/** Unread controller messages (non-destructive) — engine reports these when the run ends. */
|
|
5596
5642
|
pendingMessages() {
|
|
5597
5643
|
return [...this._messageQueue];
|
|
5598
5644
|
}
|
|
5599
|
-
/** Interrupt the active query unless a permission is pending (queued until it settles). */
|
|
5600
|
-
requestInterrupt() {
|
|
5601
|
-
if (this.abortController.signal.aborted || !this._activeQuery) return;
|
|
5602
|
-
if (this._pendingPermissions.size > 0) {
|
|
5603
|
-
this._interruptQueued = true;
|
|
5604
|
-
return;
|
|
5605
|
-
}
|
|
5606
|
-
if (typeof this._activeQuery.interrupt !== "function") return;
|
|
5607
|
-
this._activeQuery.interrupt().catch((err) => {
|
|
5608
|
-
this.logger.warn({ workerId: this.id, err: String(err) }, "interrupt() failed");
|
|
5609
|
-
});
|
|
5610
|
-
}
|
|
5611
5645
|
/**
|
|
5612
5646
|
* Provide the engine-backed ask_controller implementation. Once set, the
|
|
5613
5647
|
* worker exposes it to Claude Code as an in-process SDK MCP tool.
|
|
@@ -5645,9 +5679,7 @@ var ClaudeCodeWorker = class _ClaudeCodeWorker {
|
|
|
5645
5679
|
...this._turnLineage
|
|
5646
5680
|
});
|
|
5647
5681
|
return this._pendingPermissions.wait(requestId, _ClaudeCodeWorker.PERMISSION_TIMEOUT_MS, () => {
|
|
5648
|
-
|
|
5649
|
-
this.afterPermissionSettled();
|
|
5650
|
-
return value;
|
|
5682
|
+
return { behavior: "deny", message: "Permission request timed out" };
|
|
5651
5683
|
});
|
|
5652
5684
|
}
|
|
5653
5685
|
// --- Prompt as AsyncIterable (supports follow-up messages) ---
|
|
@@ -5674,13 +5706,22 @@ ${leftoverText}` : `${buildThirdPartyPrompt(this.skills)}${initialPrompt}`;
|
|
|
5674
5706
|
};
|
|
5675
5707
|
}
|
|
5676
5708
|
while (true) {
|
|
5677
|
-
if (this.abortController.signal.aborted
|
|
5709
|
+
if (this.abortController.signal.aborted) {
|
|
5710
|
+
this._inputClosed = true;
|
|
5678
5711
|
return { value: void 0, done: true };
|
|
5679
5712
|
}
|
|
5680
|
-
if (this.
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5713
|
+
if (this._terminalResult) {
|
|
5714
|
+
if (this._messageQueue.length === 0) {
|
|
5715
|
+
this._inputClosed = true;
|
|
5716
|
+
return { value: void 0, done: true };
|
|
5717
|
+
}
|
|
5718
|
+
} else if (this._messageQueue.length === 0) {
|
|
5719
|
+
await new Promise((resolve11) => {
|
|
5720
|
+
this._messageResolve = resolve11;
|
|
5721
|
+
});
|
|
5722
|
+
continue;
|
|
5723
|
+
}
|
|
5724
|
+
break;
|
|
5684
5725
|
}
|
|
5685
5726
|
const msg = this._messageQueue.shift();
|
|
5686
5727
|
return {
|
|
@@ -6347,7 +6388,7 @@ function updateProgressTool(deps) {
|
|
|
6347
6388
|
import { z as z23 } from "zod";
|
|
6348
6389
|
function chatWorkerTool(deps) {
|
|
6349
6390
|
return defineTool({
|
|
6350
|
-
description:
|
|
6391
|
+
description: `Send a message to a running worker. Use this to provide additional guidance, correct the worker's approach, or ask the worker to check something. The worker reads it at its next step (puppet) or turn boundary (third-party); idle multi-stage workers read it when their next stage starts. A third-party worker NEVER acts on the message mid-tool-call: it finishes the current turn first, so "queued" can mean a delay of minutes. If the worker has already finished, this tool fails explicitly \u2014 inspect its output instead.`,
|
|
6351
6392
|
parameters: z23.object({
|
|
6352
6393
|
workerId: z23.string().describe("ID of the target worker"),
|
|
6353
6394
|
message: z23.string().describe("Message to send to the worker")
|
|
@@ -6357,8 +6398,11 @@ function chatWorkerTool(deps) {
|
|
|
6357
6398
|
if (status === "not_running") {
|
|
6358
6399
|
return `[ERROR] Worker ${workerId} is not running (it may have just finished).`;
|
|
6359
6400
|
}
|
|
6401
|
+
if (status === "finished") {
|
|
6402
|
+
return `[ERROR] Worker ${workerId} has already finished; message not delivered. Use get_task_detail to inspect its output.`;
|
|
6403
|
+
}
|
|
6360
6404
|
if (status === "queued") {
|
|
6361
|
-
return `Message queued for worker ${workerId} \u2014 it
|
|
6405
|
+
return `Message queued for worker ${workerId} \u2014 QUEUED only, not delivered yet: the worker reads it at its next step (puppet), turn boundary (third-party \u2014 the current turn, including any running tool call, finishes first) or next stage start (idle). A stuck worker will never reach that point. Verify with get_task_detail before relying on it; if it looks stuck, use cancel_task instead of waiting for this message.`;
|
|
6362
6406
|
}
|
|
6363
6407
|
return `Message delivered to worker ${workerId} \u2014 it will be read at the worker's next step.`;
|
|
6364
6408
|
})
|
|
@@ -6879,14 +6923,16 @@ var TaskExecuteEngine = class {
|
|
|
6879
6923
|
* Send a message to a worker. Delivery is judged by the activeWorkers
|
|
6880
6924
|
* runtime state — NOT by the workers Map, which lingers one tick past
|
|
6881
6925
|
* disposal (removeWorkerTracking defers) and would accept messages for a
|
|
6882
|
-
* worker that is already gone.
|
|
6926
|
+
* worker that is already gone. A worker that rejects the message (its run
|
|
6927
|
+
* can no longer take input) is reported as 'finished' — never a fake
|
|
6928
|
+
* 'queued'.
|
|
6883
6929
|
*/
|
|
6884
6930
|
sendMessageToWorker(workerId, message) {
|
|
6885
6931
|
const info = this.getActiveWorkers().find((w) => w.workerId === workerId);
|
|
6886
6932
|
if (!info) return "not_running";
|
|
6887
6933
|
const worker = this.workers.get(workerId);
|
|
6888
6934
|
if (!worker) return "not_running";
|
|
6889
|
-
worker.acceptMessage(message);
|
|
6935
|
+
if (!worker.acceptMessage(message)) return "finished";
|
|
6890
6936
|
if (info.status === "idle") return "queued";
|
|
6891
6937
|
return worker instanceof WorkerAgent ? "delivered" : "queued";
|
|
6892
6938
|
}
|
|
@@ -7550,7 +7596,7 @@ var ControllerLoop = class {
|
|
|
7550
7596
|
this.signalQueue = signalQueue;
|
|
7551
7597
|
this.controllerAgent = controllerAgent;
|
|
7552
7598
|
this.heartbeatProvider = heartbeatProvider;
|
|
7553
|
-
this.heartbeatIntervalMs = options?.heartbeatIntervalMs ??
|
|
7599
|
+
this.heartbeatIntervalMs = options?.heartbeatIntervalMs ?? 6e4;
|
|
7554
7600
|
}
|
|
7555
7601
|
ctx;
|
|
7556
7602
|
signalQueue;
|
|
@@ -9239,8 +9285,11 @@ async function runWayangServer(options, io = process) {
|
|
|
9239
9285
|
return { status };
|
|
9240
9286
|
});
|
|
9241
9287
|
rpc.register(METHOD.CHAT_WORKER, (params) => {
|
|
9242
|
-
supervisor.engine.sendMessageToWorker(
|
|
9243
|
-
|
|
9288
|
+
const status = supervisor.engine.sendMessageToWorker(
|
|
9289
|
+
requiredString(params, "workerId"),
|
|
9290
|
+
requiredString(params, "message")
|
|
9291
|
+
);
|
|
9292
|
+
return { status };
|
|
9244
9293
|
});
|
|
9245
9294
|
rpc.register(METHOD.DISPOSE_WORKER, (params) => {
|
|
9246
9295
|
supervisor.engine.abortByWorkerId(requiredString(params, "workerId"));
|