@zq-silk/yui 0.7.1 → 0.8.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.
Files changed (73) hide show
  1. package/ARCHITECTURE.md +27 -28
  2. package/README.md +79 -71
  3. package/dist/cli/commandCatalog.js +283 -136
  4. package/dist/cli/completion.js +3 -3
  5. package/dist/cli/helpRenderer.js +3 -0
  6. package/dist/cli/interactionPolicy.js +48 -33
  7. package/dist/cli/interactiveSelection.js +1 -1
  8. package/dist/cli/invocationRouter.js +3 -2
  9. package/dist/cli/roleWizard.js +8 -8
  10. package/dist/cli.js +189 -93
  11. package/dist/commands/agentCommands.js +5 -5
  12. package/dist/commands/configCommands.js +351 -104
  13. package/dist/commands/configOverview.js +60 -0
  14. package/dist/commands/deliveryGuardPreflight.js +2 -2
  15. package/dist/commands/globalRoleCommands.js +9 -9
  16. package/dist/commands/profileCommands.js +8 -8
  17. package/dist/commands/resourcesCommands.js +6 -5
  18. package/dist/commands/taskCommands.js +111 -59
  19. package/dist/commands/taskRoleRuntimeStatus.js +3 -1
  20. package/dist/commands/telemetryCommands.js +11 -6
  21. package/dist/config/configCatalog.js +42 -0
  22. package/dist/config/yuiConfig.js +80 -35
  23. package/dist/context/sessionBootstrapManifest.js +1 -1
  24. package/dist/controller/clientRuntime.js +0 -2
  25. package/dist/controller/controller.js +21 -9
  26. package/dist/controller/fileSchedulerStoreAdapter.js +409 -79
  27. package/dist/controller/resourceInventory.js +9 -5
  28. package/dist/controller/runtime.js +112 -25
  29. package/dist/controller/runtimeLaunchCoordinator.js +18 -78
  30. package/dist/controller/structuredProviderObservation.js +273 -0
  31. package/dist/doctor/doctor.js +2 -2
  32. package/dist/executor/agentAdapter.js +40 -0
  33. package/dist/executor/agentExecutor.js +31 -7
  34. package/dist/executor/executorRegistry.js +11 -49
  35. package/dist/executor/fileRoleLaunchPlanner.js +115 -37
  36. package/dist/lifecycle/canonicalLifecycleEvent.js +5 -2
  37. package/dist/resources/autoResourceGc.js +3 -1
  38. package/dist/review/reviewConfig.js +0 -2
  39. package/dist/run/agentRun.js +2 -2
  40. package/dist/run/providerRetry.js +29 -16
  41. package/dist/run/providerRetryConfig.js +5 -3
  42. package/dist/runtime/agentHost.js +767 -158
  43. package/dist/runtime/builtinAgentDrivers.js +1 -5
  44. package/dist/runtime/codexAppServerRuntime.js +67 -60
  45. package/dist/runtime/exactControlPlane.js +7 -2
  46. package/dist/runtime/index.js +6 -2
  47. package/dist/runtime/launchBroker.js +30 -8
  48. package/dist/runtime/launchDiagnostics.js +1 -1
  49. package/dist/runtime/providerAuthorityFence.js +24 -0
  50. package/dist/runtime/providerControl.js +63 -0
  51. package/dist/runtime/providerRecoveryDecision.js +55 -0
  52. package/dist/runtime/providerRuntimeIdentity.js +269 -19
  53. package/dist/runtime/runtimeBinding.js +20 -11
  54. package/dist/runtime/structuredProviderHost.js +476 -0
  55. package/dist/runtime/tmuxAdapters.js +143 -42
  56. package/dist/scheduler/activeRoleRunDelivery.js +206 -120
  57. package/dist/scheduler/leaderWakeupProcessor.js +141 -16
  58. package/dist/scheduler/roleRunStall.js +12 -9
  59. package/dist/setup/setupCommand.js +153 -492
  60. package/dist/storage/compatibleTaskStore.js +9 -5
  61. package/dist/storage/migration/productionRegistry.js +169 -0
  62. package/dist/storage/taskStore.js +22 -3
  63. package/dist/telemetry/sqliteTelemetryStore.js +9 -1
  64. package/dist/telemetry/telemetryConfig.js +1 -18
  65. package/dist/telemetry/telemetryStore.js +2 -2
  66. package/dist/telemetry/telemetryWiring.js +6 -5
  67. package/dist/tmux/tmuxManager.js +1 -1
  68. package/dist/web/webSnapshot.js +5 -3
  69. package/i18n/README.zh-CN.md +48 -40
  70. package/package.json +1 -1
  71. package/skills/yui-leader/SKILL.md +12 -5
  72. package/skills/yui-operator/SKILL.md +44 -6
  73. package/skills/yui-runtime/SKILL.md +1 -1
