@zq-silk/yui 0.13.9 → 0.14.0

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 (229) hide show
  1. package/ARCHITECTURE.md +69 -428
  2. package/README.md +108 -298
  3. package/dist/agent/managedRuntimeEnvironment.js +2 -2
  4. package/dist/cli/commandCatalog.js +39 -77
  5. package/dist/cli/interactionCandidates.js +4 -4
  6. package/dist/cli/interactionPolicy.js +7 -10
  7. package/dist/cli/invocationRouter.js +1 -1
  8. package/dist/cli/updateCommand.js +6 -27
  9. package/dist/cli/updateOrchestrator.js +63 -484
  10. package/dist/cli/updatePorts.js +15 -333
  11. package/dist/cli/upgradeCommand.js +8 -65
  12. package/dist/cli.js +57 -242
  13. package/dist/commands/configCommands.js +11 -62
  14. package/dist/commands/executionAuditCommands.js +23 -23
  15. package/dist/commands/globalRoleCommands.js +2 -7
  16. package/dist/commands/jobCommands.js +1 -4
  17. package/dist/commands/projectCommands.js +5 -5
  18. package/dist/commands/releaseCommands.js +3 -10
  19. package/dist/commands/resourcesCommands.js +2 -2
  20. package/dist/commands/sessionCommands.js +2 -2
  21. package/dist/commands/taskActor.js +31 -39
  22. package/dist/commands/taskChangeSetCommands.js +5 -12
  23. package/dist/commands/taskCommands.js +464 -1249
  24. package/dist/commands/taskContextCommand.js +35 -36
  25. package/dist/commands/taskExecutionCommands.js +33 -46
  26. package/dist/commands/taskInputCommands.js +20 -42
  27. package/dist/commands/taskNextActionCommand.js +9 -9
  28. package/dist/commands/taskOverviewCommand.js +56 -95
  29. package/dist/commands/taskRoleRuntimeStatus.js +77 -107
  30. package/dist/commands/taskUpstreamCommands.js +3 -3
  31. package/dist/commands/taskWorkspaceCommands.js +7 -79
  32. package/dist/commands/telemetryCommands.js +32 -124
  33. package/dist/commands/workflowCommands.js +3 -3
  34. package/dist/completion/fileCompletionManager.js +1 -1
  35. package/dist/config/configCatalog.js +4 -6
  36. package/dist/config/yuiConfig.js +6 -43
  37. package/dist/context/dispatchContext.js +14 -30
  38. package/dist/context/roleSessionContext.js +2 -2
  39. package/dist/context/sessionBootstrapManifest.js +2 -2
  40. package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
  41. package/dist/context/turnInputContract.js +204 -0
  42. package/dist/context/wakeNotification.js +2 -2
  43. package/dist/controller/agentRuntimeObserver.js +18 -18
  44. package/dist/controller/clientRuntime.js +13 -20
  45. package/dist/controller/controller.js +89 -116
  46. package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
  47. package/dist/controller/jobControl.js +17 -17
  48. package/dist/controller/resourceInventory.js +6 -6
  49. package/dist/controller/resourceInventoryLinux.js +38 -59
  50. package/dist/controller/resourceInventoryRpc.js +3 -3
  51. package/dist/controller/resourceInventoryWorker.js +1 -1
  52. package/dist/controller/runtime.js +46 -53
  53. package/dist/controller/runtimeEventInbox.js +23 -31
  54. package/dist/controller/runtimeEventProcessor.js +15 -15
  55. package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
  56. package/dist/controller/runtimeLaunchCoordinator.js +3 -3
  57. package/dist/controller/runtimeObservationHook.js +11 -8
  58. package/dist/controller/sessionNotify.js +11 -11
  59. package/dist/controller/structuredProviderObservation.js +89 -16
  60. package/dist/coordination/workMailbox.js +309 -579
  61. package/dist/coordination/workMailboxQueue.js +5 -6
  62. package/dist/core/controllerClient.js +1 -91
  63. package/dist/core/controllerServer.js +3 -6
  64. package/dist/doctor/doctor.js +51 -314
  65. package/dist/execution/candidateConvergence.js +3 -3
  66. package/dist/execution/executionGroup.js +32 -33
  67. package/dist/execution/executionHealth.js +36 -38
  68. package/dist/execution/resourceBroker.js +12 -12
  69. package/dist/executor/agentExecutor.js +30 -265
  70. package/dist/executor/effectiveLaunch.js +9 -19
  71. package/dist/executor/executorRegistry.js +43 -17
  72. package/dist/executor/fileRoleLaunchPlanner.js +56 -56
  73. package/dist/executor/launchPlan.js +3 -3
  74. package/dist/executor/workspacePreflightClassification.js +16 -16
  75. package/dist/grant/capabilityGrant.js +20 -25
  76. package/dist/input/inputRequest.js +12 -12
  77. package/dist/integration/changeSet.js +9 -13
  78. package/dist/integration/changeSetManifest.js +1 -1
  79. package/dist/integration/gitIntegrationService.js +2 -2
  80. package/dist/integration/integrationQueueService.js +5 -21
  81. package/dist/integration/overlapDiagnostics.js +2 -2
  82. package/dist/interaction/operatorPresentation.js +1 -1
  83. package/dist/job/jobRunner.js +1 -1
  84. package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
  85. package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
  86. package/dist/message/message.js +6 -6
  87. package/dist/observability/executionAudit.js +74 -86
  88. package/dist/observability/faultClassification.js +7 -24
  89. package/dist/observability/orchestrationMetrics.js +5 -5
  90. package/dist/observability/runtimeIdentity.js +34 -101
  91. package/dist/profile/agentProfile.js +1 -1
  92. package/dist/release/cliHomeReleaseFence.js +3 -3
  93. package/dist/release/releaseWorkflowEngine.js +6 -10
  94. package/dist/release/releaseWorkflowPorts.js +2 -2
  95. package/dist/release/workflowFileLock.js +1 -1
  96. package/dist/repository/checkoutSwap.js +1 -1
  97. package/dist/repository/gitWorkspace.js +0 -13
  98. package/dist/repository/project.js +1 -1
  99. package/dist/repository/projectMaintenanceLock.js +1 -2
  100. package/dist/repository/taskBaseFreshness.js +13 -13
  101. package/dist/repository/taskWorkspaceCoordinator.js +21 -25
  102. package/dist/repository/taskWorkspaceIdentity.js +8 -21
  103. package/dist/repository/taskWorkspacePreparer.js +63 -620
  104. package/dist/resources/autoResourceGc.js +3 -3
  105. package/dist/resources/liveReferences.js +1 -1
  106. package/dist/resources/resourceGc.js +1 -1
  107. package/dist/resources/sqliteResourceRegistry.js +1 -1
  108. package/dist/review/reviewDecision.js +7 -7
  109. package/dist/review/reviewFindingLedger.js +1 -1
  110. package/dist/review/reviewOutcomeClassifier.js +35 -50
  111. package/dist/review/reviewRound.js +14 -25
  112. package/dist/review/reviewerAvailability.js +4 -4
  113. package/dist/review/taskFinalReviewContractResolution.js +41 -0
  114. package/dist/role/role.js +6 -3
  115. package/dist/runtime/agentDriver.js +4 -0
  116. package/dist/runtime/agentHost.js +151 -36
  117. package/dist/runtime/builtinAgentDrivers.js +79 -2
  118. package/dist/runtime/codexAppServerRuntime.js +122 -0
  119. package/dist/runtime/continuationManager.js +3 -5
  120. package/dist/runtime/exactControlPlane.js +17 -42
  121. package/dist/runtime/firstProgressAdvisory.js +1 -1
  122. package/dist/runtime/index.js +2 -2
  123. package/dist/runtime/launchDiagnostics.js +2 -2
  124. package/dist/runtime/lifecycleReservation.js +4 -4
  125. package/dist/runtime/processExitObservation.js +1 -1
  126. package/dist/runtime/processExitOutbox.js +0 -32
  127. package/dist/runtime/promptEnvelope.js +9 -9
  128. package/dist/runtime/providerContinuation.js +2 -2
  129. package/dist/runtime/providerContinuationReconciliationService.js +2 -2
  130. package/dist/runtime/providerRuntimeIdentity.js +76 -24
  131. package/dist/runtime/recentTurnIds.js +38 -0
  132. package/dist/runtime/runtimeContinuationProjection.js +2 -2
  133. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  134. package/dist/runtime/runtimeObservation.js +58 -21
  135. package/dist/runtime/runtimeProjection.js +19 -27
  136. package/dist/runtime/sessionLaunchRequest.js +2 -2
  137. package/dist/runtime/structuredProviderHost.js +177 -12
  138. package/dist/runtime/tmuxAdapters.js +46 -11
  139. package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
  140. package/dist/scheduler/leaderWakeupProcessor.js +147 -445
  141. package/dist/scheduler/operatorEvent.js +4 -6
  142. package/dist/scheduler/resourceQueueProjection.js +71 -0
  143. package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
  144. package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
  145. package/dist/scheduler/taskExecutionProjection.js +99 -99
  146. package/dist/scheduler/taskObservabilityProjection.js +10 -10
  147. package/dist/scheduler/taskWake.js +4 -4
  148. package/dist/scheduler/wakeReason.js +6 -10
  149. package/dist/scheduler/wakeupQueue.js +0 -9
  150. package/dist/setup/setupCommand.js +2 -2
  151. package/dist/storage/currentTaskStore.js +46 -0
  152. package/dist/storage/persistenceWorker.js +1 -1
  153. package/dist/storage/sqliteSchema.js +81 -485
  154. package/dist/storage/sqliteStore.js +206 -365
  155. package/dist/storage/storageSchema.js +1 -15
  156. package/dist/storage/storageVersions.js +8 -9
  157. package/dist/storage/storeRpc.js +10 -34
  158. package/dist/storage/taskStore.js +63 -3415
  159. package/dist/storage/upgrade/recordVersions.js +55 -149
  160. package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
  161. package/dist/task/completionReadiness.js +5 -5
  162. package/dist/task/deliveryGuard.js +10 -10
  163. package/dist/task/nextAction.js +74 -77
  164. package/dist/task/task.js +2 -4
  165. package/dist/task/taskRecordReference.js +3 -3
  166. package/dist/task/taskRecordRetirement.js +1 -1
  167. package/dist/telemetry/sqliteTelemetryStore.js +53 -53
  168. package/dist/telemetry/telemetryConfig.js +14 -14
  169. package/dist/telemetry/telemetryWiring.js +8 -14
  170. package/dist/turn/turn.js +356 -0
  171. package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
  172. package/dist/verification/gateArtifactStore.js +2 -2
  173. package/dist/web/assets/client/app.js +1 -1
  174. package/dist/web/assets/client/components.js +29 -54
  175. package/dist/web/assets/client/i18n.js +17 -37
  176. package/dist/web/assets/client/view.js +37 -37
  177. package/dist/web/assets/shell.js +1 -1
  178. package/dist/web/assets/styles/cards.js +5 -5
  179. package/dist/web/assets/styles/widgets.js +1 -2
  180. package/dist/web/webSnapshot.js +65 -60
  181. package/dist/workItem/workItem.js +11 -11
  182. package/dist/workspace/workItemChangeSetManager.js +1 -1
  183. package/docs/task-local-identity.md +5 -5
  184. package/i18n/README.zh-CN.md +41 -54
  185. package/package.json +1 -1
  186. package/skills/yui-leader/SKILL.md +85 -83
  187. package/skills/yui-operator/SKILL.md +16 -16
  188. package/skills/yui-reviewer/SKILL.md +10 -10
  189. package/skills/yui-runtime/SKILL.md +17 -18
  190. package/skills/yui-worker/SKILL.md +16 -18
  191. package/dist/context/runContextContract.js +0 -162
  192. package/dist/executor/turnCompletion.js +0 -126
  193. package/dist/review/taskFinalReviewContractEvent.js +0 -1
  194. package/dist/review/taskFinalReviewContractRebind.js +0 -367
  195. package/dist/run/agentRun.js +0 -356
  196. package/dist/run/rejectedYieldAttempt.js +0 -221
  197. package/dist/run/runControlRequest.js +0 -50
  198. package/dist/run/yieldReceipt.js +0 -65
  199. package/dist/runtime/turnCompletion.js +0 -3
  200. package/dist/scheduler/actionability.js +0 -323
  201. package/dist/scheduler/activeRoleRunDelivery.js +0 -868
  202. package/dist/scheduler/activeTaskProgress.js +0 -126
  203. package/dist/storage/compatibleTaskStore.js +0 -248
  204. package/dist/storage/migration/baseline.js +0 -78
  205. package/dist/storage/migration/classifier.js +0 -51
  206. package/dist/storage/migration/compatibleCodec.js +0 -53
  207. package/dist/storage/migration/engine.js +0 -147
  208. package/dist/storage/migration/index.js +0 -33
  209. package/dist/storage/migration/planner.js +0 -154
  210. package/dist/storage/migration/productionRegistry.js +0 -3931
  211. package/dist/storage/migration/registry.js +0 -169
  212. package/dist/storage/migration/report.js +0 -54
  213. package/dist/storage/migration/types.js +0 -31
  214. package/dist/storage/upgrade/homeClassification.js +0 -353
  215. package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
  216. package/dist/storage/upgrade/migrationReceipt.js +0 -67
  217. package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
  218. package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
  219. package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
  220. package/dist/storage/upgrade/recordVersionScan.js +0 -176
  221. package/dist/storage/upgrade/sqliteFileSet.js +0 -50
  222. package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
  223. package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
  224. package/dist/storage/upgrade/sqliteStateMigration.js +0 -918
  225. package/dist/storage/upgrade/switchProgress.js +0 -80
  226. package/dist/storage/upgrade/upgradeReceipt.js +0 -161
  227. package/dist/storage/upgradeCoordination.js +0 -187
  228. package/dist/storage/upgradeFence.js +0 -366
  229. package/dist/telemetry/telemetryCompaction.js +0 -252
