@zq-silk/yui 2.22.0 → 2.23.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/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/commands/taskRoleRuntimeStatus.js +4 -0
- package/dist/context/currentSkills.js +32 -1
- package/dist/context/sessionBootstrapManifest.js +17 -4
- package/dist/context/sessionSkillNotice.js +33 -12
- 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/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/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/nativeTitleReceipt.js +31 -0
- package/dist/runtime/nativeTitleSync.js +192 -0
- package/dist/runtime/providerRetry.js +4 -4
- package/dist/runtime/structuredProviderHost.js +42 -10
- package/dist/storage/sqliteSchema.js +20 -0
- package/dist/storage/storageVersions.js +1 -1
- package/docs/managed-turn-and-session-runtime.md +96 -1
- package/docs/managed-turn-and-session-runtime.zh-CN.md +70 -1
- package/docs/release-workflow.md +28 -0
- package/docs/release-workflow.zh-CN.md +20 -0
- package/docs/storage-baseline.md +10 -1
- package/docs/storage-baseline.zh-CN.md +5 -1
- package/docs/testing/verification-levels.md +2 -2
- package/docs/testing/verification-levels.zh-CN.md +2 -2
- package/package.json +1 -1
- package/skills/yui-runtime/SKILL.md +7 -2
- package/skills/yui-runtime/VERSION +1 -1
|
@@ -2,52 +2,64 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { codexClientInitialization } from "../runtime/codexAppServerRuntime.js";
|
|
4
4
|
const DEFAULT_TIMEOUT_MS = 1_000;
|
|
5
|
-
export
|
|
6
|
-
const timeoutMs = threadNameTimeout(request.timeoutMs);
|
|
7
|
-
const client = await CodexNamingClient.start(request.command, request.environment, request.baseArgs ?? [], timeoutMs);
|
|
8
|
-
try {
|
|
9
|
-
await withTimeout(client.request("thread/name/set", {
|
|
10
|
-
threadId: requiredText(request.threadId, "Codex thread id"),
|
|
11
|
-
name: requiredThreadName(request.name)
|
|
12
|
-
}), timeoutMs, "Timed out setting Codex thread name.");
|
|
13
|
-
}
|
|
14
|
-
finally {
|
|
15
|
-
client.close();
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
class CodexNamingClient {
|
|
5
|
+
export class CodexNamingClient {
|
|
19
6
|
child;
|
|
7
|
+
accountHome;
|
|
8
|
+
exited;
|
|
20
9
|
#pending = new Map();
|
|
21
10
|
#stderr = [];
|
|
22
11
|
#nextId = 1;
|
|
23
12
|
#closed = false;
|
|
24
|
-
|
|
13
|
+
#deadline;
|
|
14
|
+
constructor(child, timeoutMs) {
|
|
25
15
|
this.child = child;
|
|
16
|
+
this.exited = new Promise(resolve => child.once("close", () => resolve()));
|
|
17
|
+
this.#deadline = setTimeout(() => {
|
|
18
|
+
this.#failAll(new Error("Native title metadata process deadline exceeded; effect may be unknown."));
|
|
19
|
+
this.close("SIGKILL");
|
|
20
|
+
}, timeoutMs);
|
|
26
21
|
const output = createInterface({ input: child.stdout });
|
|
27
|
-
output.on("line", (line) => {
|
|
22
|
+
output.on("line", (line) => {
|
|
23
|
+
try {
|
|
24
|
+
if (Buffer.byteLength(line) > 1_048_576)
|
|
25
|
+
throw new Error("Native title reply exceeds its bound.");
|
|
26
|
+
this.#receive(line);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
this.#failAll(error instanceof Error ? error : new Error(String(error)));
|
|
30
|
+
this.close();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
child.stdout.on("error", error => { this.#failAll(error); this.close(); });
|
|
28
34
|
child.stderr.setEncoding("utf8");
|
|
29
35
|
child.stderr.on("data", (chunk) => {
|
|
30
36
|
this.#stderr.push(chunk);
|
|
31
37
|
if (this.#stderr.join("").length > 16_384)
|
|
32
38
|
this.#stderr.shift();
|
|
33
39
|
});
|
|
34
|
-
child.on("error", (error) => { this.#failAll(error); });
|
|
40
|
+
child.on("error", (error) => { this.#failAll(error); this.close(); });
|
|
41
|
+
child.stdin.on("error", (error) => { this.#failAll(error); this.close(); });
|
|
35
42
|
child.on("exit", (code, signal) => {
|
|
43
|
+
clearTimeout(this.#deadline);
|
|
36
44
|
if (this.#closed)
|
|
37
45
|
return;
|
|
46
|
+
this.#closed = true;
|
|
38
47
|
const detail = this.#stderr.join("").trim();
|
|
39
48
|
this.#failAll(new Error(`Codex App Server exited (${code ?? signal ?? "unknown"})${detail.length === 0 ? "" : `: ${detail}`}`));
|
|
40
49
|
});
|
|
41
50
|
}
|
|
42
51
|
static async start(command, environment, baseArgs, timeoutMs) {
|
|
43
|
-
const
|
|
52
|
+
const deadlineMs = threadNameTimeout(timeoutMs);
|
|
53
|
+
const client = new CodexNamingClient(spawn(command, [...baseArgs, "app-server", "--listen", "stdio://"], { env: environment, stdio: ["pipe", "pipe", "pipe"] }), deadlineMs);
|
|
44
54
|
try {
|
|
45
|
-
await withTimeout(client.request("initialize", codexClientInitialization()), timeoutMs, "Timed out initializing Codex App Server for thread naming.");
|
|
55
|
+
const initialized = await withTimeout(client.request("initialize", codexClientInitialization()), timeoutMs, "Timed out initializing Codex App Server for thread naming.");
|
|
56
|
+
client.accountHome = typeof initialized.codexHome === "string" ? initialized.codexHome : undefined;
|
|
46
57
|
client.notify("initialized", {});
|
|
47
58
|
return client;
|
|
48
59
|
}
|
|
49
60
|
catch (error) {
|
|
50
61
|
client.close();
|
|
62
|
+
await client.exited;
|
|
51
63
|
throw error;
|
|
52
64
|
}
|
|
53
65
|
}
|
|
@@ -63,11 +75,19 @@ class CodexNamingClient {
|
|
|
63
75
|
notify(method, params) {
|
|
64
76
|
this.#write({ method, params });
|
|
65
77
|
}
|
|
66
|
-
close() {
|
|
78
|
+
close(signal = "SIGTERM") {
|
|
67
79
|
if (this.#closed)
|
|
68
80
|
return;
|
|
69
81
|
this.#closed = true;
|
|
70
|
-
this
|
|
82
|
+
clearTimeout(this.#deadline);
|
|
83
|
+
this.child.kill(signal);
|
|
84
|
+
// An owned metadata process must not survive a lost reply or ignored TERM.
|
|
85
|
+
const reap = setTimeout(() => {
|
|
86
|
+
if (this.child.exitCode === null && this.child.signalCode === null)
|
|
87
|
+
this.child.kill("SIGKILL");
|
|
88
|
+
}, 250);
|
|
89
|
+
reap.unref();
|
|
90
|
+
this.child.once("exit", () => clearTimeout(reap));
|
|
71
91
|
this.#failAll(new Error("Codex App Server closed."));
|
|
72
92
|
}
|
|
73
93
|
#write(value) {
|
|
@@ -94,13 +114,20 @@ class CodexNamingClient {
|
|
|
94
114
|
}
|
|
95
115
|
return;
|
|
96
116
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
try {
|
|
118
|
+
if (message.error !== undefined) {
|
|
119
|
+
const error = object(message.error, "Codex App Server error");
|
|
120
|
+
pending.reject(new Error(typeof error.message === "string" ? error.message : "Codex App Server request failed."));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
pending.resolve(object(message.result, "Codex App Server result"));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
pending.reject(error instanceof Error ? error : new Error(String(error)));
|
|
101
128
|
}
|
|
102
|
-
|
|
103
|
-
pending.
|
|
129
|
+
finally {
|
|
130
|
+
this.#pending.delete(message.id);
|
|
104
131
|
}
|
|
105
132
|
}
|
|
106
133
|
#failAll(error) {
|
|
@@ -115,22 +142,6 @@ function object(value, label) {
|
|
|
115
142
|
}
|
|
116
143
|
return value;
|
|
117
144
|
}
|
|
118
|
-
function requiredText(value, label) {
|
|
119
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
120
|
-
throw new Error(`${label} is invalid.`);
|
|
121
|
-
}
|
|
122
|
-
return value;
|
|
123
|
-
}
|
|
124
|
-
function requiredThreadName(value) {
|
|
125
|
-
if (typeof value !== "string" || value.includes("\0")) {
|
|
126
|
-
throw new Error("Codex thread name is invalid.");
|
|
127
|
-
}
|
|
128
|
-
const normalized = value.trim();
|
|
129
|
-
if (normalized.length === 0 || normalized.length > 1_024) {
|
|
130
|
-
throw new Error("Codex thread name is invalid.");
|
|
131
|
-
}
|
|
132
|
-
return normalized;
|
|
133
|
-
}
|
|
134
145
|
function threadNameTimeout(value) {
|
|
135
146
|
if (value === undefined)
|
|
136
147
|
return DEFAULT_TIMEOUT_MS;
|
|
@@ -17,7 +17,7 @@ import { managedRuntimeAdmission } from "../runtime/agentDriver.js";
|
|
|
17
17
|
import { builtinAgentEndpointImplementation, validateAgentEndpointImplementation } from "../runtime/agentEndpointIdentity.js";
|
|
18
18
|
import { builtinAgentDriverRegistry, builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
|
|
19
19
|
import { assertProviderConversationReplaceable } from "../runtime/providerRuntimeIdentity.js";
|
|
20
|
-
import { globalRoleSessionTitle, resolveTaskRoleSessionTitle } from "../runtime/sessionTitle.js";
|
|
20
|
+
import { globalRoleSessionTitle, taskRoleSessionTitle, resolveTaskRoleSessionTitle } from "../runtime/sessionTitle.js";
|
|
21
21
|
import { parseTaskRuntimeIsolationDescriptor, taskRuntimeIsolationEnvironment } from "../runtime/taskRuntimeIsolation.js";
|
|
22
22
|
import { planningRuntimeCwd } from "../storage/homeLayout.js";
|
|
23
23
|
import { resolveAgentAdapter } from "./agentAdapter.js";
|
|
@@ -225,7 +225,11 @@ export class FileRoleLaunchPlanner {
|
|
|
225
225
|
instanceCode: role.instanceCode,
|
|
226
226
|
generatedTitle: existing?.generatedTitle
|
|
227
227
|
}), input.mode === "resume" && compatibleExisting ? existing.nativeSessionId : undefined, effective, {
|
|
228
|
-
purpose
|
|
228
|
+
purpose,
|
|
229
|
+
nativeGeneratedTitle: taskRoleSessionTitle(task, role.name, {
|
|
230
|
+
executionAuthority: (input.mode === "resume" ? existing?.effective : effective)?.executionAuthority,
|
|
231
|
+
instanceCode: role.instanceCode
|
|
232
|
+
})
|
|
229
233
|
});
|
|
230
234
|
}
|
|
231
235
|
planGlobalRole(input) {
|
|
@@ -258,7 +262,10 @@ export class FileRoleLaunchPlanner {
|
|
|
258
262
|
: existing?.generatedTitle !== undefined && existing.title === existing.generatedTitle
|
|
259
263
|
? globalRoleSessionTitle(role.name, new Date(existing.createdAt), this.store.getConfig().timeZone, role.instanceCode)
|
|
260
264
|
?? `Yui ${role.name}`
|
|
261
|
-
: undefined, input.mode === "resume" && compatibleExisting ? existing.nativeSessionId : undefined, effective, { purpose: "execution"
|
|
265
|
+
: undefined, input.mode === "resume" && compatibleExisting ? existing.nativeSessionId : undefined, effective, { purpose: "execution",
|
|
266
|
+
nativeGeneratedTitle: globalRoleSessionTitle(role.name, input.mode === "resume" && existing !== undefined ? new Date(existing.createdAt) : this.#now(), this.store.getConfig().timeZone, role.instanceCode)
|
|
267
|
+
?? (input.mode === "resume" ? `Yui ${role.name}` : undefined)
|
|
268
|
+
});
|
|
262
269
|
}
|
|
263
270
|
#compile(role, input, owner, sessionTitle, knownNativeSessionId, effective, sessionPolicy) {
|
|
264
271
|
const launchRole = effectiveRoleForLaunch(role, effective);
|
|
@@ -570,6 +577,14 @@ export class FileRoleLaunchPlanner {
|
|
|
570
577
|
YUI_DRIVER_ID: driver.id,
|
|
571
578
|
YUI_WORKSPACE: effectiveWorkspace,
|
|
572
579
|
YUI_SESSION_MANIFEST: sessionContext.sessionManifestPath,
|
|
580
|
+
// A proposal only. The independent metadata lane must prove native
|
|
581
|
+
// ownership; planning never reads/waits on title effects.
|
|
582
|
+
...(configured.adapterId !== "codex" || sessionPolicy.nativeGeneratedTitle === undefined ? {} : {
|
|
583
|
+
YUI_NATIVE_TITLE_PROPOSAL: sessionPolicy.nativeGeneratedTitle
|
|
584
|
+
}),
|
|
585
|
+
...(configured.adapterId !== "codex" || input.mode !== "resume" || existingSession?.title === undefined ? {} : {
|
|
586
|
+
YUI_NATIVE_TITLE_LOCAL: existingSession.title
|
|
587
|
+
}),
|
|
573
588
|
...(configured.adapterId === "codex"
|
|
574
589
|
? { YUI_AGENT_BASE_ARGS: JSON.stringify(configured.baseArgs) }
|
|
575
590
|
: {}),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
1
2
|
import { builtinAgentEndpointImplementation, requireBuiltinAgentEndpointImplementation } from "./agentEndpointIdentity.js";
|
|
2
3
|
import { builtinAgentDriverRegistry } from "./builtinAgentDrivers.js";
|
|
3
4
|
import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
|
|
@@ -80,6 +81,12 @@ function freezeConfiguration(value) {
|
|
|
80
81
|
class BuiltinAgentEndpoint {
|
|
81
82
|
driver;
|
|
82
83
|
configuration;
|
|
84
|
+
get contextEpoch() { return this.driver.contextEpoch; }
|
|
85
|
+
async checkQuiescent() {
|
|
86
|
+
if (!this.driver.checkQuiescent)
|
|
87
|
+
throw new Error("This native Endpoint cannot prove background quiescence.");
|
|
88
|
+
return this.driver.checkQuiescent();
|
|
89
|
+
}
|
|
83
90
|
get nativeAccess() { return this.driver.nativeAccess; }
|
|
84
91
|
get appliedGeneratedTitle() { return this.driver.appliedGeneratedTitle; }
|
|
85
92
|
get ownedProcessId() { return this.driver.ownedProcessId; }
|
|
@@ -147,6 +154,7 @@ class BuiltinAgentEndpoint {
|
|
|
147
154
|
const previous = this.#attempts.get(input.attemptId);
|
|
148
155
|
if (previous !== undefined) {
|
|
149
156
|
if (previous.input.inputRef !== input.inputRef || previous.input.boundedText !== input.boundedText
|
|
157
|
+
|| !isDeepStrictEqual(previous.input.additionalContext, input.additionalContext)
|
|
150
158
|
|| previous.operation !== operation) {
|
|
151
159
|
throw new Error("Endpoint attempt identity cannot be reused for different input or operation.");
|
|
152
160
|
}
|
|
@@ -160,7 +168,9 @@ class BuiltinAgentEndpoint {
|
|
|
160
168
|
return { status: "not-submitted", error: new ProviderTurnRejectedError("Endpoint is detached.", input.attemptId) };
|
|
161
169
|
}
|
|
162
170
|
const attempt = {
|
|
163
|
-
input: Object.freeze({ ...input }
|
|
171
|
+
input: Object.freeze({ ...input, ...(input.additionalContext === undefined ? {} : {
|
|
172
|
+
additionalContext: structuredClone(input.additionalContext)
|
|
173
|
+
}) }),
|
|
164
174
|
operation,
|
|
165
175
|
disposition: { status: "pending", reason: "submitting" }
|
|
166
176
|
};
|