@@ -0,0 +1,273 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { callController } from "../core/controllerClient.js";
3
+ import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
4
+ import { createRuntimeObservation, runtimeObservationSemanticKey } from "../runtime/runtimeObservation.js";
5
+ import { runtimeLifecycleSignalKey } from "../runtime/lifecycleReservation.js";
6
+ import { FileRuntimeEventInbox } from "./runtimeEventInbox.js";
7
+ import { resolveRuntimeHookRunFence } from "./runtimeHookRunFence.js";
8
+ let structuredSequence = 0;
9
+ export async function publishStructuredProviderAccepted(input) {
10
+ const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
11
+ const driver = builtinAgentDriverRegistry().requireByAdapterId(adapterId);
12
+ const startupSession = driver.capabilities.observation.sessionBootstrap;
13
+ const fence = resolveRuntimeHookRunFence(input.environment, adapterId, input.receipt.nativeSessionId, {
14
+ startupSession,
15
+ nativeTurnId: input.receipt.nativeTurnId
16
+ });
17
+ const observedAt = input.receipt.acceptedAt;
18
+ const commonFence = {
19
+ taskId: fence.taskId,
20
+ roleName: fence.roleName,
21
+ runId: fence.runId,
22
+ agentId: fence.agentId,
23
+ driverId: driver.id,
24
+ launchId: fence.launchId,
25
+ sessionGenerationId: fence.launchId,
26
+ conversationId: input.receipt.conversationId,
27
+ activationId: requireIdentity(input.activationId, "Provider Activation id"),
28
+ nativeSessionId: input.receipt.nativeSessionId,
29
+ nativeTurnId: input.receipt.nativeTurnId,
30
+ // The structured Host owns the exact input attempt identity. Runtime
31
+ // descriptor receipts name the Run bootstrap and must not overwrite a
32
+ // continuation or human-takeover Turn.
33
+ receiptId: input.receipt.attemptId
34
+ };
35
+ const baseSequence = nextStructuredSequence();
36
+ const observations = [observation({
37
+ kind: startupSession === "preallocated" ? "session.ready" : "session.started",
38
+ observedAt,
39
+ sequence: baseSequence,
40
+ ordinal: 0,
41
+ fence: commonFence
42
+ }), observation({
43
+ kind: "conversation.observed",
44
+ observedAt,
45
+ sequence: baseSequence,
46
+ ordinal: 1,
47
+ fence: commonFence,
48
+ payload: { recoverability: "recoverable" }
49
+ }), observation({
50
+ kind: "activation.started",
51
+ observedAt,
52
+ sequence: baseSequence,
53
+ ordinal: 2,
54
+ fence: commonFence
55
+ }), observation({
56
+ kind: "turn.accepted",
57
+ observedAt,
58
+ sequence: baseSequence,
59
+ ordinal: 3,
60
+ fence: commonFence
61
+ })];
62
+ await persistAndApply(input.home, observations, fence.taskId, fence.roleName);
63
+ }
64
+ export async function publishStructuredProviderOpened(input) {
65
+ const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
66
+ const driver = builtinAgentDriverRegistry().requireByAdapterId(adapterId);
67
+ const startupSession = driver.capabilities.observation.sessionBootstrap;
68
+ const fence = resolveRuntimeHookRunFence(input.environment, adapterId, input.nativeSessionId, { startupSession });
69
+ const commonFence = {
70
+ taskId: fence.taskId,
71
+ roleName: fence.roleName,
72
+ runId: fence.runId,
73
+ agentId: fence.agentId,
74
+ driverId: driver.id,
75
+ launchId: fence.launchId,
76
+ sessionGenerationId: fence.launchId,
77
+ conversationId: input.conversationId,
78
+ activationId: requireIdentity(input.activationId, "Provider Activation id"),
79
+ nativeSessionId: input.nativeSessionId,
80
+ ...(fence.receiptId === undefined ? {} : { receiptId: fence.receiptId })
81
+ };
82
+ const sequence = nextStructuredSequence();
83
+ const observations = [observation({
84
+ kind: startupSession === "preallocated" ? "session.ready" : "session.started",
85
+ observedAt: input.observedAt,
86
+ sequence,
87
+ ordinal: 0,
88
+ fence: commonFence
89
+ }), observation({
90
+ kind: "conversation.observed",
91
+ observedAt: input.observedAt,
92
+ sequence,
93
+ ordinal: 1,
94
+ fence: commonFence,
95
+ payload: { recoverability: input.recoverability }
96
+ }), observation({
97
+ kind: "activation.started",
98
+ observedAt: input.observedAt,
99
+ sequence,
100
+ ordinal: 2,
101
+ fence: commonFence
102
+ })];
103
+ await persistAndApply(input.home, observations, fence.taskId, fence.roleName);
104
+ }
105
+ export async function publishStructuredConversationRecoverability(input) {
106
+ const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
107
+ const driver = builtinAgentDriverRegistry().requireByAdapterId(adapterId);
108
+ const fence = resolveRuntimeHookRunFence(input.environment, adapterId, input.conversationId);
109
+ const sequence = nextStructuredSequence();
110
+ const observationFence = {
111
+ taskId: fence.taskId,
112
+ roleName: fence.roleName,
113
+ runId: fence.runId,
114
+ agentId: fence.agentId,
115
+ driverId: driver.id,
116
+ launchId: fence.launchId,
117
+ sessionGenerationId: fence.launchId,
118
+ conversationId: input.conversationId,
119
+ activationId: requireIdentity(input.activationId, "Provider Activation id"),
120
+ nativeSessionId: input.conversationId,
121
+ ...(fence.receiptId === undefined ? {} : { receiptId: fence.receiptId })
122
+ };
123
+ const observations = [observation({
124
+ kind: "activation.started",
125
+ observedAt: input.observedAt,
126
+ sequence,
127
+ ordinal: 0,
128
+ fence: observationFence
129
+ }), observation({
130
+ kind: "conversation.observed",
131
+ observedAt: input.observedAt,
132
+ sequence,
133
+ ordinal: 1,
134
+ fence: observationFence,
135
+ payload: { recoverability: input.recoverability }
136
+ })];
137
+ if (input.recoverability === "unrecoverable") {
138
+ observations.push(observation({
139
+ kind: "activation.failed",
140
+ observedAt: input.observedAt,
141
+ sequence,
142
+ ordinal: 2,
143
+ fence: observationFence,
144
+ payload: {}
145
+ }));
146
+ }
147
+ await persistAndApply(input.home, observations, fence.taskId, fence.roleName);
148
+ }
149
+ export async function publishStructuredProviderTerminal(input) {
150
+ const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
151
+ const driver = builtinAgentDriverRegistry().requireByAdapterId(adapterId);
152
+ const fence = resolveRuntimeHookRunFence(input.environment, adapterId, input.terminal.nativeSessionId, { terminal: true, nativeTurnId: input.terminal.nativeTurnId });
153
+ const kind = input.terminal.status === "completed"
154
+ ? "turn.completed"
155
+ : input.terminal.status === "cancelled" ? "turn.cancelled" : "turn.failed";
156
+ const payload = kind === "turn.completed"
157
+ ? { ...(input.terminal.summary === undefined ? {} : { summary: input.terminal.summary }) }
158
+ : kind === "turn.failed"
159
+ ? {
160
+ failure: {
161
+ code: "provider-structured-failure",
162
+ ...(input.terminal.error === undefined
163
+ ? {}
164
+ : { details: input.terminal.error })
165
+ }
166
+ }
167
+ : {};
168
+ const terminalObservation = observation({
169
+ kind,
170
+ observedAt: input.terminal.observedAt,
171
+ sequence: nextStructuredSequence(),
172
+ ordinal: 0,
173
+ fence: {
174
+ taskId: fence.taskId,
175
+ roleName: fence.roleName,
176
+ runId: fence.runId,
177
+ agentId: fence.agentId,
178
+ driverId: driver.id,
179
+ launchId: fence.launchId,
180
+ sessionGenerationId: fence.launchId,
181
+ conversationId: input.terminal.conversationId,
182
+ activationId: requireIdentity(input.activationId, "Provider Activation id"),
183
+ nativeSessionId: input.terminal.nativeSessionId,
184
+ nativeTurnId: input.terminal.nativeTurnId,
185
+ ...(fence.receiptId === undefined ? {} : { receiptId: fence.receiptId })
186
+ },
187
+ payload
188
+ });
189
+ await persistAndApply(input.home, [terminalObservation], fence.taskId, fence.roleName);
190
+ }
191
+ export async function publishStructuredProviderActivationTerminal(input) {
192
+ const adapterId = requireIdentity(input.environment.YUI_ADAPTER_ID, "Agent adapter id");
193
+ const driver = builtinAgentDriverRegistry().requireByAdapterId(adapterId);
194
+ const fence = resolveRuntimeHookRunFence(input.environment, adapterId, input.nativeSessionId);
195
+ const terminal = observation({
196
+ kind: input.status === "failed" ? "activation.failed" : "activation.ended",
197
+ observedAt: input.observedAt,
198
+ sequence: nextStructuredSequence(),
199
+ ordinal: 0,
200
+ fence: {
201
+ taskId: fence.taskId,
202
+ roleName: fence.roleName,
203
+ runId: fence.runId,
204
+ agentId: fence.agentId,
205
+ driverId: driver.id,
206
+ launchId: fence.launchId,
207
+ sessionGenerationId: fence.launchId,
208
+ conversationId: requireIdentity(input.conversationId, "Provider Conversation id"),
209
+ activationId: requireIdentity(input.activationId, "Provider Activation id"),
210
+ nativeSessionId: requireIdentity(input.nativeSessionId, "native Session id"),
211
+ ...(fence.receiptId === undefined ? {} : { receiptId: fence.receiptId })
212
+ },
213
+ payload: {}
214
+ });
215
+ await persistAndApply(input.home, [terminal], fence.taskId, fence.roleName);
216
+ }
217
+ function observation(input) {
218
+ const eventId = `agent-host-${randomUUID()}`;
219
+ const partial = {
220
+ eventId,
221
+ kind: input.kind,
222
+ fence: input.fence,
223
+ sequence: input.sequence,
224
+ payload: input.payload ?? {}
225
+ };
226
+ return createRuntimeObservation({
227
+ schemaVersion: 2,
228
+ eventId,
229
+ semanticKey: runtimeObservationSemanticKey(partial),
230
+ kind: input.kind,
231
+ authority: "provider-structured",
232
+ receivedAt: new Date().toISOString(),
233
+ observedAt: input.observedAt,
234
+ sequence: input.sequence,
235
+ ordinal: input.ordinal,
236
+ fence: input.fence,
237
+ payload: input.payload ?? {}
238
+ });
239
+ }
240
+ async function signalController(home, taskId, roleName) {
241
+ await callController(home, "scheduler.signal", {
242
+ key: runtimeLifecycleSignalKey({ scope: "task", taskId, roleName })
243
+ }, { timeoutMs: 100 }).catch(() => { });
244
+ }
245
+ function nextStructuredSequence() {
246
+ structuredSequence = (structuredSequence + 1) % Number.MAX_SAFE_INTEGER;
247
+ return structuredSequence;
248
+ }
249
+ function requireIdentity(value, label) {
250
+ if (typeof value !== "string" || value.trim().length === 0 || value.includes("\0")) {
251
+ throw new Error(`${label} is invalid.`);
252
+ }
253
+ return value.trim();
254
+ }
255
+ async function persistAndApply(home, observations, taskId, roleName) {
256
+ const inbox = new FileRuntimeEventInbox(home);
257
+ for (const entry of observations)
258
+ inbox.enqueueObservation(entry);
259
+ for (const entry of observations) {
260
+ const result = await callController(home, "runtime.observation-apply", entry, {
261
+ timeoutMs: 10_000
262
+ });
263
+ // A fast Provider can accept the initial Turn before the scheduler call
264
+ // that launched this Host has returned and committed `run.pushed`. The
265
+ // immutable inbox entry already makes that exact fenced fact durable;
266
+ // `deferred` therefore means "retained for replay", not delivery failure.
267
+ // The signal below schedules the replay after the transport transaction.
268
+ if (result.outcome !== "applied" && result.outcome !== "deferred") {
269
+ throw new Error(`Structured Provider observation was not applied: ${result.outcome ?? "unknown"}.`);
270
+ }
271
+ }
272
+ await signalController(home, taskId, roleName);
273
+ }
@@ -16,7 +16,7 @@ import { inspectStorageSchema } from "../storage/storageSchema.js";
16
16
  import { resolveTaskStoreBackendForHome } from "../storage/sqliteStore.js";