@@ -3,11 +3,9 @@ import { readFileSync, realpathSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { callController as defaultCallController } from "../core/controllerClient.js";
5
5
  import { inspectStorageSchema } from "../storage/storageSchema.js";
6
- import { openCompatibleFileTaskStore } from "../storage/compatibleTaskStore.js";
7
6
  import { yuiVersionIdentity } from "../version.js";
8
7
  import { hasRuntimeCleanupObligation, isRuntimeLaunchReservation, runtimeLifecycleTarget } from "./lifecycleReservation.js";
9
8
  import { nativeSessionIdForLaunch } from "./preallocatedNativeSession.js";
10
- import { agentRunDeliveryReceiptId } from "../run/agentRun.js";
11
9
  import { writeTextFileAtomically } from "../storage/durableFile.js";
12
10
  export const EXACT_CONTROL_ARGUMENT = "--yui-control";
13
11
  export const YUI_CONTROL_PLANE_DESCRIPTOR = "YUI_CONTROL_PLANE_DESCRIPTOR";
@@ -37,7 +35,7 @@ export function createExactTaskRuntimeDescriptor(input) {
37
35
  agentId: requireIdentity(input.agentId, "Agent id"),
38
36
  adapterId: requireAdapter(input.adapterId),
39
37
  workspace: canonicalPath(input.workspace),
40
- ...(input.runId === undefined ? {} : { runId: requireIdentity(input.runId, "Run id") }),
38
+ ...(input.turnId === undefined ? {} : { turnId: requireIdentity(input.turnId, "Turn id") }),
41
39
  ...(input.launchId === undefined
42
40
  ? {}
43
41
  : { launchId: requireIdentity(input.launchId, "Launch id") }),
@@ -79,7 +77,7 @@ export function parseExactTaskRuntimeDescriptor(value) {
79
77
  agentId: requireText(record.agentId, "Agent id"),
80
78
  adapterId: requireAdapter(record.adapterId),
81
79
  workspace: requireText(record.workspace, "Task runtime workspace"),
82
- ...(record.runId === undefined ? {} : { runId: requireText(record.runId, "Run id") }),
80
+ ...(record.turnId === undefined ? {} : { turnId: requireText(record.turnId, "Turn id") }),
83
81
  ...(record.launchId === undefined
84
82
  ? {}
85
83
  : { launchId: requireText(record.launchId, "Launch id") }),
@@ -91,7 +89,7 @@ export function parseExactTaskRuntimeDescriptor(value) {
91
89
  export function exactControlPlaneDigest(descriptor) {
92
90
  return createHash("sha256").update(serializeExactDescriptor(descriptor)).digest("hex");
93
91
  }
94
- /** Stable per Task/Role/Agent location; volatile Run/launch/native fields are content. */
92
+ /** Stable per Task/Role/Agent location; volatile Turn/launch/native fields are content. */
95
93
  export function exactTaskRuntimeDescriptorPath(home, descriptor) {
96
94
  const validated = createExactTaskRuntimeDescriptor(descriptor);
97
95
  const digest = createHash("sha256").update(JSON.stringify([
@@ -153,15 +151,7 @@ export async function assertExactControlPlanePreflight(input, options = {}) {
153
151
  assertContinuityIdentity("Local CLI", descriptor.identity, localIdentity);
154
152
  const storage = (options.inspectStorage ?? inspectStorageSchema)(descriptor.yuiHome);
155
153
  if (storage.status !== "current") {
156
- const exactRecordOnlyOlder = storage.status === "unsupported"
157
- && storage.incompatibleComponent === "record"
158
- && storage.direction === "older"
159
- && storage.currentLayoutVersion === descriptor.identity.storageLayoutVersion
160
- && storage.currentAggregateSchemaVersion === descriptor.identity.aggregateSchemaVersion;
161
- if (!exactRecordOnlyOlder) {
162
- throw new Error(`Exact control-plane storage is not current: ${storage.status}.`);
163
- }
164
- (options.openCompatibleStore ?? openCompatibleFileTaskStore)(descriptor.yuiHome).getConfig();
154
+ throw new Error(`Exact control-plane storage is not current: ${storage.status}.`);
165
155
  }
166
156
  if (storage.currentLayoutVersion !== descriptor.identity.storageLayoutVersion) {
167
157
  throw new Error("Exact control-plane storage layout does not match its frozen descriptor "
@@ -176,7 +166,7 @@ export async function assertExactControlPlanePreflight(input, options = {}) {
176
166
  // A frozen descriptor authenticates the command that created it; it no
177
167
  // longer pins the Home's deployment pointer for the lifetime of a Session.
178
168
  // Continuity is the protocol/storage contract checked above and the durable
179
- // Task/Role/Run identity checked below. This lets a compatible Controller or
169
+ // Task/Role/Turn identity checked below. This lets a compatible Controller or
180
170
  // active release advance without invalidating a still-current Session.
181
171
  if (options.checkController !== false) {
182
172
  const call = options.callController ?? defaultCallController;
@@ -202,15 +192,7 @@ export async function assertCompatibleControlPlanePreflight(input, options = {})
202
192
  const identity = validateVersionIdentity(options.identity ?? yuiVersionIdentity());
203
193
  const storage = (options.inspectStorage ?? inspectStorageSchema)(home);
204
194
  if (storage.status !== "current") {
205
- const compatibleRecordOnlyOlder = storage.status === "unsupported"
206
- && storage.incompatibleComponent === "record"
207
- && storage.direction === "older"
208
- && storage.currentLayoutVersion === identity.storageLayoutVersion
209
- && storage.currentAggregateSchemaVersion === identity.aggregateSchemaVersion;
210
- if (!compatibleRecordOnlyOlder) {
211
- throw new Error(`Managed control-plane storage is not current: ${storage.status}.`);
212
- }
213
- (options.openCompatibleStore ?? openCompatibleFileTaskStore)(home).getConfig();
195
+ throw new Error(`Managed control-plane storage is not current: ${storage.status}.`);
214
196
  }
215
197
  if (storage.currentLayoutVersion !== identity.storageLayoutVersion) {
216
198
  throw new Error("Managed control-plane storage layout is incompatible "
@@ -257,9 +239,9 @@ export function assertExactTaskRuntimeEnvironment(runtimeSource, environment, ex
257
239
  assertSamePath(runtime.workspace, requireText(environment.YUI_WORKSPACE, "YUI_WORKSPACE"), "Task runtime workspace");
258
240
  // A reused native pane retains its original process environment. Volatile
259
241
  // identity therefore comes only from the atomically published descriptor
260
- // plus durable state, never from stale ambient Run/launch/native variables.
242
+ // plus durable state, never from stale ambient Turn/launch/native variables.
261
243
  if (!resolved.fromFile) {
262
- assertOptionalEnvironment(runtime.runId, environment.YUI_RUN_ID, "Run id");
244
+ assertOptionalEnvironment(runtime.turnId, environment.YUI_TURN_ID, "Turn id");
263
245
  assertOptionalEnvironment(runtime.launchId, environment.YUI_LAUNCH_ID, "Launch id");
264
246
  assertOptionalEnvironment(runtime.nativeSessionId, environment.YUI_NATIVE_SESSION_ID, "Native session id");
265
247
  }
@@ -277,18 +259,18 @@ export function assertExactTaskRuntimeState(runtime, store, options = {}) {
277
259
  if (role === null || role.activeAgentId !== runtime.agentId) {
278
260
  throw new Error("Exact Task runtime Role or Agent is not current.");
279
261
  }
280
- const run = store.getActiveAgentRun(runtime.taskId, runtime.roleName);
281
- if (runtime.runId === undefined) {
262
+ const run = store.getActiveTurn(runtime.taskId, runtime.roleName);
263
+ if (runtime.turnId === undefined) {
282
264
  if (run !== null)
283
- throw new Error("Exact Task runtime Run is not current.");
265
+ throw new Error("Exact Task runtime Turn is not current.");
284
266
  }
285
267
  else if (run === null
286
- || run.id !== runtime.runId
268
+ || run.id !== runtime.turnId
287
269
  || run.status !== "active"
288
270
  || run.effective.agentId !== runtime.agentId
289
271
  || run.effective.adapterId !== runtime.adapterId
290
272
  || canonicalPath(run.effective.workspace.root) !== runtime.workspace) {
291
- throw new Error("Exact Task runtime Run is not current.");
273
+ throw new Error("Exact Task runtime Turn is not current.");
292
274
  }
293
275
  const sessions = store.getTaskRoleSessionSet(runtime.taskId, runtime.roleName);
294
276
  const session = sessions?.sessions[runtime.agentId];
@@ -317,13 +299,6 @@ export function assertExactTaskRuntimeState(runtime, store, options = {}) {
317
299
  && runtime.nativeSessionId !== undefined
318
300
  && (session === undefined || terminalSessionReplacementReservation)
319
301
  && runtime.nativeSessionId === nativeSessionIdForLaunch(preallocated.yuiHome, runtime.launchId, runtime.agentId, runtime.adapterId);
320
- const preallocatedBeforeInFlightProjection = exactPreallocatedReservation
321
- && (sessions?.inFlight === null || sessions?.inFlight === undefined);
322
- if (runtime.runId !== undefined && (sessions?.inFlight?.agentId !== runtime.agentId
323
- || sessions.inFlight.runId !== runtime.runId
324
- || sessions.inFlight.receiptId !== agentRunDeliveryReceiptId(run)) && !preallocatedBeforeInFlightProjection) {
325
- throw new Error("Exact Task runtime in-flight Run fence is not current.");
326
- }
327
302
  if (runtime.launchId === undefined || (!reservation && !sessionLaunch)) {
328
303
  throw new Error("Exact Task runtime launch fence is not current.");
329
304
  }
@@ -372,10 +347,10 @@ export function refreshExactTaskRuntimeDescriptorSource(source, home, store) {
372
347
  return refreshed;
373
348
  }
374
349
  /**
375
- * Advances a reused Hook's own exact source to the current durable Run/launch
350
+ * Advances a reused Hook's own exact source to the current durable Turn/launch
376
351
  * generation before the volatile fence. The stable identity (control digest,
377
352
  * Task, Role, Agent, adapter, workspace) and the native Session are preserved;
378
- * only the volatile Run/launch fields advance. A source may never jump to a
353
+ * only the volatile Turn/launch fields advance. A source may never jump to a
379
354
  * replacement native Session.
380
355
  */
381
356
  export function refreshReusedTaskRuntimeDescriptorSource(source, home, store, current) {
@@ -385,7 +360,7 @@ export function refreshReusedTaskRuntimeDescriptorSource(source, home, store, cu
385
360
  }
386
361
  const previous = resolved.descriptor;
387
362
  if (previous.nativeSessionId === undefined) {
388
- if (previous.runId !== current.runId || previous.launchId !== current.launchId) {
363
+ if (previous.turnId !== current.turnId || previous.launchId !== current.launchId) {
389
364
  throw new Error("Task runtime descriptor source cannot bind a native Session from another generation.");
390
365
  }
391
366
  return refreshExactTaskRuntimeDescriptorSource(source, home, store);
@@ -395,7 +370,7 @@ export function refreshReusedTaskRuntimeDescriptorSource(source, home, store, cu
395
370
  }
396
371
  const refreshed = createExactTaskRuntimeDescriptor({
397
372
  ...previous,
398
- runId: current.runId,
373
+ turnId: current.turnId,
399
374
  launchId: current.launchId,
400
375
  nativeSessionId: current.nativeSessionId
401
376
  });
@@ -12,7 +12,7 @@ export function projectFirstProgressAdvisory(input) {
12
12
  ? []
13
13
  : [
14
14
  ...input.events
15
- .filter((event) => typeof event.payload.leaderRunId === "string")
15
+ .filter((event) => typeof event.payload.leaderTurnId === "string")
16
16
  .map((event) => ({ at: event.createdAt, ref: `event:${event.id}` })),
17
17
  ...input.workItems
18
18
  .filter((item) => item.status !== "retired")
@@ -4,7 +4,7 @@ export { projectSessionTokenMetrics, resolveSessionTokenIdentity, unobservedSess
4
4
  export { createRuntimeBinding } from "./runtimeBinding.js";
5
5
  export { normalizeRuntimeOwner } from "./runtimeOwner.js";
6
6
  export { createSessionLaunchRequest } from "./sessionLaunchRequest.js";
7
- export { createPendingTurnCompletion, DEFAULT_RECENT_TURN_ID_LIMIT, hasRecentTurnId, rememberRecentTurnId, validatePendingTurnCompletion, validateRecentTurnIds } from "./turnCompletion.js";
7
+ export { DEFAULT_RECENT_TURN_ID_LIMIT, hasRecentTurnId, rememberRecentTurnId, validateRecentTurnIds } from "./recentTurnIds.js";
8
8
  export { RuntimeHostContentionError, RuntimeLaunchError } from "./ports.js";
9
9
  export { AgentHostPromptPushAdapter, TmuxSessionHost } from "./tmuxAdapters.js";
10
10
  export { FileTaskRuntimeIsolation, YUI_TASK_RUNTIME_ISOLATION_DESCRIPTOR, YUI_TASK_RUNTIME_SERVICE_NAMESPACE, assertTaskRuntimeIsolationPreflight, createTaskRuntimeIsolationDescriptor, parseTaskRuntimeIsolationDescriptor, planTaskRuntimeCleanup, taskRuntimeIsolationEnvironment, taskRuntimeIsolationFingerprint } from "./taskRuntimeIsolation.js";
@@ -14,7 +14,7 @@ export { formatRuntimeLaunchDiagnostic, redactLaunchArgument, redactLaunchText,
14
14
  export { DEFAULT_FORCED_GRACE_MS, DEFAULT_GRACEFUL_GRACE_MS, terminateSessionOwners } from "./sessionTerminationGuard.js";
15
15
  export { ProviderContinuationReconciliationService } from "./providerContinuationReconciliationService.js";
16
16
  export { codexNotificationBoundary, codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime } from "./codexAppServerRuntime.js";
17
- export { createProviderRuntimeBinding, acceptProviderTurn, beginProviderTurn, currentProviderActivation, currentProviderAuthority, currentProviderConversation, endProviderActivation, markProviderTurnDeliveryUnknown, rejectProviderTurn, settleProviderTurnSubmission, settleProviderTurn, startProviderActivation, supersedeProviderConversation, transferProviderAuthority, updateProviderConversationRecoverability, validateProviderRuntimeBinding } from "./providerRuntimeIdentity.js";
17
+ export { createProviderRuntimeBinding, acceptProviderTurn, beginProviderTurn, currentProviderActivation, currentProviderAuthority, currentProviderConversation, endProviderActivation, markProviderTurnDeliveryUnknown, rejectProviderTurn, settleProviderTurnSubmission, settleProviderTurn, managedProviderTurnId, startProviderActivation, supersedeProviderConversation, transferProviderAuthority, updateProviderConversationRecoverability, validateProviderRuntimeBinding } from "./providerRuntimeIdentity.js";
18
18
  export { FencedProviderControl } from "./providerControl.js";
19
19
  export { sameProviderAuthorityFence, validateProviderAuthorityFence } from "./providerAuthorityFence.js";
20
20
  export { reconcileSessionOwners } from "./sessionReconciliation.js";
@@ -22,7 +22,7 @@ const MAX_DETAIL_CHARS = 1_000;
22
22
  const SECRET_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|refresh[_-]?token|secret|password|passwd|cookie|authorization)(\s*[=:]\s*)([^\s,;]+)/gi;
23
23
  // Word boundary keeps "task-5-…" workspace paths from being mistaken for keys.
24
24
  const OPENAI_KEY_PATTERN = /\bsk-[A-Za-z0-9_-]{6,}/gu;
25
- /** A bounded, single-line, secret-redacted launch failure for Run summaries. */
25
+ /** A bounded, single-line, secret-redacted launch failure for Turn summaries. */
26
26
  export class RuntimeLaunchFailure extends Error {
27
27
  diagnostic;
28
28
  name = "RuntimeLaunchFailure";
@@ -84,7 +84,7 @@ export function formatRuntimeLaunchDiagnostic(diagnostic) {
84
84
  }
85
85
  if (diagnostic.hint !== undefined)
86
86
  fields.push(`hint=${JSON.stringify(diagnostic.hint)}`);
87
- return `Role Run could not start: ${fields.join(" ")}`;
87
+ return `Role Turn could not start: ${fields.join(" ")}`;
88
88
  }
89
89
  export function redactLaunchArgument(value) {
90
90
  return tail(redactLaunchText(value), MAX_ARGUMENT_CHARS);
@@ -6,9 +6,9 @@ export const RUNTIME_HOST_DETACH_REQUIRED_REASON = "runtime-host-detach-required
6
6
  /**
7
7
  * A Role runtime lifecycle lane already holds an in-flight operation (a
8
8
  * launch reservation or a cleanup obligation). This is scheduler
9
- * backpressure: the equivalent wake/Run must be retried after the lane
10
- * settles. It is never grounds to terminalize a Run, because the contention
11
- * happens before (or outside) any semantic Run launch.
9
+ * backpressure: the equivalent wake/Turn must be retried after the lane
10
+ * settles. It is never grounds to terminalize a Turn, because the contention
11
+ * happens before (or outside) any semantic Turn launch.
12
12
  */
13
13
  export class RuntimeLifecycleBusyError extends Error {
14
14
  name = "RuntimeLifecycleBusyError";
@@ -48,7 +48,7 @@ export function hasRuntimeCleanupObligation(mailbox) {
48
48
  /** Explicit Session end dominates a coalesced physical Host detach request. */
49
49
  export function runtimeCleanupDisposition(mailbox) {
50
50
  const reasons = [
51
- ...(mailbox?.pending.normal?.reasons ?? []),
51
+ ...(mailbox?.pending?.reasons ?? []),
52
52
  ...(!isRuntimeLaunchReservation(mailbox?.processing)
53
53
  ? mailbox?.processing?.batch.reasons ?? []
54
54
  : [])
@@ -8,7 +8,7 @@ export function validateRuntimeProcessExitObservation(observation) {
8
8
  optionalIdentity(observation.providerProcessInstanceId, "providerProcessInstanceId");
9
9
  optionalIdentity(observation.taskId, "taskId");
10
10
  identity(observation.roleName, "roleName");
11
- optionalIdentity(observation.runId, "runId");
11
+ optionalIdentity(observation.turnId, "turnId");
12
12
  identity(observation.launchId, "launchId");
13
13
  optionalIdentity(observation.nativeSessionId, "nativeSessionId");
14
14
  if (observation.processKind !== "agent-host" && observation.processKind !== "provider-child") {
@@ -50,39 +50,7 @@ export async function replayRuntimeProcessExitOutbox(home, submit) {
50
50
  throw error;
51
51
  });
52
52
  }
53
- // One-generation bridge for observations written by an Agent Host that was
54
- // already running before this release. New writers use one immutable file
55
- // per observation above, so they never share an append/unlink boundary.
56
- for (const name of entries.filter(isLegacyOutboxEntry).sort()) {
57
- const path = join(directory, name);
58
- let raw;
59
- try {
60
- raw = await readFile(path, "utf8");
61
- }
62
- catch (error) {
63
- // The old writer removes its own append log only after the Controller
64
- // acknowledges delivery. If it won that race, there is nothing to replay.
65
- if (error.code === "ENOENT")
66
- continue;
67
- throw error;
68
- }
69
- // Only consume newline-terminated records. A legacy writer can be between
70
- // append bytes and its trailing newline while this snapshot is read.
71
- const completeLength = raw.lastIndexOf("\n") + 1;
72
- const lines = raw.slice(0, completeLength).split("\n").filter(Boolean);
73
- for (const line of lines) {
74
- await submit(validateRuntimeProcessExitObservation(JSON.parse(line)));
75
- }
76
- // Deliberately leave the legacy path in place. A pre-upgrade Agent Host may
77
- // already hold an append descriptor for this inode; renaming/unlinking it
78
- // would let a later append disappear into an unlinked file. The old writer
79
- // removes the path after a successful direct submission. Otherwise the
80
- // durable file remains for the next idempotent replay.
81
- }
82
53
  }
83
54
  function outboxDirectory(home) {
84
55
  return resolve(join(home, "runtime", "agent-host-outbox"));
85
56
  }
86
- function isLegacyOutboxEntry(name) {
87
- return name.endsWith(".jsonl");
88
- }
@@ -1,15 +1,15 @@
1
1
  import { requireText, requireTimestamp } from "./validation.js";
2
- import { formatAgentRunReceiptId, formatInputRequestReceiptId, validateTaskRecordReference } from "../task/taskRecordReference.js";
2
+ import { formatTurnReceiptId, formatInputRequestReceiptId, validateTaskRecordReference } from "../task/taskRecordReference.js";
3
3
  export function createPromptEnvelope(input) {
4
- if (input.source.kind !== "agent-run"
5
- && input.source.kind !== "run-input"
4
+ if (input.source.kind !== "turn"
5
+ && input.source.kind !== "turn-input"
6
6
  && input.source.kind !== "input-request") {
7
7
  throw new Error("Prompt source kind is invalid.");
8
8
  }
9
9
  const source = validateTaskRecordReference({
10
10
  taskId: input.source.taskId,
11
11
  localId: input.source.localId
12
- }, input.source.kind === "input-request" ? "inputRequest" : "agentRun");
12
+ }, input.source.kind === "input-request" ? "inputRequest" : "turn");
13
13
  const id = requireQualifiedReceiptId(input.id, input.source.kind, source.taskId, source.localId);
14
14
  return {
15
15
  id,
@@ -23,14 +23,14 @@ export function createPromptEnvelope(input) {
23
23
  };
24
24
  }
25
25
  function requireQualifiedReceiptId(value, kind, taskId, localId) {
26
- const expected = kind === "agent-run"
27
- ? formatAgentRunReceiptId(taskId, localId)
26
+ const expected = kind === "turn"
27
+ ? formatTurnReceiptId(taskId, localId)
28
28
  : kind === "input-request"
29
29
  ? formatInputRequestReceiptId(taskId, localId)
30
- : `agent-input:${taskId}/${localId}/`;
31
- if (kind === "run-input") {
30
+ : `turn-input:${taskId}/${localId}/`;
31
+ if (kind === "turn-input") {
32
32
  if (!value.startsWith(expected)
33
- || !/^(normal|user-correction):[1-9]\d*-[1-9]\d*$/.test(value.slice(expected.length))) {
33
+ || !/^[1-9]\d*$/.test(value.slice(expected.length))) {
34
34
  throw new Error("Prompt envelope id does not match its source.");
35
35
  }
36
36
  return value;
@@ -14,7 +14,7 @@ export function createProviderContinuation(input) {
14
14
  schemaVersion: 1,
15
15
  taskId: text(input.taskId, "Task id"),
16
16
  roleName: text(input.roleName, "Role name"),
17
- runId: text(input.runId, "Run id"),
17
+ turnId: text(input.turnId, "Turn id"),
18
18
  identity: validateProviderContinuationIdentity(input.identity),
19
19
  ...(input.parentContinuationId === undefined
20
20
  ? {}
@@ -152,7 +152,7 @@ export function validateProviderContinuation(value) {
152
152
  throw new Error("Provider Continuation schemaVersion must be 1.");
153
153
  text(value.taskId, "Task id");
154
154
  text(value.roleName, "Role name");
155
- text(value.runId, "Run id");
155
+ text(value.turnId, "Turn id");
156
156
  validateProviderContinuationIdentity(value.identity);
157
157
  if (!["active", "quiescent", "unknown"].includes(value.execution)) {
158
158
  throw new Error("Provider Continuation execution is invalid.");
@@ -100,7 +100,7 @@ function groupDetachedContinuations(continuations, observations) {
100
100
  && observation.fence.continuationId === continuation.identity.continuationId
101
101
  && observation.fence.continuationGeneration === continuation.identity.generation));
102
102
  // A projected continuation without its original durable fence cannot be
103
- // safely attached to a live Run. Keep ownership conservative and let the
103
+ // safely attached to a live Turn. Keep ownership conservative and let the
104
104
  // malformed identity remain visible instead of synthesizing a receipt.
105
105
  if (source === undefined)
106
106
  continue;
@@ -149,7 +149,7 @@ function reconciliationObservation(continuation, sourceFence, now) {
149
149
  ...sourceFence,
150
150
  taskId: continuation.taskId,
151
151
  roleName: continuation.roleName,
152
- runId: continuation.runId,
152
+ turnId: continuation.turnId,
153
153
  agentId: continuation.identity.accountScope,
154
154
  driverId: continuation.identity.providerNamespace,
155
155
  conversationId: continuation.identity.conversationId,
@@ -1,7 +1,7 @@
1
1
  export function createProviderRuntimeBinding(input) {
2
2
  const startedAt = timestamp(input.startedAt, "Provider Activation startedAt");
3
3
  return validateProviderRuntimeBinding({
4
- schemaVersion: 3,
4
+ schemaVersion: 5,
5
5
  providerNamespace: identity(input.providerNamespace, "Provider namespace"),
6
6
  accountScope: identity(input.accountScope, "Provider account scope"),
7
7
  currentConversationEpoch: 1,
@@ -25,9 +25,25 @@ export function createProviderRuntimeBinding(input) {
25
25
  holderId: input.activationId,
26
26
  changedAt: startedAt
27
27
  },
28
- turn: null
28
+ turn: null,
29
+ goal: null
29
30
  });
30
31
  }
32
+ export function updateProviderGoal(raw, goal) {
33
+ const binding = validateProviderRuntimeBinding(raw);
34
+ const normalized = validateProviderGoal(goal);
35
+ return validateProviderRuntimeBinding({ ...binding, goal: normalized });
36
+ }
37
+ export function clearProviderGoal(raw) {
38
+ const binding = validateProviderRuntimeBinding(raw);
39
+ return binding.goal === null
40
+ ? binding
41
+ : validateProviderRuntimeBinding({ ...binding, goal: null });
42
+ }
43
+ /** Only active means the Provider is expected to continue autonomously. */
44
+ export function providerGoalContinues(goal) {
45
+ return goal?.status === "active";
46
+ }
31
47
  export function currentProviderAuthority(binding) {
32
48
  return validateProviderRuntimeBinding(binding).authority;
33
49
  }
@@ -146,12 +162,14 @@ export function transferProviderAuthority(raw, input) {
146
162
  }
147
163
  export function beginProviderTurn(raw, input) {
148
164
  const binding = validateProviderRuntimeBinding(raw);
149
- const runId = identity(input.runId, "Run id");
150
165
  const attemptId = identity(input.attemptId, "Provider input attempt id");
151
- if (binding.turn?.runId === runId
152
- && binding.turn.attemptId === attemptId
153
- && binding.turn.authorityEpoch === input.authorityEpoch
154
- && binding.turn.status === "submitting") {
166
+ const turnId = input.turnId === undefined ? undefined : identity(input.turnId, "Turn id");
167
+ const currentTurn = binding.turn;
168
+ if (currentTurn !== null
169
+ && currentTurn.turnId === turnId
170
+ && currentTurn.attemptId === attemptId
171
+ && currentTurn.authorityEpoch === input.authorityEpoch
172
+ && currentTurn.status === "submitting") {
155
173
  return binding;
156
174
  }
157
175
  if (binding.authority.epoch !== input.authorityEpoch
@@ -166,7 +184,7 @@ export function beginProviderTurn(raw, input) {
166
184
  return validateProviderRuntimeBinding({
167
185
  ...binding,
168
186
  turn: {
169
- runId,
187
+ ...(turnId === undefined ? {} : { turnId }),
170
188
  attemptId,
171
189
  authorityEpoch: input.authorityEpoch,
172
190
  status: "submitting",
@@ -189,7 +207,7 @@ export function acceptProviderTurn(raw, input) {
189
207
  turn: {
190
208
  ...turn,
191
209
  status: "accepted",
192
- turnId: identity(input.turnId, "Provider Turn id"),
210
+ nativeTurnId: identity(input.nativeTurnId, "Provider native Turn id"),
193
211
  updatedAt: acceptedAt
194
212
  }
195
213
  });
@@ -255,9 +273,9 @@ export function settleProviderTurnSubmission(raw, input) {
255
273
  export function settleProviderTurn(raw, input) {
256
274
  const binding = validateProviderRuntimeBinding(raw);
257
275
  const turn = binding.turn;
258
- const turnId = identity(input.turnId, "Provider Turn id");
259
- if (turn === null || turn.turnId !== turnId
260
- || (turn.status !== "accepted" && turn.status !== "running")) {
276
+ const nativeTurnId = identity(input.nativeTurnId, "Provider native Turn id");
277
+ if (turn === null || turn.nativeTurnId !== nativeTurnId
278
+ || turn.status !== "accepted") {
261
279
  throw new Error("Provider Turn settlement does not match the current Turn.");
262
280
  }
263
281
  const settledAt = orderedTurnTimestamp(turn, input.settledAt, "Provider Turn settledAt");
@@ -302,10 +320,10 @@ export function supersedeProviderConversation(raw, input) {
302
320
  }
303
321
  : entry);
304
322
  const turn = binding.turn !== null
305
- && ["submitting", "accepted", "running", "delivery-unknown"].includes(binding.turn.status)
323
+ && ["submitting", "accepted", "delivery-unknown"].includes(binding.turn.status)
306
324
  ? {
307
325
  ...binding.turn,
308
- status: binding.turn.turnId === undefined ? "rejected" : "failed",
326
+ status: binding.turn.nativeTurnId === undefined ? "rejected" : "failed",
309
327
  updatedAt: switchedAt,
310
328
  terminalReason
311
329
  }
@@ -338,12 +356,13 @@ export function supersedeProviderConversation(raw, input) {
338
356
  holderId: input.activationId,
339
357
  changedAt: switchedAt
340
358
  },
341
- turn
359
+ turn,
360
+ goal: null
342
361
  });
343
362
  }
344
363
  export function validateProviderRuntimeBinding(value) {
345
- if (value.schemaVersion !== 3)
346
- throw new Error("Provider Runtime Binding schemaVersion must be 3.");
364
+ if (value.schemaVersion !== 5)
365
+ throw new Error("Provider Runtime Binding schemaVersion must be 5.");
347
366
  identity(value.providerNamespace, "Provider namespace");
348
367
  identity(value.accountScope, "Provider account scope");
349
368
  integer(value.currentConversationEpoch, 1, "Current Provider Conversation epoch");
@@ -447,16 +466,45 @@ export function validateProviderRuntimeBinding(value) {
447
466
  throw new Error("Provider Runtime Binding requires Turn state.");
448
467
  if (value.turn !== null)
449
468
  validateProviderTurn(value.turn, value.authority.epoch);
469
+ if (!Object.hasOwn(value, "goal"))
470
+ throw new Error("Provider Runtime Binding requires Goal state.");
471
+ if (value.goal !== null)
472
+ validateProviderGoal(value.goal);
450
473
  return value;
451
474
  }
475
+ function validateProviderGoal(goal) {
476
+ if (![
477
+ "active",
478
+ "paused",
479
+ "blocked",
480
+ "usage-limited",
481
+ "budget-limited",
482
+ "complete"
483
+ ].includes(goal.status)) {
484
+ throw new Error("Provider Goal status is invalid.");
485
+ }
486
+ const normalized = {
487
+ status: goal.status,
488
+ objective: identity(goal.objective, "Provider Goal objective"),
489
+ updatedAt: timestamp(goal.updatedAt, "Provider Goal updatedAt"),
490
+ ...(goal.nativeTurnId === undefined
491
+ ? {}
492
+ : { nativeTurnId: identity(goal.nativeTurnId, "Provider Goal native Turn id") }),
493
+ ...(goal.tokenBudget === undefined
494
+ ? {}
495
+ : { tokenBudget: integer(goal.tokenBudget, 1, "Provider Goal token budget") })
496
+ };
497
+ return Object.freeze(normalized);
498
+ }
452
499
  function validateProviderTurn(turn, currentAuthorityEpoch) {
453
- identity(turn.runId, "Run id");
500
+ if (turn.turnId !== undefined)
501
+ identity(turn.turnId, "Turn id");
454
502
  identity(turn.attemptId, "Provider input attempt id");
455
503
  integer(turn.authorityEpoch, 1, "Provider Turn authority epoch");
456
504
  if (turn.authorityEpoch > currentAuthorityEpoch) {
457
505
  throw new Error("Provider Turn authority epoch is ahead of current authority.");
458
506
  }
459
- if (!["submitting", "accepted", "running", "completed", "failed", "cancelled", "rejected", "delivery-unknown"]
507
+ if (!["submitting", "accepted", "completed", "failed", "cancelled", "rejected", "delivery-unknown"]
460
508
  .includes(turn.status)) {
461
509
  throw new Error("Provider Turn status is invalid.");
462
510
  }
@@ -465,12 +513,16 @@ function validateProviderTurn(turn, currentAuthorityEpoch) {
465
513
  if (Date.parse(turn.updatedAt) < Date.parse(turn.submittedAt)) {
466
514
  throw new Error("Provider Turn updatedAt is earlier than submittedAt.");
467
515
  }
468
- const hasAcceptedIdentity = turn.status === "accepted" || turn.status === "running"
516
+ const hasAcceptedIdentity = turn.status === "accepted"
469
517
  || turn.status === "completed" || turn.status === "failed" || turn.status === "cancelled";
470
518
  if (hasAcceptedIdentity)
471
- identity(turn.turnId, "Provider Turn id");
472
- else if (turn.turnId !== undefined)
473
- throw new Error("Unaccepted Provider Turn cannot have a Turn id.");
519
+ identity(turn.nativeTurnId, "Provider native Turn id");
520
+ else if (turn.nativeTurnId !== undefined) {
521
+ throw new Error("Unaccepted Provider Turn cannot have a native Turn id.");
522
+ }
523
+ }
524
+ export function managedProviderTurnId(turn) {
525
+ return turn?.turnId ?? null;
474
526
  }
475
527
  function requireProviderTurn(binding, attemptId, status) {
476
528
  const id = identity(attemptId, "Provider input attempt id");
@@ -487,7 +539,7 @@ function orderedTurnTimestamp(turn, value, label) {
487
539
  return normalized;
488
540
  }
489
541
  function providerTurnIsActive(turn) {
490
- return turn !== null && ["submitting", "accepted", "running", "delivery-unknown"]
542
+ return turn !== null && ["submitting", "accepted", "delivery-unknown"]
491
543
  .includes(turn.status);
492
544
  }
493
545
  function currentActivationUnchecked(binding) {
@@ -0,0 +1,38 @@
1
+ import { requireText } from "./validation.js";
2
+ export const DEFAULT_RECENT_TURN_ID_LIMIT = 32;
3
+ export function validateRecentTurnIds(value, limit = DEFAULT_RECENT_TURN_ID_LIMIT) {
4
+ const normalizedLimit = requireLimit(limit);
5
+ if (!Array.isArray(value))
6
+ throw new Error("Recent Turn ids must be an array.");
7
+ if (value.length > normalizedLimit) {
8
+ throw new Error(`Recent Turn ids must not contain more than ${normalizedLimit} entries.`);
9
+ }
10
+ const result = value.map((turnId) => requireTextValue(turnId, "Recent Turn id"));
11
+ if (new Set(result).size !== result.length) {
12
+ throw new Error("Recent Turn ids must not contain duplicates.");
13
+ }
14
+ return result;
15
+ }
16
+ export function rememberRecentTurnId(recentTurnIds, turnId, limit = DEFAULT_RECENT_TURN_ID_LIMIT) {
17
+ const normalizedLimit = requireLimit(limit);
18
+ const existing = validateRecentTurnIds(recentTurnIds, normalizedLimit);
19
+ const normalizedTurnId = requireText(turnId, "Recent Turn id");
20
+ return [
21
+ ...existing.filter((candidate) => candidate !== normalizedTurnId),
22
+ normalizedTurnId
23
+ ].slice(-normalizedLimit);
24
+ }
25
+ export function hasRecentTurnId(recentTurnIds, turnId) {
26
+ return validateRecentTurnIds(recentTurnIds).includes(requireText(turnId, "Recent Turn id"));
27
+ }
28
+ function requireTextValue(value, label) {
29
+ if (typeof value !== "string")
30
+ throw new Error(`${label} is invalid.`);
31
+ return requireText(value, label);
32
+ }
33
+ function requireLimit(value) {
34
+ if (!Number.isInteger(value) || value < 1) {
35
+ throw new Error("Recent Turn id limit must be a positive integer.");
36
+ }
37
+ return value;
38
+ }
@@ -32,10 +32,10 @@ export function projectProviderContinuations(events) {
32
32
  export function blockingProviderContinuations(events) {
33
33
  return projectProviderContinuations(events).filter((entry) => (continuationOwnsWriterUmbrella(entry) || entry.identityConflict));
34
34
  }
35
- /** Exact Run-scoped writer fence shared by terminalization and retry paths. */
35
+ /** Exact Turn-scoped writer fence shared by terminalization and retry paths. */
36
36
  export function runOwnsBlockingProviderContinuation(events, owner) {
37
37
  return blockingProviderContinuations(events).some((continuation) => (continuation.taskId === owner.taskId
38
38
  && continuation.roleName === owner.roleName
39
- && continuation.runId === owner.runId
39
+ && continuation.turnId === owner.turnId
40
40
  && continuation.identity.accountScope === owner.agentId));
41
41
  }
@@ -5,7 +5,7 @@
5
5
  * The layers are deliberately time-based and conservative: short silence is
6
6
  * normal for high-reasoning-effort turns, large reviews, and tool waits.
7
7
  * Time-based layers authorize display hints and coalesced read-only diagnosis
8
- * only. They never reset a Run or replace a Provider Conversation.
8
+ * only. They never reset a Turn or replace a Provider Session.
9
9
  */
10
10
  /** Runtime silence after which a live turn is surfaced as "quiet" (hint only). */
11
11
  export const RUNTIME_QUIET_AFTER_MS = 5 * 60_000;