@zq-silk/yui 0.16.1 → 1.0.0-alpha
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 +9 -4
- package/dist/agent/agent.js +4 -9
- package/dist/agent/executionComponents.js +4 -4
- package/dist/agent/managedRuntimeEnvironment.js +0 -4
- package/dist/agentRun/agentRun.js +13 -23
- package/dist/artifacts/managedGit.js +3 -56
- package/dist/brief/taskBrief.js +3 -3
- 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 -44
- package/dist/cli/updatePorts.js +76 -86
- package/dist/cli/upgradeCommand.js +4 -8
- package/dist/cli.js +39 -33
- package/dist/commands/controllerCommands.js +2 -2
- 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 +91 -81
- package/dist/commands/taskCompletionGate.js +0 -117
- package/dist/commands/taskRoleRuntimeStatus.js +2 -2
- 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/agentRuntimeObserver.js +4 -4
- package/dist/controller/clientRuntime.js +19 -44
- package/dist/controller/controller.js +24 -10
- package/dist/controller/fileSchedulerStoreAdapter.js +91 -24
- package/dist/controller/globalInputDelivery.js +31 -8
- package/dist/controller/globalRuntimeAttention.js +34 -0
- package/dist/controller/jobSupervisor.js +3 -3
- package/dist/controller/operatorNotification.js +31 -0
- package/dist/controller/providerRetryAdmission.js +3 -1
- package/dist/controller/providerRetryDelivery.js +136 -119
- package/dist/controller/runtime.js +2 -28
- package/dist/controller/sessionOwnerReconciliation.js +42 -24
- package/dist/controller/structuredProviderObservation.js +28 -1
- package/dist/controller/updateReconciliation.js +72 -20
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/core/controllerIdentity.js +25 -0
- package/dist/core/controllerProcessIdentity.js +2 -2
- package/dist/core/controllerServer.js +4 -2
- package/dist/core/protocol.js +1 -1
- package/dist/doctor/doctor.js +2 -1
- package/dist/domain/validation.js +6 -0
- package/dist/event/taskEvent.js +3 -3
- package/dist/execution/workItemExecution.js +2 -2
- 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 +11 -8
- package/dist/executor/effectiveLaunch.js +3 -3
- package/dist/executor/executorRegistry.js +0 -9
- package/dist/executor/fileRoleLaunchPlanner.js +12 -11
- package/dist/grant/capabilityGrant.js +2 -2
- package/dist/input/inputRequest.js +4 -4
- package/dist/integration/changeSet.js +3 -3
- package/dist/integration/integrationAttempt.js +3 -3
- package/dist/integration/integrationSourceApplication.js +1 -1
- package/dist/interaction/operatorPresentation.js +2 -1
- package/dist/job/durableJob.js +1 -1
- package/dist/job/jobRunner.js +2 -2
- package/dist/message/message.js +8 -6
- package/dist/message/messageContinuation.js +8 -9
- package/dist/milestone/milestone.js +3 -3
- package/dist/observability/executionAudit.js +1 -10
- package/dist/observability/runtimeIdentity.js +0 -23
- package/dist/output/agentConfigurationPresentation.js +4 -2
- package/dist/profile/agentProfile.js +3 -3
- package/dist/release/releaseHandover.js +2 -2
- package/dist/release/releaseIdempotencyStore.js +0 -23
- package/dist/release/releaseWorkflowPorts.js +8 -4
- package/dist/release/runtimeRelease.js +9 -7
- package/dist/repository/gitWorkspace.js +66 -19
- package/dist/repository/project.js +3 -3
- package/dist/repository/taskWorkspacePreparer.js +75 -68
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceRegistry.js +90 -44
- package/dist/resources/sqliteResourceRegistry.js +5 -7
- package/dist/review/reviewRound.js +5 -5
- package/dist/role/role.js +7 -8
- package/dist/runtime/acpProtocol.js +2 -3
- package/dist/runtime/acpSession.js +21 -5
- package/dist/runtime/agentDriverObservation.js +1 -1
- package/dist/runtime/agentEndpoint.js +4 -1
- package/dist/runtime/agentHost.js +25 -65
- package/dist/runtime/agentHostCleanup.js +85 -0
- package/dist/runtime/agentHostProtocol.js +3 -3
- package/dist/runtime/builtinAgentDrivers.js +46 -119
- package/dist/runtime/builtinTranscriptObserver.js +10 -6
- package/dist/runtime/codexAppServerRuntime.js +55 -89
- package/dist/runtime/codexInteractiveHost.js +1 -1
- package/dist/runtime/jsonLineChannel.js +35 -7
- package/dist/runtime/launchBroker.js +1 -1
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/providerContinuationReconciliationService.js +86 -38
- package/dist/runtime/providerRetry.js +15 -0
- package/dist/runtime/providerRuntimeIdentity.js +3 -3
- package/dist/runtime/providerRuntimeReconciler.js +12 -2
- package/dist/runtime/runtimeCoherence.js +7 -3
- package/dist/runtime/runtimeObservation.js +3 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +106 -81
- package/dist/runtime/taskRuntimeIsolation.js +3 -3
- package/dist/runtime/tmuxAdapters.js +3 -3
- package/dist/scheduler/activeRoleRunDelivery.js +5 -1
- package/dist/scheduler/operatorInputNotificationProcessor.js +7 -17
- package/dist/scheduler/taskWake.js +1 -1
- package/dist/storage/baselineSchema.js +606 -0
- package/dist/storage/homeLayout.js +5 -16
- package/dist/storage/recordValidation.js +16 -4
- package/dist/storage/sqliteSchema.js +106 -1741
- package/dist/storage/sqliteStore.js +16 -14
- package/dist/storage/storageSchema.js +8 -7
- package/dist/storage/storageVersions.js +23 -16
- package/dist/storage/taskStore.js +3 -29
- package/dist/storage/upgrade/upgradeOrchestrator.js +14 -112
- package/dist/task/nextAction.js +33 -23
- package/dist/task/task.js +17 -8
- package/dist/task/taskActivation.js +5 -4
- package/dist/telemetry/sqliteTelemetryStore.js +2 -2
- package/dist/verification/gateArtifact.js +5 -3
- package/dist/verification/verificationPlan.js +6 -7
- 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/dist/workItem/workItem.js +6 -6
- package/dist/workspace/cleanupInspection.js +1 -9
- package/dist/worktree/managedWorkspace.js +3 -3
- package/docs/managed-turn-and-session-runtime.md +50 -7
- package/docs/managed-turn-and-session-runtime.zh-CN.md +36 -5
- 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 +70 -214
- package/docs/release-workflow.zh-CN.md +53 -157
- package/docs/roles-and-configuration.md +30 -0
- package/docs/roles-and-configuration.zh-CN.md +20 -0
- package/docs/sqlite-control-plane-design.md +48 -289
- package/docs/sqlite-control-plane-design.zh-CN.md +37 -53
- package/docs/storage-baseline.md +132 -0
- package/docs/storage-baseline.zh-CN.md +106 -0
- package/docs/task-delivery.md +110 -2
- package/docs/task-delivery.zh-CN.md +82 -2
- package/docs/task-discovery.md +9 -0
- package/docs/task-discovery.zh-CN.md +6 -0
- package/docs/testing/verification-levels.md +42 -164
- package/docs/testing/verification-levels.zh-CN.md +29 -115
- package/i18n/README.zh-CN.md +7 -4
- 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
- package/dist/storage/migrations/agentFailureContext.js +0 -22
- package/dist/storage/migrations/agentRunContract.js +0 -159
- package/dist/storage/migrations/artifactsToGit.js +0 -338
- package/dist/storage/migrations/collapseWorktreeLayout.js +0 -963
- package/dist/storage/migrations/currentInputContract.js +0 -86
- package/dist/storage/migrations/currentRuntimeContract.js +0 -228
- package/dist/storage/migrations/historicalVerificationPlan.js +0 -35
- package/dist/storage/migrations/integrationContinuation.js +0 -105
- package/dist/storage/migrations/narrowAgentFailureContext.js +0 -65
- package/dist/storage/migrations/notificationOnlyWakes.js +0 -74
- package/dist/storage/migrations/removeRuntimeGeneration.js +0 -207
- package/dist/storage/migrations/submitIntent.js +0 -126
- package/dist/storage/migrations/unifyHomeLayout.js +0 -925
- package/dist/storage/migrations/verificationPlanV1.js +0 -162
- package/dist/storage/migrations/verificationPolicy.js +0 -74
- package/dist/storage/migrations/workItemHistory.js +0 -46
|
@@ -6,9 +6,10 @@ import { settleGlobalRetryInput } from "../message/globalProviderRetry.js";
|
|
|
6
6
|
import { redactAgentErrorText } from "../runtime/agentError.js";
|
|
7
7
|
import { AGENT_HOST_CONTROL_PROTOCOL, agentHostControlSocketPath, inspectAgentHostSocket, sendAgentHostRunControl } from "../runtime/agentHost.js";
|
|
8
8
|
import { hasRuntimeCleanupObligation, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
9
|
-
import { cancelProviderRetry, providerRetryAttemptId, providerRetryPending } from "../runtime/providerRetry.js";
|
|
9
|
+
import { cancelProviderRetry, providerRetryAttemptId, providerRetryPending, providerRetryProjection } from "../runtime/providerRetry.js";
|
|
10
10
|
import { currentProviderConversation } from "../runtime/providerRuntimeIdentity.js";
|
|
11
11
|
import { retryIntentBlocker } from "./providerRetryAdmission.js";
|
|
12
|
+
import { recordGlobalRuntimeAttention } from "./globalRuntimeAttention.js";
|
|
12
13
|
/** Hooks in the existing Controller pass and nearest-deadline timer. SQLite's
|
|
13
14
|
* current Provider input is the only pending intent; nothing is queued here. */
|
|
14
15
|
export function createProviderRetryHooks(home, store, ports = {}) {
|
|
@@ -45,8 +46,11 @@ export function createProviderRetryHooks(home, store, ports = {}) {
|
|
|
45
46
|
save({ ...current, providerBinding: exhausted
|
|
46
47
|
? { ...cancelled, retry: { ...cancelled.retry, status: "exhausted" } } : cancelled });
|
|
47
48
|
const owner = set.owner;
|
|
48
|
-
if (owner.scope === "global")
|
|
49
|
-
|
|
49
|
+
if (owner.scope === "global") {
|
|
50
|
+
const stopped = load(owner)?.providerBinding;
|
|
51
|
+
settleGlobalRetryInput(store, owner.roleName, stopped, new Date(at));
|
|
52
|
+
recordGlobalRuntimeAttention(store, owner.roleName, `${binding.retry.chainId}:stopped`, providerRetryProjection(stopped), new Date(at));
|
|
53
|
+
}
|
|
50
54
|
if (owner.scope === "task") {
|
|
51
55
|
const event = createTaskEvent(store.nextEventId(owner.taskId), owner.taskId, "provider.retry-stopped", {
|
|
52
56
|
roleName: owner.roleName, chainId: binding.retry.chainId, reason
|
|
@@ -86,131 +90,144 @@ export function createProviderRetryHooks(home, store, ports = {}) {
|
|
|
86
90
|
inspectedUnknown.delete(id);
|
|
87
91
|
for (const set of current) {
|
|
88
92
|
const owner = set.owner;
|
|
89
|
-
const binding = set.providerBinding;
|
|
90
|
-
const retry = binding.retry;
|
|
91
|
-
const at = now(retry);
|
|
92
|
-
const scoped = { ...(owner.scope === "task" ? { taskId: owner.taskId } : {}), roleName: owner.roleName };
|
|
93
|
-
const session = set.sessions[set.activeAgentId];
|
|
94
|
-
const blocker = retryIntentBlocker(store, scoped, retry);
|
|
95
|
-
if (blocker !== undefined && blocker !== "background-work-unsettled") {
|
|
96
|
-
stop(set, blocker, at);
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
if (binding.retryDisabled && retry.successorAutomatic !== false || binding.authority.owner !== "controller"
|
|
100
|
-
|| binding.authority.epoch !== retry.authorityEpoch
|
|
101
|
-
|| currentProviderConversation(binding).conversationId !== retry.nativeSessionId
|
|
102
|
-
|| session?.status !== "active" || session.nativeSessionId !== retry.nativeSessionId
|
|
103
|
-
|| hasRuntimeCleanupObligation(store.getWorkMailbox(runtimeLifecycleTarget(owner)))) {
|
|
104
|
-
stop(set, "session-or-authority-changed", at);
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
// Never replay an admitted attempt. Existing exact runtime queries and
|
|
108
|
-
// terminal ingress resolve it, even across Controller restart.
|
|
109
|
-
if (retry.status === "in-flight") {
|
|
110
|
-
if (binding.run?.status === "delivery-unknown" && retry.currentAttemptId !== undefined
|
|
111
|
-
&& !inspectedUnknown.has(retry.currentAttemptId)) {
|
|
112
|
-
inspectedUnknown.add(retry.currentAttemptId);
|
|
113
|
-
let detail;
|
|
114
|
-
try {
|
|
115
|
-
const host = await inspect({ home, ...scoped, scope: owner.scope });
|
|
116
|
-
detail = host.nativeSessionId === retry.nativeSessionId && host.attemptId === retry.currentAttemptId
|
|
117
|
-
? `Exact Host query: ${host.state}; awaiting original canonical Provider evidence.`
|
|
118
|
-
: "Host query did not prove the original Session/input identity; no replay.";
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
detail = `Original Host query unavailable; no replay: ${redactAgentErrorText(error instanceof Error ? error.message : String(error))}`;
|
|
122
|
-
}
|
|
123
|
-
store.transaction(() => {
|
|
124
|
-
const latest = load(owner);
|
|
125
|
-
if (latest === null || latest.providerBinding == null || latest.providerBinding.run === null
|
|
126
|
-
|| latest.providerBinding.run.attemptId !== retry.currentAttemptId
|
|
127
|
-
|| latest.providerBinding.run.status !== "delivery-unknown")
|
|
128
|
-
return;
|
|
129
|
-
save({ ...latest, providerBinding: { ...latest.providerBinding,
|
|
130
|
-
retry: { ...latest.providerBinding.retry, reason: detail } } });
|
|
131
|
-
if (owner.scope === "task") {
|
|
132
|
-
const event = createTaskEvent(store.nextEventId(owner.taskId), owner.taskId, "provider.retry-unconfirmed", {
|
|
133
|
-
roleName: owner.roleName, attemptId: retry.currentAttemptId, nativeSessionId: retry.nativeSessionId, detail
|
|
134
|
-
}, new Date(at));
|
|
135
|
-
store.saveEvent(owner.taskId, event);
|
|
136
|
-
enqueueWork(store, owner.roleName === "leader" ? { kind: "operator" }
|
|
137
|
-
: { kind: "role", taskId: owner.taskId, roleName: "leader" }, "provider-retry-needs-attention", new Date(at), [{ type: "event", taskId: owner.taskId, id: event.id }]);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (retry.successorAutomatic !== false && at >= Date.parse(retry.deadline)) {
|
|
144
|
-
stop(set, "deadline-exhausted", at, true);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (at < Date.parse(retry.nextEligibleAt) || blocker !== undefined || binding.goal?.status === "active")
|
|
148
|
-
continue;
|
|
149
|
-
if (binding.run?.attemptId !== retry.failedAttemptId) {
|
|
150
|
-
stop(set, "superseded-input", at);
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
93
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
94
|
+
const binding = set.providerBinding;
|
|
95
|
+
const retry = binding.retry;
|
|
96
|
+
const at = now(retry);
|
|
97
|
+
const scoped = { ...(owner.scope === "task" ? { taskId: owner.taskId } : {}), roleName: owner.roleName };
|
|
98
|
+
const session = set.sessions[set.activeAgentId];
|
|
99
|
+
const blocker = retryIntentBlocker(store, scoped, retry);
|
|
100
|
+
if (blocker !== undefined && blocker !== "background-work-unsettled") {
|
|
101
|
+
stop(set, blocker, at);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (binding.retryDisabled && retry.successorAutomatic !== false || binding.authority.owner !== "controller"
|
|
105
|
+
|| binding.authority.epoch !== retry.authorityEpoch
|
|
106
|
+
|| currentProviderConversation(binding).conversationId !== retry.nativeSessionId
|
|
107
|
+
|| session?.status !== "active" || session.nativeSessionId !== retry.nativeSessionId
|
|
108
|
+
|| hasRuntimeCleanupObligation(store.getWorkMailbox(runtimeLifecycleTarget(owner)))) {
|
|
109
|
+
stop(set, "session-or-authority-changed", at);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Never replay an admitted attempt. Existing exact runtime queries and
|
|
113
|
+
// terminal ingress resolve it, even across Controller restart.
|
|
114
|
+
if (retry.status === "in-flight") {
|
|
115
|
+
if (binding.run?.status === "delivery-unknown" && retry.currentAttemptId !== undefined
|
|
116
|
+
&& !inspectedUnknown.has(retry.currentAttemptId)) {
|
|
117
|
+
inspectedUnknown.add(retry.currentAttemptId);
|
|
118
|
+
let detail;
|
|
119
|
+
try {
|
|
120
|
+
const host = await inspect({ home, ...scoped, scope: owner.scope });
|
|
121
|
+
detail = host.nativeSessionId === retry.nativeSessionId && host.attemptId === retry.currentAttemptId
|
|
122
|
+
? `Exact Host query: ${host.state}; awaiting original canonical Provider evidence.`
|
|
123
|
+
: "Host query did not prove the original Session/input identity; no replay.";
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
detail = `Original Host query unavailable; no replay: ${redactAgentErrorText(error instanceof Error ? error.message : String(error))}`;
|
|
127
|
+
}
|
|
128
|
+
store.transaction(() => {
|
|
129
|
+
const latest = load(owner);
|
|
130
|
+
if (latest === null || latest.providerBinding == null || latest.providerBinding.run === null
|
|
131
|
+
|| latest.providerBinding.run.attemptId !== retry.currentAttemptId
|
|
132
|
+
|| latest.providerBinding.run.status !== "delivery-unknown")
|
|
133
|
+
return;
|
|
134
|
+
save({ ...latest, providerBinding: { ...latest.providerBinding,
|
|
135
|
+
retry: { ...latest.providerBinding.retry, reason: detail } } });
|
|
136
|
+
if (owner.scope === "global") {
|
|
137
|
+
recordGlobalRuntimeAttention(store, owner.roleName, `${retry.currentAttemptId}:unconfirmed`, providerRetryProjection(load(owner)?.providerBinding), new Date(at));
|
|
138
|
+
}
|
|
139
|
+
if (owner.scope === "task") {
|
|
140
|
+
const event = createTaskEvent(store.nextEventId(owner.taskId), owner.taskId, "provider.retry-unconfirmed", {
|
|
141
|
+
roleName: owner.roleName, attemptId: retry.currentAttemptId, nativeSessionId: retry.nativeSessionId, detail
|
|
142
|
+
}, new Date(at));
|
|
143
|
+
store.saveEvent(owner.taskId, event);
|
|
144
|
+
enqueueWork(store, owner.roleName === "leader" ? { kind: "operator" }
|
|
145
|
+
: { kind: "role", taskId: owner.taskId, roleName: "leader" }, "provider-retry-needs-attention", new Date(at), [{ type: "event", taskId: owner.taskId, id: event.id }]);
|
|
146
|
+
}
|
|
176
147
|
});
|
|
177
|
-
}
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
178
150
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
151
|
+
if (retry.successorAutomatic !== false && at >= Date.parse(retry.deadline)) {
|
|
152
|
+
stop(set, "deadline-exhausted", at, true);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (at < Date.parse(retry.nextEligibleAt) || blocker !== undefined || binding.goal?.status === "active")
|
|
156
|
+
continue;
|
|
157
|
+
if (binding.run?.attemptId !== retry.failedAttemptId) {
|
|
158
|
+
stop(set, "superseded-input", at);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
if (owner.scope === "task" && retry.previousRunId !== undefined) {
|
|
163
|
+
if (retry.successorRunId !== undefined || retry.successorReviewRoundId !== undefined)
|
|
164
|
+
continue;
|
|
165
|
+
const previous = store.getRun(owner.taskId, retry.previousRunId);
|
|
166
|
+
if (previous?.status === "active")
|
|
167
|
+
continue; // ordinary rejected-delivery terminal fold
|
|
168
|
+
if (previous?.status !== "failed") {
|
|
169
|
+
stop(set, "run-no-longer-failed", at);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const actualTaskReviewCandidate = await ports.snapshotTaskCandidate?.(previous);
|
|
173
|
+
store.transaction(() => {
|
|
174
|
+
const latest = load(owner)?.providerBinding?.retry;
|
|
175
|
+
if (latest?.chainId !== retry.chainId || latest.failedAttemptId !== retry.failedAttemptId
|
|
176
|
+
|| latest.status !== "waiting")
|
|
177
|
+
return;
|
|
178
|
+
const reason = retryIntentBlocker(store, scoped, latest);
|
|
179
|
+
if (reason !== undefined)
|
|
180
|
+
throw new Error(reason);
|
|
181
|
+
runTaskCommand(["run", "retry", `${owner.taskId}/${previous.id}`], store, {
|
|
182
|
+
now: () => new Date(at), environment: {}, providerRetryChainId: retry.chainId,
|
|
183
|
+
...(actualTaskReviewCandidate === undefined ? {} : { actualTaskReviewCandidate })
|
|
184
|
+
});
|
|
185
|
+
});
|
|
189
186
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
187
|
+
else {
|
|
188
|
+
const original = retry.input.kind === "text" ? retry.input.text
|
|
189
|
+
: retry.input.kind === "wake"
|
|
190
|
+
? `Yui Task notification: task=${retry.input.taskId} wake=${retry.input.wakeId}.\nRead current Task context and that fixed wake window, including original Messages in full. This is not an execution assignment.`
|
|
191
|
+
: retry.input.kind === "message"
|
|
192
|
+
? `Yui Global Message: role=${retry.input.roleName} message=${retry.input.messageId}.\nRead your Session Context and referenced original Message in full.`
|
|
193
|
+
: undefined;
|
|
194
|
+
if (original === undefined) {
|
|
195
|
+
stop(set, "original-input-unavailable", at);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const result = await (ports.submit ?? sendAgentHostRunControl)({
|
|
199
|
+
home, ...scoped, scope: owner.scope,
|
|
200
|
+
control: {
|
|
201
|
+
protocol: AGENT_HOST_CONTROL_PROTOCOL, type: "submit-turn", nativeSessionId: retry.nativeSessionId,
|
|
202
|
+
authority: { epoch: binding.authority.epoch, owner: "controller", holderId: binding.authority.holderId },
|
|
203
|
+
run: { attemptId: providerRetryAttemptId(retry), boundedText: original }
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
// Durable settlement belongs to Host/Controller ingress. In
|
|
207
|
+
// particular a lost response is never a reason to replay.
|
|
208
|
+
if (result.outcome === "rejected" && result.failure?.registrationDisposition === "not-committed"
|
|
209
|
+
&& result.failure.errorName !== "ProviderTurnBusyError") {
|
|
210
|
+
stop(set, result.failure.detail, at);
|
|
196
211
|
}
|
|
197
|
-
});
|
|
198
|
-
// Durable settlement belongs to Host/Controller ingress. In
|
|
199
|
-
// particular a lost response is never a reason to replay.
|
|
200
|
-
if (result.outcome === "rejected" && result.failure?.registrationDisposition === "not-committed"
|
|
201
|
-
&& result.failure.errorName !== "ProviderTurnBusyError") {
|
|
202
|
-
stop(set, result.failure.detail, at);
|
|
203
212
|
}
|
|
204
213
|
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
// A send failure may have applied. A durable submitting/unknown
|
|
216
|
+
// identity fences it; do not manufacture a successor to uncertainty.
|
|
217
|
+
const latest = load(owner);
|
|
218
|
+
if (latest?.providerBinding?.run?.attemptId === retry.failedAttemptId) {
|
|
219
|
+
stop(set, error instanceof Error ? error.message : String(error), at);
|
|
220
|
+
}
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
205
223
|
}
|
|
206
224
|
catch (error) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
ports.onError?.(error);
|
|
225
|
+
const failure = new Error(`Provider retry failed for ${owner.scope === "task" ? owner.taskId : "global"}/${owner.roleName}: `
|
|
226
|
+
+ `${error instanceof Error ? error.message : String(error)}. `
|
|
227
|
+
+ "Inspect the current attempt; failed observation does not authorize replay.", { cause: error });
|
|
228
|
+
if (ports.onError === undefined)
|
|
229
|
+
throw failure;
|
|
230
|
+
ports.onError(failure);
|
|
214
231
|
}
|
|
215
232
|
}
|
|
216
233
|
}
|
|
@@ -10,7 +10,6 @@ import { effectiveLaunchConfig, resolveEffectiveLaunch, roleSessionMayContinue }
|
|
|
10
10
|
import { agentProcessReadinessProbe, ExecutorRegistry } from "../executor/executorRegistry.js";
|
|
11
11
|
import { FileRoleLaunchPlanner } from "../executor/fileRoleLaunchPlanner.js";
|
|
12
12
|
import { createKernelPorts } from "../kernel/kernelPorts.js";
|
|
13
|
-
import { createGlobalRoleMessage } from "../message/message.js";
|
|
14
13
|
import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
|
|
15
14
|
import { createResourceAutoGc } from "../resources/autoResourceGc.js";
|
|
16
15
|
import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
|
|
@@ -117,7 +116,7 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
|
|
|
117
116
|
store,
|
|
118
117
|
environment: options.environment,
|
|
119
118
|
tmux,
|
|
120
|
-
nativeConnection: (
|
|
119
|
+
nativeConnection: (owner) => planner.planNativeControl(owner),
|
|
121
120
|
onWarning: options.onError
|
|
122
121
|
});
|
|
123
122
|
// The runtime inbox is also the low-latency discovery source during a
|
|
@@ -252,31 +251,6 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
|
|
|
252
251
|
sessionHost,
|
|
253
252
|
promptPush,
|
|
254
253
|
launchCoordinator,
|
|
255
|
-
notifyOperatorInputOnce: async (input) => {
|
|
256
|
-
// The original attention mailbox remains pending until this one
|
|
257
|
-
// Global Message has an actual Provider receipt. Never inject keys
|
|
258
|
-
// into a busy Host console and mistake that for accepted attention.
|
|
259
|
-
const message = store.transaction(tx => {
|
|
260
|
-
const requestId = `operator-notice:${encodeURIComponent(input.receiptId)}`;
|
|
261
|
-
const previous = tx.listGlobalRoleMessages("operator").find(entry => (entry.inputControl ?? entry.interruptThen?.reusedInput)?.requestId === requestId);
|
|
262
|
-
if (previous !== undefined)
|
|
263
|
-
return previous;
|
|
264
|
-
const sessions = tx.getGlobalRoleSessionSet("operator");
|
|
265
|
-
const session = sessions?.sessions[sessions.activeAgentId];
|
|
266
|
-
if (session?.status !== "active" || sessions?.providerBinding == null)
|
|
267
|
-
return null;
|
|
268
|
-
const created = { ...createGlobalRoleMessage(tx.nextGlobalRoleMessageId(), "operator", input.text, "system", { type: "system" }, new Date(), { inputControl: { action: "queue", requestId } }),
|
|
269
|
-
deliveryTarget: { agentId: session.agentId, nativeSessionId: session.nativeSessionId } };
|
|
270
|
-
tx.saveGlobalRoleMessage(created);
|
|
271
|
-
return created;
|
|
272
|
-
});
|
|
273
|
-
if (message === null)
|
|
274
|
-
return "unavailable";
|
|
275
|
-
if (message.delivery?.via === "provider")
|
|
276
|
-
return "already-sent";
|
|
277
|
-
runningRuntime?.signal("global-role:operator");
|
|
278
|
-
return "not-ready";
|
|
279
|
-
},
|
|
280
254
|
roleResourceInventory: async (panes, inputs) => {
|
|
281
255
|
const inventory = await scanInventory(panes);
|
|
282
256
|
return inventory.resources.flatMap((resource) => {
|
|
@@ -457,7 +431,7 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
|
|
|
457
431
|
const jobControl = kernel.jobs;
|
|
458
432
|
const continuationReconciler = options.continuationMetadata === undefined
|
|
459
433
|
? undefined
|
|
460
|
-
: new ProviderContinuationReconciliationService(store, schedulerStore, options.continuationMetadata);
|
|
434
|
+
: new ProviderContinuationReconciliationService(store, schedulerStore, options.continuationMetadata, options.onError);
|
|
461
435
|
const running = await startFileTaskController(home, schedulerStore, delivery, (method, params) => method === "task.role-capabilities"
|
|
462
436
|
? readTaskAgentCapabilities(store, catalogs, params)
|
|
463
437
|
: method === "web.start" || method === "web.stop" || method === "web.status"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
4
|
+
import { createGlobalRoleMessage } from "../message/message.js";
|
|
4
5
|
import { createSessionOwnerIdentity, isLinuxProcessLive, listOwnedProcessTree, readLinuxProcessIdentity, reconcileSessionOwners, terminateSessionOwners } from "../runtime/index.js";
|
|
5
6
|
import { sessionOwnerProcessKey } from "../runtime/sessionOwnerIdentity.js";
|
|
6
7
|
import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostCancelControl } from "../runtime/agentHost.js";
|
|
7
8
|
import { settleProviderTurn, cancelQuiescentProviderInput, clearProviderGoal } from "../runtime/providerRuntimeIdentity.js";
|
|
8
|
-
import { updateTaskRoleProviderRuntime,
|
|
9
|
+
import { updateTaskRoleProviderRuntime, updateGlobalRoleProviderRuntime, roleSessionControlTarget } from "../executor/agentExecutor.js";
|
|
9
10
|
import { FileRoleLaunchPlanner } from "../executor/fileRoleLaunchPlanner.js";
|
|
10
11
|
import { stopCodexNativeSession } from "../runtime/nativeSessionControl.js";
|
|
11
12
|
import { routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
@@ -34,8 +35,8 @@ export class SessionOwnerReconciliation {
|
|
|
34
35
|
this.#tmux = deps.tmux;
|
|
35
36
|
this.#onWarning = deps.onWarning ?? (() => undefined);
|
|
36
37
|
this.#cancelInput = deps.cancelInput ?? sendAgentHostCancelControl;
|
|
37
|
-
this.#nativeConnection = deps.nativeConnection ?? ((
|
|
38
|
-
.planNativeControl(
|
|
38
|
+
this.#nativeConnection = deps.nativeConnection ?? ((owner) => new FileRoleLaunchPlanner(this.#home, this.#store, { environment: this.#environment })
|
|
39
|
+
.planNativeControl(owner));
|
|
39
40
|
this.#stopNative = deps.stopNative ?? stopCodexNativeSession;
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
@@ -173,33 +174,36 @@ export class SessionOwnerReconciliation {
|
|
|
173
174
|
};
|
|
174
175
|
}
|
|
175
176
|
async #quiesceInput(owner) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (runtimeCleanupDisposition(this.#store.getWorkMailbox(runtimeLifecycleTarget(owner))) === "detach-host")
|
|
177
|
+
const disposition = runtimeCleanupDisposition(this.#store.getWorkMailbox(runtimeLifecycleTarget(owner)));
|
|
178
|
+
if (disposition === "detach-host")
|
|
179
179
|
return;
|
|
180
|
-
const set =
|
|
180
|
+
const set = owner.scope === "task"
|
|
181
|
+
? this.#store.getTaskRoleSessionSet(owner.taskId, owner.roleName)
|
|
182
|
+
: this.#store.getGlobalRoleSessionSet(owner.roleName);
|
|
181
183
|
const binding = set?.providerBinding;
|
|
182
184
|
const input = binding?.run;
|
|
183
185
|
const unsettled = input != null && ["submitting", "accepted", "delivery-unknown"].includes(input.status);
|
|
184
186
|
const hasGoal = binding?.goal != null && binding.goal.status !== "complete";
|
|
185
|
-
const selected =
|
|
187
|
+
const selected = roleSessionControlTarget(set);
|
|
186
188
|
if (set == null || (!unsettled && !hasGoal && selected?.adapterId !== "codex"))
|
|
187
189
|
return;
|
|
188
190
|
if (selected === undefined) {
|
|
189
191
|
throw new Error("Cannot identify the native execution to stop.");
|
|
190
192
|
}
|
|
191
|
-
const request = this.#store.listEvents(owner.taskId).filter(event => ["runtime.session-replacement-requested", "runtime.session-stop-requested"].includes(event.type)
|
|
193
|
+
const request = owner.scope === "task" ? this.#store.listEvents(owner.taskId).filter(event => ["runtime.session-replacement-requested", "runtime.session-stop-requested"].includes(event.type)
|
|
192
194
|
&& event.payload.roleName === owner.roleName
|
|
193
|
-
&& event.payload.nativeSessionId === selected.nativeSessionId).at(-1);
|
|
194
|
-
const operatorStop =
|
|
195
|
-
|
|
195
|
+
&& event.payload.nativeSessionId === selected.nativeSessionId).at(-1) : undefined;
|
|
196
|
+
const operatorStop = owner.scope === "global"
|
|
197
|
+
? disposition === "end-session" || disposition === "replace-session"
|
|
198
|
+
: this.#store.getTask(owner.taskId)?.executionGate.state === "stopped"
|
|
199
|
+
|| (request !== undefined && ["user", "operator"].includes(request.payload.requestedBy));
|
|
196
200
|
if (binding?.authority.owner === "human" && !operatorStop) {
|
|
197
201
|
throw new Error("This native Session is under human control; Operator/user must request its stop or replacement.");
|
|
198
202
|
}
|
|
199
203
|
let terminal;
|
|
200
204
|
try {
|
|
201
205
|
const result = unsettled && binding?.authority.owner === "controller" && binding.authority.holderId !== undefined ? await this.#cancelInput({
|
|
202
|
-
home: this.#home,
|
|
206
|
+
home: this.#home, ...owner,
|
|
203
207
|
control: {
|
|
204
208
|
protocol: AGENT_HOST_CONTROL_PROTOCOL, type: "cancel",
|
|
205
209
|
nativeSessionId: selected.nativeSessionId,
|
|
@@ -220,7 +224,7 @@ export class SessionOwnerReconciliation {
|
|
|
220
224
|
}
|
|
221
225
|
if (terminal === undefined || hasGoal || selected.adapterId === "codex") {
|
|
222
226
|
if (selected.adapterId === "codex") {
|
|
223
|
-
await this.#stopNative(this.#nativeConnection(owner
|
|
227
|
+
await this.#stopNative(this.#nativeConnection(owner), {
|
|
224
228
|
conversationId: selected.nativeSessionId,
|
|
225
229
|
nativeTurnId: unsettled && terminal === undefined ? input?.nativeTurnId : undefined,
|
|
226
230
|
clearGoal: true
|
|
@@ -237,7 +241,7 @@ export class SessionOwnerReconciliation {
|
|
|
237
241
|
}
|
|
238
242
|
else if (selected.status !== "ended"
|
|
239
243
|
|| records.some(ownerRootIsLive)
|
|
240
|
-
|| this.#tmux?.probeRoleStatus(owner.taskId, owner.roleName) !== "exited") {
|
|
244
|
+
|| this.#tmux?.probeRoleStatus(owner.scope === "task" ? owner.taskId : "operator", owner.roleName) !== "exited") {
|
|
241
245
|
throw new Error("Native process custody is unavailable; inspect the exact local execution before reusing its workspace.");
|
|
242
246
|
}
|
|
243
247
|
}
|
|
@@ -246,9 +250,12 @@ export class SessionOwnerReconciliation {
|
|
|
246
250
|
}
|
|
247
251
|
}
|
|
248
252
|
this.#store.transaction(tx => {
|
|
249
|
-
const current =
|
|
253
|
+
const current = owner.scope === "task"
|
|
254
|
+
? tx.getTaskRoleSessionSet(owner.taskId, owner.roleName)
|
|
255
|
+
: tx.getGlobalRoleSessionSet(owner.roleName);
|
|
250
256
|
const provider = current?.providerBinding;
|
|
251
257
|
if (current == null || provider?.run?.attemptId !== input?.attemptId
|
|
258
|
+
|| provider?.run?.nativeTurnId !== input?.nativeTurnId
|
|
252
259
|
|| (selected.fromBinding
|
|
253
260
|
? current.providerBinding?.conversations.find(entry => entry.status === "current")?.conversationId
|
|
254
261
|
: current.sessions[current.activeAgentId]?.nativeSessionId) !== selected.nativeSessionId
|
|
@@ -268,15 +275,26 @@ export class SessionOwnerReconciliation {
|
|
|
268
275
|
}
|
|
269
276
|
if (hasGoal || selected.adapterId === "codex")
|
|
270
277
|
stopped = clearProviderGoal(stopped);
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
+
if (owner.scope === "global") {
|
|
279
|
+
tx.saveGlobalRoleSessionSet(updateGlobalRoleProviderRuntime(current, stopped, now));
|
|
280
|
+
if (unsettled || hasGoal)
|
|
281
|
+
tx.saveGlobalRoleMessage(createGlobalRoleMessage(tx.nextGlobalRoleMessageId(), owner.roleName, `Explicit Session stop confirmed: ${JSON.stringify({
|
|
282
|
+
nativeSessionId: selected.nativeSessionId, attemptId: input?.attemptId,
|
|
283
|
+
nativeTurnId: input?.nativeTurnId, status: stopped.run?.status ?? "quiescent",
|
|
284
|
+
evidence: terminal === undefined ? "native-resource-inspection" : "native-terminal"
|
|
285
|
+
})}`, "system", { type: "system" }, now));
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
tx.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(current, stopped, now));
|
|
289
|
+
tx.saveEvent(owner.taskId, createTaskEvent(tx.nextEventId(owner.taskId), owner.taskId, "runtime.input-stop-confirmed", {
|
|
290
|
+
roleName: owner.roleName, ...(input == null ? {} : { attemptId: input.attemptId }),
|
|
291
|
+
nativeSessionId: selected.nativeSessionId, status: stopped.run?.status ?? "quiescent",
|
|
292
|
+
evidence: terminal === undefined ? "native-resource-inspection" : "native-terminal",
|
|
293
|
+
...(input?.nativeTurnId === undefined ? {} : { nativeTurnId: input.nativeTurnId })
|
|
294
|
+
}, now));
|
|
295
|
+
}
|
|
278
296
|
}
|
|
279
|
-
else if (selected.adapterId === "codex") {
|
|
297
|
+
else if (selected.adapterId === "codex" && owner.scope === "task") {
|
|
280
298
|
tx.saveEvent(owner.taskId, createTaskEvent(tx.nextEventId(owner.taskId), owner.taskId, "runtime.input-stop-confirmed", {
|
|
281
299
|
roleName: owner.roleName, nativeSessionId: selected.nativeSessionId,
|
|
282
300
|
status: "quiescent", evidence: "native-resource-inspection"
|
|
@@ -14,6 +14,33 @@ let deliveryFailure;
|
|
|
14
14
|
// Only live diagnostics for this process's immutable files, not another queue.
|
|
15
15
|
// No payload, retry, or authoritative delivery state is kept in this map.
|
|
16
16
|
const emittedEvents = new Map();
|
|
17
|
+
/** Retained in the existing Host Inbox; it never settles a Turn or a resource. */
|
|
18
|
+
export async function publishStructuredProviderDiagnostic(input) {
|
|
19
|
+
const diagnostic = input.diagnostic;
|
|
20
|
+
const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
|
|
21
|
+
const owner = describeHostIdentity(input.environment, adapterId, diagnostic.nativeSessionId);
|
|
22
|
+
const failure = diagnostic.failure;
|
|
23
|
+
await persistAndApply(input.home, [observation({
|
|
24
|
+
kind: diagnostic.attemptId === undefined ? "conversation.observed" : "observer.health",
|
|
25
|
+
sequence: nextStructuredSequence(), ordinal: 0,
|
|
26
|
+
observedAt: new Date().toISOString(),
|
|
27
|
+
fence: {
|
|
28
|
+
...owner, driverId: builtinAgentDriverRegistry().requireByAdapterId(adapterId).id,
|
|
29
|
+
nativeSessionId: diagnostic.nativeSessionId, conversationId: diagnostic.nativeSessionId,
|
|
30
|
+
...(diagnostic.attemptId === undefined ? {} : { receiptId: diagnostic.attemptId }),
|
|
31
|
+
...(diagnostic.nativeTurnId === undefined ? {} : { nativeTurnId: diagnostic.nativeTurnId })
|
|
32
|
+
},
|
|
33
|
+
payload: {
|
|
34
|
+
...(diagnostic.attemptId === undefined ? { recoverability: "unknown" } : {}),
|
|
35
|
+
sourceId: failure.phase === "host-stop" ? "host-cleanup" : "provider-channel",
|
|
36
|
+
observerStatus: "unavailable", observerDetail: failure.detail,
|
|
37
|
+
failure: { error: standardAgentError({
|
|
38
|
+
source: "host", phase: failure.phase, message: failure.detail, raw: failure.raw ?? failure.detail,
|
|
39
|
+
inputDisposition: failure.inputDisposition, sessionDisposition: failure.sessionDisposition
|
|
40
|
+
}) }
|
|
41
|
+
}
|
|
42
|
+
})], input.environment);
|
|
43
|
+
}
|
|
17
44
|
/** A live transport observation, independent of Provider state and Run truth. */
|
|
18
45
|
export function structuredProviderEventDelivery(home, environment, nativeSessionId) {
|
|
19
46
|
try {
|
|
@@ -354,7 +381,7 @@ function observation(input) {
|
|
|
354
381
|
payload: input.payload ?? {}
|
|
355
382
|
};
|
|
356
383
|
return createRuntimeObservation({
|
|
357
|
-
schemaVersion:
|
|
384
|
+
schemaVersion: 1,
|
|
358
385
|
eventId,
|
|
359
386
|
semanticKey: runtimeObservationSemanticKey(partial),
|
|
360
387
|
kind: input.kind,
|