@zq-silk/yui 0.6.8 → 0.6.10

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 (58) hide show
  1. package/README.md +10 -3
  2. package/dist/cli/commandCatalog.js +1 -1
  3. package/dist/commands/taskCommands.js +63 -28
  4. package/dist/commands/taskContextCommand.js +27 -1
  5. package/dist/commands/taskRoleRuntimeStatus.js +17 -6
  6. package/dist/controller/agentRuntimeObserver.js +6 -3
  7. package/dist/controller/controller.js +29 -47
  8. package/dist/controller/fileSchedulerStoreAdapter.js +572 -258
  9. package/dist/controller/runtime.js +8 -1
  10. package/dist/controller/runtimeEventInbox.js +16 -5
  11. package/dist/controller/runtimeHookRunFence.js +51 -5
  12. package/dist/controller/runtimeObservationHook.js +8 -2
  13. package/dist/coordination/workMailbox.js +408 -28
  14. package/dist/coordination/workMailboxQueue.js +12 -10
  15. package/dist/executor/agentExecutor.js +101 -94
  16. package/dist/executor/executorRegistry.js +47 -2
  17. package/dist/executor/fileRoleLaunchPlanner.js +4 -2
  18. package/dist/lifecycle/exactRunTerminalization.js +1 -7
  19. package/dist/repository/taskWorkspaceCoordinator.js +9 -4
  20. package/dist/runtime/agentDriver.js +83 -4
  21. package/dist/runtime/agentDriverObservation.js +25 -10
  22. package/dist/runtime/builtinAgentDrivers.js +168 -18
  23. package/dist/runtime/codexAppServerRuntime.js +355 -0
  24. package/dist/runtime/continuationManager.js +117 -0
  25. package/dist/runtime/index.js +2 -0
  26. package/dist/runtime/lifecycleReservation.js +4 -3
  27. package/dist/runtime/promptEnvelope.js +14 -3
  28. package/dist/runtime/providerContinuation.js +225 -0
  29. package/dist/runtime/providerContinuationReconciliationService.js +172 -0
  30. package/dist/runtime/providerRuntimeIdentity.js +232 -0
  31. package/dist/runtime/providerRuntimeReconciler.js +166 -0
  32. package/dist/runtime/runtimeContinuationProjection.js +34 -0
  33. package/dist/runtime/runtimeObservation.js +217 -6
  34. package/dist/runtime/runtimeProjection.js +172 -11
  35. package/dist/scheduler/activeRoleRunDelivery.js +314 -1
  36. package/dist/scheduler/leaderWakeupProcessor.js +2 -1
  37. package/dist/scheduler/operatorInputNotificationProcessor.js +3 -2
  38. package/dist/scheduler/roleRunLiveness.js +8 -7
  39. package/dist/scheduler/roleRunStall.js +4 -2
  40. package/dist/scheduler/taskExecutionProjection.js +2 -2
  41. package/dist/storage/migration/productionRegistry.js +474 -1
  42. package/dist/storage/sqliteSchema.js +102 -21
  43. package/dist/storage/sqliteStore.js +52 -110
  44. package/dist/storage/storageVersions.js +1 -1
  45. package/dist/storage/storeRpc.js +0 -1
  46. package/dist/storage/taskStore.js +40 -53
  47. package/dist/storage/upgrade/sqliteStateMigration.js +0 -21
  48. package/dist/task/nextAction.js +1 -1
  49. package/dist/web/assets/client/app.js +1 -1
  50. package/dist/web/assets/client/components.js +233 -4
  51. package/dist/web/assets/client/i18n.js +166 -2
  52. package/dist/web/assets/client/view.js +30 -13
  53. package/dist/web/assets/styles/cards.js +62 -0
  54. package/dist/web/assets/styles/widgets.js +1 -0
  55. package/dist/web/webSnapshot.js +11 -2
  56. package/package.json +1 -1
  57. package/skills/yui-leader/SKILL.md +33 -24
  58. package/skills/yui-operator/SKILL.md +7 -5
