@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.
Files changed (193) hide show
  1. package/ARCHITECTURE.md +12 -0
  2. package/ARCHITECTURE.zh-CN.md +8 -0
  3. package/README.md +9 -4
  4. package/dist/agent/agent.js +4 -9
  5. package/dist/agent/executionComponents.js +4 -4
  6. package/dist/agent/managedRuntimeEnvironment.js +0 -4
  7. package/dist/agentRun/agentRun.js +13 -23
  8. package/dist/artifacts/managedGit.js +3 -56
  9. package/dist/brief/taskBrief.js +3 -3
  10. package/dist/cli/agentConfigurationPicker.js +24 -21
  11. package/dist/cli/commandCatalog.js +18 -10
  12. package/dist/cli/roleWizard.js +41 -30
  13. package/dist/cli/updateCommand.js +35 -13
  14. package/dist/cli/updateOrchestrator.js +73 -44
  15. package/dist/cli/updatePorts.js +76 -86
  16. package/dist/cli/upgradeCommand.js +4 -8
  17. package/dist/cli.js +39 -33
  18. package/dist/commands/controllerCommands.js +2 -2
  19. package/dist/commands/executionAuditCommands.js +2 -2
  20. package/dist/commands/projectCommands.js +1 -1
  21. package/dist/commands/releaseCommands.js +9 -38
  22. package/dist/commands/taskCommands.js +91 -81
  23. package/dist/commands/taskCompletionGate.js +0 -117
  24. package/dist/commands/taskRoleRuntimeStatus.js +2 -2
  25. package/dist/commands/taskUpstreamCommands.js +93 -54
  26. package/dist/context/runContextPack.js +30 -54
  27. package/dist/context/runInputContract.js +9 -0
  28. package/dist/context/sessionBootstrapManifest.js +11 -19
  29. package/dist/controller/agentHostObservation.js +4 -2
  30. package/dist/controller/agentRuntimeObserver.js +4 -4
  31. package/dist/controller/clientRuntime.js +19 -44
  32. package/dist/controller/controller.js +24 -10
  33. package/dist/controller/fileSchedulerStoreAdapter.js +91 -24
  34. package/dist/controller/globalInputDelivery.js +31 -8
  35. package/dist/controller/globalRuntimeAttention.js +34 -0
  36. package/dist/controller/jobSupervisor.js +3 -3
  37. package/dist/controller/operatorNotification.js +31 -0
  38. package/dist/controller/providerRetryAdmission.js +3 -1
  39. package/dist/controller/providerRetryDelivery.js +136 -119
  40. package/dist/controller/runtime.js +2 -28
  41. package/dist/controller/sessionOwnerReconciliation.js +42 -24
  42. package/dist/controller/structuredProviderObservation.js +28 -1
  43. package/dist/controller/updateReconciliation.js +72 -20
  44. package/dist/coordination/workMailbox.js +4 -4
  45. package/dist/core/controllerIdentity.js +25 -0
  46. package/dist/core/controllerProcessIdentity.js +2 -2
  47. package/dist/core/controllerServer.js +4 -2
  48. package/dist/core/protocol.js +1 -1
  49. package/dist/doctor/doctor.js +2 -1
  50. package/dist/domain/validation.js +6 -0
  51. package/dist/event/taskEvent.js +3 -3
  52. package/dist/execution/workItemExecution.js +2 -2
  53. package/dist/executor/agentAdapter.js +28 -96
  54. package/dist/executor/agentConfigurationCatalog.js +13 -68
  55. package/dist/executor/agentConfigurationFields.js +120 -0
  56. package/dist/executor/agentConfigurationProbe.js +55 -80
  57. package/dist/executor/agentExecutor.js +11 -8
  58. package/dist/executor/effectiveLaunch.js +3 -3
  59. package/dist/executor/executorRegistry.js +0 -9
  60. package/dist/executor/fileRoleLaunchPlanner.js +12 -11
  61. package/dist/grant/capabilityGrant.js +2 -2
  62. package/dist/input/inputRequest.js +4 -4
  63. package/dist/integration/changeSet.js +3 -3
  64. package/dist/integration/integrationAttempt.js +3 -3
  65. package/dist/integration/integrationSourceApplication.js +1 -1
  66. package/dist/interaction/operatorPresentation.js +2 -1
  67. package/dist/job/durableJob.js +1 -1
  68. package/dist/job/jobRunner.js +2 -2
  69. package/dist/message/message.js +8 -6
  70. package/dist/message/messageContinuation.js +8 -9
  71. package/dist/milestone/milestone.js +3 -3
  72. package/dist/observability/executionAudit.js +1 -10
  73. package/dist/observability/runtimeIdentity.js +0 -23
  74. package/dist/output/agentConfigurationPresentation.js +4 -2
  75. package/dist/profile/agentProfile.js +3 -3
  76. package/dist/release/releaseHandover.js +2 -2
  77. package/dist/release/releaseIdempotencyStore.js +0 -23
  78. package/dist/release/releaseWorkflowPorts.js +8 -4
  79. package/dist/release/runtimeRelease.js +9 -7
  80. package/dist/repository/gitWorkspace.js +66 -19
  81. package/dist/repository/project.js +3 -3
  82. package/dist/repository/taskWorkspacePreparer.js +75 -68
  83. package/dist/resources/liveReferences.js +1 -1
  84. package/dist/resources/resourceRegistry.js +90 -44
  85. package/dist/resources/sqliteResourceRegistry.js +5 -7
  86. package/dist/review/reviewRound.js +5 -5
  87. package/dist/role/role.js +7 -8
  88. package/dist/runtime/acpProtocol.js +2 -3
  89. package/dist/runtime/acpSession.js +21 -5
  90. package/dist/runtime/agentDriverObservation.js +1 -1
  91. package/dist/runtime/agentEndpoint.js +4 -1
  92. package/dist/runtime/agentHost.js +25 -65
  93. package/dist/runtime/agentHostCleanup.js +85 -0
  94. package/dist/runtime/agentHostProtocol.js +3 -3
  95. package/dist/runtime/builtinAgentDrivers.js +46 -119
  96. package/dist/runtime/builtinTranscriptObserver.js +10 -6
  97. package/dist/runtime/codexAppServerRuntime.js +55 -89
  98. package/dist/runtime/codexInteractiveHost.js +1 -1
  99. package/dist/runtime/jsonLineChannel.js +35 -7
  100. package/dist/runtime/launchBroker.js +1 -1
  101. package/dist/runtime/processExitObservation.js +1 -1
  102. package/dist/runtime/providerContinuationReconciliationService.js +86 -38
  103. package/dist/runtime/providerRetry.js +15 -0
  104. package/dist/runtime/providerRuntimeIdentity.js +3 -3
  105. package/dist/runtime/providerRuntimeReconciler.js +12 -2
  106. package/dist/runtime/runtimeCoherence.js +7 -3
  107. package/dist/runtime/runtimeObservation.js +3 -3
  108. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  109. package/dist/runtime/structuredProviderHost.js +106 -81
  110. package/dist/runtime/taskRuntimeIsolation.js +3 -3
  111. package/dist/runtime/tmuxAdapters.js +3 -3
  112. package/dist/scheduler/activeRoleRunDelivery.js +5 -1
  113. package/dist/scheduler/operatorInputNotificationProcessor.js +7 -17
  114. package/dist/scheduler/taskWake.js +1 -1
  115. package/dist/storage/baselineSchema.js +606 -0
  116. package/dist/storage/homeLayout.js +5 -16
  117. package/dist/storage/recordValidation.js +16 -4
  118. package/dist/storage/sqliteSchema.js +106 -1741
  119. package/dist/storage/sqliteStore.js +16 -14
  120. package/dist/storage/storageSchema.js +8 -7
  121. package/dist/storage/storageVersions.js +23 -16
  122. package/dist/storage/taskStore.js +3 -29
  123. package/dist/storage/upgrade/upgradeOrchestrator.js +14 -112
  124. package/dist/task/nextAction.js +33 -23
  125. package/dist/task/task.js +17 -8
  126. package/dist/task/taskActivation.js +5 -4
  127. package/dist/telemetry/sqliteTelemetryStore.js +2 -2
  128. package/dist/verification/gateArtifact.js +5 -3
  129. package/dist/verification/verificationPlan.js +6 -7
  130. package/dist/web/assets/assetManifest.js +2 -0
  131. package/dist/web/assets/client/app.js +72 -3
  132. package/dist/web/assets/client/components.js +2 -1
  133. package/dist/web/assets/client/i18n.js +2 -0
  134. package/dist/web/assets/client/taskSummary.js +345 -0
  135. package/dist/web/assets/client/taskSurface.js +44 -26
  136. package/dist/web/assets/client/view.js +33 -0
  137. package/dist/web/assets/shell.js +1 -0
  138. package/dist/web/assets/styles/cards.js +21 -0
  139. package/dist/web/webServer.js +39 -5
  140. package/dist/web/webSessions.js +165 -0
  141. package/dist/web/webSnapshot.js +23 -0
  142. package/dist/web/webTaskSurface.js +23 -0
  143. package/dist/workItem/workItem.js +6 -6
  144. package/dist/workspace/cleanupInspection.js +1 -9
  145. package/dist/worktree/managedWorkspace.js +3 -3
  146. package/docs/managed-turn-and-session-runtime.md +50 -7
  147. package/docs/managed-turn-and-session-runtime.zh-CN.md +36 -5
  148. package/docs/observability/README.md +47 -0
  149. package/docs/observability/README.zh-CN.md +37 -0
  150. package/docs/project-refresh.md +9 -0
  151. package/docs/project-refresh.zh-CN.md +8 -0
  152. package/docs/provider-retry.md +35 -0
  153. package/docs/release-workflow.md +70 -214
  154. package/docs/release-workflow.zh-CN.md +53 -157
  155. package/docs/roles-and-configuration.md +30 -0
  156. package/docs/roles-and-configuration.zh-CN.md +20 -0
  157. package/docs/sqlite-control-plane-design.md +48 -289
  158. package/docs/sqlite-control-plane-design.zh-CN.md +37 -53
  159. package/docs/storage-baseline.md +132 -0
  160. package/docs/storage-baseline.zh-CN.md +106 -0
  161. package/docs/task-delivery.md +110 -2
  162. package/docs/task-delivery.zh-CN.md +82 -2
  163. package/docs/task-discovery.md +9 -0
  164. package/docs/task-discovery.zh-CN.md +6 -0
  165. package/docs/testing/verification-levels.md +42 -164
  166. package/docs/testing/verification-levels.zh-CN.md +29 -115
  167. package/i18n/README.zh-CN.md +7 -4
  168. package/package.json +1 -1
  169. package/skills/yui-leader/SKILL.md +11 -0
  170. package/skills/yui-leader/references/execution.md +22 -0
  171. package/skills/yui-leader/references/planning.md +6 -2
  172. package/skills/yui-operator/SKILL.md +45 -13
  173. package/skills/yui-operator/references/task-delivery.md +99 -0
  174. package/skills/yui-runtime/SKILL.md +5 -3
  175. package/skills/yui-runtime/references/publication.md +56 -5
  176. package/skills/yui-runtime/references/recovery.md +12 -2
  177. package/dist/runtime/agentHostCompatibility.js +0 -127
  178. package/dist/storage/migrations/agentFailureContext.js +0 -22
  179. package/dist/storage/migrations/agentRunContract.js +0 -159
  180. package/dist/storage/migrations/artifactsToGit.js +0 -338
  181. package/dist/storage/migrations/collapseWorktreeLayout.js +0 -963
  182. package/dist/storage/migrations/currentInputContract.js +0 -86
  183. package/dist/storage/migrations/currentRuntimeContract.js +0 -228
  184. package/dist/storage/migrations/historicalVerificationPlan.js +0 -35
  185. package/dist/storage/migrations/integrationContinuation.js +0 -105
  186. package/dist/storage/migrations/narrowAgentFailureContext.js +0 -65
  187. package/dist/storage/migrations/notificationOnlyWakes.js +0 -74
  188. package/dist/storage/migrations/removeRuntimeGeneration.js +0 -207
  189. package/dist/storage/migrations/submitIntent.js +0 -126
  190. package/dist/storage/migrations/unifyHomeLayout.js +0 -925
  191. package/dist/storage/migrations/verificationPlanV1.js +0 -162
  192. package/dist/storage/migrations/verificationPolicy.js +0 -74
  193. 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
