@zq-silk/yui 0.14.0 → 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 +258 -125
- package/dist/agent/argumentPolicy.js +2 -1
- 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/sessionBootstrapManifest.js +18 -1
- 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 +51 -83
- 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 +165 -59
- 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 +27 -6
- 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
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { governingWorkItemCandidate, currentWorkItemExecutionGroup } from "../workItem/workItem.js";
|
|
2
|
+
import { MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS } from "./workItemExecution.js";
|
|
3
|
+
export function projectWorkItemExecution(item, turns, sessionSets = []) {
|
|
4
|
+
const group = currentWorkItemExecutionGroup(item);
|
|
5
|
+
const relevantTurns = turns.filter((turn) => turn.workItemId === item.id);
|
|
6
|
+
const sessionsByRole = new Map(sessionSets.map((set) => [set.owner.roleName, set]));
|
|
7
|
+
const lanes = group === undefined
|
|
8
|
+
? []
|
|
9
|
+
: [...group.lanes]
|
|
10
|
+
.sort((left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id))
|
|
11
|
+
.map((lane) => projectLane(item, group, lane, relevantTurns, sessionsByRole));
|
|
12
|
+
const laneCounts = Object.freeze({
|
|
13
|
+
running: lanes.filter(({ status }) => status === "running").length,
|
|
14
|
+
succeeded: lanes.filter(({ status }) => status === "succeeded").length,
|
|
15
|
+
needsAttention: lanes.filter(({ status }) => status === "needs-attention").length,
|
|
16
|
+
failed: lanes.filter(({ status }) => status === "failed").length,
|
|
17
|
+
unknown: lanes.filter(({ status }) => status === "unknown").length
|
|
18
|
+
});
|
|
19
|
+
const mainTurn = projectMainTurn(item, group, relevantTurns, sessionsByRole);
|
|
20
|
+
const synthesis = projectSynthesis(group, lanes, mainTurn);
|
|
21
|
+
const candidate = projectCandidate(item, group, relevantTurns, lanes, mainTurn);
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
schemaVersion: 1,
|
|
24
|
+
shape: group === undefined ? "direct" : "replicated",
|
|
25
|
+
...(group === undefined ? {} : { groupId: group.id }),
|
|
26
|
+
lanes: Object.freeze(lanes),
|
|
27
|
+
laneCounts,
|
|
28
|
+
synthesis,
|
|
29
|
+
mainTurn,
|
|
30
|
+
candidate,
|
|
31
|
+
nextAction: projectNextAction(item, lanes, synthesis, mainTurn, candidate)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function projectLane(item, group, lane, turns, sessionsByRole) {
|
|
35
|
+
const current = lane.currentTurnId === undefined
|
|
36
|
+
? undefined
|
|
37
|
+
: turns.find(({ id }) => id === lane.currentTurnId);
|
|
38
|
+
const exact = current !== undefined
|
|
39
|
+
&& current.taskId === item.taskId
|
|
40
|
+
&& current.workItemId === item.id
|
|
41
|
+
&& current.executionGroupId === group.id
|
|
42
|
+
&& current.executionLaneId === lane.id
|
|
43
|
+
&& current.roleName === lane.roleName;
|
|
44
|
+
const session = exact
|
|
45
|
+
? turnSessionStatus(current, sessionsByRole.get(lane.roleName))
|
|
46
|
+
: "unobserved";
|
|
47
|
+
if (lane.disposition === "failed") {
|
|
48
|
+
return Object.freeze({
|
|
49
|
+
laneId: lane.id,
|
|
50
|
+
ordinal: lane.ordinal,
|
|
51
|
+
roleName: lane.roleName,
|
|
52
|
+
status: "failed",
|
|
53
|
+
...(lane.currentTurnId === undefined ? {} : { currentTurnId: lane.currentTurnId }),
|
|
54
|
+
session,
|
|
55
|
+
observation: exact ? "observed" : "unobserved"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (lane.disposition === "succeeded") {
|
|
59
|
+
const producerObserved = exact
|
|
60
|
+
&& lane.successfulTurnId === current.id
|
|
61
|
+
&& current.status === "completed"
|
|
62
|
+
&& current.result !== undefined;
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
laneId: lane.id,
|
|
65
|
+
ordinal: lane.ordinal,
|
|
66
|
+
roleName: lane.roleName,
|
|
67
|
+
status: producerObserved ? "succeeded" : "unknown",
|
|
68
|
+
...(lane.currentTurnId === undefined ? {} : { currentTurnId: lane.currentTurnId }),
|
|
69
|
+
...(lane.successfulTurnId === undefined ? {} : { successfulTurnId: lane.successfulTurnId }),
|
|
70
|
+
session,
|
|
71
|
+
observation: producerObserved ? "observed" : "unobserved"
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (!exact) {
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
laneId: lane.id,
|
|
77
|
+
ordinal: lane.ordinal,
|
|
78
|
+
roleName: lane.roleName,
|
|
79
|
+
status: "unknown",
|
|
80
|
+
...(lane.currentTurnId === undefined ? {} : { currentTurnId: lane.currentTurnId }),
|
|
81
|
+
session: "unobserved",
|
|
82
|
+
observation: "unobserved"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (current.status === "failed") {
|
|
86
|
+
return Object.freeze({
|
|
87
|
+
laneId: lane.id,
|
|
88
|
+
ordinal: lane.ordinal,
|
|
89
|
+
roleName: lane.roleName,
|
|
90
|
+
status: "needs-attention",
|
|
91
|
+
currentTurnId: current.id,
|
|
92
|
+
session,
|
|
93
|
+
retryTurnId: current.id,
|
|
94
|
+
settleTurnId: current.id,
|
|
95
|
+
observation: "observed"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (current.status === "active") {
|
|
99
|
+
return Object.freeze({
|
|
100
|
+
laneId: lane.id,
|
|
101
|
+
ordinal: lane.ordinal,
|
|
102
|
+
roleName: lane.roleName,
|
|
103
|
+
status: session === "ended" ? "needs-attention" : "running",
|
|
104
|
+
currentTurnId: current.id,
|
|
105
|
+
session,
|
|
106
|
+
observation: "observed"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return Object.freeze({
|
|
110
|
+
laneId: lane.id,
|
|
111
|
+
ordinal: lane.ordinal,
|
|
112
|
+
roleName: lane.roleName,
|
|
113
|
+
status: "unknown",
|
|
114
|
+
currentTurnId: current.id,
|
|
115
|
+
session,
|
|
116
|
+
observation: "unobserved"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function projectMainTurn(item, group, turns, sessionsByRole) {
|
|
120
|
+
const candidates = turns.filter((turn) => (turn.purpose === "execution"
|
|
121
|
+
&& turn.roleName === item.assignee
|
|
122
|
+
&& turn.executionGroupId === undefined
|
|
123
|
+
&& turn.executionLaneId === undefined
|
|
124
|
+
&& turn.sourceExecutionGroupId === group?.id)).sort(compareTurns);
|
|
125
|
+
const turn = candidates.at(-1);
|
|
126
|
+
if (turn === undefined) {
|
|
127
|
+
return Object.freeze({
|
|
128
|
+
status: "not-started",
|
|
129
|
+
...(item.assignee === undefined ? {} : { roleName: item.assignee }),
|
|
130
|
+
...(group === undefined ? {} : { sourceExecutionGroupId: group.id }),
|
|
131
|
+
session: "unobserved",
|
|
132
|
+
observation: "unobserved"
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const session = turnSessionStatus(turn, sessionsByRole.get(turn.roleName));
|
|
136
|
+
const base = {
|
|
137
|
+
roleName: turn.roleName,
|
|
138
|
+
turnId: turn.id,
|
|
139
|
+
...(turn.sourceExecutionGroupId === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { sourceExecutionGroupId: turn.sourceExecutionGroupId }),
|
|
142
|
+
session
|
|
143
|
+
};
|
|
144
|
+
if (turn.status === "failed") {
|
|
145
|
+
return Object.freeze({
|
|
146
|
+
...base,
|
|
147
|
+
status: "needs-attention",
|
|
148
|
+
retryTurnId: turn.id,
|
|
149
|
+
observation: "observed"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (turn.status === "active") {
|
|
153
|
+
return Object.freeze({
|
|
154
|
+
...base,
|
|
155
|
+
status: session === "ended" ? "needs-attention" : "running",
|
|
156
|
+
observation: "observed"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return Object.freeze({
|
|
160
|
+
...base,
|
|
161
|
+
status: turn.result === undefined ? "unknown" : "succeeded",
|
|
162
|
+
observation: turn.result === undefined ? "unobserved" : "observed"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function projectSynthesis(group, lanes, mainTurn) {
|
|
166
|
+
if (group === undefined) {
|
|
167
|
+
return Object.freeze({
|
|
168
|
+
status: "not-applicable",
|
|
169
|
+
successfulLaneCount: 0,
|
|
170
|
+
requiredSuccessfulLaneCount: MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const successfulLaneCount = group.lanes.filter(({ disposition }) => disposition === "succeeded").length;
|
|
174
|
+
let status;
|
|
175
|
+
if (group.lanes.some(({ disposition }) => disposition === "open")) {
|
|
176
|
+
status = "blocked-by-open-lanes";
|
|
177
|
+
}
|
|
178
|
+
else if (lanes.some((lane) => (lane.status === "unknown" && group.lanes.some(({ id, disposition }) => (id === lane.laneId && disposition === "succeeded"))))) {
|
|
179
|
+
status = "unknown";
|
|
180
|
+
}
|
|
181
|
+
else if (successfulLaneCount < MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS) {
|
|
182
|
+
status = "insufficient-results";
|
|
183
|
+
}
|
|
184
|
+
else if (mainTurn.status === "not-started") {
|
|
185
|
+
status = "eligible";
|
|
186
|
+
}
|
|
187
|
+
else if (mainTurn.status === "running") {
|
|
188
|
+
status = "main-running";
|
|
189
|
+
}
|
|
190
|
+
else if (mainTurn.status === "needs-attention") {
|
|
191
|
+
status = "main-needs-attention";
|
|
192
|
+
}
|
|
193
|
+
else if (mainTurn.status === "succeeded") {
|
|
194
|
+
status = "complete";
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
status = "unknown";
|
|
198
|
+
}
|
|
199
|
+
return Object.freeze({
|
|
200
|
+
status,
|
|
201
|
+
successfulLaneCount,
|
|
202
|
+
requiredSuccessfulLaneCount: MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function projectCandidate(item, group, turns, lanes, mainTurn) {
|
|
206
|
+
const candidate = governingWorkItemCandidate(item);
|
|
207
|
+
if (candidate === undefined) {
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
status: "none",
|
|
210
|
+
successfulLaneTurns: Object.freeze([]),
|
|
211
|
+
observation: "observed"
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (candidate.source.type === "direct") {
|
|
215
|
+
const valid = group === undefined && item.assignee === undefined;
|
|
216
|
+
return candidateProjection(candidate, valid ? "observed" : "unknown", [], valid);
|
|
217
|
+
}
|
|
218
|
+
const sourceTurnId = candidate.source.turnId;
|
|
219
|
+
const sourceTurn = turns.find(({ id }) => id === sourceTurnId);
|
|
220
|
+
const laneTurns = group === undefined
|
|
221
|
+
? []
|
|
222
|
+
: [...group.lanes]
|
|
223
|
+
.filter(({ disposition, successfulTurnId }) => (disposition === "succeeded" && successfulTurnId !== undefined))
|
|
224
|
+
.sort((left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id))
|
|
225
|
+
.map((lane) => ({ laneId: lane.id, successfulTurnId: lane.successfulTurnId }));
|
|
226
|
+
const valid = sourceTurn !== undefined
|
|
227
|
+
&& sourceTurn.id === mainTurn.turnId
|
|
228
|
+
&& sourceTurn.status === "completed"
|
|
229
|
+
&& sourceTurn.result !== undefined
|
|
230
|
+
&& sourceTurn.executionGroupId === undefined
|
|
231
|
+
&& sourceTurn.executionLaneId === undefined
|
|
232
|
+
&& sourceTurn.sourceExecutionGroupId === group?.id
|
|
233
|
+
&& candidate.executionLaneId === undefined
|
|
234
|
+
&& candidate.executionGroupId === undefined
|
|
235
|
+
&& (group === undefined || (laneTurns.length >= MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS
|
|
236
|
+
&& lanes.filter(({ successfulTurnId }) => successfulTurnId !== undefined)
|
|
237
|
+
.every(({ status }) => status === "succeeded")));
|
|
238
|
+
return candidateProjection(candidate, valid ? "observed" : "unknown", laneTurns, valid, group?.id);
|
|
239
|
+
}
|
|
240
|
+
function candidateProjection(candidate, status, successfulLaneTurns, observed, sourceExecutionGroupId) {
|
|
241
|
+
return Object.freeze({
|
|
242
|
+
status,
|
|
243
|
+
candidateId: candidate.id,
|
|
244
|
+
sourceType: candidate.source.type,
|
|
245
|
+
...(candidate.source.type === "turn" ? { mainTurnId: candidate.source.turnId } : {}),
|
|
246
|
+
...(sourceExecutionGroupId === undefined ? {} : { sourceExecutionGroupId }),
|
|
247
|
+
successfulLaneTurns: Object.freeze(successfulLaneTurns),
|
|
248
|
+
observation: observed ? "observed" : "unobserved"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function projectNextAction(item, lanes, synthesis, mainTurn, candidate) {
|
|
252
|
+
if (["completed", "retired"].includes(item.status))
|
|
253
|
+
return action("none", [], []);
|
|
254
|
+
if (item.status === "awaiting_acceptance") {
|
|
255
|
+
return candidate.status === "observed"
|
|
256
|
+
? action("decide-candidate", ["leader"], [candidate.candidateId])
|
|
257
|
+
: action("inspect-unknown", ["leader"], candidate.candidateId === undefined ? [] : [candidate.candidateId]);
|
|
258
|
+
}
|
|
259
|
+
if (lanes.some(({ status }) => status === "unknown")) {
|
|
260
|
+
return action("inspect-unknown", ["leader"], lanes
|
|
261
|
+
.filter(({ status }) => status === "unknown")
|
|
262
|
+
.map(({ laneId }) => laneId));
|
|
263
|
+
}
|
|
264
|
+
const recoveries = lanes.filter(({ retryTurnId }) => retryTurnId !== undefined);
|
|
265
|
+
if (recoveries.length > 0) {
|
|
266
|
+
return action("retry-or-settle-lanes", ["leader"], recoveries.map(({ retryTurnId }) => retryTurnId));
|
|
267
|
+
}
|
|
268
|
+
const activeLanes = lanes.filter(({ status }) => status === "running");
|
|
269
|
+
if (activeLanes.length > 0) {
|
|
270
|
+
return action("wait-for-lanes", activeLanes.map(({ roleName }) => roleName), activeLanes.map(({ laneId }) => laneId));
|
|
271
|
+
}
|
|
272
|
+
if (synthesis.status === "insufficient-results") {
|
|
273
|
+
return action("redispatch-work", ["leader"], [item.id]);
|
|
274
|
+
}
|
|
275
|
+
if (synthesis.status === "eligible") {
|
|
276
|
+
return action("await-main-dispatch", ["controller", ...(item.assignee === undefined ? [] : [item.assignee])], [item.id]);
|
|
277
|
+
}
|
|
278
|
+
if (mainTurn.status === "running") {
|
|
279
|
+
return action("wait-for-main", mainTurn.roleName === undefined ? [] : [mainTurn.roleName], mainTurn.turnId === undefined ? [] : [mainTurn.turnId]);
|
|
280
|
+
}
|
|
281
|
+
if (mainTurn.status === "needs-attention") {
|
|
282
|
+
return mainTurn.retryTurnId === undefined
|
|
283
|
+
? action("inspect-unknown", ["leader"], mainTurn.turnId === undefined ? [] : [mainTurn.turnId])
|
|
284
|
+
: action("retry-main", ["leader"], [mainTurn.retryTurnId]);
|
|
285
|
+
}
|
|
286
|
+
if (mainTurn.status === "succeeded" && item.status === "running") {
|
|
287
|
+
return action("submit-candidate", ["leader"], [mainTurn.turnId]);
|
|
288
|
+
}
|
|
289
|
+
if (mainTurn.status === "unknown" || synthesis.status === "unknown") {
|
|
290
|
+
return action("inspect-unknown", ["leader"], mainTurn.turnId === undefined ? [item.id] : [mainTurn.turnId]);
|
|
291
|
+
}
|
|
292
|
+
if (item.status === "pending" || item.status === "failed") {
|
|
293
|
+
return action("dispatch-work", ["leader"], [item.id]);
|
|
294
|
+
}
|
|
295
|
+
return action("inspect-unknown", ["leader"], [item.id]);
|
|
296
|
+
}
|
|
297
|
+
function action(kind, owners, targetIds) {
|
|
298
|
+
return Object.freeze({
|
|
299
|
+
kind,
|
|
300
|
+
owners: Object.freeze([...new Set(owners)]),
|
|
301
|
+
targetIds: Object.freeze([...new Set(targetIds)])
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
function turnSessionStatus(turn, set) {
|
|
305
|
+
return set?.sessions[turn.effective.agentId]?.status ?? "unobserved";
|
|
306
|
+
}
|
|
307
|
+
function compareTurns(left, right) {
|
|
308
|
+
return left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id);
|
|
309
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import { enqueueRoleTurnDispatch } from "../coordination/workMailboxQueue.js";
|
|
3
|
+
import { createTurnInput } from "../context/turnInputContract.js";
|
|
4
|
+
import { contextSnapshotDeltaRefIds, freezeTurnContextSnapshot } from "../context/turnContextPack.js";
|
|
5
|
+
import { contextSnapshotRef } from "../context/contextSnapshot.js";
|
|
6
|
+
import { roleAgentSessionResumeMode } from "../executor/agentExecutor.js";
|
|
7
|
+
import { resolveEffectiveLaunch } from "../executor/effectiveLaunch.js";
|
|
8
|
+
import { createTaskEvent } from "../event/taskEvent.js";
|
|
9
|
+
import { createTurn } from "../turn/turn.js";
|
|
10
|
+
import { currentWorkItemExecutionGroup, updateWorkItemStatus } from "../workItem/workItem.js";
|
|
11
|
+
import { MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS, workItemExecutionGroupSettled } from "./workItemExecution.js";
|
|
12
|
+
export function successfulWorkItemSynthesisProducers(store, item, group) {
|
|
13
|
+
if (!workItemExecutionGroupSettled(group)) {
|
|
14
|
+
throw new Error(`WorkItem ExecutionGroup is not settled: ${item.id}/${group.id}.`);
|
|
15
|
+
}
|
|
16
|
+
return [...group.lanes]
|
|
17
|
+
.sort((left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id))
|
|
18
|
+
.flatMap((lane) => {
|
|
19
|
+
if (lane.disposition !== "succeeded")
|
|
20
|
+
return [];
|
|
21
|
+
const turn = lane.successfulTurnId === undefined
|
|
22
|
+
? null
|
|
23
|
+
: store.getTurn(item.taskId, lane.successfulTurnId);
|
|
24
|
+
if (turn === null
|
|
25
|
+
|| turn.status !== "completed"
|
|
26
|
+
|| turn.workItemId !== item.id
|
|
27
|
+
|| turn.executionGroupId !== group.id
|
|
28
|
+
|| turn.executionLaneId !== lane.id
|
|
29
|
+
|| turn.result === undefined) {
|
|
30
|
+
throw new Error(`Successful ExecutionLane has no exact Producer Turn result: ${group.id}/${lane.id}.`);
|
|
31
|
+
}
|
|
32
|
+
return [{
|
|
33
|
+
laneId: lane.id,
|
|
34
|
+
roleName: lane.roleName,
|
|
35
|
+
turnId: turn.id
|
|
36
|
+
}];
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Reconcile every settled replicated WorkItem in one Task. The Turn row is the
|
|
41
|
+
* durable caller/idempotency record: at most one initial main Turn may name a
|
|
42
|
+
* source Group, while explicit retries append more Turns with the same source.
|
|
43
|
+
*/
|
|
44
|
+
export function reconcileWorkItemMainTurns(store, taskId, now) {
|
|
45
|
+
const task = store.getTask(taskId);
|
|
46
|
+
if (task === null || task.status !== "active" || task.executionGate.state !== "enabled") {
|
|
47
|
+
return { createdTurns: [], failedWorkItemIds: [] };
|
|
48
|
+
}
|
|
49
|
+
const createdTurns = [];
|
|
50
|
+
const failedWorkItemIds = [];
|
|
51
|
+
const items = [...store.listWorkItems(taskId)].sort((left, right) => (left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id)));
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
if (item.status !== "running")
|
|
54
|
+
continue;
|
|
55
|
+
const group = currentWorkItemExecutionGroup(item);
|
|
56
|
+
if (group === undefined || !workItemExecutionGroupSettled(group))
|
|
57
|
+
continue;
|
|
58
|
+
const producers = successfulWorkItemSynthesisProducers(store, item, group);
|
|
59
|
+
if (producers.length < MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS) {
|
|
60
|
+
const summary = `ExecutionGroup ${group.id} settled with ${producers.length} successful `
|
|
61
|
+
+ `Producer result${producers.length === 1 ? "" : "s"}; at least `
|
|
62
|
+
+ `${MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS} are required.`;
|
|
63
|
+
store.saveWorkItem(taskId, updateWorkItemStatus(item, "failed", now, summary));
|
|
64
|
+
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "work.execution-group-failed", {
|
|
65
|
+
workItemId: item.id,
|
|
66
|
+
executionGroupId: group.id,
|
|
67
|
+
successfulProducerCount: String(producers.length),
|
|
68
|
+
requiredProducerCount: String(MINIMUM_WORK_ITEM_SYNTHESIS_RESULTS)
|
|
69
|
+
}, now));
|
|
70
|
+
failedWorkItemIds.push(item.id);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const existing = store.listTurns(taskId).some((turn) => (turn.purpose === "execution"
|
|
74
|
+
&& turn.workItemId === item.id
|
|
75
|
+
&& turn.sourceExecutionGroupId === group.id));
|
|
76
|
+
if (existing)
|
|
77
|
+
continue;
|
|
78
|
+
if (item.assignee === undefined) {
|
|
79
|
+
throw new Error(`Replicated WorkItem has no main assignee: ${item.id}.`);
|
|
80
|
+
}
|
|
81
|
+
const role = store.getRole(taskId, item.assignee);
|
|
82
|
+
if (role === null)
|
|
83
|
+
throw new Error(`WorkItem main Role is missing: ${taskId}/${item.assignee}.`);
|
|
84
|
+
if (store.getActiveTurn(taskId, role.name) !== null)
|
|
85
|
+
continue;
|
|
86
|
+
const workspace = role.name === "leader"
|
|
87
|
+
? store.getTaskWorkspace(taskId)
|
|
88
|
+
: store.getWorkItemWorkspace(taskId, item.id);
|
|
89
|
+
if (workspace === null) {
|
|
90
|
+
throw new Error(`WorkItem main workspace is missing: ${taskId}/${item.id}.`);
|
|
91
|
+
}
|
|
92
|
+
const visibleProjectIds = workspace.entries.map(({ projectId }) => projectId).sort();
|
|
93
|
+
const taskProjectIds = task.projectBindings.map(({ projectId }) => projectId).sort();
|
|
94
|
+
const writableProjectIds = workspace.entries
|
|
95
|
+
.filter(({ access }) => access === "write")
|
|
96
|
+
.map(({ projectId }) => projectId)
|
|
97
|
+
.sort();
|
|
98
|
+
if (!isDeepStrictEqual(visibleProjectIds, taskProjectIds)
|
|
99
|
+
|| !isDeepStrictEqual(writableProjectIds, [...item.writeProjectIds].sort())) {
|
|
100
|
+
throw new Error(`WorkItem main workspace does not match its approved scope: ${item.id}.`);
|
|
101
|
+
}
|
|
102
|
+
const effective = resolveEffectiveLaunch({
|
|
103
|
+
role,
|
|
104
|
+
purpose: "execution",
|
|
105
|
+
workspace,
|
|
106
|
+
workItemWriteProjectIds: item.writeProjectIds
|
|
107
|
+
});
|
|
108
|
+
const snapshot = freezeTurnContextSnapshot(store, {
|
|
109
|
+
taskId,
|
|
110
|
+
roleName: role.name,
|
|
111
|
+
purpose: "execution",
|
|
112
|
+
workItemId: item.id,
|
|
113
|
+
sourceExecutionGroupId: group.id,
|
|
114
|
+
workspace
|
|
115
|
+
}, now, "controller", group.assignment.contextSnapshotRef);
|
|
116
|
+
const turn = createTurn(store.nextTurnId(taskId), taskId, role.name, roleAgentSessionResumeMode(store.getTaskRoleSessionSet(taskId, role.name), effective.agentId, effective), createTurnInput({
|
|
117
|
+
source: { type: "yui", channel: "workitem-dispatch" },
|
|
118
|
+
directive: synthesisDirective(group, producers),
|
|
119
|
+
contextSnapshotRef: contextSnapshotRef(snapshot),
|
|
120
|
+
deltaRefIds: contextSnapshotDeltaRefIds(store, snapshot)
|
|
121
|
+
}), now, {
|
|
122
|
+
workItemId: item.id,
|
|
123
|
+
sourceExecutionGroupId: group.id,
|
|
124
|
+
workspace,
|
|
125
|
+
effective
|
|
126
|
+
});
|
|
127
|
+
store.saveTurn(turn);
|
|
128
|
+
store.saveActiveTurn(turn);
|
|
129
|
+
enqueueRoleTurnDispatch(store, {
|
|
130
|
+
taskId,
|
|
131
|
+
roleName: role.name,
|
|
132
|
+
turnId: turn.id,
|
|
133
|
+
reason: "workitem-synthesis-ready",
|
|
134
|
+
occurredAt: now
|
|
135
|
+
});
|
|
136
|
+
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, "turn.dispatched", {
|
|
137
|
+
turnId: turn.id,
|
|
138
|
+
role: turn.roleName,
|
|
139
|
+
purpose: turn.purpose,
|
|
140
|
+
mode: turn.mode,
|
|
141
|
+
agent: `${turn.effective.agentId}/${turn.effective.adapterId}`,
|
|
142
|
+
effectiveRevision: String(turn.effective.sourceDesiredRevision),
|
|
143
|
+
profileAccess: turn.effective.profileAccess,
|
|
144
|
+
effectivePermission: turn.effective.permission.strategy,
|
|
145
|
+
writeProjectIds: turn.effective.writeProjectIds.join(",") || "none",
|
|
146
|
+
workItemId: item.id,
|
|
147
|
+
sourceExecutionGroupId: group.id
|
|
148
|
+
}, now));
|
|
149
|
+
createdTurns.push(turn);
|
|
150
|
+
}
|
|
151
|
+
return { createdTurns, failedWorkItemIds };
|
|
152
|
+
}
|
|
153
|
+
function synthesisDirective(group, producers) {
|
|
154
|
+
return [
|
|
155
|
+
"Synthesize every frozen successful Producer result in stable Lane order.",
|
|
156
|
+
"Expand each exact source Turn from the frozen Context Snapshot and consume its original result text plus Core-authored system evidence.",
|
|
157
|
+
"Do not rerun, retry, append, or abandon any Lane. Form the final WorkItem result from these records.",
|
|
158
|
+
JSON.stringify({
|
|
159
|
+
schemaVersion: 1,
|
|
160
|
+
sourceExecutionGroupId: group.id,
|
|
161
|
+
producers
|
|
162
|
+
}, null, 2)
|
|
163
|
+
].join("\n\n");
|
|
164
|
+
}
|
|
@@ -11,10 +11,10 @@ export function createRoleSessionSet(owner, activeAgentId, now) {
|
|
|
11
11
|
updatedAt: now.toISOString()
|
|
12
12
|
};
|
|
13
13
|
return owner.scope === "global"
|
|
14
|
-
? { ...base, schemaVersion:
|
|
14
|
+
? { ...base, schemaVersion: 5 }
|
|
15
15
|
: {
|
|
16
16
|
...base,
|
|
17
|
-
schemaVersion:
|
|
17
|
+
schemaVersion: 12,
|
|
18
18
|
providerBinding: null
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -46,7 +46,7 @@ export function recordRoleAgentSession(set, input, now) {
|
|
|
46
46
|
const nativeSessionId = requireText(input.nativeSessionId, "Native session id");
|
|
47
47
|
if (set.owner.scope === "task") {
|
|
48
48
|
const historical = (set.history ?? []).find((entry) => (entry.nativeSessionId === nativeSessionId
|
|
49
|
-
|| (input.
|
|
49
|
+
|| (input.runtimeGenerationId !== undefined && entry.runtimeGenerationId === input.runtimeGenerationId)));
|
|
50
50
|
if (historical !== undefined) {
|
|
51
51
|
throw new Error("A new Task Role Session cannot reuse a historical native identity.");
|
|
52
52
|
}
|
|
@@ -78,13 +78,13 @@ export function recordRoleAgentSession(set, input, now) {
|
|
|
78
78
|
const timestamp = now.toISOString();
|
|
79
79
|
const continuing = existing?.nativeSessionId === nativeSessionId ? existing : undefined;
|
|
80
80
|
const session = {
|
|
81
|
-
schemaVersion:
|
|
81
|
+
schemaVersion: 5,
|
|
82
82
|
agentId,
|
|
83
83
|
adapterId,
|
|
84
84
|
nativeSessionId,
|
|
85
|
-
...(input.
|
|
86
|
-
? continuing?.
|
|
87
|
-
: {
|
|
85
|
+
...(input.runtimeGenerationId === undefined
|
|
86
|
+
? continuing?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: continuing.runtimeGenerationId }
|
|
87
|
+
: { runtimeGenerationId: requireText(input.runtimeGenerationId, "Runtime generation id") }),
|
|
88
88
|
...optionalSessionText("title", input.title ?? continuing?.title),
|
|
89
89
|
...optionalSessionText("preview", input.preview ?? continuing?.preview),
|
|
90
90
|
policy: input.policy,
|
|
@@ -207,7 +207,7 @@ export function retireConfirmedAbsentInactiveTaskRolePlaceholders(set, now) {
|
|
|
207
207
|
const isNeverStartedInactiveClaude = agentId !== set.activeAgentId
|
|
208
208
|
&& session.adapterId === "claude"
|
|
209
209
|
&& session.status === "active"
|
|
210
|
-
&& session.
|
|
210
|
+
&& session.runtimeGenerationId === undefined
|
|
211
211
|
&& session.recentCompletedTurnIds.length === 0;
|
|
212
212
|
if (!isNeverStartedInactiveClaude)
|
|
213
213
|
return [agentId, session];
|
|
@@ -327,7 +327,7 @@ export function detachRoleAgentSessionHost(set, now) {
|
|
|
327
327
|
if (active === undefined || active.status === "ended")
|
|
328
328
|
return set;
|
|
329
329
|
const timestamp = requireDate(now, "Role Host detach timestamp");
|
|
330
|
-
const {
|
|
330
|
+
const { runtimeGenerationId: _runtimeGenerationId, endReason: _endReason, ...session } = active;
|
|
331
331
|
let updated = validateRoleSessionSet({
|
|
332
332
|
...set,
|
|
333
333
|
sessions: {
|
|
@@ -431,7 +431,7 @@ export function validateRoleSessionSet(set) {
|
|
|
431
431
|
validateRoleAgentSession(session, agentId);
|
|
432
432
|
}
|
|
433
433
|
if (set.owner.scope === "global") {
|
|
434
|
-
if (set.schemaVersion !==
|
|
434
|
+
if (set.schemaVersion !== 5) {
|
|
435
435
|
throw new Error("Global Role session set schema version is invalid.");
|
|
436
436
|
}
|
|
437
437
|
if (Object.hasOwn(set, "providerBinding")) {
|
|
@@ -449,7 +449,7 @@ export function validateRoleSessionSet(set) {
|
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
else {
|
|
452
|
-
if (set.schemaVersion !==
|
|
452
|
+
if (set.schemaVersion !== 12) {
|
|
453
453
|
throw new Error("Task Role session set schema version is invalid.");
|
|
454
454
|
}
|
|
455
455
|
if (!Object.hasOwn(set, "providerBinding")) {
|
|
@@ -495,7 +495,7 @@ export function validateRoleSessionSet(set) {
|
|
|
495
495
|
return set;
|
|
496
496
|
}
|
|
497
497
|
export function validateRoleAgentSession(session, expectedAgentId = session.agentId) {
|
|
498
|
-
if (session.schemaVersion !==
|
|
498
|
+
if (session.schemaVersion !== 5) {
|
|
499
499
|
throw new Error(`Role Agent session schema version is invalid: ${expectedAgentId}.`);
|
|
500
500
|
}
|
|
501
501
|
const agentId = requireSafeIdentity(session.agentId, "Agent id");
|
|
@@ -510,15 +510,15 @@ export function validateRoleAgentSession(session, expectedAgentId = session.agen
|
|
|
510
510
|
// A restored opaque host may have no provider-native identity; retain its
|
|
511
511
|
// launch fence so it can be inspected or stopped without inventing identity.
|
|
512
512
|
if (session.nativeSessionId === undefined) {
|
|
513
|
-
if (session.
|
|
514
|
-
throw new Error("Role Agent session requires a native Session or
|
|
513
|
+
if (session.runtimeGenerationId === undefined) {
|
|
514
|
+
throw new Error("Role Agent session requires a native Session or runtime generation id.");
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
else {
|
|
518
518
|
requireText(session.nativeSessionId, "Native session id");
|
|
519
519
|
}
|
|
520
|
-
if (session.
|
|
521
|
-
requireSafeIdentity(session.
|
|
520
|
+
if (session.runtimeGenerationId !== undefined)
|
|
521
|
+
requireSafeIdentity(session.runtimeGenerationId, "Runtime generation id");
|
|
522
522
|
if (session.title !== undefined
|
|
523
523
|
&& optionalSessionText("title", session.title).title !== session.title) {
|
|
524
524
|
throw new Error("Role Agent session title is invalid.");
|
|
@@ -550,10 +550,10 @@ function taskRoleSessionIdentity(session) {
|
|
|
550
550
|
if (session.nativeSessionId !== undefined) {
|
|
551
551
|
return `${session.agentId}\0native\0${session.nativeSessionId}`;
|
|
552
552
|
}
|
|
553
|
-
if (session.
|
|
554
|
-
throw new Error("Opaque Task Role session requires a
|
|
553
|
+
if (session.runtimeGenerationId === undefined) {
|
|
554
|
+
throw new Error("Opaque Task Role session requires a runtime generation identity.");
|
|
555
555
|
}
|
|
556
|
-
return `${session.agentId}\
|
|
556
|
+
return `${session.agentId}\0runtime-generation\0${session.runtimeGenerationId}`;
|
|
557
557
|
}
|
|
558
558
|
function optionalSessionText(field, value) {
|
|
559
559
|
if (value === undefined)
|
|
@@ -92,12 +92,12 @@ export class ExecutorRegistry {
|
|
|
92
92
|
const request = input.mode === "new"
|
|
93
93
|
? createSessionLaunchRequest({
|
|
94
94
|
...common,
|
|
95
|
-
|
|
95
|
+
runtimeGenerationId: deliveryBase.deliveryId,
|
|
96
96
|
mode: "new"
|
|
97
97
|
})
|
|
98
98
|
: createSessionLaunchRequest({
|
|
99
99
|
...common,
|
|
100
|
-
|
|
100
|
+
runtimeGenerationId: deliveryBase.deliveryId,
|
|
101
101
|
mode: "resume",
|
|
102
102
|
nativeSessionId: input.nativeSessionId
|
|
103
103
|
});
|
|
@@ -118,7 +118,7 @@ export class ExecutorRegistry {
|
|
|
118
118
|
}
|
|
119
119
|
const delivery = {
|
|
120
120
|
...deliveryBase,
|
|
121
|
-
...(binding === undefined ? {} : {
|
|
121
|
+
...(binding === undefined ? {} : { runtimeGenerationId: binding.runtimeGenerationId }),
|
|
122
122
|
sessionStarted,
|
|
123
123
|
session,
|
|
124
124
|
};
|
|
@@ -145,27 +145,6 @@ export class ExecutorRegistry {
|
|
|
145
145
|
if (turnId === undefined) {
|
|
146
146
|
throw new Error("Runtime prompt delivery requires a Task-local Turn id.");
|
|
147
147
|
}
|
|
148
|
-
// A reused native process retains the stable descriptor path from its
|
|
149
|
-
// original control plane. Publish only the current-control source after
|
|
150
|
-
// the Turn/Session fence is durable and immediately before Provider input;
|
|
151
|
-
// the reused Hook self-refreshes its own source before the volatile
|
|
152
|
-
// fence instead of the Controller scanning history to keep it fresh.
|
|
153
|
-
if (prepared.binding.hostCreated === false
|
|
154
|
-
&& this.planner.refreshTaskRuntimeDescriptor !== undefined) {
|
|
155
|
-
if (!hasText(prepared.binding.nativeSessionId)) {
|
|
156
|
-
throw new Error("Runtime prompt delivery requires a native Session id.");
|
|
157
|
-
}
|
|
158
|
-
this.planner.refreshTaskRuntimeDescriptor({
|
|
159
|
-
taskId: input.delivery.prepared.taskId,
|
|
160
|
-
roleName: input.delivery.prepared.roleName,
|
|
161
|
-
turnId,
|
|
162
|
-
launchId: prepared.binding.launchId,
|
|
163
|
-
nativeSessionId: prepared.binding.nativeSessionId,
|
|
164
|
-
agentId: prepared.binding.agentId,
|
|
165
|
-
adapterId: prepared.binding.adapterId,
|
|
166
|
-
workspace: prepared.workspace
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
148
|
const outcome = await this.runtimePorts.promptPush.tryPush({
|
|
170
149
|
binding: prepared.binding,
|
|
171
150
|
envelope: createPromptEnvelope({
|
|
@@ -195,7 +174,7 @@ export class ExecutorRegistry {
|
|
|
195
174
|
return "unavailable";
|
|
196
175
|
const outcome = await this.runtimePorts.promptPush.trySteer({
|
|
197
176
|
owner: { scope: "task", taskId: input.taskId, roleName: input.roleName },
|
|
198
|
-
|
|
177
|
+
runtimeGenerationId: input.runtimeGenerationId,
|
|
199
178
|
agentId: input.agentId,
|
|
200
179
|
adapterId: input.adapterId,
|
|
201
180
|
nativeSessionId: input.nativeSessionId,
|
|
@@ -223,8 +202,8 @@ export class ExecutorRegistry {
|
|
|
223
202
|
|| delivery.roleName !== input.roleName
|
|
224
203
|
|| (input.turnId !== undefined
|
|
225
204
|
&& delivery.turnId !== input.turnId)
|
|
226
|
-
|| (input.
|
|
227
|
-
&& delivery.
|
|
205
|
+
|| (input.runtimeGenerationId !== undefined
|
|
206
|
+
&& delivery.runtimeGenerationId !== input.runtimeGenerationId)) {
|
|
228
207
|
continue;
|
|
229
208
|
}
|
|
230
209
|
this.#prepared.delete(deliveryId);
|
|
@@ -287,7 +266,7 @@ export class ExecutorRegistry {
|
|
|
287
266
|
...(input.nativeSessionId === undefined
|
|
288
267
|
? {}
|
|
289
268
|
: { nativeSessionId: input.nativeSessionId }),
|
|
290
|
-
...(input.
|
|
269
|
+
...(input.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: input.runtimeGenerationId }),
|
|
291
270
|
...(input.progressAt === undefined ? {} : { progressAt: input.progressAt })
|
|
292
271
|
}));
|
|
293
272
|
if (this.runtimePorts?.roleResourceInventory !== undefined
|