@zq-silk/yui 0.8.1 → 0.8.3
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.
- package/ARCHITECTURE.md +27 -28
- package/README.md +57 -46
- package/dist/cli/commandCatalog.js +57 -17
- package/dist/cli/interactionPolicy.js +4 -10
- package/dist/cli/invocationRouter.js +2 -1
- package/dist/cli.js +106 -27
- package/dist/commands/taskCommands.js +458 -77
- package/dist/commands/taskCompletionGate.js +152 -0
- package/dist/context/runContextPack.js +19 -4
- package/dist/context/sessionBootstrapManifest.js +1 -1
- package/dist/controller/fileSchedulerStoreAdapter.js +389 -70
- package/dist/controller/resourceInventory.js +9 -5
- package/dist/controller/runtime.js +80 -7
- package/dist/controller/runtimeLaunchCoordinator.js +18 -78
- package/dist/controller/structuredProviderObservation.js +273 -0
- package/dist/executor/agentAdapter.js +40 -0
- package/dist/executor/agentExecutor.js +31 -7
- package/dist/executor/executorRegistry.js +11 -49
- package/dist/executor/fileRoleLaunchPlanner.js +115 -37
- package/dist/lifecycle/canonicalLifecycleEvent.js +5 -2
- package/dist/repository/gitWorkspace.js +7 -4
- package/dist/repository/taskBaseFreshness.js +4 -2
- package/dist/run/agentRun.js +4 -4
- package/dist/runtime/agentHost.js +767 -158
- package/dist/runtime/builtinAgentDrivers.js +1 -5
- package/dist/runtime/codexAppServerRuntime.js +67 -60
- package/dist/runtime/exactControlPlane.js +7 -2
- package/dist/runtime/index.js +6 -2
- package/dist/runtime/launchBroker.js +30 -8
- package/dist/runtime/providerAuthorityFence.js +24 -0
- package/dist/runtime/providerControl.js +63 -0
- package/dist/runtime/providerRecoveryDecision.js +55 -0
- package/dist/runtime/providerRuntimeIdentity.js +269 -19
- package/dist/runtime/runtimeBinding.js +20 -11
- package/dist/runtime/structuredProviderHost.js +476 -0
- package/dist/runtime/tmuxAdapters.js +143 -42
- package/dist/scheduler/activeRoleRunDelivery.js +206 -120
- package/dist/scheduler/leaderWakeupProcessor.js +141 -16
- package/dist/scheduler/wakeReason.js +1 -0
- package/dist/storage/migration/productionRegistry.js +111 -0
- package/dist/storage/sqliteStore.js +2 -0
- package/dist/storage/taskStore.js +3 -1
- package/dist/task/completionReadiness.js +43 -0
- package/dist/task/nextAction.js +6 -4
- package/dist/task/publicationReference.js +1 -0
- package/dist/tmux/tmuxManager.js +1 -1
- package/dist/workItem/workItem.js +12 -0
- package/dist/workspace/workItemChangeSetManager.js +2 -1
- package/i18n/README.zh-CN.md +11 -8
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +8 -3
- package/skills/yui-runtime/SKILL.md +7 -2
|
@@ -25,7 +25,9 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
25
25
|
for (const task of selectedActiveSchedulerTasks(store, selection)) {
|
|
26
26
|
for (const role of selectedSchedulerRoles(store, task.id, selection)) {
|
|
27
27
|
const run = store.getActiveAgentRun(task.id, role.name);
|
|
28
|
-
if (run !== null && run.pushedAt !== undefined
|
|
28
|
+
if (run !== null && run.pushedAt !== undefined
|
|
29
|
+
&& run.providerRetry?.state !== "dispatching"
|
|
30
|
+
&& run.controlRequest?.state !== "dispatching") {
|
|
29
31
|
const continuation = await processActiveRunContinuation(store, delivery, task, role, run, now, inputDeliveryRecoveryCutoff);
|
|
30
32
|
if (continuation !== null)
|
|
31
33
|
results.push(continuation);
|
|
@@ -107,6 +109,7 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
107
109
|
let preparedSession = existingSession;
|
|
108
110
|
let preStartFencePersisted = false;
|
|
109
111
|
let deliveryAttempted = false;
|
|
112
|
+
let providerSubmissionBegun = false;
|
|
110
113
|
try {
|
|
111
114
|
const nativeSessionId = run.mode === "resume"
|
|
112
115
|
? requireResumeSession(role, run.effective, existingSession)
|
|
@@ -130,13 +133,14 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
130
133
|
preStartFencePersisted = true;
|
|
131
134
|
}
|
|
132
135
|
});
|
|
133
|
-
// A managed
|
|
134
|
-
//
|
|
136
|
+
// A managed Host may have submitted the exact Run Turn after its
|
|
137
|
+
// two-phase launch handshake. Once preparation returns that transport
|
|
135
138
|
// fact, any
|
|
136
139
|
// later readiness or aggregate-write failure is delivery uncertainty,
|
|
137
140
|
// not a launch failure: preserve the Run and its reservation for the
|
|
138
141
|
// matching provider Hook instead of terminalizing it.
|
|
139
|
-
deliveryAttempted = prepared.
|
|
142
|
+
deliveryAttempted = prepared.turnAcceptedDuringLaunch === true
|
|
143
|
+
|| prepared.turnDeliveryUnknownDuringLaunch === true;
|
|
140
144
|
// Preparation may already have an exact native Session identity while
|
|
141
145
|
// the provider is still starting. Persist that Session + the Run fence
|
|
142
146
|
// before awaiting readiness so a pre-input provider Hook can validate
|
|
@@ -158,7 +162,8 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
158
162
|
}
|
|
159
163
|
const ready = await delivery.waitUntilReady(prepared);
|
|
160
164
|
deliveryAttempted = deliveryAttempted
|
|
161
|
-
|| ready.prepared.
|
|
165
|
+
|| ready.prepared.turnAcceptedDuringLaunch === true
|
|
166
|
+
|| ready.prepared.turnDeliveryUnknownDuringLaunch === true;
|
|
162
167
|
const session = validateLaunchSubmittedRecoverySession(role, run.effective, existingSession, run.mode, ready.prepared, ready.session);
|
|
163
168
|
preparedSession = session;
|
|
164
169
|
store.saveRoleRunPrepared({
|
|
@@ -171,11 +176,56 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
171
176
|
: { launchId: ready.prepared.launchId }),
|
|
172
177
|
now
|
|
173
178
|
});
|
|
174
|
-
if (ready.prepared.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
if (ready.prepared.turnRejectedDuringLaunch === true) {
|
|
180
|
+
delivery.forgetPrepared?.({
|
|
181
|
+
taskId: task.id,
|
|
182
|
+
roleName: role.name,
|
|
183
|
+
runId: run.id,
|
|
184
|
+
...(ready.prepared.launchId === undefined
|
|
185
|
+
? {}
|
|
186
|
+
: { launchId: ready.prepared.launchId })
|
|
187
|
+
});
|
|
188
|
+
results.push({
|
|
189
|
+
taskId: task.id,
|
|
190
|
+
roleName: role.name,
|
|
191
|
+
runId: run.id,
|
|
192
|
+
status: "skipped",
|
|
193
|
+
reason: "not-ready"
|
|
194
|
+
});
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (ready.prepared.turnDeliveryUnknownDuringLaunch === true) {
|
|
198
|
+
store.saveRoleRunDelivery({
|
|
199
|
+
task,
|
|
200
|
+
role,
|
|
201
|
+
run,
|
|
202
|
+
session,
|
|
203
|
+
...(ready.prepared.launchId === undefined
|
|
204
|
+
? {}
|
|
205
|
+
: { launchId: ready.prepared.launchId }),
|
|
206
|
+
now
|
|
207
|
+
});
|
|
208
|
+
delivery.forgetPrepared?.({
|
|
209
|
+
taskId: task.id,
|
|
210
|
+
roleName: role.name,
|
|
211
|
+
runId: run.id,
|
|
212
|
+
...(ready.prepared.launchId === undefined
|
|
213
|
+
? {}
|
|
214
|
+
: { launchId: ready.prepared.launchId })
|
|
215
|
+
});
|
|
216
|
+
results.push({
|
|
217
|
+
taskId: task.id,
|
|
218
|
+
roleName: role.name,
|
|
219
|
+
runId: run.id,
|
|
220
|
+
status: "skipped",
|
|
221
|
+
reason: "delivery-uncertain"
|
|
222
|
+
});
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (ready.prepared.turnAcceptedDuringLaunch === true) {
|
|
226
|
+
// The newly-created Agent Host already submitted the exact Run Turn
|
|
227
|
+
// through Provider-native control. Persist launch transport success;
|
|
228
|
+
// only the matching structured acknowledgement marks it accepted.
|
|
179
229
|
store.saveRoleRunDelivery({
|
|
180
230
|
task,
|
|
181
231
|
role,
|
|
@@ -232,6 +282,21 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
232
282
|
});
|
|
233
283
|
continue;
|
|
234
284
|
}
|
|
285
|
+
if (session === null || session.launchId === undefined
|
|
286
|
+
|| !hasText(session.nativeSessionId)
|
|
287
|
+
|| store.beginRoleRunProviderTurn?.({
|
|
288
|
+
taskId: task.id,
|
|
289
|
+
roleName: role.name,
|
|
290
|
+
runId: run.id,
|
|
291
|
+
agentId: run.effective.agentId,
|
|
292
|
+
launchId: session.launchId,
|
|
293
|
+
nativeSessionId: session.nativeSessionId,
|
|
294
|
+
attemptId: receiptId,
|
|
295
|
+
now
|
|
296
|
+
}) !== true) {
|
|
297
|
+
throw new Error("Provider Turn intent could not be durably fenced before delivery.");
|
|
298
|
+
}
|
|
299
|
+
providerSubmissionBegun = true;
|
|
235
300
|
deliveryAttempted = true;
|
|
236
301
|
const outcome = await delivery.sendOnce({
|
|
237
302
|
delivery: ready,
|
|
@@ -253,6 +318,18 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
253
318
|
: serializeRunBootstrapEnvelope(run.bootstrapEnvelope)
|
|
254
319
|
});
|
|
255
320
|
if (outcome === "busy" || outcome === "unavailable") {
|
|
321
|
+
store.resolveRoleRunProviderSubmission?.({
|
|
322
|
+
taskId: task.id,
|
|
323
|
+
roleName: role.name,
|
|
324
|
+
runId: run.id,
|
|
325
|
+
attemptId: receiptId,
|
|
326
|
+
status: "rejected",
|
|
327
|
+
reason: outcome === "busy"
|
|
328
|
+
? "Agent Host was busy before Provider mutation."
|
|
329
|
+
: "Agent Host was unavailable before Provider mutation.",
|
|
330
|
+
now
|
|
331
|
+
});
|
|
332
|
+
providerSubmissionBegun = false;
|
|
256
333
|
results.push({
|
|
257
334
|
taskId: task.id,
|
|
258
335
|
roleName: role.name,
|
|
@@ -263,6 +340,56 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
263
340
|
});
|
|
264
341
|
continue;
|
|
265
342
|
}
|
|
343
|
+
if (outcome === "rejected") {
|
|
344
|
+
store.resolveRoleRunProviderSubmission?.({
|
|
345
|
+
taskId: task.id,
|
|
346
|
+
roleName: role.name,
|
|
347
|
+
runId: run.id,
|
|
348
|
+
attemptId: receiptId,
|
|
349
|
+
status: "rejected",
|
|
350
|
+
reason: "Provider returned an exact negative acknowledgement.",
|
|
351
|
+
now
|
|
352
|
+
});
|
|
353
|
+
providerSubmissionBegun = false;
|
|
354
|
+
results.push({
|
|
355
|
+
taskId: task.id,
|
|
356
|
+
roleName: role.name,
|
|
357
|
+
runId: run.id,
|
|
358
|
+
status: "skipped",
|
|
359
|
+
reason: "not-ready"
|
|
360
|
+
});
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (outcome === "delivery-unknown") {
|
|
364
|
+
store.resolveRoleRunProviderSubmission?.({
|
|
365
|
+
taskId: task.id,
|
|
366
|
+
roleName: role.name,
|
|
367
|
+
runId: run.id,
|
|
368
|
+
attemptId: receiptId,
|
|
369
|
+
status: "delivery-unknown",
|
|
370
|
+
reason: "Provider Turn delivery is ambiguous; automatic retry is fenced.",
|
|
371
|
+
now
|
|
372
|
+
});
|
|
373
|
+
providerSubmissionBegun = false;
|
|
374
|
+
store.saveRoleRunDelivery({
|
|
375
|
+
task,
|
|
376
|
+
role,
|
|
377
|
+
run,
|
|
378
|
+
session,
|
|
379
|
+
...(ready.prepared.launchId === undefined
|
|
380
|
+
? {}
|
|
381
|
+
: { launchId: ready.prepared.launchId }),
|
|
382
|
+
now
|
|
383
|
+
});
|
|
384
|
+
results.push({
|
|
385
|
+
taskId: task.id,
|
|
386
|
+
roleName: role.name,
|
|
387
|
+
runId: run.id,
|
|
388
|
+
status: "skipped",
|
|
389
|
+
reason: "delivery-uncertain"
|
|
390
|
+
});
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
266
393
|
const status = outcome === "sent" ? "delivered" : "already-delivered";
|
|
267
394
|
store.saveRoleRunDelivery({
|
|
268
395
|
task,
|
|
@@ -278,6 +405,17 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
278
405
|
}
|
|
279
406
|
catch (error) {
|
|
280
407
|
const message = error instanceof Error ? error.message : String(error);
|
|
408
|
+
if (providerSubmissionBegun) {
|
|
409
|
+
store.resolveRoleRunProviderSubmission?.({
|
|
410
|
+
taskId: task.id,
|
|
411
|
+
roleName: role.name,
|
|
412
|
+
runId: run.id,
|
|
413
|
+
attemptId: receiptId,
|
|
414
|
+
status: "delivery-unknown",
|
|
415
|
+
reason: message,
|
|
416
|
+
now
|
|
417
|
+
});
|
|
418
|
+
}
|
|
281
419
|
// Scheduler single-flight backpressure: the Role runtime lifecycle
|
|
282
420
|
// lane was busy when the launch was reserved. The Run stays
|
|
283
421
|
// active-unpushed and its mailbox claim is retained; the next pass
|
|
@@ -428,6 +566,23 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
428
566
|
reason: "not-ready"
|
|
429
567
|
};
|
|
430
568
|
}
|
|
569
|
+
const writer = store.getProviderAuthorityFence?.({
|
|
570
|
+
taskId: task.id,
|
|
571
|
+
roleName: role.name,
|
|
572
|
+
runId: run.id,
|
|
573
|
+
agentId: run.effective.agentId,
|
|
574
|
+
launchId: session.launchId,
|
|
575
|
+
nativeSessionId: session.nativeSessionId
|
|
576
|
+
}) ?? null;
|
|
577
|
+
if (writer !== null && writer.owner !== "controller") {
|
|
578
|
+
return {
|
|
579
|
+
taskId: task.id,
|
|
580
|
+
roleName: role.name,
|
|
581
|
+
runId: run.id,
|
|
582
|
+
status: "skipped",
|
|
583
|
+
reason: "writer-attached"
|
|
584
|
+
};
|
|
585
|
+
}
|
|
431
586
|
const originalReceipt = formatAgentRunReceiptId(task.id, run.id);
|
|
432
587
|
if (mailbox.processing !== null && (mailbox.processing.executionRef?.type !== "run"
|
|
433
588
|
|| mailbox.processing.executionRef.taskId !== task.id
|
|
@@ -447,7 +602,7 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
447
602
|
|| (existing.status === "dispatching"
|
|
448
603
|
&& inputDeliveryRecoveryCutoff !== undefined
|
|
449
604
|
&& Date.parse(existing.startedAt) < inputDeliveryRecoveryCutoff.getTime()))) {
|
|
450
|
-
return reconcileStrandedInputDelivery(store,
|
|
605
|
+
return reconcileStrandedInputDelivery(store, task, role, run, existing, now);
|
|
451
606
|
}
|
|
452
607
|
return {
|
|
453
608
|
taskId: task.id,
|
|
@@ -484,23 +639,10 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
484
639
|
reason: "runtime-unavailable"
|
|
485
640
|
};
|
|
486
641
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
agentId: run.effective.agentId,
|
|
492
|
-
launchId: session.launchId,
|
|
493
|
-
nativeSessionId: session.nativeSessionId
|
|
494
|
-
}) ?? null;
|
|
495
|
-
const mode = lane === "user-correction"
|
|
496
|
-
? activeTurn !== null && delivery.canRouteProviderInput?.(run.effective.adapterId) === true
|
|
497
|
-
? "steer-if-safe"
|
|
498
|
-
: "followup"
|
|
499
|
-
: pending.deliveryModes.includes("followup") ? "followup" : "inject";
|
|
500
|
-
// Normal facts never enter an active Turn. A user correction may steer only
|
|
501
|
-
// through the exact Turn fence above; without it, retain the high-priority
|
|
502
|
-
// lane until the current Turn ends and deliver it as the next followup.
|
|
503
|
-
if (mode === "followup" && session.status === "running") {
|
|
642
|
+
// Managed input has one write path: a new structured Turn at a settled
|
|
643
|
+
// boundary. Corrections retain their priority while the current Turn runs.
|
|
644
|
+
const mode = "followup";
|
|
645
|
+
if (session.status === "running") {
|
|
504
646
|
return {
|
|
505
647
|
taskId: task.id,
|
|
506
648
|
roleName: role.name,
|
|
@@ -509,14 +651,13 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
509
651
|
reason: "not-ready"
|
|
510
652
|
};
|
|
511
653
|
}
|
|
512
|
-
if (
|
|
513
|
-
|| delivery.canRouteProviderInput?.(run.effective.adapterId) !== true)) {
|
|
654
|
+
if (writer === null) {
|
|
514
655
|
return {
|
|
515
656
|
taskId: task.id,
|
|
516
657
|
roleName: role.name,
|
|
517
658
|
runId: run.id,
|
|
518
659
|
status: "skipped",
|
|
519
|
-
reason: "
|
|
660
|
+
reason: "not-ready"
|
|
520
661
|
};
|
|
521
662
|
}
|
|
522
663
|
let deliveryAttempted = false;
|
|
@@ -539,12 +680,10 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
539
680
|
if (readySession.launchId === undefined || !hasText(readySession.nativeSessionId)) {
|
|
540
681
|
throw new Error("Continuation delivery has no Provider Activation fence.");
|
|
541
682
|
}
|
|
542
|
-
const providerFence =
|
|
543
|
-
|
|
544
|
-
:
|
|
545
|
-
|
|
546
|
-
activationId: readySession.launchId
|
|
547
|
-
};
|
|
683
|
+
const providerFence = {
|
|
684
|
+
conversationId: writer.conversationId,
|
|
685
|
+
activationId: writer.activationId
|
|
686
|
+
};
|
|
548
687
|
const claim = store.claimInputDelivery({
|
|
549
688
|
target,
|
|
550
689
|
attemptId: requestedBatchId,
|
|
@@ -569,44 +708,13 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
569
708
|
inputDelivery = claim.delivery;
|
|
570
709
|
deliveryAttempted = true;
|
|
571
710
|
const text = continuationInput(task, role, run, inputDelivery.attemptId, inputDelivery.batch, boundedContinuationSummaries(store, task.id, inputDelivery.batch.refs));
|
|
572
|
-
if (mode !== "followup") {
|
|
573
|
-
const routed = await delivery.routeProviderInput({
|
|
574
|
-
delivery: ready,
|
|
575
|
-
attemptId: inputDelivery.attemptId,
|
|
576
|
-
mode,
|
|
577
|
-
text,
|
|
578
|
-
fence: providerFence
|
|
579
|
-
});
|
|
580
|
-
if (routed === "accepted") {
|
|
581
|
-
store.completeInputDelivery(target, inputDelivery.attemptId, now);
|
|
582
|
-
return { taskId: task.id, roleName: role.name, runId: run.id, status: "delivered" };
|
|
583
|
-
}
|
|
584
|
-
if (routed === "unknown") {
|
|
585
|
-
store.markInputDeliveryUnknown(target, inputDelivery.attemptId, "Provider input acceptance could not be reconciled.", now);
|
|
586
|
-
return {
|
|
587
|
-
taskId: task.id,
|
|
588
|
-
roleName: role.name,
|
|
589
|
-
runId: run.id,
|
|
590
|
-
status: "skipped",
|
|
591
|
-
reason: "delivery-uncertain"
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
store.releaseInputDelivery(target, inputDelivery.attemptId);
|
|
595
|
-
return {
|
|
596
|
-
taskId: task.id,
|
|
597
|
-
roleName: role.name,
|
|
598
|
-
runId: run.id,
|
|
599
|
-
status: "skipped",
|
|
600
|
-
reason: routed === "unavailable" ? "runtime-unavailable" : "not-ready"
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
711
|
const outcome = await delivery.sendOnce({
|
|
604
712
|
delivery: ready,
|
|
605
713
|
receiptId: inputDelivery.attemptId,
|
|
606
714
|
text
|
|
607
715
|
});
|
|
608
716
|
if (outcome === "busy" || outcome === "unavailable") {
|
|
609
|
-
store.releaseInputDelivery(target, inputDelivery.attemptId);
|
|
717
|
+
store.releaseInputDelivery(target, inputDelivery.attemptId, now);
|
|
610
718
|
return {
|
|
611
719
|
taskId: task.id,
|
|
612
720
|
roleName: role.name,
|
|
@@ -615,10 +723,30 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
615
723
|
reason: outcome === "busy" ? "not-ready" : "runtime-unavailable"
|
|
616
724
|
};
|
|
617
725
|
}
|
|
726
|
+
if (outcome === "rejected") {
|
|
727
|
+
store.resolveInputDeliveryNotAccepted(target, inputDelivery.attemptId, now);
|
|
728
|
+
return {
|
|
729
|
+
taskId: task.id,
|
|
730
|
+
roleName: role.name,
|
|
731
|
+
runId: run.id,
|
|
732
|
+
status: "skipped",
|
|
733
|
+
reason: "not-ready"
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
if (outcome === "delivery-unknown") {
|
|
737
|
+
store.markInputDeliveryUnknown(target, inputDelivery.attemptId, "Provider Turn delivery is ambiguous; automatic retry is fenced.", now);
|
|
738
|
+
return {
|
|
739
|
+
taskId: task.id,
|
|
740
|
+
roleName: role.name,
|
|
741
|
+
runId: run.id,
|
|
742
|
+
status: "skipped",
|
|
743
|
+
reason: "delivery-uncertain"
|
|
744
|
+
};
|
|
745
|
+
}
|
|
618
746
|
store.markInputDeliveryPushed(target, inputDelivery.attemptId, now);
|
|
619
747
|
// Keep the exact claim until the matching provider turn.accepted Hook
|
|
620
|
-
// folds it.
|
|
621
|
-
//
|
|
748
|
+
// folds it. An interrupted acknowledgement becomes delivery-unknown and
|
|
749
|
+
// cannot be resubmitted automatically.
|
|
622
750
|
return {
|
|
623
751
|
taskId: task.id,
|
|
624
752
|
roleName: role.name,
|
|
@@ -632,7 +760,7 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
632
760
|
// called. Session preparation may be retried safely.
|
|
633
761
|
}
|
|
634
762
|
else if (!deliveryAttempted)
|
|
635
|
-
store.releaseInputDelivery(target, inputDelivery.attemptId);
|
|
763
|
+
store.releaseInputDelivery(target, inputDelivery.attemptId, now);
|
|
636
764
|
else
|
|
637
765
|
store.markInputDeliveryUnknown(target, inputDelivery.attemptId, error instanceof Error ? error.message : String(error), now);
|
|
638
766
|
return {
|
|
@@ -645,7 +773,7 @@ async function processActiveRunContinuation(store, delivery, task, role, run, no
|
|
|
645
773
|
};
|
|
646
774
|
}
|
|
647
775
|
}
|
|
648
|
-
async function reconcileStrandedInputDelivery(store,
|
|
776
|
+
async function reconcileStrandedInputDelivery(store, task, role, run, input, now) {
|
|
649
777
|
const target = { kind: "role", taskId: task.id, roleName: role.name };
|
|
650
778
|
const uncertain = (reason) => {
|
|
651
779
|
store.markInputDeliveryUnknown(target, input.attemptId, reason, now);
|
|
@@ -657,51 +785,7 @@ async function reconcileStrandedInputDelivery(store, delivery, task, role, run,
|
|
|
657
785
|
reason: "delivery-uncertain"
|
|
658
786
|
};
|
|
659
787
|
};
|
|
660
|
-
|
|
661
|
-
|| delivery.reconcileProviderInput === undefined
|
|
662
|
-
|| delivery.canRouteProviderInput?.(run.effective.adapterId) !== true) {
|
|
663
|
-
return uncertain("Controller restarted without exact Provider input readback.");
|
|
664
|
-
}
|
|
665
|
-
try {
|
|
666
|
-
// Exact readback is addressed entirely from the durable fence. It must not
|
|
667
|
-
// resume a Session, create an Activation, or call any model-starting port.
|
|
668
|
-
const reconciled = await delivery.reconcileProviderInput({
|
|
669
|
-
taskId: task.id,
|
|
670
|
-
roleName: role.name,
|
|
671
|
-
agentId: run.effective.agentId,
|
|
672
|
-
adapterId: run.effective.adapterId,
|
|
673
|
-
launchId: session.launchId,
|
|
674
|
-
nativeSessionId: session.nativeSessionId,
|
|
675
|
-
attemptId: input.attemptId,
|
|
676
|
-
mode: input.mode,
|
|
677
|
-
fence: input.providerFence
|
|
678
|
-
});
|
|
679
|
-
if (reconciled === "accepted") {
|
|
680
|
-
store.completeInputDelivery(target, input.attemptId, now);
|
|
681
|
-
return {
|
|
682
|
-
taskId: task.id,
|
|
683
|
-
roleName: role.name,
|
|
684
|
-
runId: run.id,
|
|
685
|
-
status: "already-delivered"
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
if (reconciled === "not-accepted") {
|
|
689
|
-
store.resolveInputDeliveryNotAccepted(target, input.attemptId);
|
|
690
|
-
return {
|
|
691
|
-
taskId: task.id,
|
|
692
|
-
roleName: role.name,
|
|
693
|
-
runId: run.id,
|
|
694
|
-
status: "skipped",
|
|
695
|
-
reason: "not-ready"
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
return uncertain(reconciled === "unavailable"
|
|
699
|
-
? "Provider input readback is unavailable after Controller restart."
|
|
700
|
-
: "Provider input acceptance remains unknown after metadata readback.");
|
|
701
|
-
}
|
|
702
|
-
catch (error) {
|
|
703
|
-
return uncertain(`Provider input readback failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
704
|
-
}
|
|
788
|
+
return uncertain("Controller restarted with unsettled Provider delivery; automatic resubmission is fenced.");
|
|
705
789
|
}
|
|
706
790
|
function continuationInput(task, role, run, attemptId, batch, resultSummaries) {
|
|
707
791
|
const references = batch.refs.map((ref) => ("taskId" in ref
|
|
@@ -834,13 +918,15 @@ function preflightSession(role, effective, existing, mode, preflight) {
|
|
|
834
918
|
}
|
|
835
919
|
/**
|
|
836
920
|
* A Controller restart can recover an exact launch-submitted Run while its
|
|
837
|
-
*
|
|
921
|
+
* persistent Provider process is still alive. The Host intentionally does not
|
|
838
922
|
* re-plan or re-submit that Run and therefore may return no native identity;
|
|
839
923
|
* retain only the durable Session fenced to the same launch generation.
|
|
840
924
|
*/
|
|
841
925
|
function validateLaunchSubmittedRecoverySession(role, effective, existing, mode, prepared, session) {
|
|
842
926
|
if (session === null
|
|
843
|
-
&& prepared.
|
|
927
|
+
&& (prepared.turnAcceptedDuringLaunch === true
|
|
928
|
+
|| prepared.turnDeliveryUnknownDuringLaunch === true
|
|
929
|
+
|| prepared.turnRejectedDuringLaunch === true)
|
|
844
930
|
&& prepared.sessionStarted === false
|
|
845
931
|
&& existing?.launchId !== undefined
|
|
846
932
|
&& existing.launchId === prepared.launchId) {
|