@zq-silk/yui 0.15.11 → 0.16.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 (280) hide show
  1. package/ARCHITECTURE.md +11 -6
  2. package/ARCHITECTURE.zh-CN.md +8 -4
  3. package/README.md +13 -5
  4. package/dist/agentRun/agentRun.js +3 -0
  5. package/dist/artifacts/artifactCommitLock.js +16 -55
  6. package/dist/artifacts/taskArtifactRepository.js +3 -3
  7. package/dist/cli/agentConfigurationPicker.js +1 -1
  8. package/dist/cli/commandCatalog.js +92 -48
  9. package/dist/cli/completion.js +18 -18
  10. package/dist/cli/completionWizard.js +1 -1
  11. package/dist/cli/dynamicCompletion.js +1 -1
  12. package/dist/cli/interactionPolicy.js +11 -3
  13. package/dist/cli/invocationAuthority.js +64 -0
  14. package/dist/cli/managedDiagnostics.js +2 -2
  15. package/dist/cli/parseRepeatable.js +35 -0
  16. package/dist/cli/updatePorts.js +26 -5
  17. package/dist/cli.js +1303 -1235
  18. package/dist/commands/agentCommands.js +4 -4
  19. package/dist/commands/capabilityCommands.js +1 -1
  20. package/dist/commands/configCommands.js +6 -57
  21. package/dist/commands/configOverview.js +2 -2
  22. package/dist/commands/durableJobCommands.js +12 -6
  23. package/dist/commands/executionAuditCommands.js +10 -0
  24. package/dist/commands/globalRoleCommands.js +78 -29
  25. package/dist/commands/grantCommands.js +0 -3
  26. package/dist/commands/jobCommands.js +1 -4
  27. package/dist/commands/operatorCommands.js +3 -3
  28. package/dist/commands/projectCommands.js +45 -25
  29. package/dist/commands/resourcesCommands.js +10 -40
  30. package/dist/commands/roleConfiguration.js +2 -6
  31. package/dist/commands/taskActivationCommands.js +4 -8
  32. package/dist/commands/taskAgentCapabilities.js +9 -0
  33. package/dist/commands/taskCommandSupport.js +155 -0
  34. package/dist/commands/taskCommandTypes.js +1 -0
  35. package/dist/commands/taskCommands.js +355 -732
  36. package/dist/commands/taskCompletionGate.js +1 -1
  37. package/dist/commands/taskExecutionCommands.js +1 -1
  38. package/dist/commands/taskFactCommands.js +325 -0
  39. package/dist/commands/taskInputCommands.js +12 -42
  40. package/dist/commands/taskIntegrationCommands.js +20 -58
  41. package/dist/commands/taskNextActionCommand.js +7 -6
  42. package/dist/commands/taskPublicationAdoptCommand.js +127 -0
  43. package/dist/commands/taskPublicationCommands.js +12 -3
  44. package/dist/commands/taskPublicationVerifyCommand.js +24 -40
  45. package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
  46. package/dist/commands/taskUpstreamCommands.js +19 -8
  47. package/dist/commands/workflowCommands.js +6 -1
  48. package/dist/completion/completionInstaller.js +26 -26
  49. package/dist/completion/completionState.js +26 -26
  50. package/dist/completion/fileCompletionManager.js +6 -11
  51. package/dist/config/configCatalog.js +0 -2
  52. package/dist/config/timeZone.js +14 -0
  53. package/dist/config/yuiConfig.js +0 -29
  54. package/dist/context/runContextPack.js +5 -3
  55. package/dist/context/taskCatalog.js +185 -0
  56. package/dist/context/taskContext.js +152 -151
  57. package/dist/context/wakeRunReferences.js +11 -0
  58. package/dist/controller/agentCapabilities.js +58 -0
  59. package/dist/controller/agentRuntimeObserver.js +6 -11
  60. package/dist/controller/clientRuntime.js +22 -14
  61. package/dist/controller/controller.js +20 -24
  62. package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
  63. package/dist/controller/globalInputDelivery.js +13 -0
  64. package/dist/controller/jobClient.js +4 -4
  65. package/dist/controller/jobControl.js +60 -25
  66. package/dist/controller/jobSupervisor.js +4 -4
  67. package/dist/controller/providerRetryAdmission.js +100 -0
  68. package/dist/controller/providerRetryDelivery.js +218 -0
  69. package/dist/controller/runtime.js +85 -43
  70. package/dist/controller/runtimeEventProcessor.js +0 -5
  71. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  72. package/dist/controller/taskAgentError.js +35 -0
  73. package/dist/coordination/workMailboxQueue.js +2 -24
  74. package/dist/core/controllerClient.js +2 -2
  75. package/dist/core/fileLockOwner.js +74 -0
  76. package/dist/decision/decision.js +17 -0
  77. package/dist/doctor/doctor.js +18 -9
  78. package/dist/event/taskEvent.js +12 -0
  79. package/dist/execution/workItemExecutionProjection.js +2 -2
  80. package/dist/executor/agentCapabilityConfig.js +43 -0
  81. package/dist/executor/agentConfigurationCatalog.js +49 -11
  82. package/dist/executor/agentExecutor.js +5 -8
  83. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  84. package/dist/executor/taskAgentCapabilities.js +64 -0
  85. package/dist/integration/deliveryObligation.js +1 -69
  86. package/dist/integration/gitIntegrationService.js +79 -90
  87. package/dist/integration/integrationAttempt.js +3 -14
  88. package/dist/integration/integrationSourceApplication.js +4 -12
  89. package/dist/integration/manifestTags.js +2 -2
  90. package/dist/job/durableJob.js +4 -25
  91. package/dist/job/jobAssignmentScope.js +22 -0
  92. package/dist/job/jobOperation.js +16 -0
  93. package/dist/job/jobRunner.js +2 -1
  94. package/dist/job/stepDirectory.js +15 -0
  95. package/dist/kernel/builtinCapabilities.js +15 -11
  96. package/dist/kernel/kernelPorts.js +1 -17
  97. package/dist/lifecycle/exactRunTerminalization.js +5 -10
  98. package/dist/message/globalProviderRetry.js +15 -0
  99. package/dist/message/inputControlResolution.js +3 -4
  100. package/dist/message/message.js +17 -20
  101. package/dist/message/messageContinuation.js +1 -1
  102. package/dist/milestone/milestone.js +11 -0
  103. package/dist/observability/executionAudit.js +19 -0
  104. package/dist/observability/orchestrationMetrics.js +24 -1
  105. package/dist/observability/runtimeIdentity.js +1 -17
  106. package/dist/output/agentConfigurationPresentation.js +2 -0
  107. package/dist/output/timePresentation.js +1 -14
  108. package/dist/plugins/pluginService.js +12 -4
  109. package/dist/release/releaseWorkflowPorts.js +45 -96
  110. package/dist/release/runtimeRelease.js +9 -15
  111. package/dist/repository/gitWorkspace.js +371 -105
  112. package/dist/repository/projectMaintenanceLock.js +98 -82
  113. package/dist/repository/taskBaseFreshness.js +1 -1
  114. package/dist/repository/taskWorkspaceCoordinator.js +82 -144
  115. package/dist/repository/taskWorkspacePreparer.js +113 -47
  116. package/dist/repository/workspaceCleanupInspection.js +187 -0
  117. package/dist/resources/autoResourceGc.js +4 -77
  118. package/dist/resources/liveReferences.js +7 -54
  119. package/dist/resources/resourceDiscovery.js +5 -118
  120. package/dist/resources/resourceGc.js +233 -181
  121. package/dist/resources/resourceRegistrar.js +5 -4
  122. package/dist/resources/resourceRegistry.js +3 -37
  123. package/dist/resources/resourceRegistryStore.js +13 -36
  124. package/dist/resources/sqliteResourceRegistry.js +43 -26
  125. package/dist/review/deltaRecheck.js +1 -1
  126. package/dist/review/reviewAcceptance.js +1 -1
  127. package/dist/review/reviewDecision.js +1 -1
  128. package/dist/review/reviewRound.js +8 -7
  129. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  130. package/dist/runtime/acpProtocol.js +4 -51
  131. package/dist/runtime/acpSession.js +10 -75
  132. package/dist/runtime/acpSessionConfiguration.js +1 -8
  133. package/dist/runtime/agentEndpoint.js +3 -2
  134. package/dist/runtime/agentError.js +5 -3
  135. package/dist/runtime/agentFailureContext.js +43 -0
  136. package/dist/runtime/agentHost.js +42 -25
  137. package/dist/runtime/builtinAgentErrorMappers.js +91 -0
  138. package/dist/runtime/codexAppServerRuntime.js +34 -3
  139. package/dist/runtime/codexInteractiveHost.js +2 -2
  140. package/dist/runtime/index.js +0 -1
  141. package/dist/runtime/managedCaller.js +21 -1
  142. package/dist/runtime/providerControl.js +5 -1
  143. package/dist/runtime/providerErrors.js +38 -0
  144. package/dist/runtime/providerRetry.js +198 -0
  145. package/dist/runtime/providerRuntimeIdentity.js +28 -2
  146. package/dist/runtime/runtimeObservation.js +0 -5
  147. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  148. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  149. package/dist/runtime/sessionTokenMetrics.js +15 -5
  150. package/dist/runtime/structuredProviderHost.js +10 -43
  151. package/dist/runtime/taskUsageMetrics.js +275 -0
  152. package/dist/runtime/tmuxAdapters.js +6 -8
  153. package/dist/scheduler/activeRoleRunDelivery.js +19 -7
  154. package/dist/scheduler/leaderWakeupProcessor.js +24 -6
  155. package/dist/scheduler/operatorEvent.js +12 -20
  156. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  157. package/dist/scheduler/ports.js +5 -8
  158. package/dist/scheduler/roleRunLiveness.js +4 -4
  159. package/dist/scheduler/roleRunStall.js +16 -23
  160. package/dist/scheduler/taskExecutionProjection.js +49 -36
  161. package/dist/scheduler/taskObservabilityProjection.js +6 -45
  162. package/dist/scheduler/taskWake.js +5 -10
  163. package/dist/scheduler/wakeReason.js +2 -0
  164. package/dist/scheduler/wakeupQueue.js +2 -4
  165. package/dist/setup/setupCommand.js +1 -1
  166. package/dist/storage/contextRecords.js +106 -0
  167. package/dist/storage/currentTaskStore.js +1 -1
  168. package/dist/storage/homeLayout.js +13 -17
  169. package/dist/storage/migrations/agentFailureContext.js +22 -0
  170. package/dist/storage/migrations/currentInputContract.js +86 -0
  171. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  172. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  173. package/dist/storage/migrations/integrationContinuation.js +5 -4
  174. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  175. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  176. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  177. package/dist/storage/migrations/verificationPolicy.js +74 -0
  178. package/dist/storage/migrations/workItemHistory.js +46 -0
  179. package/dist/storage/persistenceWorker.js +12 -4
  180. package/dist/storage/recordValidation.js +87 -0
  181. package/dist/storage/sqliteSchema.js +173 -1
  182. package/dist/storage/sqliteStore.js +172 -161
  183. package/dist/storage/storageSchema.js +2 -14
  184. package/dist/storage/storageVersions.js +1 -1
  185. package/dist/storage/storeRpc.js +16 -7
  186. package/dist/storage/taskCatalog.js +123 -0
  187. package/dist/storage/taskStore.js +5 -7
  188. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  189. package/dist/task/archiveDiagnostics.js +1 -0
  190. package/dist/task/archivePreflight.js +124 -0
  191. package/dist/task/completionReadiness.js +5 -24
  192. package/dist/task/draftPlan.js +0 -53
  193. package/dist/task/nextAction.js +7 -13
  194. package/dist/task/publicationAdoption.js +56 -0
  195. package/dist/task/publicationReference.js +10 -0
  196. package/dist/task/remoteDelivery.js +31 -16
  197. package/dist/task/remoteDeliveryService.js +89 -0
  198. package/dist/task/taskActivation.js +2 -25
  199. package/dist/task/taskActivationService.js +0 -2
  200. package/dist/task/taskRecordReference.js +0 -1
  201. package/dist/task/taskSubmission.js +3 -14
  202. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  203. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  204. package/dist/telemetry/telemetryWiring.js +4 -3
  205. package/dist/tmux/tmuxManager.js +29 -20
  206. package/dist/verification/gateArtifact.js +15 -24
  207. package/dist/verification/gateArtifactStore.js +14 -7
  208. package/dist/verification/verificationGateService.js +29 -88
  209. package/dist/verification/verificationPlan.js +27 -72
  210. package/dist/web/assets/client/app.js +92 -17
  211. package/dist/web/assets/client/components.js +55 -13
  212. package/dist/web/assets/client/i18n.js +72 -4
  213. package/dist/web/assets/client/taskSurface.js +6 -5
  214. package/dist/web/assets/client/view.js +35 -7
  215. package/dist/web/assets/shell.js +6 -0
  216. package/dist/web/assets/styles/layout.js +7 -0
  217. package/dist/web/webServer.js +12 -3
  218. package/dist/web/webSnapshot.js +14 -85
  219. package/dist/web/webTaskSurface.js +17 -46
  220. package/dist/workItem/workItem.js +1 -12
  221. package/dist/workspace/cleanupInspection.js +63 -0
  222. package/dist/workspace/workItemChangeSetManager.js +110 -50
  223. package/docs/agent-result-consumption.md +4 -0
  224. package/docs/agent-result-consumption.zh-CN.md +3 -0
  225. package/docs/agent-runtime-drivers.md +7 -0
  226. package/docs/agent-runtime-drivers.zh-CN.md +5 -0
  227. package/docs/architecture/README.md +2 -0
  228. package/docs/architecture/README.zh-CN.md +3 -1
  229. package/docs/architecture/capabilities-and-resources.md +42 -5
  230. package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
  231. package/docs/managed-turn-and-session-runtime.md +121 -1
  232. package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
  233. package/docs/observability/README.md +62 -0
  234. package/docs/observability/README.zh-CN.md +47 -0
  235. package/docs/plugin-sdk.md +4 -2
  236. package/docs/project-refresh.md +77 -0
  237. package/docs/project-refresh.zh-CN.md +59 -0
  238. package/docs/provider-retry.md +70 -0
  239. package/docs/provider-runtime.md +3 -1
  240. package/docs/provider-runtime.zh-CN.md +4 -2
  241. package/docs/release-workflow.md +190 -7
  242. package/docs/release-workflow.zh-CN.md +139 -5
  243. package/docs/roles-and-configuration.md +29 -0
  244. package/docs/roles-and-configuration.zh-CN.md +21 -0
  245. package/docs/sqlite-control-plane-design.md +16 -3
  246. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  247. package/docs/task-dag-semantics.md +3 -3
  248. package/docs/task-dag-semantics.zh-CN.md +2 -2
  249. package/docs/task-delivery.md +223 -17
  250. package/docs/task-delivery.zh-CN.md +171 -14
  251. package/docs/task-discovery.md +101 -0
  252. package/docs/task-discovery.zh-CN.md +85 -0
  253. package/docs/testing/verification-levels.md +161 -9
  254. package/docs/testing/verification-levels.zh-CN.md +116 -9
  255. package/i18n/README.zh-CN.md +13 -7
  256. package/package.json +1 -1
  257. package/skills/yui-leader/SKILL.md +5 -0
  258. package/skills/yui-leader/references/execution.md +3 -2
  259. package/skills/yui-leader/references/integration.md +9 -5
  260. package/skills/yui-leader/references/planning.md +9 -3
  261. package/skills/yui-operator/SKILL.md +24 -8
  262. package/skills/yui-reviewer/SKILL.md +4 -0
  263. package/skills/yui-runtime/SKILL.md +17 -2
  264. package/skills/yui-runtime/references/publication.md +26 -4
  265. package/skills/yui-runtime/references/recovery.md +71 -0
  266. package/dist/agent/agentRegistry.js +0 -10
  267. package/dist/agentRun/runIdentity.js +0 -22
  268. package/dist/commands/deliveryGuardPreflight.js +0 -30
  269. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  270. package/dist/commands/taskOverviewCommand.js +0 -376
  271. package/dist/completion/completionWizard.js +0 -125
  272. package/dist/context/dispatchContext.js +0 -110
  273. package/dist/context/wakeNotification.js +0 -144
  274. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  275. package/dist/integration/integrationQueueEntry.js +0 -191
  276. package/dist/integration/integrationQueueService.js +0 -810
  277. package/dist/release/fakeReleasePorts.js +0 -55
  278. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  279. package/dist/task/deliveryGuard.js +0 -226
  280. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -0,0 +1,198 @@
