acpx 0.19.1 → 0.19.3
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/{agent-registry-DWlx5BQ4.js → agent-registry-DWnqUICY.js} +20 -17
- package/dist/agent-registry-DWnqUICY.js.map +1 -0
- package/dist/agent-registry.js +1 -1
- package/dist/{cli-BerngYEz.js → cli-C1uofM8S.js} +5 -5
- package/dist/{cli-BerngYEz.js.map → cli-C1uofM8S.js.map} +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +56 -40
- package/dist/cli.js.map +1 -1
- package/dist/{client-BchvQRpz.d.ts → client-CdG6nVDG.d.ts} +4 -3
- package/dist/client-CdG6nVDG.d.ts.map +1 -0
- package/dist/{flows-DimX0it5.js → flows-hz_Pfsp-.js} +9 -5
- package/dist/flows-hz_Pfsp-.js.map +1 -0
- package/dist/flows.d.ts +2 -2
- package/dist/flows.js +1 -1
- package/dist/{invocation-options-vobVApfO.js → invocation-options-DbZzMvKM.js} +5 -5
- package/dist/{invocation-options-vobVApfO.js.map → invocation-options-DbZzMvKM.js.map} +1 -1
- package/dist/{ipc-DAApJ5mi.js → ipc-BW06Pbb8.js} +1246 -369
- package/dist/ipc-BW06Pbb8.js.map +1 -0
- package/dist/{output-Cnuji8Bo.js → output-BjeeG-cj.js} +3 -3
- package/dist/{output-Cnuji8Bo.js.map → output-BjeeG-cj.js.map} +1 -1
- package/dist/{queue-owner-runtime-C4OOosbo.js → queue-owner-runtime-Dhr4gxNE.js} +542 -929
- package/dist/queue-owner-runtime-Dhr4gxNE.js.map +1 -0
- package/dist/runtime.d.ts +7 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +24 -17
- package/dist/runtime.js.map +1 -1
- package/dist/{session-options-Dp6mzNSy.d.ts → session-options-X7LhX9BF.d.ts} +2 -1
- package/dist/{session-options-Dp6mzNSy.d.ts.map → session-options-X7LhX9BF.d.ts.map} +1 -1
- package/dist/{session-watch-Bj9LoYUq.js → session-watch-CgfkUKLA.js} +4 -4
- package/dist/{session-watch-Bj9LoYUq.js.map → session-watch-CgfkUKLA.js.map} +1 -1
- package/dist/watch-BGdqBiNX.js +85 -0
- package/dist/watch-BGdqBiNX.js.map +1 -0
- package/package.json +11 -11
- package/skills/acpx/SKILL.md +7 -2
- package/dist/agent-registry-DWlx5BQ4.js.map +0 -1
- package/dist/client-BchvQRpz.d.ts.map +0 -1
- package/dist/flows-DimX0it5.js.map +0 -1
- package/dist/ipc-DAApJ5mi.js.map +0 -1
- package/dist/queue-owner-runtime-C4OOosbo.js.map +0 -1
- package/dist/watch-Cz6jbrRs.js +0 -32
- package/dist/watch-Cz6jbrRs.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as PROCESS_HELPER_TIMEOUT_MS, E as isChildProcessRunning, N as runTimedExecFile, S as PROCESS_HELPER_MAX_BUFFER_BYTES, n as AGENT_REGISTRY, r as BUILT_IN_AGENT_PACKAGES, t as AGENT_ARGV_REGISTRY } from "./agent-registry-
|
|
1
|
+
import { C as PROCESS_HELPER_TIMEOUT_MS, E as isChildProcessRunning, N as runTimedExecFile, S as PROCESS_HELPER_MAX_BUFFER_BYTES, n as AGENT_REGISTRY, r as BUILT_IN_AGENT_PACKAGES, t as AGENT_ARGV_REGISTRY } from "./agent-registry-DWnqUICY.js";
|
|
2
2
|
import fs, { statSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs$1 from "node:fs/promises";
|
|
@@ -11,6 +11,7 @@ import { createHash, randomInt, randomUUID } from "node:crypto";
|
|
|
11
11
|
import { isHardlinkFallbackError } from "@openclaw/fs-safe/durability";
|
|
12
12
|
import { acquireFileLock } from "@openclaw/fs-safe/file-lock";
|
|
13
13
|
import net from "node:net";
|
|
14
|
+
import { resolveSecureTempRoot } from "@openclaw/fs-safe/secure-temp-root";
|
|
14
15
|
//#region src/errors.ts
|
|
15
16
|
var AcpxOperationalError = class extends Error {
|
|
16
17
|
outputCode;
|
|
@@ -231,12 +232,12 @@ const SESSION_RECORD_SCHEMA = "acpx.session.v1";
|
|
|
231
232
|
//#endregion
|
|
232
233
|
//#region src/acp/error-shapes.ts
|
|
233
234
|
const RESOURCE_NOT_FOUND_ACP_CODES = /* @__PURE__ */ new Set([-32001, -32002]);
|
|
234
|
-
function asRecord$
|
|
235
|
+
function asRecord$5(value) {
|
|
235
236
|
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
236
237
|
return value;
|
|
237
238
|
}
|
|
238
239
|
function toAcpErrorPayload(value) {
|
|
239
|
-
const record = asRecord$
|
|
240
|
+
const record = asRecord$5(value);
|
|
240
241
|
if (!record) return;
|
|
241
242
|
if (typeof record.code !== "number" || !Number.isFinite(record.code)) return;
|
|
242
243
|
if (typeof record.message !== "string" || record.message.length === 0) return;
|
|
@@ -250,7 +251,7 @@ function extractAcpErrorInternal(value, depth) {
|
|
|
250
251
|
if (depth > 5) return;
|
|
251
252
|
const direct = toAcpErrorPayload(value);
|
|
252
253
|
if (direct) return direct;
|
|
253
|
-
const record = asRecord$
|
|
254
|
+
const record = asRecord$5(value);
|
|
254
255
|
if (!record) return;
|
|
255
256
|
return extractNestedAcpError(record, depth);
|
|
256
257
|
}
|
|
@@ -285,7 +286,7 @@ function hasSessionNotFoundHint(value, depth = 0) {
|
|
|
285
286
|
if (depth > 4) return false;
|
|
286
287
|
if (isSessionNotFoundText(value)) return true;
|
|
287
288
|
if (Array.isArray(value)) return value.some((entry) => hasSessionNotFoundHint(entry, depth + 1));
|
|
288
|
-
const record = asRecord$
|
|
289
|
+
const record = asRecord$5(value);
|
|
289
290
|
if (!record) return false;
|
|
290
291
|
return Object.values(record).some((entry) => hasSessionNotFoundHint(entry, depth + 1));
|
|
291
292
|
}
|
|
@@ -302,6 +303,136 @@ function isAcpResourceNotFoundError(error) {
|
|
|
302
303
|
return isSessionNotFoundText(formatUnknownErrorMessage(error));
|
|
303
304
|
}
|
|
304
305
|
//#endregion
|
|
306
|
+
//#region src/acp/error-normalization.ts
|
|
307
|
+
const AUTH_REQUIRED_ACP_CODES = /* @__PURE__ */ new Set([-32e3]);
|
|
308
|
+
const QUERY_CLOSED_BEFORE_RESPONSE_DETAIL = "query closed before response received";
|
|
309
|
+
function asRecord$4(value) {
|
|
310
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
311
|
+
return value;
|
|
312
|
+
}
|
|
313
|
+
function isAuthRequiredMessage(value) {
|
|
314
|
+
if (!value) return false;
|
|
315
|
+
const normalized = value.toLowerCase();
|
|
316
|
+
return [
|
|
317
|
+
"auth required",
|
|
318
|
+
"authentication required",
|
|
319
|
+
"authorization required",
|
|
320
|
+
"credential required",
|
|
321
|
+
"credentials required",
|
|
322
|
+
"token required",
|
|
323
|
+
"login required"
|
|
324
|
+
].some((needle) => normalized.includes(needle));
|
|
325
|
+
}
|
|
326
|
+
function isAcpAuthRequiredPayload(acp) {
|
|
327
|
+
if (!acp) return false;
|
|
328
|
+
if (!AUTH_REQUIRED_ACP_CODES.has(acp.code)) return false;
|
|
329
|
+
if (isAuthRequiredMessage(acp.message)) return true;
|
|
330
|
+
const data = asRecord$4(acp.data);
|
|
331
|
+
if (!data) return false;
|
|
332
|
+
return hasAuthRequiredData(data);
|
|
333
|
+
}
|
|
334
|
+
function hasAuthRequiredData(data) {
|
|
335
|
+
return data.authRequired === true || hasNonEmptyString(data.methodId) || hasNonEmptyArray(data.methods);
|
|
336
|
+
}
|
|
337
|
+
function hasNonEmptyString(value) {
|
|
338
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
339
|
+
}
|
|
340
|
+
function hasNonEmptyArray(value) {
|
|
341
|
+
return Array.isArray(value) && value.length > 0;
|
|
342
|
+
}
|
|
343
|
+
function isOutputErrorCode$1(value) {
|
|
344
|
+
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
345
|
+
}
|
|
346
|
+
function isOutputErrorOrigin$1(value) {
|
|
347
|
+
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
348
|
+
}
|
|
349
|
+
function readOutputErrorMeta(error) {
|
|
350
|
+
const record = asRecord$4(error);
|
|
351
|
+
if (!record) return {};
|
|
352
|
+
return {
|
|
353
|
+
outputCode: isOutputErrorCode$1(record.outputCode) ? record.outputCode : void 0,
|
|
354
|
+
detailCode: typeof record.detailCode === "string" && record.detailCode.trim().length > 0 ? record.detailCode : void 0,
|
|
355
|
+
origin: isOutputErrorOrigin$1(record.origin) ? record.origin : void 0,
|
|
356
|
+
retryable: typeof record.retryable === "boolean" ? record.retryable : void 0,
|
|
357
|
+
acp: extractAcpError(record.acp)
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function isTimeoutLike(error) {
|
|
361
|
+
return error instanceof Error && error.name === "TimeoutError";
|
|
362
|
+
}
|
|
363
|
+
function isNoSessionLike(error) {
|
|
364
|
+
return error instanceof Error && error.name === "NoSessionError";
|
|
365
|
+
}
|
|
366
|
+
function isUsageLike(error) {
|
|
367
|
+
if (!(error instanceof Error)) return false;
|
|
368
|
+
return error.name === "CommanderError" || error.name === "InvalidArgumentError" || asRecord$4(error)?.code === "commander.invalidArgument";
|
|
369
|
+
}
|
|
370
|
+
function formatErrorMessage(error) {
|
|
371
|
+
return formatUnknownErrorMessage(error);
|
|
372
|
+
}
|
|
373
|
+
function isAcpQueryClosedBeforeResponseError(error) {
|
|
374
|
+
const acp = extractAcpError(error);
|
|
375
|
+
if (!acp || acp.code !== -32603) return false;
|
|
376
|
+
const details = asRecord$4(acp.data)?.details;
|
|
377
|
+
if (typeof details !== "string") return false;
|
|
378
|
+
return details.toLowerCase().includes(QUERY_CLOSED_BEFORE_RESPONSE_DETAIL);
|
|
379
|
+
}
|
|
380
|
+
function mapErrorCode(error) {
|
|
381
|
+
if (error instanceof PermissionPromptUnavailableError) return "PERMISSION_PROMPT_UNAVAILABLE";
|
|
382
|
+
if (error instanceof PermissionDeniedError) return "PERMISSION_DENIED";
|
|
383
|
+
if (isTimeoutLike(error)) return "TIMEOUT";
|
|
384
|
+
if (isNoSessionLike(error) || isAcpResourceNotFoundError(error)) return "NO_SESSION";
|
|
385
|
+
if (isUsageLike(error)) return "USAGE";
|
|
386
|
+
}
|
|
387
|
+
function normalizeOutputError(error, options = {}) {
|
|
388
|
+
const meta = readOutputErrorMeta(error);
|
|
389
|
+
const code = resolveOutputErrorCode(error, options, meta);
|
|
390
|
+
const acp = options.acp ?? meta.acp ?? extractAcpError(error);
|
|
391
|
+
return {
|
|
392
|
+
code,
|
|
393
|
+
message: formatErrorMessage(error),
|
|
394
|
+
detailCode: resolveDetailCode(error, acp, options, meta),
|
|
395
|
+
origin: meta.origin ?? options.origin,
|
|
396
|
+
retryable: meta.retryable ?? options.retryable,
|
|
397
|
+
acp
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function resolveOutputErrorCode(error, options, meta) {
|
|
401
|
+
const code = meta.outputCode ?? mapErrorCode(error) ?? options.defaultCode ?? "RUNTIME";
|
|
402
|
+
if (code === "RUNTIME" && isAcpResourceNotFoundError(error)) return "NO_SESSION";
|
|
403
|
+
return code;
|
|
404
|
+
}
|
|
405
|
+
function resolveDetailCode(error, acp, options, meta) {
|
|
406
|
+
return meta.detailCode ?? options.detailCode ?? (error instanceof AuthPolicyError || isAcpAuthRequiredPayload(acp) ? "AUTH_REQUIRED" : void 0);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Returns true when an error from `client.prompt()` looks transient and
|
|
410
|
+
* can reasonably be retried (e.g. model-API 400/500, network hiccups that
|
|
411
|
+
* surface as ACP internal errors).
|
|
412
|
+
*
|
|
413
|
+
* Errors that are definitively non-recoverable (auth, missing session,
|
|
414
|
+
* invalid params, timeout, permission) return false.
|
|
415
|
+
*/
|
|
416
|
+
function isRetryablePromptError(error) {
|
|
417
|
+
if (isNonRetryablePromptError(error)) return false;
|
|
418
|
+
const acp = extractAcpError(error);
|
|
419
|
+
if (!acp) return false;
|
|
420
|
+
return acp.code === -32603 || acp.code === -32700;
|
|
421
|
+
}
|
|
422
|
+
function isNonRetryablePromptError(error) {
|
|
423
|
+
return error instanceof PermissionDeniedError || error instanceof PermissionPromptUnavailableError || isTimeoutLike(error) || isNoSessionLike(error) || isUsageLike(error);
|
|
424
|
+
}
|
|
425
|
+
function exitCodeForOutputErrorCode(code) {
|
|
426
|
+
switch (code) {
|
|
427
|
+
case "USAGE": return EXIT_CODES.USAGE;
|
|
428
|
+
case "TIMEOUT": return EXIT_CODES.TIMEOUT;
|
|
429
|
+
case "NO_SESSION": return EXIT_CODES.NO_SESSION;
|
|
430
|
+
case "PERMISSION_DENIED":
|
|
431
|
+
case "PERMISSION_PROMPT_UNAVAILABLE": return EXIT_CODES.PERMISSION_DENIED;
|
|
432
|
+
default: return EXIT_CODES.ERROR;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
305
436
|
//#region src/process-liveness.ts
|
|
306
437
|
function isProcessAlive(pid) {
|
|
307
438
|
if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
|
|
@@ -686,7 +817,15 @@ function parseCursor(recordId, cursor) {
|
|
|
686
817
|
return parsed.data[1];
|
|
687
818
|
}
|
|
688
819
|
function fileIdentity(stat) {
|
|
689
|
-
return `${stat.dev}:${stat.ino}:${stat.
|
|
820
|
+
return `${stat.dev}:${stat.ino}:${stat.birthtimeNs}`;
|
|
821
|
+
}
|
|
822
|
+
async function pathIdentity(filePath) {
|
|
823
|
+
try {
|
|
824
|
+
return fileIdentity(await fs$1.lstat(filePath, { bigint: true }));
|
|
825
|
+
} catch (error) {
|
|
826
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
|
|
827
|
+
throw error;
|
|
828
|
+
}
|
|
690
829
|
}
|
|
691
830
|
function emptySegment() {
|
|
692
831
|
return {
|
|
@@ -718,12 +857,7 @@ var SessionJournalReader = class {
|
|
|
718
857
|
const segments = [];
|
|
719
858
|
try {
|
|
720
859
|
const paths = await this.openPresentSegments(segments);
|
|
721
|
-
|
|
722
|
-
const identities = new Map(segments.map((entry) => [entry.filePath, entry.identity]));
|
|
723
|
-
if (paths.every((filePath, index) => {
|
|
724
|
-
const entry = current[index];
|
|
725
|
-
return (entry.missing ? void 0 : fileIdentity(entry.stat)) === identities.get(filePath);
|
|
726
|
-
})) return segments;
|
|
860
|
+
if (await this.matchesSnapshot(paths, segments)) return segments;
|
|
727
861
|
} catch (error) {
|
|
728
862
|
if (!retryableSnapshotError(error)) {
|
|
729
863
|
await this.closeSnapshot(segments);
|
|
@@ -744,11 +878,16 @@ var SessionJournalReader = class {
|
|
|
744
878
|
symlinks: "reject",
|
|
745
879
|
nonBlockingRead: true
|
|
746
880
|
});
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
881
|
+
try {
|
|
882
|
+
return {
|
|
883
|
+
filePath,
|
|
884
|
+
opened,
|
|
885
|
+
identity: fileIdentity(await opened.handle.stat({ bigint: true }))
|
|
886
|
+
};
|
|
887
|
+
} catch (error) {
|
|
888
|
+
await opened[Symbol.asyncDispose]();
|
|
889
|
+
throw error;
|
|
890
|
+
}
|
|
752
891
|
}));
|
|
753
892
|
let failure;
|
|
754
893
|
for (const result of results) if (result.status === "fulfilled") segments.push(result.value);
|
|
@@ -759,10 +898,33 @@ var SessionJournalReader = class {
|
|
|
759
898
|
async closeSnapshot(segments) {
|
|
760
899
|
await Promise.all(segments.map(({ opened }) => opened[Symbol.asyncDispose]()));
|
|
761
900
|
}
|
|
901
|
+
async matchesSnapshot(paths, segments) {
|
|
902
|
+
const current = await Promise.all(paths.map(pathIdentity));
|
|
903
|
+
const identities = new Map(segments.map((entry) => [entry.filePath, entry.identity]));
|
|
904
|
+
return paths.every((filePath, index) => current[index] === identities.get(filePath));
|
|
905
|
+
}
|
|
906
|
+
async withSnapshot(read, signal) {
|
|
907
|
+
for (;;) {
|
|
908
|
+
const segments = await this.openSnapshot(signal);
|
|
909
|
+
try {
|
|
910
|
+
const outcome = await read(segments).then((value) => ({ value }), (error) => {
|
|
911
|
+
if (!(error instanceof SessionWatchError) || error.code !== "WATCH_JOURNAL_CORRUPT") throw error;
|
|
912
|
+
return { error };
|
|
913
|
+
});
|
|
914
|
+
if (await this.matchesSnapshot(this.paths(), segments)) {
|
|
915
|
+
signal?.throwIfAborted();
|
|
916
|
+
if ("error" in outcome) throw outcome.error;
|
|
917
|
+
return outcome.value;
|
|
918
|
+
}
|
|
919
|
+
} finally {
|
|
920
|
+
await this.closeSnapshot(segments);
|
|
921
|
+
}
|
|
922
|
+
await setTimeout$1(5, void 0, { signal });
|
|
923
|
+
}
|
|
924
|
+
}
|
|
762
925
|
async readAcpMessages() {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
try {
|
|
926
|
+
return await this.withSnapshot(async (segments) => {
|
|
927
|
+
const messages = [];
|
|
766
928
|
for (const { opened } of segments) {
|
|
767
929
|
const payload = await opened.handle.readFile("utf8");
|
|
768
930
|
for (const line of payload.split("\n")) try {
|
|
@@ -771,15 +933,12 @@ var SessionJournalReader = class {
|
|
|
771
933
|
} catch {}
|
|
772
934
|
}
|
|
773
935
|
return messages;
|
|
774
|
-
}
|
|
775
|
-
await this.closeSnapshot(segments);
|
|
776
|
-
}
|
|
936
|
+
});
|
|
777
937
|
}
|
|
778
938
|
async readTail() {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
try {
|
|
939
|
+
return await this.withSnapshot(async (segments) => {
|
|
940
|
+
let tail = emptySegment();
|
|
941
|
+
let active = emptySegment();
|
|
783
942
|
for (const segment of segments.toReversed()) {
|
|
784
943
|
const state = emptySegment();
|
|
785
944
|
await this.readSegment(segment.opened.handle, segment.opened.stat.size, state, void 0);
|
|
@@ -797,22 +956,20 @@ var SessionJournalReader = class {
|
|
|
797
956
|
activeAnchored: active.firstSequence !== void 0,
|
|
798
957
|
activePartial: active.pending.length > 0
|
|
799
958
|
};
|
|
800
|
-
}
|
|
801
|
-
await this.closeSnapshot(segments);
|
|
802
|
-
}
|
|
959
|
+
});
|
|
803
960
|
}
|
|
804
961
|
async read(signal, options) {
|
|
805
|
-
const
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
962
|
+
const { result, states } = await this.withSnapshot(async (segments) => {
|
|
963
|
+
const page = createJournalPage(options);
|
|
964
|
+
const states = new Map(this.states);
|
|
965
|
+
let hasMore = false;
|
|
966
|
+
let firstSequence;
|
|
967
|
+
let tail = emptySegment();
|
|
968
|
+
let active = emptySegment();
|
|
812
969
|
for (const segment of segments) {
|
|
813
|
-
const state =
|
|
970
|
+
const state = { ...states.get(segment.identity) ?? emptySegment() };
|
|
814
971
|
await this.readSegment(segment.opened.handle, segment.opened.stat.size, state, page, signal);
|
|
815
|
-
|
|
972
|
+
states.set(segment.identity, state);
|
|
816
973
|
if (state.firstSequence !== void 0) {
|
|
817
974
|
if (firstSequence === void 0) firstSequence = state.firstSequence;
|
|
818
975
|
else if (state.firstSequence !== tail.sequence) corrupt("Session journal segments are not contiguous");
|
|
@@ -824,25 +981,29 @@ var SessionJournalReader = class {
|
|
|
824
981
|
break;
|
|
825
982
|
}
|
|
826
983
|
}
|
|
827
|
-
this.pruneStates(segments);
|
|
984
|
+
this.pruneStates(states, segments);
|
|
828
985
|
return {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
986
|
+
states,
|
|
987
|
+
result: {
|
|
988
|
+
events: page.events,
|
|
989
|
+
hasMore,
|
|
990
|
+
firstSequence,
|
|
991
|
+
sequence: tail.sequence,
|
|
992
|
+
messageSequence: tail.messageSequence,
|
|
993
|
+
requestId: tail.requestId,
|
|
994
|
+
activeSize: active.offset,
|
|
995
|
+
activeAnchored: active.firstSequence !== void 0,
|
|
996
|
+
activePartial: active.pending.length > 0
|
|
997
|
+
}
|
|
838
998
|
};
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
|
|
999
|
+
}, signal);
|
|
1000
|
+
signal?.throwIfAborted();
|
|
1001
|
+
this.states = states;
|
|
1002
|
+
return result;
|
|
842
1003
|
}
|
|
843
|
-
pruneStates(segments) {
|
|
1004
|
+
pruneStates(states, segments) {
|
|
844
1005
|
const retained = new Set(segments.map((entry) => entry.identity));
|
|
845
|
-
for (const identity of
|
|
1006
|
+
for (const identity of states.keys()) if (!retained.has(identity)) states.delete(identity);
|
|
846
1007
|
}
|
|
847
1008
|
async readSegment(handle, size, state, page, signal) {
|
|
848
1009
|
if (size < state.offset) corrupt("Session journal was truncated while watching");
|
|
@@ -978,6 +1139,7 @@ async function* iterateJournal(record, options) {
|
|
|
978
1139
|
let after = options.cursor === void 0 ? -1 : parseCursor(record.acpxRecordId, options.cursor);
|
|
979
1140
|
const reader = new SessionJournalReader(record);
|
|
980
1141
|
let first = true;
|
|
1142
|
+
const observation = {};
|
|
981
1143
|
for (;;) {
|
|
982
1144
|
if (signal.aborted) return;
|
|
983
1145
|
const snapshot = await settleUnlessAborted(reader.read(signal, {
|
|
@@ -992,16 +1154,34 @@ async function* iterateJournal(record, options) {
|
|
|
992
1154
|
after = sequence;
|
|
993
1155
|
yield event;
|
|
994
1156
|
}
|
|
995
|
-
if (!await continueAfterPage(record, snapshot, options)) return;
|
|
1157
|
+
if (!await continueAfterPage(record, snapshot, options, observation)) return;
|
|
996
1158
|
}
|
|
997
1159
|
}
|
|
998
|
-
async function continueAfterPage(record, snapshot, options) {
|
|
1160
|
+
async function continueAfterPage(record, snapshot, options, observation) {
|
|
1161
|
+
if (options.signal.aborted || confirmsTerminalObservation(snapshot, observation)) return false;
|
|
999
1162
|
if (!snapshot.hasMore && options.continueWatching) {
|
|
1000
|
-
|
|
1163
|
+
const decision = await settleUnlessAborted(options.continueWatching(record, snapshot.requestId), options.signal).catch((error) => {
|
|
1164
|
+
if (error instanceof SessionWatchError && error.code === "WATCH_OUTCOME_UNKNOWN") return error;
|
|
1165
|
+
throw error;
|
|
1166
|
+
});
|
|
1167
|
+
if (decision !== true) {
|
|
1168
|
+
observation.terminal = {
|
|
1169
|
+
requestId: snapshot.requestId,
|
|
1170
|
+
error: decision instanceof SessionWatchError ? decision : void 0
|
|
1171
|
+
};
|
|
1172
|
+
return !options.signal.aborted;
|
|
1173
|
+
}
|
|
1001
1174
|
}
|
|
1002
1175
|
await settleUnlessAborted(setTimeout$1(snapshot.hasMore ? 0 : 100, void 0, { signal: options.signal }), options.signal);
|
|
1003
1176
|
return !options.signal.aborted;
|
|
1004
1177
|
}
|
|
1178
|
+
function confirmsTerminalObservation(snapshot, observation) {
|
|
1179
|
+
const terminal = observation.terminal;
|
|
1180
|
+
delete observation.terminal;
|
|
1181
|
+
if (!terminal || snapshot.events.length > 0 || snapshot.hasMore || snapshot.requestId !== terminal.requestId) return false;
|
|
1182
|
+
if (terminal.error) throw terminal.error;
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1005
1185
|
function assertRetainedCursor(after, snapshot, first) {
|
|
1006
1186
|
if (after < 0) return;
|
|
1007
1187
|
if (after > snapshot.sequence) throw new SessionWatchError(first ? "WATCH_CURSOR_FUTURE" : "WATCH_CURSOR_EXPIRED", "Cursor is beyond the available session journal");
|
|
@@ -1238,12 +1418,15 @@ function parseRequestTokenUsage(raw) {
|
|
|
1238
1418
|
}
|
|
1239
1419
|
return usage;
|
|
1240
1420
|
}
|
|
1421
|
+
function isValidImageSize(size) {
|
|
1422
|
+
if (size === void 0 || size === null) return true;
|
|
1423
|
+
const record = asRecord$2(size);
|
|
1424
|
+
return !!record && isFiniteNumber(record.width) && isFiniteNumber(record.height);
|
|
1425
|
+
}
|
|
1241
1426
|
function isSessionMessageImage(raw) {
|
|
1242
1427
|
const record = asRecord$2(raw);
|
|
1243
|
-
if (!record || typeof record.source !== "string") return false;
|
|
1244
|
-
|
|
1245
|
-
const size = asRecord$2(record.size);
|
|
1246
|
-
return !!size && isFiniteNumber(size.width) && isFiniteNumber(size.height);
|
|
1428
|
+
if (!record || typeof record.source !== "string" || !isOptionalString(record.mime_type)) return false;
|
|
1429
|
+
return isValidImageSize(record.size);
|
|
1247
1430
|
}
|
|
1248
1431
|
function isSessionMessageAudio(raw) {
|
|
1249
1432
|
const record = asRecord$2(raw);
|
|
@@ -1867,182 +2050,6 @@ async function unlinkCountingBytes(filePath) {
|
|
|
1867
2050
|
return bytes;
|
|
1868
2051
|
}
|
|
1869
2052
|
//#endregion
|
|
1870
|
-
//#region src/prompt-content.ts
|
|
1871
|
-
var PromptInputValidationError = class extends Error {
|
|
1872
|
-
constructor(message) {
|
|
1873
|
-
super(message);
|
|
1874
|
-
this.name = "PromptInputValidationError";
|
|
1875
|
-
}
|
|
1876
|
-
};
|
|
1877
|
-
function asRecord$1(value) {
|
|
1878
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
1879
|
-
return value;
|
|
1880
|
-
}
|
|
1881
|
-
function isNonEmptyString(value) {
|
|
1882
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
1883
|
-
}
|
|
1884
|
-
function isBase64Data(value) {
|
|
1885
|
-
if (value.length === 0 || value.length % 4 !== 0) return false;
|
|
1886
|
-
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
|
|
1887
|
-
}
|
|
1888
|
-
function isImageMimeType(value) {
|
|
1889
|
-
return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
1890
|
-
}
|
|
1891
|
-
function isAudioMimeType(value) {
|
|
1892
|
-
return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
1893
|
-
}
|
|
1894
|
-
function isTextBlock(value) {
|
|
1895
|
-
const record = asRecord$1(value);
|
|
1896
|
-
return record?.type === "text" && typeof record.text === "string";
|
|
1897
|
-
}
|
|
1898
|
-
function isImageBlock(value) {
|
|
1899
|
-
const record = asRecord$1(value);
|
|
1900
|
-
return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
|
|
1901
|
-
}
|
|
1902
|
-
function isAudioBlock(value) {
|
|
1903
|
-
const record = asRecord$1(value);
|
|
1904
|
-
return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
|
|
1905
|
-
}
|
|
1906
|
-
function isResourceLinkBlock(value) {
|
|
1907
|
-
const record = asRecord$1(value);
|
|
1908
|
-
return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title == null || typeof record.title === "string") && typeof record.name === "string";
|
|
1909
|
-
}
|
|
1910
|
-
function isResourcePayload(value) {
|
|
1911
|
-
const record = asRecord$1(value);
|
|
1912
|
-
if (!record || !isNonEmptyString(record.uri)) return false;
|
|
1913
|
-
return typeof record.text === "string" || typeof record.blob === "string";
|
|
1914
|
-
}
|
|
1915
|
-
function isResourceBlock(value) {
|
|
1916
|
-
const record = asRecord$1(value);
|
|
1917
|
-
return record?.type === "resource" && isResourcePayload(record.resource);
|
|
1918
|
-
}
|
|
1919
|
-
const CONTENT_BLOCK_VALIDATORS = [
|
|
1920
|
-
isTextBlock,
|
|
1921
|
-
isImageBlock,
|
|
1922
|
-
isAudioBlock,
|
|
1923
|
-
isResourceLinkBlock,
|
|
1924
|
-
isResourceBlock
|
|
1925
|
-
];
|
|
1926
|
-
function isContentBlock(value) {
|
|
1927
|
-
return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
|
|
1928
|
-
}
|
|
1929
|
-
const CONTENT_BLOCK_ERROR_VALIDATORS = {
|
|
1930
|
-
text: validateTextContentBlock,
|
|
1931
|
-
image: validateImageContentBlock,
|
|
1932
|
-
audio: validateAudioContentBlock,
|
|
1933
|
-
resource_link: validateResourceLinkContentBlock,
|
|
1934
|
-
resource: validateResourceContentBlock
|
|
1935
|
-
};
|
|
1936
|
-
function contentBlockErrorValidator(type) {
|
|
1937
|
-
return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
|
|
1938
|
-
}
|
|
1939
|
-
function validateTextContentBlock(record, index) {
|
|
1940
|
-
return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
|
|
1941
|
-
}
|
|
1942
|
-
function validateImageContentBlock(record, index) {
|
|
1943
|
-
if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
|
|
1944
|
-
if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
|
|
1945
|
-
if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
|
|
1946
|
-
return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
|
|
1947
|
-
}
|
|
1948
|
-
function validateAudioContentBlock(record, index) {
|
|
1949
|
-
if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
|
|
1950
|
-
if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
|
|
1951
|
-
if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
|
|
1952
|
-
return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
|
|
1953
|
-
}
|
|
1954
|
-
function validateResourceLinkContentBlock(record, index) {
|
|
1955
|
-
if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
|
|
1956
|
-
if (record.title != null && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string or null when present`;
|
|
1957
|
-
if (typeof record.name !== "string") return `prompt[${index}] resource_link block must include a string name`;
|
|
1958
|
-
}
|
|
1959
|
-
function validateResourceContentBlock(record, index) {
|
|
1960
|
-
if (!asRecord$1(record.resource)) return `prompt[${index}] resource block must include a resource object`;
|
|
1961
|
-
return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and a string text or blob field`;
|
|
1962
|
-
}
|
|
1963
|
-
function getContentBlockValidationError(value, index) {
|
|
1964
|
-
const record = asRecord$1(value);
|
|
1965
|
-
if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
|
|
1966
|
-
const validator = contentBlockErrorValidator(record.type);
|
|
1967
|
-
return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
|
|
1968
|
-
}
|
|
1969
|
-
function isPromptInput(value) {
|
|
1970
|
-
return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
|
|
1971
|
-
}
|
|
1972
|
-
function promptCapabilityRequirement(block) {
|
|
1973
|
-
switch (block.type) {
|
|
1974
|
-
case "image": return {
|
|
1975
|
-
blockType: "image",
|
|
1976
|
-
capability: "image"
|
|
1977
|
-
};
|
|
1978
|
-
case "audio": return {
|
|
1979
|
-
blockType: "audio",
|
|
1980
|
-
capability: "audio"
|
|
1981
|
-
};
|
|
1982
|
-
case "resource": return {
|
|
1983
|
-
blockType: "resource",
|
|
1984
|
-
capability: "embeddedContext"
|
|
1985
|
-
};
|
|
1986
|
-
default: return;
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
|
-
function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
|
|
1990
|
-
for (const [index, block] of prompt.entries()) {
|
|
1991
|
-
const requirement = promptCapabilityRequirement(block);
|
|
1992
|
-
if (!requirement) continue;
|
|
1993
|
-
if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
|
|
1994
|
-
return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
function textPrompt(text) {
|
|
1998
|
-
return [{
|
|
1999
|
-
type: "text",
|
|
2000
|
-
text
|
|
2001
|
-
}];
|
|
2002
|
-
}
|
|
2003
|
-
function parseStructuredPrompt(source) {
|
|
2004
|
-
if (!source.startsWith("[")) return;
|
|
2005
|
-
try {
|
|
2006
|
-
const parsed = JSON.parse(source);
|
|
2007
|
-
if (isPromptInput(parsed)) return parsed;
|
|
2008
|
-
if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
|
|
2009
|
-
return;
|
|
2010
|
-
} catch (error) {
|
|
2011
|
-
if (error instanceof PromptInputValidationError) throw error;
|
|
2012
|
-
return;
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
function parsePromptSource(source) {
|
|
2016
|
-
const trimmed = source.trim();
|
|
2017
|
-
const structured = parseStructuredPrompt(trimmed);
|
|
2018
|
-
if (structured) return structured;
|
|
2019
|
-
if (!trimmed) return [];
|
|
2020
|
-
return textPrompt(trimmed);
|
|
2021
|
-
}
|
|
2022
|
-
function mergePromptSourceWithText(source, suffixText) {
|
|
2023
|
-
const prompt = parsePromptSource(source);
|
|
2024
|
-
const appended = suffixText.trim();
|
|
2025
|
-
if (!appended) return prompt;
|
|
2026
|
-
if (prompt.length === 0) return textPrompt(appended);
|
|
2027
|
-
return [...prompt, ...textPrompt(appended)];
|
|
2028
|
-
}
|
|
2029
|
-
function promptToDisplayText(prompt) {
|
|
2030
|
-
return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
|
|
2031
|
-
}
|
|
2032
|
-
function contentBlockDisplayText(block) {
|
|
2033
|
-
switch (block.type) {
|
|
2034
|
-
case "text": return block.text;
|
|
2035
|
-
case "resource_link": return block.title ?? block.name ?? block.uri;
|
|
2036
|
-
case "resource": return resourceBlockDisplayText(block);
|
|
2037
|
-
case "image": return `[image] ${block.mimeType}`;
|
|
2038
|
-
case "audio": return `[audio] ${block.mimeType}`;
|
|
2039
|
-
default: return "";
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
function resourceBlockDisplayText(block) {
|
|
2043
|
-
return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
|
|
2044
|
-
}
|
|
2045
|
-
//#endregion
|
|
2046
2053
|
//#region src/process-identity.ts
|
|
2047
2054
|
const IDENTITY_QUERY_TIMEOUT_MS$1 = 2e3;
|
|
2048
2055
|
const LINUX_PROCESS_QUERY = `
|
|
@@ -2439,12 +2446,228 @@ async function getOwnProcessIdentity() {
|
|
|
2439
2446
|
return await ownIdentityPending;
|
|
2440
2447
|
}
|
|
2441
2448
|
//#endregion
|
|
2442
|
-
//#region src/
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2449
|
+
//#region src/session/lock-owner.ts
|
|
2450
|
+
const OBSERVATION_REUSE_MS = 1e3;
|
|
2451
|
+
const IDENTITY_QUERY_TIMEOUT_MS = 1e3;
|
|
2452
|
+
function lockOwnerPid(value) {
|
|
2453
|
+
if (!value || typeof value !== "object" || !("pid" in value)) return;
|
|
2454
|
+
const pid = value.pid;
|
|
2455
|
+
return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
|
|
2456
|
+
}
|
|
2457
|
+
function canReuseObservation(preserved, pid, identity, fresh) {
|
|
2458
|
+
return !fresh && preserved?.pid === pid && compareProcessBirthIdentity(preserved.identity, identity) === "matching" && performance.now() - preserved.checkedAt < OBSERVATION_REUSE_MS;
|
|
2459
|
+
}
|
|
2460
|
+
async function createLockOwner(options = {}) {
|
|
2461
|
+
const { signal, capturedIdentity } = options;
|
|
2462
|
+
signal?.throwIfAborted();
|
|
2463
|
+
const processIdentity = capturedIdentity === void 0 ? await getOwnProcessIdentity() : capturedIdentity.processIdentity;
|
|
2464
|
+
signal?.throwIfAborted();
|
|
2465
|
+
let preserved;
|
|
2466
|
+
return {
|
|
2467
|
+
payload: {
|
|
2468
|
+
pid: process.pid,
|
|
2469
|
+
processIdentity
|
|
2470
|
+
},
|
|
2471
|
+
async hasExited(payload, fresh, signal) {
|
|
2472
|
+
signal?.throwIfAborted();
|
|
2473
|
+
const pid = lockOwnerPid(payload);
|
|
2474
|
+
if (!pid) return false;
|
|
2475
|
+
const identity = parseProcessBirthIdentity(payload.processIdentity);
|
|
2476
|
+
if (identity && canReuseObservation(preserved, pid, identity, fresh)) return false;
|
|
2477
|
+
const incarnation = await observeProcessIncarnation(pid, identity, IDENTITY_QUERY_TIMEOUT_MS);
|
|
2478
|
+
signal?.throwIfAborted();
|
|
2479
|
+
if (identity && incarnation !== "gone") preserved = {
|
|
2480
|
+
pid,
|
|
2481
|
+
identity,
|
|
2482
|
+
checkedAt: performance.now()
|
|
2483
|
+
};
|
|
2484
|
+
return incarnation === "gone";
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
//#endregion
|
|
2489
|
+
//#region src/prompt-content.ts
|
|
2490
|
+
var PromptInputValidationError = class extends Error {
|
|
2491
|
+
constructor(message) {
|
|
2492
|
+
super(message);
|
|
2493
|
+
this.name = "PromptInputValidationError";
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
function asRecord$1(value) {
|
|
2497
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
2498
|
+
return value;
|
|
2499
|
+
}
|
|
2500
|
+
function isNonEmptyString(value) {
|
|
2501
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
2502
|
+
}
|
|
2503
|
+
function isBase64Data(value) {
|
|
2504
|
+
if (value.length === 0 || value.length % 4 !== 0) return false;
|
|
2505
|
+
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
|
|
2506
|
+
}
|
|
2507
|
+
function isImageMimeType(value) {
|
|
2508
|
+
return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
2509
|
+
}
|
|
2510
|
+
function isAudioMimeType(value) {
|
|
2511
|
+
return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
2512
|
+
}
|
|
2513
|
+
function isTextBlock(value) {
|
|
2514
|
+
const record = asRecord$1(value);
|
|
2515
|
+
return record?.type === "text" && typeof record.text === "string";
|
|
2516
|
+
}
|
|
2517
|
+
function isImageBlock(value) {
|
|
2518
|
+
const record = asRecord$1(value);
|
|
2519
|
+
return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
|
|
2520
|
+
}
|
|
2521
|
+
function isAudioBlock(value) {
|
|
2522
|
+
const record = asRecord$1(value);
|
|
2523
|
+
return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
|
|
2524
|
+
}
|
|
2525
|
+
function isResourceLinkBlock(value) {
|
|
2526
|
+
const record = asRecord$1(value);
|
|
2527
|
+
return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title == null || typeof record.title === "string") && typeof record.name === "string";
|
|
2528
|
+
}
|
|
2529
|
+
function isResourcePayload(value) {
|
|
2530
|
+
const record = asRecord$1(value);
|
|
2531
|
+
if (!record || !isNonEmptyString(record.uri)) return false;
|
|
2532
|
+
return typeof record.text === "string" || typeof record.blob === "string";
|
|
2533
|
+
}
|
|
2534
|
+
function isResourceBlock(value) {
|
|
2535
|
+
const record = asRecord$1(value);
|
|
2536
|
+
return record?.type === "resource" && isResourcePayload(record.resource);
|
|
2537
|
+
}
|
|
2538
|
+
const CONTENT_BLOCK_VALIDATORS = [
|
|
2539
|
+
isTextBlock,
|
|
2540
|
+
isImageBlock,
|
|
2541
|
+
isAudioBlock,
|
|
2542
|
+
isResourceLinkBlock,
|
|
2543
|
+
isResourceBlock
|
|
2544
|
+
];
|
|
2545
|
+
function isContentBlock(value) {
|
|
2546
|
+
return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
|
|
2547
|
+
}
|
|
2548
|
+
const CONTENT_BLOCK_ERROR_VALIDATORS = {
|
|
2549
|
+
text: validateTextContentBlock,
|
|
2550
|
+
image: validateImageContentBlock,
|
|
2551
|
+
audio: validateAudioContentBlock,
|
|
2552
|
+
resource_link: validateResourceLinkContentBlock,
|
|
2553
|
+
resource: validateResourceContentBlock
|
|
2554
|
+
};
|
|
2555
|
+
function contentBlockErrorValidator(type) {
|
|
2556
|
+
return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
|
|
2557
|
+
}
|
|
2558
|
+
function validateTextContentBlock(record, index) {
|
|
2559
|
+
return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
|
|
2560
|
+
}
|
|
2561
|
+
function validateImageContentBlock(record, index) {
|
|
2562
|
+
if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
|
|
2563
|
+
if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
|
|
2564
|
+
if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
|
|
2565
|
+
return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
|
|
2566
|
+
}
|
|
2567
|
+
function validateAudioContentBlock(record, index) {
|
|
2568
|
+
if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
|
|
2569
|
+
if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
|
|
2570
|
+
if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
|
|
2571
|
+
return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
|
|
2572
|
+
}
|
|
2573
|
+
function validateResourceLinkContentBlock(record, index) {
|
|
2574
|
+
if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
|
|
2575
|
+
if (record.title != null && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string or null when present`;
|
|
2576
|
+
if (typeof record.name !== "string") return `prompt[${index}] resource_link block must include a string name`;
|
|
2577
|
+
}
|
|
2578
|
+
function validateResourceContentBlock(record, index) {
|
|
2579
|
+
if (!asRecord$1(record.resource)) return `prompt[${index}] resource block must include a resource object`;
|
|
2580
|
+
return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and a string text or blob field`;
|
|
2581
|
+
}
|
|
2582
|
+
function getContentBlockValidationError(value, index) {
|
|
2583
|
+
const record = asRecord$1(value);
|
|
2584
|
+
if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
|
|
2585
|
+
const validator = contentBlockErrorValidator(record.type);
|
|
2586
|
+
return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
|
|
2587
|
+
}
|
|
2588
|
+
function isPromptInput(value) {
|
|
2589
|
+
return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
|
|
2590
|
+
}
|
|
2591
|
+
function promptCapabilityRequirement(block) {
|
|
2592
|
+
switch (block.type) {
|
|
2593
|
+
case "image": return {
|
|
2594
|
+
blockType: "image",
|
|
2595
|
+
capability: "image"
|
|
2596
|
+
};
|
|
2597
|
+
case "audio": return {
|
|
2598
|
+
blockType: "audio",
|
|
2599
|
+
capability: "audio"
|
|
2600
|
+
};
|
|
2601
|
+
case "resource": return {
|
|
2602
|
+
blockType: "resource",
|
|
2603
|
+
capability: "embeddedContext"
|
|
2604
|
+
};
|
|
2605
|
+
default: return;
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
|
|
2609
|
+
for (const [index, block] of prompt.entries()) {
|
|
2610
|
+
const requirement = promptCapabilityRequirement(block);
|
|
2611
|
+
if (!requirement) continue;
|
|
2612
|
+
if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
|
|
2613
|
+
return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
function textPrompt(text) {
|
|
2617
|
+
return [{
|
|
2618
|
+
type: "text",
|
|
2619
|
+
text
|
|
2620
|
+
}];
|
|
2621
|
+
}
|
|
2622
|
+
function parseStructuredPrompt(source) {
|
|
2623
|
+
if (!source.startsWith("[")) return;
|
|
2624
|
+
try {
|
|
2625
|
+
const parsed = JSON.parse(source);
|
|
2626
|
+
if (isPromptInput(parsed)) return parsed;
|
|
2627
|
+
if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
|
|
2628
|
+
return;
|
|
2629
|
+
} catch (error) {
|
|
2630
|
+
if (error instanceof PromptInputValidationError) throw error;
|
|
2631
|
+
return;
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
function parsePromptSource(source) {
|
|
2635
|
+
const trimmed = source.trim();
|
|
2636
|
+
const structured = parseStructuredPrompt(trimmed);
|
|
2637
|
+
if (structured) return structured;
|
|
2638
|
+
if (!trimmed) return [];
|
|
2639
|
+
return textPrompt(trimmed);
|
|
2640
|
+
}
|
|
2641
|
+
function mergePromptSourceWithText(source, suffixText) {
|
|
2642
|
+
const prompt = parsePromptSource(source);
|
|
2643
|
+
const appended = suffixText.trim();
|
|
2644
|
+
if (!appended) return prompt;
|
|
2645
|
+
if (prompt.length === 0) return textPrompt(appended);
|
|
2646
|
+
return [...prompt, ...textPrompt(appended)];
|
|
2647
|
+
}
|
|
2648
|
+
function promptToDisplayText(prompt) {
|
|
2649
|
+
return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
|
|
2650
|
+
}
|
|
2651
|
+
function contentBlockDisplayText(block) {
|
|
2652
|
+
switch (block.type) {
|
|
2653
|
+
case "text": return block.text;
|
|
2654
|
+
case "resource_link": return block.title ?? block.name ?? block.uri;
|
|
2655
|
+
case "resource": return resourceBlockDisplayText(block);
|
|
2656
|
+
case "image": return `[image] ${block.mimeType}`;
|
|
2657
|
+
case "audio": return `[audio] ${block.mimeType}`;
|
|
2658
|
+
default: return "";
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
function resourceBlockDisplayText(block) {
|
|
2662
|
+
return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
|
|
2663
|
+
}
|
|
2664
|
+
//#endregion
|
|
2665
|
+
//#region src/acp/process-descendants.ts
|
|
2666
|
+
function hasStaleWindowsParent(identity, parent) {
|
|
2667
|
+
return identity.birth.kind === "windows-creation" && (parent?.birth.kind !== "windows-creation" || parent.birth.value > identity.birth.value);
|
|
2668
|
+
}
|
|
2669
|
+
function includeProcessDescendants(table, owned) {
|
|
2670
|
+
let expanded;
|
|
2448
2671
|
do {
|
|
2449
2672
|
expanded = false;
|
|
2450
2673
|
for (const identity of table.values()) {
|
|
@@ -2463,6 +2686,8 @@ var ProcessDescendants = class {
|
|
|
2463
2686
|
rootBirth;
|
|
2464
2687
|
pending;
|
|
2465
2688
|
retired = false;
|
|
2689
|
+
failedRootObservation = false;
|
|
2690
|
+
unresolvedOwnership = false;
|
|
2466
2691
|
ownProcessGroup;
|
|
2467
2692
|
captureGroupAfterExit;
|
|
2468
2693
|
groupExitedAt;
|
|
@@ -2497,10 +2722,18 @@ var ProcessDescendants = class {
|
|
|
2497
2722
|
}
|
|
2498
2723
|
return true;
|
|
2499
2724
|
} catch {
|
|
2500
|
-
|
|
2725
|
+
this.recordSnapshotFailure(captureRootGroup);
|
|
2501
2726
|
return false;
|
|
2502
2727
|
}
|
|
2503
2728
|
}
|
|
2729
|
+
recordSnapshotFailure(captureRootGroup) {
|
|
2730
|
+
if (isChildProcessRunning(this.child)) {
|
|
2731
|
+
this.failedRootObservation = true;
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
if (captureRootGroup) this.unresolvedOwnership = true;
|
|
2735
|
+
this.captureGroupAfterExit = false;
|
|
2736
|
+
}
|
|
2504
2737
|
requiredSnapshotPids(rootWasRunning) {
|
|
2505
2738
|
return [...this.identities.keys(), ...rootWasRunning && this.child.pid ? [this.child.pid] : []];
|
|
2506
2739
|
}
|
|
@@ -2512,6 +2745,10 @@ var ProcessDescendants = class {
|
|
|
2512
2745
|
if (observed && compareProcessBirthIdentity(identity.birth, observed.birth) === "matching") owned.add(pid);
|
|
2513
2746
|
}
|
|
2514
2747
|
this.includeRoot(table, owned);
|
|
2748
|
+
if (owned.has(this.child.pid ?? 0)) {
|
|
2749
|
+
this.failedRootObservation = false;
|
|
2750
|
+
this.unresolvedOwnership = false;
|
|
2751
|
+
}
|
|
2515
2752
|
if (this.ownProcessGroup) this.includeProcessGroup(table, owned, rootWasRunning);
|
|
2516
2753
|
includeProcessDescendants(table, owned);
|
|
2517
2754
|
owned.delete(this.child.pid ?? 0);
|
|
@@ -2532,29 +2769,40 @@ var ProcessDescendants = class {
|
|
|
2532
2769
|
}
|
|
2533
2770
|
includeProcessGroup(table, owned, rootWasRunning) {
|
|
2534
2771
|
const root = this.child.pid;
|
|
2535
|
-
if (root
|
|
2536
|
-
|
|
2772
|
+
if (!root || !(rootWasRunning || [...owned].some((pid) => table.get(pid)?.groupPid === root))) return;
|
|
2773
|
+
this.unresolvedOwnership = !this.admitGroupMembers(table, owned, root);
|
|
2774
|
+
if (!this.unresolvedOwnership) this.failedRootObservation = false;
|
|
2775
|
+
}
|
|
2776
|
+
admitGroupMembers(table, owned, groupPid) {
|
|
2777
|
+
let verified = true;
|
|
2778
|
+
for (const identity of table.values()) {
|
|
2779
|
+
if (identity.groupPid !== groupPid) continue;
|
|
2780
|
+
const beforeExit = this.startedBeforeRootExit(identity);
|
|
2781
|
+
if (beforeExit === void 0) verified = false;
|
|
2782
|
+
else if (beforeExit) owned.add(identity.pid);
|
|
2537
2783
|
}
|
|
2784
|
+
return verified;
|
|
2538
2785
|
}
|
|
2539
2786
|
startedBeforeRootExit(identity) {
|
|
2540
2787
|
const cutoff = this.groupExitedAt;
|
|
2541
2788
|
if (cutoff === void 0) return true;
|
|
2542
|
-
if (cutoff === null) return
|
|
2543
|
-
if (identity.birth.kind !== "linux-proc") return typeof cutoff === "number"
|
|
2544
|
-
if (typeof cutoff === "number" || identity.birth.timeNamespace !== cutoff.timeNamespace || !identity.clockTicksPerSecond) return
|
|
2789
|
+
if (cutoff === null) return;
|
|
2790
|
+
if (identity.birth.kind !== "linux-proc") return typeof cutoff === "number" ? Date.parse(identity.birth.value) <= cutoff : void 0;
|
|
2791
|
+
if (typeof cutoff === "number" || identity.birth.timeNamespace !== cutoff.timeNamespace || !identity.clockTicksPerSecond) return;
|
|
2545
2792
|
return BigInt(identity.birth.startTicks) * 100n < (cutoff.centiseconds + 1n) * identity.clockTicksPerSecond;
|
|
2546
2793
|
}
|
|
2547
2794
|
async signal(signal, timeoutMs) {
|
|
2548
2795
|
if (!await this.capture(timeoutMs) || this.retired) return;
|
|
2549
2796
|
for (const pid of this.identities.keys()) try {
|
|
2550
2797
|
process.kill(pid, signal);
|
|
2551
|
-
} catch {
|
|
2552
|
-
this.identities.delete(pid);
|
|
2553
|
-
}
|
|
2798
|
+
} catch {}
|
|
2554
2799
|
}
|
|
2555
2800
|
hasTrackedProcesses() {
|
|
2556
2801
|
return this.identities.size > 0;
|
|
2557
2802
|
}
|
|
2803
|
+
hasUnresolvedOwnership() {
|
|
2804
|
+
return this.unresolvedOwnership || !this.ownProcessGroup && this.failedRootObservation && !isChildProcessRunning(this.child);
|
|
2805
|
+
}
|
|
2558
2806
|
async waitForExit(timeoutMs) {
|
|
2559
2807
|
const deadline = performance.now() + timeoutMs;
|
|
2560
2808
|
do {
|
|
@@ -2571,46 +2819,6 @@ var ProcessDescendants = class {
|
|
|
2571
2819
|
}
|
|
2572
2820
|
};
|
|
2573
2821
|
//#endregion
|
|
2574
|
-
//#region src/session/lock-owner.ts
|
|
2575
|
-
const OBSERVATION_REUSE_MS = 1e3;
|
|
2576
|
-
const IDENTITY_QUERY_TIMEOUT_MS = 1e3;
|
|
2577
|
-
function lockOwnerPid(value) {
|
|
2578
|
-
if (!value || typeof value !== "object" || !("pid" in value)) return;
|
|
2579
|
-
const pid = value.pid;
|
|
2580
|
-
return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
|
|
2581
|
-
}
|
|
2582
|
-
function canReuseObservation(preserved, pid, identity, fresh) {
|
|
2583
|
-
return !fresh && preserved?.pid === pid && compareProcessBirthIdentity(preserved.identity, identity) === "matching" && performance.now() - preserved.checkedAt < OBSERVATION_REUSE_MS;
|
|
2584
|
-
}
|
|
2585
|
-
async function createLockOwner(options = {}) {
|
|
2586
|
-
const { signal, capturedIdentity } = options;
|
|
2587
|
-
signal?.throwIfAborted();
|
|
2588
|
-
const processIdentity = capturedIdentity === void 0 ? await getOwnProcessIdentity() : capturedIdentity.processIdentity;
|
|
2589
|
-
signal?.throwIfAborted();
|
|
2590
|
-
let preserved;
|
|
2591
|
-
return {
|
|
2592
|
-
payload: {
|
|
2593
|
-
pid: process.pid,
|
|
2594
|
-
processIdentity
|
|
2595
|
-
},
|
|
2596
|
-
async hasExited(payload, fresh, signal) {
|
|
2597
|
-
signal?.throwIfAborted();
|
|
2598
|
-
const pid = lockOwnerPid(payload);
|
|
2599
|
-
if (!pid) return false;
|
|
2600
|
-
const identity = parseProcessBirthIdentity(payload.processIdentity);
|
|
2601
|
-
if (identity && canReuseObservation(preserved, pid, identity, fresh)) return false;
|
|
2602
|
-
const incarnation = await observeProcessIncarnation(pid, identity, IDENTITY_QUERY_TIMEOUT_MS);
|
|
2603
|
-
signal?.throwIfAborted();
|
|
2604
|
-
if (identity && incarnation !== "gone") preserved = {
|
|
2605
|
-
pid,
|
|
2606
|
-
identity,
|
|
2607
|
-
checkedAt: performance.now()
|
|
2608
|
-
};
|
|
2609
|
-
return incarnation === "gone";
|
|
2610
|
-
}
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
//#endregion
|
|
2614
2822
|
//#region src/session/queue/paths.ts
|
|
2615
2823
|
function shortHash(value, length) {
|
|
2616
2824
|
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -2697,16 +2905,30 @@ function retirementTimeRemaining(deadline, maximumMs = 2e3) {
|
|
|
2697
2905
|
if (remaining <= 0) throw queueRetirementIncomplete();
|
|
2698
2906
|
return Math.min(maximumMs, remaining);
|
|
2699
2907
|
}
|
|
2700
|
-
async function
|
|
2908
|
+
async function readRetirementSnapshot(deadline) {
|
|
2909
|
+
if (process.platform !== "win32") throw queueRetirementIncomplete();
|
|
2910
|
+
return await readProcessTable(retirementTimeRemaining(deadline)).catch(() => {
|
|
2911
|
+
throw queueRetirementIncomplete();
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
function observeRetirementSnapshot(witness, table) {
|
|
2915
|
+
if (process.platform !== "win32" || !isWindowsRetirementIdentity(witness.processIdentity)) return "unknown";
|
|
2916
|
+
const observed = table?.get(witness.pid);
|
|
2917
|
+
const comparison = observed ? compareProcessBirthIdentity(witness.processIdentity, observed.birth) : "unknown";
|
|
2918
|
+
if (comparison === "different" || isProcessDefinitelyDead(witness.pid)) return "gone";
|
|
2919
|
+
return witness.pid === process.pid ? "unknown" : comparison;
|
|
2920
|
+
}
|
|
2921
|
+
function isWindowsRetirementIdentity(identity) {
|
|
2922
|
+
return identity === void 0 || identity.kind === "windows-creation";
|
|
2923
|
+
}
|
|
2924
|
+
function captureQueueRetirementReceipt(owner, previous, rootRunning, snapshot) {
|
|
2701
2925
|
const root = parseWitness({
|
|
2702
2926
|
pid: owner.pid,
|
|
2703
2927
|
processIdentity: owner.processIdentity
|
|
2704
2928
|
});
|
|
2705
2929
|
if (!root || process.platform !== "win32") throw queueRetirementIncomplete();
|
|
2706
|
-
const
|
|
2707
|
-
|
|
2708
|
-
});
|
|
2709
|
-
const saved = unsettledSnapshotWitnesses(table, previous ? previous.descendants : []);
|
|
2930
|
+
const saved = previous ? previous.descendants : [];
|
|
2931
|
+
const table = new Map(snapshot);
|
|
2710
2932
|
const owned = matchingSnapshotPids(table, rootRunning ? [root, ...saved] : saved);
|
|
2711
2933
|
if (rootRunning && !owned.has(root.pid)) throw queueRetirementIncomplete();
|
|
2712
2934
|
table.delete(1);
|
|
@@ -2716,7 +2938,7 @@ async function captureQueueRetirementReceipt(owner, previous, rootRunning, deadl
|
|
|
2716
2938
|
const receipt = {
|
|
2717
2939
|
ownerGeneration: owner.ownerGeneration,
|
|
2718
2940
|
root,
|
|
2719
|
-
descendants: mergeSnapshotDescendants(table, owned, saved)
|
|
2941
|
+
descendants: unsettledSnapshotWitnesses(snapshot, mergeSnapshotDescendants(table, owned, saved))
|
|
2720
2942
|
};
|
|
2721
2943
|
if (!parseQueueRetirementReceipt(receipt, owner)) throw queueRetirementIncomplete();
|
|
2722
2944
|
return receipt;
|
|
@@ -2752,7 +2974,11 @@ async function observeRetirementWitness(witness, deadline) {
|
|
|
2752
2974
|
}
|
|
2753
2975
|
async function assertQueueRetirementComplete(receipt, deadline) {
|
|
2754
2976
|
if (receipt === null) throw queueRetirementIncomplete();
|
|
2755
|
-
|
|
2977
|
+
const witnesses = receipt?.descendants ?? [];
|
|
2978
|
+
if (witnesses.length === 0) return;
|
|
2979
|
+
const live = witnesses.filter((witness) => observeRetirementSnapshot(witness, void 0) !== "gone");
|
|
2980
|
+
const table = live.length > 0 ? await readRetirementSnapshot(deadline) : void 0;
|
|
2981
|
+
for (const witness of live) if (observeRetirementSnapshot(witness, table) !== "gone") throw queueRetirementIncomplete();
|
|
2756
2982
|
}
|
|
2757
2983
|
//#endregion
|
|
2758
2984
|
//#region src/session/queue/lease-mutation.ts
|
|
@@ -3255,17 +3481,37 @@ function unverifiedQueueOwnerError(owner) {
|
|
|
3255
3481
|
function retirementDeadline() {
|
|
3256
3482
|
return performance.now() + PROCESS_SIGTERM_GRACE_MS + PROCESS_SIGKILL_GRACE_MS;
|
|
3257
3483
|
}
|
|
3484
|
+
async function createQueueOwnerRetirement(deadline) {
|
|
3485
|
+
const snapshot = process.platform === "win32" ? await readRetirementSnapshot(deadline).catch(() => void 0) : void 0;
|
|
3486
|
+
return {
|
|
3487
|
+
gone: false,
|
|
3488
|
+
unverified: false,
|
|
3489
|
+
leaseReleased: false,
|
|
3490
|
+
deadline,
|
|
3491
|
+
snapshot,
|
|
3492
|
+
capturedIdentity: process.platform === "win32" ? { processIdentity: snapshot?.get(process.pid)?.birth } : void 0
|
|
3493
|
+
};
|
|
3494
|
+
}
|
|
3258
3495
|
async function observeRetiringOwner(owner, deadline) {
|
|
3259
3496
|
return await observeProcessIncarnation(owner.pid, owner.processIdentity, process.platform === "win32" ? retirementTimeRemaining(deadline) : void 0);
|
|
3260
3497
|
}
|
|
3261
3498
|
function retirementBlockedByHeartbeat(owner, signal, requireStale) {
|
|
3262
3499
|
return requireStale && owner.retirement === void 0 && signal === "SIGTERM" && !isQueueOwnerHeartbeatStale(owner);
|
|
3263
3500
|
}
|
|
3264
|
-
async function prepareWindowsRetirement(owner, deadline) {
|
|
3265
|
-
if (owner.retirement === null) throw queueRetirementIncomplete();
|
|
3266
|
-
owner.retirement =
|
|
3501
|
+
async function prepareWindowsRetirement(owner, table, deadline) {
|
|
3502
|
+
if (owner.retirement === null || !table) throw queueRetirementIncomplete();
|
|
3503
|
+
owner.retirement = captureQueueRetirementReceipt(owner, owner.retirement, true, table);
|
|
3267
3504
|
await replaceQueueOwnerRecord(owner);
|
|
3268
|
-
return await observeRetirementWitness(owner.retirement.root, deadline)
|
|
3505
|
+
return await observeRetirementWitness(owner.retirement.root, deadline);
|
|
3506
|
+
}
|
|
3507
|
+
async function prepareRetiringOwner(owner, signal, retirement) {
|
|
3508
|
+
const windows = process.platform === "win32";
|
|
3509
|
+
const table = windows && signal !== "SIGTERM" ? await readRetirementSnapshot(retirement.deadline) : retirement.snapshot;
|
|
3510
|
+
let identity = windows ? observeRetirementSnapshot(owner, table) : await observeRetiringOwner(owner, retirement.deadline);
|
|
3511
|
+
if (identity === "matching" && windows) identity = await prepareWindowsRetirement(owner, table, retirement.deadline);
|
|
3512
|
+
retirement.gone = identity === "gone";
|
|
3513
|
+
retirement.unverified = identity === "unknown";
|
|
3514
|
+
return identity === "matching";
|
|
3269
3515
|
}
|
|
3270
3516
|
async function dispatchVerifiedQueueOwnerSignal(owner, signal, requireStale, retirement) {
|
|
3271
3517
|
return await withQueueLeaseMutation(owner.sessionId, async () => {
|
|
@@ -3273,26 +3519,15 @@ async function dispatchVerifiedQueueOwnerSignal(owner, signal, requireStale, ret
|
|
|
3273
3519
|
retirement.leaseReleased = current?.pid !== owner.pid;
|
|
3274
3520
|
if (!matchesQueueOwner(current, owner) || retirementBlockedByHeartbeat(current, signal, requireStale)) return false;
|
|
3275
3521
|
if (current.retirement === null) throw queueRetirementIncomplete();
|
|
3276
|
-
|
|
3277
|
-
if (identity !== "matching") {
|
|
3278
|
-
retirement.gone = identity === "gone";
|
|
3279
|
-
retirement.unverified = identity === "unknown";
|
|
3280
|
-
return false;
|
|
3281
|
-
}
|
|
3282
|
-
if (process.platform === "win32" && !await prepareWindowsRetirement(current, retirement.deadline)) return false;
|
|
3522
|
+
if (!await prepareRetiringOwner(current, signal, retirement)) return false;
|
|
3283
3523
|
return await dispatchQueueOwnerSignal(owner.pid, signal, retirement.deadline);
|
|
3284
|
-
});
|
|
3524
|
+
}, { capturedIdentity: retirement.capturedIdentity });
|
|
3285
3525
|
}
|
|
3286
|
-
async function retireQueueOwner(owner, requireStale,
|
|
3287
|
-
const
|
|
3288
|
-
|
|
3289
|
-
unverified: false,
|
|
3290
|
-
leaseReleased: false,
|
|
3291
|
-
deadline
|
|
3292
|
-
};
|
|
3293
|
-
await terminateWithDispatch(owner.pid, (signal) => dispatchVerifiedQueueOwnerSignal(owner, signal, requireStale, retirement), isProcessDefinitelyDead, process.platform === "win32" ? deadline : Infinity);
|
|
3526
|
+
async function retireQueueOwner(owner, requireStale, retirement) {
|
|
3527
|
+
const { deadline } = retirement;
|
|
3528
|
+
const exited = await terminateWithDispatch(owner.pid, (signal) => dispatchVerifiedQueueOwnerSignal(owner, signal, requireStale, retirement), isProcessDefinitelyDead, process.platform === "win32" ? deadline : Infinity);
|
|
3294
3529
|
if (await waitForReleasedOwner(owner, requireStale, retirement)) return false;
|
|
3295
|
-
const gone = retirement.gone || await observeRetiringOwner(owner, deadline) === "gone";
|
|
3530
|
+
const gone = retirement.gone || process.platform === "win32" && exited || await observeRetiringOwner(owner, deadline) === "gone";
|
|
3296
3531
|
if (retirement.unverified && !gone) throw unverifiedQueueOwnerError(owner);
|
|
3297
3532
|
return gone;
|
|
3298
3533
|
}
|
|
@@ -3307,44 +3542,80 @@ async function waitForReleasedOwner(owner, requireStale, retirement) {
|
|
|
3307
3542
|
}
|
|
3308
3543
|
return false;
|
|
3309
3544
|
}
|
|
3310
|
-
async function retireRecordedDescendants(owner,
|
|
3545
|
+
async function retireRecordedDescendants(owner, retirement) {
|
|
3311
3546
|
await withQueueLeaseMutation(owner.sessionId, async () => {
|
|
3312
3547
|
const current = await readQueueOwnerRecord(owner.sessionId);
|
|
3313
3548
|
if (!matchesQueueOwner(current, owner) || current.retirement === void 0) return;
|
|
3314
3549
|
if (current.retirement === null || process.platform !== "win32") throw queueRetirementIncomplete();
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
}
|
|
3322
|
-
async function
|
|
3323
|
-
|
|
3324
|
-
const
|
|
3325
|
-
|
|
3326
|
-
if (
|
|
3550
|
+
await retireSnapshotDescendants(current, current.retirement, retirement.deadline);
|
|
3551
|
+
}, { capturedIdentity: retirement.capturedIdentity });
|
|
3552
|
+
}
|
|
3553
|
+
function hasNewRetirementWitness(previous, receipt) {
|
|
3554
|
+
const saved = new Map(previous.descendants.map((witness) => [witness.pid, witness.processIdentity]));
|
|
3555
|
+
return receipt.descendants.some((witness) => compareProcessBirthIdentity(saved.get(witness.pid), witness.processIdentity) !== "matching");
|
|
3556
|
+
}
|
|
3557
|
+
async function retireSnapshotDescendants(owner, receipt, deadline) {
|
|
3558
|
+
while (receipt.descendants.length > 0) {
|
|
3559
|
+
const table = await readRetirementSnapshot(deadline);
|
|
3560
|
+
const discovered = captureQueueRetirementReceipt(owner, receipt, false, table);
|
|
3561
|
+
if (hasNewRetirementWitness(receipt, discovered)) {
|
|
3562
|
+
receipt = discovered;
|
|
3563
|
+
owner.retirement = receipt;
|
|
3564
|
+
await replaceQueueOwnerRecord(owner);
|
|
3565
|
+
continue;
|
|
3566
|
+
}
|
|
3567
|
+
signalRecordedDescendants(discovered, table, deadline);
|
|
3568
|
+
await waitForRecordedDescendants(discovered, deadline);
|
|
3569
|
+
discovered.descendants = discovered.descendants.filter((witness) => !isProcessDefinitelyDead(witness.pid));
|
|
3570
|
+
receipt = discovered;
|
|
3571
|
+
owner.retirement = receipt;
|
|
3572
|
+
await replaceQueueOwnerRecord(owner);
|
|
3327
3573
|
}
|
|
3328
|
-
return false;
|
|
3329
3574
|
}
|
|
3330
|
-
|
|
3575
|
+
function leafFirstRetirementWitnesses(receipt, table) {
|
|
3576
|
+
const children = new Map(receipt.descendants.map((witness) => [witness.pid, 0]));
|
|
3331
3577
|
for (const witness of receipt.descendants) {
|
|
3332
|
-
const
|
|
3333
|
-
|
|
3334
|
-
if (
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3578
|
+
const parent = retirementParent(witness.pid, table);
|
|
3579
|
+
const count = children.get(parent);
|
|
3580
|
+
if (count !== void 0) children.set(parent, count + 1);
|
|
3581
|
+
}
|
|
3582
|
+
const pending = receipt.descendants.filter((witness) => children.get(witness.pid) === 0);
|
|
3583
|
+
const byPid = new Map(receipt.descendants.map((witness) => [witness.pid, witness]));
|
|
3584
|
+
for (let index = 0; index < pending.length; index += 1) {
|
|
3585
|
+
const parent = retirementParent(pending[index].pid, table);
|
|
3586
|
+
const count = children.get(parent);
|
|
3587
|
+
if (count !== void 0) {
|
|
3588
|
+
const remaining = count - 1;
|
|
3589
|
+
children.set(parent, remaining);
|
|
3590
|
+
if (remaining === 0) pending.push(byPid.get(parent));
|
|
3341
3591
|
}
|
|
3342
3592
|
}
|
|
3593
|
+
if (pending.length !== receipt.descendants.length) throw queueRetirementIncomplete();
|
|
3594
|
+
return pending;
|
|
3595
|
+
}
|
|
3596
|
+
function retirementParent(pid, table) {
|
|
3597
|
+
const identity = table.get(pid);
|
|
3598
|
+
return identity && !hasStaleWindowsParent(identity, table.get(identity.parentPid)) ? identity.parentPid : 0;
|
|
3599
|
+
}
|
|
3600
|
+
function signalRecordedDescendants(receipt, table, deadline) {
|
|
3601
|
+
if (receipt.descendants.some((witness) => observeRetirementSnapshot(witness, table) === "unknown")) throw queueRetirementIncomplete();
|
|
3602
|
+
const ordered = leafFirstRetirementWitnesses(receipt, table);
|
|
3603
|
+
let failure;
|
|
3604
|
+
for (const witness of ordered) {
|
|
3605
|
+
if (observeRetirementSnapshot(witness, table) !== "matching") continue;
|
|
3606
|
+
retirementTimeRemaining(deadline);
|
|
3607
|
+
try {
|
|
3608
|
+
process.kill(witness.pid, "SIGKILL");
|
|
3609
|
+
} catch (error) {
|
|
3610
|
+
if (!isProcessDefinitelyDead(witness.pid)) failure ??= error;
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
if (failure) throw failure;
|
|
3343
3614
|
}
|
|
3344
3615
|
async function waitForRecordedDescendants(receipt, deadline) {
|
|
3345
|
-
|
|
3346
|
-
if (
|
|
3347
|
-
await waitMs(Math.min(
|
|
3616
|
+
for (let waited = 0; waited < 1e3; waited += PROCESS_POLL_MS) {
|
|
3617
|
+
if (receipt.descendants.every((witness) => isProcessDefinitelyDead(witness.pid))) return;
|
|
3618
|
+
await waitMs(Math.min(PROCESS_POLL_MS, retirementTimeRemaining(deadline)));
|
|
3348
3619
|
}
|
|
3349
3620
|
}
|
|
3350
3621
|
async function assertNoPendingRetirement(owner) {
|
|
@@ -3360,12 +3631,13 @@ async function terminateQueueOwnerForSession(sessionId, expectedOwner, requireSt
|
|
|
3360
3631
|
return;
|
|
3361
3632
|
}
|
|
3362
3633
|
const deadline = retirementDeadline();
|
|
3363
|
-
|
|
3634
|
+
const retirement = await createQueueOwnerRetirement(deadline);
|
|
3635
|
+
if (!await retireQueueOwner(owner, requireStale, retirement)) {
|
|
3364
3636
|
await assertNoPendingRetirement(owner);
|
|
3365
3637
|
return;
|
|
3366
3638
|
}
|
|
3367
|
-
await retireRecordedDescendants(owner,
|
|
3368
|
-
await cleanupQueueOwnerFiles(sessionId, owner.socketPath, () => ownsQueueLease(owner),
|
|
3639
|
+
await retireRecordedDescendants(owner, retirement);
|
|
3640
|
+
await cleanupQueueOwnerFiles(sessionId, owner.socketPath, () => ownsQueueLease(owner), retirement.capturedIdentity, deadline);
|
|
3369
3641
|
}
|
|
3370
3642
|
async function waitMs(ms) {
|
|
3371
3643
|
await new Promise((resolve) => {
|
|
@@ -3815,7 +4087,7 @@ function parseStringResultOwnerMessage(message, context, type, field) {
|
|
|
3815
4087
|
function parseSetModelOwnerMessage(message, context) {
|
|
3816
4088
|
if (typeof message.modelId !== "string") return null;
|
|
3817
4089
|
const response = asRecord(message.response);
|
|
3818
|
-
if (message.response !== void 0 && (!response || !Array.isArray(response.configOptions))) return null;
|
|
4090
|
+
if (message.response !== void 0 && (!response || response.configOptions !== void 0 && !Array.isArray(response.configOptions))) return null;
|
|
3819
4091
|
return {
|
|
3820
4092
|
type: "set_model_result",
|
|
3821
4093
|
...context,
|
|
@@ -3825,7 +4097,7 @@ function parseSetModelOwnerMessage(message, context) {
|
|
|
3825
4097
|
}
|
|
3826
4098
|
function parseSetConfigOptionOwnerMessage(message, context) {
|
|
3827
4099
|
const response = asRecord(message.response);
|
|
3828
|
-
if (!response || !Array.isArray(response.configOptions)) return null;
|
|
4100
|
+
if (!response || response.configOptions !== void 0 && !Array.isArray(response.configOptions)) return null;
|
|
3829
4101
|
return {
|
|
3830
4102
|
type: "set_config_option_result",
|
|
3831
4103
|
...context,
|
|
@@ -3870,8 +4142,611 @@ function assertQueueRequestSize(line) {
|
|
|
3870
4142
|
});
|
|
3871
4143
|
}
|
|
3872
4144
|
//#endregion
|
|
4145
|
+
//#region src/session/queue/socket-output.ts
|
|
4146
|
+
const OUTPUT_CHUNK_BYTES = 65536;
|
|
4147
|
+
const DRAIN_TIMEOUT_MS = 1e3;
|
|
4148
|
+
const DEFAULT_LIMITS = Object.freeze({
|
|
4149
|
+
observerBytes: 67108864,
|
|
4150
|
+
totalBytes: 268435456,
|
|
4151
|
+
observers: 64
|
|
4152
|
+
});
|
|
4153
|
+
var QueueOutputBudget = class {
|
|
4154
|
+
limits;
|
|
4155
|
+
bytes = 0;
|
|
4156
|
+
files = 0;
|
|
4157
|
+
observers = 0;
|
|
4158
|
+
constructor(limits = DEFAULT_LIMITS) {
|
|
4159
|
+
this.limits = limits;
|
|
4160
|
+
}
|
|
4161
|
+
acquire() {
|
|
4162
|
+
if (this.files >= this.limits.observers) throw new Error("Queue output spool descriptor limit reached");
|
|
4163
|
+
this.files += 1;
|
|
4164
|
+
}
|
|
4165
|
+
grow(bytes) {
|
|
4166
|
+
if (bytes > this.limits.totalBytes - this.bytes) throw new Error("Queue output spool storage limit reached");
|
|
4167
|
+
this.bytes += bytes;
|
|
4168
|
+
}
|
|
4169
|
+
release(bytes) {
|
|
4170
|
+
this.bytes -= bytes;
|
|
4171
|
+
this.files -= 1;
|
|
4172
|
+
}
|
|
4173
|
+
acquireObserver() {
|
|
4174
|
+
if (this.observers >= this.limits.observers) throw new Error("Queue blocked observer limit reached");
|
|
4175
|
+
this.observers += 1;
|
|
4176
|
+
}
|
|
4177
|
+
releaseObserver() {
|
|
4178
|
+
this.observers -= 1;
|
|
4179
|
+
}
|
|
4180
|
+
};
|
|
4181
|
+
var OutputRing = class {
|
|
4182
|
+
budget;
|
|
4183
|
+
fd;
|
|
4184
|
+
physicalBytes = 0;
|
|
4185
|
+
readOffset = 0;
|
|
4186
|
+
length = 0;
|
|
4187
|
+
constructor(budget) {
|
|
4188
|
+
this.budget = budget;
|
|
4189
|
+
budget.acquire();
|
|
4190
|
+
try {
|
|
4191
|
+
const root = resolveSecureTempRoot({ fallbackPrefix: "acpx-output" });
|
|
4192
|
+
const file = path.join(root, `${randomUUID()}.tmp`);
|
|
4193
|
+
this.fd = fs.openSync(file, "wx+", 384);
|
|
4194
|
+
fs.unlinkSync(file);
|
|
4195
|
+
} catch (error) {
|
|
4196
|
+
if (this.fd === void 0) budget.release(0);
|
|
4197
|
+
else this.close();
|
|
4198
|
+
throw error;
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
append(bytes, offset) {
|
|
4202
|
+
const capacity = this.budget.limits.observerBytes;
|
|
4203
|
+
if (bytes.length - offset > capacity - this.length) throw new Error("Queue observer output backlog limit reached");
|
|
4204
|
+
while (offset < bytes.length) {
|
|
4205
|
+
const position = (this.readOffset + this.length) % capacity;
|
|
4206
|
+
const count = Math.min(OUTPUT_CHUNK_BYTES, bytes.length - offset, capacity - position);
|
|
4207
|
+
const growth = Math.max(0, position + count - this.physicalBytes);
|
|
4208
|
+
this.budget.grow(growth);
|
|
4209
|
+
this.physicalBytes += growth;
|
|
4210
|
+
const written = fs.writeSync(this.fd, bytes, offset, count, position);
|
|
4211
|
+
if (written <= 0) throw new Error("Queue output spool write made no progress");
|
|
4212
|
+
offset += written;
|
|
4213
|
+
this.length += written;
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
read() {
|
|
4217
|
+
const capacity = this.budget.limits.observerBytes;
|
|
4218
|
+
const bytes = Buffer.allocUnsafeSlow(Math.min(OUTPUT_CHUNK_BYTES, this.length, capacity - this.readOffset));
|
|
4219
|
+
let offset = 0;
|
|
4220
|
+
while (offset < bytes.length) {
|
|
4221
|
+
const read = fs.readSync(this.fd, bytes, offset, bytes.length - offset, this.readOffset + offset);
|
|
4222
|
+
if (read <= 0) throw new Error("Queue output spool ended before its committed bytes");
|
|
4223
|
+
offset += read;
|
|
4224
|
+
}
|
|
4225
|
+
this.readOffset = (this.readOffset + bytes.length) % capacity;
|
|
4226
|
+
this.length -= bytes.length;
|
|
4227
|
+
return bytes;
|
|
4228
|
+
}
|
|
4229
|
+
close() {
|
|
4230
|
+
const fd = this.fd;
|
|
4231
|
+
this.fd = void 0;
|
|
4232
|
+
if (fd !== void 0) {
|
|
4233
|
+
fs.closeSync(fd);
|
|
4234
|
+
this.budget.release(this.physicalBytes);
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
};
|
|
4238
|
+
var QueueSocketOutput = class {
|
|
4239
|
+
socket;
|
|
4240
|
+
budget;
|
|
4241
|
+
ring;
|
|
4242
|
+
blocked = false;
|
|
4243
|
+
ending = false;
|
|
4244
|
+
disposed = false;
|
|
4245
|
+
reserved = false;
|
|
4246
|
+
pendingWrites = 0;
|
|
4247
|
+
constructor(socket, budget) {
|
|
4248
|
+
this.socket = socket;
|
|
4249
|
+
this.budget = budget;
|
|
4250
|
+
socket.on("drain", this.onDrain);
|
|
4251
|
+
socket.once("close", () => {
|
|
4252
|
+
this.disposed = true;
|
|
4253
|
+
socket.off("drain", this.onDrain);
|
|
4254
|
+
this.closeSpool();
|
|
4255
|
+
this.releaseObserver();
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
send(message) {
|
|
4259
|
+
if (this.ending || this.socket.destroyed || !this.socket.writable) return;
|
|
4260
|
+
try {
|
|
4261
|
+
this.writeFrame(Buffer.from(`${JSON.stringify(message)}\n`));
|
|
4262
|
+
} catch (error) {
|
|
4263
|
+
this.fail(error);
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
writeFrame(bytes) {
|
|
4267
|
+
let offset = 0;
|
|
4268
|
+
while (!this.blocked && offset < bytes.length) {
|
|
4269
|
+
const end = Math.min(offset + OUTPUT_CHUNK_BYTES, bytes.length);
|
|
4270
|
+
const chunk = Buffer.allocUnsafeSlow(end - offset);
|
|
4271
|
+
bytes.copy(chunk, 0, offset, end);
|
|
4272
|
+
this.write(chunk);
|
|
4273
|
+
offset = end;
|
|
4274
|
+
}
|
|
4275
|
+
if (offset < bytes.length) {
|
|
4276
|
+
this.ring ??= new OutputRing(this.budget);
|
|
4277
|
+
this.ring.append(bytes, offset);
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
end() {
|
|
4281
|
+
if (this.ending || this.socket.destroyed) return;
|
|
4282
|
+
this.ending = true;
|
|
4283
|
+
this.armTimeout();
|
|
4284
|
+
this.finishIfDrained();
|
|
4285
|
+
}
|
|
4286
|
+
write(bytes) {
|
|
4287
|
+
if (!this.reserved) {
|
|
4288
|
+
this.budget.acquireObserver();
|
|
4289
|
+
this.reserved = true;
|
|
4290
|
+
}
|
|
4291
|
+
this.pendingWrites += 1;
|
|
4292
|
+
try {
|
|
4293
|
+
this.blocked = !this.socket.write(bytes, this.onWrite);
|
|
4294
|
+
} catch (error) {
|
|
4295
|
+
this.pendingWrites -= 1;
|
|
4296
|
+
throw error;
|
|
4297
|
+
}
|
|
4298
|
+
if (this.blocked && !this.socket.timeout) this.armTimeout();
|
|
4299
|
+
}
|
|
4300
|
+
onWrite = (error) => {
|
|
4301
|
+
this.pendingWrites -= 1;
|
|
4302
|
+
if (this.disposed) return;
|
|
4303
|
+
if (error) {
|
|
4304
|
+
this.fail(error);
|
|
4305
|
+
return;
|
|
4306
|
+
}
|
|
4307
|
+
this.releaseIfIdle();
|
|
4308
|
+
};
|
|
4309
|
+
armTimeout() {
|
|
4310
|
+
if (process.platform !== "win32") this.socket.setTimeout(DRAIN_TIMEOUT_MS);
|
|
4311
|
+
}
|
|
4312
|
+
onDrain = () => {
|
|
4313
|
+
if (this.disposed) return;
|
|
4314
|
+
this.blocked = false;
|
|
4315
|
+
if (!this.ending) this.socket.setTimeout(0);
|
|
4316
|
+
try {
|
|
4317
|
+
this.pump();
|
|
4318
|
+
this.releaseIfIdle();
|
|
4319
|
+
this.finishIfDrained();
|
|
4320
|
+
} catch (error) {
|
|
4321
|
+
this.fail(error);
|
|
4322
|
+
}
|
|
4323
|
+
};
|
|
4324
|
+
pump() {
|
|
4325
|
+
while (!this.blocked && this.ring && this.ring.length > 0) this.write(this.ring.read());
|
|
4326
|
+
if (this.ring?.length === 0) this.closeSpool();
|
|
4327
|
+
}
|
|
4328
|
+
finishIfDrained() {
|
|
4329
|
+
if (this.ending && !this.ring?.length && !this.socket.writableEnded) this.socket.end(() => this.socket.destroy());
|
|
4330
|
+
}
|
|
4331
|
+
releaseObserver() {
|
|
4332
|
+
if (this.reserved) {
|
|
4333
|
+
this.reserved = false;
|
|
4334
|
+
this.budget.releaseObserver();
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
releaseIfIdle() {
|
|
4338
|
+
if (this.pendingWrites === 0 && !this.blocked && !this.ring?.length) this.releaseObserver();
|
|
4339
|
+
}
|
|
4340
|
+
closeSpool() {
|
|
4341
|
+
const ring = this.ring;
|
|
4342
|
+
this.ring = void 0;
|
|
4343
|
+
try {
|
|
4344
|
+
ring?.close();
|
|
4345
|
+
} catch (error) {
|
|
4346
|
+
this.socket.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
fail(error) {
|
|
4350
|
+
this.disposed = true;
|
|
4351
|
+
this.socket.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
4352
|
+
this.closeSpool();
|
|
4353
|
+
}
|
|
4354
|
+
};
|
|
4355
|
+
//#endregion
|
|
4356
|
+
//#region src/session/queue/ipc-server.ts
|
|
4357
|
+
const QUEUE_SOCKET_DRAIN_TIMEOUT_MS = 1e3;
|
|
4358
|
+
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
4359
|
+
return {
|
|
4360
|
+
type: "error",
|
|
4361
|
+
requestId,
|
|
4362
|
+
ownerGeneration: void 0,
|
|
4363
|
+
code: "RUNTIME",
|
|
4364
|
+
detailCode,
|
|
4365
|
+
origin: "queue",
|
|
4366
|
+
retryable: options.retryable,
|
|
4367
|
+
message
|
|
4368
|
+
};
|
|
4369
|
+
}
|
|
4370
|
+
function makeQueueOwnerErrorFromUnknown(requestId, error, detailCode, options = {}) {
|
|
4371
|
+
const normalized = normalizeOutputError(error, {
|
|
4372
|
+
defaultCode: "RUNTIME",
|
|
4373
|
+
origin: "queue",
|
|
4374
|
+
detailCode,
|
|
4375
|
+
retryable: options.retryable
|
|
4376
|
+
});
|
|
4377
|
+
return {
|
|
4378
|
+
type: "error",
|
|
4379
|
+
requestId,
|
|
4380
|
+
code: normalized.code,
|
|
4381
|
+
detailCode: normalized.detailCode,
|
|
4382
|
+
origin: normalized.origin,
|
|
4383
|
+
message: normalized.message,
|
|
4384
|
+
retryable: normalized.retryable,
|
|
4385
|
+
acp: normalized.acp
|
|
4386
|
+
};
|
|
4387
|
+
}
|
|
4388
|
+
var SessionQueueOwner = class SessionQueueOwner {
|
|
4389
|
+
server;
|
|
4390
|
+
controlHandlers;
|
|
4391
|
+
ownerGeneration;
|
|
4392
|
+
maxQueueDepth;
|
|
4393
|
+
maxRequestBytes;
|
|
4394
|
+
onQueueDepthChanged;
|
|
4395
|
+
pending = [];
|
|
4396
|
+
activeTask;
|
|
4397
|
+
waiters = [];
|
|
4398
|
+
sockets = /* @__PURE__ */ new Set();
|
|
4399
|
+
taskSockets = /* @__PURE__ */ new Set();
|
|
4400
|
+
drainingSockets = /* @__PURE__ */ new Set();
|
|
4401
|
+
outputBudget = new QueueOutputBudget();
|
|
4402
|
+
outputs = /* @__PURE__ */ new Map();
|
|
4403
|
+
closed = false;
|
|
4404
|
+
constructor(server, controlHandlers, lease, options) {
|
|
4405
|
+
this.server = server;
|
|
4406
|
+
this.controlHandlers = controlHandlers;
|
|
4407
|
+
this.ownerGeneration = lease.ownerGeneration;
|
|
4408
|
+
this.maxQueueDepth = Math.max(1, Math.round(options.maxQueueDepth));
|
|
4409
|
+
this.maxRequestBytes = queueRequestByteLimit(options.maxRequestBytes?.toString());
|
|
4410
|
+
this.onQueueDepthChanged = options.onQueueDepthChanged;
|
|
4411
|
+
}
|
|
4412
|
+
static async start(lease, controlHandlers, options = { maxQueueDepth: 16 }) {
|
|
4413
|
+
const ownerRef = { current: void 0 };
|
|
4414
|
+
const server = net.createServer((socket) => {
|
|
4415
|
+
ownerRef.current?.handleConnection(socket);
|
|
4416
|
+
});
|
|
4417
|
+
ownerRef.current = new SessionQueueOwner(server, controlHandlers, lease, options);
|
|
4418
|
+
await new Promise((resolve, reject) => {
|
|
4419
|
+
const onListening = () => {
|
|
4420
|
+
server.off("error", onError);
|
|
4421
|
+
resolve();
|
|
4422
|
+
};
|
|
4423
|
+
const onError = (error) => {
|
|
4424
|
+
server.off("listening", onListening);
|
|
4425
|
+
reject(error);
|
|
4426
|
+
};
|
|
4427
|
+
server.once("listening", onListening);
|
|
4428
|
+
server.once("error", onError);
|
|
4429
|
+
server.listen(lease.socketPath);
|
|
4430
|
+
});
|
|
4431
|
+
return ownerRef.current;
|
|
4432
|
+
}
|
|
4433
|
+
beginShutdown() {
|
|
4434
|
+
if (this.closed) return;
|
|
4435
|
+
this.closed = true;
|
|
4436
|
+
for (const waiter of this.waiters.splice(0)) waiter(void 0);
|
|
4437
|
+
for (const task of this.pending.splice(0)) {
|
|
4438
|
+
if (task.waitForCompletion) task.send(makeQueueOwnerError(task.requestId, "Queue owner shutting down before prompt execution", "QUEUE_OWNER_SHUTTING_DOWN", { retryable: true }));
|
|
4439
|
+
task.close();
|
|
4440
|
+
}
|
|
4441
|
+
for (const socket of this.sockets) if (!this.taskSockets.has(socket) && !this.drainingSockets.has(socket)) socket.destroy();
|
|
4442
|
+
this.emitQueueDepth();
|
|
4443
|
+
}
|
|
4444
|
+
async close() {
|
|
4445
|
+
this.beginShutdown();
|
|
4446
|
+
await new Promise((resolve) => {
|
|
4447
|
+
const forceCloseTimer = setTimeout(() => {
|
|
4448
|
+
for (const socket of this.sockets) socket.destroy();
|
|
4449
|
+
}, QUEUE_SOCKET_DRAIN_TIMEOUT_MS);
|
|
4450
|
+
forceCloseTimer.unref();
|
|
4451
|
+
this.server.close(() => {
|
|
4452
|
+
clearTimeout(forceCloseTimer);
|
|
4453
|
+
resolve();
|
|
4454
|
+
});
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
async nextTask(timeoutMs) {
|
|
4458
|
+
if (this.pending.length > 0) {
|
|
4459
|
+
const task = this.pending.shift();
|
|
4460
|
+
this.emitQueueDepth();
|
|
4461
|
+
if (task) {
|
|
4462
|
+
this.activeTask = task;
|
|
4463
|
+
recordPerfDuration("queue.owner.wait_ms", Date.now() - task.enqueuedAt);
|
|
4464
|
+
}
|
|
4465
|
+
return task;
|
|
4466
|
+
}
|
|
4467
|
+
if (this.closed) return;
|
|
4468
|
+
return await new Promise((resolve) => {
|
|
4469
|
+
const timer = timeoutMs != null && setTimeout(() => {
|
|
4470
|
+
const index = this.waiters.indexOf(waiter);
|
|
4471
|
+
if (index >= 0) this.waiters.splice(index, 1);
|
|
4472
|
+
resolve(void 0);
|
|
4473
|
+
}, Math.max(0, timeoutMs));
|
|
4474
|
+
const waiter = (task) => {
|
|
4475
|
+
if (timer) clearTimeout(timer);
|
|
4476
|
+
resolve(task);
|
|
4477
|
+
};
|
|
4478
|
+
this.waiters.push(waiter);
|
|
4479
|
+
});
|
|
4480
|
+
}
|
|
4481
|
+
queueDepth() {
|
|
4482
|
+
return this.pending.length;
|
|
4483
|
+
}
|
|
4484
|
+
completeTask(task) {
|
|
4485
|
+
if (this.activeTask === task) this.activeTask = void 0;
|
|
4486
|
+
}
|
|
4487
|
+
async cancelPrompt(targetRequestId) {
|
|
4488
|
+
if (targetRequestId === void 0) return await this.controlHandlers.cancelPrompt();
|
|
4489
|
+
const index = this.pending.findIndex((task) => task.requestId === targetRequestId);
|
|
4490
|
+
if (index >= 0) {
|
|
4491
|
+
const [task] = this.pending.splice(index, 1);
|
|
4492
|
+
task.send(makeQueueOwnerError(task.requestId, "Prompt cancelled before execution", "QUEUE_REQUEST_CANCELLED", { retryable: false }));
|
|
4493
|
+
task.close();
|
|
4494
|
+
this.emitQueueDepth();
|
|
4495
|
+
return true;
|
|
4496
|
+
}
|
|
4497
|
+
return this.activeTask?.requestId === targetRequestId ? await this.controlHandlers.cancelPrompt() : false;
|
|
4498
|
+
}
|
|
4499
|
+
emitQueueDepth() {
|
|
4500
|
+
this.onQueueDepthChanged?.(this.pending.length);
|
|
4501
|
+
}
|
|
4502
|
+
enqueue(task) {
|
|
4503
|
+
if (this.closed) {
|
|
4504
|
+
task.send(makeQueueOwnerError(task.requestId, "Queue owner is shutting down", "QUEUE_OWNER_SHUTTING_DOWN", { retryable: true }));
|
|
4505
|
+
task.close();
|
|
4506
|
+
return false;
|
|
4507
|
+
}
|
|
4508
|
+
if (this.activeTask?.requestId === task.requestId || this.pending.some((queued) => queued.requestId === task.requestId)) {
|
|
4509
|
+
task.send(makeQueueOwnerError(task.requestId, "Request is already queued or active", "QUEUE_REQUEST_DUPLICATE", { retryable: false }));
|
|
4510
|
+
task.close();
|
|
4511
|
+
return false;
|
|
4512
|
+
}
|
|
4513
|
+
const waiter = this.waiters.shift();
|
|
4514
|
+
if (waiter) {
|
|
4515
|
+
this.activeTask = task;
|
|
4516
|
+
waiter(task);
|
|
4517
|
+
return true;
|
|
4518
|
+
}
|
|
4519
|
+
if (this.pending.length >= this.maxQueueDepth) {
|
|
4520
|
+
task.send({
|
|
4521
|
+
...makeQueueOwnerError(task.requestId, `Queue owner is overloaded (${this.pending.length}/${this.maxQueueDepth} queued)`, "QUEUE_OWNER_OVERLOADED", { retryable: true }),
|
|
4522
|
+
ownerGeneration: this.ownerGeneration
|
|
4523
|
+
});
|
|
4524
|
+
task.close();
|
|
4525
|
+
return false;
|
|
4526
|
+
}
|
|
4527
|
+
this.pending.push(task);
|
|
4528
|
+
this.emitQueueDepth();
|
|
4529
|
+
return true;
|
|
4530
|
+
}
|
|
4531
|
+
handleControlRequest(options) {
|
|
4532
|
+
this.taskSockets.add(options.socket);
|
|
4533
|
+
this.writeQueueMessage(options.socket, {
|
|
4534
|
+
type: "accepted",
|
|
4535
|
+
requestId: options.requestId,
|
|
4536
|
+
ownerGeneration: this.ownerGeneration
|
|
4537
|
+
});
|
|
4538
|
+
options.run().then((message) => {
|
|
4539
|
+
this.writeQueueMessage(options.socket, {
|
|
4540
|
+
...message,
|
|
4541
|
+
ownerGeneration: this.ownerGeneration
|
|
4542
|
+
});
|
|
4543
|
+
}).catch((error) => {
|
|
4544
|
+
this.writeQueueMessage(options.socket, {
|
|
4545
|
+
...makeQueueOwnerErrorFromUnknown(options.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
|
|
4546
|
+
ownerGeneration: this.ownerGeneration
|
|
4547
|
+
});
|
|
4548
|
+
}).finally(() => {
|
|
4549
|
+
this.endSocket(options.socket);
|
|
4550
|
+
});
|
|
4551
|
+
}
|
|
4552
|
+
writeQueueMessage(socket, message) {
|
|
4553
|
+
this.outputs.get(socket)?.send(message);
|
|
4554
|
+
}
|
|
4555
|
+
endSocket(socket) {
|
|
4556
|
+
if (socket.destroyed || this.drainingSockets.has(socket)) return;
|
|
4557
|
+
this.taskSockets.delete(socket);
|
|
4558
|
+
this.drainingSockets.add(socket);
|
|
4559
|
+
this.outputs.get(socket)?.end();
|
|
4560
|
+
}
|
|
4561
|
+
failRequest(socket, requestId, message, detailCode) {
|
|
4562
|
+
this.writeQueueMessage(socket, {
|
|
4563
|
+
...makeQueueOwnerError(requestId, message, detailCode, { retryable: false }),
|
|
4564
|
+
ownerGeneration: this.ownerGeneration
|
|
4565
|
+
});
|
|
4566
|
+
this.endSocket(socket);
|
|
4567
|
+
}
|
|
4568
|
+
parseRequestLine(socket, line) {
|
|
4569
|
+
let parsed;
|
|
4570
|
+
try {
|
|
4571
|
+
parsed = JSON.parse(line);
|
|
4572
|
+
} catch {
|
|
4573
|
+
this.failRequest(socket, "unknown", "Invalid queue request payload", "QUEUE_REQUEST_PAYLOAD_INVALID_JSON");
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4576
|
+
const request = parseQueueRequest(parsed);
|
|
4577
|
+
if (!request) this.failRequest(socket, "unknown", "Invalid queue request", "QUEUE_REQUEST_INVALID");
|
|
4578
|
+
return request ?? void 0;
|
|
4579
|
+
}
|
|
4580
|
+
rejectStaleOwnerGeneration(socket, request) {
|
|
4581
|
+
if (request.ownerGeneration === void 0 || this.ownerGeneration === void 0 || request.ownerGeneration === this.ownerGeneration) return false;
|
|
4582
|
+
this.failRequest(socket, request.requestId, "Queue request targeted a stale queue owner generation", "QUEUE_OWNER_GENERATION_MISMATCH");
|
|
4583
|
+
return true;
|
|
4584
|
+
}
|
|
4585
|
+
rejectClosedOwner(socket, request) {
|
|
4586
|
+
if (!this.closed) return false;
|
|
4587
|
+
this.writeQueueMessage(socket, {
|
|
4588
|
+
...makeQueueOwnerError(request.requestId, "Queue owner is shutting down", "QUEUE_OWNER_CLOSED", { retryable: true }),
|
|
4589
|
+
ownerGeneration: this.ownerGeneration
|
|
4590
|
+
});
|
|
4591
|
+
this.endSocket(socket);
|
|
4592
|
+
return true;
|
|
4593
|
+
}
|
|
4594
|
+
handleControlQueueRequest(socket, request) {
|
|
4595
|
+
if (request.type === "cancel_prompt") {
|
|
4596
|
+
this.handleControlRequest({
|
|
4597
|
+
socket,
|
|
4598
|
+
requestId: request.requestId,
|
|
4599
|
+
run: async () => ({
|
|
4600
|
+
type: "cancel_result",
|
|
4601
|
+
requestId: request.requestId,
|
|
4602
|
+
cancelled: await this.cancelPrompt(request.targetRequestId)
|
|
4603
|
+
})
|
|
4604
|
+
});
|
|
4605
|
+
return true;
|
|
4606
|
+
}
|
|
4607
|
+
if (request.type === "close_session") {
|
|
4608
|
+
this.handleControlRequest({
|
|
4609
|
+
socket,
|
|
4610
|
+
requestId: request.requestId,
|
|
4611
|
+
run: async () => ({
|
|
4612
|
+
type: "close_session_result",
|
|
4613
|
+
requestId: request.requestId,
|
|
4614
|
+
closed: await this.controlHandlers.closeSession(request.timeoutMs)
|
|
4615
|
+
})
|
|
4616
|
+
});
|
|
4617
|
+
return true;
|
|
4618
|
+
}
|
|
4619
|
+
return this.handleSessionControlQueueRequest(socket, request);
|
|
4620
|
+
}
|
|
4621
|
+
handleSessionControlQueueRequest(socket, request) {
|
|
4622
|
+
if (request.type === "set_mode") {
|
|
4623
|
+
this.handleControlRequest({
|
|
4624
|
+
socket,
|
|
4625
|
+
requestId: request.requestId,
|
|
4626
|
+
run: async () => {
|
|
4627
|
+
await this.controlHandlers.setSessionMode(request.modeId, request.timeoutMs);
|
|
4628
|
+
return {
|
|
4629
|
+
type: "set_mode_result",
|
|
4630
|
+
requestId: request.requestId,
|
|
4631
|
+
modeId: request.modeId
|
|
4632
|
+
};
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
return true;
|
|
4636
|
+
}
|
|
4637
|
+
if (request.type === "set_model") {
|
|
4638
|
+
this.handleControlRequest({
|
|
4639
|
+
socket,
|
|
4640
|
+
requestId: request.requestId,
|
|
4641
|
+
run: async () => {
|
|
4642
|
+
const response = await this.controlHandlers.setSessionModel(request.modelId, request.timeoutMs);
|
|
4643
|
+
return {
|
|
4644
|
+
type: "set_model_result",
|
|
4645
|
+
requestId: request.requestId,
|
|
4646
|
+
modelId: request.modelId,
|
|
4647
|
+
response
|
|
4648
|
+
};
|
|
4649
|
+
}
|
|
4650
|
+
});
|
|
4651
|
+
return true;
|
|
4652
|
+
}
|
|
4653
|
+
if (request.type === "set_config_option") {
|
|
4654
|
+
this.handleControlRequest({
|
|
4655
|
+
socket,
|
|
4656
|
+
requestId: request.requestId,
|
|
4657
|
+
run: async () => ({
|
|
4658
|
+
type: "set_config_option_result",
|
|
4659
|
+
requestId: request.requestId,
|
|
4660
|
+
response: await this.controlHandlers.setSessionConfigOption(request.configId, request.value, request.timeoutMs)
|
|
4661
|
+
})
|
|
4662
|
+
});
|
|
4663
|
+
return true;
|
|
4664
|
+
}
|
|
4665
|
+
return false;
|
|
4666
|
+
}
|
|
4667
|
+
enqueuePromptRequest(socket, request) {
|
|
4668
|
+
this.taskSockets.add(socket);
|
|
4669
|
+
const task = {
|
|
4670
|
+
requestId: request.requestId,
|
|
4671
|
+
message: request.message,
|
|
4672
|
+
prompt: request.prompt ?? textPrompt(request.message),
|
|
4673
|
+
permissionMode: request.permissionMode,
|
|
4674
|
+
resumePolicy: request.resumePolicy,
|
|
4675
|
+
nonInteractivePermissions: request.nonInteractivePermissions,
|
|
4676
|
+
permissionPolicy: request.permissionPolicy,
|
|
4677
|
+
timeoutMs: request.timeoutMs,
|
|
4678
|
+
suppressSdkConsoleErrors: request.suppressSdkConsoleErrors,
|
|
4679
|
+
promptRetries: request.promptRetries,
|
|
4680
|
+
sessionOptions: request.sessionOptions,
|
|
4681
|
+
waitForCompletion: request.waitForCompletion,
|
|
4682
|
+
reportPromptStarted: request.reportPromptStarted,
|
|
4683
|
+
enqueuedAt: Date.now(),
|
|
4684
|
+
send: (message) => {
|
|
4685
|
+
this.writeQueueMessage(socket, {
|
|
4686
|
+
...message,
|
|
4687
|
+
ownerGeneration: this.ownerGeneration
|
|
4688
|
+
});
|
|
4689
|
+
},
|
|
4690
|
+
close: () => {
|
|
4691
|
+
this.endSocket(socket);
|
|
4692
|
+
}
|
|
4693
|
+
};
|
|
4694
|
+
if (!this.enqueue(task)) return;
|
|
4695
|
+
this.writeQueueMessage(socket, {
|
|
4696
|
+
type: "accepted",
|
|
4697
|
+
requestId: request.requestId,
|
|
4698
|
+
ownerGeneration: this.ownerGeneration
|
|
4699
|
+
});
|
|
4700
|
+
if (!request.waitForCompletion) task.close();
|
|
4701
|
+
}
|
|
4702
|
+
handleConnection(socket) {
|
|
4703
|
+
this.sockets.add(socket);
|
|
4704
|
+
this.outputs.set(socket, new QueueSocketOutput(socket, this.outputBudget));
|
|
4705
|
+
socket.setEncoding("utf8");
|
|
4706
|
+
socket.on("timeout", () => socket.destroy());
|
|
4707
|
+
socket.once("close", () => {
|
|
4708
|
+
this.outputs.delete(socket);
|
|
4709
|
+
this.sockets.delete(socket);
|
|
4710
|
+
this.taskSockets.delete(socket);
|
|
4711
|
+
this.drainingSockets.delete(socket);
|
|
4712
|
+
});
|
|
4713
|
+
let buffer = "";
|
|
4714
|
+
let handled = false;
|
|
4715
|
+
const processLine = (line) => {
|
|
4716
|
+
if (handled) return;
|
|
4717
|
+
handled = true;
|
|
4718
|
+
const request = this.parseRequestLine(socket, line);
|
|
4719
|
+
if (!request || this.rejectClosedOwner(socket, request) || this.rejectStaleOwnerGeneration(socket, request)) return;
|
|
4720
|
+
if (this.handleControlQueueRequest(socket, request)) return;
|
|
4721
|
+
if (request.type !== "submit_prompt") {
|
|
4722
|
+
this.failRequest(socket, request.requestId, "Invalid queue request", "QUEUE_REQUEST_INVALID");
|
|
4723
|
+
return;
|
|
4724
|
+
}
|
|
4725
|
+
this.enqueuePromptRequest(socket, request);
|
|
4726
|
+
};
|
|
4727
|
+
socket.on("data", (chunk) => {
|
|
4728
|
+
buffer += chunk;
|
|
4729
|
+
let index = buffer.indexOf("\n");
|
|
4730
|
+
while (index >= 0) {
|
|
4731
|
+
const rawLine = buffer.slice(0, index);
|
|
4732
|
+
if (this.rejectOversizedRequest(socket, rawLine)) return;
|
|
4733
|
+
const line = rawLine.trim();
|
|
4734
|
+
buffer = buffer.slice(index + 1);
|
|
4735
|
+
if (line.length > 0) processLine(line);
|
|
4736
|
+
index = buffer.indexOf("\n");
|
|
4737
|
+
}
|
|
4738
|
+
this.rejectOversizedRequest(socket, buffer);
|
|
4739
|
+
});
|
|
4740
|
+
socket.on("error", () => {});
|
|
4741
|
+
}
|
|
4742
|
+
rejectOversizedRequest(socket, line) {
|
|
4743
|
+
if (!queueRequestExceedsLimit(line, this.maxRequestBytes)) return false;
|
|
4744
|
+
socket.destroy();
|
|
4745
|
+
return true;
|
|
4746
|
+
}
|
|
4747
|
+
};
|
|
4748
|
+
//#endregion
|
|
3873
4749
|
//#region src/session/queue/ipc.ts
|
|
3874
|
-
const MAX_MESSAGE_BUFFER_SIZE = 10485760;
|
|
3875
4750
|
function assertOwnerGeneration(owner, message) {
|
|
3876
4751
|
if (owner.ownerGeneration !== void 0 && message.ownerGeneration !== void 0 && message.ownerGeneration !== owner.ownerGeneration) throw new QueueProtocolError("Queue owner returned mismatched generation", {
|
|
3877
4752
|
detailCode: "QUEUE_OWNER_GENERATION_MISMATCH",
|
|
@@ -3957,7 +4832,7 @@ async function runQueueOwnerRequest(options) {
|
|
|
3957
4832
|
socket.setEncoding("utf8");
|
|
3958
4833
|
return await new Promise((resolve, reject) => {
|
|
3959
4834
|
let settled = false;
|
|
3960
|
-
|
|
4835
|
+
const responseFragments = [];
|
|
3961
4836
|
const state = { acknowledged: false };
|
|
3962
4837
|
const finishResolve = (result) => {
|
|
3963
4838
|
if (settled) return;
|
|
@@ -4001,19 +4876,21 @@ async function runQueueOwnerRequest(options) {
|
|
|
4001
4876
|
}
|
|
4002
4877
|
};
|
|
4003
4878
|
socket.on("data", (chunk) => {
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4879
|
+
try {
|
|
4880
|
+
let offset = 0;
|
|
4881
|
+
let newline = chunk.indexOf("\n");
|
|
4882
|
+
while (newline >= 0) {
|
|
4883
|
+
if (settled) return;
|
|
4884
|
+
responseFragments.push(chunk.slice(offset, newline));
|
|
4885
|
+
const line = responseFragments.join("").trim();
|
|
4886
|
+
responseFragments.length = 0;
|
|
4887
|
+
if (line.length > 0) processLine(line);
|
|
4888
|
+
offset = newline + 1;
|
|
4889
|
+
newline = chunk.indexOf("\n", offset);
|
|
4890
|
+
}
|
|
4891
|
+
if (!settled && offset < chunk.length) responseFragments.push(chunk.slice(offset));
|
|
4892
|
+
} catch (error) {
|
|
4893
|
+
finishReject(uncertainQueueOutcome(error));
|
|
4017
4894
|
}
|
|
4018
4895
|
});
|
|
4019
4896
|
socket.once("error", (error) => {
|
|
@@ -4340,6 +5217,6 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
|
|
|
4340
5217
|
});
|
|
4341
5218
|
}
|
|
4342
5219
|
//#endregion
|
|
4343
|
-
export {
|
|
5220
|
+
export { resetPerfMetrics as $, findSession as A, PERMISSION_MODES as At, assertPersistedKeyPolicy as B, GeminiAcpStartupTimeoutError as Bt, textPrompt as C, normalizeOutputError as Ct, DEFAULT_HISTORY_LIMIT as D, EXIT_CODES as Dt, observeProcessIncarnation as E, AUTH_POLICIES as Et, normalizeName as F, AgentSpawnError as Ft, SESSION_JOURNAL_SCHEMA as G, SessionModeReplayError as Gt, serializeSessionRecordForDisk as H, PermissionPromptUnavailableError as Ht, pruneSessions as I, AgentStartupError as It, watchSession as J, SessionResumeRequiredError as Jt, SessionJournalReader as K, SessionModelReplayError as Kt, readSessionRecord as L, AuthPolicyError as Lt, isoNow as M, SESSION_RECORD_SCHEMA as Mt, listSessions as N, AcpxOperationalError as Nt, absolutePath as O, NON_INTERACTIVE_PERMISSION_POLICIES as Ot, listSessionsForAgent as P, AgentDisconnectedError as Pt, measurePerf as Q, resolveSessionRecord as R, ClaudeAcpSessionCreateTimeoutError as Rt, promptToDisplayText as S, isRetryablePromptError as St, lockOwnerPid as T, isAcpResourceNotFoundError as Tt, extractAgentSessionId as U, QueueConnectionError as Ut, parseSessionRecord as V, PermissionDeniedError as Vt, normalizeAgentSessionId as W, SessionConfigOptionReplayError as Wt, getPerfMetricsSnapshot as X, formatPerfMetric as Y, UnsupportedPromptContentError as Yt, incrementPerfCounter as Z, ProcessDescendants as _, _usingCtx as _t, trySetModelOnRunningOwner as a, isSessionUpdateNotification as at, mergePromptSourceWithText as b, formatErrorMessage as bt, probeQueueOwnerHealth as c, parsePromptStopReason as ct, releaseQueueOwnerLease as d, sessionBaseDir as dt, setPerfGauge as et, terminateProcess as f, sessionEventActivePath as ft, QueueLeaseGuardSettlementError as g, writePrivateJsonFile as gt, waitMs as h, writePrivateFile as ht, trySetModeOnRunningOwner as i, isAcpMessageObject as it, findSessionByDirectoryWalk as j, PERMISSION_POLICY_ACTIONS as jt, findGitRepositoryRoot as k, OUTPUT_FORMATS as kt, readQueueOwnerRecord as l, DEFAULT_EVENT_SEGMENT_MAX_BYTES as lt, tryAcquireQueueOwnerLease as m, sessionEventSegmentPath as mt, tryCloseSessionOnRunningOwner as n, extractSessionUpdateNotification as nt, trySubmitToRunningOwner as o, parseJsonRpcErrorMessage as ot, terminateQueueOwnerForSession as p, sessionEventLockPath as pt, SessionWatchError as q, SessionNotFoundError as qt, trySetConfigOptionOnRunningOwner as r, isAcpJsonRpcMessage as rt, SessionQueueOwner as s, parsePermissionNotice as st, tryCancelOnRunningOwner as t, startPerfTimer as tt, refreshQueueOwnerLease as u, defaultSessionEventLog as ut, PromptInputValidationError as v, isProcessAlive as vt, createLockOwner as w, extractAcpError as wt, parsePromptSource as x, isAcpQueryClosedBeforeResponseError as xt, getUnsupportedPromptContentMessage as y, exitCodeForOutputErrorCode as yt, writeSessionRecord as z, CopilotAcpUnsupportedError as zt };
|
|
4344
5221
|
|
|
4345
|
-
//# sourceMappingURL=ipc-
|
|
5222
|
+
//# sourceMappingURL=ipc-BW06Pbb8.js.map
|