@zq-silk/yui 0.16.1 → 0.16.2
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/ARCHITECTURE.md +12 -0
- package/ARCHITECTURE.zh-CN.md +8 -0
- package/README.md +3 -0
- package/dist/agent/managedRuntimeEnvironment.js +0 -4
- package/dist/agentRun/agentRun.js +7 -17
- package/dist/cli/agentConfigurationPicker.js +24 -21
- package/dist/cli/commandCatalog.js +18 -10
- package/dist/cli/roleWizard.js +41 -30
- package/dist/cli/updateCommand.js +35 -13
- package/dist/cli/updateOrchestrator.js +73 -33
- package/dist/cli/updatePorts.js +40 -17
- package/dist/cli.js +35 -26
- package/dist/commands/controllerCommands.js +1 -1
- package/dist/commands/executionAuditCommands.js +2 -2
- package/dist/commands/projectCommands.js +1 -1
- package/dist/commands/releaseCommands.js +9 -38
- package/dist/commands/taskCommands.js +84 -81
- package/dist/commands/taskCompletionGate.js +0 -117
- package/dist/commands/taskRoleRuntimeStatus.js +1 -1
- package/dist/commands/taskUpstreamCommands.js +93 -54
- package/dist/context/runContextPack.js +30 -54
- package/dist/context/runInputContract.js +9 -0
- package/dist/context/sessionBootstrapManifest.js +11 -19
- package/dist/controller/agentHostObservation.js +4 -2
- package/dist/controller/controller.js +8 -6
- package/dist/controller/fileSchedulerStoreAdapter.js +85 -18
- package/dist/controller/globalInputDelivery.js +28 -7
- package/dist/controller/globalRuntimeAttention.js +34 -0
- package/dist/controller/operatorNotification.js +31 -0
- package/dist/controller/providerRetryAdmission.js +3 -1
- package/dist/controller/providerRetryDelivery.js +10 -3
- package/dist/controller/runtime.js +1 -27
- package/dist/controller/sessionOwnerReconciliation.js +42 -24
- package/dist/controller/structuredProviderObservation.js +27 -0
- package/dist/controller/updateReconciliation.js +72 -20
- package/dist/doctor/doctor.js +2 -1
- package/dist/executor/agentAdapter.js +28 -96
- package/dist/executor/agentConfigurationCatalog.js +13 -68
- package/dist/executor/agentConfigurationFields.js +120 -0
- package/dist/executor/agentConfigurationProbe.js +55 -80
- package/dist/executor/agentExecutor.js +5 -2
- package/dist/executor/executorRegistry.js +0 -9
- package/dist/executor/fileRoleLaunchPlanner.js +12 -11
- package/dist/interaction/operatorPresentation.js +2 -1
- package/dist/message/messageContinuation.js +8 -9
- package/dist/observability/executionAudit.js +1 -10
- package/dist/observability/runtimeIdentity.js +0 -23
- package/dist/output/agentConfigurationPresentation.js +4 -2
- package/dist/release/releaseHandover.js +2 -2
- package/dist/release/releaseIdempotencyStore.js +0 -23
- package/dist/release/releaseWorkflowPorts.js +8 -4
- package/dist/repository/gitWorkspace.js +66 -19
- package/dist/repository/taskWorkspacePreparer.js +75 -68
- package/dist/resources/resourceRegistry.js +90 -44
- package/dist/resources/sqliteResourceRegistry.js +3 -5
- package/dist/runtime/acpSession.js +21 -5
- package/dist/runtime/agentEndpoint.js +4 -1
- package/dist/runtime/agentHost.js +22 -62
- package/dist/runtime/agentHostCleanup.js +85 -0
- package/dist/runtime/agentHostProtocol.js +1 -1
- package/dist/runtime/builtinAgentDrivers.js +46 -119
- package/dist/runtime/builtinTranscriptObserver.js +10 -6
- package/dist/runtime/codexAppServerRuntime.js +55 -89
- package/dist/runtime/jsonLineChannel.js +35 -7
- package/dist/runtime/providerContinuationReconciliationService.js +42 -3
- package/dist/runtime/providerRetry.js +15 -0
- package/dist/runtime/providerRuntimeReconciler.js +12 -2
- package/dist/runtime/structuredProviderHost.js +106 -81
- package/dist/scheduler/activeRoleRunDelivery.js +5 -1
- package/dist/scheduler/operatorInputNotificationProcessor.js +7 -17
- package/dist/storage/upgrade/upgradeOrchestrator.js +0 -10
- package/dist/task/nextAction.js +33 -23
- package/dist/task/task.js +2 -1
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +72 -3
- package/dist/web/assets/client/components.js +2 -1
- package/dist/web/assets/client/i18n.js +2 -0
- package/dist/web/assets/client/taskSummary.js +345 -0
- package/dist/web/assets/client/taskSurface.js +44 -26
- package/dist/web/assets/client/view.js +33 -0
- package/dist/web/assets/shell.js +1 -0
- package/dist/web/assets/styles/cards.js +21 -0
- package/dist/web/webServer.js +39 -5
- package/dist/web/webSessions.js +165 -0
- package/dist/web/webSnapshot.js +23 -0
- package/dist/web/webTaskSurface.js +23 -0
- package/docs/managed-turn-and-session-runtime.md +31 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +23 -0
- package/docs/observability/README.md +47 -0
- package/docs/observability/README.zh-CN.md +37 -0
- package/docs/project-refresh.md +9 -0
- package/docs/project-refresh.zh-CN.md +8 -0
- package/docs/provider-retry.md +35 -0
- package/docs/release-workflow.md +124 -20
- package/docs/release-workflow.zh-CN.md +103 -14
- package/docs/roles-and-configuration.md +30 -0
- package/docs/roles-and-configuration.zh-CN.md +20 -0
- package/docs/task-delivery.md +109 -0
- package/docs/task-delivery.zh-CN.md +80 -0
- package/docs/task-discovery.md +9 -0
- package/docs/task-discovery.zh-CN.md +6 -0
- package/docs/testing/verification-levels.md +29 -11
- package/docs/testing/verification-levels.zh-CN.md +25 -7
- package/i18n/README.zh-CN.md +2 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +11 -0
- package/skills/yui-leader/references/execution.md +22 -0
- package/skills/yui-leader/references/planning.md +6 -2
- package/skills/yui-operator/SKILL.md +45 -13
- package/skills/yui-operator/references/task-delivery.md +99 -0
- package/skills/yui-runtime/SKILL.md +5 -3
- package/skills/yui-runtime/references/publication.md +56 -5
- package/skills/yui-runtime/references/recovery.md +12 -2
- package/dist/runtime/agentHostCompatibility.js +0 -127
|
@@ -7,7 +7,7 @@ import WebSocket from "ws";
|
|
|
7
7
|
import { YUI_VERSION } from "../version.js";
|
|
8
8
|
import { AcpStructuredProviderSession } from "./acpSession.js";
|
|
9
9
|
import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
|
|
10
|
-
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
10
|
+
import { providerDeliveryFailureFrom, serializeAgentErrorRaw } from "./agentError.js";
|
|
11
11
|
import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
12
12
|
import { codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
|
|
13
13
|
import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
|
|
@@ -65,6 +65,7 @@ export async function startStructuredProviderSession(payload, input = {}) {
|
|
|
65
65
|
? {}
|
|
66
66
|
: { nativeSessionId: control.nativeSessionId }),
|
|
67
67
|
...(input.onTerminal === undefined ? {} : { onTerminal: input.onTerminal }),
|
|
68
|
+
...(input.onDiagnostic === undefined ? {} : { onDiagnostic: input.onDiagnostic }),
|
|
68
69
|
mirror
|
|
69
70
|
});
|
|
70
71
|
return Object.freeze({ session });
|
|
@@ -79,7 +80,7 @@ export async function startStructuredProviderSession(payload, input = {}) {
|
|
|
79
80
|
goal: opened.goal
|
|
80
81
|
});
|
|
81
82
|
}
|
|
82
|
-
const session = await ClaudeStructuredProviderSession.open(child, exit, processInstanceId, control, input.onAccepted, input.onTerminal, input.onGoal, input.onActivity, mirror);
|
|
83
|
+
const session = await ClaudeStructuredProviderSession.open(child, exit, processInstanceId, control, input.onAccepted, input.onTerminal, input.onGoal, input.onActivity, input.onDiagnostic, mirror);
|
|
83
84
|
return Object.freeze({ session });
|
|
84
85
|
}
|
|
85
86
|
catch (error) {
|
|
@@ -325,6 +326,7 @@ class CodexStructuredProviderSession {
|
|
|
325
326
|
onGoal;
|
|
326
327
|
onInput;
|
|
327
328
|
onActivity;
|
|
329
|
+
mirror;
|
|
328
330
|
nativeAccountHome;
|
|
329
331
|
#turnAttempts = new Map();
|
|
330
332
|
adapterId = "codex";
|
|
@@ -335,7 +337,7 @@ class CodexStructuredProviderSession {
|
|
|
335
337
|
#bufferedStarts = [];
|
|
336
338
|
#bufferedTerminals = [];
|
|
337
339
|
#bufferedActivities = [];
|
|
338
|
-
constructor(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, nativeAccountHome) {
|
|
340
|
+
constructor(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, mirror, nativeAccountHome) {
|
|
339
341
|
this.child = child;
|
|
340
342
|
this.exit = exit;
|
|
341
343
|
this.processInstanceId = processInstanceId;
|
|
@@ -346,6 +348,7 @@ class CodexStructuredProviderSession {
|
|
|
346
348
|
this.onGoal = onGoal;
|
|
347
349
|
this.onInput = onInput;
|
|
348
350
|
this.onActivity = onActivity;
|
|
351
|
+
this.mirror = mirror;
|
|
349
352
|
this.nativeAccountHome = nativeAccountHome;
|
|
350
353
|
}
|
|
351
354
|
static async open(child, exit, processInstanceId, payload, control, onStarted, onTerminal, onGoal, onInput, onActivity, mirror) {
|
|
@@ -387,7 +390,7 @@ class CodexStructuredProviderSession {
|
|
|
387
390
|
name: control.sessionTitle
|
|
388
391
|
});
|
|
389
392
|
}
|
|
390
|
-
const session = new CodexStructuredProviderSession(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, optionalId(initialized.codexHome));
|
|
393
|
+
const session = new CodexStructuredProviderSession(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, mirror, optionalId(initialized.codexHome));
|
|
391
394
|
session.#activeTurnId = resumedActiveTurnId;
|
|
392
395
|
const ownedTurn = control.kind === "restore" ? control.ownedTurn : undefined;
|
|
393
396
|
session.#clientOwnedTurnId = ownedTurn?.turnId;
|
|
@@ -445,9 +448,21 @@ class CodexStructuredProviderSession {
|
|
|
445
448
|
#observeMessage(message, emit) {
|
|
446
449
|
const method = typeof message.method === "string" ? message.method : "";
|
|
447
450
|
const params = object(message.params) ?? {};
|
|
448
|
-
|
|
451
|
+
const threadId = optionalId(params.threadId);
|
|
452
|
+
if (threadId !== this.conversationId) {
|
|
453
|
+
if (threadId === undefined && (method === "turn/started" || method === "turn/completed")) {
|
|
454
|
+
this.mirror("stderr", `Codex protocol: ${method} has no thread identity; ignored.\n`);
|
|
455
|
+
}
|
|
449
456
|
return undefined;
|
|
450
|
-
|
|
457
|
+
}
|
|
458
|
+
let goal;
|
|
459
|
+
try {
|
|
460
|
+
goal = codexGoalNotification({ method, params });
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
this.mirror("stderr", "Codex protocol: invalid Goal notification; ignored.\n");
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
451
466
|
if (goal !== undefined) {
|
|
452
467
|
if (emit)
|
|
453
468
|
this.onGoal?.(goal);
|
|
@@ -456,17 +471,20 @@ class CodexStructuredProviderSession {
|
|
|
456
471
|
if (emit && (method === "item/started" || method === "item/completed"
|
|
457
472
|
|| method === "item/agentMessage/delta" || method === "item/reasoning/summaryTextDelta")) {
|
|
458
473
|
const item = object(params.item);
|
|
459
|
-
const
|
|
474
|
+
const delta = method === "item/agentMessage/delta" || method === "item/reasoning/summaryTextDelta";
|
|
475
|
+
const id = optionalId(delta ? params.itemId : item?.id);
|
|
460
476
|
const nativeTurnId = optionalId(params.turnId);
|
|
461
|
-
const tool =
|
|
462
|
-
|
|
463
|
-
|
|
477
|
+
const tool = typeof item?.type === "string"
|
|
478
|
+
&& ["commandExecution", "mcpToolCall", "dynamicToolCall", "fileChange"].includes(item.type);
|
|
479
|
+
const model = delta || item?.type === "agentMessage" || item?.type === "reasoning";
|
|
480
|
+
const phase = model ? "model" : tool ? codexToolPhase(item, method === "item/started") : undefined;
|
|
481
|
+
if (tool && phase === undefined) {
|
|
482
|
+
this.mirror("stderr", "Codex protocol: tool item has no valid lifecycle status; ignored.\n");
|
|
483
|
+
}
|
|
484
|
+
if (id !== undefined && nativeTurnId !== undefined && phase !== undefined) {
|
|
464
485
|
const activity = {
|
|
465
486
|
conversationId: this.conversationId, nativeSessionId: this.conversationId,
|
|
466
|
-
nativeTurnId, id, observedAt: new Date().toISOString(),
|
|
467
|
-
phase: model ? "model" : method === "item/started" ? "started"
|
|
468
|
-
: item?.status === "failed" || (typeof item?.exitCode === "number" && item.exitCode !== 0)
|
|
469
|
-
? "failed" : "completed"
|
|
487
|
+
nativeTurnId, id, observedAt: new Date().toISOString(), phase
|
|
470
488
|
};
|
|
471
489
|
if (this.#submissionPending)
|
|
472
490
|
this.#bufferedActivities.push(activity);
|
|
@@ -486,10 +504,10 @@ class CodexStructuredProviderSession {
|
|
|
486
504
|
return undefined;
|
|
487
505
|
}
|
|
488
506
|
if (method === "turn/started") {
|
|
489
|
-
const
|
|
490
|
-
|
|
507
|
+
const turn = object(params.turn);
|
|
508
|
+
const turnId = optionalId(turn?.id);
|
|
509
|
+
if (turnId !== undefined && turn?.status === "inProgress") {
|
|
491
510
|
this.#activeTurnId = turnId;
|
|
492
|
-
const turn = object(params.turn) ?? {};
|
|
493
511
|
const input = codexTurnInput(turn);
|
|
494
512
|
const started = {
|
|
495
513
|
conversationId: this.conversationId,
|
|
@@ -503,14 +521,20 @@ class CodexStructuredProviderSession {
|
|
|
503
521
|
else if (emit)
|
|
504
522
|
this.#emitStarted(started);
|
|
505
523
|
}
|
|
524
|
+
else {
|
|
525
|
+
this.mirror("stderr", "Codex protocol: turn/started has no valid Turn identity/status; ignored.\n");
|
|
526
|
+
}
|
|
506
527
|
return undefined;
|
|
507
528
|
}
|
|
508
529
|
if (method !== "turn/completed")
|
|
509
530
|
return undefined;
|
|
510
|
-
const turn = object(params.turn)
|
|
511
|
-
const nativeTurnId = optionalId(turn
|
|
512
|
-
if (nativeTurnId === undefined
|
|
531
|
+
const turn = object(params.turn);
|
|
532
|
+
const nativeTurnId = optionalId(turn?.id);
|
|
533
|
+
if (nativeTurnId === undefined || turn === null
|
|
534
|
+
|| (turn.status !== "completed" && turn.status !== "failed" && turn.status !== "interrupted")) {
|
|
535
|
+
this.mirror("stderr", "Codex protocol: turn/completed has no valid terminal Turn identity/status; ignored.\n");
|
|
513
536
|
return undefined;
|
|
537
|
+
}
|
|
514
538
|
const status = turn.status === "failed"
|
|
515
539
|
? "failed"
|
|
516
540
|
: turn.status === "interrupted" ? "cancelled" : "completed";
|
|
@@ -680,6 +704,7 @@ class ClaudeStructuredProviderSession {
|
|
|
680
704
|
conversationId;
|
|
681
705
|
channel;
|
|
682
706
|
onGoal;
|
|
707
|
+
mirror;
|
|
683
708
|
adapterId = "claude";
|
|
684
709
|
get ownedProcessId() { return this.child.pid; }
|
|
685
710
|
#activeAttemptId;
|
|
@@ -689,22 +714,33 @@ class ClaudeStructuredProviderSession {
|
|
|
689
714
|
#openToolIds = new Set();
|
|
690
715
|
#resultAttempts = new Map();
|
|
691
716
|
#lastGoalKey;
|
|
692
|
-
constructor(child, exit, processInstanceId, conversationId, channel, onGoal) {
|
|
717
|
+
constructor(child, exit, processInstanceId, conversationId, channel, onGoal, mirror) {
|
|
693
718
|
this.child = child;
|
|
694
719
|
this.exit = exit;
|
|
695
720
|
this.processInstanceId = processInstanceId;
|
|
696
721
|
this.conversationId = conversationId;
|
|
697
722
|
this.channel = channel;
|
|
698
723
|
this.onGoal = onGoal;
|
|
724
|
+
this.mirror = mirror;
|
|
699
725
|
}
|
|
700
|
-
static async open(child, exit, processInstanceId, control, onAccepted, onTerminal, onGoal, onActivity, mirror) {
|
|
701
|
-
const channel = new JsonLineChannel(child, mirror);
|
|
726
|
+
static async open(child, exit, processInstanceId, control, onAccepted, onTerminal, onGoal, onActivity, onDiagnostic, mirror) {
|
|
702
727
|
const nativeSessionId = control.nativeSessionId;
|
|
703
728
|
if (nativeSessionId === undefined) {
|
|
704
729
|
throw new Error("Managed Claude launch requires a preallocated native Session id.");
|
|
705
730
|
}
|
|
706
|
-
|
|
707
|
-
channel
|
|
731
|
+
let receivingAttemptId;
|
|
732
|
+
const channel = new JsonLineChannel(child, mirror, error => onDiagnostic?.({
|
|
733
|
+
nativeSessionId,
|
|
734
|
+
...((receivingAttemptId ?? session.#activeAttemptId) === undefined
|
|
735
|
+
? {} : { attemptId: receivingAttemptId ?? session.#activeAttemptId }),
|
|
736
|
+
failure: providerDeliveryFailureFrom(error, { phase: "turn-reconcile", inputDisposition: "unknown" })
|
|
737
|
+
}));
|
|
738
|
+
const session = new ClaudeStructuredProviderSession(child, exit, processInstanceId, nativeSessionId, channel, onGoal, mirror);
|
|
739
|
+
channel.onMessage((message) => {
|
|
740
|
+
receivingAttemptId = session.#activeAttemptId;
|
|
741
|
+
session.#receive(message, onTerminal, onAccepted, onActivity);
|
|
742
|
+
receivingAttemptId = undefined;
|
|
743
|
+
});
|
|
708
744
|
// This client owns the whole Claude execution process, unlike a Codex
|
|
709
745
|
// proxy. An exit without a result ends the exact local input as failure,
|
|
710
746
|
// not as continuing work merely because the supervising Host is alive.
|
|
@@ -855,24 +891,35 @@ class ClaudeStructuredProviderSession {
|
|
|
855
891
|
}
|
|
856
892
|
return;
|
|
857
893
|
}
|
|
858
|
-
if (message.type !== "result"
|
|
859
|
-
|| optionalId(message.session_id) !== this.conversationId)
|
|
894
|
+
if (message.type !== "result")
|
|
860
895
|
return;
|
|
896
|
+
const sessionId = optionalId(message.session_id);
|
|
897
|
+
if (sessionId !== this.conversationId) {
|
|
898
|
+
if (sessionId === undefined)
|
|
899
|
+
this.mirror("stderr", "Claude protocol: result has no Session identity; ignored.\n");
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
861
902
|
// A result UUID identifies this message, not the Provider execution.
|
|
862
903
|
// Retain its local association so a delayed duplicate cannot be assigned
|
|
863
904
|
// to a successor request on the same long-lived process.
|
|
864
905
|
const resultId = optionalId(message.uuid);
|
|
865
|
-
const
|
|
906
|
+
const subtype = message.subtype;
|
|
907
|
+
const failed = subtype === "success" ? message.is_error
|
|
908
|
+
: ["error_during_execution", "error_max_turns", "error_max_budget_usd",
|
|
909
|
+
"error_max_structured_output_retries"].includes(String(subtype)) ? true : undefined;
|
|
910
|
+
if (resultId === undefined || typeof message.is_error !== "boolean" || failed === undefined) {
|
|
911
|
+
this.mirror("stderr", "Claude protocol: result has no valid identity/status; ignored.\n");
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const priorAttempt = this.#resultAttempts.get(resultId);
|
|
866
915
|
const attemptId = priorAttempt ?? this.#activeAttemptId;
|
|
867
916
|
if (attemptId === undefined)
|
|
868
917
|
return;
|
|
869
|
-
|
|
870
|
-
this.#resultAttempts.set(resultId, attemptId);
|
|
918
|
+
this.#resultAttempts.set(resultId, attemptId);
|
|
871
919
|
if (attemptId === this.#activeAttemptId) {
|
|
872
920
|
this.#activeAttemptId = undefined;
|
|
873
921
|
this.#openToolIds.clear();
|
|
874
922
|
}
|
|
875
|
-
const failed = message.is_error === true || message.subtype === "error_during_execution";
|
|
876
923
|
const result = typeof message.result === "string" && message.result.length > 0
|
|
877
924
|
? message.result
|
|
878
925
|
: providerErrorEvidence(message).error;
|
|
@@ -891,64 +938,44 @@ class ClaudeStructuredProviderSession {
|
|
|
891
938
|
});
|
|
892
939
|
}
|
|
893
940
|
}
|
|
941
|
+
function codexToolPhase(item, started) {
|
|
942
|
+
if (started)
|
|
943
|
+
return item.status === "inProgress" ? "started" : undefined;
|
|
944
|
+
if (item.status === "failed")
|
|
945
|
+
return "failed";
|
|
946
|
+
if (item.status === "declined"
|
|
947
|
+
&& (item.type === "commandExecution" || item.type === "fileChange"))
|
|
948
|
+
return "failed";
|
|
949
|
+
if (item.status !== "completed")
|
|
950
|
+
return undefined;
|
|
951
|
+
if (item.type === "commandExecution" && typeof item.exitCode === "number" && item.exitCode !== 0) {
|
|
952
|
+
return "failed";
|
|
953
|
+
}
|
|
954
|
+
if (item.type === "dynamicToolCall" && item.success === false)
|
|
955
|
+
return "failed";
|
|
956
|
+
return "completed";
|
|
957
|
+
}
|
|
894
958
|
function claudeActiveGoal(message, conversationId) {
|
|
895
|
-
if (
|
|
959
|
+
if (message.type !== "active_goal" || optionalId(message.session_id) !== conversationId)
|
|
896
960
|
return undefined;
|
|
897
|
-
if (message.
|
|
961
|
+
if (message.value === null)
|
|
898
962
|
return null;
|
|
899
|
-
const raw = object(message.
|
|
963
|
+
const raw = object(message.value);
|
|
900
964
|
if (raw === null)
|
|
901
965
|
return undefined;
|
|
902
|
-
const objective = typeof raw.
|
|
966
|
+
const objective = typeof raw.condition === "string" ? raw.condition.trim() : "";
|
|
903
967
|
if (objective.length === 0)
|
|
904
968
|
return undefined;
|
|
905
|
-
const status = providerGoalStatus(raw.status);
|
|
906
|
-
if (status === undefined)
|
|
907
|
-
return undefined;
|
|
908
|
-
const tokenBudget = positiveOptionalInteger(raw.token_budget ?? raw.tokenBudget);
|
|
909
969
|
return Object.freeze({
|
|
910
970
|
conversationId,
|
|
911
|
-
|
|
971
|
+
// Claude emits a live goal or clears it. There is no Codex-style Goal
|
|
972
|
+
// status/budget/Turn field on this event, and clearing is not success.
|
|
973
|
+
status: "active",
|
|
912
974
|
objective,
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
? {}
|
|
916
|
-
: { nativeTurnId: optionalId(raw.turn_id ?? raw.turnId) }),
|
|
917
|
-
...(tokenBudget === undefined ? {} : { tokenBudget })
|
|
975
|
+
// set_at is creation time, not a last-update timestamp.
|
|
976
|
+
updatedAt: new Date().toISOString()
|
|
918
977
|
});
|
|
919
978
|
}
|
|
920
|
-
function providerGoalStatus(value) {
|
|
921
|
-
switch (value) {
|
|
922
|
-
case "active":
|
|
923
|
-
case "paused":
|
|
924
|
-
case "blocked":
|
|
925
|
-
case "complete":
|
|
926
|
-
return value;
|
|
927
|
-
case "usageLimited":
|
|
928
|
-
case "usage_limited":
|
|
929
|
-
case "usage-limited":
|
|
930
|
-
return "usage-limited";
|
|
931
|
-
case "budgetLimited":
|
|
932
|
-
case "budget_limited":
|
|
933
|
-
case "budget-limited":
|
|
934
|
-
return "budget-limited";
|
|
935
|
-
default:
|
|
936
|
-
return undefined;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
function providerTimestamp(value) {
|
|
940
|
-
if (typeof value === "string" && Number.isFinite(Date.parse(value))) {
|
|
941
|
-
return new Date(value).toISOString();
|
|
942
|
-
}
|
|
943
|
-
if (Number.isSafeInteger(value) && value >= 0) {
|
|
944
|
-
const epoch = value;
|
|
945
|
-
return new Date(epoch < 1_000_000_000_000 ? epoch * 1_000 : epoch).toISOString();
|
|
946
|
-
}
|
|
947
|
-
return new Date().toISOString();
|
|
948
|
-
}
|
|
949
|
-
function positiveOptionalInteger(value) {
|
|
950
|
-
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
951
|
-
}
|
|
952
979
|
function childExit(child, processInstanceId) {
|
|
953
980
|
return new Promise((resolvePromise, reject) => {
|
|
954
981
|
child.once("error", reject);
|
|
@@ -971,10 +998,8 @@ function object(value) {
|
|
|
971
998
|
: null;
|
|
972
999
|
}
|
|
973
1000
|
function optionalId(value) {
|
|
974
|
-
return typeof value === "string" && value.
|
|
975
|
-
|
|
976
|
-
function nestedId(value, key) {
|
|
977
|
-
return optionalId(object(value[key])?.id);
|
|
1001
|
+
return typeof value === "string" && !value.includes("\0") && value.length > 0
|
|
1002
|
+
&& value.trim() === value ? value : undefined;
|
|
978
1003
|
}
|
|
979
1004
|
function providerErrorEvidence(value) {
|
|
980
1005
|
const error = object(value);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { serializeRunInputEnvelope } from "../context/runInputContract.js";
|
|
3
|
+
import { readRunContextSnapshot } from "../context/runContextPack.js";
|
|
3
4
|
import { roleSessionMayContinue, sameEffectiveLaunch } from "../executor/effectiveLaunch.js";
|
|
4
5
|
import { RuntimeLifecycleBusyError } from "../runtime/lifecycleReservation.js";
|
|
5
6
|
import { managedProviderTurnId } from "../runtime/providerRuntimeIdentity.js";
|
|
@@ -121,6 +122,9 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
121
122
|
let prepared;
|
|
122
123
|
let submitted = false;
|
|
123
124
|
try {
|
|
125
|
+
// Validate the dispatch contract before starting any Provider resources.
|
|
126
|
+
readRunContextSnapshot(store, run);
|
|
127
|
+
const text = serializeRunInputEnvelope(runInputEnvelope(run));
|
|
124
128
|
const nativeSessionId = mode === "resume"
|
|
125
129
|
? requireResumeSession(role, run, existingSession)
|
|
126
130
|
: undefined;
|
|
@@ -172,7 +176,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
172
176
|
const outcome = await delivery.sendOnce({
|
|
173
177
|
delivery: ready,
|
|
174
178
|
receiptId: attemptId,
|
|
175
|
-
text
|
|
179
|
+
text
|
|
176
180
|
});
|
|
177
181
|
if (outcome.status === "pending") {
|
|
178
182
|
// The original Host request is still in flight. Its durable submitting
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createOperatorBatchPresentation } from "../interaction/operatorPresentation.js";
|
|
2
2
|
import { mailboxHasWork, nextPendingBatch } from "../coordination/workMailbox.js";
|
|
3
|
-
export async function processOperatorInputNotifications(store,
|
|
3
|
+
export async function processOperatorInputNotifications(store, selection, now = new Date()) {
|
|
4
4
|
if (selection !== undefined && !selection.full && !selection.operator)
|
|
5
5
|
return [];
|
|
6
6
|
const targetMailbox = { kind: "operator" };
|
|
@@ -35,30 +35,20 @@ export async function processOperatorInputNotifications(store, delivery, selecti
|
|
|
35
35
|
store.completeWorkMailbox(targetMailbox, processing.batchId);
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
|
-
const target = store.getOperatorDeliveryTarget();
|
|
39
|
-
if (target === null || delivery.notifyOperatorInputOnce === undefined) {
|
|
40
|
-
const reason = target === null ? "operator-unavailable" : "delivery-unsupported";
|
|
41
|
-
store.releaseWorkMailbox(targetMailbox, processing.batchId);
|
|
42
|
-
return attentions.map((attention) => skipped(attention, reason));
|
|
43
|
-
}
|
|
44
38
|
try {
|
|
45
39
|
const presentation = createOperatorBatchPresentation(processing.batchId, attentions.map(toPresentationItem));
|
|
46
|
-
const outcome =
|
|
47
|
-
|
|
40
|
+
const outcome = store.queueOperatorNotification({
|
|
41
|
+
batchId: processing.batchId,
|
|
48
42
|
receiptId: presentation.receiptId,
|
|
49
43
|
text: presentation.text
|
|
50
|
-
});
|
|
51
|
-
if (outcome === "unavailable"
|
|
44
|
+
}, now);
|
|
45
|
+
if (outcome.status === "unavailable") {
|
|
52
46
|
store.releaseWorkMailbox(targetMailbox, processing.batchId);
|
|
53
|
-
|
|
54
|
-
return attentions.map((attention) => skipped(attention, reason));
|
|
47
|
+
return attentions.map((attention) => skipped(attention, "operator-unavailable"));
|
|
55
48
|
}
|
|
56
|
-
if (outcome === "sent")
|
|
57
|
-
store.markOperatorRunStarted(now);
|
|
58
|
-
store.completeWorkMailbox(targetMailbox, processing.batchId);
|
|
59
49
|
return attentions.map((attention) => ({
|
|
60
50
|
...attentionIdentity(attention),
|
|
61
|
-
|
|
51
|
+
...outcome
|
|
62
52
|
}));
|
|
63
53
|
}
|
|
64
54
|
catch (error) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { copyFileSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
3
3
|
import Database from "better-sqlite3";
|
|
4
|
-
import { inspectAgentHostCompatibility, describeAgentHostUpgradeBlockers } from "../../runtime/agentHostCompatibility.js";
|
|
5
4
|
import { RUNTIME_OBSERVATION_TASK_EVENT, createRuntimeObservation } from "../../runtime/runtimeObservation.js";
|
|
6
5
|
import { RUNTIME_PROCESS_EXIT_TASK_EVENT, validateRuntimeProcessExitObservation } from "../../runtime/processExitObservation.js";
|
|
7
6
|
import { SqliteTaskStore } from "../sqliteStore.js";
|
|
@@ -40,15 +39,6 @@ export async function runStorageUpgrade(options) {
|
|
|
40
39
|
? classification.classification.blocker.action
|
|
41
40
|
: "Use a compatible Yui release.");
|
|
42
41
|
}
|
|
43
|
-
const incompatibleHosts = await inspectAgentHostCompatibility(options.home);
|
|
44
|
-
if (incompatibleHosts.length > 0) {
|
|
45
|
-
return {
|
|
46
|
-
...blocked(state.status === "current" ? currentClassification() : migratableClassification(state.currentVersion), "host-compatibility", `Existing Agent Hosts cannot safely use the target Controller/storage:\n${describeAgentHostUpgradeBlockers(incompatibleHosts)}`, "Keep the current Controller, Home and Host processes unchanged. Inspect the named Sessions and original pending "
|
|
47
|
-
+ "inputs/results; let current work settle, then use explicitly authorized Session replacement/cleanup at a safe "
|
|
48
|
-
+ "boundary before retrying the upgrade. This target cannot hot-patch legacy Host memory."),
|
|
49
|
-
hosts: incompatibleHosts
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
42
|
if (state.status === "current") {
|
|
53
43
|
try {
|
|
54
44
|
validateCurrentStore(options.home);
|
package/dist/task/nextAction.js
CHANGED
|
@@ -91,24 +91,7 @@ export function projectNextAction(facts) {
|
|
|
91
91
|
ref: refs[1]
|
|
92
92
|
}
|
|
93
93
|
],
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const draftWork = selectOpenWorkItem(facts.workItems);
|
|
98
|
-
if (draftWork.kind === "blocked") {
|
|
99
|
-
const refs = [
|
|
100
|
-
ref("work-item", draftWork.itemId),
|
|
101
|
-
ref("work-item", draftWork.blockedBy)
|
|
102
|
-
];
|
|
103
|
-
return buildAction(facts, {
|
|
104
|
-
kind: "repair-protocol-inconsistency",
|
|
105
|
-
reason: `Draft Work Item ${draftWork.itemId} depends on ${draftWork.blockedBy}, which is missing, retired, or not completed. Edit the Draft before activation.`,
|
|
106
|
-
refs,
|
|
107
|
-
conflicts: refs,
|
|
108
|
-
preconditions: [
|
|
109
|
-
{ fact: `Draft dependency ${draftWork.blockedBy} is valid`, satisfied: false, ref: refs[1] }
|
|
110
|
-
],
|
|
111
|
-
recommendedCommand: `yui task work edit ${task.id}/${draftWork.itemId} --clear-dependencies`
|
|
94
|
+
...dependencyJudgment(task.id, dependencyIssue.workItemId)
|
|
112
95
|
});
|
|
113
96
|
}
|
|
114
97
|
return buildAction(facts, {
|
|
@@ -323,18 +306,24 @@ export function projectNextAction(facts) {
|
|
|
323
306
|
}
|
|
324
307
|
const openWork = selectOpenWorkItem(facts.workItems);
|
|
325
308
|
if (openWork?.kind === "blocked") {
|
|
309
|
+
const issue = draftWorkItemDependencyIssue(facts.workItems);
|
|
310
|
+
const itemId = issue?.workItemId ?? openWork.itemId;
|
|
311
|
+
const dependencyId = issue?.dependencyId ?? openWork.blockedBy;
|
|
326
312
|
const refs = [
|
|
327
|
-
ref("work-item",
|
|
328
|
-
ref("work-item",
|
|
313
|
+
ref("work-item", itemId),
|
|
314
|
+
ref("work-item", dependencyId)
|
|
329
315
|
];
|
|
330
316
|
return buildAction(facts, {
|
|
331
317
|
kind: "repair-protocol-inconsistency",
|
|
332
|
-
reason:
|
|
318
|
+
reason: issue?.kind === "cycle"
|
|
319
|
+
? `Work Item dependency cycle includes ${itemId}/${dependencyId}.`
|
|
320
|
+
: `Work Item ${itemId} depends on ${dependencyId}, which is ${issue === undefined ? "not completed" : "missing or retired"}.`,
|
|
333
321
|
refs,
|
|
334
322
|
conflicts: refs,
|
|
335
323
|
preconditions: [
|
|
336
|
-
{ fact: `Dependency ${
|
|
337
|
-
]
|
|
324
|
+
{ fact: `Dependency ${dependencyId} is valid and completed`, satisfied: false, ref: refs[1] }
|
|
325
|
+
],
|
|
326
|
+
...dependencyJudgment(task.id, itemId)
|
|
338
327
|
});
|
|
339
328
|
}
|
|
340
329
|
if (openWork?.kind === "ready") {
|
|
@@ -769,6 +758,27 @@ function reviewRoundConflict(round, activeRuns) {
|
|
|
769
758
|
}
|
|
770
759
|
return null;
|
|
771
760
|
}
|
|
761
|
+
function dependencyJudgment(taskId, workItemId) {
|
|
762
|
+
return {
|
|
763
|
+
recommendedCommand: `yui task work show ${taskId}/${workItemId}`,
|
|
764
|
+
alternatives: [
|
|
765
|
+
{
|
|
766
|
+
kind: "inspect-dependencies",
|
|
767
|
+
reason: "Read the related requirements and dependency records before choosing a repair.",
|
|
768
|
+
recommendedCommand: `yui task work list ${taskId}`
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
kind: "revise-dependencies",
|
|
772
|
+
reason: "If the intended dependency graph is wrong, edit the affected WorkItem with --after for the complete intended set, preserving unrelated valid dependencies."
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
kind: "retire-obsolete-work",
|
|
776
|
+
reason: "Only if the requirement is no longer needed, deliberately retire it and reconcile its dependents."
|
|
777
|
+
}
|
|
778
|
+
],
|
|
779
|
+
judgmentRequired: "The records identify a blocked dependency, not which business requirement or edge is wrong. Determine the intended graph from Task requirements; do not infer permission to delete dependencies."
|
|
780
|
+
};
|
|
781
|
+
}
|
|
772
782
|
function selectOpenWorkItem(workItems) {
|
|
773
783
|
const byId = new Map(workItems.map((item) => [item.id, item]));
|
|
774
784
|
const openItems = workItems.filter((item) => OPEN_WORK_ITEM_STATUSES.has(item.status));
|
package/dist/task/task.js
CHANGED
|
@@ -304,7 +304,8 @@ export function reopenTask(task, now) {
|
|
|
304
304
|
}
|
|
305
305
|
: {}),
|
|
306
306
|
status: "active",
|
|
307
|
-
|
|
307
|
+
// Reopening intent does not lift an independent execution stop. Only the
|
|
308
|
+
// explicit start operation may do that after its authority/cleanup checks.
|
|
308
309
|
updatedAt: now.toISOString()
|
|
309
310
|
});
|
|
310
311
|
}
|
|
@@ -9,6 +9,7 @@ import { MARKDOWN_SCRIPT } from "./client/markdown.js";
|
|
|
9
9
|
import { THEME_SCRIPT } from "./client/theme.js";
|
|
10
10
|
import { VIEW_SCRIPT } from "./client/view.js";
|
|
11
11
|
import { TASK_SURFACE_SCRIPT } from "./client/taskSurface.js";
|
|
12
|
+
import { TASK_SUMMARY_SCRIPT } from "./client/taskSummary.js";
|
|
12
13
|
import { DASHBOARD_HTML } from "./shell.js";
|
|
13
14
|
import { FONT_FACE_STYLES } from "./fonts.js";
|
|
14
15
|
import { FONT_WOFF2_BASE64 } from "./fontData.js";
|
|
@@ -35,6 +36,7 @@ export const WEB_ASSETS = Object.freeze({
|
|
|
35
36
|
"/assets/js/components.js": { contentType: "text/javascript; charset=utf-8", body: COMPONENTS_SCRIPT },
|
|
36
37
|
"/assets/js/view.js": { contentType: "text/javascript; charset=utf-8", body: VIEW_SCRIPT },
|
|
37
38
|
"/assets/js/task-surface.js": { contentType: "text/javascript; charset=utf-8", body: TASK_SURFACE_SCRIPT },
|
|
39
|
+
"/assets/js/task-summary.js": { contentType: "text/javascript; charset=utf-8", body: TASK_SUMMARY_SCRIPT },
|
|
38
40
|
"/assets/app.js": { contentType: "text/javascript; charset=utf-8", body: APP_SCRIPT },
|
|
39
41
|
...fontAssets(),
|
|
40
42
|
"/assets/vendor/xterm.mjs": vendorAsset("@xterm/xterm/lib/xterm.mjs", "text/javascript; charset=utf-8"),
|