@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.
- package/ARCHITECTURE.md +40 -4
- package/README.md +23 -4
- package/dist/cli/commandCatalog.js +21 -2
- package/dist/cli/updatePorts.js +4 -4
- package/dist/cli.js +43 -14
- package/dist/commands/agentCommands.js +1 -1
- package/dist/commands/configCommands.js +1 -86
- package/dist/commands/executionAuditCommands.js +17 -16
- package/dist/commands/globalRoleCommands.js +4 -4
- package/dist/commands/sessionCommands.js +2 -6
- package/dist/commands/taskActor.js +1 -2
- package/dist/commands/taskCommands.js +93 -21
- package/dist/commands/taskContextCommand.js +1 -1
- package/dist/commands/taskExecutionCommands.js +0 -5
- package/dist/commands/taskOverviewCommand.js +5 -1
- package/dist/commands/taskRoleRuntimeStatus.js +3 -16
- package/dist/config/configCatalog.js +1 -6
- package/dist/config/yuiConfig.js +0 -79
- package/dist/context/sessionBootstrapManifest.js +26 -23
- package/dist/controller/clientRuntime.js +40 -3
- package/dist/controller/controller.js +29 -54
- package/dist/controller/fileSchedulerStoreAdapter.js +372 -1117
- package/dist/controller/runtime.js +12 -5
- package/dist/controller/runtimeHookRunFence.js +3 -9
- package/dist/controller/runtimeLaunchCoordinator.js +44 -67
- package/dist/controller/structuredProviderObservation.js +18 -5
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/execution/executionHealth.js +1 -1
- package/dist/executor/agentExecutor.js +103 -93
- package/dist/executor/executorRegistry.js +8 -20
- package/dist/executor/fileRoleLaunchPlanner.js +26 -93
- package/dist/executor/turnCompletion.js +5 -5
- package/dist/lifecycle/exactRunTerminalization.js +2 -4
- package/dist/observability/executionAudit.js +40 -94
- package/dist/operator/operatorSessionHistory.js +7 -5
- package/dist/output/rolePresentation.js +0 -1
- package/dist/repository/taskWorkspacePreparer.js +0 -1
- package/dist/role/role.js +13 -21
- package/dist/run/agentRun.js +4 -54
- package/dist/runtime/agentDriver.js +2 -0
- package/dist/runtime/agentError.js +114 -0
- package/dist/runtime/agentHost.js +55 -82
- package/dist/runtime/builtinAgentDrivers.js +21 -9
- package/dist/runtime/builtinAgentErrorMappers.js +150 -0
- package/dist/runtime/exactControlPlane.js +6 -12
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/launchBroker.js +5 -19
- package/dist/runtime/lifecycleReservation.js +20 -4
- package/dist/runtime/providerRuntimeIdentity.js +11 -19
- package/dist/runtime/runtimeBinding.js +0 -27
- package/dist/runtime/runtimeObservation.js +7 -16
- package/dist/runtime/runtimeSessionCandidate.js +3 -10
- package/dist/runtime/sessionLaunchRequest.js +1 -2
- package/dist/runtime/sessionReconciliation.js +2 -2
- package/dist/runtime/structuredProviderHost.js +44 -79
- package/dist/runtime/taskRuntimeIsolation.js +0 -7
- package/dist/runtime/tmuxAdapters.js +6 -49
- package/dist/scheduler/activeRoleRunDelivery.js +220 -178
- package/dist/scheduler/activeTaskProgress.js +1 -4
- package/dist/scheduler/leaderWakeupProcessor.js +123 -88
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +10 -14
- package/dist/scheduler/wakeReason.js +4 -0
- package/dist/storage/migration/productionRegistry.js +475 -0
- package/dist/storage/sqliteSchema.js +54 -2
- package/dist/storage/sqliteStore.js +11 -44
- package/dist/storage/taskStore.js +8 -36
- package/dist/web/webSnapshot.js +3 -0
- package/i18n/README.zh-CN.md +11 -3
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +30 -8
- package/skills/yui-operator/SKILL.md +14 -6
- package/skills/yui-runtime/SKILL.md +11 -8
- package/dist/lifecycle/providerErrorClass.js +0 -152
- package/dist/run/providerRetry.js +0 -226
- package/dist/run/providerRetryConfig.js +0 -27
- package/dist/runtime/providerErrorCodes.js +0 -278
- package/dist/runtime/providerRecoveryDecision.js +0 -55
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createAgentRun } from "../run/agentRun.js";
|
|
2
|
-
import { createRunAssignment } from "../context/runContextContract.js";
|
|
2
|
+
import { createRunAssignment, serializeRunBootstrapEnvelope } from "../context/runContextContract.js";
|
|
3
3
|
import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
|
|
4
4
|
import { effectiveLaunchSnapshotsCompatible, effectiveLaunchSnapshotsCompatibleForTaskSession } from "../executor/effectiveLaunch.js";
|
|
5
5
|
import { roleAgentSessionResumeMode } from "../executor/agentExecutor.js";
|
|
6
6
|
import { RuntimeLifecycleBusyError } from "../runtime/lifecycleReservation.js";
|
|
7
|
-
import { recordLeaderFailure } from "./leaderFailure.js";
|
|
8
7
|
import { isSchedulerTaskWorkspaceReady } from "./ports.js";
|
|
9
8
|
import { RuntimeLaunchError } from "../runtime/ports.js";
|
|
9
|
+
import { serializeAgentErrorRaw } from "../runtime/agentError.js";
|
|
10
10
|
export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
11
11
|
const results = [];
|
|
12
12
|
const wakeups = selection === undefined || selection.full
|
|
@@ -42,8 +42,10 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
42
42
|
results.push({ taskId: task.id, status: "skipped", reason: "busy" });
|
|
43
43
|
continue;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// A durable wake is already the complete next intent. Do not materialize
|
|
46
|
+
// another Run while the Provider still owns the previous Turn: doing so
|
|
47
|
+
// would make its late terminal compete with a newer Run generation.
|
|
48
|
+
if (providerTurnIsUnsettled(store, task.id, role.name)) {
|
|
47
49
|
results.push({ taskId: task.id, status: "skipped", reason: "busy" });
|
|
48
50
|
continue;
|
|
49
51
|
}
|
|
@@ -55,6 +57,7 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
55
57
|
let run = null;
|
|
56
58
|
let prepared;
|
|
57
59
|
let preStartFencePersisted = false;
|
|
60
|
+
let mode = "new";
|
|
58
61
|
try {
|
|
59
62
|
const compatibleSession = existingSession !== null
|
|
60
63
|
&& (reopening
|
|
@@ -65,16 +68,15 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
65
68
|
&& !compatibleSession;
|
|
66
69
|
if (hasNativeSession(existingSession) && !compatibleSession
|
|
67
70
|
&& !reopenIdentityDrift
|
|
68
|
-
&& existingSession.status
|
|
71
|
+
&& existingSession.status === "active") {
|
|
69
72
|
throw new Error(`Leader Session is incompatible with desired effective launch: ${task.id}/${role.name}.`);
|
|
70
73
|
}
|
|
71
74
|
const resumableSession = hasNativeSession(existingSession)
|
|
72
|
-
&& existingSession.status
|
|
73
|
-
&& existingSession.status !== "broken";
|
|
75
|
+
&& existingSession.status === "active";
|
|
74
76
|
// Reuse a healthy Session. A terminal Session is disposable and the next
|
|
75
77
|
// Run starts fresh without consulting historical recovery records.
|
|
76
78
|
const sessionSet = store.getTaskRoleSessionSet?.(task.id, role.name) ?? null;
|
|
77
|
-
|
|
79
|
+
mode = reopenIdentityDrift
|
|
78
80
|
? "new"
|
|
79
81
|
: sessionSet === null
|
|
80
82
|
? resumableSession && compatibleSession ? "resume" : "new"
|
|
@@ -135,25 +137,17 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
135
137
|
mode,
|
|
136
138
|
runId: run.id,
|
|
137
139
|
...(mode === "resume" ? { nativeSessionId: existingSession.nativeSessionId } : {}),
|
|
140
|
+
...(mode !== "resume" || existingSession?.launchId === undefined
|
|
141
|
+
? {}
|
|
142
|
+
: { hostActivationId: existingSession.launchId }),
|
|
138
143
|
beforeHostStart: (preflight) => {
|
|
139
144
|
persistPreStartFence(store, task, role, run, existingSession, mode, preflight, now);
|
|
140
145
|
effectiveSession = preflightSession(role, run.effective, existingSession, mode, preflight);
|
|
141
146
|
preStartFencePersisted = true;
|
|
142
147
|
}
|
|
143
148
|
});
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
// fact, any
|
|
147
|
-
// later readiness or aggregate-write failure is delivery uncertainty,
|
|
148
|
-
// not a launch failure: preserve the Run and its reservation for the
|
|
149
|
-
// matching provider Hook instead of terminalizing it.
|
|
150
|
-
deliveryAttempted = prepared.turnAcceptedDuringLaunch === true
|
|
151
|
-
|| prepared.turnDeliveryUnknownDuringLaunch === true;
|
|
152
|
-
// Persist the exact preparation fence before waiting on provider
|
|
153
|
-
// readiness. A pre-input lifecycle Hook may fire during that wait; it
|
|
154
|
-
// must be able to resolve this Run/Session/launch generation from durable
|
|
155
|
-
// state rather than an in-memory delivery object. Fresh providers that
|
|
156
|
-
// discover their native Session later intentionally persist `null`.
|
|
149
|
+
// Persist the Session identity before submitting the Leader Turn.
|
|
150
|
+
// Starting/restoring a Session is independent from sending Run input.
|
|
157
151
|
if (!preStartFencePersisted) {
|
|
158
152
|
const preparedFenceSession = prepared.session === undefined
|
|
159
153
|
? existingSession
|
|
@@ -169,9 +163,6 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
169
163
|
});
|
|
170
164
|
}
|
|
171
165
|
const ready = await delivery.waitUntilReady(prepared);
|
|
172
|
-
deliveryAttempted = deliveryAttempted
|
|
173
|
-
|| ready.prepared.turnAcceptedDuringLaunch === true
|
|
174
|
-
|| ready.prepared.turnDeliveryUnknownDuringLaunch === true;
|
|
175
166
|
const latestTask = store.getTask(task.id);
|
|
176
167
|
if (latestTask === null
|
|
177
168
|
|| latestTask.status !== "active"
|
|
@@ -198,10 +189,13 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
198
189
|
: { launchId: ready.prepared.launchId }),
|
|
199
190
|
now
|
|
200
191
|
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
deliveryAttempted = true;
|
|
193
|
+
const outcome = await delivery.sendOnce({
|
|
194
|
+
delivery: ready,
|
|
195
|
+
receiptId: formatAgentRunReceiptId(task.id, run.id),
|
|
196
|
+
text: serializeRunBootstrapEnvelope(run.bootstrapEnvelope)
|
|
197
|
+
});
|
|
198
|
+
if (outcome === "busy" || outcome === "unavailable") {
|
|
205
199
|
delivery.forgetPrepared?.({
|
|
206
200
|
taskId: task.id,
|
|
207
201
|
roleName: role.name,
|
|
@@ -214,12 +208,12 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
214
208
|
taskId: task.id,
|
|
215
209
|
runId: run.id,
|
|
216
210
|
status: "skipped",
|
|
217
|
-
reason: "busy"
|
|
211
|
+
reason: outcome === "busy" ? "busy" : "not-ready"
|
|
218
212
|
});
|
|
219
213
|
continue;
|
|
220
214
|
}
|
|
221
|
-
if (
|
|
222
|
-
const
|
|
215
|
+
if (outcome === "rejected") {
|
|
216
|
+
const terminal = store.saveRoleRunDeliveryFailure({
|
|
223
217
|
taskId: task.id,
|
|
224
218
|
roleName: role.name,
|
|
225
219
|
agentId: run.effective.agentId,
|
|
@@ -232,43 +226,10 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
232
226
|
...(ready.prepared.launchId === undefined
|
|
233
227
|
? {}
|
|
234
228
|
: { launchId: ready.prepared.launchId }),
|
|
235
|
-
summary:
|
|
229
|
+
summary: "Provider rejected the Leader Turn before acceptance; Operator recovery is required.",
|
|
236
230
|
cleanupRequired: false,
|
|
237
231
|
now
|
|
238
232
|
});
|
|
239
|
-
if (persisted === "failed") {
|
|
240
|
-
delivery.forgetPrepared?.({
|
|
241
|
-
taskId: task.id,
|
|
242
|
-
roleName: role.name,
|
|
243
|
-
runId: run.id,
|
|
244
|
-
...(ready.prepared.launchId === undefined
|
|
245
|
-
? {}
|
|
246
|
-
: { launchId: ready.prepared.launchId })
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
results.push({
|
|
250
|
-
taskId: task.id,
|
|
251
|
-
runId: run.id,
|
|
252
|
-
status: persisted === "failed" ? "failed" : "skipped",
|
|
253
|
-
reason: "provider-rejected",
|
|
254
|
-
terminalized: persisted === "failed",
|
|
255
|
-
...(persisted === "failed"
|
|
256
|
-
? {}
|
|
257
|
-
: { error: "Run state changed while recording exact Provider rejection." })
|
|
258
|
-
});
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
if (ready.prepared.turnDeliveryUnknownDuringLaunch === true) {
|
|
262
|
-
store.saveRoleRunDelivery({
|
|
263
|
-
task,
|
|
264
|
-
role,
|
|
265
|
-
run,
|
|
266
|
-
session: effectiveSession,
|
|
267
|
-
...(ready.prepared.launchId === undefined
|
|
268
|
-
? {}
|
|
269
|
-
: { launchId: ready.prepared.launchId }),
|
|
270
|
-
now
|
|
271
|
-
});
|
|
272
233
|
delivery.forgetPrepared?.({
|
|
273
234
|
taskId: task.id,
|
|
274
235
|
roleName: role.name,
|
|
@@ -280,15 +241,13 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
280
241
|
results.push({
|
|
281
242
|
taskId: task.id,
|
|
282
243
|
runId: run.id,
|
|
283
|
-
status: "skipped",
|
|
284
|
-
reason: "
|
|
244
|
+
status: terminal === "failed" ? "failed" : "skipped",
|
|
245
|
+
reason: "provider-rejected",
|
|
246
|
+
...(terminal === "failed" ? { terminalized: true } : {})
|
|
285
247
|
});
|
|
286
248
|
continue;
|
|
287
249
|
}
|
|
288
|
-
if (
|
|
289
|
-
// The Agent Host submitted the exact first Turn through structured
|
|
290
|
-
// Provider control. Persist the transport fence without a second write;
|
|
291
|
-
// the matching structured acknowledgement owns Run acceptance.
|
|
250
|
+
if (outcome === "delivery-unknown") {
|
|
292
251
|
store.saveRoleRunDelivery({
|
|
293
252
|
task,
|
|
294
253
|
role,
|
|
@@ -307,10 +266,34 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
307
266
|
? {}
|
|
308
267
|
: { launchId: ready.prepared.launchId })
|
|
309
268
|
});
|
|
310
|
-
results.push({
|
|
269
|
+
results.push({
|
|
270
|
+
taskId: task.id,
|
|
271
|
+
runId: run.id,
|
|
272
|
+
status: "skipped",
|
|
273
|
+
reason: "delivery-uncertain"
|
|
274
|
+
});
|
|
311
275
|
continue;
|
|
312
276
|
}
|
|
313
|
-
|
|
277
|
+
store.saveRoleRunDelivery({
|
|
278
|
+
task,
|
|
279
|
+
role,
|
|
280
|
+
run,
|
|
281
|
+
session: effectiveSession,
|
|
282
|
+
...(ready.prepared.launchId === undefined
|
|
283
|
+
? {}
|
|
284
|
+
: { launchId: ready.prepared.launchId }),
|
|
285
|
+
now
|
|
286
|
+
});
|
|
287
|
+
delivery.forgetPrepared?.({
|
|
288
|
+
taskId: task.id,
|
|
289
|
+
roleName: role.name,
|
|
290
|
+
runId: run.id,
|
|
291
|
+
...(ready.prepared.launchId === undefined
|
|
292
|
+
? {}
|
|
293
|
+
: { launchId: ready.prepared.launchId })
|
|
294
|
+
});
|
|
295
|
+
results.push({ taskId: task.id, runId: run.id, status: "dispatched" });
|
|
296
|
+
continue;
|
|
314
297
|
}
|
|
315
298
|
catch (error) {
|
|
316
299
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -336,6 +319,57 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
336
319
|
});
|
|
337
320
|
continue;
|
|
338
321
|
}
|
|
322
|
+
store.recordAgentError?.({
|
|
323
|
+
taskId: task.id,
|
|
324
|
+
roleName: role.name,
|
|
325
|
+
runId: run.id,
|
|
326
|
+
source: error instanceof RuntimeLaunchError ? "host" : "yui",
|
|
327
|
+
phase: deliveryAttempted
|
|
328
|
+
? "turn-submit"
|
|
329
|
+
: mode === "new" ? "session-start" : "session-restore",
|
|
330
|
+
message: detail,
|
|
331
|
+
raw: serializeAgentErrorRaw(error),
|
|
332
|
+
inputDisposition: deliveryAttempted ? "unknown" : "not-accepted"
|
|
333
|
+
}, now);
|
|
334
|
+
if (!deliveryAttempted) {
|
|
335
|
+
const failedSession = store.getRoleSession(task.id, role.name, run.effective.agentId);
|
|
336
|
+
const terminal = store.saveRoleRunDeliveryFailure({
|
|
337
|
+
taskId: task.id,
|
|
338
|
+
roleName: role.name,
|
|
339
|
+
agentId: run.effective.agentId,
|
|
340
|
+
adapterId: run.effective.adapterId,
|
|
341
|
+
runId: run.id,
|
|
342
|
+
mailboxBatchId: formatAgentRunReceiptId(task.id, run.id),
|
|
343
|
+
...(failedSession?.nativeSessionId === undefined
|
|
344
|
+
? {}
|
|
345
|
+
: { nativeSessionId: failedSession.nativeSessionId }),
|
|
346
|
+
...(prepared?.launchId === undefined && failedSession?.launchId === undefined
|
|
347
|
+
? {}
|
|
348
|
+
: { launchId: prepared?.launchId ?? failedSession.launchId }),
|
|
349
|
+
summary: `Leader Session preparation failed before Turn acceptance: ${message}`,
|
|
350
|
+
cleanupRequired: false,
|
|
351
|
+
now
|
|
352
|
+
});
|
|
353
|
+
if (terminal === "failed") {
|
|
354
|
+
delivery.forgetPrepared?.({
|
|
355
|
+
taskId: task.id,
|
|
356
|
+
roleName: role.name,
|
|
357
|
+
runId: run.id,
|
|
358
|
+
...(prepared?.launchId === undefined
|
|
359
|
+
? {}
|
|
360
|
+
: { launchId: prepared.launchId })
|
|
361
|
+
});
|
|
362
|
+
results.push({
|
|
363
|
+
taskId: task.id,
|
|
364
|
+
runId: run.id,
|
|
365
|
+
status: "failed",
|
|
366
|
+
reason: "unavailable",
|
|
367
|
+
error: message,
|
|
368
|
+
terminalized: true
|
|
369
|
+
});
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
339
373
|
// A managed Provider lifecycle operation may still be settling. Keep
|
|
340
374
|
// this newly-claimed Run as the sole mailbox owner; active-Run delivery
|
|
341
375
|
// retries after the lifecycle lane clears.
|
|
@@ -372,20 +406,13 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
372
406
|
? {}
|
|
373
407
|
: { launchId: prepared.launchId })
|
|
374
408
|
});
|
|
375
|
-
|
|
376
|
-
task,
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
now
|
|
409
|
+
results.push({
|
|
410
|
+
taskId: task.id,
|
|
411
|
+
runId: run.id,
|
|
412
|
+
status: "skipped",
|
|
413
|
+
reason: "not-ready",
|
|
414
|
+
error: message
|
|
382
415
|
});
|
|
383
|
-
if (failureResult === "state-changed") {
|
|
384
|
-
results.push({ taskId: task.id, status: "skipped", reason: "state-changed" });
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
results.push({ taskId: task.id, runId: run.id, status: "failed", error: message });
|
|
388
|
-
}
|
|
389
416
|
continue;
|
|
390
417
|
}
|
|
391
418
|
results.push({
|
|
@@ -399,6 +426,14 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
399
426
|
}
|
|
400
427
|
return results;
|
|
401
428
|
}
|
|
429
|
+
function providerTurnIsUnsettled(store, taskId, roleName) {
|
|
430
|
+
if (store.getRoleSession(taskId, roleName)?.status !== "active")
|
|
431
|
+
return false;
|
|
432
|
+
const status = store.getTaskRoleSessionSet?.(taskId, roleName)
|
|
433
|
+
?.providerBinding?.turn?.status;
|
|
434
|
+
return status !== undefined
|
|
435
|
+
&& ["submitting", "accepted", "running", "delivery-unknown"].includes(status);
|
|
436
|
+
}
|
|
402
437
|
function validateReadySession(role, effective, existing, mode, session) {
|
|
403
438
|
if (mode === "new" && session === null)
|
|
404
439
|
return null;
|
|
@@ -421,7 +456,7 @@ function validateReadySession(role, effective, existing, mode, session) {
|
|
|
421
456
|
}
|
|
422
457
|
return {
|
|
423
458
|
...session,
|
|
424
|
-
status: "
|
|
459
|
+
status: "active",
|
|
425
460
|
...(mode === "resume" && existing !== null
|
|
426
461
|
? { effective: existing.effective }
|
|
427
462
|
: {})
|
|
@@ -454,7 +489,7 @@ function preflightSession(role, effective, existing, mode, preflight) {
|
|
|
454
489
|
nativeSessionId: preflight.nativeSessionId,
|
|
455
490
|
launchId: preflight.launchId,
|
|
456
491
|
...(preflight.sessionTitle === undefined ? {} : { title: preflight.sessionTitle }),
|
|
457
|
-
status: "
|
|
492
|
+
status: "active",
|
|
458
493
|
effective: preflight.effective
|
|
459
494
|
};
|
|
460
495
|
return validateReadySession(role, effective, existing, mode, session);
|
|
@@ -125,7 +125,10 @@ export async function reconcileExitedRoleRuns(store, delivery, now, selection, e
|
|
|
125
125
|
...(run.workspace === undefined ? {} : { managedWorkspace: run.workspace }),
|
|
126
126
|
mode: "resume",
|
|
127
127
|
runId: run.id,
|
|
128
|
-
nativeSessionId: session.nativeSessionId
|
|
128
|
+
nativeSessionId: session.nativeSessionId,
|
|
129
|
+
...(session.launchId === undefined
|
|
130
|
+
? {}
|
|
131
|
+
: { hostActivationId: session.launchId })
|
|
129
132
|
});
|
|
130
133
|
store.saveRoleRunPrepared({
|
|
131
134
|
task,
|
|
@@ -56,16 +56,12 @@ export function projectRoleRunHealth(input) {
|
|
|
56
56
|
const session = input.nativeSession;
|
|
57
57
|
const nativeSession = session === null || session === undefined
|
|
58
58
|
? "missing"
|
|
59
|
-
: session.status === "
|
|
60
|
-
? "stopped"
|
|
61
|
-
: session.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
: !hasResourceIdentityText(session.nativeSessionId)
|
|
66
|
-
&& !hasResourceIdentityText(session.launchId)
|
|
67
|
-
? "unknown"
|
|
68
|
-
: "matching";
|
|
59
|
+
: session.status === "ended"
|
|
60
|
+
? session.endReason === "failed" ? "broken" : "stopped"
|
|
61
|
+
: !hasResourceIdentityText(session.nativeSessionId)
|
|
62
|
+
&& !hasResourceIdentityText(session.launchId)
|
|
63
|
+
? "unknown"
|
|
64
|
+
: "matching";
|
|
69
65
|
const resourceActivity = hostLiveness === "present"
|
|
70
66
|
&& nativeSession === "matching"
|
|
71
67
|
&& resourceEvidenceIsFresh(input.resource, input.now, windowMs, diagnosticAfterMs)
|
|
@@ -689,7 +685,7 @@ export async function reconcileStalledRoleRuns(store, delivery, now, selection,
|
|
|
689
685
|
|| (candidate.session.agentId === runAgentId
|
|
690
686
|
&& candidate.session.adapterId === runAdapterId);
|
|
691
687
|
const sessionUsable = candidate.session === null
|
|
692
|
-
||
|
|
688
|
+
|| candidate.session.status === "active";
|
|
693
689
|
const expectedResourceIdentity = candidate.session === null
|
|
694
690
|
? undefined
|
|
695
691
|
: {
|
|
@@ -786,7 +782,7 @@ export async function reconcileStalledRoleRuns(store, delivery, now, selection,
|
|
|
786
782
|
continue;
|
|
787
783
|
const evidenceKey = [
|
|
788
784
|
kind,
|
|
789
|
-
stallEvidenceKey(candidate.
|
|
785
|
+
stallEvidenceKey(candidate.session?.status),
|
|
790
786
|
classification,
|
|
791
787
|
...(candidate.role.name === "leader"
|
|
792
788
|
? [leaderStallEvidence(store, candidate.task.id, observed, now, windowMs)]
|
|
@@ -1001,8 +997,8 @@ function leaderStallEvidence(store, taskId, observed, now, windowMs) {
|
|
|
1001
997
|
: "recent";
|
|
1002
998
|
return `downstream=active:${active},healthy:${healthy},stalled:${stalled}:leader-mailbox=${pendingAge},leader-processing=${processingAge}`;
|
|
1003
999
|
}
|
|
1004
|
-
function stallEvidenceKey(
|
|
1005
|
-
return `live-pane-no-progress:
|
|
1000
|
+
function stallEvidenceKey(sessionStatus) {
|
|
1001
|
+
return `live-pane-no-progress:session=${sessionStatus ?? "unknown"}`;
|
|
1006
1002
|
}
|
|
1007
1003
|
function exactLiveStatuses(statuses, candidates) {
|
|
1008
1004
|
const expected = new Set(candidates.map(({ task, role }) => `${task.id}\0${role.name}`));
|
|
@@ -17,8 +17,12 @@ export const WAKE_REASON_KINDS = Object.freeze([
|
|
|
17
17
|
"task-orphaned",
|
|
18
18
|
"input-timeout",
|
|
19
19
|
"role-run-stalled",
|
|
20
|
+
"agent-error",
|
|
21
|
+
"agent-session-recovery",
|
|
20
22
|
"review-failed",
|
|
21
23
|
"task-reopened",
|
|
24
|
+
"agent-error",
|
|
25
|
+
"agent-session-recovery",
|
|
22
26
|
"leader-run-failed",
|
|
23
27
|
"role-run-failed",
|
|
24
28
|
"job-finished",
|