@byok-sdk/client 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/adapters/index.js +14 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/agent-home.d.ts +5 -0
- package/dist/bin/agent-memory-mcp-server.d.ts +38 -0
- package/dist/bin/agent-message-mcp-server.d.ts +24 -0
- package/dist/bin/byok-agent-memory-mcp.d.ts +2 -0
- package/dist/bin/byok-agent-memory-mcp.js +432 -0
- package/dist/bin/byok-agent-memory-mcp.js.map +1 -0
- package/dist/bin/byok-agent-message-mcp.d.ts +2 -0
- package/dist/bin/byok-agent-message-mcp.js +441 -0
- package/dist/bin/byok-agent-message-mcp.js.map +1 -0
- package/dist/bin/byok-agent.js +1792 -192
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/daemon/agent-memory-filesystem.d.ts +23 -0
- package/dist/daemon/agent-memory-fs-helper.d.ts +10 -0
- package/dist/daemon/agent-memory.d.ts +160 -0
- package/dist/daemon/agent-message-outbox.d.ts +58 -0
- package/dist/daemon/control-protocol.d.ts +25 -0
- package/dist/daemon/create-daemon.d.ts +10 -0
- package/dist/daemon/memory-guidance.d.ts +8 -0
- package/dist/daemon/resolve-agent-memory-mcp-bin.d.ts +6 -0
- package/dist/daemon/resolve-agent-message-mcp-bin.d.ts +6 -0
- package/dist/daemon/task-runner.d.ts +79 -3
- package/dist/daemon/toolset-registry.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1801 -201
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID, createHash, createPrivateKey, generateKeyPairSync, sign, randomBytes, timingSafeEqual, createHmac } from 'crypto';
|
|
2
|
-
import { promises, mkdirSync, linkSync, fstatSync, lstatSync, unlinkSync,
|
|
2
|
+
import { promises, mkdirSync, constants, existsSync, linkSync, fstatSync, lstatSync, unlinkSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, readFileSync, realpathSync } from 'fs';
|
|
3
3
|
import * as path3 from 'path';
|
|
4
4
|
import path3__default, { join, isAbsolute } from 'path';
|
|
5
|
-
import { AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AgentRefSchema, AgentHomeProjectionPayloadSchema, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, AgentEgressPolicySchema, BYOK_PAIR_PATH, PairResponseSchema, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, AgentContentReceiptPayloadSchema, encodeEnvelope, PROTOCOL_VERSION, createEnvelope, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, STRICT_AGENT_ONLY_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AgentHomeProjectionCompletionRequestSchema, byokAgentHomeProjectionCompletionPath, AgentHomeProjectionReadbackSchema, parseMessage, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, RuntimeIdSchema, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, decodeEnvelope, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, UnknownMessageTypeError, BYOK_WS_PATH } from '@byok-sdk/protocol';
|
|
5
|
+
import { AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AgentRefSchema, AgentHomeProjectionPayloadSchema, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, AgentEgressPolicySchema, BYOK_PAIR_PATH, PairResponseSchema, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, AgentContentReceiptPayloadSchema, encodeEnvelope, PROTOCOL_VERSION, createEnvelope, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, TERMINAL_PROJECTION_SELECTION_CAPABILITY, STRICT_AGENT_ONLY_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AGENT_MESSAGE_EGRESS_CAPABILITY, AgentHomeProjectionCompletionRequestSchema, byokAgentHomeProjectionCompletionPath, AgentHomeProjectionReadbackSchema, parseMessage, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, AgentMessagePublishPayloadSchema, AgentMessageDispositionPayloadSchema, RuntimeIdSchema, AGENT_MEMORY_PROJECTION_CAPABILITY, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, decodeEnvelope, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, UnknownMessageTypeError, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionMutationSchema, AGENT_MEMORY_PROJECTION_MAX_REDACTED_BYTES, BYOK_WS_PATH } from '@byok-sdk/protocol';
|
|
6
6
|
import net, { createServer, createConnection } from 'net';
|
|
7
7
|
import * as os4 from 'os';
|
|
8
8
|
import os4__default from 'os';
|
|
@@ -627,12 +627,16 @@ var AgentHomeLeaseManager = class _AgentHomeLeaseManager {
|
|
|
627
627
|
let handle;
|
|
628
628
|
let rootGate;
|
|
629
629
|
let ownsMarker = false;
|
|
630
|
+
let homeIdentity;
|
|
630
631
|
try {
|
|
631
632
|
rootGate = await acquirePathMutationGate({
|
|
632
633
|
scope: "agent-home-root",
|
|
633
634
|
targetPath: resolution.agentsRoot
|
|
634
635
|
}, { waitMs: 1e3 });
|
|
635
636
|
await ensureDirectoryNoSymlink(resolution.agentsRoot, canonicalHome);
|
|
637
|
+
const homeStat = await promises.stat(canonicalHome, { bigint: true });
|
|
638
|
+
if (!homeStat.isDirectory()) throw new AgentHomeResolutionError(`Agent home ${canonicalHome} is not a directory`);
|
|
639
|
+
homeIdentity = Object.freeze({ dev: homeStat.dev, ino: homeStat.ino });
|
|
636
640
|
const internalDir = await ensureDirectoryNoSymlink(
|
|
637
641
|
canonicalHome,
|
|
638
642
|
path3__default.join(canonicalHome, AGENT_HOME_INTERNAL_DIRECTORY)
|
|
@@ -671,6 +675,7 @@ var AgentHomeLeaseManager = class _AgentHomeLeaseManager {
|
|
|
671
675
|
}
|
|
672
676
|
const acquiredLockPath = lockPath;
|
|
673
677
|
if (acquiredLockPath === void 0) throw new AgentHomeError("Agent home lease marker path was not established");
|
|
678
|
+
if (homeIdentity === void 0) throw new AgentHomeError("Agent home lease identity was not established");
|
|
674
679
|
let released = false;
|
|
675
680
|
let releaseAttempt;
|
|
676
681
|
return {
|
|
@@ -678,6 +683,7 @@ var AgentHomeLeaseManager = class _AgentHomeLeaseManager {
|
|
|
678
683
|
agentRef,
|
|
679
684
|
canonicalHome,
|
|
680
685
|
cwd: canonicalHome,
|
|
686
|
+
homeIdentity,
|
|
681
687
|
release: () => {
|
|
682
688
|
if (released) return Promise.resolve();
|
|
683
689
|
if (releaseAttempt !== void 0) return releaseAttempt;
|
|
@@ -1032,14 +1038,14 @@ function sameTaskTerminalMatch(entry, expected) {
|
|
|
1032
1038
|
return sameRef(entry.agentRef, expected.agentRef) && entry.taskId === expected.taskId && entry.runtimeId === expected.runtimeId && entry.cwd === path3__default.resolve(expected.cwd);
|
|
1033
1039
|
}
|
|
1034
1040
|
function sessionFileName(runtimeId, sessionRef) {
|
|
1035
|
-
const
|
|
1041
|
+
const digest3 = createHash("sha256").update(sessionRef, "utf8").digest("hex");
|
|
1036
1042
|
const runtime = runtimeId.replace(/[^a-z0-9._-]/giu, "_").slice(0, 64) || "runtime";
|
|
1037
|
-
return `${runtime}-${
|
|
1043
|
+
return `${runtime}-${digest3}.jsonl`;
|
|
1038
1044
|
}
|
|
1039
1045
|
function taskTerminalFileName(runtimeId, taskId) {
|
|
1040
|
-
const
|
|
1046
|
+
const digest3 = createHash("sha256").update(taskId, "utf8").digest("hex");
|
|
1041
1047
|
const runtime = runtimeId.replace(/[^a-z0-9._-]/giu, "_").slice(0, 64) || "runtime";
|
|
1042
|
-
return `${runtime}-task-${
|
|
1048
|
+
return `${runtime}-task-${digest3}.jsonl`;
|
|
1043
1049
|
}
|
|
1044
1050
|
async function evidenceDirectory(cwdInput) {
|
|
1045
1051
|
if (!path3__default.isAbsolute(cwdInput)) {
|
|
@@ -4997,6 +5003,7 @@ var CodexAdapter = class {
|
|
|
4997
5003
|
steer: false,
|
|
4998
5004
|
resume: true,
|
|
4999
5005
|
approvalInteractive: false,
|
|
5006
|
+
mcpToolsets: true,
|
|
5000
5007
|
permissionModes: ["auto", "readonly"]
|
|
5001
5008
|
},
|
|
5002
5009
|
environmentRequirements: { credentialNames: [] }
|
|
@@ -5128,7 +5135,7 @@ ${withStreams.stderr ?? ""}`);
|
|
|
5128
5135
|
resumeRef: startInput.manifest.sessionRef,
|
|
5129
5136
|
instruction: startInput.instruction,
|
|
5130
5137
|
modelId: manifestModelId,
|
|
5131
|
-
policyArgs: [...policyArgs],
|
|
5138
|
+
policyArgs: [...policyArgs, ...codexMcpConfigArgs(startInput.mcpServers)],
|
|
5132
5139
|
cwd: manifestCwd,
|
|
5133
5140
|
env: runtimeEnv,
|
|
5134
5141
|
spawnFn: this.options.spawnFn,
|
|
@@ -5158,6 +5165,18 @@ ${withStreams.stderr ?? ""}`);
|
|
|
5158
5165
|
return (this.options.resolveBin ?? resolveCodexBin)();
|
|
5159
5166
|
}
|
|
5160
5167
|
};
|
|
5168
|
+
function codexMcpConfigArgs(servers) {
|
|
5169
|
+
if (servers === void 0 || Object.keys(servers).length === 0) return [];
|
|
5170
|
+
const args = ["--ignore-user-config"];
|
|
5171
|
+
for (const [name, server] of Object.entries(servers).sort(([left], [right]) => left.localeCompare(right))) {
|
|
5172
|
+
args.push("-c", `mcp_servers.${name}.command=${JSON.stringify(server.command)}`);
|
|
5173
|
+
if (server.args !== void 0) args.push("-c", `mcp_servers.${name}.args=${JSON.stringify([...server.args])}`);
|
|
5174
|
+
for (const [key, value] of Object.entries(server.env ?? {}).sort(([left], [right]) => left.localeCompare(right))) {
|
|
5175
|
+
args.push("-c", `mcp_servers.${name}.env.${key}=${JSON.stringify(value)}`);
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
return args;
|
|
5179
|
+
}
|
|
5161
5180
|
async function resolveRealWorkspaceDir(workspaceDir) {
|
|
5162
5181
|
return promises.realpath(workspaceDir).catch(() => workspaceDir);
|
|
5163
5182
|
}
|
|
@@ -6884,6 +6903,27 @@ function parseApprovalsRequestParams(value) {
|
|
|
6884
6903
|
if (typeof value.summary !== "string") return void 0;
|
|
6885
6904
|
return { taskId: value.taskId, summary: value.summary };
|
|
6886
6905
|
}
|
|
6906
|
+
function parseAgentMessagePublishParams(value) {
|
|
6907
|
+
if (!isRecord3(value) || Object.keys(value).some((key) => key !== "contextToken" && key !== "contentType" && key !== "body")) return void 0;
|
|
6908
|
+
if (typeof value.contextToken !== "string" || value.contextToken.length < 32 || value.contextToken.length > 160) return void 0;
|
|
6909
|
+
if (value.contentType !== "text/plain" && value.contentType !== "text/markdown") return void 0;
|
|
6910
|
+
if (typeof value.body !== "string" || value.body.length === 0) return void 0;
|
|
6911
|
+
return { contextToken: value.contextToken, contentType: value.contentType, body: value.body };
|
|
6912
|
+
}
|
|
6913
|
+
function validAgentMemoryContextToken(value) {
|
|
6914
|
+
return typeof value === "string" && value.length >= 32 && value.length <= 160 && !/[\u0000\r\n]/u.test(value);
|
|
6915
|
+
}
|
|
6916
|
+
function parseAgentMemoryRecallParams(value) {
|
|
6917
|
+
if (!isRecord3(value) || Object.keys(value).some((key) => key !== "contextToken" && key !== "path" && key !== "ifRevision")) return void 0;
|
|
6918
|
+
if (!validAgentMemoryContextToken(value.contextToken) || typeof value.path !== "string" || value.ifRevision !== void 0 && typeof value.ifRevision !== "string") return void 0;
|
|
6919
|
+
return { contextToken: value.contextToken, path: value.path, ...value.ifRevision === void 0 ? {} : { ifRevision: value.ifRevision } };
|
|
6920
|
+
}
|
|
6921
|
+
function parseAgentMemorySaveParams(value) {
|
|
6922
|
+
if (!isRecord3(value) || Object.keys(value).some((key) => key !== "contextToken" && key !== "op" && key !== "path" && key !== "expectedRevision" && key !== "content")) return void 0;
|
|
6923
|
+
if (!validAgentMemoryContextToken(value.contextToken) || value.op !== "replace" && value.op !== "delete" || typeof value.path !== "string" || typeof value.expectedRevision !== "string" || value.op === "replace" && typeof value.content !== "string" || value.op === "delete" && value.content !== void 0) return void 0;
|
|
6924
|
+
const content = value.content;
|
|
6925
|
+
return { contextToken: value.contextToken, op: value.op, path: value.path, expectedRevision: value.expectedRevision, ...typeof content === "string" ? { content } : {} };
|
|
6926
|
+
}
|
|
6887
6927
|
var ASSERTION_AUDIENCE_MAX_BYTES = 256;
|
|
6888
6928
|
function parseAssertionIssueParams(value) {
|
|
6889
6929
|
if (!isRecord3(value)) return void 0;
|
|
@@ -7141,6 +7181,8 @@ async function startControlServer(opts) {
|
|
|
7141
7181
|
}
|
|
7142
7182
|
return { endpoint, stopServing, close };
|
|
7143
7183
|
}
|
|
7184
|
+
var AGENT_MESSAGE_MCP_SERVER_NAME = "byokagentmessage";
|
|
7185
|
+
var AGENT_MEMORY_MCP_SERVER_NAME = "byokagentmemory";
|
|
7144
7186
|
var MAX_LOCAL_MCP_SERVERS_PER_TOOLSET = 16;
|
|
7145
7187
|
var MAX_LOCAL_MCP_ARGS = 64;
|
|
7146
7188
|
var MAX_LOCAL_MCP_TOKEN_CHARS = 4096;
|
|
@@ -7230,7 +7272,7 @@ function buildState(configured) {
|
|
|
7230
7272
|
`DaemonConfig.mcpToolsets.${toolsetId}.mcpServers contains invalid server name ${JSON.stringify(serverName)}`
|
|
7231
7273
|
);
|
|
7232
7274
|
}
|
|
7233
|
-
if (serverName === APPROVAL_MCP_SERVER_NAME) {
|
|
7275
|
+
if (serverName === APPROVAL_MCP_SERVER_NAME || serverName === AGENT_MESSAGE_MCP_SERVER_NAME || serverName === AGENT_MEMORY_MCP_SERVER_NAME) {
|
|
7234
7276
|
throw new Error(
|
|
7235
7277
|
`DaemonConfig.mcpToolsets.${toolsetId}.mcpServers.${serverName} uses a server name reserved by the daemon`
|
|
7236
7278
|
);
|
|
@@ -7393,9 +7435,9 @@ function deterministicJitterMs(input) {
|
|
|
7393
7435
|
throw new Error("deterministic jitter ratio must be between 0 and 1");
|
|
7394
7436
|
}
|
|
7395
7437
|
if (input.baseMs === 0 || ratio === 0) return Math.round(input.baseMs);
|
|
7396
|
-
const
|
|
7397
|
-
const high =
|
|
7398
|
-
const low =
|
|
7438
|
+
const digest3 = createHash("sha256").update("byok-jitter-v1\0", "utf8").update(input.domain, "utf8").update("\0", "utf8").update(input.seed, "utf8").update("\0", "utf8").update(String(input.sequence), "utf8").digest();
|
|
7439
|
+
const high = digest3.readUInt32BE(0) & 2097151;
|
|
7440
|
+
const low = digest3.readUInt32BE(4);
|
|
7399
7441
|
const unit = (high * 4294967296 + low) / 9007199254740992;
|
|
7400
7442
|
const multiplier = 1 - ratio + unit * ratio * 2;
|
|
7401
7443
|
return Math.max(0, Math.round(input.baseMs * multiplier));
|
|
@@ -9368,9 +9410,9 @@ function isSqliteAvailable() {
|
|
|
9368
9410
|
}
|
|
9369
9411
|
}
|
|
9370
9412
|
var SECURE_FILE_MODE = 384;
|
|
9371
|
-
function openJournalDatabase(
|
|
9413
|
+
function openJournalDatabase(path38, busyTimeoutMs, faults) {
|
|
9372
9414
|
const { DatabaseSync } = loadSqliteModule();
|
|
9373
|
-
const db = new DatabaseSync(
|
|
9415
|
+
const db = new DatabaseSync(path38, { timeout: busyTimeoutMs });
|
|
9374
9416
|
try {
|
|
9375
9417
|
faults?.onStep?.("after-open");
|
|
9376
9418
|
db.exec("PRAGMA auto_vacuum = INCREMENTAL;");
|
|
@@ -9513,9 +9555,9 @@ var RECEIVED_STATE = "received";
|
|
|
9513
9555
|
function byteLength(value) {
|
|
9514
9556
|
return Buffer.byteLength(value, "utf8");
|
|
9515
9557
|
}
|
|
9516
|
-
function fileBytes(
|
|
9558
|
+
function fileBytes(path38) {
|
|
9517
9559
|
try {
|
|
9518
|
-
return statSync(
|
|
9560
|
+
return statSync(path38).size;
|
|
9519
9561
|
} catch {
|
|
9520
9562
|
return 0;
|
|
9521
9563
|
}
|
|
@@ -10745,130 +10787,1262 @@ var ProgressBatcher = class {
|
|
|
10745
10787
|
}
|
|
10746
10788
|
}
|
|
10747
10789
|
};
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
var
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
var GIT_OBSERVATION_TIMEOUT_MS = 5e3;
|
|
10755
|
-
var MAX_PENDING_APPROVALS_PER_TASK = 16;
|
|
10756
|
-
var NoPendingApprovalError = class extends Error {
|
|
10757
|
-
constructor(taskId) {
|
|
10758
|
-
super(`no pending out-of-band approval to resolve for task ${taskId}`);
|
|
10759
|
-
this.taskId = taskId;
|
|
10760
|
-
this.name = "NoPendingApprovalError";
|
|
10790
|
+
var AGENT_MESSAGE_DIRECTORY = path3__default.join(".byok", "messages");
|
|
10791
|
+
var AGENT_MESSAGE_OUTBOX_FILENAME = "outbox-v1.jsonl";
|
|
10792
|
+
var AgentMessageOutboxError = class extends Error {
|
|
10793
|
+
constructor(message) {
|
|
10794
|
+
super(message);
|
|
10795
|
+
this.name = "AgentMessageOutboxError";
|
|
10761
10796
|
}
|
|
10762
|
-
taskId;
|
|
10763
10797
|
};
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10798
|
+
function stableJson(value) {
|
|
10799
|
+
const encoded = JSON.stringify(value);
|
|
10800
|
+
if (encoded === void 0) throw new AgentMessageOutboxError("message outbox value is not serializable");
|
|
10801
|
+
return encoded;
|
|
10802
|
+
}
|
|
10803
|
+
function hashBody(body) {
|
|
10804
|
+
return `sha256:${createHash("sha256").update(body, "utf8").digest("hex")}`;
|
|
10805
|
+
}
|
|
10806
|
+
function sameAgentRef(left, right) {
|
|
10807
|
+
return left.agentId === right.agentId && left.profileRevision === right.profileRevision;
|
|
10808
|
+
}
|
|
10809
|
+
function exactDisposition(record, value) {
|
|
10810
|
+
return value.messageId === record.messageId && value.cursor === record.cursor && value.contract === record.contract && value.contentHash === record.contentHash && value.sessionRef === record.sessionRef && sameAgentRef(value.agentRef, record.agentRef);
|
|
10811
|
+
}
|
|
10812
|
+
var AgentMessageOutbox = class _AgentMessageOutbox {
|
|
10813
|
+
constructor(homeDir, outboxPath) {
|
|
10814
|
+
this.homeDir = homeDir;
|
|
10815
|
+
this.outboxPath = outboxPath;
|
|
10816
|
+
}
|
|
10817
|
+
homeDir;
|
|
10818
|
+
outboxPath;
|
|
10819
|
+
pendingByTask = /* @__PURE__ */ new Map();
|
|
10820
|
+
dispositionByTask = /* @__PURE__ */ new Map();
|
|
10821
|
+
nextCursor = 1;
|
|
10822
|
+
logEntries = 0;
|
|
10823
|
+
writeTail = Promise.resolve();
|
|
10824
|
+
static async open(homeDir) {
|
|
10825
|
+
const directory = path3__default.join(homeDir, AGENT_MESSAGE_DIRECTORY);
|
|
10826
|
+
await ensureSecureDir(directory);
|
|
10827
|
+
const outbox = new _AgentMessageOutbox(homeDir, path3__default.join(directory, AGENT_MESSAGE_OUTBOX_FILENAME));
|
|
10828
|
+
await outbox.load();
|
|
10829
|
+
return outbox;
|
|
10830
|
+
}
|
|
10831
|
+
/** Re-open every existing Agent-local message outbox without following Agent-home symlinks. */
|
|
10832
|
+
static async recover(agentsRoot, tenantId) {
|
|
10833
|
+
if (!path3__default.isAbsolute(agentsRoot)) throw new AgentMessageOutboxError("message outbox recovery root must be absolute");
|
|
10834
|
+
let canonicalRoot;
|
|
10835
|
+
try {
|
|
10836
|
+
canonicalRoot = await promises.realpath(agentsRoot);
|
|
10837
|
+
} catch (error) {
|
|
10838
|
+
if (error.code === "ENOENT") return [];
|
|
10839
|
+
throw error;
|
|
10840
|
+
}
|
|
10841
|
+
const recovered = [];
|
|
10842
|
+
for (const entry of await promises.readdir(canonicalRoot, { withFileTypes: true })) {
|
|
10843
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
10844
|
+
const home = path3__default.join(canonicalRoot, entry.name);
|
|
10845
|
+
const canonicalHome = await promises.realpath(home);
|
|
10846
|
+
if (path3__default.relative(canonicalRoot, canonicalHome) !== entry.name) {
|
|
10847
|
+
throw new AgentMessageOutboxError(`message outbox recovery home escaped the canonical agents root: ${entry.name}`);
|
|
10848
|
+
}
|
|
10849
|
+
try {
|
|
10850
|
+
await promises.lstat(path3__default.join(canonicalHome, AGENT_MESSAGE_DIRECTORY, AGENT_MESSAGE_OUTBOX_FILENAME));
|
|
10851
|
+
} catch (error) {
|
|
10852
|
+
if (error.code === "ENOENT") continue;
|
|
10853
|
+
throw error;
|
|
10854
|
+
}
|
|
10855
|
+
const outbox = await _AgentMessageOutbox.open(canonicalHome);
|
|
10856
|
+
if (outbox.records().some((record) => record.agentRef.agentId !== entry.name)) {
|
|
10857
|
+
throw new AgentMessageOutboxError(`message outbox in ${entry.name} claims a different Agent`);
|
|
10858
|
+
}
|
|
10859
|
+
if (outbox.records().some((record) => record.tenantId !== tenantId)) {
|
|
10860
|
+
throw new AgentMessageOutboxError(`message outbox in ${entry.name} claims a different authenticated tenant`);
|
|
10861
|
+
}
|
|
10862
|
+
recovered.push(outbox);
|
|
10781
10863
|
}
|
|
10864
|
+
return Object.freeze(recovered);
|
|
10782
10865
|
}
|
|
10866
|
+
records() {
|
|
10867
|
+
return Object.freeze([...this.pendingByTask.values()].sort((a, b) => a.cursor - b.cursor));
|
|
10868
|
+
}
|
|
10869
|
+
/** Activated records with no exact disposition yet; only these may be transport-replayed. */
|
|
10870
|
+
retryableRecords() {
|
|
10871
|
+
return Object.freeze(this.records().filter((record) => !this.dispositionByTask.has(record.taskId)));
|
|
10872
|
+
}
|
|
10873
|
+
get(taskId) {
|
|
10874
|
+
return this.pendingByTask.get(taskId);
|
|
10875
|
+
}
|
|
10876
|
+
async appendDraft(input) {
|
|
10877
|
+
return this.exclusive(async () => {
|
|
10878
|
+
if (input.contentType !== input.requirement.contentType) throw new AgentMessageOutboxError("message contentType does not match the offer contract");
|
|
10879
|
+
const byteCount = Buffer.byteLength(input.body, "utf8");
|
|
10880
|
+
if (byteCount < 1 || byteCount > input.requirement.maxBytes) throw new AgentMessageOutboxError("message body exceeds the offer byte contract");
|
|
10881
|
+
const existing = this.pendingByTask.get(input.taskId);
|
|
10882
|
+
if (existing !== void 0) {
|
|
10883
|
+
if (existing.tenantId !== input.tenantId || existing.contentType !== input.contentType || existing.body !== input.body || existing.contract !== input.requirement.contract || !sameAgentRef(existing.agentRef, input.agentRef)) {
|
|
10884
|
+
throw new AgentMessageOutboxError("required-message task already has a different immutable draft");
|
|
10885
|
+
}
|
|
10886
|
+
return existing;
|
|
10887
|
+
}
|
|
10888
|
+
if (this.pendingByTask.size >= input.maxPendingEvents) throw new AgentMessageOutboxError("message outbox event quota is exhausted");
|
|
10889
|
+
const pendingBytes = this.records().reduce((sum, record2) => sum + record2.byteCount, 0);
|
|
10890
|
+
if (pendingBytes + byteCount > input.maxPendingBytes) throw new AgentMessageOutboxError("message outbox byte quota is exhausted");
|
|
10891
|
+
const record = Object.freeze({
|
|
10892
|
+
schema: 1,
|
|
10893
|
+
taskId: input.taskId,
|
|
10894
|
+
tenantId: input.tenantId,
|
|
10895
|
+
agentRef: Object.freeze({ ...input.agentRef }),
|
|
10896
|
+
contract: input.requirement.contract,
|
|
10897
|
+
messageId: randomUUID(),
|
|
10898
|
+
cursor: this.nextCursor++,
|
|
10899
|
+
contentType: input.contentType,
|
|
10900
|
+
body: input.body,
|
|
10901
|
+
contentHash: hashBody(input.body),
|
|
10902
|
+
byteCount,
|
|
10903
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10904
|
+
...input.sessionRef === void 0 ? {} : { sessionRef: input.sessionRef }
|
|
10905
|
+
});
|
|
10906
|
+
await this.appendEntry({ schema: 1, kind: "append", record });
|
|
10907
|
+
this.pendingByTask.set(record.taskId, record);
|
|
10908
|
+
return record;
|
|
10909
|
+
});
|
|
10910
|
+
}
|
|
10911
|
+
async activate(taskId, sessionRef) {
|
|
10912
|
+
return this.exclusive(async () => {
|
|
10913
|
+
const record = this.pendingByTask.get(taskId);
|
|
10914
|
+
if (record === void 0) return void 0;
|
|
10915
|
+
if (record.sessionRef !== void 0) {
|
|
10916
|
+
if (record.sessionRef !== sessionRef) throw new AgentMessageOutboxError("message draft is already bound to a different session");
|
|
10917
|
+
return record;
|
|
10918
|
+
}
|
|
10919
|
+
await this.appendEntry({ schema: 1, kind: "activate", taskId, messageId: record.messageId, sessionRef });
|
|
10920
|
+
const activated = Object.freeze({ ...record, sessionRef });
|
|
10921
|
+
this.pendingByTask.set(taskId, activated);
|
|
10922
|
+
return activated;
|
|
10923
|
+
});
|
|
10924
|
+
}
|
|
10925
|
+
publishPayload(record) {
|
|
10926
|
+
if (record.sessionRef === void 0) throw new AgentMessageOutboxError("message draft is not bound to a durable session");
|
|
10927
|
+
return AgentMessagePublishPayloadSchema.parse({
|
|
10928
|
+
agentRef: record.agentRef,
|
|
10929
|
+
sessionRef: record.sessionRef,
|
|
10930
|
+
contract: record.contract,
|
|
10931
|
+
messageId: record.messageId,
|
|
10932
|
+
cursor: record.cursor,
|
|
10933
|
+
contentType: record.contentType,
|
|
10934
|
+
body: record.body,
|
|
10935
|
+
contentHash: record.contentHash,
|
|
10936
|
+
byteCount: record.byteCount
|
|
10937
|
+
});
|
|
10938
|
+
}
|
|
10939
|
+
async applyDisposition(taskId, input) {
|
|
10940
|
+
return this.exclusive(async () => {
|
|
10941
|
+
const disposition = AgentMessageDispositionPayloadSchema.parse(input);
|
|
10942
|
+
const record = this.pendingByTask.get(taskId);
|
|
10943
|
+
if (record === void 0) return "unknown";
|
|
10944
|
+
if (!exactDisposition(record, disposition)) return "mismatch";
|
|
10945
|
+
await this.appendEntry({ schema: 1, kind: "disposition", taskId, disposition });
|
|
10946
|
+
if (disposition.outcome === "accepted") {
|
|
10947
|
+
this.pendingByTask.delete(taskId);
|
|
10948
|
+
this.dispositionByTask.delete(taskId);
|
|
10949
|
+
} else {
|
|
10950
|
+
this.dispositionByTask.set(taskId, disposition);
|
|
10951
|
+
}
|
|
10952
|
+
if (this.logEntries >= 512) await this.compact();
|
|
10953
|
+
return disposition.outcome;
|
|
10954
|
+
});
|
|
10955
|
+
}
|
|
10956
|
+
async load() {
|
|
10957
|
+
let raw;
|
|
10958
|
+
try {
|
|
10959
|
+
const stat = await promises.stat(this.outboxPath);
|
|
10960
|
+
if (stat.size > 64 * 1024 * 1024) throw new AgentMessageOutboxError("message outbox exceeds its bounded on-disk size");
|
|
10961
|
+
raw = await promises.readFile(this.outboxPath, "utf8");
|
|
10962
|
+
} catch (error) {
|
|
10963
|
+
if (error.code === "ENOENT") return;
|
|
10964
|
+
throw error;
|
|
10965
|
+
}
|
|
10966
|
+
for (const line of raw.split("\n")) {
|
|
10967
|
+
if (line.length === 0) continue;
|
|
10968
|
+
const entry = JSON.parse(line);
|
|
10969
|
+
this.logEntries += 1;
|
|
10970
|
+
if (entry.schema !== 1) throw new AgentMessageOutboxError("message outbox schema is unsupported");
|
|
10971
|
+
if (entry.kind === "append") {
|
|
10972
|
+
if (this.pendingByTask.has(entry.record.taskId)) throw new AgentMessageOutboxError("message outbox contains duplicate task draft");
|
|
10973
|
+
this.pendingByTask.set(entry.record.taskId, Object.freeze(entry.record));
|
|
10974
|
+
this.nextCursor = Math.max(this.nextCursor, entry.record.cursor + 1);
|
|
10975
|
+
} else if (entry.kind === "activate") {
|
|
10976
|
+
const record = this.pendingByTask.get(entry.taskId);
|
|
10977
|
+
if (record === void 0 || record.messageId !== entry.messageId) throw new AgentMessageOutboxError("message activation has no exact draft");
|
|
10978
|
+
if (record.sessionRef !== void 0 && record.sessionRef !== entry.sessionRef) throw new AgentMessageOutboxError("message activation session conflicts");
|
|
10979
|
+
this.pendingByTask.set(entry.taskId, Object.freeze({ ...record, sessionRef: entry.sessionRef }));
|
|
10980
|
+
} else if (entry.kind === "disposition") {
|
|
10981
|
+
const record = this.pendingByTask.get(entry.taskId);
|
|
10982
|
+
if (record === void 0 || !exactDisposition(record, entry.disposition)) throw new AgentMessageOutboxError("message outbox contains a mismatched disposition");
|
|
10983
|
+
if (entry.disposition.outcome === "accepted") {
|
|
10984
|
+
this.pendingByTask.delete(entry.taskId);
|
|
10985
|
+
this.dispositionByTask.delete(entry.taskId);
|
|
10986
|
+
} else {
|
|
10987
|
+
this.dispositionByTask.set(entry.taskId, entry.disposition);
|
|
10988
|
+
}
|
|
10989
|
+
} else {
|
|
10990
|
+
throw new AgentMessageOutboxError("message outbox entry kind is invalid");
|
|
10991
|
+
}
|
|
10992
|
+
}
|
|
10993
|
+
}
|
|
10994
|
+
async appendEntry(entry) {
|
|
10995
|
+
const handle = await promises.open(this.outboxPath, constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY, 384);
|
|
10996
|
+
try {
|
|
10997
|
+
await handle.write(`${stableJson(entry)}
|
|
10998
|
+
`, void 0, "utf8");
|
|
10999
|
+
await handle.sync();
|
|
11000
|
+
this.logEntries += 1;
|
|
11001
|
+
} finally {
|
|
11002
|
+
await handle.close();
|
|
11003
|
+
}
|
|
11004
|
+
}
|
|
11005
|
+
async compact() {
|
|
11006
|
+
const entries = this.records().flatMap((record) => {
|
|
11007
|
+
const append = { schema: 1, kind: "append", record };
|
|
11008
|
+
const disposition = this.dispositionByTask.get(record.taskId);
|
|
11009
|
+
return disposition === void 0 ? [append] : [append, { schema: 1, kind: "disposition", taskId: record.taskId, disposition }];
|
|
11010
|
+
});
|
|
11011
|
+
await atomicWriteFile(this.outboxPath, entries.map(stableJson).join(entries.length === 0 ? "" : "\n"), { mode: 384 });
|
|
11012
|
+
this.logEntries = entries.length;
|
|
11013
|
+
}
|
|
11014
|
+
async exclusive(fn) {
|
|
11015
|
+
const prior = this.writeTail;
|
|
11016
|
+
let release;
|
|
11017
|
+
this.writeTail = new Promise((resolve) => {
|
|
11018
|
+
release = resolve;
|
|
11019
|
+
});
|
|
11020
|
+
await prior;
|
|
11021
|
+
try {
|
|
11022
|
+
return await fn();
|
|
11023
|
+
} finally {
|
|
11024
|
+
release();
|
|
11025
|
+
}
|
|
11026
|
+
}
|
|
11027
|
+
};
|
|
11028
|
+
|
|
11029
|
+
// src/daemon/memory-guidance.ts
|
|
11030
|
+
var AGENT_MEMORY_GUIDANCE = [
|
|
11031
|
+
"At the start of this Agent task, first read `MEMORY.md` in the provided `cwd`.",
|
|
11032
|
+
"Treat `MEMORY.md` as a concise, self-contained recovery index; if it is empty, initialize a brief index from durable, non-secret task knowledge.",
|
|
11033
|
+
"Read files under `notes/` only as needed, following pointers from the index.",
|
|
11034
|
+
"When task permissions allow and a durable value is learned, update the relevant `notes/` entry and the `MEMORY.md` index.",
|
|
11035
|
+
"Never write credentials, secrets, tokens, API keys, private keys, or other authentication material to `MEMORY.md` or `notes/`."
|
|
11036
|
+
].join("\n");
|
|
11037
|
+
function prependAgentMemoryGuidance(instruction) {
|
|
11038
|
+
return `${AGENT_MEMORY_GUIDANCE}
|
|
11039
|
+
|
|
11040
|
+
${instruction}`;
|
|
10783
11041
|
}
|
|
10784
|
-
var
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
11042
|
+
var AGENT_MEMORY_AUDIT_FILENAME = "agent-memory-audit-v1.jsonl";
|
|
11043
|
+
var AGENT_MEMORY_OUTBOX_FILENAME = "agent-memory-redacted-outbox-v2.json";
|
|
11044
|
+
var AGENT_MEMORY_MAX_FILE_BYTES = 256 * 1024;
|
|
11045
|
+
var AGENT_MEMORY_MAX_SNAPSHOT_BYTES = 1024 * 1024;
|
|
11046
|
+
var AGENT_MEMORY_MAX_SNAPSHOT_FILES = 128;
|
|
11047
|
+
var AGENT_MEMORY_MAX_SNAPSHOT_ENTRIES = 512;
|
|
11048
|
+
var AGENT_MEMORY_MAX_LOCAL_LOG_BYTES = AGENT_MEMORY_MAX_SNAPSHOT_BYTES;
|
|
11049
|
+
var REVISION = /^sha256:[a-f0-9]{64}$/u;
|
|
11050
|
+
var SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
11051
|
+
var SECRET_LIKE = /(?:^|[-_.])(secret|token|credential|password|passwd|api[-_]?key|private[-_]?key|cookie)(?:$|[-_.])/iu;
|
|
11052
|
+
var encoder2 = new TextEncoder();
|
|
11053
|
+
var AGENT_MEMORY_PROJECTION_PUBLISH_TIMEOUT_MS = 1e4;
|
|
11054
|
+
var AgentMemoryError = class extends Error {
|
|
11055
|
+
constructor(message) {
|
|
11056
|
+
super(message);
|
|
11057
|
+
this.name = "AgentMemoryError";
|
|
11058
|
+
}
|
|
11059
|
+
};
|
|
11060
|
+
var AgentMemoryRevisionConflictError = class extends AgentMemoryError {
|
|
11061
|
+
constructor(expectedRevision, actualRevision) {
|
|
11062
|
+
super(`Agent memory revision conflict: expected ${expectedRevision}, current ${actualRevision}`);
|
|
11063
|
+
this.expectedRevision = expectedRevision;
|
|
11064
|
+
this.actualRevision = actualRevision;
|
|
11065
|
+
this.name = "AgentMemoryRevisionConflictError";
|
|
11066
|
+
}
|
|
11067
|
+
expectedRevision;
|
|
11068
|
+
actualRevision;
|
|
11069
|
+
};
|
|
11070
|
+
var DRAINED_AGENT_MEMORY_PROJECTION_REPLAY = Object.freeze({ status: "drained" });
|
|
11071
|
+
var AgentMemoryProjectionReplayPendingError = class extends AgentMemoryError {
|
|
11072
|
+
constructor(outcome) {
|
|
11073
|
+
super("Agent memory projection replay remains pending");
|
|
11074
|
+
this.outcome = outcome;
|
|
11075
|
+
this.name = "AgentMemoryProjectionReplayPendingError";
|
|
11076
|
+
}
|
|
11077
|
+
outcome;
|
|
11078
|
+
};
|
|
11079
|
+
function digestBytes(content) {
|
|
11080
|
+
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
10790
11081
|
}
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
const rank = new Map(preference.map((id, index) => [id, index]));
|
|
10794
|
-
return [...candidates].sort((a, b) => (rank.get(a.descriptor.id) ?? preference.length) - (rank.get(b.descriptor.id) ?? preference.length));
|
|
11082
|
+
function digest2(content) {
|
|
11083
|
+
return digestBytes(encoder2.encode(content));
|
|
10795
11084
|
}
|
|
10796
|
-
function
|
|
10797
|
-
return
|
|
11085
|
+
function nonEmpty(value) {
|
|
11086
|
+
return typeof value === "string" && value.length > 0 && !/[\u0000\r\n]/u.test(value);
|
|
10798
11087
|
}
|
|
10799
|
-
function
|
|
10800
|
-
return
|
|
11088
|
+
function revision(value) {
|
|
11089
|
+
return typeof value === "string" && REVISION.test(value);
|
|
10801
11090
|
}
|
|
10802
|
-
function
|
|
10803
|
-
|
|
10804
|
-
|
|
11091
|
+
function taskContext(value) {
|
|
11092
|
+
if (!value || !nonEmpty(value.taskId) || !nonEmpty(value.tenantId) || !nonEmpty(value.deviceId) || !nonEmpty(value.sessionRef) || !nonEmpty(value.runtimeId) || !nonEmpty(value.leaseId) || !value.agentRef || !nonEmpty(value.agentRef.agentId) || !nonEmpty(value.agentRef.profileRevision) || !path3__default.isAbsolute(value.canonicalHome) || typeof value.homeIdentity?.dev !== "bigint" || typeof value.homeIdentity.ino !== "bigint") {
|
|
11093
|
+
throw new AgentMemoryError("Agent memory requires an exact active Agent task context");
|
|
11094
|
+
}
|
|
11095
|
+
return Object.freeze({ ...value, agentRef: Object.freeze({ ...value.agentRef }), homeIdentity: Object.freeze({ ...value.homeIdentity }), canonicalHome: path3__default.resolve(value.canonicalHome) });
|
|
10805
11096
|
}
|
|
10806
|
-
function
|
|
10807
|
-
|
|
11097
|
+
function validateAgentMemoryPath(value) {
|
|
11098
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 1024 || /[\u0000\\]/u.test(value)) throw new AgentMemoryError("memory path is invalid");
|
|
11099
|
+
if (value === "MEMORY.md") return value;
|
|
11100
|
+
if (path3__default.posix.isAbsolute(value) || /[*?\[{]/u.test(value)) throw new AgentMemoryError("memory path must name exactly one file");
|
|
11101
|
+
const parts = value.split("/");
|
|
11102
|
+
if (parts.length < 2 || parts[0] !== "notes" || !value.endsWith(".md") || parts.some((part) => part === "" || part === "." || part === ".." || part === ".byok" || !SAFE_SEGMENT.test(part) || SECRET_LIKE.test(part))) {
|
|
11103
|
+
throw new AgentMemoryError("memory path must be MEMORY.md or notes/<safe-relative>.md");
|
|
11104
|
+
}
|
|
11105
|
+
return value;
|
|
10808
11106
|
}
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
11107
|
+
var SECURE_DIRECTORY_DESCRIPTOR_ROOT = "/proc/self/fd";
|
|
11108
|
+
function isAgentMemorySecureFilesystemAvailable(externalHelperConfigured = false) {
|
|
11109
|
+
const nativeLinux = process.platform === "linux" && typeof constants.O_NOFOLLOW === "number" && typeof constants.O_DIRECTORY === "number" && typeof constants.O_NONBLOCK === "number" && existsSync(SECURE_DIRECTORY_DESCRIPTOR_ROOT);
|
|
11110
|
+
return nativeLinux || externalHelperConfigured && process.platform === "darwin";
|
|
10812
11111
|
}
|
|
10813
|
-
function
|
|
10814
|
-
if (!
|
|
10815
|
-
|
|
10816
|
-
|
|
11112
|
+
function requireSecureDirectoryDescriptors() {
|
|
11113
|
+
if (!isAgentMemorySecureFilesystemAvailable(false) || process.platform !== "linux") {
|
|
11114
|
+
throw new AgentMemoryError("Agent memory is unavailable because this Node platform lacks safe descriptor-relative filesystem operations");
|
|
11115
|
+
}
|
|
11116
|
+
return SECURE_DIRECTORY_DESCRIPTOR_ROOT;
|
|
10817
11117
|
}
|
|
10818
|
-
function
|
|
10819
|
-
|
|
11118
|
+
function noFollowFlags(base) {
|
|
11119
|
+
requireSecureDirectoryDescriptors();
|
|
11120
|
+
return base | constants.O_NOFOLLOW;
|
|
10820
11121
|
}
|
|
10821
|
-
function
|
|
10822
|
-
return
|
|
10823
|
-
let settled = false;
|
|
10824
|
-
const timer = setTimeout(() => {
|
|
10825
|
-
if (!settled) {
|
|
10826
|
-
settled = true;
|
|
10827
|
-
resolve(false);
|
|
10828
|
-
}
|
|
10829
|
-
}, timeoutMs);
|
|
10830
|
-
timer.unref?.();
|
|
10831
|
-
void (async () => {
|
|
10832
|
-
try {
|
|
10833
|
-
await fn();
|
|
10834
|
-
} catch {
|
|
10835
|
-
}
|
|
10836
|
-
if (!settled) {
|
|
10837
|
-
settled = true;
|
|
10838
|
-
clearTimeout(timer);
|
|
10839
|
-
resolve(true);
|
|
10840
|
-
}
|
|
10841
|
-
})();
|
|
10842
|
-
});
|
|
11122
|
+
function descriptorPath(handle) {
|
|
11123
|
+
return `${requireSecureDirectoryDescriptors()}/${handle.fd}`;
|
|
10843
11124
|
}
|
|
10844
|
-
function
|
|
11125
|
+
async function openPinnedDirectory(target, expectedIdentity) {
|
|
11126
|
+
requireSecureDirectoryDescriptors();
|
|
11127
|
+
let handle;
|
|
10845
11128
|
try {
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
11129
|
+
handle = await promises.open(target, noFollowFlags(constants.O_RDONLY | constants.O_DIRECTORY));
|
|
11130
|
+
const stat = await handle.stat({ bigint: true });
|
|
11131
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || expectedIdentity !== void 0 && (stat.dev !== expectedIdentity.dev || stat.ino !== expectedIdentity.ino)) throw new AgentMemoryError("memory directory is not a real directory");
|
|
11132
|
+
return handle;
|
|
11133
|
+
} catch (error) {
|
|
11134
|
+
await handle?.close().catch(() => {
|
|
11135
|
+
});
|
|
11136
|
+
if (error instanceof AgentMemoryError) throw error;
|
|
11137
|
+
throw new AgentMemoryError("memory directory is unavailable or unsafe");
|
|
10849
11138
|
}
|
|
10850
11139
|
}
|
|
10851
|
-
async function
|
|
10852
|
-
const
|
|
10853
|
-
const candidate = path3__default.resolve(realWorkspaceDir, name);
|
|
10854
|
-
const prefix = realWorkspaceDir.endsWith(path3__default.sep) ? realWorkspaceDir : realWorkspaceDir + path3__default.sep;
|
|
10855
|
-
if (candidate !== realWorkspaceDir && !candidate.startsWith(prefix)) {
|
|
10856
|
-
return { ok: false, reason: `artifact name "${name}" resolves outside the task workspace \u2014 rejected` };
|
|
10857
|
-
}
|
|
10858
|
-
let realCandidate = candidate;
|
|
11140
|
+
async function withPinnedDirectory(home, parts, operation, expectedHomeIdentity) {
|
|
11141
|
+
const handles = [];
|
|
10859
11142
|
try {
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
11143
|
+
let directory = await openPinnedDirectory(home, expectedHomeIdentity);
|
|
11144
|
+
handles.push(directory);
|
|
11145
|
+
for (const part of parts) {
|
|
11146
|
+
directory = await openPinnedDirectory(`${descriptorPath(directory)}/${part}`);
|
|
11147
|
+
handles.push(directory);
|
|
11148
|
+
}
|
|
11149
|
+
return await operation(directory);
|
|
11150
|
+
} finally {
|
|
11151
|
+
await Promise.all(handles.reverse().map((handle) => handle.close().catch(() => {
|
|
11152
|
+
})));
|
|
10865
11153
|
}
|
|
10866
|
-
|
|
11154
|
+
}
|
|
11155
|
+
async function withMemoryParent(context, relativePath, operation) {
|
|
11156
|
+
const parts = relativePath.split("/");
|
|
11157
|
+
const fileName = parts.pop();
|
|
11158
|
+
if (fileName === void 0 || parts.some((part) => !SAFE_SEGMENT.test(part) && part !== ".byok")) throw new AgentMemoryError("memory path is invalid");
|
|
11159
|
+
return withPinnedDirectory(context.canonicalHome, parts, (directory) => operation(directory, fileName), context.homeIdentity);
|
|
11160
|
+
}
|
|
11161
|
+
async function readPinnedFile(directory, fileName, maxBytes = AGENT_MEMORY_MAX_FILE_BYTES) {
|
|
10867
11162
|
let handle;
|
|
10868
11163
|
try {
|
|
10869
|
-
handle = await promises.open(
|
|
10870
|
-
|
|
10871
|
-
|
|
11164
|
+
handle = await promises.open(
|
|
11165
|
+
`${descriptorPath(directory)}/${fileName}`,
|
|
11166
|
+
noFollowFlags(constants.O_RDONLY | constants.O_NONBLOCK)
|
|
11167
|
+
);
|
|
11168
|
+
} catch (error) {
|
|
11169
|
+
if (error.code === "ENOENT") return Object.freeze({ exists: false, content: "", revision: digest2(""), byteCount: 0 });
|
|
11170
|
+
throw new AgentMemoryError("could not open memory file");
|
|
11171
|
+
}
|
|
11172
|
+
try {
|
|
11173
|
+
const before = await handle.stat({ bigint: true });
|
|
11174
|
+
if (!before.isFile() || before.isSymbolicLink() || before.size > BigInt(maxBytes)) throw new AgentMemoryError("memory file is not a bounded regular file");
|
|
11175
|
+
const bytes = Buffer.alloc(Number(before.size));
|
|
11176
|
+
let offset = 0;
|
|
11177
|
+
while (offset < bytes.length) {
|
|
11178
|
+
const read = await handle.read(bytes, offset, bytes.length - offset, offset);
|
|
11179
|
+
if (read.bytesRead === 0) break;
|
|
11180
|
+
offset += read.bytesRead;
|
|
11181
|
+
}
|
|
11182
|
+
const after = await handle.stat({ bigint: true });
|
|
11183
|
+
if (offset !== bytes.length || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ino !== before.ino) throw new AgentMemoryError("memory file changed during read");
|
|
11184
|
+
const content = bytes.toString("utf8");
|
|
11185
|
+
if (!Buffer.from(content, "utf8").equals(bytes)) throw new AgentMemoryError("memory file is not valid UTF-8");
|
|
11186
|
+
return Object.freeze({ exists: true, content, revision: digestBytes(bytes), byteCount: bytes.length });
|
|
11187
|
+
} finally {
|
|
11188
|
+
await handle.close().catch(() => {
|
|
11189
|
+
});
|
|
11190
|
+
}
|
|
11191
|
+
}
|
|
11192
|
+
async function readFile(context, relativePath, maxBytes = AGENT_MEMORY_MAX_FILE_BYTES) {
|
|
11193
|
+
if (context.filesystem !== void 0) return context.filesystem.read(relativePath, maxBytes);
|
|
11194
|
+
return withMemoryParent(context, relativePath, (directory, fileName) => readPinnedFile(directory, fileName, maxBytes));
|
|
11195
|
+
}
|
|
11196
|
+
async function syncDirectory(directory) {
|
|
11197
|
+
try {
|
|
11198
|
+
await directory.sync();
|
|
11199
|
+
} catch (error) {
|
|
11200
|
+
if (!["EINVAL", "EPERM"].includes(error.code ?? "")) throw error;
|
|
11201
|
+
}
|
|
11202
|
+
}
|
|
11203
|
+
async function replaceNative(context, relativePath, expected, content) {
|
|
11204
|
+
const byteCount = encoder2.encode(content).byteLength;
|
|
11205
|
+
if (byteCount > AGENT_MEMORY_MAX_FILE_BYTES) throw new AgentMemoryError("memory content exceeds its bounded file size");
|
|
11206
|
+
return withMemoryParent(context, relativePath, async (directory, fileName) => {
|
|
11207
|
+
const before = await readPinnedFile(directory, fileName);
|
|
11208
|
+
if (before.revision !== expected) throw new AgentMemoryRevisionConflictError(expected, before.revision);
|
|
11209
|
+
const parent = descriptorPath(directory);
|
|
11210
|
+
const temporary = `${parent}/.byok-memory-${randomUUID()}.tmp`;
|
|
11211
|
+
let handle;
|
|
11212
|
+
try {
|
|
11213
|
+
const check = await readPinnedFile(directory, fileName);
|
|
11214
|
+
if (check.revision !== expected || check.exists !== before.exists) throw new AgentMemoryRevisionConflictError(expected, check.revision);
|
|
11215
|
+
handle = await promises.open(temporary, noFollowFlags(constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL), 384);
|
|
11216
|
+
await handle.writeFile(content, "utf8");
|
|
11217
|
+
await handle.sync();
|
|
11218
|
+
await handle.close();
|
|
11219
|
+
handle = void 0;
|
|
11220
|
+
const finalCheck = await readPinnedFile(directory, fileName);
|
|
11221
|
+
if (finalCheck.revision !== expected || finalCheck.exists !== before.exists) throw new AgentMemoryRevisionConflictError(expected, finalCheck.revision);
|
|
11222
|
+
await promises.rename(temporary, `${parent}/${fileName}`);
|
|
11223
|
+
await syncDirectory(directory);
|
|
11224
|
+
return Object.freeze({ exists: true, content, revision: digest2(content), byteCount });
|
|
11225
|
+
} catch (error) {
|
|
11226
|
+
await handle?.close().catch(() => {
|
|
11227
|
+
});
|
|
11228
|
+
await promises.rm(temporary, { force: true }).catch(() => {
|
|
11229
|
+
});
|
|
11230
|
+
if (error instanceof AgentMemoryError) throw error;
|
|
11231
|
+
throw new AgentMemoryError("could not atomically replace memory file");
|
|
11232
|
+
}
|
|
11233
|
+
});
|
|
11234
|
+
}
|
|
11235
|
+
async function replace(context, relativePath, expected, content) {
|
|
11236
|
+
if (context.filesystem !== void 0) return context.filesystem.replace(relativePath, expected, content, AGENT_MEMORY_MAX_FILE_BYTES);
|
|
11237
|
+
return replaceNative(context, relativePath, expected, content);
|
|
11238
|
+
}
|
|
11239
|
+
async function removeNative(context, relativePath, expected) {
|
|
11240
|
+
if (relativePath === "MEMORY.md") throw new AgentMemoryError("MEMORY.md may not be deleted");
|
|
11241
|
+
await withMemoryParent(context, relativePath, async (directory, fileName) => {
|
|
11242
|
+
const before = await readPinnedFile(directory, fileName);
|
|
11243
|
+
if (!before.exists || before.revision !== expected) throw new AgentMemoryRevisionConflictError(expected, before.revision);
|
|
11244
|
+
const parent = descriptorPath(directory);
|
|
11245
|
+
const tombstone = `${parent}/.byok-memory-delete-${randomUUID()}.tmp`;
|
|
11246
|
+
try {
|
|
11247
|
+
const check = await readPinnedFile(directory, fileName);
|
|
11248
|
+
if (!check.exists || check.revision !== expected) throw new AgentMemoryRevisionConflictError(expected, check.revision);
|
|
11249
|
+
await promises.rename(`${parent}/${fileName}`, tombstone);
|
|
11250
|
+
await syncDirectory(directory);
|
|
11251
|
+
await promises.rm(tombstone);
|
|
11252
|
+
await syncDirectory(directory);
|
|
11253
|
+
} catch (error) {
|
|
11254
|
+
if (error instanceof AgentMemoryError) throw error;
|
|
11255
|
+
throw new AgentMemoryError("could not atomically delete memory file");
|
|
11256
|
+
}
|
|
11257
|
+
});
|
|
11258
|
+
}
|
|
11259
|
+
async function remove(context, relativePath, expected) {
|
|
11260
|
+
if (relativePath === "MEMORY.md") throw new AgentMemoryError("MEMORY.md may not be deleted");
|
|
11261
|
+
if (context.filesystem !== void 0) return context.filesystem.delete(relativePath, expected);
|
|
11262
|
+
return removeNative(context, relativePath, expected);
|
|
11263
|
+
}
|
|
11264
|
+
async function readInternalFile(context, fileName) {
|
|
11265
|
+
const relativePath = `${AGENT_HOME_INTERNAL_DIRECTORY}/${fileName}`;
|
|
11266
|
+
if (context.filesystem !== void 0) return context.filesystem.read(relativePath, AGENT_MEMORY_MAX_LOCAL_LOG_BYTES);
|
|
11267
|
+
return withPinnedDirectory(
|
|
11268
|
+
context.canonicalHome,
|
|
11269
|
+
[AGENT_HOME_INTERNAL_DIRECTORY],
|
|
11270
|
+
(directory) => readPinnedFile(directory, fileName, AGENT_MEMORY_MAX_LOCAL_LOG_BYTES),
|
|
11271
|
+
context.homeIdentity
|
|
11272
|
+
);
|
|
11273
|
+
}
|
|
11274
|
+
async function replaceInternalFile(context, fileName, expectedRevision, content) {
|
|
11275
|
+
const byteCount = encoder2.encode(content).byteLength;
|
|
11276
|
+
if (byteCount > AGENT_MEMORY_MAX_LOCAL_LOG_BYTES) throw new AgentMemoryError("Agent memory internal state exceeds its bounded size");
|
|
11277
|
+
const relativePath = `${AGENT_HOME_INTERNAL_DIRECTORY}/${fileName}`;
|
|
11278
|
+
if (context.filesystem !== void 0) return context.filesystem.replace(relativePath, expectedRevision, content, AGENT_MEMORY_MAX_LOCAL_LOG_BYTES);
|
|
11279
|
+
return withPinnedDirectory(context.canonicalHome, [AGENT_HOME_INTERNAL_DIRECTORY], async (directory) => {
|
|
11280
|
+
const before = await readPinnedFile(directory, fileName, AGENT_MEMORY_MAX_LOCAL_LOG_BYTES);
|
|
11281
|
+
if (before.revision !== expectedRevision) throw new AgentMemoryRevisionConflictError(expectedRevision, before.revision);
|
|
11282
|
+
const parent = descriptorPath(directory);
|
|
11283
|
+
const temporary = `${parent}/.byok-agent-memory-${randomUUID()}.tmp`;
|
|
11284
|
+
let handle;
|
|
11285
|
+
try {
|
|
11286
|
+
handle = await promises.open(temporary, noFollowFlags(constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL), 384);
|
|
11287
|
+
await handle.writeFile(content, "utf8");
|
|
11288
|
+
await handle.sync();
|
|
11289
|
+
await handle.close();
|
|
11290
|
+
handle = void 0;
|
|
11291
|
+
const check = await readPinnedFile(directory, fileName, AGENT_MEMORY_MAX_LOCAL_LOG_BYTES);
|
|
11292
|
+
if (check.revision !== expectedRevision || check.exists !== before.exists) throw new AgentMemoryRevisionConflictError(expectedRevision, check.revision);
|
|
11293
|
+
await promises.rename(temporary, `${parent}/${fileName}`);
|
|
11294
|
+
await syncDirectory(directory);
|
|
11295
|
+
return Object.freeze({ exists: true, content, revision: digest2(content), byteCount });
|
|
11296
|
+
} catch (error) {
|
|
11297
|
+
await handle?.close().catch(() => {
|
|
11298
|
+
});
|
|
11299
|
+
await promises.rm(temporary, { force: true }).catch(() => {
|
|
11300
|
+
});
|
|
11301
|
+
if (error instanceof AgentMemoryError) throw error;
|
|
11302
|
+
throw new AgentMemoryError("could not atomically replace Agent memory internal state");
|
|
11303
|
+
}
|
|
11304
|
+
}, context.homeIdentity);
|
|
11305
|
+
}
|
|
11306
|
+
function boundedAuditTail(previous, entry) {
|
|
11307
|
+
if (encoder2.encode(entry).byteLength > AGENT_MEMORY_MAX_LOCAL_LOG_BYTES) throw new AgentMemoryError("Agent memory audit entry exceeds its bounded size");
|
|
11308
|
+
const lines = previous.split("\n").filter((line) => line.length > 0);
|
|
11309
|
+
const kept = [entry];
|
|
11310
|
+
let byteCount = encoder2.encode(entry).byteLength;
|
|
11311
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
11312
|
+
const candidate = `${lines[index]}
|
|
11313
|
+
`;
|
|
11314
|
+
const candidateBytes = encoder2.encode(candidate).byteLength;
|
|
11315
|
+
if (byteCount + candidateBytes > AGENT_MEMORY_MAX_LOCAL_LOG_BYTES) break;
|
|
11316
|
+
kept.unshift(candidate);
|
|
11317
|
+
byteCount += candidateBytes;
|
|
11318
|
+
}
|
|
11319
|
+
return kept.join("");
|
|
11320
|
+
}
|
|
11321
|
+
async function audit(context, kind, values) {
|
|
11322
|
+
const entry = `${JSON.stringify({ version: 1, kind, taskId: context.taskId, tenantId: context.tenantId, deviceId: context.deviceId, agentRef: context.agentRef, sessionRef: context.sessionRef, runtimeId: context.runtimeId, ...values, recordedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
11323
|
+
`;
|
|
11324
|
+
const current = await readInternalFile(context, AGENT_MEMORY_AUDIT_FILENAME);
|
|
11325
|
+
await replaceInternalFile(context, AGENT_MEMORY_AUDIT_FILENAME, current.revision, boundedAuditTail(current.content, entry));
|
|
11326
|
+
}
|
|
11327
|
+
async function recordAuditWarning(context, kind, values) {
|
|
11328
|
+
try {
|
|
11329
|
+
await audit(context, kind, values);
|
|
11330
|
+
return void 0;
|
|
11331
|
+
} catch {
|
|
11332
|
+
return Object.freeze({ code: "agent_memory_audit_unavailable" });
|
|
11333
|
+
}
|
|
11334
|
+
}
|
|
11335
|
+
var agentMemoryHomeQueues = /* @__PURE__ */ new Map();
|
|
11336
|
+
async function exclusiveAgentMemoryHome(home, fn) {
|
|
11337
|
+
const previous = agentMemoryHomeQueues.get(home) ?? Promise.resolve();
|
|
11338
|
+
let release;
|
|
11339
|
+
const next = new Promise((resolve) => {
|
|
11340
|
+
release = resolve;
|
|
11341
|
+
});
|
|
11342
|
+
agentMemoryHomeQueues.set(home, next);
|
|
11343
|
+
await previous;
|
|
11344
|
+
try {
|
|
11345
|
+
return await fn();
|
|
11346
|
+
} finally {
|
|
11347
|
+
release();
|
|
11348
|
+
if (agentMemoryHomeQueues.get(home) === next) agentMemoryHomeQueues.delete(home);
|
|
11349
|
+
}
|
|
11350
|
+
}
|
|
11351
|
+
var AgentMemoryService = class {
|
|
11352
|
+
constructor(input) {
|
|
11353
|
+
this.input = input;
|
|
11354
|
+
}
|
|
11355
|
+
input;
|
|
11356
|
+
async recall(input) {
|
|
11357
|
+
const context = taskContext(this.input);
|
|
11358
|
+
const relativePath = validateAgentMemoryPath(input.path);
|
|
11359
|
+
if (input.ifRevision !== void 0 && !revision(input.ifRevision)) throw new AgentMemoryError("ifRevision must be a sha256 content revision");
|
|
11360
|
+
const current = await readFile(context, relativePath);
|
|
11361
|
+
if (!current.exists) throw new AgentMemoryError("memory file does not exist");
|
|
11362
|
+
if (input.ifRevision !== void 0 && current.revision !== input.ifRevision) throw new AgentMemoryRevisionConflictError(input.ifRevision, current.revision);
|
|
11363
|
+
const auditWarning = await exclusiveAgentMemoryHome(context.canonicalHome, () => recordAuditWarning(context, "recall", {
|
|
11364
|
+
path: relativePath,
|
|
11365
|
+
revision: current.revision,
|
|
11366
|
+
byteCount: current.byteCount
|
|
11367
|
+
}));
|
|
11368
|
+
return Object.freeze({
|
|
11369
|
+
path: relativePath,
|
|
11370
|
+
revision: current.revision,
|
|
11371
|
+
content: current.content,
|
|
11372
|
+
...auditWarning === void 0 ? {} : { auditWarning }
|
|
11373
|
+
});
|
|
11374
|
+
}
|
|
11375
|
+
async save(input) {
|
|
11376
|
+
const context = taskContext(this.input);
|
|
11377
|
+
const relativePath = validateAgentMemoryPath(input.path);
|
|
11378
|
+
if (input.op !== "replace" && input.op !== "delete" || !revision(input.expectedRevision)) throw new AgentMemoryError("memory save requires op and sha256 expectedRevision");
|
|
11379
|
+
if (input.op === "replace" && typeof input.content !== "string") throw new AgentMemoryError("replace requires string content");
|
|
11380
|
+
if (input.op === "delete" && input.content !== void 0) throw new AgentMemoryError("delete does not accept content");
|
|
11381
|
+
const expectedRevision = input.expectedRevision;
|
|
11382
|
+
const content = input.content;
|
|
11383
|
+
return exclusiveAgentMemoryHome(context.canonicalHome, async () => {
|
|
11384
|
+
if (input.op === "delete") {
|
|
11385
|
+
await remove(context, relativePath, expectedRevision);
|
|
11386
|
+
const auditWarning2 = await recordAuditWarning(context, "save", { path: relativePath, operation: "delete" });
|
|
11387
|
+
return Object.freeze({ path: relativePath, deleted: true, ...auditWarning2 === void 0 ? {} : { auditWarning: auditWarning2 } });
|
|
11388
|
+
}
|
|
11389
|
+
if (typeof content !== "string") throw new AgentMemoryError("replace requires string content");
|
|
11390
|
+
const current = await replace(context, relativePath, expectedRevision, content);
|
|
11391
|
+
const auditWarning = await recordAuditWarning(context, "save", { path: relativePath, operation: "replace", revision: current.revision, byteCount: current.byteCount });
|
|
11392
|
+
return Object.freeze({ path: relativePath, revision: current.revision, deleted: false, ...auditWarning === void 0 ? {} : { auditWarning } });
|
|
11393
|
+
});
|
|
11394
|
+
}
|
|
11395
|
+
};
|
|
11396
|
+
async function memoryNotePaths(context) {
|
|
11397
|
+
if (context.filesystem !== void 0) {
|
|
11398
|
+
const paths = await context.filesystem.walk("notes", AGENT_MEMORY_MAX_SNAPSHOT_ENTRIES);
|
|
11399
|
+
const candidates2 = [];
|
|
11400
|
+
for (const candidate of paths) {
|
|
11401
|
+
try {
|
|
11402
|
+
candidates2.push(validateAgentMemoryPath(candidate));
|
|
11403
|
+
} catch {
|
|
11404
|
+
}
|
|
11405
|
+
}
|
|
11406
|
+
return Object.freeze(candidates2);
|
|
11407
|
+
}
|
|
11408
|
+
const candidates = [];
|
|
11409
|
+
let entriesSeen = 0;
|
|
11410
|
+
async function walk(directory, relativeDirectory) {
|
|
11411
|
+
const entries = await promises.readdir(descriptorPath(directory), { withFileTypes: true });
|
|
11412
|
+
for (const entry of entries) {
|
|
11413
|
+
entriesSeen += 1;
|
|
11414
|
+
if (entriesSeen > AGENT_MEMORY_MAX_SNAPSHOT_ENTRIES) throw new AgentMemoryError("memory snapshot exceeds bounded directory entries");
|
|
11415
|
+
const candidate = `${relativeDirectory}/${entry.name}`;
|
|
11416
|
+
if (entry.isSymbolicLink()) throw new AgentMemoryError("memory notes contains a symlink");
|
|
11417
|
+
if (entry.isDirectory()) {
|
|
11418
|
+
if (SAFE_SEGMENT.test(entry.name) && !SECRET_LIKE.test(entry.name) && entry.name !== ".byok") {
|
|
11419
|
+
const nested = await openPinnedDirectory(`${descriptorPath(directory)}/${entry.name}`);
|
|
11420
|
+
try {
|
|
11421
|
+
await walk(nested, candidate);
|
|
11422
|
+
} finally {
|
|
11423
|
+
await nested.close().catch(() => {
|
|
11424
|
+
});
|
|
11425
|
+
}
|
|
11426
|
+
}
|
|
11427
|
+
continue;
|
|
11428
|
+
}
|
|
11429
|
+
if (!entry.isFile()) continue;
|
|
11430
|
+
try {
|
|
11431
|
+
candidates.push(validateAgentMemoryPath(candidate));
|
|
11432
|
+
} catch {
|
|
11433
|
+
}
|
|
11434
|
+
}
|
|
11435
|
+
}
|
|
11436
|
+
await withPinnedDirectory(context.canonicalHome, ["notes"], (directory) => walk(directory, "notes"), context.homeIdentity);
|
|
11437
|
+
return Object.freeze(candidates);
|
|
11438
|
+
}
|
|
11439
|
+
async function captureAgentMemorySnapshot(input) {
|
|
11440
|
+
const context = taskContext(input);
|
|
11441
|
+
const candidates = ["MEMORY.md", ...await memoryNotePaths(context)];
|
|
11442
|
+
const paths = [...new Set(candidates)].sort((a, b) => a.localeCompare(b));
|
|
11443
|
+
if (paths.length > AGENT_MEMORY_MAX_SNAPSHOT_FILES) throw new AgentMemoryError("memory snapshot exceeds bounded file count");
|
|
11444
|
+
const files = [];
|
|
11445
|
+
let totalBytes = 0;
|
|
11446
|
+
for (const relativePath of paths) {
|
|
11447
|
+
const current = await readFile(context, relativePath);
|
|
11448
|
+
if (!current.exists) {
|
|
11449
|
+
if (relativePath === "MEMORY.md") throw new AgentMemoryError("MEMORY.md disappeared before snapshot");
|
|
11450
|
+
continue;
|
|
11451
|
+
}
|
|
11452
|
+
totalBytes += current.byteCount;
|
|
11453
|
+
if (totalBytes > AGENT_MEMORY_MAX_SNAPSHOT_BYTES) throw new AgentMemoryError("memory snapshot exceeds bounded total size");
|
|
11454
|
+
files.push(Object.freeze({ path: relativePath, revision: current.revision, byteCount: current.byteCount, content: current.content }));
|
|
11455
|
+
}
|
|
11456
|
+
const snapshot = Object.freeze({ files: Object.freeze(files), totalBytes });
|
|
11457
|
+
await exclusiveAgentMemoryHome(context.canonicalHome, () => audit(context, "snapshot", {
|
|
11458
|
+
files: files.map((file) => ({ path: file.path, revision: file.revision, byteCount: file.byteCount }))
|
|
11459
|
+
}));
|
|
11460
|
+
return snapshot;
|
|
11461
|
+
}
|
|
11462
|
+
function bytesEqual(left, right) {
|
|
11463
|
+
if (left.byteLength !== right.byteLength) return false;
|
|
11464
|
+
return left.every((value, index) => value === right[index]);
|
|
11465
|
+
}
|
|
11466
|
+
function rawSnapshotBytes(snapshot) {
|
|
11467
|
+
return encoder2.encode(JSON.stringify({
|
|
11468
|
+
files: snapshot.files.map((file) => ({ path: file.path, revision: file.revision, byteCount: file.byteCount, content: file.content }))
|
|
11469
|
+
}));
|
|
11470
|
+
}
|
|
11471
|
+
function redactedBytes(raw, candidate) {
|
|
11472
|
+
if (!(candidate instanceof Uint8Array)) throw new AgentMemoryError("redactor must return Uint8Array bytes");
|
|
11473
|
+
const bytes = candidate.slice();
|
|
11474
|
+
if (bytes.byteLength > AGENT_MEMORY_PROJECTION_MAX_REDACTED_BYTES) throw new AgentMemoryError("redacted snapshot exceeds bounded projection bytes");
|
|
11475
|
+
if (bytesEqual(bytes, rawSnapshotBytes(raw))) throw new AgentMemoryError("identity/pass-through redactor is forbidden");
|
|
11476
|
+
return bytes;
|
|
11477
|
+
}
|
|
11478
|
+
function isPlainRecord(value) {
|
|
11479
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11480
|
+
}
|
|
11481
|
+
function exactKeys(value, keys) {
|
|
11482
|
+
const actual = Object.keys(value).sort();
|
|
11483
|
+
const expected = [...keys].sort();
|
|
11484
|
+
return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
|
|
11485
|
+
}
|
|
11486
|
+
function validOrderingValue(value, allowZero = false) {
|
|
11487
|
+
return typeof value === "number" && Number.isInteger(value) && value >= (allowZero ? 0 : 1) && value <= AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE;
|
|
11488
|
+
}
|
|
11489
|
+
function freezeOutboxRecord(value) {
|
|
11490
|
+
if (!isPlainRecord(value) || !exactKeys(value, ["version", "mutation", "createdAt"]) || value.version !== 2 || typeof value.createdAt !== "string" || value.createdAt.length === 0 || /[\u0000\r\n]/u.test(value.createdAt)) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11491
|
+
const mutation = AgentMemoryProjectionMutationSchema.safeParse(value.mutation);
|
|
11492
|
+
if (!mutation.success) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11493
|
+
return Object.freeze({ version: 2, mutation: Object.freeze(mutation.data), createdAt: value.createdAt });
|
|
11494
|
+
}
|
|
11495
|
+
function freezeOutboxState(value) {
|
|
11496
|
+
if (!isPlainRecord(value) || !exactKeys(value, ["version", "currentWriterEpoch", "highWater", "pending"]) || value.version !== 2 || !validOrderingValue(value.currentWriterEpoch) || !Array.isArray(value.highWater) || !Array.isArray(value.pending)) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11497
|
+
if (value.highWater.length > 1 || value.pending.length > 1) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11498
|
+
const highWater = value.highWater.map((entry) => {
|
|
11499
|
+
if (!isPlainRecord(entry) || !exactKeys(entry, ["writerEpoch", "sourceSeq"]) || !validOrderingValue(entry.writerEpoch) || !validOrderingValue(entry.sourceSeq, true)) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11500
|
+
if (entry.writerEpoch !== value.currentWriterEpoch) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11501
|
+
return Object.freeze({ writerEpoch: entry.writerEpoch, sourceSeq: entry.sourceSeq });
|
|
11502
|
+
}).sort((left, right) => left.writerEpoch - right.writerEpoch);
|
|
11503
|
+
const pending = value.pending.map(freezeOutboxRecord).sort((left, right) => left.mutation.sourceSeq - right.mutation.sourceSeq);
|
|
11504
|
+
const seenEpochs = /* @__PURE__ */ new Set();
|
|
11505
|
+
const highWaterByEpoch = /* @__PURE__ */ new Map();
|
|
11506
|
+
for (const entry of highWater) {
|
|
11507
|
+
if (seenEpochs.has(entry.writerEpoch)) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11508
|
+
seenEpochs.add(entry.writerEpoch);
|
|
11509
|
+
highWaterByEpoch.set(entry.writerEpoch, entry.sourceSeq);
|
|
11510
|
+
}
|
|
11511
|
+
const mutationIds = /* @__PURE__ */ new Set();
|
|
11512
|
+
const sourceSeqs = /* @__PURE__ */ new Set();
|
|
11513
|
+
for (const record of pending) {
|
|
11514
|
+
if (record.mutation.writerEpoch !== value.currentWriterEpoch || mutationIds.has(record.mutation.mutationId) || sourceSeqs.has(record.mutation.sourceSeq) || record.mutation.sourceSeq > (highWaterByEpoch.get(record.mutation.writerEpoch) ?? 0)) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11515
|
+
mutationIds.add(record.mutation.mutationId);
|
|
11516
|
+
sourceSeqs.add(record.mutation.sourceSeq);
|
|
11517
|
+
}
|
|
11518
|
+
return Object.freeze({ version: 2, currentWriterEpoch: value.currentWriterEpoch, highWater: Object.freeze(highWater), pending: Object.freeze(pending) });
|
|
11519
|
+
}
|
|
11520
|
+
function outboxStateJson(state) {
|
|
11521
|
+
return JSON.stringify({ version: state.version, currentWriterEpoch: state.currentWriterEpoch, highWater: state.highWater, pending: state.pending });
|
|
11522
|
+
}
|
|
11523
|
+
function initialOutboxState(writerEpoch) {
|
|
11524
|
+
return freezeOutboxState({ version: 2, currentWriterEpoch: writerEpoch, highWater: [], pending: [] });
|
|
11525
|
+
}
|
|
11526
|
+
function stateWithHighWater(state, writerEpoch, sourceSeq, pending) {
|
|
11527
|
+
if (writerEpoch !== state.currentWriterEpoch) throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11528
|
+
return freezeOutboxState({ version: 2, currentWriterEpoch: state.currentWriterEpoch, highWater: [Object.freeze({ writerEpoch, sourceSeq })], pending });
|
|
11529
|
+
}
|
|
11530
|
+
async function publishAgentMemoryProjection(port, mutation) {
|
|
11531
|
+
let timer;
|
|
11532
|
+
try {
|
|
11533
|
+
return await new Promise((resolve, reject) => {
|
|
11534
|
+
timer = setTimeout(
|
|
11535
|
+
() => reject(new AgentMemoryError("Agent memory projection publish timed out")),
|
|
11536
|
+
AGENT_MEMORY_PROJECTION_PUBLISH_TIMEOUT_MS
|
|
11537
|
+
);
|
|
11538
|
+
try {
|
|
11539
|
+
Promise.resolve(port.publish(Object.freeze({ mutation }))).then(resolve, reject);
|
|
11540
|
+
} catch (error) {
|
|
11541
|
+
reject(error);
|
|
11542
|
+
}
|
|
11543
|
+
});
|
|
11544
|
+
} finally {
|
|
11545
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
11546
|
+
}
|
|
11547
|
+
}
|
|
11548
|
+
var AgentMemoryRedactedOutbox = class _AgentMemoryRedactedOutbox {
|
|
11549
|
+
constructor(context, grant, filePath) {
|
|
11550
|
+
this.context = context;
|
|
11551
|
+
this.grant = grant;
|
|
11552
|
+
this.filePath = filePath;
|
|
11553
|
+
}
|
|
11554
|
+
context;
|
|
11555
|
+
grant;
|
|
11556
|
+
filePath;
|
|
11557
|
+
state;
|
|
11558
|
+
fileRevision;
|
|
11559
|
+
writeTail = Promise.resolve();
|
|
11560
|
+
static async open(input, grant) {
|
|
11561
|
+
const context = taskContext(input);
|
|
11562
|
+
const outbox = new _AgentMemoryRedactedOutbox(context, grant, path3__default.join(context.canonicalHome, AGENT_HOME_INTERNAL_DIRECTORY, AGENT_MEMORY_OUTBOX_FILENAME));
|
|
11563
|
+
await outbox.load();
|
|
11564
|
+
await outbox.admitGrant();
|
|
11565
|
+
return outbox;
|
|
11566
|
+
}
|
|
11567
|
+
pending() {
|
|
11568
|
+
return this.state.pending;
|
|
11569
|
+
}
|
|
11570
|
+
async append(bytes) {
|
|
11571
|
+
return this.exclusive(async () => {
|
|
11572
|
+
if (this.state.currentWriterEpoch !== this.grant.writerEpoch) throw new AgentMemoryError("Agent memory outbox writer epoch is stale");
|
|
11573
|
+
if (this.state.pending.length > 0) throw new AgentMemoryError("Agent memory outbox has pending projection mutations");
|
|
11574
|
+
const currentHighWater = this.state.highWater[0]?.sourceSeq ?? 0;
|
|
11575
|
+
if (currentHighWater >= AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE) throw new AgentMemoryError("Agent memory outbox source sequence is exhausted");
|
|
11576
|
+
const sourceSeq = currentHighWater + 1;
|
|
11577
|
+
const mutation = AgentMemoryProjectionMutationSchema.parse({
|
|
11578
|
+
taskId: this.context.taskId,
|
|
11579
|
+
agentRef: this.context.agentRef,
|
|
11580
|
+
sessionRef: this.context.sessionRef,
|
|
11581
|
+
runtimeId: this.context.runtimeId,
|
|
11582
|
+
grantRef: this.grant.grantRef,
|
|
11583
|
+
writerEpoch: this.grant.writerEpoch,
|
|
11584
|
+
sourceSeq,
|
|
11585
|
+
mutationId: randomUUID(),
|
|
11586
|
+
policyRevision: this.grant.policyRevision,
|
|
11587
|
+
snapshot: { redactedHash: digestBytes(bytes), redactedByteCount: bytes.byteLength, redactedBytes: Buffer.from(bytes).toString("base64url") }
|
|
11588
|
+
});
|
|
11589
|
+
const record = Object.freeze({ version: 2, mutation: Object.freeze(mutation), createdAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
11590
|
+
await this.persist(stateWithHighWater(this.state, mutation.writerEpoch, mutation.sourceSeq, [record]));
|
|
11591
|
+
return record;
|
|
11592
|
+
});
|
|
11593
|
+
}
|
|
11594
|
+
async replay(port) {
|
|
11595
|
+
return this.exclusive(async () => {
|
|
11596
|
+
for (const record of this.pending()) {
|
|
11597
|
+
if (!(await publishAgentMemoryProjection(port, record.mutation)).accepted) {
|
|
11598
|
+
return Object.freeze({
|
|
11599
|
+
status: "pending",
|
|
11600
|
+
writerEpoch: record.mutation.writerEpoch,
|
|
11601
|
+
sourceSeq: record.mutation.sourceSeq,
|
|
11602
|
+
mutationId: record.mutation.mutationId
|
|
11603
|
+
});
|
|
11604
|
+
}
|
|
11605
|
+
await this.persist(freezeOutboxState({
|
|
11606
|
+
version: 2,
|
|
11607
|
+
currentWriterEpoch: this.state.currentWriterEpoch,
|
|
11608
|
+
highWater: this.state.highWater,
|
|
11609
|
+
pending: this.state.pending.filter((candidate) => candidate.mutation.mutationId !== record.mutation.mutationId)
|
|
11610
|
+
}));
|
|
11611
|
+
}
|
|
11612
|
+
return DRAINED_AGENT_MEMORY_PROJECTION_REPLAY;
|
|
11613
|
+
});
|
|
11614
|
+
}
|
|
11615
|
+
async load() {
|
|
11616
|
+
const current = await readInternalFile(this.context, AGENT_MEMORY_OUTBOX_FILENAME);
|
|
11617
|
+
this.fileRevision = current.revision;
|
|
11618
|
+
this.state = current.exists ? this.loadBody(current.content) : initialOutboxState(this.grant.writerEpoch);
|
|
11619
|
+
}
|
|
11620
|
+
loadBody(body) {
|
|
11621
|
+
try {
|
|
11622
|
+
return freezeOutboxState(JSON.parse(body));
|
|
11623
|
+
} catch {
|
|
11624
|
+
throw new AgentMemoryError("Agent memory outbox state is invalid");
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
async admitGrant() {
|
|
11628
|
+
if (this.grant.writerEpoch < this.state.currentWriterEpoch) throw new AgentMemoryError("Agent memory outbox writer epoch is stale");
|
|
11629
|
+
if (this.grant.writerEpoch === this.state.currentWriterEpoch) return;
|
|
11630
|
+
await this.persist(freezeOutboxState({ version: 2, currentWriterEpoch: this.grant.writerEpoch, highWater: [], pending: [] }));
|
|
11631
|
+
}
|
|
11632
|
+
async persist(next) {
|
|
11633
|
+
const replaced = await replaceInternalFile(this.context, AGENT_MEMORY_OUTBOX_FILENAME, this.fileRevision, outboxStateJson(next));
|
|
11634
|
+
this.fileRevision = replaced.revision;
|
|
11635
|
+
this.state = next;
|
|
11636
|
+
}
|
|
11637
|
+
async exclusive(fn) {
|
|
11638
|
+
const previous = this.writeTail;
|
|
11639
|
+
let release;
|
|
11640
|
+
this.writeTail = new Promise((resolve) => {
|
|
11641
|
+
release = resolve;
|
|
11642
|
+
});
|
|
11643
|
+
await previous;
|
|
11644
|
+
try {
|
|
11645
|
+
return await fn();
|
|
11646
|
+
} finally {
|
|
11647
|
+
release();
|
|
11648
|
+
}
|
|
11649
|
+
}
|
|
11650
|
+
};
|
|
11651
|
+
async function snapshotAndProjectAgentMemory(input, projection) {
|
|
11652
|
+
if (projection?.capability !== AGENT_MEMORY_PROJECTION_CAPABILITY || !projection.grant || !projection.redactor || !projection.port) return;
|
|
11653
|
+
const context = taskContext(input);
|
|
11654
|
+
const outbox = await AgentMemoryRedactedOutbox.open(context, projection.grant);
|
|
11655
|
+
const initialReplay = await outbox.replay(projection.port);
|
|
11656
|
+
if (initialReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(initialReplay);
|
|
11657
|
+
const snapshot = await captureAgentMemorySnapshot(context);
|
|
11658
|
+
await outbox.append(redactedBytes(snapshot, await projection.redactor.redact(snapshot)));
|
|
11659
|
+
const trailingReplay = await outbox.replay(projection.port);
|
|
11660
|
+
if (trailingReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(trailingReplay);
|
|
11661
|
+
}
|
|
11662
|
+
var AGENT_MEMORY_FILESYSTEM_HELPER_PROTOCOL = 2;
|
|
11663
|
+
var AGENT_MEMORY_FILESYSTEM_HELPER_VERSION = "2";
|
|
11664
|
+
var HELPER_REQUEST_TIMEOUT_MS = 1e4;
|
|
11665
|
+
var HELPER_MAX_JSON_LINE_BYTES = 2 * 1024 * 1024;
|
|
11666
|
+
var HELPER_MAX_CONTENT_BYTES = 1 * 1024 * 1024;
|
|
11667
|
+
var HELPER_MAX_STDERR_BYTES = 4 * 1024;
|
|
11668
|
+
var HelperRevisionConflict = class extends Error {
|
|
11669
|
+
constructor(actualRevision) {
|
|
11670
|
+
super("helper revision conflict");
|
|
11671
|
+
this.actualRevision = actualRevision;
|
|
11672
|
+
}
|
|
11673
|
+
actualRevision;
|
|
11674
|
+
};
|
|
11675
|
+
function safeHelperPath(value) {
|
|
11676
|
+
if (typeof value !== "string" || !path3__default.isAbsolute(value) || value.length === 0 || /[\u0000\r\n]/u.test(value)) {
|
|
11677
|
+
throw new AgentMemoryError("Agent memory filesystem helper must be an explicit absolute executable path");
|
|
11678
|
+
}
|
|
11679
|
+
return path3__default.resolve(value);
|
|
11680
|
+
}
|
|
11681
|
+
function helperPlatformSupported() {
|
|
11682
|
+
return process.platform === "darwin";
|
|
11683
|
+
}
|
|
11684
|
+
function isAgentMemoryFilesystemHelperSupported() {
|
|
11685
|
+
return helperPlatformSupported();
|
|
11686
|
+
}
|
|
11687
|
+
function unixIdentity(homeIdentity) {
|
|
11688
|
+
return Object.freeze({ kind: "unix", dev: homeIdentity.dev.toString(10), ino: homeIdentity.ino.toString(10) });
|
|
11689
|
+
}
|
|
11690
|
+
function responseRecord(value) {
|
|
11691
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
11692
|
+
const record = value;
|
|
11693
|
+
if (typeof record.id !== "string" || record.protocol !== AGENT_MEMORY_FILESYSTEM_HELPER_PROTOCOL || typeof record.ok !== "boolean") return void 0;
|
|
11694
|
+
if (record.ok) {
|
|
11695
|
+
if (record.result === null || typeof record.result !== "object" || Array.isArray(record.result)) return void 0;
|
|
11696
|
+
return record;
|
|
11697
|
+
}
|
|
11698
|
+
if (record.error === null || typeof record.error !== "object" || Array.isArray(record.error)) return void 0;
|
|
11699
|
+
const error = record.error;
|
|
11700
|
+
if (typeof error.code !== "string" || typeof error.message !== "string" || error.actualRevision !== void 0 && typeof error.actualRevision !== "string") return void 0;
|
|
11701
|
+
return record;
|
|
11702
|
+
}
|
|
11703
|
+
function boundedFileState(result, maxBytes) {
|
|
11704
|
+
let content;
|
|
11705
|
+
try {
|
|
11706
|
+
if (typeof result.contentBase64 !== "string" || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}|[A-Za-z0-9+/]{3})?$/u.test(result.contentBase64)) {
|
|
11707
|
+
throw new Error("invalid base64");
|
|
11708
|
+
}
|
|
11709
|
+
content = Buffer.from(result.contentBase64, "base64").toString("utf8");
|
|
11710
|
+
} catch {
|
|
11711
|
+
throw new AgentMemoryError("Agent memory filesystem helper returned an invalid file state");
|
|
11712
|
+
}
|
|
11713
|
+
if (typeof result.exists !== "boolean" || typeof result.revision !== "string" || typeof result.byteCount !== "number" || !Number.isSafeInteger(result.byteCount) || result.byteCount < 0 || result.byteCount > maxBytes || Buffer.byteLength(content, "utf8") !== result.byteCount || !/^sha256:[a-f0-9]{64}$/u.test(result.revision)) {
|
|
11714
|
+
throw new AgentMemoryError("Agent memory filesystem helper returned an invalid file state");
|
|
11715
|
+
}
|
|
11716
|
+
return Object.freeze({ exists: result.exists, content, revision: result.revision, byteCount: result.byteCount });
|
|
11717
|
+
}
|
|
11718
|
+
function encodeReplaceContent(content, maxBytes) {
|
|
11719
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0 || maxBytes > HELPER_MAX_CONTENT_BYTES) {
|
|
11720
|
+
throw new AgentMemoryError("Agent memory filesystem helper requested an invalid byte limit");
|
|
11721
|
+
}
|
|
11722
|
+
const bytes = Buffer.from(content, "utf8");
|
|
11723
|
+
if (bytes.byteLength > maxBytes) {
|
|
11724
|
+
throw new AgentMemoryError("Agent memory filesystem helper replacement exceeds its requested byte limit");
|
|
11725
|
+
}
|
|
11726
|
+
return bytes.toString("base64").replace(/=+$/u, "");
|
|
11727
|
+
}
|
|
11728
|
+
var AgentMemoryFilesystemHelperClient = class _AgentMemoryFilesystemHelperClient {
|
|
11729
|
+
constructor(child) {
|
|
11730
|
+
this.child = child;
|
|
11731
|
+
child.stdout.on("data", (chunk) => this.handleStdoutChunk(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
11732
|
+
child.stderr.on("data", (chunk) => {
|
|
11733
|
+
this.stderrBytes += Buffer.byteLength(chunk);
|
|
11734
|
+
if (this.stderrBytes > HELPER_MAX_STDERR_BYTES) this.fail(new AgentMemoryError("Agent memory filesystem helper exceeded bounded stderr"));
|
|
11735
|
+
});
|
|
11736
|
+
child.stdin.on("error", () => this.fail(new AgentMemoryError("Agent memory filesystem helper request could not be written")));
|
|
11737
|
+
child.once("error", () => this.fail(new AgentMemoryError("Agent memory filesystem helper could not be started")));
|
|
11738
|
+
child.once("exit", (code, signal) => {
|
|
11739
|
+
if (!this.closed || code !== 0) this.fail(new AgentMemoryError(`Agent memory filesystem helper exited unexpectedly (${code ?? signal ?? "unknown"})`));
|
|
11740
|
+
});
|
|
11741
|
+
}
|
|
11742
|
+
child;
|
|
11743
|
+
pending = /* @__PURE__ */ new Map();
|
|
11744
|
+
stdoutBuffer = Buffer.alloc(0);
|
|
11745
|
+
sequence = 0;
|
|
11746
|
+
stderrBytes = 0;
|
|
11747
|
+
closed = false;
|
|
11748
|
+
fatalError;
|
|
11749
|
+
static async open(input) {
|
|
11750
|
+
if (!helperPlatformSupported()) throw new AgentMemoryError("Agent memory filesystem helper is not admitted on this platform");
|
|
11751
|
+
const helperBin = safeHelperPath(input.helperBin);
|
|
11752
|
+
const child = spawn(helperBin, ["serve"], {
|
|
11753
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
11754
|
+
shell: false,
|
|
11755
|
+
windowsHide: true,
|
|
11756
|
+
env: Object.freeze({})
|
|
11757
|
+
});
|
|
11758
|
+
const client = new _AgentMemoryFilesystemHelperClient(child);
|
|
11759
|
+
try {
|
|
11760
|
+
const result = await client.request("open", {
|
|
11761
|
+
root: path3__default.resolve(input.canonicalHome),
|
|
11762
|
+
expectedIdentity: unixIdentity(input.homeIdentity)
|
|
11763
|
+
});
|
|
11764
|
+
if (result.helperVersion !== AGENT_MEMORY_FILESYSTEM_HELPER_VERSION) throw new AgentMemoryError("Agent memory filesystem helper version mismatch");
|
|
11765
|
+
const identity = result.identity;
|
|
11766
|
+
if (identity === null || typeof identity !== "object" || Array.isArray(identity)) throw new AgentMemoryError("Agent memory filesystem helper omitted root identity");
|
|
11767
|
+
const actual = identity;
|
|
11768
|
+
const expected = unixIdentity(input.homeIdentity);
|
|
11769
|
+
if (actual.kind !== expected.kind || actual.dev !== expected.dev || actual.ino !== expected.ino) throw new AgentMemoryError("Agent memory filesystem helper root identity mismatch");
|
|
11770
|
+
return client;
|
|
11771
|
+
} catch (error) {
|
|
11772
|
+
await client.close().catch(() => {
|
|
11773
|
+
});
|
|
11774
|
+
throw error;
|
|
11775
|
+
}
|
|
11776
|
+
}
|
|
11777
|
+
async read(relativePath, maxBytes) {
|
|
11778
|
+
return boundedFileState(await this.request("read", { path: relativePath, maxBytes }), maxBytes);
|
|
11779
|
+
}
|
|
11780
|
+
async replace(relativePath, expectedRevision, content, maxBytes) {
|
|
11781
|
+
try {
|
|
11782
|
+
const contentBase64 = encodeReplaceContent(content, maxBytes);
|
|
11783
|
+
return boundedFileState(await this.request("replace", { path: relativePath, expectedRevision, contentBase64, maxBytes }), maxBytes);
|
|
11784
|
+
} catch (error) {
|
|
11785
|
+
if (error instanceof HelperRevisionConflict) throw new AgentMemoryRevisionConflictError(expectedRevision, error.actualRevision);
|
|
11786
|
+
throw error;
|
|
11787
|
+
}
|
|
11788
|
+
}
|
|
11789
|
+
async delete(relativePath, expectedRevision) {
|
|
11790
|
+
try {
|
|
11791
|
+
await this.request("delete", { path: relativePath, expectedRevision });
|
|
11792
|
+
} catch (error) {
|
|
11793
|
+
if (error instanceof HelperRevisionConflict) throw new AgentMemoryRevisionConflictError(expectedRevision, error.actualRevision);
|
|
11794
|
+
throw error;
|
|
11795
|
+
}
|
|
11796
|
+
}
|
|
11797
|
+
async append(relativePath, content, maxBytes) {
|
|
11798
|
+
await this.request("append", { path: relativePath, content, maxBytes });
|
|
11799
|
+
}
|
|
11800
|
+
async walk(relativePath, maxEntries) {
|
|
11801
|
+
const result = await this.request("walk", { path: relativePath, maxEntries });
|
|
11802
|
+
if (!Array.isArray(result.paths) || result.paths.length > maxEntries || result.paths.some((candidate) => typeof candidate !== "string")) {
|
|
11803
|
+
throw new AgentMemoryError("Agent memory filesystem helper returned an invalid walk result");
|
|
11804
|
+
}
|
|
11805
|
+
return Object.freeze([...result.paths]);
|
|
11806
|
+
}
|
|
11807
|
+
async close() {
|
|
11808
|
+
if (this.closed) return;
|
|
11809
|
+
this.closed = true;
|
|
11810
|
+
try {
|
|
11811
|
+
if (this.child.exitCode === null && this.child.signalCode === null && this.fatalError === void 0) await this.requestWhileClosing("close", {});
|
|
11812
|
+
} finally {
|
|
11813
|
+
this.child.stdin.end();
|
|
11814
|
+
if (this.child.exitCode === null && this.child.signalCode === null) this.child.kill();
|
|
11815
|
+
this.rejectPending(new AgentMemoryError("Agent memory filesystem helper is closed"));
|
|
11816
|
+
}
|
|
11817
|
+
}
|
|
11818
|
+
request(op, fields) {
|
|
11819
|
+
if (this.closed) return Promise.reject(new AgentMemoryError("Agent memory filesystem helper is closed"));
|
|
11820
|
+
return this.requestInternal(op, fields);
|
|
11821
|
+
}
|
|
11822
|
+
requestWhileClosing(op, fields) {
|
|
11823
|
+
return this.requestInternal(op, fields);
|
|
11824
|
+
}
|
|
11825
|
+
requestInternal(op, fields) {
|
|
11826
|
+
if (this.fatalError !== void 0) return Promise.reject(this.fatalError);
|
|
11827
|
+
const id = `m${++this.sequence}`;
|
|
11828
|
+
let line;
|
|
11829
|
+
try {
|
|
11830
|
+
line = `${JSON.stringify({ id, protocol: AGENT_MEMORY_FILESYSTEM_HELPER_PROTOCOL, op, ...fields })}
|
|
11831
|
+
`;
|
|
11832
|
+
} catch {
|
|
11833
|
+
return Promise.reject(new AgentMemoryError("Agent memory filesystem helper request could not be encoded"));
|
|
11834
|
+
}
|
|
11835
|
+
if (Buffer.byteLength(line, "utf8") > HELPER_MAX_JSON_LINE_BYTES) {
|
|
11836
|
+
return Promise.reject(new AgentMemoryError("Agent memory filesystem helper request exceeded bounded stdin"));
|
|
11837
|
+
}
|
|
11838
|
+
return new Promise((resolve, reject) => {
|
|
11839
|
+
const timer = setTimeout(() => {
|
|
11840
|
+
this.pending.delete(id);
|
|
11841
|
+
const error = new AgentMemoryError("Agent memory filesystem helper request timed out");
|
|
11842
|
+
reject(error);
|
|
11843
|
+
this.fail(error);
|
|
11844
|
+
}, HELPER_REQUEST_TIMEOUT_MS);
|
|
11845
|
+
timer.unref?.();
|
|
11846
|
+
this.pending.set(id, { resolve: (response) => resolve(response.result), reject, timer });
|
|
11847
|
+
this.child.stdin.write(line, (error) => {
|
|
11848
|
+
if (!error) return;
|
|
11849
|
+
const item = this.pending.get(id);
|
|
11850
|
+
if (item === void 0) return;
|
|
11851
|
+
clearTimeout(item.timer);
|
|
11852
|
+
this.pending.delete(id);
|
|
11853
|
+
item.reject(new AgentMemoryError("Agent memory filesystem helper request could not be written"));
|
|
11854
|
+
});
|
|
11855
|
+
});
|
|
11856
|
+
}
|
|
11857
|
+
handleStdoutChunk(chunk) {
|
|
11858
|
+
let offset = 0;
|
|
11859
|
+
while (offset < chunk.length && this.fatalError === void 0) {
|
|
11860
|
+
const newline = chunk.indexOf(10, offset);
|
|
11861
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
11862
|
+
const segment = chunk.subarray(offset, end);
|
|
11863
|
+
if (this.stdoutBuffer.length + segment.length > HELPER_MAX_JSON_LINE_BYTES) {
|
|
11864
|
+
this.fail(new AgentMemoryError("Agent memory filesystem helper exceeded bounded stdout"));
|
|
11865
|
+
return;
|
|
11866
|
+
}
|
|
11867
|
+
this.stdoutBuffer = this.stdoutBuffer.length === 0 ? Buffer.from(segment) : Buffer.concat([this.stdoutBuffer, segment]);
|
|
11868
|
+
if (newline === -1) return;
|
|
11869
|
+
const line = this.stdoutBuffer;
|
|
11870
|
+
this.stdoutBuffer = Buffer.alloc(0);
|
|
11871
|
+
this.handleLine(line);
|
|
11872
|
+
offset = newline + 1;
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11875
|
+
handleLine(line) {
|
|
11876
|
+
let parsed;
|
|
11877
|
+
try {
|
|
11878
|
+
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(line));
|
|
11879
|
+
} catch {
|
|
11880
|
+
this.fail(new AgentMemoryError("Agent memory filesystem helper returned malformed JSON"));
|
|
11881
|
+
return;
|
|
11882
|
+
}
|
|
11883
|
+
const response = responseRecord(parsed);
|
|
11884
|
+
if (response === void 0) {
|
|
11885
|
+
this.fail(new AgentMemoryError("Agent memory filesystem helper returned an invalid response"));
|
|
11886
|
+
return;
|
|
11887
|
+
}
|
|
11888
|
+
const item = this.pending.get(response.id);
|
|
11889
|
+
if (item === void 0) {
|
|
11890
|
+
this.fail(new AgentMemoryError("Agent memory filesystem helper returned an unsolicited response"));
|
|
11891
|
+
return;
|
|
11892
|
+
}
|
|
11893
|
+
clearTimeout(item.timer);
|
|
11894
|
+
this.pending.delete(response.id);
|
|
11895
|
+
if (response.ok) {
|
|
11896
|
+
item.resolve(response);
|
|
11897
|
+
return;
|
|
11898
|
+
}
|
|
11899
|
+
if (response.error.code === "revision_conflict" && typeof response.error.actualRevision === "string") {
|
|
11900
|
+
item.reject(new HelperRevisionConflict(response.error.actualRevision));
|
|
11901
|
+
return;
|
|
11902
|
+
}
|
|
11903
|
+
item.reject(new AgentMemoryError(`Agent memory filesystem helper rejected the operation: ${response.error.code}`));
|
|
11904
|
+
}
|
|
11905
|
+
fail(error) {
|
|
11906
|
+
if (this.fatalError !== void 0) return;
|
|
11907
|
+
this.fatalError = error;
|
|
11908
|
+
this.rejectPending(error);
|
|
11909
|
+
if (this.child.exitCode === null && this.child.signalCode === null) this.child.kill();
|
|
11910
|
+
}
|
|
11911
|
+
rejectPending(error) {
|
|
11912
|
+
for (const item of this.pending.values()) {
|
|
11913
|
+
clearTimeout(item.timer);
|
|
11914
|
+
item.reject(error);
|
|
11915
|
+
}
|
|
11916
|
+
this.pending.clear();
|
|
11917
|
+
}
|
|
11918
|
+
};
|
|
11919
|
+
async function openAgentMemoryFilesystemHelper(input) {
|
|
11920
|
+
return AgentMemoryFilesystemHelperClient.open(input);
|
|
11921
|
+
}
|
|
11922
|
+
|
|
11923
|
+
// src/daemon/task-runner.ts
|
|
11924
|
+
var DEFAULT_APPROVAL_TIMEOUT_MS = 10 * 6e4;
|
|
11925
|
+
var DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS = 5e3;
|
|
11926
|
+
var AGENT_TERMINAL_EVIDENCE_MAX_ATTEMPTS = 3;
|
|
11927
|
+
var AGENT_TERMINAL_EVIDENCE_RETRY_DELAY_MS = 20;
|
|
11928
|
+
var GIT_OBSERVATION_TIMEOUT_MS = 5e3;
|
|
11929
|
+
var MAX_PENDING_APPROVALS_PER_TASK = 16;
|
|
11930
|
+
var NoPendingApprovalError = class extends Error {
|
|
11931
|
+
constructor(taskId) {
|
|
11932
|
+
super(`no pending out-of-band approval to resolve for task ${taskId}`);
|
|
11933
|
+
this.taskId = taskId;
|
|
11934
|
+
this.name = "NoPendingApprovalError";
|
|
11935
|
+
}
|
|
11936
|
+
taskId;
|
|
11937
|
+
};
|
|
11938
|
+
var MAX_INLINE_ARTIFACT_BYTES = 64 * 1024;
|
|
11939
|
+
var MAX_TRACKED_TASK_IDS = 2e3;
|
|
11940
|
+
var MAX_DURATION_EXCEEDED_REASON_PREFIX = "resource limit exceeded: maxDurationMs";
|
|
11941
|
+
var MAX_OUTPUT_BYTES_EXCEEDED_REASON_PREFIX = "resource limit exceeded: maxTaskOutputBytes";
|
|
11942
|
+
var MAX_PROGRESS_BATCH_BYTES_EXCEEDED_REASON_PREFIX = "resource limit exceeded: progressBatch.maxBatchBytes";
|
|
11943
|
+
var RESULT_DOCUMENT_UNDELIVERABLE_REASON_PREFIX = "result document undeliverable";
|
|
11944
|
+
function resultDocumentRejectionDetail(check) {
|
|
11945
|
+
switch (check.reason) {
|
|
11946
|
+
case "over-cap":
|
|
11947
|
+
return `${check.bytes} bytes as canonical JSON, over the ${RESULT_DOCUMENT_MAX_BYTES}-byte limit (it is never truncated \u2014 a truncated JSON document is not valid JSON; use artifactRefs for a result this size)`;
|
|
11948
|
+
case "not-serializable":
|
|
11949
|
+
return "not JSON-serializable (JSON.stringify threw, or produced no output at all)";
|
|
11950
|
+
case "not-plain-json":
|
|
11951
|
+
return "not plain JSON data: it does not equal its own JSON round trip, so serializing it would silently change it (an undefined-valued key, NaN, a function or symbol value, a Date, a toJSON that rewrites the value, or a getter that answers differently on a second read)";
|
|
11952
|
+
default: {
|
|
11953
|
+
const exhaustive = check;
|
|
11954
|
+
throw new Error(`unhandled result document rejection: ${JSON.stringify(exhaustive)}`);
|
|
11955
|
+
}
|
|
11956
|
+
}
|
|
11957
|
+
}
|
|
11958
|
+
var DEFAULT_MAX_TASK_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
11959
|
+
function isKnownRuntimeId(id) {
|
|
11960
|
+
return RuntimeIdSchema.safeParse(id).success;
|
|
11961
|
+
}
|
|
11962
|
+
function terminalUsageNumber(value, maximum) {
|
|
11963
|
+
return value !== void 0 && Number.isSafeInteger(value) && value >= 0 && value <= maximum ? value : void 0;
|
|
11964
|
+
}
|
|
11965
|
+
var DEFAULT_RUNTIME_PREFERENCE = ["claude", "codex", "pi"];
|
|
11966
|
+
function orderByPreference(candidates, preference) {
|
|
11967
|
+
const rank = new Map(preference.map((id, index) => [id, index]));
|
|
11968
|
+
return [...candidates].sort((a, b) => (rank.get(a.descriptor.id) ?? preference.length) - (rank.get(b.descriptor.id) ?? preference.length));
|
|
11969
|
+
}
|
|
11970
|
+
function adapterSupportsMode(descriptor, mode) {
|
|
11971
|
+
return descriptor.capabilities.permissionModes.includes(mode);
|
|
11972
|
+
}
|
|
11973
|
+
function adapterSupportsMcpToolsets(descriptor) {
|
|
11974
|
+
return descriptor.capabilities.mcpToolsets === true;
|
|
11975
|
+
}
|
|
11976
|
+
function withoutRequiredToolsets(payload) {
|
|
11977
|
+
const { requiredToolsets, egressPolicy, messageEgress, ...offer } = payload;
|
|
11978
|
+
return offer;
|
|
11979
|
+
}
|
|
11980
|
+
function sameEgressPolicy(left, right) {
|
|
11981
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
11982
|
+
}
|
|
11983
|
+
function offeredAgentRef(payload) {
|
|
11984
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "agentRef")) return void 0;
|
|
11985
|
+
return validateAgentRef(payload.agentRef);
|
|
11986
|
+
}
|
|
11987
|
+
function offeredSessionRef(payload) {
|
|
11988
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "sessionRef")) return void 0;
|
|
11989
|
+
const value = payload.sessionRef;
|
|
11990
|
+
return typeof value === "string" ? value : void 0;
|
|
11991
|
+
}
|
|
11992
|
+
function errorMessage4(err) {
|
|
11993
|
+
return err instanceof Error ? err.message : String(err);
|
|
11994
|
+
}
|
|
11995
|
+
function raceSettleFirst(fn, timeoutMs) {
|
|
11996
|
+
return new Promise((resolve) => {
|
|
11997
|
+
let settled = false;
|
|
11998
|
+
const timer = setTimeout(() => {
|
|
11999
|
+
if (!settled) {
|
|
12000
|
+
settled = true;
|
|
12001
|
+
resolve(false);
|
|
12002
|
+
}
|
|
12003
|
+
}, timeoutMs);
|
|
12004
|
+
timer.unref?.();
|
|
12005
|
+
void (async () => {
|
|
12006
|
+
try {
|
|
12007
|
+
await fn();
|
|
12008
|
+
} catch {
|
|
12009
|
+
}
|
|
12010
|
+
if (!settled) {
|
|
12011
|
+
settled = true;
|
|
12012
|
+
clearTimeout(timer);
|
|
12013
|
+
resolve(true);
|
|
12014
|
+
}
|
|
12015
|
+
})();
|
|
12016
|
+
});
|
|
12017
|
+
}
|
|
12018
|
+
function estimateEventBytes(event) {
|
|
12019
|
+
try {
|
|
12020
|
+
return Buffer.byteLength(JSON.stringify(event), "utf8");
|
|
12021
|
+
} catch {
|
|
12022
|
+
return 0;
|
|
12023
|
+
}
|
|
12024
|
+
}
|
|
12025
|
+
async function openArtifact(workspaceDir, name) {
|
|
12026
|
+
const realWorkspaceDir = await promises.realpath(workspaceDir).catch(() => workspaceDir);
|
|
12027
|
+
const candidate = path3__default.resolve(realWorkspaceDir, name);
|
|
12028
|
+
const prefix = realWorkspaceDir.endsWith(path3__default.sep) ? realWorkspaceDir : realWorkspaceDir + path3__default.sep;
|
|
12029
|
+
if (candidate !== realWorkspaceDir && !candidate.startsWith(prefix)) {
|
|
12030
|
+
return { ok: false, reason: `artifact name "${name}" resolves outside the task workspace \u2014 rejected` };
|
|
12031
|
+
}
|
|
12032
|
+
let realCandidate = candidate;
|
|
12033
|
+
try {
|
|
12034
|
+
realCandidate = await promises.realpath(candidate);
|
|
12035
|
+
} catch {
|
|
12036
|
+
}
|
|
12037
|
+
if (realCandidate !== realWorkspaceDir && !realCandidate.startsWith(prefix)) {
|
|
12038
|
+
return { ok: false, reason: `artifact name "${name}" resolves outside the task workspace \u2014 rejected` };
|
|
12039
|
+
}
|
|
12040
|
+
const O_NOFOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
12041
|
+
let handle;
|
|
12042
|
+
try {
|
|
12043
|
+
handle = await promises.open(candidate, constants.O_RDONLY | O_NOFOLLOW);
|
|
12044
|
+
} catch (err) {
|
|
12045
|
+
return { ok: false, reason: `artifact "${name}" could not be opened: ${errorMessage4(err)}` };
|
|
10872
12046
|
}
|
|
10873
12047
|
try {
|
|
10874
12048
|
const st = await handle.stat();
|
|
@@ -10890,6 +12064,16 @@ var TaskRunner = class {
|
|
|
10890
12064
|
}
|
|
10891
12065
|
deps;
|
|
10892
12066
|
tasks = /* @__PURE__ */ new Map();
|
|
12067
|
+
pendingMessageTasks = /* @__PURE__ */ new Map();
|
|
12068
|
+
messageContextByToken = /* @__PURE__ */ new Map();
|
|
12069
|
+
messageContextByTask = /* @__PURE__ */ new Map();
|
|
12070
|
+
memoryContextByToken = /* @__PURE__ */ new Map();
|
|
12071
|
+
memoryContextByTask = /* @__PURE__ */ new Map();
|
|
12072
|
+
memoryInFlightByTask = /* @__PURE__ */ new Map();
|
|
12073
|
+
memoryClosingTasks = /* @__PURE__ */ new Set();
|
|
12074
|
+
memoryFilesystemByTask = /* @__PURE__ */ new Map();
|
|
12075
|
+
recoveredMessageOutboxes = /* @__PURE__ */ new Map();
|
|
12076
|
+
recoveredMessageRetryTimers = /* @__PURE__ */ new Map();
|
|
10893
12077
|
/**
|
|
10894
12078
|
* Finding F4 (cancel lost during the offer-processing window): a
|
|
10895
12079
|
* `task.cancel` for a taskId that hasn't finished `handleOffer` yet (still
|
|
@@ -11029,6 +12213,128 @@ var TaskRunner = class {
|
|
|
11029
12213
|
pendingApprovals: (active.pendingApprovalId !== void 0 ? 1 : 0) + active.approvalQueue.length
|
|
11030
12214
|
}));
|
|
11031
12215
|
}
|
|
12216
|
+
/** Authenticated control-socket entry used only by the SDK-owned task MCP helper. */
|
|
12217
|
+
async publishAgentMessage(input) {
|
|
12218
|
+
const taskId = this.messageContextByToken.get(input.contextToken);
|
|
12219
|
+
if (taskId === void 0 || this.messageContextByTask.get(taskId) !== input.contextToken) {
|
|
12220
|
+
throw new Error("invalid or expired Agent message task context");
|
|
12221
|
+
}
|
|
12222
|
+
const pending = this.pendingMessageTasks.get(taskId);
|
|
12223
|
+
const active = this.tasks.get(taskId);
|
|
12224
|
+
const context = pending ?? (active?.messageRequirement && active.agentRef && active.messageOutbox ? { agentRef: active.agentRef, requirement: active.messageRequirement, outbox: active.messageOutbox } : void 0);
|
|
12225
|
+
if (context === void 0) throw new Error("task has no active required Agent message contract");
|
|
12226
|
+
const record = await context.outbox.appendDraft({
|
|
12227
|
+
taskId,
|
|
12228
|
+
tenantId: this.deps.tenantId,
|
|
12229
|
+
agentRef: context.agentRef,
|
|
12230
|
+
requirement: context.requirement,
|
|
12231
|
+
contentType: input.contentType,
|
|
12232
|
+
body: input.body,
|
|
12233
|
+
maxPendingEvents: 64,
|
|
12234
|
+
maxPendingBytes: 4 * 1024 * 1024
|
|
12235
|
+
});
|
|
12236
|
+
if (active === void 0) return { messageId: record.messageId, state: "staged" };
|
|
12237
|
+
const activated = await context.outbox.activate(taskId, active.session.sessionRef);
|
|
12238
|
+
if (activated === void 0) throw new Error("Agent message draft disappeared before activation");
|
|
12239
|
+
this.sendAgentMessageRecord(context.outbox, activated);
|
|
12240
|
+
return { messageId: activated.messageId, state: "pending" };
|
|
12241
|
+
}
|
|
12242
|
+
/** Authenticated control-socket entry used only by the SDK-owned memory MCP helper. */
|
|
12243
|
+
async recallAgentMemory(input) {
|
|
12244
|
+
return this.runMemoryOperation(input.contextToken, (context) => new AgentMemoryService(context).recall(input));
|
|
12245
|
+
}
|
|
12246
|
+
/** Authenticated control-socket entry used only by the SDK-owned memory MCP helper. */
|
|
12247
|
+
async saveAgentMemory(input) {
|
|
12248
|
+
return this.runMemoryOperation(input.contextToken, (context) => new AgentMemoryService(context).save(input));
|
|
12249
|
+
}
|
|
12250
|
+
/** Restore activated, unaccepted message drafts before transport admission on daemon restart. */
|
|
12251
|
+
async recoverAgentMessageOutboxes(agentsRoot) {
|
|
12252
|
+
if (this.deps.tenantId === void 0) throw new Error("Agent message recovery requires authenticated tenant enrollment");
|
|
12253
|
+
for (const outbox of await AgentMessageOutbox.recover(agentsRoot, this.deps.tenantId)) {
|
|
12254
|
+
for (const record of outbox.retryableRecords()) {
|
|
12255
|
+
if (record.sessionRef === void 0) continue;
|
|
12256
|
+
const existing = this.recoveredMessageOutboxes.get(record.taskId);
|
|
12257
|
+
if (existing !== void 0 && existing !== outbox) throw new Error(`multiple Agent message outboxes claim task ${record.taskId}`);
|
|
12258
|
+
this.recoveredMessageOutboxes.set(record.taskId, outbox);
|
|
12259
|
+
}
|
|
12260
|
+
}
|
|
12261
|
+
}
|
|
12262
|
+
/** Retry stable recovered records after a transport handshake/re-handshake. */
|
|
12263
|
+
retryRecoveredAgentMessages() {
|
|
12264
|
+
for (const [taskId, outbox] of this.recoveredMessageOutboxes) {
|
|
12265
|
+
const record = outbox.get(taskId);
|
|
12266
|
+
if (record?.sessionRef !== void 0) this.sendAgentMessageRecord(outbox, record);
|
|
12267
|
+
}
|
|
12268
|
+
}
|
|
12269
|
+
sendAgentMessageRecord(outbox, record) {
|
|
12270
|
+
this.deps.send(createEnvelope("agent.message.publish", outbox.publishPayload(record), {
|
|
12271
|
+
taskId: record.taskId,
|
|
12272
|
+
sessionRef: record.sessionRef
|
|
12273
|
+
}));
|
|
12274
|
+
const active = this.tasks.get(record.taskId);
|
|
12275
|
+
if (active?.messageOutbox === outbox) {
|
|
12276
|
+
if (active.messageRetryTimer !== void 0) clearTimeout(active.messageRetryTimer);
|
|
12277
|
+
active.messageRetryTimer = setTimeout(() => {
|
|
12278
|
+
active.messageRetryTimer = void 0;
|
|
12279
|
+
if (this.tasks.get(record.taskId) !== active) return;
|
|
12280
|
+
const pending = outbox.get(record.taskId);
|
|
12281
|
+
if (pending !== void 0) this.sendAgentMessageRecord(outbox, pending);
|
|
12282
|
+
}, 1e3);
|
|
12283
|
+
active.messageRetryTimer.unref?.();
|
|
12284
|
+
return;
|
|
12285
|
+
}
|
|
12286
|
+
if (this.recoveredMessageOutboxes.get(record.taskId) === outbox) {
|
|
12287
|
+
const prior = this.recoveredMessageRetryTimers.get(record.taskId);
|
|
12288
|
+
if (prior !== void 0) clearTimeout(prior);
|
|
12289
|
+
const timer = setTimeout(() => {
|
|
12290
|
+
this.recoveredMessageRetryTimers.delete(record.taskId);
|
|
12291
|
+
const pending = outbox.get(record.taskId);
|
|
12292
|
+
if (pending !== void 0 && this.recoveredMessageOutboxes.get(record.taskId) === outbox) {
|
|
12293
|
+
this.sendAgentMessageRecord(outbox, pending);
|
|
12294
|
+
}
|
|
12295
|
+
}, 1e3);
|
|
12296
|
+
timer.unref?.();
|
|
12297
|
+
this.recoveredMessageRetryTimers.set(record.taskId, timer);
|
|
12298
|
+
}
|
|
12299
|
+
}
|
|
12300
|
+
async handleAgentMessageDisposition(taskId, disposition) {
|
|
12301
|
+
const active = this.tasks.get(taskId);
|
|
12302
|
+
const outbox = active?.messageOutbox ?? this.recoveredMessageOutboxes.get(taskId);
|
|
12303
|
+
if (outbox === void 0) return;
|
|
12304
|
+
const outcome = await outbox.applyDisposition(taskId, disposition);
|
|
12305
|
+
if (active === void 0) {
|
|
12306
|
+
if (outcome === "accepted" || outcome === "held" || outcome === "refused") {
|
|
12307
|
+
const timer = this.recoveredMessageRetryTimers.get(taskId);
|
|
12308
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
12309
|
+
this.recoveredMessageRetryTimers.delete(taskId);
|
|
12310
|
+
}
|
|
12311
|
+
if (outcome === "accepted") this.recoveredMessageOutboxes.delete(taskId);
|
|
12312
|
+
return;
|
|
12313
|
+
}
|
|
12314
|
+
if (outcome === "held") {
|
|
12315
|
+
if (active.messageRetryTimer !== void 0) clearTimeout(active.messageRetryTimer);
|
|
12316
|
+
active.messageRetryTimer = void 0;
|
|
12317
|
+
return;
|
|
12318
|
+
}
|
|
12319
|
+
if (outcome === "refused") {
|
|
12320
|
+
if (active.messageRetryTimer !== void 0) clearTimeout(active.messageRetryTimer);
|
|
12321
|
+
active.messageRetryTimer = void 0;
|
|
12322
|
+
this.revokeAgentMessageContext(taskId);
|
|
12323
|
+
return;
|
|
12324
|
+
}
|
|
12325
|
+
if (outcome !== "accepted") return;
|
|
12326
|
+
if (active.messageRetryTimer !== void 0) {
|
|
12327
|
+
clearTimeout(active.messageRetryTimer);
|
|
12328
|
+
active.messageRetryTimer = void 0;
|
|
12329
|
+
}
|
|
12330
|
+
active.messageAccepted = true;
|
|
12331
|
+
this.revokeAgentMessageContext(taskId);
|
|
12332
|
+
if (active.pendingMessageCompletion !== void 0) {
|
|
12333
|
+
const completion = active.pendingMessageCompletion;
|
|
12334
|
+
active.pendingMessageCompletion = void 0;
|
|
12335
|
+
await this.publishSuccessfulCompletion(active, completion.finalOutput, completion.document);
|
|
12336
|
+
}
|
|
12337
|
+
}
|
|
11032
12338
|
/** M4 Phase 2: stop claiming any FUTURE `task.offer` — see `stoppingOffers`'s own doc comment. Idempotent. */
|
|
11033
12339
|
stopAcceptingOffers() {
|
|
11034
12340
|
this.stoppingOffers = true;
|
|
@@ -11204,6 +12510,9 @@ var TaskRunner = class {
|
|
|
11204
12510
|
case "task.reject":
|
|
11205
12511
|
await this.handleReject(envelope.task_id, envelope.payload.reason, envelope.payload.approvalId);
|
|
11206
12512
|
return;
|
|
12513
|
+
case "agent.message.disposition":
|
|
12514
|
+
await this.handleAgentMessageDisposition(envelope.task_id, envelope.payload);
|
|
12515
|
+
return;
|
|
11207
12516
|
default:
|
|
11208
12517
|
return;
|
|
11209
12518
|
}
|
|
@@ -11234,12 +12543,22 @@ var TaskRunner = class {
|
|
|
11234
12543
|
this.decline(taskId, reason, retryable, agentRef);
|
|
11235
12544
|
};
|
|
11236
12545
|
const sessionRef = offeredSessionRef(payload);
|
|
12546
|
+
const messageRequirement = "messageEgress" in payload ? payload.messageEgress : void 0;
|
|
12547
|
+
const terminalProjection = "terminalProjection" in payload ? payload.terminalProjection : void 0;
|
|
11237
12548
|
if ("egressPolicy" in payload) {
|
|
11238
12549
|
if (this.deps.agentEgressPolicy === void 0 || !sameEgressPolicy(this.deps.agentEgressPolicy, payload.egressPolicy)) {
|
|
11239
12550
|
decline("Agent egress offer policy is not exactly enabled by this daemon", false);
|
|
11240
12551
|
return;
|
|
11241
12552
|
}
|
|
11242
12553
|
}
|
|
12554
|
+
if (messageRequirement !== void 0 && (agentRef === void 0 || this.deps.agentMessageMcpBin === void 0 || this.deps.tenantId === void 0)) {
|
|
12555
|
+
decline("required Agent message egress is unavailable on this daemon", false);
|
|
12556
|
+
return;
|
|
12557
|
+
}
|
|
12558
|
+
if (terminalProjection?.mode === "result-document" && this.deps.resultDocument === void 0) {
|
|
12559
|
+
decline("offer requires a result document but this daemon has no resultDocument extractor", false);
|
|
12560
|
+
return;
|
|
12561
|
+
}
|
|
11243
12562
|
this.inFlightOffers.add(taskId);
|
|
11244
12563
|
let agentBinding;
|
|
11245
12564
|
let agentLeaseTransferred = false;
|
|
@@ -11298,11 +12617,29 @@ var TaskRunner = class {
|
|
|
11298
12617
|
}
|
|
11299
12618
|
const offered = withoutRequiredToolsets(payload);
|
|
11300
12619
|
const requestedRuntime = payload.dispatchSelection?.runtimeId ?? payload.runtime;
|
|
11301
|
-
const
|
|
12620
|
+
const requiresAgentMemoryMcp = agentRef !== void 0 && this.deps.agentMemoryMcpBin !== void 0 && isAgentMemorySecureFilesystemAvailable(this.deps.agentMemoryFilesystemHelperBin !== void 0);
|
|
12621
|
+
const pick = await this.pickAdapter(
|
|
12622
|
+
requestedRuntime,
|
|
12623
|
+
payload.policy.mode,
|
|
12624
|
+
requiredToolsets !== void 0 || messageRequirement !== void 0 || requiresAgentMemoryMcp
|
|
12625
|
+
);
|
|
11302
12626
|
if (!pick.ok) {
|
|
11303
12627
|
decline(pick.reason, pick.retryable);
|
|
11304
12628
|
return;
|
|
11305
12629
|
}
|
|
12630
|
+
let taskMcpServers = this.withAgentMessageMcp(
|
|
12631
|
+
resolvedMcp?.ok ? resolvedMcp.servers : void 0,
|
|
12632
|
+
taskId,
|
|
12633
|
+
messageRequirement
|
|
12634
|
+
);
|
|
12635
|
+
if (requiresAgentMemoryMcp && agentRef !== void 0) {
|
|
12636
|
+
try {
|
|
12637
|
+
taskMcpServers = this.withAgentMemoryMcp(taskMcpServers, taskId, agentRef);
|
|
12638
|
+
} catch (error) {
|
|
12639
|
+
decline(`Agent memory MCP configuration failed: ${errorMessage4(error)}`, false);
|
|
12640
|
+
return;
|
|
12641
|
+
}
|
|
12642
|
+
}
|
|
11306
12643
|
let prepared;
|
|
11307
12644
|
try {
|
|
11308
12645
|
prepared = await pick.adapter.prepare({
|
|
@@ -11310,7 +12647,7 @@ var TaskRunner = class {
|
|
|
11310
12647
|
policy: decision.policy,
|
|
11311
12648
|
descriptor: pick.descriptor,
|
|
11312
12649
|
requiredToolsetIds: requiredToolsets ?? [],
|
|
11313
|
-
...
|
|
12650
|
+
...taskMcpServers === void 0 ? {} : { mcpServers: taskMcpServers }
|
|
11314
12651
|
});
|
|
11315
12652
|
} catch (error) {
|
|
11316
12653
|
decline(`runtime preparation failed: ${errorMessage4(error)}`, true);
|
|
@@ -11365,6 +12702,23 @@ var TaskRunner = class {
|
|
|
11365
12702
|
decline(`Agent home initialization failed: ${errorMessage4(error)}`, false);
|
|
11366
12703
|
return;
|
|
11367
12704
|
}
|
|
12705
|
+
if (messageRequirement !== void 0) {
|
|
12706
|
+
try {
|
|
12707
|
+
const outbox = await AgentMessageOutbox.open(agentBinding.resolution.canonicalHome);
|
|
12708
|
+
this.pendingMessageTasks.set(taskId, {
|
|
12709
|
+
taskId,
|
|
12710
|
+
agentRef: agentBinding.resolution.agentRef,
|
|
12711
|
+
requirement: messageRequirement,
|
|
12712
|
+
outbox
|
|
12713
|
+
});
|
|
12714
|
+
} catch (error) {
|
|
12715
|
+
await agentBinding.lease.release().catch(() => {
|
|
12716
|
+
});
|
|
12717
|
+
agentBinding = void 0;
|
|
12718
|
+
decline(`Agent message outbox initialization failed: ${errorMessage4(error)}`, true);
|
|
12719
|
+
return;
|
|
12720
|
+
}
|
|
12721
|
+
}
|
|
11368
12722
|
} else if (this.deps.gitWorkspaceManager && this.deps.gitWorkspaceStore) {
|
|
11369
12723
|
known = sessionRef ? await this.deps.sessionWorkspaces.get(sessionRef) : void 0;
|
|
11370
12724
|
const gitManager = this.deps.gitWorkspaceManager;
|
|
@@ -11548,9 +12902,9 @@ var TaskRunner = class {
|
|
|
11548
12902
|
}
|
|
11549
12903
|
const startInput = {
|
|
11550
12904
|
manifest,
|
|
11551
|
-
instruction: gitWorkspaceId ? prependGitWorkspaceGuidance(resolvedInstruction) : resolvedInstruction,
|
|
12905
|
+
instruction: agentBinding === void 0 ? gitWorkspaceId ? prependGitWorkspaceGuidance(resolvedInstruction) : resolvedInstruction : prependAgentMemoryGuidance(resolvedInstruction),
|
|
11552
12906
|
env,
|
|
11553
|
-
...
|
|
12907
|
+
...taskMcpServers === void 0 ? {} : { mcpServers: taskMcpServers },
|
|
11554
12908
|
approvalChannel: {
|
|
11555
12909
|
taskId,
|
|
11556
12910
|
storeDir: this.deps.storeDir,
|
|
@@ -11620,7 +12974,12 @@ var TaskRunner = class {
|
|
|
11620
12974
|
),
|
|
11621
12975
|
approvalQueue: [],
|
|
11622
12976
|
outputBytesSoFar: 0,
|
|
11623
|
-
startedAtMs: Date.now()
|
|
12977
|
+
startedAtMs: Date.now(),
|
|
12978
|
+
...messageRequirement === void 0 ? {} : {
|
|
12979
|
+
messageRequirement,
|
|
12980
|
+
messageOutbox: this.pendingMessageTasks.get(taskId).outbox
|
|
12981
|
+
},
|
|
12982
|
+
...terminalProjection === void 0 ? {} : { terminalProjection }
|
|
11624
12983
|
};
|
|
11625
12984
|
if (agentBinding !== void 0) {
|
|
11626
12985
|
try {
|
|
@@ -11648,6 +13007,7 @@ var TaskRunner = class {
|
|
|
11648
13007
|
return;
|
|
11649
13008
|
}
|
|
11650
13009
|
}
|
|
13010
|
+
const activatedMessageRecord = active.messageOutbox === void 0 ? void 0 : await active.messageOutbox.activate(taskId, session.sessionRef);
|
|
11651
13011
|
if (this.pendingCancelled.has(taskId)) {
|
|
11652
13012
|
const reason = this.pendingCancelled.get(taskId);
|
|
11653
13013
|
this.pendingCancelled.delete(taskId);
|
|
@@ -11673,6 +13033,10 @@ var TaskRunner = class {
|
|
|
11673
13033
|
this.deps.send(createEnvelope("task.started", {}, { taskId }));
|
|
11674
13034
|
agentLeaseTransferred = agentBinding !== void 0;
|
|
11675
13035
|
this.tasks.set(taskId, active);
|
|
13036
|
+
this.pendingMessageTasks.delete(taskId);
|
|
13037
|
+
if (active.messageOutbox !== void 0 && activatedMessageRecord !== void 0) {
|
|
13038
|
+
this.sendAgentMessageRecord(active.messageOutbox, activatedMessageRecord);
|
|
13039
|
+
}
|
|
11676
13040
|
if (payload.limits?.maxDurationMs !== void 0) {
|
|
11677
13041
|
this.armMaxDurationTimer(active, payload.limits.maxDurationMs);
|
|
11678
13042
|
}
|
|
@@ -11690,6 +13054,11 @@ var TaskRunner = class {
|
|
|
11690
13054
|
});
|
|
11691
13055
|
}
|
|
11692
13056
|
} finally {
|
|
13057
|
+
if (!agentLeaseTransferred) {
|
|
13058
|
+
this.pendingMessageTasks.delete(taskId);
|
|
13059
|
+
this.revokeAgentMessageContext(taskId);
|
|
13060
|
+
this.revokeAgentMemoryContext(taskId);
|
|
13061
|
+
}
|
|
11693
13062
|
if (agentBinding !== void 0 && !agentLeaseTransferred) {
|
|
11694
13063
|
await agentBinding.lease.release().catch(() => {
|
|
11695
13064
|
});
|
|
@@ -11697,6 +13066,153 @@ var TaskRunner = class {
|
|
|
11697
13066
|
this.inFlightOffers.delete(taskId);
|
|
11698
13067
|
}
|
|
11699
13068
|
}
|
|
13069
|
+
withAgentMessageMcp(existing, taskId, requirement) {
|
|
13070
|
+
if (requirement === void 0) return existing;
|
|
13071
|
+
const bin = this.deps.agentMessageMcpBin;
|
|
13072
|
+
const contextToken = `${randomUUID()}.${randomUUID()}`;
|
|
13073
|
+
this.revokeAgentMessageContext(taskId);
|
|
13074
|
+
this.messageContextByToken.set(contextToken, taskId);
|
|
13075
|
+
this.messageContextByTask.set(taskId, contextToken);
|
|
13076
|
+
return Object.freeze({
|
|
13077
|
+
...existing ?? {},
|
|
13078
|
+
[AGENT_MESSAGE_MCP_SERVER_NAME]: Object.freeze({
|
|
13079
|
+
command: bin.command,
|
|
13080
|
+
args: Object.freeze([...bin.args]),
|
|
13081
|
+
env: Object.freeze({
|
|
13082
|
+
BYOK_STORE_DIR: this.deps.storeDir,
|
|
13083
|
+
BYOK_PRODUCT_ID: this.deps.productId,
|
|
13084
|
+
BYOK_AGENT_MESSAGE_CONTEXT: contextToken
|
|
13085
|
+
})
|
|
13086
|
+
})
|
|
13087
|
+
});
|
|
13088
|
+
}
|
|
13089
|
+
revokeAgentMessageContext(taskId) {
|
|
13090
|
+
const token = this.messageContextByTask.get(taskId);
|
|
13091
|
+
if (token !== void 0) this.messageContextByToken.delete(token);
|
|
13092
|
+
this.messageContextByTask.delete(taskId);
|
|
13093
|
+
}
|
|
13094
|
+
/** Injected only after strict Agent admission; a host registry may never replace this reserved name. */
|
|
13095
|
+
withAgentMemoryMcp(existing, taskId, agentRef) {
|
|
13096
|
+
if (existing !== void 0 && Object.prototype.hasOwnProperty.call(existing, AGENT_MEMORY_MCP_SERVER_NAME)) {
|
|
13097
|
+
throw new Error(`MCP server name "${AGENT_MEMORY_MCP_SERVER_NAME}" is reserved by the daemon`);
|
|
13098
|
+
}
|
|
13099
|
+
const bin = this.deps.agentMemoryMcpBin;
|
|
13100
|
+
const contextToken = `${randomUUID()}.${randomUUID()}`;
|
|
13101
|
+
this.revokeAgentMemoryContext(taskId);
|
|
13102
|
+
this.memoryContextByToken.set(contextToken, Object.freeze({ taskId, agentRef: Object.freeze({ ...agentRef }) }));
|
|
13103
|
+
this.memoryContextByTask.set(taskId, contextToken);
|
|
13104
|
+
return Object.freeze({
|
|
13105
|
+
...existing ?? {},
|
|
13106
|
+
[AGENT_MEMORY_MCP_SERVER_NAME]: Object.freeze({
|
|
13107
|
+
command: bin.command,
|
|
13108
|
+
args: Object.freeze([...bin.args]),
|
|
13109
|
+
env: Object.freeze({
|
|
13110
|
+
BYOK_STORE_DIR: this.deps.storeDir,
|
|
13111
|
+
BYOK_PRODUCT_ID: this.deps.productId,
|
|
13112
|
+
BYOK_AGENT_MEMORY_CONTEXT: contextToken
|
|
13113
|
+
})
|
|
13114
|
+
})
|
|
13115
|
+
});
|
|
13116
|
+
}
|
|
13117
|
+
/** Reconstruct all sensitive context from the active sealed task, never from MCP/model arguments. */
|
|
13118
|
+
activeMemoryContext(contextToken) {
|
|
13119
|
+
const registered = this.memoryContextByToken.get(contextToken);
|
|
13120
|
+
if (registered === void 0 || this.memoryContextByTask.get(registered.taskId) !== contextToken || this.memoryClosingTasks.has(registered.taskId)) {
|
|
13121
|
+
throw new Error("invalid, expired, or quiescing Agent memory task context");
|
|
13122
|
+
}
|
|
13123
|
+
const active = this.tasks.get(registered.taskId);
|
|
13124
|
+
if (active === void 0 || active.finalizationStarted || active.agentBinding === void 0 || active.agentRef === void 0 || active.agentHandoff === void 0 || this.deps.tenantId === void 0 || active.agentRef.agentId !== registered.agentRef.agentId || active.agentRef.profileRevision !== registered.agentRef.profileRevision || active.agentBinding.resolution.agentRef.agentId !== registered.agentRef.agentId || active.agentBinding.resolution.agentRef.profileRevision !== registered.agentRef.profileRevision || active.agentHandoff.sessionRef !== active.session.sessionRef || active.agentHandoff.runtimeId !== active.adapter.descriptor.id || active.agentHandoff.cwd !== active.agentBinding.lease.cwd || active.agentBinding.lease.canonicalHome !== active.agentBinding.resolution.canonicalHome) {
|
|
13125
|
+
throw new Error("Agent memory context no longer matches its exact active task identity");
|
|
13126
|
+
}
|
|
13127
|
+
return Object.freeze({
|
|
13128
|
+
taskId: registered.taskId,
|
|
13129
|
+
tenantId: this.deps.tenantId,
|
|
13130
|
+
deviceId: this.deps.deviceId,
|
|
13131
|
+
agentRef: Object.freeze({ ...active.agentRef }),
|
|
13132
|
+
sessionRef: active.session.sessionRef,
|
|
13133
|
+
runtimeId: active.adapter.descriptor.id,
|
|
13134
|
+
canonicalHome: active.agentBinding.resolution.canonicalHome,
|
|
13135
|
+
leaseId: active.agentBinding.lease.leaseId,
|
|
13136
|
+
homeIdentity: active.agentBinding.lease.homeIdentity
|
|
13137
|
+
});
|
|
13138
|
+
}
|
|
13139
|
+
async runMemoryOperation(contextToken, operation) {
|
|
13140
|
+
let context = this.activeMemoryContext(contextToken);
|
|
13141
|
+
context = await this.bindAgentMemoryFilesystem(context);
|
|
13142
|
+
const current = this.activeMemoryContext(contextToken);
|
|
13143
|
+
if (current.taskId !== context.taskId || current.leaseId !== context.leaseId) throw new Error("Agent memory context changed during secure filesystem handshake");
|
|
13144
|
+
context = Object.freeze({ ...current, ...context.filesystem === void 0 ? {} : { filesystem: context.filesystem } });
|
|
13145
|
+
const pending = this.memoryInFlightByTask.get(context.taskId) ?? /* @__PURE__ */ new Set();
|
|
13146
|
+
this.memoryInFlightByTask.set(context.taskId, pending);
|
|
13147
|
+
const result = operation(context);
|
|
13148
|
+
pending.add(result);
|
|
13149
|
+
try {
|
|
13150
|
+
return await result;
|
|
13151
|
+
} finally {
|
|
13152
|
+
pending.delete(result);
|
|
13153
|
+
if (pending.size === 0) this.memoryInFlightByTask.delete(context.taskId);
|
|
13154
|
+
}
|
|
13155
|
+
}
|
|
13156
|
+
async quiesceAndSnapshotAgentMemory(active) {
|
|
13157
|
+
if (active.agentBinding === void 0 || active.agentRef === void 0 || active.agentHandoff === void 0) return;
|
|
13158
|
+
if (!isAgentMemorySecureFilesystemAvailable(this.deps.agentMemoryFilesystemHelperBin !== void 0)) return;
|
|
13159
|
+
if (this.deps.tenantId === void 0) {
|
|
13160
|
+
console.error(`[byok/client] Agent memory quiescent snapshot skipped for ${active.taskId}: exact tenant context is unavailable`);
|
|
13161
|
+
return;
|
|
13162
|
+
}
|
|
13163
|
+
this.memoryClosingTasks.add(active.taskId);
|
|
13164
|
+
try {
|
|
13165
|
+
await Promise.allSettled([...this.memoryInFlightByTask.get(active.taskId) ?? []]);
|
|
13166
|
+
const context = await this.bindAgentMemoryFilesystem({
|
|
13167
|
+
taskId: active.taskId,
|
|
13168
|
+
tenantId: this.deps.tenantId,
|
|
13169
|
+
deviceId: this.deps.deviceId,
|
|
13170
|
+
agentRef: active.agentRef,
|
|
13171
|
+
sessionRef: active.agentHandoff.sessionRef,
|
|
13172
|
+
runtimeId: active.agentHandoff.runtimeId,
|
|
13173
|
+
canonicalHome: active.agentBinding.resolution.canonicalHome,
|
|
13174
|
+
leaseId: active.agentBinding.lease.leaseId,
|
|
13175
|
+
homeIdentity: active.agentBinding.lease.homeIdentity
|
|
13176
|
+
});
|
|
13177
|
+
await snapshotAndProjectAgentMemory(context, this.deps.agentMemoryHostedProjection);
|
|
13178
|
+
} catch (error) {
|
|
13179
|
+
console.error(`[byok/client] Agent memory quiescent snapshot failed for ${active.taskId}: ${errorMessage4(error)}`);
|
|
13180
|
+
} finally {
|
|
13181
|
+
await this.closeAgentMemoryFilesystem(active.taskId);
|
|
13182
|
+
}
|
|
13183
|
+
}
|
|
13184
|
+
async bindAgentMemoryFilesystem(context) {
|
|
13185
|
+
const helperBin = this.deps.agentMemoryFilesystemHelperBin;
|
|
13186
|
+
if (helperBin === void 0) return context;
|
|
13187
|
+
let filesystem = this.memoryFilesystemByTask.get(context.taskId);
|
|
13188
|
+
if (filesystem === void 0) {
|
|
13189
|
+
filesystem = openAgentMemoryFilesystemHelper({
|
|
13190
|
+
helperBin,
|
|
13191
|
+
canonicalHome: context.canonicalHome,
|
|
13192
|
+
homeIdentity: context.homeIdentity
|
|
13193
|
+
});
|
|
13194
|
+
this.memoryFilesystemByTask.set(context.taskId, filesystem);
|
|
13195
|
+
void filesystem.catch(() => {
|
|
13196
|
+
if (this.memoryFilesystemByTask.get(context.taskId) === filesystem) this.memoryFilesystemByTask.delete(context.taskId);
|
|
13197
|
+
});
|
|
13198
|
+
}
|
|
13199
|
+
return Object.freeze({ ...context, filesystem: await filesystem });
|
|
13200
|
+
}
|
|
13201
|
+
async closeAgentMemoryFilesystem(taskId) {
|
|
13202
|
+
const filesystem = this.memoryFilesystemByTask.get(taskId);
|
|
13203
|
+
this.memoryFilesystemByTask.delete(taskId);
|
|
13204
|
+
if (filesystem === void 0) return;
|
|
13205
|
+
await filesystem.then((authority) => authority.close()).catch(() => {
|
|
13206
|
+
});
|
|
13207
|
+
}
|
|
13208
|
+
revokeAgentMemoryContext(taskId) {
|
|
13209
|
+
const token = this.memoryContextByTask.get(taskId);
|
|
13210
|
+
if (token !== void 0) this.memoryContextByToken.delete(token);
|
|
13211
|
+
this.memoryContextByTask.delete(taskId);
|
|
13212
|
+
this.memoryInFlightByTask.delete(taskId);
|
|
13213
|
+
this.memoryClosingTasks.delete(taskId);
|
|
13214
|
+
void this.closeAgentMemoryFilesystem(taskId);
|
|
13215
|
+
}
|
|
11700
13216
|
/** Protocol §7: an instruction too large to inline arrives as a `blobRef` — resolve it via the blob client rather than failing closed. */
|
|
11701
13217
|
async resolveInstruction(instruction) {
|
|
11702
13218
|
if (typeof instruction === "string") return instruction;
|
|
@@ -11774,42 +13290,13 @@ var TaskRunner = class {
|
|
|
11774
13290
|
if (!outcome.deliver) return;
|
|
11775
13291
|
await this.observeGit(active, "completed");
|
|
11776
13292
|
if (this.tasks.get(active.taskId) !== active || active.beingTornDown) return;
|
|
11777
|
-
if (
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
false
|
|
11782
|
-
);
|
|
13293
|
+
if (active.messageRequirement !== void 0 && active.messageAccepted !== true) {
|
|
13294
|
+
active.pendingMessageCompletion = { finalOutput, ...outcome.document === void 0 ? {} : { document: outcome.document } };
|
|
13295
|
+
const record = active.messageOutbox?.get(active.taskId);
|
|
13296
|
+
if (record !== void 0) this.sendAgentMessageRecord(active.messageOutbox, record);
|
|
11783
13297
|
return;
|
|
11784
13298
|
}
|
|
11785
|
-
|
|
11786
|
-
await this.persistAgentTerminalEvidence(active, "complete");
|
|
11787
|
-
this.deps.send(
|
|
11788
|
-
createEnvelope(
|
|
11789
|
-
"task.complete",
|
|
11790
|
-
{
|
|
11791
|
-
summary: finalOutput,
|
|
11792
|
-
sessionRef: active.session.sessionRef,
|
|
11793
|
-
// Spread rather than `document: outcome.document`, so a
|
|
11794
|
-
// completion with no document is the exact same payload it
|
|
11795
|
-
// was before this field existed — not one carrying an
|
|
11796
|
-
// explicit `document: undefined` key.
|
|
11797
|
-
//
|
|
11798
|
-
// `outcome.document` is the protocol's CANONICAL SNAPSHOT
|
|
11799
|
-
// (`checkResultDocument`), never the object the extractor
|
|
11800
|
-
// returned: pure data serializes identically at the root
|
|
11801
|
-
// (where it was measured) and nested inside this payload
|
|
11802
|
-
// (where the codec actually serializes it), so a contextual
|
|
11803
|
-
// `toJSON(key)` or an unstable getter cannot make the wire
|
|
11804
|
-
// bytes differ from what the cap gate approved.
|
|
11805
|
-
...outcome.document !== void 0 ? { document: outcome.document } : {},
|
|
11806
|
-
...this.terminalInferenceUsagePayload(active),
|
|
11807
|
-
...this.agentTerminalPayload(active)
|
|
11808
|
-
},
|
|
11809
|
-
{ taskId: active.taskId, sessionRef: active.session.sessionRef }
|
|
11810
|
-
)
|
|
11811
|
-
);
|
|
11812
|
-
await this.finish(active.taskId);
|
|
13299
|
+
await this.publishSuccessfulCompletion(active, finalOutput, outcome.document);
|
|
11813
13300
|
return;
|
|
11814
13301
|
}
|
|
11815
13302
|
if (event.type === "progress") {
|
|
@@ -11845,6 +13332,26 @@ var TaskRunner = class {
|
|
|
11845
13332
|
await this.fail(active.taskId, failure.reason, failure.retryable);
|
|
11846
13333
|
}
|
|
11847
13334
|
}
|
|
13335
|
+
async publishSuccessfulCompletion(active, finalOutput, document) {
|
|
13336
|
+
if (document !== void 0 && !this.hasResultDocumentCapability()) {
|
|
13337
|
+
await this.fail(
|
|
13338
|
+
active.taskId,
|
|
13339
|
+
`${RESULT_DOCUMENT_UNDELIVERABLE_REASON_PREFIX}: the connected server stopped advertising the result-document capability before this completion could be sent (a reconnect to an older server), so it would silently discard this document`,
|
|
13340
|
+
false
|
|
13341
|
+
);
|
|
13342
|
+
return;
|
|
13343
|
+
}
|
|
13344
|
+
if (!this.reserveSemanticTerminal(active)) return;
|
|
13345
|
+
await this.persistAgentTerminalEvidence(active, "complete");
|
|
13346
|
+
this.deps.send(createEnvelope("task.complete", {
|
|
13347
|
+
summary: finalOutput,
|
|
13348
|
+
sessionRef: active.session.sessionRef,
|
|
13349
|
+
...document !== void 0 ? { document } : {},
|
|
13350
|
+
...this.terminalInferenceUsagePayload(active),
|
|
13351
|
+
...this.agentTerminalPayload(active)
|
|
13352
|
+
}, { taskId: active.taskId, sessionRef: active.session.sessionRef }));
|
|
13353
|
+
await this.finish(active.taskId);
|
|
13354
|
+
}
|
|
11848
13355
|
/**
|
|
11849
13356
|
* Protocol §7: an `artifact` `AgentEvent` only names a file the runtime
|
|
11850
13357
|
* wrote into the task workspace (`name`/`contentType` — it carries no
|
|
@@ -12527,11 +14034,26 @@ var TaskRunner = class {
|
|
|
12527
14034
|
* docs/protocol.md §7.2.
|
|
12528
14035
|
*/
|
|
12529
14036
|
async resolveResultDocument(active, finalOutput) {
|
|
14037
|
+
if (active.terminalProjection?.mode === "none" || active.messageRequirement !== void 0 && active.terminalProjection === void 0) return { deliver: true };
|
|
12530
14038
|
const extract = this.deps.resultDocument?.extract;
|
|
12531
|
-
if (!extract)
|
|
14039
|
+
if (!extract) {
|
|
14040
|
+
if (active.terminalProjection?.mode === "result-document") {
|
|
14041
|
+
await this.fail(
|
|
14042
|
+
active.taskId,
|
|
14043
|
+
`${RESULT_DOCUMENT_UNDELIVERABLE_REASON_PREFIX}: the offer requires result contract ${active.terminalProjection.contract} but this daemon has no extractor`,
|
|
14044
|
+
false
|
|
14045
|
+
);
|
|
14046
|
+
return { deliver: false };
|
|
14047
|
+
}
|
|
14048
|
+
return { deliver: true };
|
|
14049
|
+
}
|
|
12532
14050
|
let document;
|
|
12533
14051
|
try {
|
|
12534
|
-
document = extract(finalOutput, {
|
|
14052
|
+
document = extract(finalOutput, {
|
|
14053
|
+
taskId: active.taskId,
|
|
14054
|
+
sessionRef: active.session.sessionRef,
|
|
14055
|
+
...active.terminalProjection === void 0 ? {} : { terminalProjection: active.terminalProjection }
|
|
14056
|
+
});
|
|
12535
14057
|
} catch (err) {
|
|
12536
14058
|
await this.fail(
|
|
12537
14059
|
active.taskId,
|
|
@@ -12548,7 +14070,17 @@ var TaskRunner = class {
|
|
|
12548
14070
|
);
|
|
12549
14071
|
return { deliver: false };
|
|
12550
14072
|
}
|
|
12551
|
-
if (document === void 0)
|
|
14073
|
+
if (document === void 0) {
|
|
14074
|
+
if (active.terminalProjection?.mode === "result-document") {
|
|
14075
|
+
await this.fail(
|
|
14076
|
+
active.taskId,
|
|
14077
|
+
`${RESULT_DOCUMENT_UNDELIVERABLE_REASON_PREFIX}: the required result contract ${active.terminalProjection.contract} produced no document`,
|
|
14078
|
+
false
|
|
14079
|
+
);
|
|
14080
|
+
return { deliver: false };
|
|
14081
|
+
}
|
|
14082
|
+
return { deliver: true };
|
|
14083
|
+
}
|
|
12552
14084
|
const check = checkResultDocument(document);
|
|
12553
14085
|
if (!check.ok) {
|
|
12554
14086
|
const detail = resultDocumentRejectionDetail(check);
|
|
@@ -12682,6 +14214,10 @@ var TaskRunner = class {
|
|
|
12682
14214
|
clearTimeout(active.maxDurationTimer);
|
|
12683
14215
|
active.maxDurationTimer = void 0;
|
|
12684
14216
|
}
|
|
14217
|
+
if (active.messageRetryTimer) {
|
|
14218
|
+
clearTimeout(active.messageRetryTimer);
|
|
14219
|
+
active.messageRetryTimer = void 0;
|
|
14220
|
+
}
|
|
12685
14221
|
active.batcher.stop();
|
|
12686
14222
|
this.addFinishedTaskId(taskId);
|
|
12687
14223
|
const queued = active.approvalQueue.splice(0);
|
|
@@ -12722,6 +14258,7 @@ var TaskRunner = class {
|
|
|
12722
14258
|
if (active.agentBinding !== void 0 && active.agentRef !== void 0 && active.agentHandoff !== void 0) {
|
|
12723
14259
|
const agentRef = active.agentRef;
|
|
12724
14260
|
const handoff = active.agentHandoff;
|
|
14261
|
+
await this.quiesceAndSnapshotAgentMemory(active);
|
|
12725
14262
|
if (!active.agentTerminalPersisted) {
|
|
12726
14263
|
const cause = active.terminalCause ?? "failed";
|
|
12727
14264
|
const result = await this.retryAgentTerminalEvidence(
|
|
@@ -12760,11 +14297,15 @@ var TaskRunner = class {
|
|
|
12760
14297
|
}
|
|
12761
14298
|
active.gitLease?.release();
|
|
12762
14299
|
this.tasks.delete(taskId);
|
|
14300
|
+
this.revokeAgentMessageContext(taskId);
|
|
14301
|
+
this.revokeAgentMemoryContext(taskId);
|
|
12763
14302
|
active.resolveSemanticTerminalSettled?.(leaseReleased);
|
|
12764
14303
|
return leaseReleased;
|
|
12765
14304
|
}
|
|
12766
14305
|
active.gitLease?.release();
|
|
12767
14306
|
this.tasks.delete(taskId);
|
|
14307
|
+
this.revokeAgentMessageContext(taskId);
|
|
14308
|
+
this.revokeAgentMemoryContext(taskId);
|
|
12768
14309
|
active.resolveSemanticTerminalSettled?.(true);
|
|
12769
14310
|
return true;
|
|
12770
14311
|
}
|
|
@@ -12928,9 +14469,9 @@ function metadataStatusEvent(event) {
|
|
|
12928
14469
|
return { ...event };
|
|
12929
14470
|
}
|
|
12930
14471
|
}
|
|
12931
|
-
var
|
|
14472
|
+
var encoder3 = new TextEncoder();
|
|
12932
14473
|
function eventBytes(event) {
|
|
12933
|
-
return
|
|
14474
|
+
return encoder3.encode(JSON.stringify(event)).length;
|
|
12934
14475
|
}
|
|
12935
14476
|
var AGENT_EGRESS_DIRECTORY = path3__default.join(".byok", "egress");
|
|
12936
14477
|
var AGENT_RELIABLE_SPOOL_FILENAME = "reliable-v1.jsonl";
|
|
@@ -12948,7 +14489,7 @@ var AgentReliableQuotaError = class extends AgentReliableSpoolError {
|
|
|
12948
14489
|
}
|
|
12949
14490
|
reason;
|
|
12950
14491
|
};
|
|
12951
|
-
function
|
|
14492
|
+
function sameAgentRef2(left, right) {
|
|
12952
14493
|
return left.agentId === right.agentId && left.profileRevision === right.profileRevision;
|
|
12953
14494
|
}
|
|
12954
14495
|
function stableRecordJson(value) {
|
|
@@ -12981,7 +14522,7 @@ function assertWireType(value) {
|
|
|
12981
14522
|
}
|
|
12982
14523
|
}
|
|
12983
14524
|
function sameRecord(record, candidate) {
|
|
12984
|
-
return record.wireType === candidate.wireType &&
|
|
14525
|
+
return record.wireType === candidate.wireType && sameAgentRef2(record.agentRef, candidate.agentRef) && record.tenantId === candidate.tenantId && record.policyRevision === candidate.policyRevision && record.eventId === candidate.eventId && record.cursor === candidate.cursor && record.payloadHash === candidate.payloadHash && record.byteCount === candidate.byteCount && record.sessionRef === candidate.sessionRef && record.taskId === candidate.taskId;
|
|
12985
14526
|
}
|
|
12986
14527
|
function parseEntry2(value) {
|
|
12987
14528
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new AgentReliableSpoolError("reliable spool entry is not an object");
|
|
@@ -13168,7 +14709,7 @@ var AgentReliableSpool = class _AgentReliableSpool {
|
|
|
13168
14709
|
return this.exclusive(async () => {
|
|
13169
14710
|
const record = this.pending.get(ack.eventId);
|
|
13170
14711
|
if (!record) return false;
|
|
13171
|
-
if (record.cursor !== ack.cursor || record.tenantId !== ack.tenantId || record.sessionRef !== ack.sessionRef || record.policyRevision !== ack.policyRevision || !
|
|
14712
|
+
if (record.cursor !== ack.cursor || record.tenantId !== ack.tenantId || record.sessionRef !== ack.sessionRef || record.policyRevision !== ack.policyRevision || !sameAgentRef2(record.agentRef, ack.agentRef)) return false;
|
|
13172
14713
|
await this.appendEntry({ schema: 1, kind: "ack", ack: Object.freeze({ ...ack, agentRef: { ...ack.agentRef } }) });
|
|
13173
14714
|
this.pending.delete(record.eventId);
|
|
13174
14715
|
if (this.logEntries >= 512) await this.compact();
|
|
@@ -13201,7 +14742,7 @@ var AgentReliableSpool = class _AgentReliableSpool {
|
|
|
13201
14742
|
} else {
|
|
13202
14743
|
const record = this.pending.get(entry.ack.eventId);
|
|
13203
14744
|
if (!record) throw new AgentReliableSpoolError("reliable spool acknowledges an unknown event");
|
|
13204
|
-
if (record.cursor !== entry.ack.cursor || record.tenantId !== entry.ack.tenantId || record.sessionRef !== entry.ack.sessionRef || record.policyRevision !== entry.ack.policyRevision || !
|
|
14745
|
+
if (record.cursor !== entry.ack.cursor || record.tenantId !== entry.ack.tenantId || record.sessionRef !== entry.ack.sessionRef || record.policyRevision !== entry.ack.policyRevision || !sameAgentRef2(record.agentRef, entry.ack.agentRef)) throw new AgentReliableSpoolError("reliable spool contains a mismatched ack");
|
|
13205
14746
|
this.pending.delete(record.eventId);
|
|
13206
14747
|
}
|
|
13207
14748
|
}
|
|
@@ -13863,7 +15404,7 @@ var AgentHomeProjectionCompletionError = class extends Error {
|
|
|
13863
15404
|
this.name = "AgentHomeProjectionCompletionError";
|
|
13864
15405
|
}
|
|
13865
15406
|
};
|
|
13866
|
-
function
|
|
15407
|
+
function sameAgentRef3(left, right) {
|
|
13867
15408
|
return left.agentId === right.agentId && left.profileRevision === right.profileRevision;
|
|
13868
15409
|
}
|
|
13869
15410
|
var AgentHomeProjectionCompletionClient = class {
|
|
@@ -13906,7 +15447,7 @@ var AgentHomeProjectionCompletionClient = class {
|
|
|
13906
15447
|
cause: error
|
|
13907
15448
|
});
|
|
13908
15449
|
}
|
|
13909
|
-
if (readback.tenantId !== this.options.tenantId || readback.deviceId !== this.options.deviceId || readback.requestId !== completion.requestId || !
|
|
15450
|
+
if (readback.tenantId !== this.options.tenantId || readback.deviceId !== this.options.deviceId || readback.requestId !== completion.requestId || !sameAgentRef3(readback.agentRef, completion.agentRef) || readback.projectionHash !== completion.projectionHash || readback.status !== completion.outcome || readback.completedAt === void 0) {
|
|
13910
15451
|
throw new AgentHomeProjectionCompletionError(
|
|
13911
15452
|
"Agent-home projection completion readback does not exactly match the authenticated request"
|
|
13912
15453
|
);
|
|
@@ -13914,6 +15455,15 @@ var AgentHomeProjectionCompletionClient = class {
|
|
|
13914
15455
|
return readback;
|
|
13915
15456
|
}
|
|
13916
15457
|
};
|
|
15458
|
+
function resolveAgentMessageMcpBin() {
|
|
15459
|
+
const script = path3__default.join(path3__default.dirname(fileURLToPath(import.meta.url)), "bin", "byok-agent-message-mcp.js");
|
|
15460
|
+
return Object.freeze({ command: process.execPath, args: Object.freeze([script]) });
|
|
15461
|
+
}
|
|
15462
|
+
function resolveAgentMemoryMcpBin(externalHelperConfigured = false) {
|
|
15463
|
+
if (!isAgentMemorySecureFilesystemAvailable(externalHelperConfigured)) return void 0;
|
|
15464
|
+
const script = path3__default.join(path3__default.dirname(fileURLToPath(import.meta.url)), "bin", "byok-agent-memory-mcp.js");
|
|
15465
|
+
return Object.freeze({ command: process.execPath, args: Object.freeze([script]) });
|
|
15466
|
+
}
|
|
13917
15467
|
var AGENT_CONTENT_READ_SURFACES = ["workspace", "transcript", "artifact"];
|
|
13918
15468
|
var AGENT_CONTENT_READ_CAPABILITIES = Object.freeze({
|
|
13919
15469
|
workspace: AGENT_CONTENT_WORKSPACE_READ_CAPABILITY,
|
|
@@ -14145,11 +15695,11 @@ var RootPolicyError = class extends Error {
|
|
|
14145
15695
|
this.reason = reason;
|
|
14146
15696
|
}
|
|
14147
15697
|
};
|
|
14148
|
-
function
|
|
15698
|
+
function sameAgentRef4(left, right) {
|
|
14149
15699
|
return left.agentId === right.agentId && left.profileRevision === right.profileRevision;
|
|
14150
15700
|
}
|
|
14151
15701
|
function sameSessionIdentity(left, right) {
|
|
14152
|
-
return
|
|
15702
|
+
return sameAgentRef4(left.agentRef, right.agentRef) && left.sessionRef === right.sessionRef && left.runtimeId === right.runtimeId && left.cwd === right.cwd;
|
|
14153
15703
|
}
|
|
14154
15704
|
function validateRequest(request) {
|
|
14155
15705
|
if (!isRecord5(request)) throw new AgentContentReadRequestError("content read request must be an object");
|
|
@@ -14421,7 +15971,7 @@ var AgentContentReadPolicyEngine = class {
|
|
|
14421
15971
|
}
|
|
14422
15972
|
async checkSessionIdentity(request, resolver, requiredCwd) {
|
|
14423
15973
|
const session = request.session;
|
|
14424
|
-
if (session === void 0 || !
|
|
15974
|
+
if (session === void 0 || !sameAgentRef4(session.agentRef, request.agentRef) || requiredCwd !== void 0 && session.cwd !== requiredCwd) {
|
|
14425
15975
|
return "identity-mismatch";
|
|
14426
15976
|
}
|
|
14427
15977
|
let expected;
|
|
@@ -14542,6 +16092,7 @@ function computeCapabilities(adapters, agentHomeConfigured = false, strictAgentO
|
|
|
14542
16092
|
if (adapters.some((adapter) => adapter.descriptor.capabilities.steer)) flags.push("steer");
|
|
14543
16093
|
flags.push("blob-upload");
|
|
14544
16094
|
flags.push("approval-targeting");
|
|
16095
|
+
flags.push(TERMINAL_PROJECTION_SELECTION_CAPABILITY);
|
|
14545
16096
|
const selectionAdapters = adapters.filter(
|
|
14546
16097
|
(adapter) => ALL_RUNTIME_IDS.includes(adapter.descriptor.id)
|
|
14547
16098
|
);
|
|
@@ -14560,6 +16111,9 @@ function computeCapabilities(adapters, agentHomeConfigured = false, strictAgentO
|
|
|
14560
16111
|
AGENT_EGRESS_RELIABLE_ACK_CAPABILITY,
|
|
14561
16112
|
AGENT_EGRESS_FRESH_SESSION_CAPABILITY
|
|
14562
16113
|
);
|
|
16114
|
+
if (agentHomeConfigured && adapters.some((adapter) => adapter.descriptor.capabilities.mcpToolsets === true)) {
|
|
16115
|
+
flags.push(AGENT_MESSAGE_EGRESS_CAPABILITY);
|
|
16116
|
+
}
|
|
14563
16117
|
}
|
|
14564
16118
|
if (contentReadPolicies !== void 0) {
|
|
14565
16119
|
for (const surface of Object.keys(AGENT_CONTENT_READ_CAPABILITIES)) {
|
|
@@ -14670,6 +16224,23 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
14670
16224
|
"DaemonConfig.agentHome and DaemonConfig.gitWorkspace are mutually exclusive; Agent home is the only workspace authority for Agent offers"
|
|
14671
16225
|
);
|
|
14672
16226
|
}
|
|
16227
|
+
if (config.agentMemory !== void 0 && config.agentHome === void 0) {
|
|
16228
|
+
throw new Error("DaemonConfig.agentMemory requires DaemonConfig.agentHome for the exact Agent memory authority");
|
|
16229
|
+
}
|
|
16230
|
+
if (config.agentMemoryFilesystem !== void 0 && config.agentHome === void 0) {
|
|
16231
|
+
throw new Error("DaemonConfig.agentMemoryFilesystem requires DaemonConfig.agentHome for the exact Agent memory authority");
|
|
16232
|
+
}
|
|
16233
|
+
if (config.agentMemoryFilesystem !== void 0 && (!path3__default.isAbsolute(config.agentMemoryFilesystem.helperBin) || /[\u0000\r\n]/u.test(config.agentMemoryFilesystem.helperBin))) {
|
|
16234
|
+
throw new Error("DaemonConfig.agentMemoryFilesystem.helperBin must be an explicit absolute executable path");
|
|
16235
|
+
}
|
|
16236
|
+
const externalAgentMemoryFilesystem = config.agentMemoryFilesystem !== void 0;
|
|
16237
|
+
if (externalAgentMemoryFilesystem && !isAgentMemoryFilesystemHelperSupported()) {
|
|
16238
|
+
throw new Error("DaemonConfig.agentMemoryFilesystem is not admitted on this platform without its native race proof");
|
|
16239
|
+
}
|
|
16240
|
+
if (config.agentMemory !== void 0 && !isAgentMemorySecureFilesystemAvailable(externalAgentMemoryFilesystem)) {
|
|
16241
|
+
throw new Error("DaemonConfig.agentMemory requires a platform with safe descriptor-relative filesystem operations");
|
|
16242
|
+
}
|
|
16243
|
+
const agentMemoryMcpBin = config.agentHome === void 0 ? void 0 : resolveAgentMemoryMcpBin(externalAgentMemoryFilesystem);
|
|
14673
16244
|
const localAgentRelease = resolveLocalAgentReleaseIdentity(config.localAgentRelease);
|
|
14674
16245
|
const toolsetRegistry = new McpToolsetRegistry(config.mcpToolsets);
|
|
14675
16246
|
validatePiByokLauncherConfig(config.piByokLauncher);
|
|
@@ -15101,6 +16672,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15101
16672
|
approvalRegistry,
|
|
15102
16673
|
storeDir,
|
|
15103
16674
|
productId: config.productId,
|
|
16675
|
+
tenantId: record.tenantId,
|
|
15104
16676
|
// U2 terminal inference usage consumes the one U4a-resolved,
|
|
15105
16677
|
// process-immutable identity captured above. This is composition-only:
|
|
15106
16678
|
// TaskRunner receives no config, manifest, or second identity resolver.
|
|
@@ -15115,6 +16687,10 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15115
16687
|
// doc comment. Spread rather than assigned so an unconfigured daemon
|
|
15116
16688
|
// builds the exact `deps` object it did before this seam existed.
|
|
15117
16689
|
...config.resultDocument ? { resultDocument: config.resultDocument } : {},
|
|
16690
|
+
...agentMemoryMcpBin === void 0 ? {} : { agentMemoryMcpBin },
|
|
16691
|
+
...config.agentMemoryFilesystem === void 0 ? {} : { agentMemoryFilesystemHelperBin: path3__default.resolve(config.agentMemoryFilesystem.helperBin) },
|
|
16692
|
+
...config.agentHome !== void 0 && config.agentEgress !== void 0 ? { agentMessageMcpBin: resolveAgentMessageMcpBin() } : {},
|
|
16693
|
+
...config.agentMemory === void 0 ? {} : { agentMemoryHostedProjection: config.agentMemory },
|
|
15118
16694
|
// M4 Phase 3 hardening: bridges TaskRunner's stale-approval-race
|
|
15119
16695
|
// finding out to the SAME local observability seam every other
|
|
15120
16696
|
// daemon-local event already uses (see observer.ts's own module doc
|
|
@@ -15145,6 +16721,9 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15145
16721
|
...activePressureEngine ? { admissionGuard: () => activePressureEngine.admissionGuard() } : {}
|
|
15146
16722
|
};
|
|
15147
16723
|
runner = new TaskRunner(deps);
|
|
16724
|
+
if (config.agentHome !== void 0 && config.agentEgress !== void 0) {
|
|
16725
|
+
await runner.recoverAgentMessageOutboxes(path3__default.join(config.agentHome.hostStorageRoot, "agents"));
|
|
16726
|
+
}
|
|
15148
16727
|
const handleAgentHomeProjectionEnvelope = async (envelope) => {
|
|
15149
16728
|
if (envelope.type !== "agent.home.projection") return false;
|
|
15150
16729
|
if (agentHomeManager === void 0 || agentHomeProjectionCompletion === void 0) {
|
|
@@ -15327,6 +16906,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15327
16906
|
observer.handleInboundEnvelope(envelope);
|
|
15328
16907
|
if (envelope.type === "agent.home.projection") return handleAgentHomeProjectionEnvelope(envelope).then(() => void 0);
|
|
15329
16908
|
if (envelope.type === "agent.egress.ack") return handleAgentEgressEnvelope(envelope).then(() => void 0);
|
|
16909
|
+
if (envelope.type === "agent.message.disposition") return runner?.handleEnvelope(envelope) ?? Promise.resolve();
|
|
15330
16910
|
if (envelope.type === "agent.content.read") return handleAgentContentReadEnvelope(envelope).then(() => void 0);
|
|
15331
16911
|
return runner?.handleEnvelope(envelope) ?? Promise.resolve();
|
|
15332
16912
|
},
|
|
@@ -15334,6 +16914,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15334
16914
|
const wasSettled = connectionState === "open" || connectionState === "degraded";
|
|
15335
16915
|
connectionState = state;
|
|
15336
16916
|
observer.noteConnectionState(state);
|
|
16917
|
+
if (!wasSettled && (state === "open" || state === "degraded")) runner?.retryRecoveredAgentMessages();
|
|
15337
16918
|
if (!wasSettled && (state === "open" || state === "degraded")) runPresenceDiscovery();
|
|
15338
16919
|
},
|
|
15339
16920
|
backoff: overrides.backoff,
|
|
@@ -15352,6 +16933,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15352
16933
|
});
|
|
15353
16934
|
await connection.start();
|
|
15354
16935
|
await connection.waitForAck();
|
|
16936
|
+
runner.retryRecoveredAgentMessages();
|
|
15355
16937
|
for (const record2 of agentEgress.retryableReliableRecords(connection.getServerCapabilities())) {
|
|
15356
16938
|
dispatchReliableRecord(record2);
|
|
15357
16939
|
}
|
|
@@ -15699,6 +17281,24 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
|
|
|
15699
17281
|
if (!runner) throw new ControlError("not_found", "daemon is not started");
|
|
15700
17282
|
return runner.requestApproval(parsed.taskId, parsed.summary);
|
|
15701
17283
|
},
|
|
17284
|
+
"agent_messages.publish": (params) => {
|
|
17285
|
+
const parsed = parseAgentMessagePublishParams(params);
|
|
17286
|
+
if (!parsed) throw new ControlError("bad_request", "agent_messages.publish requires exactly {contextToken,contentType,body}");
|
|
17287
|
+
if (!runner) throw new ControlError("not_found", "daemon is not started");
|
|
17288
|
+
return runner.publishAgentMessage(parsed);
|
|
17289
|
+
},
|
|
17290
|
+
"agent_memory.recall": (params) => {
|
|
17291
|
+
const parsed = parseAgentMemoryRecallParams(params);
|
|
17292
|
+
if (!parsed) throw new ControlError("bad_request", "agent_memory.recall requires exactly {contextToken,path,ifRevision?}");
|
|
17293
|
+
if (!runner) throw new ControlError("not_found", "daemon is not started");
|
|
17294
|
+
return runner.recallAgentMemory(parsed);
|
|
17295
|
+
},
|
|
17296
|
+
"agent_memory.save": (params) => {
|
|
17297
|
+
const parsed = parseAgentMemorySaveParams(params);
|
|
17298
|
+
if (!parsed) throw new ControlError("bad_request", "agent_memory.save requires exactly {contextToken,op,path,expectedRevision,content?}");
|
|
17299
|
+
if (!runner) throw new ControlError("not_found", "daemon is not started");
|
|
17300
|
+
return runner.saveAgentMemory(parsed);
|
|
17301
|
+
},
|
|
15702
17302
|
/**
|
|
15703
17303
|
* Plan `device-assertion-broker`: mint one short-lived, audience-scoped
|
|
15704
17304
|
* device assertion for a sibling local process.
|
|
@@ -16589,8 +18189,8 @@ var TruthMemoryClient = class {
|
|
|
16589
18189
|
#requestId;
|
|
16590
18190
|
#allowedObjectDownloadOrigins;
|
|
16591
18191
|
async listManifest(query = {}) {
|
|
16592
|
-
const
|
|
16593
|
-
const response = await this.#proofFetch(
|
|
18192
|
+
const path38 = manifestPath(query);
|
|
18193
|
+
const response = await this.#proofFetch(path38, {
|
|
16594
18194
|
method: "GET",
|
|
16595
18195
|
operation: "truth.list",
|
|
16596
18196
|
resource: "records",
|
|
@@ -16697,9 +18297,9 @@ var TruthMemoryClient = class {
|
|
|
16697
18297
|
}
|
|
16698
18298
|
async #write(kind, recordKey, requestId, payload, expectedPrimary, expectedSnapshots) {
|
|
16699
18299
|
assertDistinctExpectedWrites([expectedPrimary, ...expectedSnapshots]);
|
|
16700
|
-
const
|
|
18300
|
+
const path38 = recordPath(kind, recordKey);
|
|
16701
18301
|
const body = new TextEncoder().encode(JSON.stringify(payload));
|
|
16702
|
-
const response = await this.#proofFetch(
|
|
18302
|
+
const response = await this.#proofFetch(path38, {
|
|
16703
18303
|
method: "PUT",
|
|
16704
18304
|
operation: "truth.write",
|
|
16705
18305
|
resource: `${kind}/${recordKey}`,
|
|
@@ -16725,8 +18325,8 @@ var TruthMemoryClient = class {
|
|
|
16725
18325
|
};
|
|
16726
18326
|
}
|
|
16727
18327
|
async #readVerified(listed) {
|
|
16728
|
-
const
|
|
16729
|
-
const response = await this.#proofFetch(
|
|
18328
|
+
const path38 = recordPath(listed.kind, listed.recordKey);
|
|
18329
|
+
const response = await this.#proofFetch(path38, {
|
|
16730
18330
|
method: "GET",
|
|
16731
18331
|
operation: "truth.read",
|
|
16732
18332
|
resource: `${listed.kind}/${listed.recordKey}`,
|
|
@@ -16787,16 +18387,16 @@ var TruthMemoryClient = class {
|
|
|
16787
18387
|
}
|
|
16788
18388
|
return { ...listed, bytes };
|
|
16789
18389
|
}
|
|
16790
|
-
async #proofFetch(
|
|
18390
|
+
async #proofFetch(path38, request) {
|
|
16791
18391
|
const proof = await this.options.signer.sign({
|
|
16792
18392
|
method: request.method,
|
|
16793
|
-
path:
|
|
18393
|
+
path: path38,
|
|
16794
18394
|
operation: request.operation,
|
|
16795
18395
|
resource: request.resource,
|
|
16796
18396
|
requestId: request.requestId,
|
|
16797
18397
|
body: request.body
|
|
16798
18398
|
});
|
|
16799
|
-
const response = await this.#fetch(new URL(
|
|
18399
|
+
const response = await this.#fetch(new URL(path38, this.#base), {
|
|
16800
18400
|
method: request.method,
|
|
16801
18401
|
headers: {
|
|
16802
18402
|
...request.headers,
|
|
@@ -16807,7 +18407,7 @@ var TruthMemoryClient = class {
|
|
|
16807
18407
|
if (!response.ok) {
|
|
16808
18408
|
throw new TruthMemoryClientError(
|
|
16809
18409
|
"truth_http_failed",
|
|
16810
|
-
`truth request ${request.method} ${
|
|
18410
|
+
`truth request ${request.method} ${path38} failed with HTTP ${response.status}`,
|
|
16811
18411
|
response.status
|
|
16812
18412
|
);
|
|
16813
18413
|
}
|
|
@@ -17099,7 +18699,7 @@ ${args.map((a) => ` ${plistString(a)}`).join("\n")}
|
|
|
17099
18699
|
}
|
|
17100
18700
|
function createLaunchdLifecycle(def, deps = {}) {
|
|
17101
18701
|
const run = deps.run ?? defaultRunner;
|
|
17102
|
-
const
|
|
18702
|
+
const fs29 = deps.fs ?? promises;
|
|
17103
18703
|
const homedir = deps.homedir ?? (() => os4__default.homedir());
|
|
17104
18704
|
const getuid = deps.getuid ?? (() => {
|
|
17105
18705
|
if (typeof process.getuid !== "function") {
|
|
@@ -17113,7 +18713,7 @@ function createLaunchdLifecycle(def, deps = {}) {
|
|
|
17113
18713
|
const serviceTarget = () => `${domainTarget()}/${label}`;
|
|
17114
18714
|
async function fileExists(p) {
|
|
17115
18715
|
try {
|
|
17116
|
-
await
|
|
18716
|
+
await fs29.stat(p);
|
|
17117
18717
|
return true;
|
|
17118
18718
|
} catch {
|
|
17119
18719
|
return false;
|
|
@@ -17121,9 +18721,9 @@ function createLaunchdLifecycle(def, deps = {}) {
|
|
|
17121
18721
|
}
|
|
17122
18722
|
async function writePlist(program) {
|
|
17123
18723
|
const xml = generateLaunchdPlist({ label, program, logDir: def.logDir });
|
|
17124
|
-
await
|
|
17125
|
-
await
|
|
17126
|
-
await
|
|
18724
|
+
await fs29.mkdir(path3__default.dirname(plistPath()), { recursive: true });
|
|
18725
|
+
await fs29.mkdir(def.logDir, { recursive: true });
|
|
18726
|
+
await fs29.writeFile(plistPath(), xml, "utf8");
|
|
17127
18727
|
}
|
|
17128
18728
|
async function install(opts = {}) {
|
|
17129
18729
|
await writePlist(opts.program ?? def.program);
|
|
@@ -17134,7 +18734,7 @@ function createLaunchdLifecycle(def, deps = {}) {
|
|
|
17134
18734
|
}
|
|
17135
18735
|
async function uninstall() {
|
|
17136
18736
|
await runIdempotent(run, "launchctl", ["bootout", serviceTarget()], "launchctl bootout", LAUNCHD_NOT_LOADED);
|
|
17137
|
-
await
|
|
18737
|
+
await fs29.rm(plistPath(), { force: true });
|
|
17138
18738
|
}
|
|
17139
18739
|
async function start() {
|
|
17140
18740
|
if (!await fileExists(plistPath())) {
|
|
@@ -17218,14 +18818,14 @@ WantedBy=default.target
|
|
|
17218
18818
|
}
|
|
17219
18819
|
function createSystemdLifecycle(def, deps = {}) {
|
|
17220
18820
|
const run = deps.run ?? defaultRunner;
|
|
17221
|
-
const
|
|
18821
|
+
const fs29 = deps.fs ?? promises;
|
|
17222
18822
|
const homedir = deps.homedir ?? (() => os4__default.homedir());
|
|
17223
18823
|
const name = sanitizeServiceName(def.name);
|
|
17224
18824
|
const unitName = `${name}.service`;
|
|
17225
18825
|
const unitPath = () => path3__default.join(homedir(), ".config", "systemd", "user", unitName);
|
|
17226
18826
|
async function fileExists(p) {
|
|
17227
18827
|
try {
|
|
17228
|
-
await
|
|
18828
|
+
await fs29.stat(p);
|
|
17229
18829
|
return true;
|
|
17230
18830
|
} catch {
|
|
17231
18831
|
return false;
|
|
@@ -17233,9 +18833,9 @@ function createSystemdLifecycle(def, deps = {}) {
|
|
|
17233
18833
|
}
|
|
17234
18834
|
async function writeUnit(program) {
|
|
17235
18835
|
const unit = generateSystemdUnit({ name, displayName: def.displayName ?? def.name, program, logDir: def.logDir });
|
|
17236
|
-
await
|
|
17237
|
-
await
|
|
17238
|
-
await
|
|
18836
|
+
await fs29.mkdir(path3__default.dirname(unitPath()), { recursive: true });
|
|
18837
|
+
await fs29.mkdir(def.logDir, { recursive: true });
|
|
18838
|
+
await fs29.writeFile(unitPath(), unit, "utf8");
|
|
17239
18839
|
}
|
|
17240
18840
|
async function install(opts = {}) {
|
|
17241
18841
|
await writeUnit(opts.program ?? def.program);
|
|
@@ -17244,7 +18844,7 @@ function createSystemdLifecycle(def, deps = {}) {
|
|
|
17244
18844
|
}
|
|
17245
18845
|
async function uninstall() {
|
|
17246
18846
|
await runIdempotent(run, "systemctl", ["--user", "disable", "--now", unitName], "systemctl disable --now", SYSTEMD_NOT_LOADED);
|
|
17247
|
-
await
|
|
18847
|
+
await fs29.rm(unitPath(), { force: true });
|
|
17248
18848
|
await run("systemctl", ["--user", "daemon-reload"]);
|
|
17249
18849
|
}
|
|
17250
18850
|
async function start() {
|
|
@@ -17307,7 +18907,7 @@ ${argXml}${cwdXml}
|
|
|
17307
18907
|
}
|
|
17308
18908
|
function createWinswLifecycle(def, deps = {}) {
|
|
17309
18909
|
const run = deps.run ?? defaultRunner;
|
|
17310
|
-
const
|
|
18910
|
+
const fs29 = deps.fs ?? promises;
|
|
17311
18911
|
const windows = def.windows;
|
|
17312
18912
|
if (!windows) {
|
|
17313
18913
|
throw new Error("WinSW service lifecycle requires `ServiceDefinition.windows.winswBin` (the product-bundled WinSW executable path)");
|
|
@@ -17319,7 +18919,7 @@ function createWinswLifecycle(def, deps = {}) {
|
|
|
17319
18919
|
const xmlPath = path3__default.join(installDir, `${id}.xml`);
|
|
17320
18920
|
async function fileExists(p) {
|
|
17321
18921
|
try {
|
|
17322
|
-
await
|
|
18922
|
+
await fs29.stat(p);
|
|
17323
18923
|
return true;
|
|
17324
18924
|
} catch {
|
|
17325
18925
|
return false;
|
|
@@ -17327,10 +18927,10 @@ function createWinswLifecycle(def, deps = {}) {
|
|
|
17327
18927
|
}
|
|
17328
18928
|
async function writeFiles(program) {
|
|
17329
18929
|
const xml = generateWinswXml({ id, displayName: def.displayName ?? def.name, program, logDir: def.logDir });
|
|
17330
|
-
await
|
|
17331
|
-
await
|
|
17332
|
-
await
|
|
17333
|
-
await
|
|
18930
|
+
await fs29.mkdir(installDir, { recursive: true });
|
|
18931
|
+
await fs29.mkdir(def.logDir, { recursive: true });
|
|
18932
|
+
await fs29.copyFile(winswBin, exePath);
|
|
18933
|
+
await fs29.writeFile(xmlPath, xml, "utf8");
|
|
17334
18934
|
}
|
|
17335
18935
|
async function install(opts = {}) {
|
|
17336
18936
|
await writeFiles(opts.program ?? def.program);
|
|
@@ -17340,8 +18940,8 @@ function createWinswLifecycle(def, deps = {}) {
|
|
|
17340
18940
|
async function uninstall() {
|
|
17341
18941
|
await runIdempotent(run, exePath, ["stop"], "winsw stop", WINSW_NOT_INSTALLED);
|
|
17342
18942
|
await runIdempotent(run, exePath, ["uninstall"], "winsw uninstall", WINSW_NOT_INSTALLED);
|
|
17343
|
-
await
|
|
17344
|
-
await
|
|
18943
|
+
await fs29.rm(exePath, { force: true });
|
|
18944
|
+
await fs29.rm(xmlPath, { force: true });
|
|
17345
18945
|
}
|
|
17346
18946
|
async function start() {
|
|
17347
18947
|
if (!await fileExists(xmlPath)) {
|
|
@@ -17384,6 +18984,6 @@ function createServiceLifecycle(def, opts = {}) {
|
|
|
17384
18984
|
}
|
|
17385
18985
|
}
|
|
17386
18986
|
|
|
17387
|
-
export { AGENT_CONTENT_READ_CAPABILITIES, AGENT_CONTENT_READ_CAPABILITY_ARTIFACT, AGENT_CONTENT_READ_CAPABILITY_TRANSCRIPT, AGENT_CONTENT_READ_CAPABILITY_WORKSPACE, AGENT_HOME_PROJECTION_STATE_FILE, AgentHomeBusyError, AgentHomeCollisionError, AgentHomeError, AgentHomeLayout, AgentHomeLeaseCorruptError, AgentHomeLeaseManager, AgentHomeManager, AgentHomeResolutionError, AgentRefValidationError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, AgentSessionHandoffStore, AgentSessionHandoffStoreError, BlobClient, ClaudeAdapter, CodexAdapter, DEFAULT_ACK_CRITICAL_RESERVE_BYTES, DEFAULT_CLEANUP_BATCH_LIMIT, DEFAULT_HARD_BUDGET_RATIO, DEFAULT_INCREMENTAL_VACUUM_PAGES, DEFAULT_LOG_ROTATION, DEFAULT_NORMAL_COMPACTION_INTERVAL_MS, DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS, DEFAULT_RETENTION_MS, DEFAULT_SOFT_BUDGET_RATIO, DaemonObserver, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStateRelocationBusyError, LocalStateRelocationError, LocalStateRelocationIntegrityError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, McpToolsetDefinitionRevisionConflictError, McpToolsetRevisionConflictError, PI_PACKAGE_NAME, PiAdapter, PolicyUnsupportedError, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, RuntimeDisposalFailure, RuntimeExecutionFailure, SKILL_PACKS_CAPABILITY, SKILL_PACKS_DIRNAME, SKILL_PACK_AUDIT_FILENAME, SKILL_PACK_INSTALL_ERROR_CODES, SKILL_PACK_LOCK_FILENAME, SKILL_PACK_LOCK_SCHEMA, SKILL_PACK_RESPONSE_MAX_BYTES, SecureDirHardeningError, SkillPackInstallError, SqliteLocalTaskJournal, SteerUnsupportedError, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createAgentHomeProjection, createAgentHomeProjectionConsumer, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, readDeviceEnrollmentStatus, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
|
|
18987
|
+
export { AGENT_CONTENT_READ_CAPABILITIES, AGENT_CONTENT_READ_CAPABILITY_ARTIFACT, AGENT_CONTENT_READ_CAPABILITY_TRANSCRIPT, AGENT_CONTENT_READ_CAPABILITY_WORKSPACE, AGENT_HOME_PROJECTION_STATE_FILE, AGENT_MEMORY_AUDIT_FILENAME, AGENT_MEMORY_OUTBOX_FILENAME, AgentHomeBusyError, AgentHomeCollisionError, AgentHomeError, AgentHomeLayout, AgentHomeLeaseCorruptError, AgentHomeLeaseManager, AgentHomeManager, AgentHomeResolutionError, AgentMemoryError, AgentMemoryRevisionConflictError, AgentRefValidationError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, AgentSessionHandoffStore, AgentSessionHandoffStoreError, BlobClient, ClaudeAdapter, CodexAdapter, DEFAULT_ACK_CRITICAL_RESERVE_BYTES, DEFAULT_CLEANUP_BATCH_LIMIT, DEFAULT_HARD_BUDGET_RATIO, DEFAULT_INCREMENTAL_VACUUM_PAGES, DEFAULT_LOG_ROTATION, DEFAULT_NORMAL_COMPACTION_INTERVAL_MS, DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS, DEFAULT_RETENTION_MS, DEFAULT_SOFT_BUDGET_RATIO, DaemonObserver, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStateRelocationBusyError, LocalStateRelocationError, LocalStateRelocationIntegrityError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, McpToolsetDefinitionRevisionConflictError, McpToolsetRevisionConflictError, PI_PACKAGE_NAME, PiAdapter, PolicyUnsupportedError, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, RuntimeDisposalFailure, RuntimeExecutionFailure, SKILL_PACKS_CAPABILITY, SKILL_PACKS_DIRNAME, SKILL_PACK_AUDIT_FILENAME, SKILL_PACK_INSTALL_ERROR_CODES, SKILL_PACK_LOCK_FILENAME, SKILL_PACK_LOCK_SCHEMA, SKILL_PACK_RESPONSE_MAX_BYTES, SecureDirHardeningError, SkillPackInstallError, SqliteLocalTaskJournal, SteerUnsupportedError, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createAgentHomeProjection, createAgentHomeProjectionConsumer, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isAgentMemorySecureFilesystemAvailable, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, readDeviceEnrollmentStatus, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
|
|
17388
18988
|
//# sourceMappingURL=index.js.map
|
|
17389
18989
|
//# sourceMappingURL=index.js.map
|