17
17
  import { resolveStoreWorkerEnabledForHome } from "../storage/storeRpc.js";
18
18
  import { classifyHome } from "../storage/upgrade/homeClassification.js";
19
- import { resolveGitBin, resolveTmuxBin } from "../config/yuiConfig.js";
19
+ import { resolveTmuxBin } from "../config/yuiConfig.js";
20
20
  import { readMigrationReceipt } from "../storage/upgrade/migrationReceipt.js";
21
21
  import { latestStorageVersionState } from "../storage/upgrade/recordVersions.js";
22
22
  import { COMMITTED_DATABASE_FILENAME } from "../storage/upgrade/sqliteStateMigration.js";
@@ -985,7 +985,7 @@ function readDurableConfigSafely(home, storageOptions) {
985
985
  const config = store.getConfig();
986
986
  return {
987
987
  tmuxBin: resolveTmuxBin(config.tmuxBin),
988
- gitBin: resolveGitBin(config.gitBin)
988
+ gitBin: "git"
989
989
  };
990
990
  }
991
991
  catch {
@@ -159,6 +159,24 @@ class CodexAdapter extends BaseAdapter {
159
159
  const launch = this.compileNew(input);
160
160
  return { ...launch, argv: [...launch.argv, "resume", nativeId(input.nativeSessionId)] };
161
161
  }
162
+ compileManagedControl(input, _mode, _nativeSessionId) {
163
+ const launch = this.compileNew(input);
164
+ const argv = [...launch.argv];
165
+ if (input.config.model !== undefined) {
166
+ const modelFlag = argv.findIndex((value, index) => (value === "--model" && argv[index + 1] === input.config.model));
167
+ if (modelFlag < 0)
168
+ throw new Error("Managed Codex launch lost its selected model.");
169
+ argv.splice(modelFlag, 2);
170
+ // App Server thread/start reads the model from resolved configuration;
171
+ // the interactive --model shortcut is not inherited by new threads.
172
+ argv.push("--config", `model=${tomlString(input.config.model)}`);
173
+ }
174
+ return {
175
+ ...launch,
176
+ argv: [...argv, "app-server", "--stdio"],
177
+ transport: "codex-app-server-stdio"
178
+ };
179
+ }
162
180
  }