- settleGlobalRetryInput(store, owner.roleName, load(owner)?.providerBinding, new Date(at));
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
- if (owner.scope === "task" && retry.previousRunId !== undefined) {
155
- if (retry.successorRunId !== undefined || retry.successorReviewRoundId !== undefined)
156
- continue;
157
- const previous = store.getRun(owner.taskId, retry.previousRunId);
158
- if (previous?.status === "active")
159
- continue; // ordinary rejected-delivery terminal fold
160
- if (previous?.status !== "failed") {
161
- stop(set, "run-no-longer-failed", at);
162
- continue;
163
- }
164
- const actualTaskReviewCandidate = await ports.snapshotTaskCandidate?.(previous);
165
- store.transaction(() => {
166
- const latest = load(owner)?.providerBinding?.retry;
167
- if (latest?.chainId !== retry.chainId || latest.failedAttemptId !== retry.failedAttemptId
168
- || latest.status !== "waiting")
169
- return;
170
- const reason = retryIntentBlocker(store, scoped, latest);
171
- if (reason !== undefined)
172
- throw new Error(reason);
173
- runTaskCommand(["run", "retry", `${owner.taskId}/${previous.id}`], store, {
174
- now: () => new Date(at), environment: {}, providerRetryChainId: retry.chainId,
175
- ...(actualTaskReviewCandidate === undefined ? {} : { actualTaskReviewCandidate })
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
- else {
180
- const original = retry.input.kind === "text" ? retry.input.text
181
- : retry.input.kind === "wake"
182
- ? `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.`
183
- : retry.input.kind === "message"
184
- ? `Yui Global Message: role=${retry.input.roleName} message=${retry.input.messageId}.\nRead your Session Context and referenced original Message in full.`
185
- : undefined;
186
- if (original === undefined) {
187
- stop(set, "original-input-unavailable", at);
188
- continue;
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
- const result = await (ports.submit ?? sendAgentHostRunControl)({
191
- home, ...scoped, scope: owner.scope,
192
- control: {
193
- protocol: AGENT_HOST_CONTROL_PROTOCOL, type: "submit-turn", nativeSessionId: retry.nativeSessionId,
194
- authority: { epoch: binding.authority.epoch, owner: "controller", holderId: binding.authority.holderId },
195
- run: { attemptId: providerRetryAttemptId(retry), boundedText: original }
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
- // A send failure may have applied. A durable submitting/unknown
208
- // identity fences it; do not manufacture a successor to uncertainty.
209
- const latest = load(owner);
210
- if (latest?.providerBinding?.run?.attemptId === retry.failedAttemptId) {
211
- stop(set, error instanceof Error ? error.message : String(error), at);
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: (taskId, roleName) => planner.planNativeControl(taskId, roleName),
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, taskRoleControlTarget } from "../executor/agentExecutor.js";
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 ?? ((taskId, roleName) => new FileRoleLaunchPlanner(this.#home, this.#store, { environment: this.#environment })
38
- .planNativeControl(taskId, roleName));
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
- if (owner.scope !== "task")
177
- return;
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 = this.#store.getTaskRoleSessionSet(owner.taskId, owner.roleName);
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 = taskRoleControlTarget(set);
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 = this.#store.getTask(owner.taskId)?.executionGate.state === "stopped"
195
- || (request !== undefined && ["user", "operator"].includes(request.payload.requestedBy));
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, scope: "task", taskId: owner.taskId, roleName: owner.roleName,
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.taskId, owner.roleName), {
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 = tx.getTaskRoleSessionSet(owner.taskId, owner.roleName);
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
- tx.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(current, stopped, now));
272
- tx.saveEvent(owner.taskId, createTaskEvent(tx.nextEventId(owner.taskId), owner.taskId, "runtime.input-stop-confirmed", {
273
- roleName: owner.roleName, ...(input == null ? {} : { attemptId: input.attemptId }),
274
- nativeSessionId: selected.nativeSessionId, status: stopped.run?.status ?? "quiescent",
275
- evidence: terminal === undefined ? "native-resource-inspection" : "native-terminal",
276
- ...(input?.nativeTurnId === undefined ? {} : { nativeTurnId: input.nativeTurnId })
277
- }, now));
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: 4,
384
+ schemaVersion: 1,
358
385
  eventId,
359
386
  semanticKey: runtimeObservationSemanticKey(partial),
360
387
  kind: input.kind,