1
+ export const PROVIDER_RETRY_LIMIT = 5;
2
+ export const PROVIDER_RETRY_BUDGET_MS = 600_000;
3
+ export function providerRetryPending(binding) {
4
+ return binding?.retry?.status === "waiting" || binding?.retry?.status === "in-flight";
5
+ }
6
+ /** Called only in the transaction recording the exact failed/rejected input. */
7
+ export function recordProviderFailure(binding, input) {
8
+ let turn = binding.run;
9
+ const previous = binding.retry;
10
+ if (turn === null || !["failed", "rejected", "delivery-unknown"].includes(turn.status))
11
+ return binding;
12
+ turn = { ...turn, failure: { error: input.error, ref: input.failureRef } };
13
+ binding = { ...binding, run: turn };
14
+ if (turn.status === "delivery-unknown")
15
+ return binding;
16
+ if (previous?.currentAttemptId === turn.attemptId
17
+ && ["cancelled", "exhausted", "needs-attention"].includes(previous.status))
18
+ return binding;
19
+ if (previous?.failedAttemptId === turn.attemptId && previous.status !== "in-flight")
20
+ return binding;
21
+ if (input.error.retryable !== true || input.error.inputDisposition === "unknown"
22
+ || input.error.sessionDisposition !== "recoverable"
23
+ || binding.authority.owner !== "controller" || binding.retryDisabled === true
24
+ || turn.status === "failed" && (turn.nativeTurnId === undefined || input.error.inputDisposition !== "accepted")) {
25
+ return providerRetryPending(binding)
26
+ ? cancelProviderRetry(binding, "failure-not-safely-retryable", input.at) : binding;
27
+ }
28
+ const continuing = previous?.status === "in-flight" && previous.currentAttemptId === turn.attemptId;
29
+ const originalInput = continuing ? previous.input : turn.input;
30
+ if (originalInput === undefined)
31
+ return binding; // no owned input: never replay arbitrary native chat
32
+ const current = {
33
+ policyVersion: 1,
34
+ chainId: continuing ? previous.chainId : turn.attemptId,
35
+ status: "waiting",
36
+ input: originalInput,
37
+ nativeSessionId: binding.conversations.find(c => c.epoch === binding.currentConversationEpoch).conversationId,
38
+ authorityEpoch: binding.authority.epoch,
39
+ attempts: continuing ? previous.attempts - (input.noProviderWrite && previous.successorAutomatic !== false ? 1 : 0) : 0,
40
+ transportSequence: continuing ? previous.transportSequence : 0,
41
+ startedAt: continuing ? previous.startedAt : iso(input.at),
42
+ intentAt: continuing ? previous.intentAt : turn.submittedAt,
43
+ deadline: continuing ? previous.deadline : iso(input.at + PROVIDER_RETRY_BUDGET_MS),
44
+ nextEligibleAt: iso(input.at),
45
+ updatedAt: iso(input.at),
46
+ failedAttemptId: turn.attemptId,
47
+ failureAttemptId: turn.nativeTurnId !== undefined || !continuing ? turn.attemptId : previous.failureAttemptId,
48
+ ...((turn.nativeTurnId ?? (continuing ? previous.failedNativeTurnId : undefined)) === undefined ? {}
49
+ : { failedNativeTurnId: turn.nativeTurnId ?? previous.failedNativeTurnId }),
50
+ ...(turn.runId === undefined ? {} : { previousRunId: turn.runId }),
51
+ failureRef: input.failureRef,
52
+ error: input.error
53
+ };
54
+ const random = unitRandom(input.random ?? Math.random);
55
+ const window = Math.min(60_000, 5_000 * 2 ** current.attempts);
56
+ const backoff = Math.ceil(window * (0.5 + random / 2));
57
+ const serverWait = input.error.retryAfterMs;
58
+ const delay = serverWait === undefined ? backoff
59
+ : Math.max(backoff, serverWait + 1 + Math.ceil(random * 1_000));
60
+ const eligible = input.at + delay;
61
+ const exhausted = current.attempts >= PROVIDER_RETRY_LIMIT || eligible >= Date.parse(current.deadline);
62
+ return {
63
+ ...binding,
64
+ ...(!continuing && previous !== undefined
65
+ ? { retryHistory: [...(binding.retryHistory ?? []), previous] } : {}),
66
+ retry: {
67
+ // A terminal chain has no next submission. Keep its bounded deadline
68
+ // representable even for huge hints; the unshortened hint stays in error.
69
+ ...current, nextEligibleAt: iso(exhausted ? Math.min(eligible, Date.parse(current.deadline)) : eligible),
70
+ ...(turn.retrySupported !== true ? { status: "needs-attention", reason: "host-safe-retry-unsupported" }
71
+ : exhausted ? { status: "exhausted", reason: current.attempts >= PROVIDER_RETRY_LIMIT
72
+ ? "automatic-attempt-limit" : "retry-after-exceeds-deadline" } : {})
73
+ }
74
+ };
75
+ }
76
+ /** Atomically called at the shared native write admission, never by a timer alone. */
77
+ export function admitProviderRetry(binding, input) {
78
+ const retry = binding.retry;
79
+ if (retry?.status === "in-flight" && retry.currentAttemptId === input.attemptId)
80
+ return binding;
81
+ if (retry?.status !== "waiting"
82
+ || input.at < Date.parse(retry.nextEligibleAt)
83
+ || retry.successorAutomatic !== false && (binding.retryDisabled === true
84
+ || input.at >= Date.parse(retry.deadline) || retry.attempts >= PROVIDER_RETRY_LIMIT)
85
+ || binding.authority.owner !== "controller" || binding.authority.epoch !== retry.authorityEpoch
86
+ || binding.conversations.find(c => c.epoch === binding.currentConversationEpoch)?.conversationId !== retry.nativeSessionId
87
+ || binding.run?.attemptId !== retry.failedAttemptId
88
+ || !["failed", "rejected", "deferred"].includes(binding.run.status)) {
89
+ throw new Error("Provider retry is not eligible under the current input, Session, authority or budget.");
90
+ }
91
+ return { ...binding, retry: {
92
+ ...retry, status: "in-flight", attempts: retry.attempts + (retry.successorAutomatic === false ? 0 : 1),
93
+ transportSequence: retry.transportSequence + 1,
94
+ currentAttemptId: input.attemptId, updatedAt: iso(input.at)
95
+ } };
96
+ }
97
+ /** Busy/preflight refusal is not a model attempt. Keep its exact receipt visible. */
98
+ export function deferProviderRetry(binding, at, reason) {
99
+ const retry = binding.retry;
100
+ if (retry?.status !== "in-flight" || retry.currentAttemptId !== binding.run?.attemptId)
101
+ return binding;
102
+ const { currentAttemptId: _attempt, successorRunId, ...remaining } = retry;
103
+ return { ...binding, retry: {
104
+ ...remaining, attempts: retry.attempts - (retry.successorAutomatic === false ? 0 : 1),
105
+ failedAttemptId: binding.run.attemptId,
106
+ ...(reason === undefined && successorRunId !== undefined ? { successorRunId } : {}),
107
+ ...(reason !== undefined && binding.run?.runId !== undefined ? { previousRunId: binding.run.runId } : {}),
108
+ status: reason === undefined ? "waiting" : "needs-attention",
109
+ nextEligibleAt: iso(Math.min(at + 1_000, Date.parse(retry.deadline))),
110
+ updatedAt: iso(at), ...(reason === undefined ? {} : { reason })
111
+ } };
112
+ }
113
+ export function cancelProviderRetry(binding, reason, at) {
114
+ return !providerRetryPending(binding) ? binding : {
115
+ ...binding, retry: { ...binding.retry, status: "cancelled", reason, updatedAt: iso(at) }
116
+ };
117
+ }
118
+ export function completeProviderRetry(binding, turn) {
119
+ const retry = binding.retry;
120
+ return retry === undefined || !["in-flight", "cancelled", "needs-attention"].includes(retry.status)
121
+ || retry.currentAttemptId !== turn.attemptId
122
+ || turn.status !== "completed" ? binding : {
123
+ ...binding, retry: { ...retry, status: "recovered", updatedAt: turn.updatedAt }
124
+ };
125
+ }
126
+ export function providerRetryAttemptId(retry) {
127
+ return `provider-retry:${retry.chainId}/${retry.transportSequence + 1}`;
128
+ }
129
+ export function providerRetryPrompt(retry, original) {
130
+ if (retry.failedNativeTurnId === undefined)
131
+ return original;
132
+ return [
133
+ "Yui infrastructure recovery, not new user authorization.",
134
+ `Continue the existing input after failed attempt ${retry.failureAttemptId}`,
135
+ `(native Turn ${retry.failedNativeTurnId}; failure ${retry.failureRef}).`,
136
+ "Read current authorized context and the original input. Inspect existing work and receipts first;",
137
+ "continue only unfinished work. Preserve local changes and do not repeat confirmed side effects.",
138
+ original
139
+ ].join("\n");
140
+ }
141
+ /** The same presentation is consumed by CLI, Context and Web. */
142
+ export function providerRetryProjection(binding) {
143
+ const retry = binding?.retry;
144
+ if (retry === undefined)
145
+ return null;
146
+ return {
147
+ chainId: retry.chainId,
148
+ status: retry.status === "in-flight" && binding?.run?.status === "delivery-unknown"
149
+ ? "delivery-unknown" : retry.status,
150
+ attempts: retry.status === "recovered" ? 0 : retry.attempts,
151
+ limit: PROVIDER_RETRY_LIMIT, nextEligibleAt: retry.nextEligibleAt, deadline: retry.deadline,
152
+ category: retry.error.category, preservesWork: true, nativeSessionId: retry.nativeSessionId,
153
+ ...(retry.reason === undefined ? {} : { reason: retry.reason }),
154
+ failureRef: retry.failureRef,
155
+ ...(retry.previousRunId === undefined ? {} : { previousRunId: retry.previousRunId }),
156
+ ...(retry.successorRunId === undefined ? {} : { successorRunId: retry.successorRunId })
157
+ };
158
+ }
159
+ export function controlProviderRetry(binding, action, at) {
160
+ if (action === "enable")
161
+ return { ...binding, retryDisabled: false };
162
+ return { ...cancelProviderRetry(binding, `user-${action}`, at),
163
+ ...(action === "disable" ? { retryDisabled: true } : {}) };
164
+ }
165
+ export function renderProviderRetry(binding) {
166
+ const view = providerRetryProjection(binding);
167
+ return view === null ? `Provider retry: ${binding?.retryDisabled ? "disabled" : "none"}`
168
+ : `Provider retry: ${view.category}/${view.status}; ${view.attempts}/${view.limit}; next=${view.nextEligibleAt}; `
169
+ + `deadline=${view.deadline}; existing work preserved${view.reason === undefined ? "" : `; ${view.reason}`}`;
170
+ }
171
+ export function validateProviderRetry(retry) {
172
+ if (retry.policyVersion !== 1 || !["waiting", "in-flight", "recovered", "cancelled", "exhausted", "needs-attention"].includes(retry.status)
173
+ || !Number.isSafeInteger(retry.attempts) || retry.attempts < 0 || retry.attempts > PROVIDER_RETRY_LIMIT
174
+ || !Number.isSafeInteger(retry.transportSequence) || retry.transportSequence < retry.attempts
175
+ || !Number.isSafeInteger(retry.authorityEpoch) || retry.authorityEpoch < 1
176
+ || [retry.chainId, retry.nativeSessionId, retry.failedAttemptId, retry.failureRef].some(v => typeof v !== "string" || v.length === 0)
177
+ || [retry.startedAt, retry.intentAt, retry.deadline, retry.nextEligibleAt, retry.updatedAt].some(v => !Number.isFinite(Date.parse(v)))
178
+ || Date.parse(retry.deadline) - Date.parse(retry.startedAt) !== PROVIDER_RETRY_BUDGET_MS
179
+ || retry.status === "in-flight" && !retry.currentAttemptId)
180
+ throw new Error("Invalid Provider retry record.");
181
+ validateProviderInput(retry.input);
182
+ }
183
+ export function validateProviderInput(input) {
184
+ const fields = input.kind === "run" ? [input.taskId, input.runId]
185
+ : input.kind === "wake" ? [input.taskId, input.wakeId]
186
+ : input.kind === "message" ? [input.roleName, input.messageId]
187
+ : input.kind === "text" ? [input.text] : [];
188
+ if (fields.length === 0 || fields.some(v => typeof v !== "string" || !v.trim())) {
189
+ throw new Error("Invalid owned Provider input.");
190
+ }
191
+ }
192
+ function iso(at) { return new Date(at).toISOString(); }
193
+ function unitRandom(random) {
194
+ const value = random();
195
+ if (!Number.isFinite(value) || value < 0 || value > 1)
196
+ throw new Error("Retry RNG must return a unit fraction.");
197
+ return value;
198
+ }
@@ -1,3 +1,5 @@
1
+ import { cancelProviderRetry, completeProviderRetry, validateProviderInput, validateProviderRetry } from "./providerRetry.js";
2
+ import { isStandardAgentError } from "./agentError.js";
1
3
  export function createProviderRuntimeBinding(input) {
2
4
  const startedAt = timestamp(input.startedAt, "Provider Conversation startedAt");
3
5
  return validateProviderRuntimeBinding({
@@ -84,7 +86,7 @@ export function transferProviderAuthority(raw, input) {
84
86
  });
85
87
  }
86
88
  export function beginProviderTurn(raw, input) {
87
- const binding = validateProviderRuntimeBinding(raw);
89
+ let binding = validateProviderRuntimeBinding(raw);
88
90
  const attemptId = identity(input.attemptId, "Provider input attempt id");
89
91
  const runId = input.runId === undefined ? undefined : identity(input.runId, "AgentRun id");
90
92
  const currentRun = binding.run;
@@ -104,6 +106,9 @@ export function beginProviderTurn(raw, input) {
104
106
  throw new Error("Provider Conversation already has an unsettled AgentRun.");
105
107
  }
106
108
  const submittedAt = timestamp(input.submittedAt, "Provider Turn submittedAt");
109
+ if (binding.retry?.currentAttemptId !== attemptId) {
110
+ binding = cancelProviderRetry(binding, "superseded-by-explicit-input", Date.parse(submittedAt));
111
+ }
107
112
  return validateProviderRuntimeBinding({
108
113
  ...binding,
109
114
  run: {
@@ -111,6 +116,8 @@ export function beginProviderTurn(raw, input) {
111
116
  attemptId,
112
117
  authorityEpoch: input.authorityEpoch,
113
118
  status: "submitting",
119
+ ...(input.input === undefined ? {} : { input: input.input }),
120
+ ...(input.retrySupported === undefined ? {} : { retrySupported: input.retrySupported }),
114
121
  submittedAt,
115
122
  updatedAt: submittedAt
116
123
  }
@@ -221,7 +228,7 @@ export function settleProviderTurn(raw, input) {
221
228
  throw new Error("Provider Turn settlement does not match the current AgentRun.");
222
229
  }
223
230
  const settledAt = orderedRunTimestamp(run, input.settledAt, "Provider Turn settledAt");
224
- return validateProviderRuntimeBinding({
231
+ const settled = validateProviderRuntimeBinding({
225
232
  ...binding,
226
233
  run: {
227
234
  ...run,
@@ -233,6 +240,7 @@ export function settleProviderTurn(raw, input) {
233
240
  : { terminalReason: identity(input.reason, "Provider Turn terminal reason") })
234
241
  }
235
242
  });
243
+ return completeProviderRetry(settled, settled.run);
236
244
  }
237
245
  /** Explicitly abandon an engineering input only after its execution resources
238
246
  * are quiescent. This does not invent native acceptance, a Turn id or success. */
@@ -367,6 +375,24 @@ export function validateProviderRuntimeBinding(value) {
367
375
  throw new Error("Provider Runtime Binding requires Goal state.");
368
376
  if (value.goal !== null)
369
377
  validateProviderGoal(value.goal);
378
+ if (value.retry !== undefined)
379
+ validateProviderRetry(value.retry);
380
+ if (value.retryHistory !== undefined) {
381
+ if (!Array.isArray(value.retryHistory))
382
+ throw new Error("Provider retry audit must be an array.");
383
+ for (const retry of value.retryHistory) {
384
+ validateProviderRetry(retry);
385
+ if (retry.status === "waiting" || retry.status === "in-flight")
386
+ throw new Error("Provider retry audit cannot schedule work.");
387
+ }
388
+ }
389
+ if (value.retryDisabled !== undefined && typeof value.retryDisabled !== "boolean")
390
+ throw new Error("Provider retry switch must be boolean.");
391
+ if (value.run?.input !== undefined)
392
+ validateProviderInput(value.run.input);
393
+ if (value.run?.failure !== undefined
394
+ && (!isStandardAgentError(value.run.failure.error) || !value.run.failure.ref))
395
+ throw new Error("Invalid Provider input failure.");
370
396
  return value;
371
397
  }
372
398
  function validateProviderGoal(goal) {
@@ -547,11 +547,6 @@ function requireTimestamp(value, label) {
547
547
  throw new Error(`${label} is invalid.`);
548
548
  return timestamp;
549
549
  }
550
- function requireNonNegativeInteger(value, minimum, label) {
551
- if (!Number.isSafeInteger(value) || value < minimum)
552
- throw new Error(`${label} is invalid.`);
553
- return value;
554
- }
555
550
  function requireIdentity(value, label) {
556
551
  const identity = requireText(value, label);
557
552
  if (identity.includes("/../") || identity === "__proto__")
@@ -18,11 +18,10 @@ export function projectRuntimeSessionCandidate(sessions) {
18
18
  sessionUpdatedAt: active.updatedAt
19
19
  };
20
20
  }
21
- /** Deterministic owner order shared by all storage backends. */
21
+ /** Deterministic owner order for current runtime discovery. */
22
22
  export function compareRuntimeSessionCandidates(left, right) {
23
23
  if (left.owner.scope !== right.owner.scope) {
24
- // Preserve the historical adapter contract: Task owners precede the
25
- // bounded global Role set.
24
+ // Task owners precede the bounded global Role set.
26
25
  return left.owner.scope === "task" ? -1 : 1;
27
26
  }
28
27
  if (left.owner.scope === "task" && right.owner.scope === "task") {
@@ -17,7 +17,7 @@ export function createSessionOwnerIdentity(input) {
17
17
  throw new TypeError("Global session owner must not carry a task id.");
18
18
  }
19
19
  const providerRoot = input.providerRoot;
20
- if (!["launch-env", "pane-pid", "owned-child"].includes(providerRoot.attribution)) {
20
+ if (!["pane-pid", "owned-child"].includes(providerRoot.attribution)) {
21
21
  throw new TypeError("Session owner process attribution is invalid.");
22
22
  }
23
23
  if (!Number.isSafeInteger(providerRoot.pid) || providerRoot.pid <= 0) {
@@ -26,11 +26,21 @@ export function resolveSessionTokenIdentity(input) {
26
26
  export function projectSessionTokenMetrics(events, identity) {
27
27
  if (identity === null)
28
28
  return unobservedSessionTokenMetrics();
29
- const observations = events
30
- .map(runtimeObservationFromTaskEvent)
31
- .filter((observation) => (observation !== null
32
- && isRuntimeTokenEvidence(observation)
33
- && matchesSessionIdentity(observation, identity)))
29
+ return projectSessionTokenObservations(events.flatMap((event) => {
30
+ const observation = runtimeObservationFromTaskEvent(event);
31
+ return observation === null ? [] : [observation];
32
+ }), identity);
33
+ }
34
+ /** Shared reducer for authorized, already decoded canonical observations. */
35
+ export function projectSessionTokenObservations(input, identity) {
36
+ const observations = input
37
+ .filter((observation) => (isRuntimeTokenEvidence(observation)
38
+ && matchesSessionIdentity(observation, identity)
39
+ && (observation.authority === "provider-structured" || observation.authority === "driver-inferred")
40
+ // Child counters have no declared inclusion relationship with the
41
+ // Session's parent counter. They must never be added as extra requests.
42
+ && observation.fence.continuationId === undefined
43
+ && observation.fence.parentContinuationId === undefined))
34
44
  .sort(compareObservations);
35
45
  const incompleteBoundaries = observations.filter(({ payload }) => (payload.usage === undefined));
36
46
  const request = observations.filter(({ payload }) => (payload.usage?.semantics === "request-context"));
@@ -2,13 +2,14 @@ import { spawn } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { Duplex } from "node:stream";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
5
6
  import WebSocket from "ws";
6
- import { CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexAppServerErrorIsMissing, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
7
- import { serializeAgentErrorRaw } from "./agentError.js";
7
+ import { YUI_VERSION } from "../version.js";
8
8
  import { AcpStructuredProviderSession } from "./acpSession.js";
9
9
  import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
10
+ import { serializeAgentErrorRaw } from "./agentError.js";
10
11
  import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
11
- import { YUI_VERSION } from "../version.js";
12
+ import { codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
12
13
  import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
13
14
  import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
14
15
  const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
@@ -18,44 +19,6 @@ const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
18
19
  */
19
20
  const CODEX_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("The Codex app-server protocol");
20
21
  const CLAUDE_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("Claude Code's stream-json interface");
21
- export class ProviderDeliveryUnknownError extends Error {
22
- attemptId;
23
- name = "ProviderDeliveryUnknownError";
24
- constructor(message, attemptId,
25
- // Wrapping must not become the end of the causal chain: the original
26
- // transport or Controller failure is the reason a reader needs.
27
- options) {
28
- super(message, options);
29
- this.attemptId = attemptId;
30
- }
31
- }
32
- export class ProviderTurnRejectedError extends Error {
33
- attemptId;
34
- name = "ProviderTurnRejectedError";
35
- constructor(message, attemptId, options) {
36
- super(message, options);
37
- this.attemptId = attemptId;
38
- }
39
- }
40
- /** Another ordinary client currently owns the thread's active Turn. */
41
- export class ProviderTurnBusyError extends Error {
42
- attemptId;
43
- activeTurnId;
44
- name = "ProviderTurnBusyError";
45
- constructor(message, attemptId, activeTurnId) {
46
- super(message);
47
- this.attemptId = attemptId;
48
- this.activeTurnId = activeTurnId;
49
- }
50
- }
51
- export class ProviderConversationMissingError extends Error {
52
- conversationId;
53
- name = "ProviderConversationMissingError";
54
- constructor(conversationId, message) {
55
- super(message);
56
- this.conversationId = conversationId;
57
- }
58
- }
59
22
  export async function startStructuredProviderSession(payload, input = {}) {
60
23
  const control = payload.providerControl;
61
24
  if (control === undefined) {
@@ -462,7 +425,7 @@ class CodexStructuredProviderSession {
462
425
  ? {}
463
426
  : {
464
427
  error: recovered.error ?? "Provider Turn failed.",
465
- rawError: serializeAgentErrorRaw(recovered)
428
+ ...(recovered.rawError === undefined ? {} : { rawError: recovered.rawError })
466
429
  })
467
430
  };
468
431
  session.#clientOwnedTurnId = undefined;
@@ -594,7 +557,11 @@ class CodexStructuredProviderSession {
594
557
  conversationId: this.conversationId,
595
558
  attemptId: turn.attemptId,
596
559
  text: turn.boundedText,
597
- expectedNoActiveTurn: true
560
+ expectedNoActiveTurn: true,
561
+ ...(turn.requireQuiescent ? { requireQuiescent: true } : {}),
562
+ ...(turn.expectedFailedNativeTurnId === undefined ? {} : {
563
+ expectedFailedNativeTurnId: turn.expectedFailedNativeTurnId
564
+ })
598
565
  });
599
566
  if (acceptance.status === "unknown") {
600
567
  throw new ProviderDeliveryUnknownError(acceptance.reason, turn.attemptId);