@zq-silk/yui 0.13.8 → 0.13.9
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 +9 -8
- package/dist/cli/commandCatalog.js +21 -2
- package/dist/cli.js +42 -13
- package/dist/commands/agentCommands.js +1 -1
- package/dist/commands/configCommands.js +1 -86
- package/dist/commands/executionAuditCommands.js +17 -16
- package/dist/commands/globalRoleCommands.js +4 -4
- package/dist/commands/sessionCommands.js +2 -6
- package/dist/commands/taskActor.js +1 -2
- package/dist/commands/taskCommands.js +92 -9
- package/dist/commands/taskRoleRuntimeStatus.js +3 -3
- package/dist/config/configCatalog.js +1 -6
- package/dist/config/yuiConfig.js +0 -79
- package/dist/controller/clientRuntime.js +40 -3
- package/dist/controller/controller.js +29 -52
- package/dist/controller/fileSchedulerStoreAdapter.js +305 -1056
- package/dist/controller/runtime.js +12 -5
- package/dist/controller/runtimeHookRunFence.js +3 -9
- package/dist/controller/runtimeLaunchCoordinator.js +44 -67
- package/dist/controller/structuredProviderObservation.js +18 -5
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/execution/executionHealth.js +1 -1
- package/dist/executor/agentExecutor.js +92 -68
- package/dist/executor/executorRegistry.js +8 -20
- package/dist/executor/fileRoleLaunchPlanner.js +24 -90
- package/dist/executor/turnCompletion.js +5 -5
- package/dist/lifecycle/exactRunTerminalization.js +1 -1
- package/dist/observability/executionAudit.js +40 -94
- package/dist/operator/operatorSessionHistory.js +7 -5
- package/dist/role/role.js +1 -1
- package/dist/run/agentRun.js +4 -54
- package/dist/runtime/agentDriver.js +2 -0
- package/dist/runtime/agentError.js +114 -0
- package/dist/runtime/agentHost.js +55 -82
- package/dist/runtime/builtinAgentDrivers.js +21 -9
- package/dist/runtime/builtinAgentErrorMappers.js +150 -0
- package/dist/runtime/exactControlPlane.js +6 -12
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/launchBroker.js +5 -19
- package/dist/runtime/lifecycleReservation.js +20 -4
- package/dist/runtime/providerRuntimeIdentity.js +3 -2
- package/dist/runtime/runtimeBinding.js +0 -27
- package/dist/runtime/runtimeObservation.js +7 -16
- package/dist/runtime/runtimeSessionCandidate.js +3 -10
- package/dist/runtime/sessionLaunchRequest.js +1 -2
- package/dist/runtime/sessionReconciliation.js +2 -2
- package/dist/runtime/structuredProviderHost.js +44 -79
- package/dist/runtime/taskRuntimeIsolation.js +0 -7
- package/dist/runtime/tmuxAdapters.js +6 -49
- package/dist/scheduler/activeRoleRunDelivery.js +218 -168
- package/dist/scheduler/leaderWakeupProcessor.js +126 -86
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +7 -11
- package/dist/scheduler/wakeReason.js +4 -0
- package/dist/storage/migration/productionRegistry.js +332 -0
- package/dist/storage/sqliteSchema.js +54 -2
- package/dist/storage/sqliteStore.js +11 -44
- package/dist/storage/taskStore.js +7 -35
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +30 -8
- package/skills/yui-operator/SKILL.md +14 -6
- package/skills/yui-runtime/SKILL.md +6 -4
- package/dist/lifecycle/providerErrorClass.js +0 -152
- package/dist/run/providerRetry.js +0 -226
- package/dist/run/providerRetryConfig.js +0 -27
- package/dist/runtime/providerErrorCodes.js +0 -278
- package/dist/runtime/providerRecoveryDecision.js +0 -55
|
@@ -5,27 +5,6 @@ export function createRuntimeBinding(input) {
|
|
|
5
5
|
const hostCreated = input.hostCreated === undefined
|
|
6
6
|
? undefined
|
|
7
7
|
: requireBoolean(input.hostCreated, "Runtime host-created flag");
|
|
8
|
-
const initialTurnRunId = input.initialTurnRunId === undefined
|
|
9
|
-
? undefined
|
|
10
|
-
: requireSafeIdentity(input.initialTurnRunId, "Initial Turn Run id");
|
|
11
|
-
const initialTurnDeliveryUnknownRunId = input.initialTurnDeliveryUnknownRunId === undefined
|
|
12
|
-
? undefined
|
|
13
|
-
: requireSafeIdentity(input.initialTurnDeliveryUnknownRunId, "Delivery-unknown initial Turn Run id");
|
|
14
|
-
const initialTurnRejectedRunId = input.initialTurnRejectedRunId === undefined
|
|
15
|
-
? undefined
|
|
16
|
-
: requireSafeIdentity(input.initialTurnRejectedRunId, "Rejected initial Turn Run id");
|
|
17
|
-
const initialTurnBusyRunId = input.initialTurnBusyRunId === undefined
|
|
18
|
-
? undefined
|
|
19
|
-
: requireSafeIdentity(input.initialTurnBusyRunId, "Busy initial Turn Run id");
|
|
20
|
-
if ([
|
|
21
|
-
initialTurnRunId,
|
|
22
|
-
initialTurnDeliveryUnknownRunId,
|
|
23
|
-
initialTurnBusyRunId,
|
|
24
|
-
initialTurnRejectedRunId
|
|
25
|
-
]
|
|
26
|
-
.filter((value) => value !== undefined).length > 1) {
|
|
27
|
-
throw new TypeError("Runtime binding must report at most one initial Turn outcome.");
|
|
28
|
-
}
|
|
29
8
|
return {
|
|
30
9
|
id: requireSafeIdentity(input.id, "Runtime binding id"),
|
|
31
10
|
launchId: requireSafeIdentity(input.launchId, "Launch id"),
|
|
@@ -34,12 +13,6 @@ export function createRuntimeBinding(input) {
|
|
|
34
13
|
adapterId: requireSafeIdentity(input.adapterId, "Agent adapter id"),
|
|
35
14
|
hostRef: requireText(input.hostRef, "Session host reference"),
|
|
36
15
|
...(hostCreated === undefined ? {} : { hostCreated }),
|
|
37
|
-
...(initialTurnRunId === undefined ? {} : { initialTurnRunId }),
|
|
38
|
-
...(initialTurnDeliveryUnknownRunId === undefined
|
|
39
|
-
? {}
|
|
40
|
-
: { initialTurnDeliveryUnknownRunId }),
|
|
41
|
-
...(initialTurnBusyRunId === undefined ? {} : { initialTurnBusyRunId }),
|
|
42
|
-
...(initialTurnRejectedRunId === undefined ? {} : { initialTurnRejectedRunId }),
|
|
43
16
|
...(input.nativeSessionId === undefined
|
|
44
17
|
? {}
|
|
45
18
|
: { nativeSessionId: requireText(input.nativeSessionId, "Native session id") }),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { requireDriverId } from "./agentDriver.js";
|
|
3
|
+
import { isStandardAgentError } from "./agentError.js";
|
|
3
4
|
export const RUNTIME_OBSERVATION_TASK_EVENT = "runtime.observation";
|
|
4
5
|
/**
|
|
5
6
|
* Numeric usage and value-less partial request boundaries are both durable
|
|
@@ -435,7 +436,7 @@ export function runtimeObservationSemanticKey(input) {
|
|
|
435
436
|
...continuationIdentity,
|
|
436
437
|
fence.continuationId ?? fence.nativeTurnId ?? "none",
|
|
437
438
|
input.kind,
|
|
438
|
-
input.payload?.outcome ?? input.payload?.failure?.code ?? "terminal",
|
|
439
|
+
input.payload?.outcome ?? input.payload?.failure?.error.code ?? "terminal",
|
|
439
440
|
input.kind === "continuation.settled" ? input.payload?.resultRef ?? "none" : "none",
|
|
440
441
|
input.kind === "turn.failed" && input.payload?.failure?.runTerminal === true
|
|
441
442
|
? "run-terminal"
|
|
@@ -494,21 +495,17 @@ function normalizeFailure(input) {
|
|
|
494
495
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
495
496
|
throw new Error("Runtime failure evidence must be an object.");
|
|
496
497
|
}
|
|
498
|
+
if (!isStandardAgentError(input.error)) {
|
|
499
|
+
throw new Error("Runtime failure requires a standard Agent error.");
|
|
500
|
+
}
|
|
497
501
|
return Object.freeze({
|
|
498
|
-
|
|
499
|
-
code: requireText(input.code, "Runtime failure code"),
|
|
500
|
-
...(input.details === undefined
|
|
501
|
-
? {}
|
|
502
|
-
: { details: requireText(input.details, "Runtime failure details") }),
|
|
502
|
+
error: Object.freeze({ ...input.error }),
|
|
503
503
|
...(input.lastOutput === undefined
|
|
504
504
|
? {}
|
|
505
505
|
: { lastOutput: requireText(input.lastOutput, "Runtime failure last output") }),
|
|
506
506
|
...(input.runTerminal === undefined
|
|
507
507
|
? {}
|
|
508
|
-
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") })
|
|
509
|
-
...(input.retryAfterMs === undefined
|
|
510
|
-
? {}
|
|
511
|
-
: { retryAfterMs: requirePositiveMilliseconds(input.retryAfterMs) })
|
|
508
|
+
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") })
|
|
512
509
|
});
|
|
513
510
|
}
|
|
514
511
|
function requireBoolean(value, label) {
|
|
@@ -516,12 +513,6 @@ function requireBoolean(value, label) {
|
|
|
516
513
|
throw new Error(`${label} must be boolean.`);
|
|
517
514
|
return value;
|
|
518
515
|
}
|
|
519
|
-
function requirePositiveMilliseconds(value) {
|
|
520
|
-
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
521
|
-
throw new Error("Runtime failure retryAfterMs must be a positive safe integer.");
|
|
522
|
-
}
|
|
523
|
-
return value;
|
|
524
|
-
}
|
|
525
516
|
function validateUsage(input) {
|
|
526
517
|
if (!["cumulative-session", "request-context", "remaining-context"].includes(input.semantics)) {
|
|
527
518
|
throw new Error("Runtime usage semantics are invalid.");
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { activeRoleAgentSession } from "../executor/agentExecutor.js";
|
|
2
|
-
/**
|
|
3
|
-
export function runtimeSessionRequiresCleanup(input) {
|
|
4
|
-
if (input.status === "stopped" || input.status === "broken")
|
|
5
|
-
return false;
|
|
6
|
-
return input.status === "running" || input.launchId !== undefined;
|
|
7
|
-
}
|
|
8
|
-
/** Projects only the current active Agent Session; stopped history disappears. */
|
|
2
|
+
/** Projects only the current active Agent Session; ended history disappears. */
|
|
9
3
|
export function projectRuntimeSessionCandidate(sessions) {
|
|
10
4
|
const active = activeRoleAgentSession(sessions);
|
|
11
|
-
if (active === null || active.status === "
|
|
5
|
+
if (active === null || active.status === "ended")
|
|
12
6
|
return null;
|
|
13
7
|
return {
|
|
14
8
|
owner: sessions.owner.scope === "task"
|
|
@@ -22,9 +16,8 @@ export function projectRuntimeSessionCandidate(sessions) {
|
|
|
22
16
|
adapterId: active.adapterId,
|
|
23
17
|
nativeSessionId: active.nativeSessionId,
|
|
24
18
|
...(active.launchId === undefined ? {} : { launchId: active.launchId }),
|
|
25
|
-
status: active.status,
|
|
26
19
|
sessionUpdatedAt: active.updatedAt,
|
|
27
|
-
cleanupRequired:
|
|
20
|
+
cleanupRequired: active.launchId !== undefined
|
|
28
21
|
};
|
|
29
22
|
}
|
|
30
23
|
/** Deterministic owner order shared by all storage backends. */
|
|
@@ -18,8 +18,7 @@ export function createSessionLaunchRequest(input) {
|
|
|
18
18
|
if (runtimeIsolation !== undefined && (input.owner.scope !== "task"
|
|
19
19
|
|| runtimeIsolation.taskId !== input.owner.taskId
|
|
20
20
|
|| runtimeIsolation.workspace.root !== workspace
|
|
21
|
-
|| runtimeIsolation.generation.launchId !== input.launchId
|
|
22
|
-
|| runtimeIsolation.generation.runId !== input.runId)) {
|
|
21
|
+
|| runtimeIsolation.generation.launchId !== input.launchId)) {
|
|
23
22
|
throw new TypeError("Session launch request does not match its Task runtime isolation descriptor.");
|
|
24
23
|
}
|
|
25
24
|
const common = {
|
|
@@ -41,14 +41,14 @@ function reconcileOne(record, input) {
|
|
|
41
41
|
mismatch = "identity-conflict";
|
|
42
42
|
}
|
|
43
43
|
else if (physical?.alive === true) {
|
|
44
|
-
if (durable === undefined || durable.status === "
|
|
44
|
+
if (durable === undefined || durable.status === "ended") {
|
|
45
45
|
mismatch = "durable-terminal-physical-live";
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
else if (physical === undefined) {
|
|
49
49
|
verificationGap = "/proc identity unavailable";
|
|
50
50
|
}
|
|
51
|
-
else if (durable !== undefined && durable.status === "
|
|
51
|
+
else if (durable !== undefined && durable.status === "active") {
|
|
52
52
|
mismatch = "durable-live-physical-absent";
|
|
53
53
|
}
|
|
54
54
|
const terminalTask = taskStatus === "completed"
|
|
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { Duplex } from "node:stream";
|
|
4
4
|
import WebSocket from "ws";
|
|
5
5
|
import { CodexAppServerRequestError, CodexAppServerRuntime, codexAppServerErrorIsMissing } from "./codexAppServerRuntime.js";
|
|
6
|
+
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
6
7
|
import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
|
|
7
8
|
import { YUI_VERSION } from "../version.js";
|
|
8
9
|
const PROVIDER_MESSAGE_MAX_BYTES = 16 * 1024 * 1024;
|
|
@@ -399,7 +400,7 @@ class CodexStructuredProviderSession {
|
|
|
399
400
|
}
|
|
400
401
|
const session = new CodexStructuredProviderSession(child, exit, processInstanceId, conversationId, runtime, onTerminal);
|
|
401
402
|
session.#activeTurnId = resumedActiveTurnId;
|
|
402
|
-
const ownedTurn = control.kind === "
|
|
403
|
+
const ownedTurn = control.kind === "restore" ? control.ownedTurn : undefined;
|
|
403
404
|
session.#clientOwnedTurnId = ownedTurn?.turnId;
|
|
404
405
|
stopOpeningBuffer();
|
|
405
406
|
let recoveredTerminal;
|
|
@@ -426,7 +427,12 @@ class CodexStructuredProviderSession {
|
|
|
426
427
|
? "failed"
|
|
427
428
|
: recovered.status === "interrupted" ? "cancelled" : "completed",
|
|
428
429
|
observedAt: new Date().toISOString(),
|
|
429
|
-
...(recovered.
|
|
430
|
+
...(recovered.status !== "failed"
|
|
431
|
+
? {}
|
|
432
|
+
: {
|
|
433
|
+
error: recovered.error ?? "Provider Turn failed.",
|
|
434
|
+
rawError: serializeAgentErrorRaw(recovered)
|
|
435
|
+
})
|
|
430
436
|
};
|
|
431
437
|
session.#clientOwnedTurnId = undefined;
|
|
432
438
|
}
|
|
@@ -459,13 +465,16 @@ class CodexStructuredProviderSession {
|
|
|
459
465
|
const status = turn.status === "failed"
|
|
460
466
|
? "failed"
|
|
461
467
|
: turn.status === "interrupted" ? "cancelled" : "completed";
|
|
468
|
+
const failure = status === "failed"
|
|
469
|
+
? providerErrorEvidence(turn.error)
|
|
470
|
+
: undefined;
|
|
462
471
|
const terminal = {
|
|
463
472
|
conversationId: this.conversationId,
|
|
464
473
|
nativeSessionId: this.conversationId,
|
|
465
474
|
nativeTurnId,
|
|
466
475
|
status,
|
|
467
476
|
observedAt: new Date().toISOString(),
|
|
468
|
-
...(
|
|
477
|
+
...(failure === undefined ? {} : failure)
|
|
469
478
|
};
|
|
470
479
|
if (this.#submissionPending && emit) {
|
|
471
480
|
this.#bufferedTerminals.push(terminal);
|
|
@@ -546,7 +555,6 @@ class ClaudeStructuredProviderSession {
|
|
|
546
555
|
channel;
|
|
547
556
|
adapterId = "claude";
|
|
548
557
|
#activeTurnId;
|
|
549
|
-
#waiter;
|
|
550
558
|
constructor(child, exit, processInstanceId, conversationId, channel) {
|
|
551
559
|
this.child = child;
|
|
552
560
|
this.exit = exit;
|
|
@@ -562,14 +570,6 @@ class ClaudeStructuredProviderSession {
|
|
|
562
570
|
}
|
|
563
571
|
const session = new ClaudeStructuredProviderSession(child, exit, processInstanceId, nativeSessionId, channel);
|
|
564
572
|
channel.onMessage((message) => session.#receive(message, onTerminal));
|
|
565
|
-
exit.then(() => {
|
|
566
|
-
const waiter = session.#waiter;
|
|
567
|
-
if (waiter === undefined)
|
|
568
|
-
return;
|
|
569
|
-
clearTimeout(waiter.timer);
|
|
570
|
-
session.#waiter = undefined;
|
|
571
|
-
waiter.reject(new ProviderDeliveryUnknownError("Claude process exited before replaying the submitted user message.", waiter.attemptId));
|
|
572
|
-
}).catch(() => { });
|
|
573
573
|
return session;
|
|
574
574
|
}
|
|
575
575
|
get nativeSessionId() {
|
|
@@ -579,24 +579,9 @@ class ClaudeStructuredProviderSession {
|
|
|
579
579
|
return this.#activeTurnId;
|
|
580
580
|
}
|
|
581
581
|
async submitTurn(turn) {
|
|
582
|
-
if (this.#activeTurnId !== undefined
|
|
582
|
+
if (this.#activeTurnId !== undefined) {
|
|
583
583
|
throw new ProviderTurnRejectedError("Provider Conversation already has an unsettled Turn.", turn.attemptId);
|
|
584
584
|
}
|
|
585
|
-
let deliveryTimer;
|
|
586
|
-
const receipt = new Promise((resolvePromise, reject) => {
|
|
587
|
-
deliveryTimer = setTimeout(() => {
|
|
588
|
-
if (this.#waiter?.attemptId === turn.attemptId)
|
|
589
|
-
this.#waiter = undefined;
|
|
590
|
-
reject(new ProviderDeliveryUnknownError("Claude did not replay the submitted user message before the acknowledgement deadline.", turn.attemptId));
|
|
591
|
-
}, PROVIDER_ACCEPT_TIMEOUT_MS);
|
|
592
|
-
this.#waiter = {
|
|
593
|
-
attemptId: turn.attemptId,
|
|
594
|
-
text: turn.boundedText,
|
|
595
|
-
resolve: resolvePromise,
|
|
596
|
-
reject,
|
|
597
|
-
timer: deliveryTimer
|
|
598
|
-
};
|
|
599
|
-
});
|
|
600
585
|
try {
|
|
601
586
|
await this.channel.send({
|
|
602
587
|
type: "user",
|
|
@@ -607,12 +592,22 @@ class ClaudeStructuredProviderSession {
|
|
|
607
592
|
});
|
|
608
593
|
}
|
|
609
594
|
catch (error) {
|
|
610
|
-
|
|
611
|
-
clearTimeout(deliveryTimer);
|
|
612
|
-
this.#waiter = undefined;
|
|
613
|
-
throw new ProviderDeliveryUnknownError(`Claude input write did not produce an exact replay acknowledgement: ${error instanceof Error ? error.message : String(error)}`, turn.attemptId);
|
|
595
|
+
throw new ProviderDeliveryUnknownError(`Claude input write did not complete: ${error instanceof Error ? error.message : String(error)}`, turn.attemptId);
|
|
614
596
|
}
|
|
615
|
-
|
|
597
|
+
// AgentHost is the sole writer to this dedicated stream-json process.
|
|
598
|
+
// A completed pipe write is the smallest reliable acceptance boundary;
|
|
599
|
+
// Claude's later `result` is the matching terminal for this serialized
|
|
600
|
+
// Turn. Requiring an echoed user-message creates a second, brittle
|
|
601
|
+
// protocol without improving delivery safety.
|
|
602
|
+
const nativeTurnId = `claude-stream:${turn.attemptId}`;
|
|
603
|
+
this.#activeTurnId = nativeTurnId;
|
|
604
|
+
return Object.freeze({
|
|
605
|
+
attemptId: turn.attemptId,
|
|
606
|
+
conversationId: this.conversationId,
|
|
607
|
+
nativeSessionId: this.conversationId,
|
|
608
|
+
nativeTurnId,
|
|
609
|
+
acceptedAt: new Date().toISOString()
|
|
610
|
+
});
|
|
616
611
|
}
|
|
617
612
|
waitForExit() {
|
|
618
613
|
return this.exit;
|
|
@@ -621,42 +616,17 @@ class ClaudeStructuredProviderSession {
|
|
|
621
616
|
terminateProcessGroup(this.child, signal);
|
|
622
617
|
}
|
|
623
618
|
#receive(message, onTerminal) {
|
|
624
|
-
if (message.type === "user")
|
|
625
|
-
const waiter = this.#waiter;
|
|
626
|
-
if (waiter === undefined || claudeUserText(message) !== waiter.text)
|
|
627
|
-
return;
|
|
628
|
-
const observedSessionId = optionalId(message.session_id);
|
|
629
|
-
if (observedSessionId !== this.conversationId) {
|
|
630
|
-
clearTimeout(waiter.timer);
|
|
631
|
-
this.#waiter = undefined;
|
|
632
|
-
waiter.reject(new ProviderDeliveryUnknownError("Claude replayed input for a different native Session.", waiter.attemptId));
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
const nativeTurnId = optionalId(message.uuid);
|
|
636
|
-
if (nativeTurnId === undefined) {
|
|
637
|
-
clearTimeout(waiter.timer);
|
|
638
|
-
this.#waiter = undefined;
|
|
639
|
-
waiter.reject(new ProviderDeliveryUnknownError("Claude replayed input without a native message identity.", waiter.attemptId));
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
this.#activeTurnId = nativeTurnId;
|
|
643
|
-
clearTimeout(waiter.timer);
|
|
644
|
-
this.#waiter = undefined;
|
|
645
|
-
waiter.resolve(Object.freeze({
|
|
646
|
-
attemptId: waiter.attemptId,
|
|
647
|
-
conversationId: this.conversationId,
|
|
648
|
-
nativeSessionId: this.conversationId,
|
|
649
|
-
nativeTurnId,
|
|
650
|
-
acceptedAt: new Date().toISOString()
|
|
651
|
-
}));
|
|
619
|
+
if (message.type === "user")
|
|
652
620
|
return;
|
|
653
|
-
}
|
|
654
621
|
if (message.type !== "result" || this.#activeTurnId === undefined
|
|
655
622
|
|| optionalId(message.session_id) !== this.conversationId)
|
|
656
623
|
return;
|
|
657
624
|
const nativeTurnId = this.#activeTurnId;
|
|
658
625
|
this.#activeTurnId = undefined;
|
|
659
626
|
const failed = message.is_error === true || message.subtype === "error_during_execution";
|
|
627
|
+
const result = typeof message.result === "string" && message.result.length > 0
|
|
628
|
+
? message.result
|
|
629
|
+
: "Provider Turn failed.";
|
|
660
630
|
onTerminal?.({
|
|
661
631
|
conversationId: this.conversationId,
|
|
662
632
|
nativeSessionId: this.conversationId,
|
|
@@ -664,9 +634,11 @@ class ClaudeStructuredProviderSession {
|
|
|
664
634
|
clientOwned: true,
|
|
665
635
|
status: failed ? "failed" : "completed",
|
|
666
636
|
observedAt: new Date().toISOString(),
|
|
667
|
-
...(
|
|
668
|
-
?
|
|
669
|
-
:
|
|
637
|
+
...(failed
|
|
638
|
+
? { error: result, rawError: providerErrorEvidence(message).rawError }
|
|
639
|
+
: typeof message.result === "string" && message.result.length > 0
|
|
640
|
+
? { summary: message.result }
|
|
641
|
+
: {})
|
|
670
642
|
});
|
|
671
643
|
}
|
|
672
644
|
}
|
|
@@ -712,19 +684,12 @@ function optionalId(value) {
|
|
|
712
684
|
function nestedId(value, key) {
|
|
713
685
|
return optionalId(object(value[key])?.id);
|
|
714
686
|
}
|
|
715
|
-
function
|
|
687
|
+
function providerErrorEvidence(value) {
|
|
716
688
|
const error = object(value);
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
if (!Array.isArray(content))
|
|
724
|
-
return undefined;
|
|
725
|
-
const text = content.flatMap((entry) => {
|
|
726
|
-
const block = object(entry);
|
|
727
|
-
return block?.type === "text" && typeof block.text === "string" ? [block.text] : [];
|
|
728
|
-
});
|
|
729
|
-
return text.length === 1 ? text[0] : text.join("");
|
|
689
|
+
const message = typeof error?.message === "string" && error.message.length > 0
|
|
690
|
+
? error.message
|
|
691
|
+
: typeof value === "string" && value.length > 0
|
|
692
|
+
? value
|
|
693
|
+
: "Provider Turn failed.";
|
|
694
|
+
return { error: message, rawError: serializeAgentErrorRaw(value) };
|
|
730
695
|
}
|
|
@@ -212,9 +212,6 @@ export function createTaskRuntimeIsolationDescriptor(input) {
|
|
|
212
212
|
const workspace = validateManagedWorkspace(input.workspace);
|
|
213
213
|
const owner = taskRuntimeWorkspaceOwner(workspace.owner);
|
|
214
214
|
const taskId = requireIdentity(owner.taskId, "Task id");
|
|
215
|
-
const runId = input.runId === undefined
|
|
216
|
-
? undefined
|
|
217
|
-
: requireIdentity(input.runId, "Run id");
|
|
218
215
|
const launchId = requireIdentity(input.launchId, "Launch id");
|
|
219
216
|
const generationId = requireIdentity(input.generationId, "Generation id");
|
|
220
217
|
const runtimeRoot = canonicalPath(input.runtimeRoot, "Task runtime root");
|
|
@@ -240,7 +237,6 @@ export function createTaskRuntimeIsolationDescriptor(input) {
|
|
|
240
237
|
portAllocations,
|
|
241
238
|
externalCapabilities: Object.freeze({ declared, requested }),
|
|
242
239
|
generation: Object.freeze({
|
|
243
|
-
...(runId === undefined ? {} : { runId }),
|
|
244
240
|
launchId,
|
|
245
241
|
generationId
|
|
246
242
|
})
|
|
@@ -287,9 +283,6 @@ export function parseTaskRuntimeIsolationDescriptor(serialized) {
|
|
|
287
283
|
requested: capabilities(external.requested, "Requested external capability")
|
|
288
284
|
},
|
|
289
285
|
generation: {
|
|
290
|
-
...(generation.runId === undefined
|
|
291
|
-
? {}
|
|
292
|
-
: { runId: requireIdentity(generation.runId, "Run id") }),
|
|
293
286
|
launchId: requireIdentity(generation.launchId, "Launch id"),
|
|
294
287
|
generationId: requireIdentity(generation.generationId, "Generation id")
|
|
295
288
|
}
|
|
@@ -37,7 +37,7 @@ export class TmuxSessionHost {
|
|
|
37
37
|
async start(request, beforeHostStart) {
|
|
38
38
|
return this.#launch(request, beforeHostStart);
|
|
39
39
|
}
|
|
40
|
-
async
|
|
40
|
+
async restore(request, beforeHostStart) {
|
|
41
41
|
return this.#launch(request, beforeHostStart);
|
|
42
42
|
}
|
|
43
43
|
async stop(binding) {
|
|
@@ -228,10 +228,7 @@ export class TmuxSessionHost {
|
|
|
228
228
|
...(planned.launch.env.YUI_SESSION_TITLE === undefined
|
|
229
229
|
? {}
|
|
230
230
|
: { sessionTitle: planned.launch.env.YUI_SESSION_TITLE }),
|
|
231
|
-
...(nativeSessionId === undefined ? {} : { nativeSessionId })
|
|
232
|
-
...(planned.initialTurnRunId === undefined
|
|
233
|
-
? {}
|
|
234
|
-
: { initialTurnRunId: planned.initialTurnRunId })
|
|
231
|
+
...(nativeSessionId === undefined ? {} : { nativeSessionId })
|
|
235
232
|
});
|
|
236
233
|
const yuiHome = planned.launch.env.YUI_HOME;
|
|
237
234
|
const childLifecycle = planned.launch.childLifecycle;
|
|
@@ -264,9 +261,6 @@ export class TmuxSessionHost {
|
|
|
264
261
|
roleName: request.owner.roleName
|
|
265
262
|
}),
|
|
266
263
|
hostCreated,
|
|
267
|
-
...(hostCreated && planned.initialTurnRunId !== undefined
|
|
268
|
-
? { initialTurnRunId: planned.initialTurnRunId }
|
|
269
|
-
: {}),
|
|
270
264
|
...(nativeSessionId === undefined ? {} : { nativeSessionId })
|
|
271
265
|
});
|
|
272
266
|
if (hostCreated) {
|
|
@@ -277,7 +271,6 @@ export class TmuxSessionHost {
|
|
|
277
271
|
if (request.mode === "new"
|
|
278
272
|
&& request.owner.scope === "task"
|
|
279
273
|
&& request.runId !== undefined
|
|
280
|
-
&& planned.initialTurnRunId === request.runId
|
|
281
274
|
&& this.#waitForNativeSession !== undefined) {
|
|
282
275
|
binding = createRuntimeBinding({
|
|
283
276
|
...binding,
|
|
@@ -348,10 +341,6 @@ export class TmuxSessionHost {
|
|
|
348
341
|
}
|
|
349
342
|
};
|
|
350
343
|
let hostCreated = false;
|
|
351
|
-
let providerAcknowledged = false;
|
|
352
|
-
let providerDeliveryUnknown = false;
|
|
353
|
-
let providerBusy = false;
|
|
354
|
-
let providerRejected = false;
|
|
355
344
|
let providerDispatchObserved = false;
|
|
356
345
|
let providerSnapshot;
|
|
357
346
|
try {
|
|
@@ -363,17 +352,8 @@ export class TmuxSessionHost {
|
|
|
363
352
|
...(request.owner.scope === "task" ? { taskId: request.owner.taskId } : {}),
|
|
364
353
|
roleName: request.owner.roleName,
|
|
365
354
|
launchId: reservation.launchId,
|
|
366
|
-
requireTurnAck:
|
|
355
|
+
requireTurnAck: false
|
|
367
356
|
});
|
|
368
|
-
providerDeliveryUnknown = providerSnapshot.state === "delivery-unknown";
|
|
369
|
-
providerBusy = planned.initialTurnRunId !== undefined
|
|
370
|
-
&& providerSnapshot.state === "busy";
|
|
371
|
-
providerRejected = planned.initialTurnRunId !== undefined
|
|
372
|
-
&& providerSnapshot.state === "rejected";
|
|
373
|
-
providerAcknowledged = !providerDeliveryUnknown && !providerBusy && !providerRejected;
|
|
374
|
-
if (providerSnapshot.state === "rejected" && !providerRejected) {
|
|
375
|
-
throw new Error("Agent Host rejected a launch without an initial Provider Turn.");
|
|
376
|
-
}
|
|
377
357
|
providerDispatchObserved = true;
|
|
378
358
|
}
|
|
379
359
|
if (!hostCreated) {
|
|
@@ -396,25 +376,13 @@ export class TmuxSessionHost {
|
|
|
396
376
|
if (controlResult.outcome === "active-same-launch") {
|
|
397
377
|
broker.revoke(request.launchId);
|
|
398
378
|
}
|
|
399
|
-
const acceptableState = controlResult.snapshot.state
|
|
400
|
-
|
|
401
|
-
&& controlResult.snapshot.state === "idle");
|
|
402
|
-
const deliveryUnknownState = planned.initialTurnRunId !== undefined
|
|
403
|
-
&& controlResult.snapshot.state === "delivery-unknown";
|
|
404
|
-
const busyState = planned.initialTurnRunId !== undefined
|
|
405
|
-
&& controlResult.snapshot.state === "busy";
|
|
406
|
-
const rejectedState = planned.initialTurnRunId !== undefined
|
|
407
|
-
&& controlResult.snapshot.state === "rejected";
|
|
408
|
-
if ((!acceptableState && !deliveryUnknownState && !busyState && !rejectedState)
|
|
379
|
+
const acceptableState = ["idle", "ready", "busy"].includes(controlResult.snapshot.state);
|
|
380
|
+
if (!acceptableState
|
|
409
381
|
|| controlResult.snapshot.launchId !== reservation.launchId) {
|
|
410
382
|
broker.revoke(request.launchId);
|
|
411
383
|
throw new Error(`Agent Host did not return an exact Provider acknowledgement for ${reservation.launchId}.`);
|
|
412
384
|
}
|
|
413
385
|
providerSnapshot = controlResult.snapshot;
|
|
414
|
-
providerAcknowledged = acceptableState;
|
|
415
|
-
providerDeliveryUnknown = deliveryUnknownState;
|
|
416
|
-
providerBusy = busyState;
|
|
417
|
-
providerRejected = rejectedState;
|
|
418
386
|
providerDispatchObserved = true;
|
|
419
387
|
}
|
|
420
388
|
}
|
|
@@ -457,18 +425,6 @@ export class TmuxSessionHost {
|
|
|
457
425
|
roleName: request.owner.roleName
|
|
458
426
|
}),
|
|
459
427
|
hostCreated,
|
|
460
|
-
...(providerAcknowledged && planned.initialTurnRunId !== undefined
|
|
461
|
-
? { initialTurnRunId: planned.initialTurnRunId }
|
|
462
|
-
: {}),
|
|
463
|
-
...(providerDeliveryUnknown && planned.initialTurnRunId !== undefined
|
|
464
|
-
? { initialTurnDeliveryUnknownRunId: planned.initialTurnRunId }
|
|
465
|
-
: {}),
|
|
466
|
-
...(providerBusy && planned.initialTurnRunId !== undefined
|
|
467
|
-
? { initialTurnBusyRunId: planned.initialTurnRunId }
|
|
468
|
-
: {}),
|
|
469
|
-
...(providerRejected && planned.initialTurnRunId !== undefined
|
|
470
|
-
? { initialTurnRejectedRunId: planned.initialTurnRunId }
|
|
471
|
-
: {}),
|
|
472
428
|
...((providerSnapshot?.nativeSessionId ?? nativeSessionId) === undefined
|
|
473
429
|
? {}
|
|
474
430
|
: { nativeSessionId: providerSnapshot?.nativeSessionId ?? nativeSessionId }),
|
|
@@ -575,6 +531,7 @@ export class AgentHostPromptPushAdapter {
|
|
|
575
531
|
type: "submit-turn",
|
|
576
532
|
launchId: request.binding.launchId,
|
|
577
533
|
nativeSessionId: request.binding.nativeSessionId,
|
|
534
|
+
runId: request.envelope.source.localId,
|
|
578
535
|
authority: request.binding.providerAuthority,
|
|
579
536
|
turn: {
|
|
580
537
|
attemptId: request.envelope.id,
|