@zq-silk/yui 0.13.7 → 0.13.9

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 (78) hide show
  1. package/ARCHITECTURE.md +40 -4
  2. package/README.md +23 -4
  3. package/dist/cli/commandCatalog.js +21 -2
  4. package/dist/cli/updatePorts.js +4 -4
  5. package/dist/cli.js +43 -14
  6. package/dist/commands/agentCommands.js +1 -1
  7. package/dist/commands/configCommands.js +1 -86
  8. package/dist/commands/executionAuditCommands.js +17 -16
  9. package/dist/commands/globalRoleCommands.js +4 -4
  10. package/dist/commands/sessionCommands.js +2 -6
  11. package/dist/commands/taskActor.js +1 -2
  12. package/dist/commands/taskCommands.js +93 -21
  13. package/dist/commands/taskContextCommand.js +1 -1
  14. package/dist/commands/taskExecutionCommands.js +0 -5
  15. package/dist/commands/taskOverviewCommand.js +5 -1
  16. package/dist/commands/taskRoleRuntimeStatus.js +3 -16
  17. package/dist/config/configCatalog.js +1 -6
  18. package/dist/config/yuiConfig.js +0 -79
  19. package/dist/context/sessionBootstrapManifest.js +26 -23
  20. package/dist/controller/clientRuntime.js +40 -3
  21. package/dist/controller/controller.js +29 -54
  22. package/dist/controller/fileSchedulerStoreAdapter.js +372 -1117
  23. package/dist/controller/runtime.js +12 -5
  24. package/dist/controller/runtimeHookRunFence.js +3 -9
  25. package/dist/controller/runtimeLaunchCoordinator.js +44 -67
  26. package/dist/controller/structuredProviderObservation.js +18 -5
  27. package/dist/coordination/workMailbox.js +4 -4
  28. package/dist/execution/executionHealth.js +1 -1
  29. package/dist/executor/agentExecutor.js +103 -93
  30. package/dist/executor/executorRegistry.js +8 -20
  31. package/dist/executor/fileRoleLaunchPlanner.js +26 -93
  32. package/dist/executor/turnCompletion.js +5 -5
  33. package/dist/lifecycle/exactRunTerminalization.js +2 -4
  34. package/dist/observability/executionAudit.js +40 -94
  35. package/dist/operator/operatorSessionHistory.js +7 -5
  36. package/dist/output/rolePresentation.js +0 -1
  37. package/dist/repository/taskWorkspacePreparer.js +0 -1
  38. package/dist/role/role.js +13 -21
  39. package/dist/run/agentRun.js +4 -54
  40. package/dist/runtime/agentDriver.js +2 -0
  41. package/dist/runtime/agentError.js +114 -0
  42. package/dist/runtime/agentHost.js +55 -82
  43. package/dist/runtime/builtinAgentDrivers.js +21 -9
  44. package/dist/runtime/builtinAgentErrorMappers.js +150 -0
  45. package/dist/runtime/exactControlPlane.js +6 -12
  46. package/dist/runtime/index.js +1 -2
  47. package/dist/runtime/launchBroker.js +5 -19
  48. package/dist/runtime/lifecycleReservation.js +20 -4
  49. package/dist/runtime/providerRuntimeIdentity.js +11 -19
  50. package/dist/runtime/runtimeBinding.js +0 -27
  51. package/dist/runtime/runtimeObservation.js +7 -16
  52. package/dist/runtime/runtimeSessionCandidate.js +3 -10
  53. package/dist/runtime/sessionLaunchRequest.js +1 -2
  54. package/dist/runtime/sessionReconciliation.js +2 -2
  55. package/dist/runtime/structuredProviderHost.js +44 -79
  56. package/dist/runtime/taskRuntimeIsolation.js +0 -7
  57. package/dist/runtime/tmuxAdapters.js +6 -49
  58. package/dist/scheduler/activeRoleRunDelivery.js +220 -178
  59. package/dist/scheduler/activeTaskProgress.js +1 -4
  60. package/dist/scheduler/leaderWakeupProcessor.js +123 -88
  61. package/dist/scheduler/roleRunLiveness.js +4 -1
  62. package/dist/scheduler/roleRunStall.js +10 -14
  63. package/dist/scheduler/wakeReason.js +4 -0
  64. package/dist/storage/migration/productionRegistry.js +475 -0
  65. package/dist/storage/sqliteSchema.js +54 -2
  66. package/dist/storage/sqliteStore.js +11 -44
  67. package/dist/storage/taskStore.js +8 -36
  68. package/dist/web/webSnapshot.js +3 -0
  69. package/i18n/README.zh-CN.md +11 -3
  70. package/package.json +1 -1
  71. package/skills/yui-leader/SKILL.md +30 -8
  72. package/skills/yui-operator/SKILL.md +14 -6
  73. package/skills/yui-runtime/SKILL.md +11 -8
  74. package/dist/lifecycle/providerErrorClass.js +0 -152
  75. package/dist/run/providerRetry.js +0 -226
  76. package/dist/run/providerRetryConfig.js +0 -27
  77. package/dist/runtime/providerErrorCodes.js +0 -278
  78. package/dist/runtime/providerRecoveryDecision.js +0 -55
