@zq-silk/yui 0.14.1 → 0.14.2
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 +64 -35
- package/README.md +254 -124
- package/dist/agent/managedRuntimeEnvironment.js +5 -8
- package/dist/cli/commandCatalog.js +74 -109
- package/dist/cli/helpRenderer.js +1 -2
- package/dist/cli/interactionCandidates.js +10 -0
- package/dist/cli/interactionPolicy.js +76 -37
- package/dist/cli/roleWizard.js +5 -6
- package/dist/cli/updateOrchestrator.js +10 -8
- package/dist/cli/updatePorts.js +17 -13
- package/dist/cli/upgradeCommand.js +2 -5
- package/dist/cli.js +268 -231
- package/dist/commands/agentCommands.js +13 -0
- package/dist/commands/configCommands.js +7 -19
- package/dist/commands/configOverview.js +3 -2
- package/dist/commands/durableJobCommands.js +1 -1
- package/dist/commands/executionAuditCommands.js +4 -9
- package/dist/commands/globalRoleCommands.js +17 -0
- package/dist/commands/profileCommands.js +200 -30
- package/dist/commands/sessionCommands.js +1 -1
- package/dist/commands/taskActor.js +29 -127
- package/dist/commands/taskChangeSetCommands.js +1 -3
- package/dist/commands/taskCommands.js +1771 -2107
- package/dist/commands/taskCompletionGate.js +27 -103
- package/dist/commands/taskContextCommand.js +47 -80
- package/dist/commands/taskExecutionCommands.js +9 -27
- package/dist/commands/taskInputCommands.js +10 -10
- package/dist/commands/taskIntegrationCommands.js +69 -61
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -29
- package/dist/commands/taskOverviewCommand.js +25 -3
- package/dist/commands/taskPublicationCommands.js +151 -85
- package/dist/commands/taskPublicationVerifyCommand.js +181 -0
- package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
- package/dist/commands/taskRoleRuntimeStatus.js +5 -6
- package/dist/commands/taskUpstreamCommands.js +79 -95
- package/dist/config/configCatalog.js +1 -1
- package/dist/context/contextSnapshot.js +17 -2
- package/dist/context/sourceTurnContext.js +30 -0
- package/dist/context/turnContextPack.js +107 -48
- package/dist/context/turnInputContract.js +11 -4
- package/dist/context/wakeNotification.js +84 -22
- package/dist/controller/agentRuntimeObserver.js +9 -12
- package/dist/controller/clientRuntime.js +13 -13
- package/dist/controller/controller.js +11 -11
- package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
- package/dist/controller/jobControl.js +11 -10
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +2 -2
- package/dist/controller/runtime.js +18 -61
- package/dist/controller/runtimeEventInbox.js +57 -34
- package/dist/controller/runtimeEventProcessor.js +36 -96
- package/dist/controller/runtimeHookTurnFence.js +33 -57
- package/dist/controller/runtimeLaunchCoordinator.js +44 -40
- package/dist/controller/runtimeObservationHook.js +18 -12
- package/dist/controller/sessionNotify.js +43 -28
- package/dist/controller/sessionOwnerReconciliation.js +21 -21
- package/dist/controller/structuredProviderObservation.js +13 -16
- package/dist/coordination/workMailboxQueue.js +132 -0
- package/dist/core/controllerServer.js +1 -0
- package/dist/domain/agentResultTransport.js +60 -0
- package/dist/execution/executionHealth.js +111 -118
- package/dist/execution/reviewMainTurn.js +161 -0
- package/dist/execution/workItemExecution.js +454 -0
- package/dist/execution/workItemExecutionProjection.js +309 -0
- package/dist/execution/workItemMainTurn.js +164 -0
- package/dist/executor/agentExecutor.js +19 -19
- package/dist/executor/executorRegistry.js +7 -28
- package/dist/executor/fileRoleLaunchPlanner.js +16 -82
- package/dist/external/githubPublicationVerifier.js +114 -0
- package/dist/external/gitlabPublicationVerifier.js +158 -0
- package/dist/external/pinnedCommandRunner.js +73 -0
- package/dist/integration/changeSetManifest.js +0 -3
- package/dist/integration/deliveryObligation.js +43 -6
- package/dist/integration/gitIntegrationService.js +284 -101
- package/dist/integration/integrationAttempt.js +64 -14
- package/dist/integration/integrationQueueEntry.js +5 -35
- package/dist/integration/integrationQueueService.js +65 -194
- package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
- package/dist/lifecycle/exactTurnTerminalization.js +100 -97
- package/dist/message/message.js +16 -0
- package/dist/observability/executionAudit.js +4 -25
- package/dist/observability/faultClassification.js +58 -70
- package/dist/observability/orchestrationMetrics.js +8 -50
- package/dist/profile/agentProfile.js +60 -15
- package/dist/profile/agentProfileRuntime.js +100 -0
- package/dist/release/releaseWorkflowPorts.js +5 -68
- package/dist/repository/executionLaneGitSnapshot.js +80 -0
- package/dist/repository/gitWorkspace.js +9 -67
- package/dist/repository/taskBaseFreshness.js +3 -1
- package/dist/repository/taskWorkspaceCoordinator.js +32 -4
- package/dist/repository/taskWorkspacePreparer.js +252 -411
- package/dist/resources/liveReferences.js +6 -55
- package/dist/resources/resourceDiscovery.js +1 -30
- package/dist/resources/resourceRegistrar.js +0 -23
- package/dist/review/deltaRecheck.js +8 -65
- package/dist/review/reviewAcceptance.js +22 -19
- package/dist/review/reviewConfig.js +0 -10
- package/dist/review/reviewDecision.js +2 -2
- package/dist/review/reviewRound.js +147 -273
- package/dist/review/reviewerAvailability.js +13 -23
- package/dist/role/role.js +3 -0
- package/dist/runtime/agentDriverObservation.js +1 -1
- package/dist/runtime/agentHost.js +51 -51
- package/dist/runtime/builtinAgentDrivers.js +9 -2
- package/dist/runtime/codexAppServerRuntime.js +23 -5
- package/dist/runtime/exactControlPlane.js +2 -267
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/launchBroker.js +11 -11
- package/dist/runtime/lifecycleReservation.js +2 -2
- package/dist/runtime/managedCaller.js +111 -0
- package/dist/runtime/ports.js +16 -3
- package/dist/runtime/preallocatedNativeSession.js +2 -2
- package/dist/runtime/processExitObservation.js +3 -2
- package/dist/runtime/providerContinuationReconciliationService.js +1 -1
- package/dist/runtime/runtimeBinding.js +1 -1
- package/dist/runtime/runtimeObservation.js +33 -16
- package/dist/runtime/runtimeSessionCandidate.js +2 -2
- package/dist/runtime/runtimeStopReceipt.js +11 -11
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/sessionOwnerIdentity.js +9 -9
- package/dist/runtime/sessionOwnerRegistry.js +13 -13
- package/dist/runtime/sessionReconciliation.js +4 -4
- package/dist/runtime/sessionTerminationGuard.js +9 -9
- package/dist/runtime/sessionTokenMetrics.js +5 -7
- package/dist/runtime/structuredProviderHost.js +5 -5
- package/dist/runtime/taskRuntimeIsolation.js +24 -24
- package/dist/runtime/tmuxAdapters.js +32 -30
- package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
- package/dist/scheduler/leaderWakeupProcessor.js +78 -55
- package/dist/scheduler/roleTurnLiveness.js +6 -6
- package/dist/scheduler/roleTurnStall.js +8 -9
- package/dist/scheduler/taskExecutionProjection.js +19 -41
- package/dist/scheduler/taskObservabilityProjection.js +75 -122
- package/dist/storage/sqliteSchema.js +1 -21
- package/dist/storage/sqliteStore.js +62 -47
- package/dist/storage/storageSchema.js +1 -8
- package/dist/storage/storageVersions.js +7 -4
- package/dist/storage/taskStore.js +8 -8
- package/dist/storage/upgrade/upgradeOrchestrator.js +112 -83
- package/dist/task/completionReadiness.js +17 -98
- package/dist/task/deliveryGuard.js +9 -11
- package/dist/task/draftPlan.js +142 -0
- package/dist/task/nextAction.js +179 -477
- package/dist/task/publicationVerification.js +1 -0
- package/dist/task/remoteDelivery.js +233 -0
- package/dist/task/task.js +108 -4
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/turn/turn.js +109 -16
- package/dist/verification/verificationGateService.js +0 -26
- package/dist/web/assets/client/components.js +99 -121
- package/dist/web/assets/client/i18n.js +136 -58
- package/dist/web/assets/client/view.js +44 -0
- package/dist/web/assets/styles/cards.js +3 -15
- package/dist/web/assets/styles/widgets.js +4 -0
- package/dist/web/webSnapshot.js +29 -14
- package/dist/workItem/dependencyGate.js +34 -0
- package/dist/workItem/workItem.js +99 -266
- package/dist/workspace/workItemChangeSetManager.js +15 -59
- package/docs/task-local-identity.md +1 -1
- package/i18n/README.zh-CN.md +164 -58
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +272 -782
- package/skills/yui-operator/SKILL.md +190 -365
- package/skills/yui-reviewer/SKILL.md +40 -33
- package/skills/yui-runtime/SKILL.md +22 -0
- package/skills/yui-worker/SKILL.md +19 -6
- package/dist/execution/candidateConvergence.js +0 -623
- package/dist/execution/executionGroup.js +0 -854
- package/dist/execution/resourceBroker.js +0 -426
- package/dist/executor/launchPlan.js +0 -16
- package/dist/review/reviewFinding.js +0 -240
- package/dist/review/reviewFindingLedger.js +0 -550
- package/dist/review/reviewOutcomeClassifier.js +0 -255
- package/dist/scheduler/resourceQueueProjection.js +0 -71
- package/dist/task/repairWave.js +0 -150
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
4
|
import { callController as defaultCallController } from "../core/controllerClient.js";
|
|
5
5
|
import { inspectStorageSchema } from "../storage/storageSchema.js";
|
|
6
6
|
import { yuiVersionIdentity } from "../version.js";
|
|
7
|
-
import { hasRuntimeCleanupObligation, isRuntimeLaunchReservation, runtimeLifecycleTarget } from "./lifecycleReservation.js";
|
|
8
|
-
import { nativeSessionIdForLaunch } from "./preallocatedNativeSession.js";
|
|
9
|
-
import { writeTextFileAtomically } from "../storage/durableFile.js";
|
|
10
7
|
export const EXACT_CONTROL_ARGUMENT = "--yui-control";
|
|
11
8
|
export const YUI_CONTROL_PLANE_DESCRIPTOR = "YUI_CONTROL_PLANE_DESCRIPTOR";
|
|
12
|
-
export const YUI_TASK_RUNTIME_DESCRIPTOR = "YUI_TASK_RUNTIME_DESCRIPTOR";
|
|
13
9
|
export function createExactControlPlaneDescriptor(input) {
|
|
14
10
|
const identity = validateVersionIdentity(input.identity ?? yuiVersionIdentity());
|
|
15
11
|
return Object.freeze({
|
|
@@ -25,25 +21,6 @@ export function createExactControlPlaneDescriptor(input) {
|
|
|
25
21
|
: { activeReleaseDigest: input.activeReleaseDigest })
|
|
26
22
|
});
|
|
27
23
|
}
|
|
28
|
-
export function createExactTaskRuntimeDescriptor(input) {
|
|
29
|
-
return Object.freeze({
|
|
30
|
-
schemaVersion: 1,
|
|
31
|
-
kind: "yui-task-runtime",
|
|
32
|
-
controlPlaneDigest: requireDigest(input.controlPlaneDigest),
|
|
33
|
-
taskId: requireIdentity(input.taskId, "Task id"),
|
|
34
|
-
roleName: requireIdentity(input.roleName, "Role name"),
|
|
35
|
-
agentId: requireIdentity(input.agentId, "Agent id"),
|
|
36
|
-
adapterId: requireAdapter(input.adapterId),
|
|
37
|
-
workspace: canonicalPath(input.workspace),
|
|
38
|
-
...(input.turnId === undefined ? {} : { turnId: requireIdentity(input.turnId, "Turn id") }),
|
|
39
|
-
...(input.launchId === undefined
|
|
40
|
-
? {}
|
|
41
|
-
: { launchId: requireIdentity(input.launchId, "Launch id") }),
|
|
42
|
-
...(input.nativeSessionId === undefined
|
|
43
|
-
? {}
|
|
44
|
-
: { nativeSessionId: requireIdentity(input.nativeSessionId, "Native session id") })
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
24
|
export function serializeExactDescriptor(descriptor) {
|
|
48
25
|
return JSON.stringify(descriptor);
|
|
49
26
|
}
|
|
@@ -64,47 +41,9 @@ export function parseExactControlPlaneDescriptor(value) {
|
|
|
64
41
|
: { activeReleaseDigest: record.activeReleaseDigest })
|
|
65
42
|
});
|
|
66
43
|
}
|
|
67
|
-
export function parseExactTaskRuntimeDescriptor(value) {
|
|
68
|
-
const record = parseDescriptorRecord(value);
|
|
69
|
-
assertDescriptorKind(record, "yui-task-runtime");
|
|
70
|
-
if (record.schemaVersion !== 1) {
|
|
71
|
-
throw new Error("Exact Task runtime descriptor schema version is invalid.");
|
|
72
|
-
}
|
|
73
|
-
return createExactTaskRuntimeDescriptor({
|
|
74
|
-
controlPlaneDigest: requireText(record.controlPlaneDigest, "Control-plane digest"),
|
|
75
|
-
taskId: requireText(record.taskId, "Task id"),
|
|
76
|
-
roleName: requireText(record.roleName, "Role name"),
|
|
77
|
-
agentId: requireText(record.agentId, "Agent id"),
|
|
78
|
-
adapterId: requireAdapter(record.adapterId),
|
|
79
|
-
workspace: requireText(record.workspace, "Task runtime workspace"),
|
|
80
|
-
...(record.turnId === undefined ? {} : { turnId: requireText(record.turnId, "Turn id") }),
|
|
81
|
-
...(record.launchId === undefined
|
|
82
|
-
? {}
|
|
83
|
-
: { launchId: requireText(record.launchId, "Launch id") }),
|
|
84
|
-
...(record.nativeSessionId === undefined
|
|
85
|
-
? {}
|
|
86
|
-
: { nativeSessionId: requireText(record.nativeSessionId, "Native session id") })
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
44
|
export function exactControlPlaneDigest(descriptor) {
|
|
90
45
|
return createHash("sha256").update(serializeExactDescriptor(descriptor)).digest("hex");
|
|
91
46
|
}
|
|
92
|
-
/** Stable per Task/Role/Agent location; volatile Turn/launch/native fields are content. */
|
|
93
|
-
export function exactTaskRuntimeDescriptorPath(home, descriptor) {
|
|
94
|
-
const validated = createExactTaskRuntimeDescriptor(descriptor);
|
|
95
|
-
const digest = createHash("sha256").update(JSON.stringify([
|
|
96
|
-
validated.controlPlaneDigest,
|
|
97
|
-
validated.taskId,
|
|
98
|
-
validated.roleName,
|
|
99
|
-
validated.agentId,
|
|
100
|
-
validated.adapterId,
|
|
101
|
-
validated.workspace
|
|
102
|
-
])).digest("hex");
|
|
103
|
-
return join(canonicalPath(home), "runtime", "exact-task-runtime", `${digest}.json`);
|
|
104
|
-
}
|
|
105
|
-
export function readExactTaskRuntimeDescriptorSource(source, home) {
|
|
106
|
-
return readTaskRuntimeSource(source, home).descriptor;
|
|
107
|
-
}
|
|
108
47
|
export function exactControlPlaneCommandPrefix(descriptor) {
|
|
109
48
|
return [
|
|
110
49
|
descriptor.executable,
|
|
@@ -226,187 +165,6 @@ export function assertControllerStatusIdentity(status, expected = yuiVersionIden
|
|
|
226
165
|
assertControllerField(status.storageLayoutVersion, expected.storageLayoutVersion, "storage layout");
|
|
227
166
|
assertControllerField(status.aggregateSchemaVersion, expected.aggregateSchemaVersion, "aggregate schema");
|
|
228
167
|
}
|
|
229
|
-
export function assertExactTaskRuntimeEnvironment(runtimeSource, environment, expectedControlDigest, expectedHome = requireText(environment.YUI_HOME, "YUI_HOME")) {
|
|
230
|
-
const resolved = readTaskRuntimeSource(runtimeSource, expectedHome);
|
|
231
|
-
const runtime = resolved.descriptor;
|
|
232
|
-
if (runtime.controlPlaneDigest !== requireDigest(expectedControlDigest)) {
|
|
233
|
-
throw new Error("Task runtime descriptor belongs to another exact control plane.");
|
|
234
|
-
}
|
|
235
|
-
assertEnvironment(runtime.taskId, environment.YUI_TASK_ID, "Task id");
|
|
236
|
-
assertEnvironment(runtime.roleName, environment.YUI_ROLE, "Role name");
|
|
237
|
-
assertEnvironment(runtime.agentId, environment.YUI_AGENT_ID, "Agent id");
|
|
238
|
-
assertEnvironment(runtime.adapterId, environment.YUI_ADAPTER_ID, "Agent adapter id");
|
|
239
|
-
assertSamePath(runtime.workspace, requireText(environment.YUI_WORKSPACE, "YUI_WORKSPACE"), "Task runtime workspace");
|
|
240
|
-
// A reused native pane retains its original process environment. Volatile
|
|
241
|
-
// identity therefore comes only from the atomically published descriptor
|
|
242
|
-
// plus durable state, never from stale ambient Turn/launch/native variables.
|
|
243
|
-
if (!resolved.fromFile) {
|
|
244
|
-
assertOptionalEnvironment(runtime.turnId, environment.YUI_TURN_ID, "Turn id");
|
|
245
|
-
assertOptionalEnvironment(runtime.launchId, environment.YUI_LAUNCH_ID, "Launch id");
|
|
246
|
-
assertOptionalEnvironment(runtime.nativeSessionId, environment.YUI_NATIVE_SESSION_ID, "Native session id");
|
|
247
|
-
}
|
|
248
|
-
return runtime;
|
|
249
|
-
}
|
|
250
|
-
/** Fences a descriptor to the one currently active durable Task runtime. */
|
|
251
|
-
export function assertExactTaskRuntimeState(runtime, store, options = {}) {
|
|
252
|
-
const task = store.getTask(runtime.taskId);
|
|
253
|
-
if (task === null
|
|
254
|
-
|| task.status !== "active"
|
|
255
|
-
|| task.executionGate.state !== "enabled") {
|
|
256
|
-
throw new Error("Exact Task runtime Task is not current and active.");
|
|
257
|
-
}
|
|
258
|
-
const role = store.getRole(runtime.taskId, runtime.roleName);
|
|
259
|
-
if (role === null || role.activeAgentId !== runtime.agentId) {
|
|
260
|
-
throw new Error("Exact Task runtime Role or Agent is not current.");
|
|
261
|
-
}
|
|
262
|
-
const run = store.getActiveTurn(runtime.taskId, runtime.roleName);
|
|
263
|
-
if (runtime.turnId === undefined) {
|
|
264
|
-
if (run !== null)
|
|
265
|
-
throw new Error("Exact Task runtime Turn is not current.");
|
|
266
|
-
}
|
|
267
|
-
else if (run === null
|
|
268
|
-
|| run.id !== runtime.turnId
|
|
269
|
-
|| run.status !== "active"
|
|
270
|
-
|| run.effective.agentId !== runtime.agentId
|
|
271
|
-
|| run.effective.adapterId !== runtime.adapterId
|
|
272
|
-
|| canonicalPath(run.effective.workspace.root) !== runtime.workspace) {
|
|
273
|
-
throw new Error("Exact Task runtime Turn is not current.");
|
|
274
|
-
}
|
|
275
|
-
const sessions = store.getTaskRoleSessionSet(runtime.taskId, runtime.roleName);
|
|
276
|
-
const session = sessions?.sessions[runtime.agentId];
|
|
277
|
-
if (sessions !== null && sessions.activeAgentId !== runtime.agentId) {
|
|
278
|
-
throw new Error("Exact Task runtime Session Agent is not current.");
|
|
279
|
-
}
|
|
280
|
-
const lifecycleMailbox = store.getWorkMailbox(runtimeLifecycleTarget({
|
|
281
|
-
scope: "task",
|
|
282
|
-
taskId: runtime.taskId,
|
|
283
|
-
roleName: runtime.roleName
|
|
284
|
-
}));
|
|
285
|
-
const reservation = runtime.launchId !== undefined
|
|
286
|
-
&& isRuntimeLaunchReservation(lifecycleMailbox?.processing, runtime.launchId);
|
|
287
|
-
const sessionLaunch = runtime.launchId !== undefined
|
|
288
|
-
&& session?.launchId === runtime.launchId;
|
|
289
|
-
const preallocated = options.preallocatedDriverSessionReservation;
|
|
290
|
-
const exactHostLaunchReservation = runtime.launchId !== undefined
|
|
291
|
-
&& reservation
|
|
292
|
-
&& !hasRuntimeCleanupObligation(lifecycleMailbox);
|
|
293
|
-
const terminalSessionReplacementReservation = exactHostLaunchReservation
|
|
294
|
-
&& session !== undefined
|
|
295
|
-
&& session.status === "ended";
|
|
296
|
-
const exactPreallocatedReservation = preallocated !== undefined
|
|
297
|
-
&& runtime.adapterId === preallocated.adapterId
|
|
298
|
-
&& exactHostLaunchReservation
|
|
299
|
-
&& runtime.nativeSessionId !== undefined
|
|
300
|
-
&& (session === undefined || terminalSessionReplacementReservation)
|
|
301
|
-
&& runtime.nativeSessionId === nativeSessionIdForLaunch(preallocated.yuiHome, runtime.launchId, runtime.agentId, runtime.adapterId);
|
|
302
|
-
if (runtime.launchId === undefined || (!reservation && !sessionLaunch)) {
|
|
303
|
-
throw new Error("Exact Task runtime launch fence is not current.");
|
|
304
|
-
}
|
|
305
|
-
if (runtime.nativeSessionId === undefined) {
|
|
306
|
-
if (session !== undefined && !terminalSessionReplacementReservation) {
|
|
307
|
-
throw new Error("Exact Task runtime native Session fence is missing.");
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
else if (session === undefined || terminalSessionReplacementReservation) {
|
|
311
|
-
if (!exactPreallocatedReservation) {
|
|
312
|
-
throw new Error("Exact Task runtime native Session fence is not current.");
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
else if (session.agentId !== runtime.agentId
|
|
316
|
-
|| session.adapterId !== runtime.adapterId
|
|
317
|
-
|| session.nativeSessionId !== runtime.nativeSessionId
|
|
318
|
-
|| session.launchId !== runtime.launchId
|
|
319
|
-
|| session.status === "ended"
|
|
320
|
-
|| session.effective.agentId !== runtime.agentId
|
|
321
|
-
|| session.effective.adapterId !== runtime.adapterId
|
|
322
|
-
|| canonicalPath(session.effective.workspace.root) !== runtime.workspace) {
|
|
323
|
-
throw new Error("Exact Task runtime native Session fence is not current.");
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/** Publishes provider-discovered native identity without changing the stable source path. */
|
|
327
|
-
export function refreshExactTaskRuntimeDescriptorSource(source, home, store) {
|
|
328
|
-
const resolved = readTaskRuntimeSource(source, home);
|
|
329
|
-
if (!resolved.fromFile) {
|
|
330
|
-
throw new Error("A managed Task runtime descriptor must use its stable file source.");
|
|
331
|
-
}
|
|
332
|
-
const current = resolved.descriptor;
|
|
333
|
-
const session = store.getTaskRoleSessionSet(current.taskId, current.roleName)
|
|
334
|
-
?.sessions[current.agentId];
|
|
335
|
-
if (session === undefined) {
|
|
336
|
-
throw new Error("Exact Task runtime native Session is not available for refresh.");
|
|
337
|
-
}
|
|
338
|
-
const refreshed = createExactTaskRuntimeDescriptor({
|
|
339
|
-
...current,
|
|
340
|
-
nativeSessionId: session.nativeSessionId
|
|
341
|
-
});
|
|
342
|
-
if (exactTaskRuntimeDescriptorPath(home, refreshed) !== resolve(source)) {
|
|
343
|
-
throw new Error("Refreshed Task runtime descriptor changed its stable identity.");
|
|
344
|
-
}
|
|
345
|
-
assertExactTaskRuntimeState(refreshed, store);
|
|
346
|
-
writeTextFileAtomically(resolve(source), `${serializeExactDescriptor(refreshed)}\n`);
|
|
347
|
-
return refreshed;
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Advances a reused Hook's own exact source to the current durable Turn/launch
|
|
351
|
-
* generation before the volatile fence. The stable identity (control digest,
|
|
352
|
-
* Task, Role, Agent, adapter, workspace) and the native Session are preserved;
|
|
353
|
-
* only the volatile Turn/launch fields advance. A source may never jump to a
|
|
354
|
-
* replacement native Session.
|
|
355
|
-
*/
|
|
356
|
-
export function refreshReusedTaskRuntimeDescriptorSource(source, home, store, current) {
|
|
357
|
-
const resolved = readTaskRuntimeSource(source, home);
|
|
358
|
-
if (!resolved.fromFile) {
|
|
359
|
-
throw new Error("A managed Task runtime descriptor must use its stable file source.");
|
|
360
|
-
}
|
|
361
|
-
const previous = resolved.descriptor;
|
|
362
|
-
if (previous.nativeSessionId === undefined) {
|
|
363
|
-
if (previous.turnId !== current.turnId || previous.launchId !== current.launchId) {
|
|
364
|
-
throw new Error("Task runtime descriptor source cannot bind a native Session from another generation.");
|
|
365
|
-
}
|
|
366
|
-
return refreshExactTaskRuntimeDescriptorSource(source, home, store);
|
|
367
|
-
}
|
|
368
|
-
if (previous.nativeSessionId !== current.nativeSessionId) {
|
|
369
|
-
throw new Error("Task runtime descriptor source cannot jump to a replacement native Session.");
|
|
370
|
-
}
|
|
371
|
-
const refreshed = createExactTaskRuntimeDescriptor({
|
|
372
|
-
...previous,
|
|
373
|
-
turnId: current.turnId,
|
|
374
|
-
launchId: current.launchId,
|
|
375
|
-
nativeSessionId: current.nativeSessionId
|
|
376
|
-
});
|
|
377
|
-
if (exactTaskRuntimeDescriptorPath(home, refreshed) !== resolve(source)) {
|
|
378
|
-
throw new Error("Refreshed Task runtime descriptor changed its stable identity.");
|
|
379
|
-
}
|
|
380
|
-
assertExactTaskRuntimeState(refreshed, store);
|
|
381
|
-
writeTextFileAtomically(resolve(source), `${serializeExactDescriptor(refreshed)}\n`);
|
|
382
|
-
return refreshed;
|
|
383
|
-
}
|
|
384
|
-
function readTaskRuntimeSource(source, home) {
|
|
385
|
-
const value = requireText(source, "Exact Task runtime descriptor source");
|
|
386
|
-
if (value.trimStart().startsWith("{")) {
|
|
387
|
-
return { descriptor: parseExactTaskRuntimeDescriptor(value), fromFile: false };
|
|
388
|
-
}
|
|
389
|
-
const requested = resolve(value);
|
|
390
|
-
const root = resolve(canonicalPath(home), "runtime", "exact-task-runtime");
|
|
391
|
-
if (dirname(requested) !== root) {
|
|
392
|
-
throw new Error("Exact Task runtime descriptor path is outside its control plane.");
|
|
393
|
-
}
|
|
394
|
-
let actual;
|
|
395
|
-
try {
|
|
396
|
-
actual = realpathSync(requested);
|
|
397
|
-
}
|
|
398
|
-
catch (error) {
|
|
399
|
-
throw new Error("Exact Task runtime descriptor file is unavailable.", { cause: error });
|
|
400
|
-
}
|
|
401
|
-
if (actual !== requested) {
|
|
402
|
-
throw new Error("Exact Task runtime descriptor file must not be a symbolic link.");
|
|
403
|
-
}
|
|
404
|
-
const descriptor = parseExactTaskRuntimeDescriptor(readFileSync(actual, "utf8"));
|
|
405
|
-
if (exactTaskRuntimeDescriptorPath(home, descriptor) !== requested) {
|
|
406
|
-
throw new Error("Exact Task runtime descriptor path does not match its stable identity.");
|
|
407
|
-
}
|
|
408
|
-
return { descriptor, fromFile: true };
|
|
409
|
-
}
|
|
410
168
|
function validateVersionIdentity(value) {
|
|
411
169
|
if (!isRecord(value))
|
|
412
170
|
throw new Error("Yui version identity is invalid.");
|
|
@@ -459,16 +217,6 @@ function assertSamePath(expected, actual, label) {
|
|
|
459
217
|
throw new Error(`${label} does not match the frozen control plane (expected ${expected}, found ${normalized}).`);
|
|
460
218
|
}
|
|
461
219
|
}
|
|
462
|
-
function assertEnvironment(expected, actual, label) {
|
|
463
|
-
if (actual !== expected) {
|
|
464
|
-
throw new Error(`${label} does not match the exact Task runtime descriptor.`);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
function assertOptionalEnvironment(expected, actual, label) {
|
|
468
|
-
if (actual !== expected) {
|
|
469
|
-
throw new Error(`${label} does not match the exact Task runtime descriptor.`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
220
|
function parseDescriptorRecord(value) {
|
|
473
221
|
let parsed;
|
|
474
222
|
try {
|
|
@@ -487,19 +235,6 @@ function assertDescriptorKind(value, expected) {
|
|
|
487
235
|
+ `${typeof value.kind === "string" ? value.kind : "unknown"}.`);
|
|
488
236
|
}
|
|
489
237
|
}
|
|
490
|
-
function requireAdapter(value) {
|
|
491
|
-
if (value !== "codex" && value !== "claude") {
|
|
492
|
-
throw new Error("Agent adapter id is invalid.");
|
|
493
|
-
}
|
|
494
|
-
return value;
|
|
495
|
-
}
|
|
496
|
-
function requireIdentity(value, label) {
|
|
497
|
-
const text = requireText(value, label).trim();
|
|
498
|
-
if (text.length === 0 || text.length > 1_024 || text.includes("\0")) {
|
|
499
|
-
throw new Error(`${label} is invalid.`);
|
|
500
|
-
}
|
|
501
|
-
return text;
|
|
502
|
-
}
|
|
503
238
|
function requireText(value, label) {
|
|
504
239
|
if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
|
|
505
240
|
throw new Error(`${label} is invalid.`);
|
|
@@ -4,7 +4,7 @@ export function projectFirstProgressAdvisory(input) {
|
|
|
4
4
|
: [...(input.sessions.history ?? []), ...Object.values(input.sessions.sessions)]
|
|
5
5
|
.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
6
6
|
const unique = [...new Map(sessions.map((session) => [
|
|
7
|
-
`${session.nativeSessionId}\0${session.
|
|
7
|
+
`${session.nativeSessionId}\0${session.runtimeGenerationId ?? ""}`,
|
|
8
8
|
session
|
|
9
9
|
])).values()];
|
|
10
10
|
const firstGenerationAt = unique[0]?.createdAt;
|
package/dist/runtime/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { createRuntimeBinding } from "./runtimeBinding.js";
|
|
|
5
5
|
export { normalizeRuntimeOwner } from "./runtimeOwner.js";
|
|
6
6
|
export { createSessionLaunchRequest } from "./sessionLaunchRequest.js";
|
|
7
7
|
export { DEFAULT_RECENT_TURN_ID_LIMIT, hasRecentTurnId, rememberRecentTurnId, validateRecentTurnIds } from "./recentTurnIds.js";
|
|
8
|
-
export { RuntimeHostContentionError, RuntimeLaunchError } from "./ports.js";
|
|
8
|
+
export { RuntimeGenerationMismatchError, RuntimeHostContentionError, RuntimeLaunchError } from "./ports.js";
|
|
9
9
|
export { AgentHostPromptPushAdapter, TmuxSessionHost } from "./tmuxAdapters.js";
|
|
10
10
|
export { FileTaskRuntimeIsolation, YUI_TASK_RUNTIME_ISOLATION_DESCRIPTOR, YUI_TASK_RUNTIME_SERVICE_NAMESPACE, assertTaskRuntimeIsolationPreflight, createTaskRuntimeIsolationDescriptor, parseTaskRuntimeIsolationDescriptor, planTaskRuntimeCleanup, taskRuntimeIsolationEnvironment, taskRuntimeIsolationFingerprint } from "./taskRuntimeIsolation.js";
|
|
11
11
|
export { createSessionOwnerIdentity, discoverProviderRootByLaunchEnv, isLinuxProcessLive, listLaunchFencedProcesses, listOwnedProcessTree, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
|
|
@@ -17,30 +17,30 @@ export class LaunchBroker {
|
|
|
17
17
|
#reservations = new Map();
|
|
18
18
|
reserve(payload) {
|
|
19
19
|
validatePayload(payload);
|
|
20
|
-
if (this.#reservations.has(payload.
|
|
21
|
-
throw new Error(`Launch payload is already reserved: ${payload.
|
|
20
|
+
if (this.#reservations.has(payload.runtimeGenerationId)) {
|
|
21
|
+
throw new Error(`Launch payload is already reserved: ${payload.runtimeGenerationId}.`);
|
|
22
22
|
}
|
|
23
23
|
const ticket = randomBytes(32).toString("hex");
|
|
24
|
-
this.#reservations.set(payload.
|
|
24
|
+
this.#reservations.set(payload.runtimeGenerationId, Object.freeze({
|
|
25
25
|
ticket,
|
|
26
26
|
payload,
|
|
27
27
|
createdAt: Date.now()
|
|
28
28
|
}));
|
|
29
|
-
return Object.freeze({
|
|
29
|
+
return Object.freeze({ runtimeGenerationId: payload.runtimeGenerationId, ticket });
|
|
30
30
|
}
|
|
31
|
-
redeem(
|
|
32
|
-
const reservation = this.#reservations.get(
|
|
31
|
+
redeem(runtimeGenerationId, ticket) {
|
|
32
|
+
const reservation = this.#reservations.get(runtimeGenerationId);
|
|
33
33
|
if (reservation === undefined || reservation.ticket !== ticket) {
|
|
34
34
|
throw new Error("Launch ticket is invalid or already consumed.");
|
|
35
35
|
}
|
|
36
|
-
this.#reservations.delete(
|
|
36
|
+
this.#reservations.delete(runtimeGenerationId);
|
|
37
37
|
if (Date.now() - reservation.createdAt > AGENT_HOST_LAUNCH_TICKET_TTL_MS) {
|
|
38
38
|
throw new Error("Launch ticket expired before redemption.");
|
|
39
39
|
}
|
|
40
40
|
return reservation.payload;
|
|
41
41
|
}
|
|
42
|
-
revoke(
|
|
43
|
-
this.#reservations.delete(
|
|
42
|
+
revoke(runtimeGenerationId) {
|
|
43
|
+
this.#reservations.delete(runtimeGenerationId);
|
|
44
44
|
}
|
|
45
45
|
pendingCount() {
|
|
46
46
|
return this.#reservations.size;
|
|
@@ -53,9 +53,9 @@ export function validateAgentHostLaunchPayload(value) {
|
|
|
53
53
|
return validatePayload(value);
|
|
54
54
|
}
|
|
55
55
|
function validatePayload(payload) {
|
|
56
|
-
if (payload.schemaVersion !==
|
|
56
|
+
if (payload.schemaVersion !== 2)
|
|
57
57
|
throw new Error("Agent Host launch payload version is invalid.");
|
|
58
|
-
text(payload.
|
|
58
|
+
text(payload.runtimeGenerationId, "runtimeGenerationId");
|
|
59
59
|
text(payload.command, "command");
|
|
60
60
|
text(payload.cwd, "cwd");
|
|
61
61
|
if (!Array.isArray(payload.args))
|
|
@@ -33,11 +33,11 @@ export function runtimeLifecycleSignalKey(owner) {
|
|
|
33
33
|
? `role:${encodeURIComponent(owner.taskId)}/${encodeURIComponent(owner.roleName)}`
|
|
34
34
|
: `global-role:${encodeURIComponent(owner.roleName)}`;
|
|
35
35
|
}
|
|
36
|
-
export function isRuntimeLaunchReservation(processing,
|
|
36
|
+
export function isRuntimeLaunchReservation(processing, runtimeGenerationId) {
|
|
37
37
|
return processing?.owner === RUNTIME_LIFECYCLE_OWNER
|
|
38
38
|
&& processing.batch.reasons.length === 1
|
|
39
39
|
&& processing.batch.reasons[0] === RUNTIME_LAUNCH_RESERVED_REASON
|
|
40
|
-
&& (
|
|
40
|
+
&& (runtimeGenerationId === undefined || processing.batchId === runtimeGenerationId);
|
|
41
41
|
}
|
|
42
42
|
export function hasRuntimeLaunchReservation(mailbox) {
|
|
43
43
|
return isRuntimeLaunchReservation(mailbox?.processing);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { activeRoleAgentBinding } from "../role/role.js";
|
|
3
|
+
/** Per-process credential injected at native Session launch. */
|
|
4
|
+
export const MANAGED_CALLER_KEY_ENV = "YUI_JOB_CALLER_KEY";
|
|
5
|
+
/**
|
|
6
|
+
* A managed Session presented valid self-identity but is no longer the current
|
|
7
|
+
* runtime of its Task Role. This is a bounded diagnosis rather than a bare
|
|
8
|
+
* denial: the Agent can still read current state and decide whether to re-read,
|
|
9
|
+
* hand back, or stop.
|
|
10
|
+
*/
|
|
11
|
+
export class ManagedRuntimeDriftError extends Error {
|
|
12
|
+
name = "ManagedRuntimeDriftError";
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** Reads the process's own immutable managed identity, or undefined when unmanaged. */
|
|
18
|
+
export function managedTaskSessionIdentity(environment) {
|
|
19
|
+
const env = environment ?? {};
|
|
20
|
+
if (env.YUI_SESSION_SCOPE !== "task")
|
|
21
|
+
return undefined;
|
|
22
|
+
const taskId = identity(env.YUI_TASK_ID);
|
|
23
|
+
const roleName = identity(env.YUI_ROLE);
|
|
24
|
+
if (taskId === undefined || roleName === undefined) {
|
|
25
|
+
throw new ManagedRuntimeDriftError("Managed Task Session identity is incomplete: YUI_TASK_ID and YUI_ROLE are required.");
|
|
26
|
+
}
|
|
27
|
+
const workspace = identity(env.YUI_WORKSPACE);
|
|
28
|
+
const callerKey = identity(env[MANAGED_CALLER_KEY_ENV]);
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
taskId,
|
|
31
|
+
roleName,
|
|
32
|
+
...(workspace === undefined ? {} : { workspace }),
|
|
33
|
+
...(callerKey === undefined ? {} : { callerKey })
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolves the current runtime authority for a managed Task Session, or
|
|
38
|
+
* undefined for an unmanaged (plain user) invocation. Throws only when the
|
|
39
|
+
* process claims managed identity that durable state no longer recognizes.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveManagedTaskCaller(store, environment) {
|
|
42
|
+
const self = managedTaskSessionIdentity(environment);
|
|
43
|
+
if (self === undefined)
|
|
44
|
+
return undefined;
|
|
45
|
+
return requireCurrentRuntime(store, self);
|
|
46
|
+
}
|
|
47
|
+
/** Same as resolveManagedTaskCaller, but requires a managed Task Session. */
|
|
48
|
+
export function requireManagedTaskCaller(store, environment) {
|
|
49
|
+
const caller = resolveManagedTaskCaller(store, environment);
|
|
50
|
+
if (caller === undefined) {
|
|
51
|
+
throw new ManagedRuntimeDriftError("This command requires a managed Task Session.");
|
|
52
|
+
}
|
|
53
|
+
return caller;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The current runtime authority for one Task Role, or undefined. Used by
|
|
57
|
+
* command authorization that must not fail the whole invocation, only decline
|
|
58
|
+
* one privileged effect.
|
|
59
|
+
*/
|
|
60
|
+
export function currentManagedRuntime(store, environment, taskId, roleName) {
|
|
61
|
+
let caller;
|
|
62
|
+
try {
|
|
63
|
+
caller = resolveManagedTaskCaller(store, environment);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
if (caller === undefined || caller.taskId !== taskId)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (roleName !== undefined && caller.roleName !== roleName)
|
|
71
|
+
return undefined;
|
|
72
|
+
return caller;
|
|
73
|
+
}
|
|
74
|
+
function requireCurrentRuntime(store, self) {
|
|
75
|
+
const role = store.getRole(self.taskId, self.roleName);
|
|
76
|
+
if (role === null) {
|
|
77
|
+
throw new ManagedRuntimeDriftError(`This managed Session belongs to ${self.taskId}/${self.roleName}, which no longer exists. `
|
|
78
|
+
+ "A new Session must be launched to act on this Task.");
|
|
79
|
+
}
|
|
80
|
+
const agentId = role.activeAgentId;
|
|
81
|
+
if (self.callerKey === undefined) {
|
|
82
|
+
throw new ManagedRuntimeDriftError(`This managed Session carries no ${MANAGED_CALLER_KEY_ENV}, so it cannot be recognized `
|
|
83
|
+
+ `as the current runtime of ${self.taskId}/${self.roleName}.`);
|
|
84
|
+
}
|
|
85
|
+
const expectedHash = store.getJobCallerKeyHash(self.taskId, self.roleName, agentId);
|
|
86
|
+
if (expectedHash === null
|
|
87
|
+
|| createHash("sha256").update(self.callerKey).digest("hex") !== expectedHash) {
|
|
88
|
+
throw new ManagedRuntimeDriftError(`This managed Session is no longer the current runtime of ${self.taskId}/${self.roleName} `
|
|
89
|
+
+ `(the Role now runs Agent ${agentId}). Its native Session was replaced or its Role was `
|
|
90
|
+
+ "rebound, so its durable caller key no longer matches. Nothing was changed. Read the "
|
|
91
|
+
+ `current state with \`yui task show ${self.taskId}\`; acting requires the Session Yui `
|
|
92
|
+
+ "launched for the current runtime.");
|
|
93
|
+
}
|
|
94
|
+
const activeTurn = store.getActiveTurn(self.taskId, self.roleName);
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
taskId: self.taskId,
|
|
97
|
+
roleName: self.roleName,
|
|
98
|
+
agentId,
|
|
99
|
+
adapterId: activeRoleAgentBinding(role).adapterId,
|
|
100
|
+
...(self.workspace === undefined ? {} : { workspace: self.workspace }),
|
|
101
|
+
...(activeTurn === null || activeTurn.status !== "active"
|
|
102
|
+
? {}
|
|
103
|
+
: { currentTurnId: activeTurn.id })
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function identity(value) {
|
|
107
|
+
if (typeof value !== "string" || value.includes("\0"))
|
|
108
|
+
return undefined;
|
|
109
|
+
const normalized = value.trim();
|
|
110
|
+
return normalized.length === 0 || normalized !== value ? undefined : normalized;
|
|
111
|
+
}
|
package/dist/runtime/ports.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/** A persisted launch is either temporarily unavailable or permanently lost. */
|
|
2
2
|
export class RuntimeLaunchError extends Error {
|
|
3
3
|
retryable;
|
|
4
|
-
|
|
4
|
+
runtimeGenerationId;
|
|
5
5
|
reason;
|
|
6
6
|
name = "RuntimeLaunchError";
|
|
7
|
-
constructor(retryable,
|
|
7
|
+
constructor(retryable, runtimeGenerationId, message, reason) {
|
|
8
8
|
super(message);
|
|
9
9
|
this.retryable = retryable;
|
|
10
|
-
this.
|
|
10
|
+
this.runtimeGenerationId = runtimeGenerationId;
|
|
11
11
|
this.reason = reason;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -20,3 +20,16 @@ export class RuntimeHostContentionError extends Error {
|
|
|
20
20
|
this.reason = reason;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
/** A reused Agent Host acknowledged a different runtime generation. */
|
|
24
|
+
export class RuntimeGenerationMismatchError extends Error {
|
|
25
|
+
expectedRuntimeGenerationId;
|
|
26
|
+
observedRuntimeGenerationId;
|
|
27
|
+
hostState;
|
|
28
|
+
name = "RuntimeGenerationMismatchError";
|
|
29
|
+
constructor(expectedRuntimeGenerationId, observedRuntimeGenerationId, hostState, message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.expectedRuntimeGenerationId = expectedRuntimeGenerationId;
|
|
32
|
+
this.observedRuntimeGenerationId = observedRuntimeGenerationId;
|
|
33
|
+
this.hostState = hostState;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,10 +2,10 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { requireText } from "./validation.js";
|
|
4
4
|
/** Deterministic native identity preallocated for one exact provider launch. */
|
|
5
|
-
export function nativeSessionIdForLaunch(home,
|
|
5
|
+
export function nativeSessionIdForLaunch(home, runtimeGenerationId, agentId, adapterId) {
|
|
6
6
|
const hex = createHash("sha256").update(JSON.stringify([
|
|
7
7
|
resolve(requireText(home, "YUI_HOME")),
|
|
8
|
-
requireText(
|
|
8
|
+
requireText(runtimeGenerationId, "Runtime generation id"),
|
|
9
9
|
requireText(agentId, "Agent id"),
|
|
10
10
|
requireText(adapterId, "Agent adapter id")
|
|
11
11
|
])).digest("hex");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export const RUNTIME_PROCESS_EXIT_SCHEMA_VERSION =
|
|
1
|
+
export const RUNTIME_PROCESS_EXIT_SCHEMA_VERSION = 2;
|
|
2
|
+
export const RUNTIME_PROCESS_EXIT_TASK_EVENT = "runtime.process-exit-observed";
|
|
2
3
|
export function validateRuntimeProcessExitObservation(observation) {
|
|
3
4
|
if (observation.schemaVersion !== RUNTIME_PROCESS_EXIT_SCHEMA_VERSION) {
|
|
4
5
|
throw new Error("Runtime process-exit observation version is invalid.");
|
|
@@ -9,7 +10,7 @@ export function validateRuntimeProcessExitObservation(observation) {
|
|
|
9
10
|
optionalIdentity(observation.taskId, "taskId");
|
|
10
11
|
identity(observation.roleName, "roleName");
|
|
11
12
|
optionalIdentity(observation.turnId, "turnId");
|
|
12
|
-
identity(observation.
|
|
13
|
+
identity(observation.runtimeGenerationId, "runtimeGenerationId");
|
|
13
14
|
optionalIdentity(observation.nativeSessionId, "nativeSessionId");
|
|
14
15
|
if (observation.processKind !== "agent-host" && observation.processKind !== "provider-child") {
|
|
15
16
|
throw new Error("Runtime process kind is invalid.");
|
|
@@ -135,7 +135,7 @@ function reconciliationObservation(continuation, sourceFence, now) {
|
|
|
135
135
|
const settled = continuation.execution === "quiescent"
|
|
136
136
|
&& continuation.observation === "exact";
|
|
137
137
|
return createRuntimeObservation({
|
|
138
|
-
schemaVersion:
|
|
138
|
+
schemaVersion: 4,
|
|
139
139
|
eventId: `continuation-reconcile:${digest}`,
|
|
140
140
|
semanticKey: `continuation-reconcile:${digest}`,
|
|
141
141
|
kind: settled ? "continuation.settled" : "continuation.started",
|
|
@@ -7,7 +7,7 @@ export function createRuntimeBinding(input) {
|
|
|
7
7
|
: requireBoolean(input.hostCreated, "Runtime host-created flag");
|
|
8
8
|
return {
|
|
9
9
|
id: requireSafeIdentity(input.id, "Runtime binding id"),
|
|
10
|
-
|
|
10
|
+
runtimeGenerationId: requireSafeIdentity(input.runtimeGenerationId, "Runtime generation id"),
|
|
11
11
|
owner: normalizeRuntimeOwner(input.owner),
|
|
12
12
|
agentId: requireSafeIdentity(input.agentId, "Agent id"),
|
|
13
13
|
adapterId: requireSafeIdentity(input.adapterId, "Agent adapter id"),
|