163
181
  class ClaudeAdapter extends BaseAdapter {
164
182
  id = "claude";
@@ -261,6 +279,28 @@ class ClaudeAdapter extends BaseAdapter {
261
279
  const launch = super.compileNew(input);
262
280
  return { ...launch, argv: [...launch.argv, "--resume", nativeId(input.nativeSessionId)] };
263
281
  }
282
+ compileManagedControl(input, mode, nativeSessionId) {
283
+ if (nativeSessionId === undefined) {
284
+ throw new Error("Managed Claude control requires a preallocated native Session id.");
285
+ }
286
+ const sessionId = nativeId(nativeSessionId);
287
+ const launch = mode === "new"
288
+ ? super.compileNew(input)
289
+ : this.compileResume({ ...input, nativeSessionId: sessionId });
290
+ return {
291
+ ...launch,
292
+ argv: [
293
+ ...launch.argv,
294
+ ...(mode === "new" ? ["--session-id", sessionId] : []),
295
+ "-p",
296
+ "--output-format", "stream-json",
297
+ "--input-format", "stream-json",
298
+ "--verbose",
299
+ "--replay-user-messages"
300
+ ],
301
+ transport: "claude-stream-json"
302
+ };
303
+ }
264
304
  }
265
305
  function driverPreInputReadiness(adapterId) {
266
306
  const capability = builtinAgentDriverRegistry().requireByAdapterId(adapterId)
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { hasRecentTurnId, rememberRecentTurnId, validatePendingTurnCompletion, validateRecentTurnIds } from "./turnCompletion.js";
3
3
  import { effectiveLaunchSnapshotsCompatible, effectiveLaunchSnapshotsCompatibleForTaskMain, validateEffectiveLaunchSnapshot } from "./effectiveLaunch.js";
4
- import { validateProviderRuntimeBinding } from "../runtime/providerRuntimeIdentity.js";
4
+ import { rebindProviderRuntimeRun, validateProviderRuntimeBinding } from "../runtime/providerRuntimeIdentity.js";
5
5
  import { builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
6
6
  export function createRoleSessionSet(owner, activeAgentId, now) {
7
7
  const base = {
@@ -14,7 +14,7 @@ export function createRoleSessionSet(owner, activeAgentId, now) {
14
14
  ? { ...base, schemaVersion: 3 }
15
15
  : {
16
16
  ...base,
17
- schemaVersion: 5,
17
+ schemaVersion: 6,
18
18
  inFlight: null,
19
19
  providerBinding: null
20
20
  };
@@ -285,13 +285,39 @@ export function bindTaskRoleRun(set, fence, preparedAt) {
285
285
  throw new Error("Task Role session set already has an in-flight Run.");
286
286
  }
287
287
  const timestamp = requireDate(preparedAt, "Task Role Run preparedAt");
288
+ const providerBinding = set.providerBinding === null
289
+ ? null
290
+ : rebindProviderRuntimeRun(set.providerBinding, normalized.runId);
288
291
  const updated = {
289
292
  ...set,
290
293
  inFlight: { ...normalized, preparedAt: timestamp },
294
+ providerBinding,
291
295
  updatedAt: timestamp
292
296
  };
293
297
  return validateRoleSessionSet(updated);
294
298
  }
299
+ /** Re-fences the same active Run for an exact Provider retry without losing its Conversation. */
300
+ export function prepareTaskRoleRunRedispatch(set, fence, preparedAt) {
301
+ validateRoleSessionSet(set);
302
+ const normalized = normalizeTaskRoleRunFence(fence);
303
+ if (set.inFlight === null
304
+ || set.inFlight.agentId !== normalized.agentId
305
+ || set.inFlight.runId !== normalized.runId) {
306
+ throw new Error("Provider retry does not match the in-flight Task Run.");
307
+ }
308
+ if (set.providerBinding !== null
309
+ && set.providerBinding.turn !== null
310
+ && ["submitting", "accepted", "running", "delivery-unknown"]
311
+ .includes(set.providerBinding.turn.status)) {
312
+ throw new Error("Provider retry cannot redispatch an unsettled Turn.");
313
+ }
314
+ const timestamp = requireDate(preparedAt, "Task Role retry preparedAt");
315
+ return validateRoleSessionSet({
316
+ ...set,
317
+ inFlight: { ...normalized, preparedAt: timestamp },
318
+ updatedAt: timestamp
319
+ });
320
+ }
295
321
  export function bindTaskRoleProviderRuntime(set, binding, updatedAt) {
296
322
  validateRoleSessionSet(set);
297
323
  const normalized = validateProviderRuntimeBinding(binding);
@@ -446,7 +472,6 @@ export function clearTaskRoleRun(set, fence, clearedAt) {
446
472
  const updated = {
447
473
  ...set,
448
474
  inFlight: null,
449
- providerBinding: null,
450
475
  updatedAt: timestamp
451
476
  };
452
477
  return validateRoleSessionSet(updated);
@@ -519,7 +544,6 @@ export function settleTaskRoleCompletion(set, expected, settledAt) {
519
544
  }
520
545
  },
521
546
  inFlight: null,
522
- providerBinding: null,
523
547
  updatedAt: timestamp
524
548
  };
525
549
  return validateRoleSessionSet(updated);
@@ -550,7 +574,7 @@ export function validateRoleSessionSet(set) {
550
574
  }
551
575
  }
552
576
  else {
553
- if (set.schemaVersion !== 5) {
577
+ if (set.schemaVersion !== 6) {
554
578
  throw new Error("Task Role session set schema version is invalid.");
555
579
  }
556
580
  if (!Object.hasOwn(set, "inFlight")
@@ -590,10 +614,10 @@ export function validateRoleSessionSet(set) {
590
614
  throw new Error("Task Role in-flight Run Agent must be active.");
591
615
  }
592
616
  if (providerBinding !== null) {
593
- if (inFlight === null || providerBinding.runId !== inFlight.runId) {
617
+ if (inFlight !== null && providerBinding.runId !== inFlight.runId) {
594
618
  throw new Error("Provider Runtime Binding must match the in-flight Run.");
595
619
  }
596
- const session = taskSet.sessions[inFlight.agentId];
620
+ const session = taskSet.sessions[inFlight?.agentId ?? set.activeAgentId];
597
621
  if (session === undefined) {
598
622
  throw new Error("Provider Runtime Binding has no active Role Agent session.");
599
623
  }
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { createPromptEnvelope, createRuntimeBinding, createSessionLaunchRequest } from "../runtime/index.js";
2
+ import { createPromptEnvelope, createSessionLaunchRequest } from "../runtime/index.js";
3
3
  import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
4
4
  /**
5
5
  * rr13/test: Test-only liveness seam. Integration tests that spawn a real
@@ -26,9 +26,6 @@ export class ExecutorRegistry {
26
26
  this.readiness = readiness;
27
27
  this.runtimePorts = runtimePorts;
28
28
  }
29
- canRouteProviderInput(adapterId) {
30
- return adapterId === "codex" && this.runtimePorts?.providerInputRouting !== undefined;
31
- }
32
29
  async prepareRoleSession(input) {
33
30
  if (input.mode === "resume" && !hasText(input.nativeSessionId)) {
34
31
  throw new Error("Role session resume requires a native session id.");
@@ -122,10 +119,16 @@ export class ExecutorRegistry {
122
119
  sessionStarted,
123
120
  session,
124
121
  ...(input.runId !== undefined
125
- && ((sessionStarted
126
- && (planned?.initialPromptRunId ?? binding?.initialPromptRunId) === input.runId)
127
- || binding?.launchPromptUncertainRunId === input.runId)
128
- ? { inputSubmittedAtLaunch: true }
122
+ && ((binding?.initialTurnRunId === input.runId))
123
+ ? { turnAcceptedDuringLaunch: true }
124
+ : {}),
125
+ ...(input.runId !== undefined
126
+ && binding?.initialTurnDeliveryUnknownRunId === input.runId
127
+ ? { turnDeliveryUnknownDuringLaunch: true }
128
+ : {}),
129
+ ...(input.runId !== undefined
130
+ && binding?.initialTurnRejectedRunId === input.runId
131
+ ? { turnRejectedDuringLaunch: true }
129
132
  : {})
130
133
  };
131
134
  this.#prepared.set(delivery.deliveryId, {
@@ -196,47 +199,6 @@ export class ExecutorRegistry {
196
199
  }
197
200
  return outcome;
198
201
  }
199
- async routeProviderInput(input) {
200
- const prepared = this.requirePrepared(input.delivery.prepared);
201
- if (prepared.binding === undefined || this.runtimePorts?.providerInputRouting === undefined) {
202
- return "unavailable";
203
- }
204
- try {
205
- return await this.runtimePorts.providerInputRouting.route({
206
- binding: prepared.binding,
207
- attemptId: input.attemptId,
208
- mode: input.mode,
209
- text: input.text,
210
- fence: input.fence
211
- });
212
- }
213
- finally {
214
- // A routed mutation is fenced by its durable inputDelivery, not by this
215
- // process-local preparation. Never let a later Turn reuse a cached
216
- // Activation binding after this attempt (including an unknown result).
217
- this.#prepared.delete(input.delivery.prepared.deliveryId);
218
- }
219
- }
220
- async reconcileProviderInput(input) {
221
- if (this.runtimePorts?.providerInputRouting === undefined) {
222
- return "unavailable";
223
- }
224
- return this.runtimePorts.providerInputRouting.reconcile({
225
- binding: createRuntimeBinding({
226
- id: `metadata:${input.taskId}:${input.roleName}:${input.launchId}`,
227
- launchId: input.launchId,
228
- owner: { scope: "task", taskId: input.taskId, roleName: input.roleName },
229
- agentId: input.agentId,
230
- adapterId: input.adapterId,
231
- hostRef: "metadata-only",
232
- hostCreated: false,
233
- nativeSessionId: input.nativeSessionId
234
- }),
235
- attemptId: input.attemptId,
236
- mode: input.mode,
237
- fence: input.fence
238
- });
239
- }
240
202
  async notifyOperatorInputOnce(input) {
241
203
  const probe = this.readiness(input.adapterId, "operator");
242
204
  return this.tmux.sendRoleInputOnceIfReadyAsync === undefined