@@ -555,9 +555,14 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
555
555
  const lifecycleTails = new Map();
556
556
  return async (method, params) => {
557
557
  if (method === "runtime.observation-apply") {
558
- return {
559
- outcome: schedulerStore.observeRuntimeObservation(createRuntimeObservation(params), new Date())
560
- };
558
+ try {
559
+ return {
560
+ outcome: schedulerStore.observeRuntimeObservation(createRuntimeObservation(params), new Date())
561
+ };
562
+ }
563
+ catch (error) {
564
+ throw applicationError("INVALID_PARAMS", error instanceof Error ? error.message : String(error));
565
+ }
561
566
  }
562
567
  if (method === "runtime.provider-turn-begin") {
563
568
  const value = providerTurnControlParams(params);
@@ -588,8 +593,10 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
588
593
  const value = providerTurnControlParams(params);
589
594
  const status = params.status;
590
595
  const reason = params.reason;
596
+ const raw = params.raw;
591
597
  if ((status !== "rejected" && status !== "delivery-unknown")
592
- || typeof reason !== "string" || reason.trim().length === 0) {
598
+ || typeof reason !== "string" || reason.trim().length === 0
599
+ || typeof raw !== "string" || raw.trim().length === 0) {
593
600
  throw applicationError("INVALID_PARAMS", "Provider Turn resolution is invalid.");
594
601
  }
595
602
  schedulerStore.resolveAgentHostProviderTurnSubmission({
@@ -599,6 +606,7 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
599
606
  attemptId: value.attemptId,
600
607
  status,
601
608
  reason,
609
+ raw,
602
610
  now: value.now
603
611
  });
604
612
  return { recorded: true };
@@ -769,7 +777,6 @@ export function createRuntimeLifecycleDispatcher(store, schedulerStore, sessionH
769
777
  validateLifecycleEnvironment(request.environment, agent);
770
778
  const session = sessions?.sessions[effective.agentId];
771
779
  const managedTurnDispatch = activeRun !== null && (activeRun.pushedAt === undefined
772
- || activeRun.providerRetry?.state === "dispatching"
773
780
  || activeRun.controlRequest?.state === "dispatching");
774
781
  // An ensure call may reattach the already-admitted Run to its existing
775
782
  // Conversation, but it may not manufacture a fresh Conversation without a
@@ -87,19 +87,13 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
87
87
  }));
88
88
  const exactReservation = isRuntimeLaunchReservation(mailbox?.processing, launchId)
89
89
  && !hasRuntimeCleanupObligation(mailbox);
90
- const executionRef = mailbox?.processing?.executionRef;
91
90
  const startupRunId = options.startupSession === undefined
92
91
  ? undefined
93
92
  : requireIdentity(runtime?.runId
94
- ?? environment.YUI_RUN_ID
95
- ?? (executionRef?.type === "run" && executionRef.taskId === taskId
96
- ? executionRef.id
97
- : undefined), "Run id");
93
+ ?? environment.YUI_RUN_ID, "Run id");
98
94
  const startupReservation = startupRunId !== undefined
