@cydm/happy-elves 0.1.0-beta.289 → 0.1.0-beta.294
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/apps/cli/package.json +1 -1
- package/apps/daemon/dist/relay/release.js +17 -2
- package/apps/daemon/dist/session/primitives.js +1 -0
- package/apps/daemon/package.json +1 -1
- package/apps/relay/dist/controller-handlers.js +9 -6
- package/apps/relay/dist/db.js +2 -0
- package/apps/relay/dist/http-routes.js +17 -2
- package/apps/relay/dist/http-schemas.d.ts +13 -0
- package/apps/relay/dist/http-schemas.js +1 -0
- package/apps/relay/dist/machine-handlers.js +50 -72
- package/apps/relay/dist/projections.js +1 -0
- package/apps/relay/dist/relay-context.js +3 -3
- package/apps/relay/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/packages/client/dist/client.js +48 -14
- package/packages/shared/dist/protocol-schemas.d.ts +14 -0
- package/packages/shared/dist/protocol-schemas.js +2 -1
- package/packages/shared/dist/protocol-types.d.ts +2 -1
- package/packages/shared/dist/protocol.d.ts +6 -0
- package/packages/shared/dist/protocol.js +6 -0
package/apps/cli/package.json
CHANGED
|
@@ -117,12 +117,13 @@ function releaseStages(release) {
|
|
|
117
117
|
{ name: "p0-release", command: "pnpm", args: ["verify:p0:release"], phase: "gate" },
|
|
118
118
|
{ name: "deploy-production", command: "pnpm", args: ["deploy:production"], phase: "deploy" },
|
|
119
119
|
{ name: "verify-deploy", command: "pnpm", args: ["verify:deploy"], phase: "verify" },
|
|
120
|
+
{ name: "publish-package", command: "pnpm", args: ["publish:public"], phase: "publish" },
|
|
120
121
|
];
|
|
121
122
|
for (const machineId of release.targetMachineIds ?? []) {
|
|
122
123
|
stages.push({
|
|
123
124
|
name: `daemon-update:${machineId}`,
|
|
124
125
|
command: "happy-elves",
|
|
125
|
-
args: ["remote", "daemon-update", machineId, "--version", "
|
|
126
|
+
args: ["remote", "daemon-update", machineId, "--version", "__PUBLIC_PACKAGE_VERSION__", "--wait", "--json"],
|
|
126
127
|
phase: "update",
|
|
127
128
|
});
|
|
128
129
|
}
|
|
@@ -220,7 +221,7 @@ import fs from "node:fs/promises";
|
|
|
220
221
|
import path from "node:path";
|
|
221
222
|
|
|
222
223
|
const input = ${inputJson};
|
|
223
|
-
const terminalStatuses = new Set(["gate_failed", "deploy_failed", "verify_failed", "update_failed", "notify_failed", "dogfood_failed", "succeeded", "failed"]);
|
|
224
|
+
const terminalStatuses = new Set(["gate_failed", "deploy_failed", "verify_failed", "publish_failed", "update_failed", "notify_failed", "dogfood_failed", "succeeded", "failed"]);
|
|
224
225
|
|
|
225
226
|
main().catch(async (error) => {
|
|
226
227
|
await fail("failed", error);
|
|
@@ -230,6 +231,7 @@ main().catch(async (error) => {
|
|
|
230
231
|
async function main() {
|
|
231
232
|
await fs.mkdir(path.dirname(input.logPath), { recursive: true });
|
|
232
233
|
await updateState({ status: "running", updatedAt: new Date().toISOString() });
|
|
234
|
+
input.publicPackageVersion = await publicPackageVersion();
|
|
233
235
|
await log("release runner started " + JSON.stringify({ jobId: input.jobId, profile: input.release.profile.name, repoCwd: input.repoCwd }));
|
|
234
236
|
for (const stage of input.stages) {
|
|
235
237
|
await runStage(stage);
|
|
@@ -243,6 +245,7 @@ async function runStage(stage) {
|
|
|
243
245
|
const args = stage.args.map((arg) => {
|
|
244
246
|
if (arg === "__RELEASE_SUMMARY__") return releaseSummary("Release completed");
|
|
245
247
|
if (arg === "__RELEASE_REVIEW_SUMMARY__") return releaseSummary("Release completed; please review the evidence");
|
|
248
|
+
if (arg === "__PUBLIC_PACKAGE_VERSION__") return input.publicPackageVersion;
|
|
246
249
|
return arg;
|
|
247
250
|
});
|
|
248
251
|
await log("$ " + stage.command + " " + args.map(shellQuote).join(" "));
|
|
@@ -271,11 +274,19 @@ function statusForPhase(phase) {
|
|
|
271
274
|
if (phase === "gate") return "gate_failed";
|
|
272
275
|
if (phase === "deploy") return "deploy_failed";
|
|
273
276
|
if (phase === "verify") return "verify_failed";
|
|
277
|
+
if (phase === "publish") return "publish_failed";
|
|
274
278
|
if (phase === "update") return "update_failed";
|
|
275
279
|
if (phase === "notify") return "notify_failed";
|
|
276
280
|
return "failed";
|
|
277
281
|
}
|
|
278
282
|
|
|
283
|
+
async function publicPackageVersion() {
|
|
284
|
+
if (input.release.publicPackageVersion) return input.release.publicPackageVersion;
|
|
285
|
+
const result = await run("git", ["rev-list", "--count", "HEAD"], { cwd: input.repoCwd, env: process.env });
|
|
286
|
+
if (result.exitCode !== 0) throw new Error("failed to derive public package version: " + (result.stderr || result.stdout));
|
|
287
|
+
return "0.1.0-beta." + result.stdout.trim();
|
|
288
|
+
}
|
|
289
|
+
|
|
279
290
|
async function fail(status, error) {
|
|
280
291
|
const message = error instanceof Error ? error.stack || error.message : String(error);
|
|
281
292
|
await log("release runner failed: " + message).catch(() => {});
|
|
@@ -306,6 +317,10 @@ function envForStage(stage) {
|
|
|
306
317
|
delete env.HAPPY_ELVES_RELAY_URL;
|
|
307
318
|
delete env.HAPPY_ELVES_CONTROLLER_TOKEN;
|
|
308
319
|
delete env.HAPPY_ELVES_ACCOUNT_SECRET;
|
|
320
|
+
if (stage.phase !== "publish") {
|
|
321
|
+
delete env.NPM_TOKEN;
|
|
322
|
+
delete env.NODE_AUTH_TOKEN;
|
|
323
|
+
}
|
|
309
324
|
return env;
|
|
310
325
|
}
|
|
311
326
|
const config = input.controllerConfig;
|
|
@@ -263,6 +263,7 @@ export async function handleFork(ws, config, command) {
|
|
|
263
263
|
sourceSessionId: command.sessionId,
|
|
264
264
|
sourceCheckpointId,
|
|
265
265
|
}),
|
|
266
|
+
controllerEncryptedMetadata: command.controllerEncryptedMetadata,
|
|
266
267
|
});
|
|
267
268
|
if (authoritativeForkTranscript) {
|
|
268
269
|
try {
|
package/apps/daemon/package.json
CHANGED
|
@@ -112,8 +112,8 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
112
112
|
db.exec("BEGIN");
|
|
113
113
|
try {
|
|
114
114
|
db.prepare(`INSERT INTO sessions
|
|
115
|
-
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, created_at, updated_at)
|
|
116
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, connection.accountId, message.machineId, message.agent, message.cwd, message.name, "new", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : null, createdAt, createdAt);
|
|
115
|
+
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, controller_encrypted_metadata, created_at, updated_at)
|
|
116
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, connection.accountId, message.machineId, message.agent, message.cwd, message.name, "new", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : null, message.controllerEncryptedMetadata ? JSON.stringify(message.controllerEncryptedMetadata) : null, createdAt, createdAt);
|
|
117
117
|
db.prepare(`INSERT INTO relay_admissions
|
|
118
118
|
(account_id, request_id, session_id, machine_id, kind, turn_id, admission, dispatch, created_at, updated_at)
|
|
119
119
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(connection.accountId, message.requestId, sessionId, message.machineId, "createSession", null, "accepted", "queued", createdAt, createdAt);
|
|
@@ -251,8 +251,10 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
251
251
|
return;
|
|
252
252
|
const updatedAt = now();
|
|
253
253
|
db.prepare(`UPDATE sessions
|
|
254
|
-
SET encrypted_metadata = ?,
|
|
255
|
-
|
|
254
|
+
SET encrypted_metadata = ?,
|
|
255
|
+
controller_encrypted_metadata = COALESCE(?, controller_encrypted_metadata),
|
|
256
|
+
updated_at = ?
|
|
257
|
+
WHERE id = ? AND account_id = ?`).run(JSON.stringify(message.encryptedMetadata), message.controllerEncryptedMetadata ? JSON.stringify(message.controllerEncryptedMetadata) : null, updatedAt, sessionRow.id, connection.accountId);
|
|
256
258
|
const updated = sessionSnapshot(db.prepare("SELECT * FROM sessions WHERE id = ? AND account_id = ?").get(sessionRow.id, connection.accountId));
|
|
257
259
|
broadcastControllers(connection.accountId, { type: "server:session", session: updated });
|
|
258
260
|
sendAck(connection, {
|
|
@@ -677,8 +679,8 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
677
679
|
const sessionId = randomId("ses");
|
|
678
680
|
const createdAt = now();
|
|
679
681
|
db.prepare(`INSERT INTO sessions
|
|
680
|
-
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, created_at, updated_at)
|
|
681
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, connection.accountId, message.machineId, message.agent, message.cwd, message.name, "new", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : null, createdAt, createdAt);
|
|
682
|
+
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, controller_encrypted_metadata, created_at, updated_at)
|
|
683
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, connection.accountId, message.machineId, message.agent, message.cwd, message.name, "new", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : null, message.controllerEncryptedMetadata ? JSON.stringify(message.controllerEncryptedMetadata) : null, createdAt, createdAt);
|
|
682
684
|
const session = sessionSnapshot(db.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId));
|
|
683
685
|
broadcastControllers(connection.accountId, { type: "server:session", session });
|
|
684
686
|
markCommandPending(connection.accountId, message.machineId, message.requestId);
|
|
@@ -749,6 +751,7 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
749
751
|
name: message.name,
|
|
750
752
|
sourceEncryptedMetadata: sessionRow.encrypted_metadata ? parseJson(sessionRow.encrypted_metadata, undefined) : undefined,
|
|
751
753
|
encryptedMetadata: message.encryptedMetadata,
|
|
754
|
+
controllerEncryptedMetadata: message.controllerEncryptedMetadata,
|
|
752
755
|
});
|
|
753
756
|
return;
|
|
754
757
|
}
|
package/apps/relay/dist/db.js
CHANGED
|
@@ -61,6 +61,7 @@ export function initDb(db) {
|
|
|
61
61
|
name TEXT NOT NULL,
|
|
62
62
|
status TEXT NOT NULL,
|
|
63
63
|
encrypted_metadata TEXT,
|
|
64
|
+
controller_encrypted_metadata TEXT,
|
|
64
65
|
current_head TEXT,
|
|
65
66
|
last_turn_id TEXT,
|
|
66
67
|
head_basis_event_id INTEGER,
|
|
@@ -291,6 +292,7 @@ export function initDb(db) {
|
|
|
291
292
|
ensureColumn(db, "relay_admissions", "started_at", "INTEGER");
|
|
292
293
|
ensureColumn(db, "relay_admissions", "finished_at", "INTEGER");
|
|
293
294
|
ensureColumn(db, "relay_admissions", "terminal_status", "TEXT");
|
|
295
|
+
ensureColumn(db, "sessions", "controller_encrypted_metadata", "TEXT");
|
|
294
296
|
ensureColumn(db, "relay_admissions", "last_error_code", "TEXT");
|
|
295
297
|
ensureColumn(db, "relay_dispatch_outbox", "message", "TEXT");
|
|
296
298
|
ensureColumn(db, "relay_dispatch_outbox", "command_type", "TEXT");
|
|
@@ -77,6 +77,7 @@ function sessionEventLogicalSeqValue(row) {
|
|
|
77
77
|
}
|
|
78
78
|
function canonicalEventRows(context, accountId, rows) {
|
|
79
79
|
const cache = new Map();
|
|
80
|
+
const suppressCache = new Map();
|
|
80
81
|
const seenHistorical = new Set();
|
|
81
82
|
const canonicalRows = [];
|
|
82
83
|
for (const row of rows) {
|
|
@@ -90,6 +91,20 @@ function canonicalEventRows(context, accountId, rows) {
|
|
|
90
91
|
requestTurnId = alias?.request_turn_id ?? null;
|
|
91
92
|
cache.set(key, requestTurnId);
|
|
92
93
|
}
|
|
94
|
+
if (requestTurnId) {
|
|
95
|
+
let suppress = suppressCache.get(key);
|
|
96
|
+
if (suppress === undefined) {
|
|
97
|
+
suppress = context.aliasedRuntimeEventHasRequestEvents({
|
|
98
|
+
accountId,
|
|
99
|
+
sessionId: row.session_id,
|
|
100
|
+
machineId: row.machine_id,
|
|
101
|
+
runtimeTurnId: row.turn_id,
|
|
102
|
+
});
|
|
103
|
+
suppressCache.set(key, suppress);
|
|
104
|
+
}
|
|
105
|
+
if (suppress)
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
93
108
|
const canonicalRow = requestTurnId ? { ...row, turn_id: requestTurnId } : row;
|
|
94
109
|
const historicalKey = canonicalHistoricalEventKey(canonicalRow);
|
|
95
110
|
if (historicalKey) {
|
|
@@ -284,8 +299,8 @@ export function registerHttpRoutes(app, context, controllerInviteTtlMs) {
|
|
|
284
299
|
context.db.exec("BEGIN");
|
|
285
300
|
try {
|
|
286
301
|
context.db.prepare(`INSERT INTO sessions
|
|
287
|
-
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, created_at, updated_at)
|
|
288
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, token.account_id, token.machine_id, body.agent, body.cwd, body.name, "new", body.encryptedMetadata ? JSON.stringify(body.encryptedMetadata) : null, createdAt, createdAt);
|
|
302
|
+
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, controller_encrypted_metadata, created_at, updated_at)
|
|
303
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, token.account_id, token.machine_id, body.agent, body.cwd, body.name, "new", body.encryptedMetadata ? JSON.stringify(body.encryptedMetadata) : null, body.controllerEncryptedMetadata ? JSON.stringify(body.controllerEncryptedMetadata) : null, createdAt, createdAt);
|
|
289
304
|
context.db.prepare(`INSERT INTO relay_admissions
|
|
290
305
|
(account_id, request_id, session_id, machine_id, kind, turn_id, admission, dispatch, created_at, updated_at)
|
|
291
306
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(token.account_id, body.requestId, sessionId, token.machine_id, "createSession", null, "accepted", "queued", createdAt, createdAt);
|
|
@@ -148,6 +148,19 @@ export declare const machineCreateSessionAdmissionSchema: z.ZodObject<{
|
|
|
148
148
|
ciphertext: z.ZodString;
|
|
149
149
|
}, z.core.$strip>;
|
|
150
150
|
}, z.core.$strip>>;
|
|
151
|
+
controllerEncryptedMetadata: z.ZodOptional<z.ZodObject<{
|
|
152
|
+
v: z.ZodLiteral<1>;
|
|
153
|
+
alg: z.ZodLiteral<"A256GCM">;
|
|
154
|
+
scope: z.ZodString;
|
|
155
|
+
key: z.ZodObject<{
|
|
156
|
+
nonce: z.ZodString;
|
|
157
|
+
ciphertext: z.ZodString;
|
|
158
|
+
}, z.core.$strip>;
|
|
159
|
+
data: z.ZodObject<{
|
|
160
|
+
nonce: z.ZodString;
|
|
161
|
+
ciphertext: z.ZodString;
|
|
162
|
+
}, z.core.$strip>;
|
|
163
|
+
}, z.core.$strip>>;
|
|
151
164
|
}, z.core.$strip>;
|
|
152
165
|
export declare const machinePromptAdmissionSchema: z.ZodObject<{
|
|
153
166
|
requestId: z.ZodString;
|
|
@@ -124,6 +124,7 @@ export const machineCreateSessionAdmissionSchema = z.object({
|
|
|
124
124
|
name: z.string().min(1),
|
|
125
125
|
model: z.string().min(1).optional(),
|
|
126
126
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
127
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
127
128
|
});
|
|
128
129
|
export const machinePromptAdmissionSchema = z.object({
|
|
129
130
|
requestId: z.string().min(1),
|
|
@@ -346,9 +346,9 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
346
346
|
}
|
|
347
347
|
else {
|
|
348
348
|
db.prepare(`INSERT INTO sessions
|
|
349
|
-
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata,
|
|
349
|
+
(id, account_id, machine_id, agent, cwd, name, status, encrypted_metadata, controller_encrypted_metadata,
|
|
350
350
|
current_head, last_turn_id, source_session_id, source_checkpoint_id, created_at, updated_at)
|
|
351
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(message.sessionId, connection.accountId, connection.machineId, source.agent, source.cwd, message.name ?? source.name, message.transcriptPending === true ? "running" : "ready", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : source.encrypted_metadata, message.sourceCheckpointId, source.last_turn_id, message.sourceSessionId, message.sourceCheckpointId, ts, ts);
|
|
351
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(message.sessionId, connection.accountId, connection.machineId, source.agent, source.cwd, message.name ?? source.name, message.transcriptPending === true ? "running" : "ready", message.encryptedMetadata ? JSON.stringify(message.encryptedMetadata) : source.encrypted_metadata, message.controllerEncryptedMetadata ? JSON.stringify(message.controllerEncryptedMetadata) : null, message.sourceCheckpointId, source.last_turn_id, message.sourceSessionId, message.sourceCheckpointId, ts, ts);
|
|
352
352
|
}
|
|
353
353
|
const row = db.prepare("SELECT * FROM sessions WHERE id = ?").get(message.sessionId);
|
|
354
354
|
if (row)
|
|
@@ -532,7 +532,10 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
532
532
|
broadcastControllers(connection.accountId, {
|
|
533
533
|
type: "server:sessionTranscriptReplaced",
|
|
534
534
|
session,
|
|
535
|
-
events: inserted.
|
|
535
|
+
events: inserted.flatMap((event) => {
|
|
536
|
+
const canonicalEvent = canonicalEventForControllers(db, connection.accountId, event);
|
|
537
|
+
return canonicalEvent ? [canonicalEvent] : [];
|
|
538
|
+
}),
|
|
536
539
|
hasMoreBefore: message.hasMoreBefore,
|
|
537
540
|
nextBefore: message.nextBefore,
|
|
538
541
|
});
|
|
@@ -601,7 +604,10 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
601
604
|
broadcastControllers(connection.accountId, {
|
|
602
605
|
type: "server:sessionTranscriptPrepended",
|
|
603
606
|
session,
|
|
604
|
-
events: inserted
|
|
607
|
+
events: inserted.flatMap((event) => {
|
|
608
|
+
const canonicalEvent = canonicalEventForControllers(db, connection.accountId, event);
|
|
609
|
+
return canonicalEvent ? [canonicalEvent] : [];
|
|
610
|
+
}),
|
|
605
611
|
hasMoreBefore: message.hasMoreBefore,
|
|
606
612
|
nextBefore: message.nextBefore,
|
|
607
613
|
});
|
|
@@ -619,20 +625,6 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
619
625
|
acknowledgeMachineMessage();
|
|
620
626
|
return;
|
|
621
627
|
}
|
|
622
|
-
const activeClaim = sessionBefore
|
|
623
|
-
? activePromptClaim(db, connection.accountId, message.sessionId, connection.machineId)
|
|
624
|
-
: undefined;
|
|
625
|
-
if (sessionBefore?.status === "running" && activeClaim && message.status) {
|
|
626
|
-
recordAliasesForRuntimeTurnIds({
|
|
627
|
-
accountId: connection.accountId,
|
|
628
|
-
sessionId: message.sessionId,
|
|
629
|
-
machineId: connection.machineId,
|
|
630
|
-
requestTurnId: activeClaim.turn_id,
|
|
631
|
-
requestId: activeClaim.request_id,
|
|
632
|
-
runtimeTurnIds: [message.lastTurnId, message.currentHead, message.basis.turnId],
|
|
633
|
-
recordTurnAlias,
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
628
|
const input = {
|
|
637
629
|
accountId: connection.accountId,
|
|
638
630
|
sessionId: message.sessionId,
|
|
@@ -673,21 +665,6 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
673
665
|
acknowledgeMachineMessage();
|
|
674
666
|
return;
|
|
675
667
|
}
|
|
676
|
-
if (message.status && activeClaim && sessionBefore?.status === "running") {
|
|
677
|
-
db.prepare(`UPDATE sessions
|
|
678
|
-
SET status = ?,
|
|
679
|
-
last_turn_id = COALESCE(?, last_turn_id),
|
|
680
|
-
updated_at = ?
|
|
681
|
-
WHERE id = ? AND account_id = ? AND machine_id = ? AND status = 'running'`).run(message.status, message.lastTurnId ?? message.currentHead ?? message.basis.turnId, ts, message.sessionId, connection.accountId, connection.machineId);
|
|
682
|
-
finishSessionClaim({
|
|
683
|
-
accountId: connection.accountId,
|
|
684
|
-
sessionId: message.sessionId,
|
|
685
|
-
requestId: activeClaim.request_id,
|
|
686
|
-
turnId: activeClaim.turn_id,
|
|
687
|
-
terminalStatus: message.status,
|
|
688
|
-
finishedAt: ts,
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
668
|
const row = db.prepare("SELECT * FROM sessions WHERE id = ?").get(message.sessionId);
|
|
692
669
|
if (row)
|
|
693
670
|
broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(row) });
|
|
@@ -704,17 +681,6 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
704
681
|
acknowledgeMachineMessage();
|
|
705
682
|
return;
|
|
706
683
|
}
|
|
707
|
-
maybeAliasHistoricalRuntimeEventToActiveClaim({
|
|
708
|
-
db,
|
|
709
|
-
accountId: connection.accountId,
|
|
710
|
-
sessionId: message.sessionId,
|
|
711
|
-
machineId: connection.machineId,
|
|
712
|
-
session: sessionRow,
|
|
713
|
-
turnId: message.turnId,
|
|
714
|
-
messageId: message.messageId,
|
|
715
|
-
occurredAt: message.occurredAt,
|
|
716
|
-
recordTurnAlias,
|
|
717
|
-
});
|
|
718
684
|
const event = insertEvent({
|
|
719
685
|
accountId: connection.accountId,
|
|
720
686
|
sessionId: message.sessionId,
|
|
@@ -727,7 +693,9 @@ export function handleMachineMessage(context, connection, message) {
|
|
|
727
693
|
payload: message.payload,
|
|
728
694
|
});
|
|
729
695
|
const pendingSessionRow = applyPendingSessionHeadAdvances(db, connection.accountId, message.sessionId, connection.machineId, now());
|
|
730
|
-
|
|
696
|
+
const canonicalEvent = canonicalEventForControllers(db, connection.accountId, event);
|
|
697
|
+
if (canonicalEvent)
|
|
698
|
+
broadcastControllers(connection.accountId, { type: "server:event", event: canonicalEvent });
|
|
731
699
|
if (pendingSessionRow)
|
|
732
700
|
broadcastControllers(connection.accountId, { type: "server:session", session: sessionSnapshot(pendingSessionRow) });
|
|
733
701
|
acknowledgeMachineMessage();
|
|
@@ -943,7 +911,15 @@ function applySessionHeadAdvance(db, input, ts) {
|
|
|
943
911
|
sessionRow.current_head === input.currentHead ||
|
|
944
912
|
sessionRow.last_turn_id === input.lastTurnId;
|
|
945
913
|
const shouldAdvance = !rewriteFenced && (comparison > 0 || (comparison === 0 && currentHeadIsBasisEvent));
|
|
914
|
+
const activeClaim = activePromptClaim(db, input.accountId, input.sessionId, input.machineId);
|
|
915
|
+
const activeClaimOwnsHeadAdvance = !activeClaim ||
|
|
916
|
+
input.basis.turnId === activeClaim.turn_id ||
|
|
917
|
+
input.currentHead === activeClaim.turn_id ||
|
|
918
|
+
input.lastTurnId === activeClaim.turn_id;
|
|
919
|
+
if (!activeClaimOwnsHeadAdvance)
|
|
920
|
+
return { status: "noop", session: sessionRow };
|
|
946
921
|
const shouldSettleStatus = !rewriteFenced &&
|
|
922
|
+
!activeClaim &&
|
|
947
923
|
input.status !== undefined &&
|
|
948
924
|
sessionRow.status === "running" &&
|
|
949
925
|
comparison === 0 &&
|
|
@@ -960,7 +936,7 @@ function applySessionHeadAdvance(db, input, ts) {
|
|
|
960
936
|
head_basis_turn_seq = COALESCE(?, head_basis_turn_seq),
|
|
961
937
|
encrypted_metadata = COALESCE(?, encrypted_metadata),
|
|
962
938
|
updated_at = ?
|
|
963
|
-
WHERE id = ? AND account_id = ? AND machine_id = ?`).run(
|
|
939
|
+
WHERE id = ? AND account_id = ? AND machine_id = ?`).run(shouldSettleStatus ? input.status ?? null : null, shouldAdvance ? input.currentHead : null, shouldAdvance ? input.lastTurnId : null, shouldAdvance ? basisEvent.id : null, shouldAdvance ? basisEvent.message_id : null, shouldAdvance ? nextOrder.time : null, shouldAdvance ? nextOrder.seq : null, input.encryptedMetadata ? JSON.stringify(input.encryptedMetadata) : null, ts, input.sessionId, input.accountId, input.machineId);
|
|
964
940
|
const session = db.prepare("SELECT * FROM sessions WHERE id = ?").get(input.sessionId);
|
|
965
941
|
return { status: "applied", session };
|
|
966
942
|
}
|
|
@@ -1061,29 +1037,6 @@ function promptTurnForRequestId(db, accountId, sessionId, machineId, requestId)
|
|
|
1061
1037
|
LIMIT 1`)
|
|
1062
1038
|
.get(accountId, sessionId, machineId, requestId);
|
|
1063
1039
|
}
|
|
1064
|
-
function maybeAliasHistoricalRuntimeEventToActiveClaim(input) {
|
|
1065
|
-
if (input.session.status !== "running")
|
|
1066
|
-
return;
|
|
1067
|
-
if (!isHistoricalRuntimeBackfillMessage(input.messageId, input.occurredAt))
|
|
1068
|
-
return;
|
|
1069
|
-
const claim = activePromptClaim(input.db, input.accountId, input.sessionId, input.machineId);
|
|
1070
|
-
if (!claim)
|
|
1071
|
-
return;
|
|
1072
|
-
recordAliasesForRuntimeTurnIds({
|
|
1073
|
-
accountId: input.accountId,
|
|
1074
|
-
sessionId: input.sessionId,
|
|
1075
|
-
machineId: input.machineId,
|
|
1076
|
-
requestTurnId: claim.turn_id,
|
|
1077
|
-
requestId: claim.request_id,
|
|
1078
|
-
runtimeTurnIds: [input.turnId],
|
|
1079
|
-
recordTurnAlias: input.recordTurnAlias,
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
function isHistoricalRuntimeBackfillMessage(messageId, occurredAt) {
|
|
1083
|
-
if (messageId?.startsWith("hist_") || messageId?.startsWith("tail_"))
|
|
1084
|
-
return true;
|
|
1085
|
-
return occurredAt !== undefined;
|
|
1086
|
-
}
|
|
1087
1040
|
function recordAliasesForRuntimeTurnIds(input) {
|
|
1088
1041
|
for (const runtimeTurnId of input.runtimeTurnIds) {
|
|
1089
1042
|
if (!isRuntimeTurnAliasCandidate(input.requestTurnId, runtimeTurnId))
|
|
@@ -1114,8 +1067,33 @@ function canonicalEventForControllers(db, accountId, event) {
|
|
|
1114
1067
|
WHERE account_id = ? AND session_id = ? AND machine_id = ? AND runtime_turn_id = ?
|
|
1115
1068
|
LIMIT 1`)
|
|
1116
1069
|
.get(accountId, event.sessionId, event.machineId, event.turnId);
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1070
|
+
if (!alias || alias.request_turn_id === event.turnId)
|
|
1071
|
+
return event;
|
|
1072
|
+
if (aliasedRuntimeEventHasRequestEvents(db, {
|
|
1073
|
+
accountId,
|
|
1074
|
+
sessionId: event.sessionId,
|
|
1075
|
+
machineId: event.machineId,
|
|
1076
|
+
runtimeTurnId: event.turnId,
|
|
1077
|
+
})) {
|
|
1078
|
+
return undefined;
|
|
1079
|
+
}
|
|
1080
|
+
return { ...event, turnId: alias.request_turn_id };
|
|
1081
|
+
}
|
|
1082
|
+
function aliasedRuntimeEventHasRequestEvents(db, params) {
|
|
1083
|
+
const alias = db
|
|
1084
|
+
.prepare(`SELECT request_turn_id FROM session_turn_aliases
|
|
1085
|
+
WHERE account_id = ? AND session_id = ? AND machine_id = ? AND runtime_turn_id = ?
|
|
1086
|
+
LIMIT 1`)
|
|
1087
|
+
.get(params.accountId, params.sessionId, params.machineId, params.runtimeTurnId);
|
|
1088
|
+
if (!alias || alias.request_turn_id === params.runtimeTurnId)
|
|
1089
|
+
return false;
|
|
1090
|
+
const existing = db
|
|
1091
|
+
.prepare(`SELECT COUNT(*) AS count FROM (
|
|
1092
|
+
SELECT 1 FROM session_events
|
|
1093
|
+
WHERE account_id = ? AND session_id = ? AND machine_id = ? AND turn_id = ?
|
|
1094
|
+
LIMIT 3
|
|
1095
|
+
)`)
|
|
1096
|
+
.get(params.accountId, params.sessionId, params.machineId, alias.request_turn_id);
|
|
1097
|
+
return (existing?.count ?? 0) >= 3;
|
|
1120
1098
|
}
|
|
1121
1099
|
//# sourceMappingURL=machine-handlers.js.map
|
|
@@ -149,6 +149,7 @@ export function sessionSnapshot(row, capabilitiesForMachine, historyModelForMach
|
|
|
149
149
|
createdAt: row.created_at,
|
|
150
150
|
updatedAt: row.updated_at,
|
|
151
151
|
encryptedMetadata: parseJson(row.encrypted_metadata, undefined),
|
|
152
|
+
controllerEncryptedMetadata: parseJson(row.controller_encrypted_metadata, undefined),
|
|
152
153
|
currentHead: row.current_head ?? undefined,
|
|
153
154
|
lastTurnId: row.last_turn_id ?? undefined,
|
|
154
155
|
headBasis: sessionHeadBasis(row),
|
|
@@ -571,6 +571,9 @@ export function createRelayContext(options) {
|
|
|
571
571
|
const currentHead = session?.current_head;
|
|
572
572
|
if (session?.status === "closed")
|
|
573
573
|
return false;
|
|
574
|
+
if (session?.status === "running" && params.source === "machine" && session.last_turn_id && params.turnId !== session.last_turn_id) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
574
577
|
if (!currentHead)
|
|
575
578
|
return true;
|
|
576
579
|
if (typeof session?.head_basis_message_id === "string" &&
|
|
@@ -578,9 +581,6 @@ export function createRelayContext(options) {
|
|
|
578
581
|
params.source === "machine") {
|
|
579
582
|
return false;
|
|
580
583
|
}
|
|
581
|
-
if (session?.status === "running" && params.source === "machine" && session.last_turn_id && params.turnId !== session.last_turn_id) {
|
|
582
|
-
return false;
|
|
583
|
-
}
|
|
584
584
|
const nextOrder = logicalEventOrder({
|
|
585
585
|
id: eventId,
|
|
586
586
|
createdAt,
|
|
@@ -40,6 +40,7 @@ export type SessionRow = {
|
|
|
40
40
|
name: string;
|
|
41
41
|
status: SessionSnapshot["status"];
|
|
42
42
|
encrypted_metadata: string | null;
|
|
43
|
+
controller_encrypted_metadata: string | null;
|
|
43
44
|
current_head: string | null;
|
|
44
45
|
last_turn_id: string | null;
|
|
45
46
|
head_basis_event_id: number | null;
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decryptJson, encryptJson, normalizeSessionTags, normalizeSessionName, sessionTagsMatch, parseServerMessage, randomId, } from "../../shared/dist/index.js";
|
|
1
|
+
import { decryptJson, encryptJson, normalizeSessionTags, sessionTagKeys, normalizeSessionName, sessionTagsMatch, parseServerMessage, randomId, } from "../../shared/dist/index.js";
|
|
2
2
|
import { addControllerDevice, claimControllerInvite, createControllerInvite, createPairingCode, createScopedToken, deleteMemory as deleteMemoryRecord, listDevices, listEncryptedMemories, listMemorySettings, renameDevice, markSessionRecent, pinWorkspaceCwd, listScopedTokens, revokeDevice, revokeScopedToken, saveEncryptedMemory, setSessionStar, setMemorySettings, setWorkspaceProjectPreference, tokenSelf, unpinWorkspaceCwd, workspaceSyncState, } from "./account.js";
|
|
3
3
|
import { ControllerClientError, ControllerCommandError } from "./errors.js";
|
|
4
4
|
import { authenticatedJson, normalizeRelayUrl, readRelayJson, relayHttpError } from "./http.js";
|
|
@@ -30,6 +30,11 @@ function runtimeSessionIdsForMetadata(metadata) {
|
|
|
30
30
|
function isCanonicalRuntimeSessionCandidate(left, right) {
|
|
31
31
|
return left.createdAt < right.createdAt || (left.createdAt === right.createdAt && left.id < right.id);
|
|
32
32
|
}
|
|
33
|
+
function controllerSessionMetadata(tags) {
|
|
34
|
+
if (tags.length === 0)
|
|
35
|
+
return undefined;
|
|
36
|
+
return { tags, tagKeys: sessionTagKeys(tags) };
|
|
37
|
+
}
|
|
33
38
|
function runSettlementTimeoutMs(options) {
|
|
34
39
|
if (options.waitTimeoutMs !== undefined)
|
|
35
40
|
return options.waitTimeoutMs;
|
|
@@ -226,6 +231,7 @@ export class ControllerClient {
|
|
|
226
231
|
const requestedRuntimeName = input.runtimeName === undefined ? undefined : normalizeSessionName(input.runtimeName);
|
|
227
232
|
const model = normalizeOptionalString(input.model);
|
|
228
233
|
const tags = normalizeSessionTags(input.tags);
|
|
234
|
+
const controllerMetadata = controllerSessionMetadata(tags);
|
|
229
235
|
const requestId = randomId("req");
|
|
230
236
|
const result = await this.sendCommand({
|
|
231
237
|
type: "controller:createSession",
|
|
@@ -246,29 +252,34 @@ export class ControllerClient {
|
|
|
246
252
|
...(input.hiddenFromWorkspace ? { hiddenFromWorkspace: true, visibility: "hidden" } : {}),
|
|
247
253
|
permissionMode: input.permissionMode,
|
|
248
254
|
...(input.source ? { source: input.source } : {}),
|
|
249
|
-
...(tags.length > 0 ? { tags, tagKeys: tags
|
|
255
|
+
...(tags.length > 0 ? { tags, tagKeys: sessionTagKeys(tags) } : {}),
|
|
250
256
|
}),
|
|
257
|
+
...(controllerMetadata ? {
|
|
258
|
+
controllerEncryptedMetadata: await encryptJson(this.config.accountSecret, `session:controller-metadata:create:${requestId}`, controllerMetadata),
|
|
259
|
+
} : {}),
|
|
251
260
|
});
|
|
252
261
|
return { ...result, requestId };
|
|
253
262
|
}
|
|
254
263
|
async updateSessionMetadata(input) {
|
|
255
264
|
const sessionId = requireNonEmpty(input.sessionId, "sessionId");
|
|
256
265
|
const requestId = randomId("req");
|
|
257
|
-
const
|
|
258
|
-
const
|
|
266
|
+
const tags = normalizeSessionTags(input.metadata.tags);
|
|
267
|
+
const runtimeMetadata = { ...input.metadata };
|
|
259
268
|
if (tags.length > 0) {
|
|
260
|
-
|
|
261
|
-
|
|
269
|
+
runtimeMetadata.tags = tags;
|
|
270
|
+
runtimeMetadata.tagKeys = sessionTagKeys(tags);
|
|
262
271
|
}
|
|
263
272
|
else {
|
|
264
|
-
delete
|
|
265
|
-
delete
|
|
273
|
+
delete runtimeMetadata.tags;
|
|
274
|
+
delete runtimeMetadata.tagKeys;
|
|
266
275
|
}
|
|
276
|
+
const controllerMetadata = controllerSessionMetadata(tags) ?? {};
|
|
267
277
|
const result = await this.sendCommand({
|
|
268
278
|
type: "controller:updateSessionMetadata",
|
|
269
279
|
requestId,
|
|
270
280
|
sessionId,
|
|
271
|
-
encryptedMetadata: await encryptJson(this.config.accountSecret, `session:${sessionId}:metadata:update:${requestId}`,
|
|
281
|
+
encryptedMetadata: await encryptJson(this.config.accountSecret, `session:${sessionId}:metadata:update:${requestId}`, runtimeMetadata),
|
|
282
|
+
controllerEncryptedMetadata: await encryptJson(this.config.accountSecret, `session:${sessionId}:controller-metadata:update:${requestId}`, controllerMetadata),
|
|
272
283
|
});
|
|
273
284
|
return { requestId, sessionId: result.sessionId ?? sessionId };
|
|
274
285
|
}
|
|
@@ -573,6 +584,7 @@ export class ControllerClient {
|
|
|
573
584
|
const from = requireNonEmpty(input.from, "from");
|
|
574
585
|
const name = requireNonEmpty(input.name, "name");
|
|
575
586
|
const tags = normalizeSessionTags(input.tags);
|
|
587
|
+
const controllerMetadata = controllerSessionMetadata(tags);
|
|
576
588
|
const requestId = randomId("req");
|
|
577
589
|
return await this.sendCommand({
|
|
578
590
|
type: "controller:fork",
|
|
@@ -584,8 +596,11 @@ export class ControllerClient {
|
|
|
584
596
|
sourceSessionId: checkedSessionId,
|
|
585
597
|
from,
|
|
586
598
|
name,
|
|
587
|
-
...(tags.length > 0 ? { tags, tagKeys: tags
|
|
599
|
+
...(tags.length > 0 ? { tags, tagKeys: sessionTagKeys(tags) } : {}),
|
|
588
600
|
}),
|
|
601
|
+
...(controllerMetadata ? {
|
|
602
|
+
controllerEncryptedMetadata: await encryptJson(this.config.accountSecret, `session:fork:${requestId}:controller-metadata`, controllerMetadata),
|
|
603
|
+
} : {}),
|
|
589
604
|
});
|
|
590
605
|
}
|
|
591
606
|
async renameSession(sessionId, name) {
|
|
@@ -700,14 +715,33 @@ export class ControllerClient {
|
|
|
700
715
|
}
|
|
701
716
|
}
|
|
702
717
|
async decodeSessionMetadata(session) {
|
|
703
|
-
|
|
704
|
-
|
|
718
|
+
let runtimeMetadata = {};
|
|
719
|
+
let controllerMetadata = {};
|
|
705
720
|
try {
|
|
706
|
-
|
|
721
|
+
if (session.encryptedMetadata)
|
|
722
|
+
runtimeMetadata = await decryptJson(this.config.accountSecret, session.encryptedMetadata);
|
|
707
723
|
}
|
|
708
724
|
catch {
|
|
709
|
-
|
|
725
|
+
runtimeMetadata = {};
|
|
726
|
+
}
|
|
727
|
+
try {
|
|
728
|
+
if (session.controllerEncryptedMetadata)
|
|
729
|
+
controllerMetadata = await decryptJson(this.config.accountSecret, session.controllerEncryptedMetadata);
|
|
730
|
+
}
|
|
731
|
+
catch {
|
|
732
|
+
controllerMetadata = {};
|
|
733
|
+
}
|
|
734
|
+
const merged = { ...runtimeMetadata, ...controllerMetadata };
|
|
735
|
+
const tags = normalizeSessionTags(controllerMetadata.tags ?? runtimeMetadata.tags);
|
|
736
|
+
if (tags.length > 0) {
|
|
737
|
+
merged.tags = tags;
|
|
738
|
+
merged.tagKeys = sessionTagKeys(tags);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
delete merged.tags;
|
|
742
|
+
delete merged.tagKeys;
|
|
710
743
|
}
|
|
744
|
+
return merged;
|
|
711
745
|
}
|
|
712
746
|
async decodeMemory(memory) {
|
|
713
747
|
const payload = await decryptJson(this.config.accountSecret, memory.encryptedMemory);
|
|
@@ -233,6 +233,19 @@ export declare const sessionSnapshotSchema: z.ZodObject<{
|
|
|
233
233
|
ciphertext: z.ZodString;
|
|
234
234
|
}, z.core.$strip>;
|
|
235
235
|
}, z.core.$strip>>;
|
|
236
|
+
controllerEncryptedMetadata: z.ZodOptional<z.ZodObject<{
|
|
237
|
+
v: z.ZodLiteral<1>;
|
|
238
|
+
alg: z.ZodLiteral<"A256GCM">;
|
|
239
|
+
scope: z.ZodString;
|
|
240
|
+
key: z.ZodObject<{
|
|
241
|
+
nonce: z.ZodString;
|
|
242
|
+
ciphertext: z.ZodString;
|
|
243
|
+
}, z.core.$strip>;
|
|
244
|
+
data: z.ZodObject<{
|
|
245
|
+
nonce: z.ZodString;
|
|
246
|
+
ciphertext: z.ZodString;
|
|
247
|
+
}, z.core.$strip>;
|
|
248
|
+
}, z.core.$strip>>;
|
|
236
249
|
currentHead: z.ZodOptional<z.ZodString>;
|
|
237
250
|
lastTurnId: z.ZodOptional<z.ZodString>;
|
|
238
251
|
headBasis: z.ZodOptional<z.ZodObject<{
|
|
@@ -563,6 +576,7 @@ export declare const releaseJobResultSchema: z.ZodObject<{
|
|
|
563
576
|
gate_failed: "gate_failed";
|
|
564
577
|
deploy_failed: "deploy_failed";
|
|
565
578
|
verify_failed: "verify_failed";
|
|
579
|
+
publish_failed: "publish_failed";
|
|
566
580
|
update_failed: "update_failed";
|
|
567
581
|
notify_failed: "notify_failed";
|
|
568
582
|
dogfood_failed: "dogfood_failed";
|
|
@@ -83,6 +83,7 @@ export const sessionSnapshotSchema = z.object({
|
|
|
83
83
|
createdAt: z.number(),
|
|
84
84
|
updatedAt: z.number(),
|
|
85
85
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
86
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
86
87
|
currentHead: z.string().min(1).optional(),
|
|
87
88
|
lastTurnId: z.string().min(1).optional(),
|
|
88
89
|
headBasis: z.object({
|
|
@@ -260,7 +261,7 @@ export const releaseJobResultSchema = z.object({
|
|
|
260
261
|
action: z.enum(["start", "status", "logs"]),
|
|
261
262
|
accepted: z.boolean().optional(),
|
|
262
263
|
jobId: z.string().min(1).optional(),
|
|
263
|
-
status: z.enum(["accepted", "running", "gate_failed", "deploy_failed", "verify_failed", "update_failed", "notify_failed", "dogfood_failed", "succeeded", "failed"]).optional(),
|
|
264
|
+
status: z.enum(["accepted", "running", "gate_failed", "deploy_failed", "verify_failed", "publish_failed", "update_failed", "notify_failed", "dogfood_failed", "succeeded", "failed"]).optional(),
|
|
264
265
|
profileName: z.string().min(1).optional(),
|
|
265
266
|
releaseSessionId: z.string().min(1).optional(),
|
|
266
267
|
machineId: z.string().min(1).optional(),
|
|
@@ -61,6 +61,7 @@ export type SessionSnapshot = {
|
|
|
61
61
|
createdAt: number;
|
|
62
62
|
updatedAt: number;
|
|
63
63
|
encryptedMetadata?: EncryptedEnvelope;
|
|
64
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
64
65
|
currentHead?: string;
|
|
65
66
|
lastTurnId?: string;
|
|
66
67
|
headBasis?: {
|
|
@@ -209,7 +210,7 @@ export type DaemonLifecycleResult = {
|
|
|
209
210
|
updateState?: DaemonUpdateState;
|
|
210
211
|
logs?: string[];
|
|
211
212
|
};
|
|
212
|
-
export type ReleaseJobStage = "accepted" | "running" | "gate_failed" | "deploy_failed" | "verify_failed" | "update_failed" | "notify_failed" | "dogfood_failed" | "succeeded" | "failed";
|
|
213
|
+
export type ReleaseJobStage = "accepted" | "running" | "gate_failed" | "deploy_failed" | "verify_failed" | "publish_failed" | "update_failed" | "notify_failed" | "dogfood_failed" | "succeeded" | "failed";
|
|
213
214
|
export type ReleaseProfile = {
|
|
214
215
|
name: string;
|
|
215
216
|
releaseSessionTags: string[];
|
|
@@ -11,6 +11,7 @@ export type ControllerClientMessage = {
|
|
|
11
11
|
name: string;
|
|
12
12
|
model?: string;
|
|
13
13
|
encryptedMetadata?: EncryptedEnvelope;
|
|
14
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
14
15
|
} | {
|
|
15
16
|
type: "controller:prompt";
|
|
16
17
|
requestId: string;
|
|
@@ -33,6 +34,7 @@ export type ControllerClientMessage = {
|
|
|
33
34
|
requestId: string;
|
|
34
35
|
sessionId: string;
|
|
35
36
|
encryptedMetadata: EncryptedEnvelope;
|
|
37
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
36
38
|
} | {
|
|
37
39
|
type: "controller:optionResponse";
|
|
38
40
|
requestId: string;
|
|
@@ -142,6 +144,7 @@ export type ControllerClientMessage = {
|
|
|
142
144
|
runtimeSessionId: string;
|
|
143
145
|
name: string;
|
|
144
146
|
encryptedMetadata?: EncryptedEnvelope;
|
|
147
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
145
148
|
} | {
|
|
146
149
|
type: "controller:rewind";
|
|
147
150
|
requestId: string;
|
|
@@ -154,6 +157,7 @@ export type ControllerClientMessage = {
|
|
|
154
157
|
from: string;
|
|
155
158
|
name: string;
|
|
156
159
|
encryptedMetadata?: EncryptedEnvelope;
|
|
160
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
157
161
|
} | {
|
|
158
162
|
type: "controller:renameSession";
|
|
159
163
|
requestId: string;
|
|
@@ -311,6 +315,7 @@ export type MachineClientMessage = {
|
|
|
311
315
|
messageId?: string;
|
|
312
316
|
transcriptPending?: boolean;
|
|
313
317
|
encryptedMetadata?: EncryptedEnvelope;
|
|
318
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
314
319
|
} | {
|
|
315
320
|
type: "machine:sessionRenamed";
|
|
316
321
|
requestId: string;
|
|
@@ -493,6 +498,7 @@ export type MachineCommand = {
|
|
|
493
498
|
name: string;
|
|
494
499
|
sourceEncryptedMetadata?: EncryptedEnvelope;
|
|
495
500
|
encryptedMetadata?: EncryptedEnvelope;
|
|
501
|
+
controllerEncryptedMetadata?: EncryptedEnvelope;
|
|
496
502
|
} | {
|
|
497
503
|
type: "machine:renameSession";
|
|
498
504
|
requestId: string;
|
|
@@ -12,6 +12,7 @@ const controllerMessageSchema = z.discriminatedUnion("type", [
|
|
|
12
12
|
name: z.string().min(1),
|
|
13
13
|
model: z.string().min(1).optional(),
|
|
14
14
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
15
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
15
16
|
}),
|
|
16
17
|
z.object({
|
|
17
18
|
type: z.literal("controller:prompt"),
|
|
@@ -37,6 +38,7 @@ const controllerMessageSchema = z.discriminatedUnion("type", [
|
|
|
37
38
|
requestId: z.string().min(1),
|
|
38
39
|
sessionId: z.string().min(1),
|
|
39
40
|
encryptedMetadata: encryptedEnvelopeSchema,
|
|
41
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
40
42
|
}),
|
|
41
43
|
z.object({
|
|
42
44
|
type: z.literal("controller:optionResponse"),
|
|
@@ -160,6 +162,7 @@ const controllerMessageSchema = z.discriminatedUnion("type", [
|
|
|
160
162
|
runtimeSessionId: z.string().min(1),
|
|
161
163
|
name: z.string().min(1),
|
|
162
164
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
165
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
163
166
|
}),
|
|
164
167
|
z.object({
|
|
165
168
|
type: z.literal("controller:rewind"),
|
|
@@ -174,6 +177,7 @@ const controllerMessageSchema = z.discriminatedUnion("type", [
|
|
|
174
177
|
from: z.string().min(1),
|
|
175
178
|
name: z.string().min(1),
|
|
176
179
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
180
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
177
181
|
}),
|
|
178
182
|
z.object({
|
|
179
183
|
type: z.literal("controller:renameSession"),
|
|
@@ -372,6 +376,7 @@ const machineMessageSchema = z.discriminatedUnion("type", [
|
|
|
372
376
|
messageId: z.string().min(1).optional(),
|
|
373
377
|
transcriptPending: z.boolean().optional(),
|
|
374
378
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
379
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
375
380
|
}),
|
|
376
381
|
z.object({
|
|
377
382
|
type: z.literal("machine:sessionRenamed"),
|
|
@@ -580,6 +585,7 @@ const machineCommandSchema = z.discriminatedUnion("type", [
|
|
|
580
585
|
name: z.string().min(1),
|
|
581
586
|
sourceEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
582
587
|
encryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
588
|
+
controllerEncryptedMetadata: encryptedEnvelopeSchema.optional(),
|
|
583
589
|
}),
|
|
584
590
|
z.object({
|
|
585
591
|
type: z.literal("machine:renameSession"),
|