@zq-silk/yui 2.22.0 → 2.25.0
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/README.md +9 -4
- package/dist/artifacts/artifactCapability.js +6 -6
- package/dist/artifacts/gitArtifactRef.js +10 -10
- package/dist/artifacts/jobArtifact.js +5 -5
- package/dist/artifacts/managedGit.js +15 -12
- package/dist/artifacts/taskArtifactRepository.js +35 -33
- package/dist/cli/commandCatalog.js +2 -2
- package/dist/cli/updateCommand.js +20 -3
- package/dist/cli/updateOrchestrator.js +13 -0
- package/dist/cli/updatePorts.js +27 -0
- package/dist/cli.js +9 -2
- package/dist/commands/configCommands.js +64 -1
- package/dist/commands/projectCommands.js +9 -9
- package/dist/commands/taskCompletionGate.js +1 -1
- package/dist/commands/taskIntegrationCommands.js +1 -1
- package/dist/commands/taskPublicationAdoptCommand.js +1 -1
- package/dist/commands/taskRoleRuntimeStatus.js +4 -0
- package/dist/commands/taskUpstreamCommands.js +1 -1
- package/dist/config/configCatalog.js +3 -0
- package/dist/config/gitConfig.js +20 -0
- package/dist/config/yuiConfig.js +1 -0
- package/dist/context/currentSkills.js +32 -1
- package/dist/context/sessionBootstrapManifest.js +17 -4
- package/dist/context/sessionSkillNotice.js +33 -12
- package/dist/controlPlaneCli.js +4 -4
- package/dist/controller/clientRuntime.js +37 -18
- package/dist/controller/controller.js +16 -1
- package/dist/controller/fileSchedulerStoreAdapter.js +2 -0
- package/dist/controller/hostLifecycle.js +153 -0
- package/dist/controller/hostLifecycleChecks.js +27 -0
- package/dist/controller/hostUpgrade.js +344 -0
- package/dist/controller/jobArtifactControl.js +3 -3
- package/dist/controller/jobDefinitionControl.js +1 -1
- package/dist/controller/runtime.js +67 -16
- package/dist/controller/sessionNotify.js +5 -46
- package/dist/execution/codexThreadNaming.js +54 -43
- package/dist/executor/fileRoleLaunchPlanner.js +18 -3
- package/dist/integration/gitIntegrationService.js +1 -1
- package/dist/kernel/builtinCapabilities.js +3 -3
- package/dist/repository/gitCommand.js +153 -0
- package/dist/repository/gitCompatibility.js +3 -2
- package/dist/repository/gitWorkspace.js +579 -563
- package/dist/repository/gitWorktreeInventory.js +15 -19
- package/dist/repository/projectRefresh.js +1 -1
- package/dist/repository/taskBaseFreshness.js +1 -4
- package/dist/repository/taskWorkspacePreparer.js +1 -1
- package/dist/runtime/agentEndpoint.js +11 -1
- package/dist/runtime/agentEndpointIdentity.js +2 -0
- package/dist/runtime/agentHost.js +167 -42
- package/dist/runtime/agentHostImplementation.js +3 -1
- package/dist/runtime/codexAppServerRuntime.js +3 -0
- package/dist/runtime/codexInteractiveHost.js +62 -17
- package/dist/runtime/codexNativeAccess.js +1 -1
- package/dist/runtime/contextRecovery.js +15 -0
- package/dist/runtime/hostSessionLifecycle.js +83 -0
- package/dist/runtime/hostUpgradeGate.js +43 -0
- package/dist/runtime/lifecycleChecks.js +47 -0
- package/dist/runtime/lifecycleReservation.js +9 -1
- package/dist/runtime/nativeExecutable.js +5 -2
- package/dist/runtime/nativeTitleReceipt.js +31 -0
- package/dist/runtime/nativeTitleSync.js +192 -0
- package/dist/runtime/platform.js +11 -0
- package/dist/runtime/providerRetry.js +4 -4
- package/dist/runtime/structuredProviderHost.js +42 -10
- package/dist/storage/sqliteSchema.js +30 -0
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/taskStore.js +7 -1
- package/dist/web/webConversation.js +2 -2
- package/dist/web/webMaterials.js +19 -19
- package/dist/web/webTaskSurface.js +3 -3
- package/dist/workspace/workItemChangeSetManager.js +3 -3
- package/docs/managed-turn-and-session-runtime.md +96 -1
- package/docs/managed-turn-and-session-runtime.zh-CN.md +70 -1
- package/docs/project-refresh.md +3 -2
- package/docs/project-refresh.zh-CN.md +2 -1
- package/docs/release-workflow.md +86 -2
- package/docs/release-workflow.zh-CN.md +65 -1
- package/docs/roles-and-configuration.md +34 -0
- package/docs/roles-and-configuration.zh-CN.md +27 -0
- package/docs/storage-baseline.md +14 -1
- package/docs/storage-baseline.zh-CN.md +7 -1
- package/docs/testing/verification-levels.md +7 -7
- package/docs/testing/verification-levels.zh-CN.md +6 -6
- package/i18n/README.zh-CN.md +8 -4
- package/package.json +1 -1
- package/skills/yui-runtime/SKILL.md +7 -2
- package/skills/yui-runtime/VERSION +1 -1
- package/dist/runtime/native/darwin-x64/claude-process-owner +0 -0
- package/dist/runtime/native/darwin-x64/process-identity +0 -0
|
@@ -4,7 +4,7 @@ import { createConnection, createServer } from "node:net";
|
|
|
4
4
|
import { homedir, tmpdir } from "node:os";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
|
-
import { createSessionSkillNotice } from "../context/sessionSkillNotice.js";
|
|
7
|
+
import { createSessionSkillNotice, createSessionSkillLifecycleCheck } from "../context/sessionSkillNotice.js";
|
|
8
8
|
import { publishStructuredConversationRecoverability, publishStructuredProviderAccepted, publishStructuredProviderActivity, publishStructuredProviderAttachmentExit, publishStructuredProviderConnection, publishStructuredProviderDiagnostic, publishStructuredProviderGoal, publishStructuredProviderInputObserved, publishStructuredProviderInputSettlement, publishStructuredProviderOpened, publishStructuredProviderStarted, publishStructuredProviderTerminal, replayStructuredProviderPersistence, structuredProviderEventDelivery } from "../controller/structuredProviderObservation.js";
|
|
9
9
|
import { callController, controllerCallMayHaveApplied, ControllerClientError } from "../core/controllerClient.js";
|
|
10
10
|
import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
|
|
@@ -16,6 +16,9 @@ import { providerDeliveryFailure, providerDeliveryFailureFrom, redactAgentErrorT
|
|
|
16
16
|
import { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
|
|
17
17
|
import { AGENT_HOST_IMPLEMENTATION } from "./agentHostImplementation.js";
|
|
18
18
|
import { closeAgentHostEndpoints } from "./agentHostCleanup.js";
|
|
19
|
+
import { createHostUpgradeGate } from "./hostUpgradeGate.js";
|
|
20
|
+
import { createHostSessionLifecycle } from "./hostSessionLifecycle.js";
|
|
21
|
+
import { createNonBlockingChecks } from "./lifecycleChecks.js";
|
|
19
22
|
import { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
20
23
|
import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
|
|
21
24
|
import { runCodexInteractiveHost } from "./codexInteractiveHost.js";
|
|
@@ -83,6 +86,8 @@ export async function runAgentHost(input) {
|
|
|
83
86
|
}
|
|
84
87
|
let session;
|
|
85
88
|
const skillNotice = createSessionSkillNotice(input.home);
|
|
89
|
+
const upgrade = createHostUpgradeGate();
|
|
90
|
+
let upgradeDetaching = false;
|
|
86
91
|
// This process really holds the Endpoint code its Session runs on. The lease
|
|
87
92
|
// spans the Session's Turns, so installing a newer generation does not change
|
|
88
93
|
// the implementation under a Session that is still using this one.
|
|
@@ -112,6 +117,16 @@ export async function runAgentHost(input) {
|
|
|
112
117
|
});
|
|
113
118
|
};
|
|
114
119
|
let snapshot = hostSnapshot("idle");
|
|
120
|
+
const lifecycleChecks = createNonBlockingChecks([
|
|
121
|
+
createSessionSkillLifecycleCheck(input.home, () => (sessionPayload ?? payload).environment), {
|
|
122
|
+
id: "controller-lifecycle-hint",
|
|
123
|
+
run: (_transition, signal) => {
|
|
124
|
+
if (!signal.aborted)
|
|
125
|
+
return signalRoleMailbox(input.home, sessionPayload ?? payload);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
], error => process.stderr.write(`Session lifecycle check failed: ${errorText(error)}\n`));
|
|
129
|
+
const lifecycle = createHostSessionLifecycle({ after: lifecycleChecks });
|
|
115
130
|
let dispatchTail = Promise.resolve();
|
|
116
131
|
let promptHuman = () => { };
|
|
117
132
|
let humanConsole;
|
|
@@ -120,10 +135,23 @@ export async function runAgentHost(input) {
|
|
|
120
135
|
let modelChanging = false;
|
|
121
136
|
const recentSteerAttempts = new Map();
|
|
122
137
|
await replayExitOutbox(input.home);
|
|
138
|
+
const hostEvent = (event, fields) => ({
|
|
139
|
+
event: { ...event, processInstanceId: fields.processInstanceId, nativeSessionId: fields.nativeSessionId,
|
|
140
|
+
attemptId: fields.attemptId, nativeTurnId: fields.nativeTurnId },
|
|
141
|
+
fields
|
|
142
|
+
});
|
|
123
143
|
const updateSnapshot = (next) => {
|
|
124
|
-
|
|
144
|
+
// Validate the payload before committing the FSM; an invalid observation
|
|
145
|
+
// must not leave the public snapshot and lifecycle on different states.
|
|
146
|
+
validateSnapshot(hostSnapshot(lifecycle.state, next.fields));
|
|
147
|
+
const result = lifecycle.send(next.event);
|
|
148
|
+
if (result.status === "ignored")
|
|
149
|
+
return;
|
|
150
|
+
if (result.status === "invalid")
|
|
151
|
+
throw new Error(result.reason);
|
|
152
|
+
const { appliedGeneratedTitle: _oldTitle, ...rest } = next.fields;
|
|
125
153
|
snapshot = validateSnapshot({
|
|
126
|
-
...rest,
|
|
154
|
+
...hostSnapshot(result.state, rest),
|
|
127
155
|
...(session?.appliedGeneratedTitle === undefined ? {} : {
|
|
128
156
|
appliedGeneratedTitle: session.appliedGeneratedTitle
|
|
129
157
|
})
|
|
@@ -150,7 +178,7 @@ export async function runAgentHost(input) {
|
|
|
150
178
|
await publishStructuredProviderAccepted({
|
|
151
179
|
home: input.home, environment: observedPayload.environment, receipt
|
|
152
180
|
});
|
|
153
|
-
updateSnapshot(
|
|
181
|
+
updateSnapshot(hostEvent({ type: "accepted" }, {
|
|
154
182
|
adapterId: session.adapterId,
|
|
155
183
|
processInstanceId: session.processInstanceId,
|
|
156
184
|
nativeSessionId: receipt.nativeSessionId,
|
|
@@ -178,7 +206,7 @@ export async function runAgentHost(input) {
|
|
|
178
206
|
if (started.clientOwned || observedPayload === undefined)
|
|
179
207
|
return;
|
|
180
208
|
const observedAuthority = authority === undefined ? undefined : { ...authority };
|
|
181
|
-
updateSnapshot(
|
|
209
|
+
updateSnapshot(hostEvent({ type: "native-started" }, {
|
|
182
210
|
adapterId: observedPayload.providerControl?.adapterId,
|
|
183
211
|
processInstanceId: session?.processInstanceId,
|
|
184
212
|
nativeSessionId: started.nativeSessionId,
|
|
@@ -239,7 +267,7 @@ export async function runAgentHost(input) {
|
|
|
239
267
|
terminal
|
|
240
268
|
});
|
|
241
269
|
if (session !== undefined && terminal.conversationId === session.conversationId) {
|
|
242
|
-
updateSnapshot(
|
|
270
|
+
updateSnapshot(hostEvent({ type: "settled", occupancy: session.inspect().activeNativeTurnId === undefined ? "idle" : "busy" }, {
|
|
243
271
|
adapterId: session.adapterId,
|
|
244
272
|
processInstanceId: session.processInstanceId,
|
|
245
273
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -282,7 +310,7 @@ export async function runAgentHost(input) {
|
|
|
282
310
|
|| activeRunAttemptId !== terminalAttemptId)
|
|
283
311
|
return;
|
|
284
312
|
if (session !== undefined) {
|
|
285
|
-
updateSnapshot(
|
|
313
|
+
updateSnapshot(hostEvent({ type: "terminal" }, {
|
|
286
314
|
adapterId: terminalPayload.providerControl.adapterId,
|
|
287
315
|
processInstanceId: session.processInstanceId,
|
|
288
316
|
nativeSessionId: terminal.nativeSessionId,
|
|
@@ -306,7 +334,7 @@ export async function runAgentHost(input) {
|
|
|
306
334
|
if (session === undefined)
|
|
307
335
|
return;
|
|
308
336
|
const currentPayload = sessionPayload ?? terminalPayload;
|
|
309
|
-
updateSnapshot(
|
|
337
|
+
updateSnapshot(hostEvent({ type: "settled", occupancy: session.inspect().activeNativeTurnId === undefined ? "idle" : "busy" }, {
|
|
310
338
|
adapterId: currentPayload.providerControl.adapterId,
|
|
311
339
|
processInstanceId: session.processInstanceId,
|
|
312
340
|
nativeSessionId: terminal.nativeSessionId,
|
|
@@ -317,7 +345,7 @@ export async function runAgentHost(input) {
|
|
|
317
345
|
promptHuman();
|
|
318
346
|
}
|
|
319
347
|
catch (error) {
|
|
320
|
-
updateSnapshot(
|
|
348
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: "failed" }, {
|
|
321
349
|
adapterId: terminalPayload.providerControl.adapterId,
|
|
322
350
|
processInstanceId: session?.processInstanceId,
|
|
323
351
|
nativeSessionId: terminal.nativeSessionId,
|
|
@@ -433,10 +461,10 @@ export async function runAgentHost(input) {
|
|
|
433
461
|
conversationRecoverability = "recoverable";
|
|
434
462
|
codexClientAttachedAt = Date.now();
|
|
435
463
|
observeExit(started.session, currentPayload);
|
|
436
|
-
const
|
|
437
|
-
? ownedTurn === undefined ? "
|
|
464
|
+
const occupancy = activeRunPayload !== undefined
|
|
465
|
+
? ownedTurn === undefined ? "unknown" : "owned"
|
|
438
466
|
: started.session.inspect().activeNativeTurnId === undefined ? "idle" : "busy";
|
|
439
|
-
updateSnapshot(
|
|
467
|
+
updateSnapshot(hostEvent({ type: "connected", occupancy }, {
|
|
440
468
|
adapterId: "codex",
|
|
441
469
|
processInstanceId: started.session.processInstanceId,
|
|
442
470
|
nativeSessionId: started.session.nativeSessionId,
|
|
@@ -470,7 +498,7 @@ export async function runAgentHost(input) {
|
|
|
470
498
|
lastError = error;
|
|
471
499
|
}
|
|
472
500
|
}
|
|
473
|
-
updateSnapshot(
|
|
501
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: "failed" }, {
|
|
474
502
|
adapterId: "codex",
|
|
475
503
|
processInstanceId: disconnectedSession.processInstanceId,
|
|
476
504
|
nativeSessionId: disconnectedSession.nativeSessionId,
|
|
@@ -483,6 +511,10 @@ export async function runAgentHost(input) {
|
|
|
483
511
|
};
|
|
484
512
|
const observeExit = (providerSession, launched) => {
|
|
485
513
|
void providerSession.waitForExit().then((result) => enqueueSerialized(async () => {
|
|
514
|
+
// A drained attachment is not an ended native Session and must not
|
|
515
|
+
// trigger reconnect, cancellation, or session lifecycle replacement.
|
|
516
|
+
if (upgradeDetaching)
|
|
517
|
+
return;
|
|
486
518
|
const ownsCurrentSession = session === providerSession;
|
|
487
519
|
const currentPayload = ownsCurrentSession
|
|
488
520
|
? activeRunPayload ?? lastTerminalPayload ?? sessionPayload ?? launched : launched;
|
|
@@ -501,7 +533,7 @@ export async function runAgentHost(input) {
|
|
|
501
533
|
}
|
|
502
534
|
consecutiveCodexDisconnects += 1;
|
|
503
535
|
if (consecutiveCodexDisconnects > MAX_CONSECUTIVE_CODEX_DISCONNECTS) {
|
|
504
|
-
updateSnapshot(
|
|
536
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: "failed" }, {
|
|
505
537
|
adapterId: "codex",
|
|
506
538
|
processInstanceId: result.processInstanceId,
|
|
507
539
|
nativeSessionId: providerSession.nativeSessionId,
|
|
@@ -513,7 +545,7 @@ export async function runAgentHost(input) {
|
|
|
513
545
|
}));
|
|
514
546
|
return;
|
|
515
547
|
}
|
|
516
|
-
updateSnapshot(
|
|
548
|
+
updateSnapshot(hostEvent({ type: "disconnected" }, {
|
|
517
549
|
adapterId: "codex",
|
|
518
550
|
processInstanceId: result.processInstanceId,
|
|
519
551
|
nativeSessionId: providerSession.nativeSessionId,
|
|
@@ -583,7 +615,7 @@ export async function runAgentHost(input) {
|
|
|
583
615
|
}
|
|
584
616
|
if (hostStopRequested || !ownsCurrentSession)
|
|
585
617
|
return;
|
|
586
|
-
updateSnapshot(
|
|
618
|
+
updateSnapshot(hostEvent(failures.length === 0 ? { type: "exit" } : { type: "failure", outcome: "failed" }, {
|
|
587
619
|
adapterId: currentPayload.providerControl?.adapterId,
|
|
588
620
|
processInstanceId: result.processInstanceId,
|
|
589
621
|
nativeSessionId: providerSession.nativeSessionId,
|
|
@@ -595,7 +627,7 @@ export async function runAgentHost(input) {
|
|
|
595
627
|
? {}
|
|
596
628
|
: { detail: "Provider process exited before the active AgentRun reached a terminal boundary." })
|
|
597
629
|
}));
|
|
598
|
-
})).catch((error) => updateSnapshot(
|
|
630
|
+
})).catch((error) => updateSnapshot(hostEvent({ type: "failure", outcome: "failed" }, {
|
|
599
631
|
adapterId: launched.providerControl?.adapterId,
|
|
600
632
|
processInstanceId: providerSession.processInstanceId,
|
|
601
633
|
...authorityFields(),
|
|
@@ -610,7 +642,7 @@ export async function runAgentHost(input) {
|
|
|
610
642
|
if (activeRunPayload !== undefined
|
|
611
643
|
|| sessionPayload !== undefined
|
|
612
644
|
&& (structuredProviderEventDelivery(input.home, sessionPayload.environment).unpersisted ?? 0) > 0
|
|
613
|
-
||
|
|
645
|
+
|| !lifecycle.can({ type: "launch" })) {
|
|
614
646
|
throw new Error("Agent Host still owns an unsettled Provider Turn.");
|
|
615
647
|
}
|
|
616
648
|
const requestedAuthority = validateProviderAuthorityFence(providerControl.authority);
|
|
@@ -624,7 +656,7 @@ export async function runAgentHost(input) {
|
|
|
624
656
|
&& !sameProviderAuthorityFence(authority, requestedAuthority)) {
|
|
625
657
|
throw new Error("Agent Host launch carries a stale Provider authority fence.");
|
|
626
658
|
}
|
|
627
|
-
updateSnapshot(
|
|
659
|
+
updateSnapshot(hostEvent({ type: "launch" }, {
|
|
628
660
|
adapterId: providerControl.adapterId,
|
|
629
661
|
...(session === undefined ? {} : {
|
|
630
662
|
processInstanceId: session.processInstanceId,
|
|
@@ -734,10 +766,10 @@ export async function runAgentHost(input) {
|
|
|
734
766
|
const restoredOwnedRun = providerControl.kind === "restore"
|
|
735
767
|
? providerControl.ownedTurn
|
|
736
768
|
: undefined;
|
|
737
|
-
const
|
|
738
|
-
? "
|
|
769
|
+
const occupancy = restoredOwnedRun !== undefined
|
|
770
|
+
? "owned"
|
|
739
771
|
: session.inspect().activeNativeTurnId === undefined ? "idle" : "busy";
|
|
740
|
-
updateSnapshot(
|
|
772
|
+
updateSnapshot(hostEvent({ type: "connected", occupancy }, {
|
|
741
773
|
adapterId: providerControl.adapterId,
|
|
742
774
|
processInstanceId: session.processInstanceId,
|
|
743
775
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -769,7 +801,7 @@ export async function runAgentHost(input) {
|
|
|
769
801
|
const state = error instanceof ProviderTurnBusyError
|
|
770
802
|
? "busy"
|
|
771
803
|
: error instanceof ProviderTurnRejectedError ? "rejected" : "failed";
|
|
772
|
-
updateSnapshot(
|
|
804
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: state }, {
|
|
773
805
|
adapterId: providerControl.adapterId,
|
|
774
806
|
processInstanceId: session?.processInstanceId,
|
|
775
807
|
nativeSessionId: session?.nativeSessionId ?? providerControl.nativeSessionId,
|
|
@@ -790,6 +822,8 @@ export async function runAgentHost(input) {
|
|
|
790
822
|
};
|
|
791
823
|
const enqueueDispatch = (next) => (enqueueSerialized(() => dispatch(next)));
|
|
792
824
|
const submitRun = async (request, operation) => {
|
|
825
|
+
if (upgrade.fenced)
|
|
826
|
+
throw new ProviderTurnBusyError("Host upgrade admission is fenced.", request.run.attemptId);
|
|
793
827
|
if (session === undefined || sessionPayload === undefined) {
|
|
794
828
|
throw new Error("Agent Host has no live Provider Conversation.");
|
|
795
829
|
}
|
|
@@ -800,7 +834,7 @@ export async function runAgentHost(input) {
|
|
|
800
834
|
|| !sameProviderAuthorityFence(authority, request.authority)) {
|
|
801
835
|
throw new Error("Agent Host rejected a stale Provider writer fence.");
|
|
802
836
|
}
|
|
803
|
-
if (activeRunPayload !== undefined ||
|
|
837
|
+
if (activeRunPayload !== undefined || !lifecycle.can({ type: "submit" })
|
|
804
838
|
|| (structuredProviderEventDelivery(input.home, sessionPayload.environment).unpersisted ?? 0) > 0
|
|
805
839
|
|| session.inspect().activeNativeTurnId !== undefined) {
|
|
806
840
|
operation.failure = providerDeliveryFailure({
|
|
@@ -830,7 +864,7 @@ export async function runAgentHost(input) {
|
|
|
830
864
|
};
|
|
831
865
|
activeRunAttemptId = request.run.attemptId;
|
|
832
866
|
activeNativeTurnId = undefined;
|
|
833
|
-
updateSnapshot(
|
|
867
|
+
updateSnapshot(hostEvent({ type: "submit" }, {
|
|
834
868
|
adapterId: session.adapterId,
|
|
835
869
|
processInstanceId: session.processInstanceId,
|
|
836
870
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -853,6 +887,7 @@ export async function runAgentHost(input) {
|
|
|
853
887
|
&& typeof retry.text === "string")
|
|
854
888
|
recoveryInput = {
|
|
855
889
|
text: retry.text,
|
|
890
|
+
...(typeof retry.context === "string" ? { context: retry.context } : {}),
|
|
856
891
|
...(typeof retry.expectedFailedNativeTurnId === "string"
|
|
857
892
|
? { expectedFailedNativeTurnId: retry.expectedFailedNativeTurnId } : {})
|
|
858
893
|
};
|
|
@@ -871,8 +906,8 @@ export async function runAgentHost(input) {
|
|
|
871
906
|
const registrationUnknown = !registrationSettled
|
|
872
907
|
&& (error instanceof ControllerAcknowledgementUnknownError
|
|
873
908
|
|| error instanceof ProviderDeliveryUnknownError);
|
|
874
|
-
updateSnapshot(
|
|
875
|
-
|
|
909
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: registrationUnknown ? "delivery-unknown"
|
|
910
|
+
: error instanceof ProviderTurnBusyError ? "busy" : "failed" }, {
|
|
876
911
|
adapterId: session.adapterId,
|
|
877
912
|
processInstanceId: session.processInstanceId,
|
|
878
913
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -912,10 +947,20 @@ export async function runAgentHost(input) {
|
|
|
912
947
|
try {
|
|
913
948
|
// beginDurableProviderTurn validated current execution-environment,
|
|
914
949
|
// authority and Session identity before this native write.
|
|
915
|
-
const notice = skillNotice.prepare(recoveryInput?.text ?? request.run.boundedText, activeRunPayload.environment, session.nativeSessionId, {
|
|
950
|
+
const notice = skillNotice.prepare(session.adapterId === "codex" ? request.run.boundedText : recoveryInput?.text ?? request.run.boundedText, activeRunPayload.environment, session.nativeSessionId, { contextEpoch: session.contextEpoch });
|
|
916
951
|
const receipt = endpointReceipt(await session.submit({
|
|
917
952
|
...request.run,
|
|
918
|
-
boundedText: notice.text,
|
|
953
|
+
boundedText: session.adapterId === "codex" ? notice.inputText : notice.text,
|
|
954
|
+
...(session.adapterId !== "codex" || notice.context === undefined && recoveryInput?.context === undefined ? {} : {
|
|
955
|
+
additionalContext: {
|
|
956
|
+
...(notice.context === undefined ? {} : {
|
|
957
|
+
"yui.session-skills": { kind: "application", value: notice.context }
|
|
958
|
+
}),
|
|
959
|
+
...(recoveryInput?.context === undefined ? {} : {
|
|
960
|
+
"yui.recovery": { kind: "application", value: recoveryInput.context }
|
|
961
|
+
})
|
|
962
|
+
}
|
|
963
|
+
}),
|
|
919
964
|
...(recoveryInput === undefined ? {} : { requireQuiescent: true }),
|
|
920
965
|
...(recoveryInput?.expectedFailedNativeTurnId === undefined ? {} : {
|
|
921
966
|
expectedFailedNativeTurnId: recoveryInput.expectedFailedNativeTurnId
|
|
@@ -942,7 +987,7 @@ export async function runAgentHost(input) {
|
|
|
942
987
|
await resolveProviderTurnSubmission(input.home, durableRun, unknown);
|
|
943
988
|
throw unknown;
|
|
944
989
|
}
|
|
945
|
-
updateSnapshot(
|
|
990
|
+
updateSnapshot(hostEvent({ type: "accepted" }, {
|
|
946
991
|
adapterId: session.adapterId,
|
|
947
992
|
processInstanceId: session.processInstanceId,
|
|
948
993
|
nativeSessionId: receipt.nativeSessionId,
|
|
@@ -973,7 +1018,7 @@ export async function runAgentHost(input) {
|
|
|
973
1018
|
: error instanceof ProviderTurnBusyError
|
|
974
1019
|
? "busy"
|
|
975
1020
|
: error instanceof ProviderTurnRejectedError ? "rejected" : "failed";
|
|
976
|
-
updateSnapshot(
|
|
1021
|
+
updateSnapshot(hostEvent({ type: "failure", outcome: state }, {
|
|
977
1022
|
adapterId: session.adapterId,
|
|
978
1023
|
processInstanceId: session.processInstanceId,
|
|
979
1024
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -1035,10 +1080,13 @@ export async function runAgentHost(input) {
|
|
|
1035
1080
|
}
|
|
1036
1081
|
try {
|
|
1037
1082
|
await assertHostExecutionEnvironment(input.home, sessionPayload, session.nativeSessionId);
|
|
1038
|
-
const notice = skillNotice.prepare(request.run.boundedText, sessionPayload.environment, session.nativeSessionId);
|
|
1083
|
+
const notice = skillNotice.prepare(request.run.boundedText, sessionPayload.environment, session.nativeSessionId, { contextEpoch: session.contextEpoch });
|
|
1039
1084
|
const receipt = endpointReceipt(await session.steer({
|
|
1040
1085
|
...request.run,
|
|
1041
|
-
boundedText: notice.text,
|
|
1086
|
+
boundedText: session.adapterId === "codex" ? notice.inputText : notice.text,
|
|
1087
|
+
...(session.adapterId !== "codex" || notice.context === undefined ? {} : {
|
|
1088
|
+
additionalContext: { "yui.session-skills": { kind: "application", value: notice.context } }
|
|
1089
|
+
}),
|
|
1042
1090
|
inputRef: request.run.attemptId
|
|
1043
1091
|
}), request.run.attemptId);
|
|
1044
1092
|
if (receipt.nativeTurnId !== request.nativeTurnId) {
|
|
@@ -1067,7 +1115,7 @@ export async function runAgentHost(input) {
|
|
|
1067
1115
|
if (activeRunPayload !== undefined || session.inspect().activeNativeTurnId !== undefined
|
|
1068
1116
|
|| sessionPayload !== undefined
|
|
1069
1117
|
&& (structuredProviderEventDelivery(input.home, sessionPayload.environment).unpersisted ?? 0) > 0
|
|
1070
|
-
||
|
|
1118
|
+
|| !lifecycle.can({ type: "authority-changed" })) {
|
|
1071
1119
|
throw new Error("Agent Host authority cannot transfer while a AgentRun is unsettled.");
|
|
1072
1120
|
}
|
|
1073
1121
|
const next = validateProviderAuthorityFence(request.authority);
|
|
@@ -1079,7 +1127,7 @@ export async function runAgentHost(input) {
|
|
|
1079
1127
|
}
|
|
1080
1128
|
}
|
|
1081
1129
|
authority = next;
|
|
1082
|
-
updateSnapshot(
|
|
1130
|
+
updateSnapshot(hostEvent({ type: "authority-changed" }, {
|
|
1083
1131
|
adapterId: session.adapterId,
|
|
1084
1132
|
processInstanceId: session.processInstanceId,
|
|
1085
1133
|
nativeSessionId: session.nativeSessionId,
|
|
@@ -1138,6 +1186,64 @@ export async function runAgentHost(input) {
|
|
|
1138
1186
|
return { turn: { id: accepted.nativeTurnId, items: [], status: "inProgress", error: null } };
|
|
1139
1187
|
};
|
|
1140
1188
|
const handleControl = async (request) => {
|
|
1189
|
+
if (request.type === "prepare-upgrade" || request.type === "finish-upgrade") {
|
|
1190
|
+
upgrade.request(request, {
|
|
1191
|
+
nativeSessionId: snapshot.nativeSessionId ?? "",
|
|
1192
|
+
processInstanceId: snapshot.processInstanceId ?? "",
|
|
1193
|
+
hostGeneration: AGENT_HOST_IMPLEMENTATION.generation
|
|
1194
|
+
});
|
|
1195
|
+
if (request.type === "prepare-upgrade") {
|
|
1196
|
+
// Fence synchronously, then join the same lane as submission and
|
|
1197
|
+
// terminal publication. No check-then-submit gap on Host-owned paths.
|
|
1198
|
+
await enqueueSerialized(async () => {
|
|
1199
|
+
upgrade.request(request, {
|
|
1200
|
+
nativeSessionId: snapshot.nativeSessionId ?? "", processInstanceId: snapshot.processInstanceId ?? "",
|
|
1201
|
+
hostGeneration: AGENT_HOST_IMPLEMENTATION.generation
|
|
1202
|
+
});
|
|
1203
|
+
await upgrade.drain({
|
|
1204
|
+
busy: session === undefined || activeRunPayload !== undefined || activeNativeTurnId !== undefined
|
|
1205
|
+
|| snapshot.state !== "idle" || nativeTui !== undefined || nativeOpening !== undefined
|
|
1206
|
+
|| modelChanging || session.inspect().activeNativeTurnId !== undefined
|
|
1207
|
+
|| session.inspect().submissions.some(s => s.disposition.status === "unknown"
|
|
1208
|
+
|| s.disposition.status === "pending" && s.disposition.reason === "submitting"),
|
|
1209
|
+
events: structuredProviderEventDelivery(input.home, sessionPayload?.environment ?? payload.environment, snapshot.nativeSessionId),
|
|
1210
|
+
checkQuiescent: async () => {
|
|
1211
|
+
if (authority?.owner !== "controller" || conversationRecoverability !== "recoverable") {
|
|
1212
|
+
throw new Error("Upgrade requires an exactly resumable controller-owned native Session.");
|
|
1213
|
+
}
|
|
1214
|
+
return await session.checkQuiescent()
|
|
1215
|
+
&& session.inspect().activeNativeTurnId === undefined;
|
|
1216
|
+
},
|
|
1217
|
+
release: async () => {
|
|
1218
|
+
const events = structuredProviderEventDelivery(input.home, sessionPayload.environment, snapshot.nativeSessionId);
|
|
1219
|
+
if (events.pending !== 0 || events.unpersisted !== 0 || events.pendingTerminals !== 0 || events.failure
|
|
1220
|
+
|| session.inspect().activeNativeTurnId !== undefined
|
|
1221
|
+
|| session.nativeSessionId !== request.nativeSessionId
|
|
1222
|
+
|| session.processInstanceId !== request.processInstanceId) {
|
|
1223
|
+
throw new Error("Native execution or event delivery changed before Endpoint release.");
|
|
1224
|
+
}
|
|
1225
|
+
upgradeDetaching = true;
|
|
1226
|
+
session.detach();
|
|
1227
|
+
await endpointLease?.release();
|
|
1228
|
+
const drain = await endpointOwner.stop(endpointAdapterId, ENDPOINT_DRAIN_TIMEOUT_MS);
|
|
1229
|
+
if (!drain.quiescent)
|
|
1230
|
+
throw new Error("Endpoint release did not prove owned client/implementation drain.");
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
if (upgrade.observation?.state !== "drained")
|
|
1237
|
+
throw new Error("Host has not drained.");
|
|
1238
|
+
// The Controller persists the drain receipt before this request.
|
|
1239
|
+
// Delay close until this connection has had a chance to receive its ACK.
|
|
1240
|
+
setImmediate(() => { hostStopRequested = true; stopResolve(); });
|
|
1241
|
+
}
|
|
1242
|
+
return controlResult("accepted", { ...snapshot, hostUpgrade: upgrade.observation });
|
|
1243
|
+
}
|
|
1244
|
+
if (upgrade.fenced && ["launch", "submit-turn", "steer-turn", "set-authority", "native-open", "native-model"].includes(request.type)) {
|
|
1245
|
+
return controlResult("busy", { ...snapshot, hostUpgrade: upgrade.observation });
|
|
1246
|
+
}
|
|
1141
1247
|
if (request.type === "native-model") {
|
|
1142
1248
|
return enqueueSerialized(async () => {
|
|
1143
1249
|
const current = session;
|
|
@@ -1226,7 +1332,7 @@ export async function runAgentHost(input) {
|
|
|
1226
1332
|
const persisted = await replayStructuredProviderPersistence(input.home, sessionPayload.environment);
|
|
1227
1333
|
if (persisted.length > 0 && activeRunPayload === undefined) {
|
|
1228
1334
|
const active = session.inspect().activeNativeTurnId;
|
|
1229
|
-
updateSnapshot(
|
|
1335
|
+
updateSnapshot(hostEvent({ type: "settled", occupancy: active === undefined ? "idle" : "busy" }, {
|
|
1230
1336
|
adapterId: session.adapterId, processInstanceId: session.processInstanceId,
|
|
1231
1337
|
nativeSessionId: session.nativeSessionId, conversationId: session.conversationId,
|
|
1232
1338
|
nativeTurnId: active, ...authorityFields()
|
|
@@ -1270,7 +1376,7 @@ export async function runAgentHost(input) {
|
|
|
1270
1376
|
activeRunPayload = undefined;
|
|
1271
1377
|
activeRunAttemptId = undefined;
|
|
1272
1378
|
activeNativeTurnId = undefined;
|
|
1273
|
-
updateSnapshot(
|
|
1379
|
+
updateSnapshot(hostEvent({ type: "settled", occupancy: session.inspect().activeNativeTurnId === undefined ? "idle" : "busy" }, {
|
|
1274
1380
|
adapterId: session.adapterId, processInstanceId: session.processInstanceId,
|
|
1275
1381
|
nativeSessionId: session.nativeSessionId, conversationId: session.conversationId,
|
|
1276
1382
|
...authorityFields()
|
|
@@ -1293,9 +1399,10 @@ export async function runAgentHost(input) {
|
|
|
1293
1399
|
return requestBytes <= 8000;
|
|
1294
1400
|
}).slice(0, 8);
|
|
1295
1401
|
return controlResult("status", session === undefined
|
|
1296
|
-
? snapshot
|
|
1402
|
+
? { ...snapshot, hostUpgrade: upgrade.observation }
|
|
1297
1403
|
: validateSnapshot({
|
|
1298
1404
|
...snapshot,
|
|
1405
|
+
hostUpgrade: upgrade.observation,
|
|
1299
1406
|
nativeTui: !!nativeTui,
|
|
1300
1407
|
...(nativeRequests === undefined ? {} : { nativeRequests,
|
|
1301
1408
|
nativeRequestsOmitted: nativeRequests.length !== session.nativeAccess.requests.length }),
|
|
@@ -1403,7 +1510,7 @@ export async function runAgentHost(input) {
|
|
|
1403
1510
|
throw new Error("Unsupported Host request.");
|
|
1404
1511
|
const redeemed = await redeem(input.home, request.ticket);
|
|
1405
1512
|
if (activeRunPayload !== undefined
|
|
1406
|
-
||
|
|
1513
|
+
|| !lifecycle.can({ type: "launch" })) {
|
|
1407
1514
|
if (redeemed.providerControl?.mode === "resume"
|
|
1408
1515
|
&& redeemed.providerControl.nativeSessionId === snapshot.nativeSessionId) {
|
|
1409
1516
|
return controlResult("accepted", snapshot);
|
|
@@ -1490,6 +1597,7 @@ export async function runAgentHost(input) {
|
|
|
1490
1597
|
return 0;
|
|
1491
1598
|
}
|
|
1492
1599
|
finally {
|
|
1600
|
+
lifecycleChecks.close();
|
|
1493
1601
|
for (const [signal, handler] of handlers)
|
|
1494
1602
|
process.removeListener(signal, handler);
|
|
1495
1603
|
if (forceKillTimer !== undefined)
|
|
@@ -1577,6 +1685,9 @@ export async function sendAgentHostCancelControl(input) {
|
|
|
1577
1685
|
export async function sendAgentHostNativeControl(input) {
|
|
1578
1686
|
return sendAgentHostControl(input);
|
|
1579
1687
|
}
|
|
1688
|
+
export async function sendAgentHostUpgradeControl(input) {
|
|
1689
|
+
return sendAgentHostControl(input);
|
|
1690
|
+
}
|
|
1580
1691
|
export async function inspectAgentHost(input) {
|
|
1581
1692
|
const result = await sendAgentHostControl({
|
|
1582
1693
|
...input,
|
|
@@ -1758,7 +1869,8 @@ export async function openAgentHostControl(home, payload, snapshot, dispatch) {
|
|
|
1758
1869
|
hostImplementation: AGENT_HOST_IMPLEMENTATION,
|
|
1759
1870
|
controlCapabilities: payload.providerControl === undefined ? ["status"] : [
|
|
1760
1871
|
"status", "launch", "submit-turn", "steer-turn", "cancel", "set-authority",
|
|
1761
|
-
"native-open", "native-respond", "native-model", "reconcile-turn"
|
|
1872
|
+
"native-open", "native-respond", "native-model", "reconcile-turn",
|
|
1873
|
+
...(payload.providerControl.adapterId === "codex" ? ["prepare-upgrade", "finish-upgrade"] : [])
|
|
1762
1874
|
],
|
|
1763
1875
|
...(!["task", "global"].includes(payload.environment.YUI_SESSION_SCOPE ?? "") ? {} : {
|
|
1764
1876
|
eventDelivery: structuredProviderEventDelivery(home, payload.environment, result.snapshot.nativeSessionId)
|
|
@@ -1909,6 +2021,12 @@ function validateControl(control) {
|
|
|
1909
2021
|
}
|
|
1910
2022
|
if (control.type === "status")
|
|
1911
2023
|
return Object.freeze({ ...control });
|
|
2024
|
+
if (control.type === "prepare-upgrade" || control.type === "finish-upgrade") {
|
|
2025
|
+
for (const key of ["requestId", "nativeSessionId", "processInstanceId", "hostGeneration"]) {
|
|
2026
|
+
validateIdentity(control[key], key);
|
|
2027
|
+
}
|
|
2028
|
+
return Object.freeze({ ...control });
|
|
2029
|
+
}
|
|
1912
2030
|
if (control.type === "reconcile-turn") {
|
|
1913
2031
|
validateIdentity(control.nativeSessionId, "native Session id");
|
|
1914
2032
|
validateIdentity(control.attemptId, "Provider input attempt id");
|
|
@@ -2025,6 +2143,13 @@ function validateSnapshot(snapshot) {
|
|
|
2025
2143
|
|| value.length === 0 || value.length > 64 || value.includes("\0")))) {
|
|
2026
2144
|
throw new Error("Agent Host control capability advertisement is invalid.");
|
|
2027
2145
|
}
|
|
2146
|
+
if (snapshot.hostUpgrade !== undefined) {
|
|
2147
|
+
for (const key of ["requestId", "nativeSessionId", "processInstanceId", "hostGeneration"]) {
|
|
2148
|
+
validateIdentity(snapshot.hostUpgrade[key], key);
|
|
2149
|
+
}
|
|
2150
|
+
if (!["waiting", "drained", "failed"].includes(snapshot.hostUpgrade.state))
|
|
2151
|
+
throw new Error("Invalid Host drain state.");
|
|
2152
|
+
}
|
|
2028
2153
|
const authorityFields = [
|
|
2029
2154
|
snapshot.authorityEpoch,
|
|
2030
2155
|
snapshot.authorityOwner,
|
|
@@ -2124,11 +2249,11 @@ function signalRoleMailbox(home, payload) {
|
|
|
2124
2249
|
const taskId = payload.environment.YUI_TASK_ID;
|
|
2125
2250
|
const roleName = payload.environment.YUI_ROLE;
|
|
2126
2251
|
if (roleName === undefined)
|
|
2127
|
-
return;
|
|
2252
|
+
return Promise.resolve();
|
|
2128
2253
|
const key = taskId === undefined
|
|
2129
2254
|
? `global-role:${encodeURIComponent(roleName)}`
|
|
2130
2255
|
: `role:${encodeURIComponent(taskId)}/${encodeURIComponent(roleName)}`;
|
|
2131
|
-
|
|
2256
|
+
return callController(home, "scheduler.signal", { key }).then(() => undefined).catch(() => {
|
|
2132
2257
|
// This is a low-latency hint. Durable mailbox state and periodic
|
|
2133
2258
|
// reconciliation remain the recovery path across a Controller handover.
|
|
2134
2259
|
});
|
|
@@ -8,7 +8,9 @@ const release = detectRunningRelease(fileURLToPath(import.meta.url));
|
|
|
8
8
|
const modules = [
|
|
9
9
|
"agentHost.js", "agentHostProtocol.js", "agentHostImplementation.js",
|
|
10
10
|
"codexInteractiveHost.js", "../controller/structuredProviderObservation.js",
|
|
11
|
-
"../controller/runtimeEventInbox.js"
|
|
11
|
+
"../controller/runtimeEventInbox.js", "../context/sessionSkillNotice.js",
|
|
12
|
+
"../context/sessionBootstrapManifest.js", "../context/currentSkills.js", "contextRecovery.js", "hostUpgradeGate.js",
|
|
13
|
+
"hostSessionLifecycle.js", "lifecycleChecks.js"
|
|
12
14
|
];
|
|
13
15
|
export const AGENT_HOST_IMPLEMENTATION = Object.freeze({
|
|
14
16
|
id: "yui.agent-host",
|
|
@@ -171,6 +171,7 @@ export class CodexAppServerRuntime {
|
|
|
171
171
|
return this.startTurn({
|
|
172
172
|
conversationId: input.conversationId,
|
|
173
173
|
text: input.text,
|
|
174
|
+
...(input.additionalContext === undefined ? {} : { additionalContext: input.additionalContext }),
|
|
174
175
|
expectedNoActiveTurn: input.expectedNoActiveTurn,
|
|
175
176
|
...(input.requireQuiescent ? { requireQuiescent: true } : {}),
|
|
176
177
|
...(input.expectedFailedNativeTurnId === undefined ? {} : {
|
|
@@ -230,6 +231,7 @@ export class CodexAppServerRuntime {
|
|
|
230
231
|
try {
|
|
231
232
|
const result = await this.transport.request("turn/start", {
|
|
232
233
|
threadId,
|
|
234
|
+
...(input.additionalContext === undefined ? {} : { additionalContext: input.additionalContext }),
|
|
233
235
|
...(input.clientUserMessageId === undefined
|
|
234
236
|
? {}
|
|
235
237
|
: { clientUserMessageId: text(input.clientUserMessageId, "Codex input attempt id") }),
|
|
@@ -265,6 +267,7 @@ export class CodexAppServerRuntime {
|
|
|
265
267
|
try {
|
|
266
268
|
const result = await this.transport.request("turn/steer", {
|
|
267
269
|
threadId,
|
|
270
|
+
...(input.additionalContext === undefined ? {} : { additionalContext: input.additionalContext }),
|
|
268
271
|
expectedTurnId,
|
|
269
272
|
...(input.clientUserMessageId === undefined
|
|
270
273
|
? {}
|