@@ -16,7 +16,7 @@ import { AsyncTaskStoreClient, resolveStoreWorkerEnabledForHome } from "../stora
16
16
  import { FileTaskWorkspacePreparer } from "../repository/taskWorkspacePreparer.js";
17
17
  import { NodeCommandExecutor } from "../tmux/commandExecutor.js";
18
18
  import { TmuxManager, yuiTmuxServerName } from "../tmux/tmuxManager.js";
19
- import { FileTaskRuntimeIsolation, TmuxPromptPushAdapter, TmuxSessionHost } from "../runtime/index.js";
19
+ import { FileTaskRuntimeIsolation, TmuxPromptPushAdapter, TmuxSessionHost, ProviderContinuationReconciliationService } from "../runtime/index.js";
20
20
  import { startFileTaskController } from "./controller.js";
21
21
  import { FileSchedulerStoreAdapter } from "./fileSchedulerStoreAdapter.js";
22
22
  import { openSchedulerTelemetry } from "../telemetry/telemetryWiring.js";
@@ -224,6 +224,9 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
224
224
  sessionHost,
225
225
  promptPush,
226
226
  launchCoordinator,
227
+ ...(options.providerInputRouting === undefined
228
+ ? {}
229
+ : { providerInputRouting: options.providerInputRouting }),
227
230
  roleResourceInventory: async (panes, inputs) => {
228
231
  const inventory = await scanInventory(panes);
229
232
  return inventory.resources.flatMap((resource) => {
@@ -370,6 +373,9 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
370
373
  onError: options.onError
371
374
  });
372
375
  const jobControl = createDurableJobControl(store);
376
+ const continuationReconciler = options.continuationMetadata === undefined
377
+ ? undefined
378
+ : new ProviderContinuationReconciliationService(store, schedulerStore, options.continuationMetadata);
373
379
  const running = await startFileTaskController(home, schedulerStore, delivery, lifecycleDispatcher, {
374
380
  intervalMs: options.intervalMs
375
381
  ?? reconciliationIntervalMilliseconds(store.getConfig().reconciliationIntervalSeconds),
@@ -382,6 +388,7 @@ export async function startFileTaskControllerRuntime(home, options = {}) {
382
388
  lifecycleHost,
383
389
  jobSupervisor,
384
390
  jobControl,
391
+ ...(continuationReconciler === undefined ? {} : { continuationReconciler }),
385
392
  ...(resourceReaper === undefined ? {} : { resourceReaper }),
386
393
  resourceAutoGc,
387
394
  onExpiredEphemeralDomain: (domain) => {
@@ -1,5 +1,5 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { closeSync, constants, existsSync, fchmodSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { closeSync, constants, existsSync, fchmodSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { withUpgradeCoordinationLock } from "../storage/upgradeCoordination.js";
5
5
  import { createRuntimeObservation } from "../runtime/runtimeObservation.js";
@@ -213,9 +213,18 @@ export class FileRuntimeEventInbox {
213
213
  const invalidDirectory = join(this.home, INVALID_RUNTIME_EVENT_DIRECTORY);
214
214
  ensureInboxDirectory(invalidDirectory);
215
215
  const source = join(this.directory, name);
216
- const target = join(invalidDirectory, `${name}.${randomUUID()}`);
216
+ // One semantic ingress identity owns one quarantine slot. Repeated poison
217
+ // entries replace neither the first diagnostic nor create an event storm.
218
+ const target = join(invalidDirectory, name);
217
219
  try {
218
- renameSync(source, target);
220
+ try {
221
+ linkSync(source, target);
222
+ }
223
+ catch (error) {
224
+ if (!isNodeError(error, "EEXIST"))
225
+ throw error;
226
+ }
227
+ unlinkSync(source);
219
228
  fsyncDirectory(this.directory);
220
229
  fsyncDirectory(invalidDirectory);
221
230
  }
@@ -237,9 +246,11 @@ function runtimeEventId(type, input) {
237
246
  if (type === "runtime-observation") {
238
247
  const observation = input.observation;
239
248
  return `turn-${createHash("sha256").update(JSON.stringify([
240
- 1,
249
+ 2,
241
250
  type,
242
- observation
251
+ observation.fence.taskId ?? null,
252
+ observation.fence.roleName,
253
+ observation.semanticKey
243
254
  ])).digest("hex")}`;
244
255
  }
245
256
  if (type === "durable-job-terminal") {
@@ -49,7 +49,19 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
49
49
  }
50
50
  const inFlight = sessions?.inFlight;
51
51
  const session = sessions?.sessions[agentId];
52
- const acceptedBinding = options.nativeTurnId === undefined
52
+ const roleMailbox = store.getWorkMailbox({ kind: "role", taskId, roleName });
53
+ const roleInputDelivery = roleMailbox?.inputDelivery;
54
+ const roleExecution = roleMailbox?.processing?.executionRef;
55
+ const activationReceiptId = roleInputDelivery?.executionRef?.type === "run"
56
+ && roleInputDelivery.executionRef.taskId === taskId
57
+ && roleInputDelivery.executionRef.id === inFlight?.runId
58
+ ? roleInputDelivery.attemptId
59
+ : roleExecution?.type === "run"
60
+ && roleExecution.taskId === taskId
61
+ && roleExecution.id === inFlight?.runId
62
+ ? roleMailbox.processing.batchId
63
+ : inFlight?.receiptId;
64
+ const acceptedTurn = options.nativeTurnId === undefined
53
65
  ? null
54
66
  : acceptedTurnBinding(store.listEvents(taskId), {
55
67
  taskId,
@@ -58,6 +70,14 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
58
70
  nativeSessionId,
59
71
  nativeTurnId: options.nativeTurnId
60
72
  });
73
+ const acceptedBinding = acceptedTurn ?? (options.continuationId === undefined ? null : knownContinuationBinding(store.listEvents(taskId), {
74
+ taskId,
75
+ roleName,
76
+ agentId,
77
+ nativeSessionId,
78
+ continuationId: options.continuationId,
79
+ continuationGeneration: options.continuationGeneration ?? 1
80
+ }));
61
81
  const mailbox = store.getWorkMailbox(runtimeLifecycleTarget({
62
82
  scope: "task",
63
83
  taskId,
@@ -163,15 +183,15 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
163
183
  if (run.effective.workspace.root !== workspace) {
164
184
  throw new Error("Runtime observation Hook workspace does not match the durable Run snapshot.");
165
185
  }
166
- if (session !== undefined) {
186
+ if (session !== undefined && acceptedBinding === null) {
167
187
  if (session.adapterId !== adapterId
168
- || (acceptedBinding === null && session.launchId !== effectiveLaunchId)
188
+ || session.launchId !== effectiveLaunchId
169
189
  || session.nativeSessionId !== nativeSessionId
170
190
  || session.effective.workspace.root !== workspace) {
171
191
  throw new Error("Runtime observation Hook Session does not match its durable generation.");
172
192
  }
173
193
  }
174
- else {
194
+ else if (session === undefined && acceptedBinding === null) {
175
195
  if (!discoveredStartup && !preallocatedStartup) {
176
196
  throw new Error("Runtime observation Hook launch is not durably reserved.");
177
197
  }
@@ -183,12 +203,38 @@ export function resolveRuntimeHookRunFence(environment, adapterId, payloadNative
183
203
  launchId: effectiveLaunchId,
184
204
  runId,
185
205
  ...(acceptedBinding?.fence.receiptId === undefined
186
- ? inFlight?.receiptId === undefined ? {} : { receiptId: inFlight.receiptId }
206
+ ? activationReceiptId === undefined ? {} : { receiptId: activationReceiptId }
187
207
  : { receiptId: acceptedBinding.fence.receiptId }),
188
208
  nativeSessionId,
189
209
  workspace
190
210
  };
191
211
  }
212
+ function knownContinuationBinding(events, expected) {
213
+ const matches = events
214
+ .map(runtimeObservationFromTaskEvent)
215
+ .filter((observation) => observation !== null
216
+ && observation.kind.startsWith("continuation.")
217
+ && observation.fence.taskId === expected.taskId
218
+ && observation.fence.roleName === expected.roleName
219
+ && observation.fence.agentId === expected.agentId
220
+ && observation.fence.nativeSessionId === expected.nativeSessionId
221
+ && observation.fence.continuationId === expected.continuationId
222
+ && observation.fence.continuationGeneration === expected.continuationGeneration
223
+ && observation.fence.runId !== undefined)
224
+ .sort((left, right) => (left.receivedAt.localeCompare(right.receivedAt)
225
+ || (left.sequence ?? -1) - (right.sequence ?? -1)
226
+ || (left.ordinal ?? -1) - (right.ordinal ?? -1)
227
+ || left.eventId.localeCompare(right.eventId)));
228
+ const binding = matches.at(-1) ?? null;
229
+ if (binding === null)
230
+ return null;
231
+ if (matches.some((candidate) => candidate.fence.runId !== binding.fence.runId
232
+ || candidate.fence.launchId !== binding.fence.launchId
233
+ || candidate.fence.receiptId !== binding.fence.receiptId)) {
234
+ throw new Error("Runtime observation Hook continuation has conflicting durable Run bindings.");
235
+ }
236
+ return binding;
237
+ }
192
238
  function acceptedTurnBinding(events, expected) {
193
239
  const matches = events
194
240
  .map(runtimeObservationFromTaskEvent)
@@ -1,7 +1,7 @@
1
1
  import { callController } from "../core/controllerClient.js";
2
2
  import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
3
3
  import { normalizeAgentDriverHookClassification } from "../runtime/agentDriver.js";
4
- import { mapAgentDriverHook } from "../runtime/agentDriverObservation.js";
4
+ import { mapAgentDriverHooks } from "../runtime/agentDriverObservation.js";
5
5
  import { runtimeLifecycleSignalKey } from "../runtime/lifecycleReservation.js";
6
6
  import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
7
7
  import { FileRuntimeEventInbox, MAX_RUNTIME_EVENT_FILE_BYTES } from "./runtimeEventInbox.js";
@@ -44,6 +44,10 @@ export function parseRuntimeObservationHook(stdinJson, environment, now = new Da
44
44
  ? {}
45
45
  : { startupSession: classification.startupSession }),
46
46
  terminal: classification.terminal,
47
+ ...(classification.continuationId === undefined ? {} : {
48
+ continuationId: classification.continuationId,
49
+ continuationGeneration: classification.continuationGeneration ?? 1
50
+ }),
47
51
  ...(nativeTurnId === undefined ? {} : { nativeTurnId })
48
52
  });
49
53
  const driverInput = {
@@ -63,13 +67,15 @@ export function parseRuntimeObservationHook(stdinJson, environment, now = new Da
63
67
  driverId,
64
68
  launchId: fence.launchId,
65
69
  sessionGenerationId: fence.launchId,
70
+ conversationId: fence.nativeSessionId,
71
+ activationId: fence.launchId,
66
72
  nativeSessionId: fence.nativeSessionId,
67
73
  nativeTurnId: nativeTurnId ?? fence.runId,
68
74
  receiptId: fence.receiptId ?? formatAgentRunReceiptId(fence.taskId, fence.runId)
69
75
  },
70
76
  payload
71
77
  };
72
- const observations = [mapAgentDriverHook({ ...driverInput, ordinal: 0 })];
78
+ const observations = mapAgentDriverHooks({ ...driverInput, ordinal: 0 });
73
79
  return {
74
80
  home: requireIdentity(environment.YUI_HOME, "YUI_HOME"),
75
81
  taskId: fence.taskId,