@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.
- package/ARCHITECTURE.md +27 -28
- package/README.md +79 -71
- package/dist/cli/commandCatalog.js +283 -136
- package/dist/cli/completion.js +3 -3
- package/dist/cli/helpRenderer.js +3 -0
- package/dist/cli/interactionPolicy.js +48 -33
- package/dist/cli/interactiveSelection.js +1 -1
- package/dist/cli/invocationRouter.js +3 -2
- package/dist/cli/roleWizard.js +8 -8
- package/dist/cli.js +189 -93
- package/dist/commands/agentCommands.js +5 -5
- package/dist/commands/configCommands.js +351 -104
- package/dist/commands/configOverview.js +60 -0
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/globalRoleCommands.js +9 -9
- package/dist/commands/profileCommands.js +8 -8
- package/dist/commands/resourcesCommands.js +6 -5
- package/dist/commands/taskCommands.js +111 -59
- package/dist/commands/taskRoleRuntimeStatus.js +3 -1
- package/dist/commands/telemetryCommands.js +11 -6
- package/dist/config/configCatalog.js +42 -0
- package/dist/config/yuiConfig.js +80 -35
- package/dist/context/sessionBootstrapManifest.js +1 -1
- package/dist/controller/clientRuntime.js +0 -2
- package/dist/controller/controller.js +21 -9
- package/dist/controller/fileSchedulerStoreAdapter.js +409 -79
- package/dist/controller/resourceInventory.js +9 -5
- package/dist/controller/runtime.js +112 -25
- package/dist/controller/runtimeLaunchCoordinator.js +18 -78
- package/dist/controller/structuredProviderObservation.js +273 -0
- package/dist/doctor/doctor.js +2 -2
- package/dist/executor/agentAdapter.js +40 -0
- package/dist/executor/agentExecutor.js +31 -7
- package/dist/executor/executorRegistry.js +11 -49
- package/dist/executor/fileRoleLaunchPlanner.js +115 -37
- package/dist/lifecycle/canonicalLifecycleEvent.js +5 -2
- package/dist/resources/autoResourceGc.js +3 -1
- package/dist/review/reviewConfig.js +0 -2
- package/dist/run/agentRun.js +2 -2
- package/dist/run/providerRetry.js +29 -16
- package/dist/run/providerRetryConfig.js +5 -3
- package/dist/runtime/agentHost.js +767 -158
- package/dist/runtime/builtinAgentDrivers.js +1 -5
- package/dist/runtime/codexAppServerRuntime.js +67 -60
- package/dist/runtime/exactControlPlane.js +7 -2
- package/dist/runtime/index.js +6 -2
- package/dist/runtime/launchBroker.js +30 -8
- package/dist/runtime/launchDiagnostics.js +1 -1
- package/dist/runtime/providerAuthorityFence.js +24 -0
- package/dist/runtime/providerControl.js +63 -0
- package/dist/runtime/providerRecoveryDecision.js +55 -0
- package/dist/runtime/providerRuntimeIdentity.js +269 -19
- package/dist/runtime/runtimeBinding.js +20 -11
- package/dist/runtime/structuredProviderHost.js +476 -0
- package/dist/runtime/tmuxAdapters.js +143 -42
- package/dist/scheduler/activeRoleRunDelivery.js +206 -120
- package/dist/scheduler/leaderWakeupProcessor.js +141 -16
- package/dist/scheduler/roleRunStall.js +12 -9
- package/dist/setup/setupCommand.js +153 -492
- package/dist/storage/compatibleTaskStore.js +9 -5
- package/dist/storage/migration/productionRegistry.js +169 -0
- package/dist/storage/taskStore.js +22 -3
- package/dist/telemetry/sqliteTelemetryStore.js +9 -1
- package/dist/telemetry/telemetryConfig.js +1 -18
- package/dist/telemetry/telemetryStore.js +2 -2
- package/dist/telemetry/telemetryWiring.js +6 -5
- package/dist/tmux/tmuxManager.js +1 -1
- package/dist/web/webSnapshot.js +5 -3
- package/i18n/README.zh-CN.md +48 -40
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +12 -5
- package/skills/yui-operator/SKILL.md +44 -6
- 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
|
+
}
|
package/dist/doctor/doctor.js
CHANGED
|
@@ -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 {
|
|
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:
|
|
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:
|
|
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 !==
|
|
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
|
|
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.
|
|
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,
|
|
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
|
-
&& ((
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|