99
95
  && exactReservation
100
- && executionRef?.type === "run"
101
- && executionRef.taskId === taskId
102
- && executionRef.id === startupRunId;
96
+ && !hasRuntimeCleanupObligation(mailbox);
103
97
  const startupRun = startupRunId === undefined
104
98
  ? null
105
99
  : store.getAgentRun(taskId, startupRunId);
@@ -108,7 +102,7 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
108
102
  && sessions !== null
109
103
  && startupReservation
110
104
  && startupRun?.mode === "new"
111
- && (session.status === "stopped" || session.status === "broken");
105
+ && session.status === "ended";
112
106
  const preallocatedStartup = options.startupSession === "preallocated"
113
107
  && expectedNativeSessionId !== undefined
114
108
  && (session === undefined || replacementStartup)
@@ -89,42 +89,45 @@ export class RuntimeLaunchCoordinator {
89
89
  };
90
90
  const generationPrefix = `runtime-${expectedFingerprint}:generation:`;
91
91
  const proposedGenerationId = requireText(this.#createGenerationId(), "Launch generation id");
92
- const proposedLaunchId = `${generationPrefix}${proposedGenerationId}`;
93
- let runtimeIsolation = this.#preflightRuntimeIsolation(request, proposedLaunchId, proposedGenerationId, false);
92
+ let proposedLaunchId = `${generationPrefix}${proposedGenerationId}`;
93
+ let reusedConfirmedRunningHost = false;
94
+ if (request.mode === "resume" && request.hostActivationId !== undefined) {
95
+ if (!request.hostActivationId.startsWith(generationPrefix)) {
96
+ throw new Error("Session restore targets an incompatible Host activation.");
97
+ }
98
+ const inspection = await this.host.inspectOwner(request.owner);
99
+ if (inspection.state === "unavailable" || inspection.state === "starting") {
100
+ throw new RuntimeLaunchError(true, request.hostActivationId, `Host activation is temporarily ${inspection.state}: ${request.owner.roleName}.`);
101
+ }
102
+ if (inspection.state === "running") {
103
+ proposedLaunchId = request.hostActivationId;
104
+ reusedConfirmedRunningHost = true;
105
+ }
106
+ }
107
+ let runtimeIsolation = reusedConfirmedRunningHost
108
+ ? undefined
109
+ : this.#preflightRuntimeIsolation(request, proposedLaunchId, proposedGenerationId, false);
94
110
  let reservation = this.reservations.reserveRuntimeLaunch({
95
111
  owner: request.owner,
96
- launchId: proposedLaunchId,
97
- ...(request.runId === undefined ? {} : { runId: request.runId })
112
+ launchId: proposedLaunchId
98
113
  }, assertLaunchCurrent, this.#now());
99
- let reusedConfirmedRunningHost = false;
100
114
  if (reservation.status === "existing") {
101
115
  if (!reservation.launchId.startsWith(generationPrefix)) {
102
116
  this.#requireCleanup(request.owner);
103
117
  throw new Error(`Runtime launch reservation belongs to stale Role or Agent state: ${request.owner.roleName}.`);
104
118
  }
105
- const sameRunReservation = request.runId !== undefined
106
- && reservation.runId === request.runId;
107
- const differentRunReservation = request.runId !== undefined
108
- && reservation.runId !== undefined
109
- && reservation.runId !== request.runId;
110
119
  const inspection = await this.host.inspectOwner(request.owner);
111
120
  if (inspection.state === "unavailable" || inspection.state === "starting") {
112
- if (sameRunReservation) {
113
- throw new RuntimeLaunchError(true, reservation.launchId, `Runtime is temporarily ${inspection.state}: ${request.runId}/${reservation.launchId}.`);
114
- }
115
- throw new Error(`Runtime launch reservation cannot yet be verified: ${request.owner.roleName}.`);
121
+ throw new RuntimeLaunchError(true, reservation.launchId, `Runtime is temporarily ${inspection.state}: ${request.owner.roleName}/${reservation.launchId}.`);
116
122
  }
117
123
  if (inspection.state === "stopped") {
118
- if (sameRunReservation) {
119
- throw new RuntimeLaunchError(false, reservation.launchId, `Exact Run launch generation stopped before delivery: ${request.runId}/${reservation.launchId}.`);
120
- }
121
124
  const taskOwner = request.owner.scope === "task"
122
125
  ? request.owner
123
126
  : undefined;
124
127
  let exactCleanupAttempted = false;
125
128
  let completed = false;
126
129
  try {
127
- completed = this.reservations.completeRuntimeLaunchReservation(request.owner, reservation.launchId, differentRunReservation ? reservation.runId : undefined, taskOwner !== undefined && this.#runtimeIsolation !== undefined
130
+ completed = this.reservations.completeRuntimeLaunchReservation(request.owner, reservation.launchId, taskOwner !== undefined && this.#runtimeIsolation !== undefined
128
131
  ? () => {
129
132
  exactCleanupAttempted = true;
130
133
  this.#cleanupTaskLaunch(taskOwner, reservation.launchId);
@@ -143,19 +146,15 @@ export class RuntimeLaunchCoordinator {
143
146
  }
144
147
  reservation = this.reservations.reserveRuntimeLaunch({
145
148
  owner: request.owner,
146
- launchId: proposedLaunchId,
147
- ...(request.runId === undefined ? {} : { runId: request.runId })
149
+ launchId: proposedLaunchId
148
150
  }, assertLaunchCurrent, this.#now());
149
151
  if (reservation.status !== "reserved") {
150
152
  throw new Error("Runtime launch reservation could not be renewed.");
151
153
  }
152
154
  }
153
155
  else {
154
- if (differentRunReservation) {
155
- throw new Error(`Runtime launch reservation belongs to another Run whose host is still running: ${reservation.runId}.`);
156
- }
157
156
  reusedConfirmedRunningHost = true;
158
- runtimeIsolation = this.#preflightRuntimeIsolation(request, reservation.launchId, reservation.launchId.slice(generationPrefix.length), true);
157
+ runtimeIsolation = undefined;
159
158
  assertLaunchCurrent();
160
159
  }
161
160
  }
@@ -194,7 +193,7 @@ export class RuntimeLaunchCoordinator {
194
193
  ? {}
195
194
  : { environment: request.environment })
196
195
  }, beforeHostStart === undefined ? undefined : observePreflight)
197
- : await this.host.resume({
196
+ : await this.host.restore({
198
197
  mode: "resume",
199
198
  launchId,
200
199
  owner: request.owner,
@@ -228,7 +227,7 @@ export class RuntimeLaunchCoordinator {
228
227
  let exactCleanupAttempted = false;
229
228
  let completed = false;
230
229
  try {
231
- completed = this.reservations.completeRuntimeLaunchReservation(request.owner, launchId, undefined, runtimeIsolation === undefined
230
+ completed = this.reservations.completeRuntimeLaunchReservation(request.owner, launchId, runtimeIsolation === undefined
232
231
  ? undefined
233
232
  : () => {
234
233
  exactCleanupAttempted = true;
@@ -258,31 +257,28 @@ export class RuntimeLaunchCoordinator {
258
257
  throw error;
259
258
  }
260
259
  if (reusedConfirmedRunningHost && binding.hostCreated === true) {
261
- if (request.runId !== undefined && reservation.runId === request.runId) {
262
- throw new RuntimeLaunchError(false, launchId, `Exact Run launch generation was unexpectedly recreated: ${request.runId}/${launchId}.`);
263
- }
264
260
  await this.#compensateStartedHost(request.owner, binding, launchId, runtimeIsolation, new Error(`Runtime host was recreated while recovering an existing generation: ${request.owner.roleName}.`));
265
261
  }
266
262
  try {
267
263
  assertLaunchCurrent();
268
- if (persistence === "immediate" && binding.nativeSessionId !== undefined) {
269
- this.reservations.recordReservedRuntimeNativeSession({
270
- owner: request.owner,
271
- launchId,
272
- agentId: request.agentId,
273
- adapterId: request.adapterId,
274
- nativeSessionId: binding.nativeSessionId,
275
- effective: request.effective
276
- }, assertLaunchCurrent, this.#now());
277
- }
278
- else {
279
- // Deferred scheduler persistence records a known native identity while
280
- // retaining the reservation until exact Run delivery. Fresh Codex has
281
- // no identity yet and keeps it until its matching generation Hook.
282
- this.reservations.confirmRuntimeLaunchReservation({
283
- owner: request.owner,
284
- launchId
285
- }, assertLaunchCurrent);
264
+ const reservationState = this.reservations.confirmRuntimeLaunchReservation({
265
+ owner: request.owner,
266
+ launchId
267
+ }, assertLaunchCurrent);
268
+ if (reservationState === "reserved") {
269
+ if (binding.nativeSessionId !== undefined) {
270
+ this.reservations.recordReservedRuntimeNativeSession({
271
+ owner: request.owner,
272
+ launchId,
273
+ agentId: request.agentId,
274
+ adapterId: request.adapterId,
275
+ nativeSessionId: binding.nativeSessionId,
276
+ effective: request.effective
277
+ }, assertLaunchCurrent, this.#now());
278
+ }
279
+ else if (!this.reservations.completeRuntimeLaunchReservation(request.owner, launchId)) {
280
+ throw new Error("Runtime Host-start reservation changed before completion.");
281
+ }
286
282
  }
287
283
  }
288
284
  catch (error) {
@@ -366,7 +362,6 @@ export class RuntimeLaunchCoordinator {
366
362
  }
367
363
  return this.#runtimeIsolation.preflight({
368
364
  workspace: request.managedWorkspace,
369
- ...(request.runId === undefined ? {} : { runId: request.runId }),
370
365
  launchId,
371
366
  generationId: requireText(generationId, "Launch generation id"),
372
367
  ...(request.runtimePolicy === undefined ? {} : { policy: request.runtimePolicy }),
@@ -419,9 +414,7 @@ function validateRuntimeLaunchPreflight(preflight, request, launchId) {
419
414
  || preflight.adapterId !== request.adapterId
420
415
  || !effectiveLaunchSnapshotsCompatible(preflight.effective, request.effective)
421
416
  || (request.mode === "resume"
422
- && preflight.nativeSessionId !== request.nativeSessionId)
423
- || (preflight.initialTurnRunId !== undefined
424
- && preflight.initialTurnRunId !== request.runId)) {
417
+ && preflight.nativeSessionId !== request.nativeSessionId)) {
425
418
  throw new Error(`Session host pre-start launch fence does not match the requested runtime: ${request.owner.roleName}.`);
426
419
  }
427
420
  }
@@ -438,22 +431,6 @@ function requireMatchingRuntimeBinding(raw, request, launchId) {
438
431
  && (binding.owner.scope === "global"
439
432
  || (request.owner.scope === "task"
440
433
  && binding.owner.taskId === request.owner.taskId));
441
- if (binding.initialTurnRunId !== undefined
442
- && binding.initialTurnRunId !== request.runId) {
443
- throw new RuntimeBindingContractError(`Session host returned an initial structured Turn for another Run: ${request.owner.roleName}.`);
444
- }
445
- if (binding.initialTurnDeliveryUnknownRunId !== undefined
446
- && binding.initialTurnDeliveryUnknownRunId !== request.runId) {
447
- throw new RuntimeBindingContractError(`Session host returned a delivery-unknown initial structured Turn for another Run: ${request.owner.roleName}.`);
448
- }
449
- if (binding.initialTurnBusyRunId !== undefined
450
- && binding.initialTurnBusyRunId !== request.runId) {
451
- throw new RuntimeBindingContractError(`Session host returned a busy initial structured Turn for another Run: ${request.owner.roleName}.`);
452
- }
453
- if (binding.initialTurnRejectedRunId !== undefined
454
- && binding.initialTurnRejectedRunId !== request.runId) {
455
- throw new RuntimeBindingContractError(`Session host returned a rejected initial structured Turn for another Run: ${request.owner.roleName}.`);
456
- }
457
434
  if (binding.launchId !== launchId
458
435
  || !ownerMatches
459
436
  || binding.agentId !== request.agentId
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { callController } from "../core/controllerClient.js";
3
3
  import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
4
+ import { standardAgentError } from "../runtime/agentError.js";
4
5
  import { createRuntimeObservation, runtimeObservationSemanticKey } from "../runtime/runtimeObservation.js";
5
6
  import { runtimeLifecycleSignalKey } from "../runtime/lifecycleReservation.js";
6
7
  import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
@@ -159,11 +160,23 @@ export async function publishStructuredProviderTerminal(input) {
159
160
  : kind === "turn.failed"
160
161
  ? {
161
162
  failure: {
162
- code: "provider-structured-failure",
163
- ...(input.terminal.error === undefined
164
- ? {}
165
- : { details: input.terminal.error })
166
- }
163
+ error: standardAgentError({
164
+ source: "provider",
165
+ phase: "turn-execute",
166
+ classification: driver.runtime.mapError({
167
+ message: input.terminal.error ?? "Provider Turn failed.",
168
+ raw: input.terminal.rawError
169
+ ?? input.terminal.error
170
+ ?? "Provider Turn failed without an error payload."
171
+ }),
172
+ message: input.terminal.error ?? "Provider Turn failed.",
173
+ raw: input.terminal.rawError
174
+ ?? input.terminal.error
175
+ ?? "Provider Turn failed without an error payload.",
176
+ inputDisposition: "accepted"
177
+ })
178
+ },
179
+ summary: input.terminal.error ?? "Provider Turn failed."
167
180
  }
168
181
  : {};
169
182
  const terminalObservation = observation({
@@ -157,7 +157,7 @@ function requireProcessing(mailbox, batchId) {
157
157
  }
158
158
  export function createWorkMailbox(target) {
159
159
  return {
160
- schemaVersion: 2,
160
+ schemaVersion: 3,
161
161
  target: copyTarget(target),
162
162
  nextSequence: 1,
163
163
  processing: null,
@@ -173,8 +173,8 @@ export function createWorkMailbox(target) {
173
173
  export function validateWorkMailbox(value) {
174
174
  const mailbox = record(value, "WorkMailbox");
175
175
  exact(mailbox, ["schemaVersion", "target", "nextSequence", "processing", "pending", "inputDelivery"], "WorkMailbox");
176
- if (mailbox.schemaVersion !== 2)
177
- throw new Error("WorkMailbox must use schemaVersion 2");
176
+ if (mailbox.schemaVersion !== 3)
177
+ throw new Error("WorkMailbox must use schemaVersion 3");
178
178
  const target = parseTarget(mailbox.target);
179
179
  const nextSequence = requireInteger(mailbox.nextSequence, 1, "WorkMailbox nextSequence");
180
180
  const processing = mailbox.processing === null ? null : parseProcessing(mailbox.processing);
@@ -215,7 +215,7 @@ export function validateWorkMailbox(value) {
215
215
  if (inputDelivery !== null && target.kind !== "role" && target.kind !== "operator") {
216
216
  throw new Error("WorkMailbox inputDelivery requires a Role or Operator target");
217
217
  }
218
- return { schemaVersion: 2, target, nextSequence, processing, pending, inputDelivery };
218
+ return { schemaVersion: 3, target, nextSequence, processing, pending, inputDelivery };
219
219
  }
220
220
  function parsePendingLanes(value) {
221
221
  const lanes = record(value, "WorkMailbox pending");
@@ -205,7 +205,7 @@ function projectExecutionLaneHealth(lane, input, policy) {
205
205
  });
206
206
  }
207
207
  const exit = latestExactProcessExit(input.events, run, session);
208
- const sessionDead = session?.status === "stopped" || session?.status === "broken";
208
+ const sessionDead = session?.status === "ended";
209
209
  if (sessionDead
210
210
  && exit !== null
211
211
  && isAbnormalExit(exit.classification)