@rivet-dev/agentos-core 0.0.0-codex-darwin-ci-publish.61a7af3 → 0.0.0-nathan-binding-workspace.13eb4d4
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 +15 -15
- package/dist/{agent-os.d.ts → agentos.d.ts} +37 -86
- package/dist/{agent-os.js → agentos.js} +146 -188
- package/dist/agents.d.ts +1 -1
- package/dist/agents.js +2 -2
- package/dist/{host-tools-zod.d.ts → bindings-zod.d.ts} +1 -1
- package/dist/{host-tools-zod.js → bindings-zod.js} +16 -16
- package/dist/bindings.d.ts +45 -0
- package/dist/bindings.js +26 -0
- package/dist/cron/cron-manager.d.ts +3 -3
- package/dist/cron/cron-manager.js +2 -5
- package/dist/cron/types.d.ts +1 -1
- package/dist/host-dir-mount.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/json-rpc.d.ts +1 -17
- package/dist/json-rpc.js +0 -8
- package/dist/layers.d.ts +1 -1
- package/dist/layers.js +3 -3
- package/dist/packages.d.ts +1 -1
- package/dist/packages.js +1 -1
- package/dist/runtime-compat.d.ts +6 -2
- package/dist/runtime-compat.js +6 -5
- package/dist/runtime.d.ts +2 -2
- package/dist/sidecar/{agent-os-protocol.d.ts → agentos-protocol.d.ts} +0 -36
- package/dist/sidecar/{agent-os-protocol.js → agentos-protocol.js} +2 -42
- package/dist/sidecar/native-process-client.d.ts +3 -2
- package/dist/sidecar/native-process-client.js +6 -1
- package/dist/sidecar/permissions.js +3 -3
- package/dist/sidecar/process.d.ts +4 -4
- package/dist/sidecar/process.js +3 -3
- package/dist/sidecar/rpc-client.d.ts +41 -40
- package/dist/sidecar/rpc-client.js +53 -8
- package/dist/test/runtime.d.ts +1 -1
- package/dist/test/runtime.js +1 -1
- package/dist/test/sandbox-agent.js +1 -1
- package/dist/types.d.ts +3 -3
- package/package.json +25 -25
- package/dist/host-tools.d.ts +0 -45
- package/dist/host-tools.js +0 -26
|
@@ -4,22 +4,14 @@ import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, w
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, join, posix as posixPath, resolve as resolveHostPath, } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import {
|
|
8
|
-
import { zodToJsonSchema } from "./
|
|
7
|
+
import { validateBindings } from "./bindings.js";
|
|
8
|
+
import { zodToJsonSchema } from "./bindings-zod.js";
|
|
9
9
|
import { resolvePublishedSidecarBinary } from "./sidecar/binary.js";
|
|
10
10
|
import { findCargoBinary, resolveCargoBinary } from "./sidecar/cargo.js";
|
|
11
11
|
export { isAcpTimeoutErrorData } from "./json-rpc.js";
|
|
12
12
|
const ACP_PROTOCOL_VERSION = 1;
|
|
13
|
-
const ACP_EXTENSION_NAMESPACE = "dev.rivet.
|
|
13
|
+
const ACP_EXTENSION_NAMESPACE = "dev.rivet.agentos.acp";
|
|
14
14
|
const SHELL_DISPOSE_TIMEOUT_MS = 5_000;
|
|
15
|
-
/**
|
|
16
|
-
* Reserved `env` key on `AcpResumeSessionRequest` carrying the resolved adapter
|
|
17
|
-
* bin entrypoint. The resume wire request omits a dedicated `adapterEntrypoint`
|
|
18
|
-
* field; the sidecar reads the entrypoint from this key and strips it before
|
|
19
|
-
* launching the adapter. Must stay in sync with the sidecar constant of the same
|
|
20
|
-
* name in `crates/agentos-sidecar/src/acp_extension.rs`.
|
|
21
|
-
*/
|
|
22
|
-
const RESUME_ADAPTER_ENTRYPOINT_ENV = "AGENT_OS_RESUME_ADAPTER_ENTRYPOINT";
|
|
23
15
|
function defaultAcpClientCapabilities() {
|
|
24
16
|
return {
|
|
25
17
|
fs: {
|
|
@@ -49,10 +41,15 @@ import { createHostDirBackend } from "./host-dir-mount.js";
|
|
|
49
41
|
import { serializeMountConfigForSidecar, } from "./js-bridge.js";
|
|
50
42
|
import { createSnapshotExport, } from "./layers.js";
|
|
51
43
|
import { processSoftware, resolvePackageDir, } from "./packages.js";
|
|
44
|
+
// `@agentos-software/common` (coreutils, sed, grep, gawk, findutils, diffutils,
|
|
45
|
+
// tar, gzip) is part of the default VM software set, so callers never have to add
|
|
46
|
+
// it explicitly. It is prepended to any user-supplied `software` (deduped by
|
|
47
|
+
// reference, so passing it explicitly is still harmless).
|
|
48
|
+
import defaultCommonSoftware from "@agentos-software/common";
|
|
52
49
|
import { allowAll } from "./runtime-compat.js";
|
|
53
|
-
import { AcpRuntimeKind, decodeAcpCallback, decodeAcpEvent, decodeAcpResponse, encodeAcpCallbackResponse, encodeAcpRequest, } from "./sidecar/
|
|
50
|
+
import { AcpRuntimeKind, decodeAcpCallback, decodeAcpEvent, decodeAcpResponse, encodeAcpCallbackResponse, encodeAcpRequest, } from "./sidecar/agentos-protocol.js";
|
|
54
51
|
import { serializePermissionsForSidecar } from "./sidecar/permissions.js";
|
|
55
|
-
import {
|
|
52
|
+
import { createAgentOSSidecarClient, NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarKernelProxy, NativeSidecarProcessClient, serializeRootFilesystemForSidecar, } from "./sidecar/rpc-client.js";
|
|
56
53
|
const LEGACY_PERMISSION_METHOD = "request/permission";
|
|
57
54
|
const ACP_PERMISSION_METHOD = "session/request_permission";
|
|
58
55
|
class AcpDispatchError extends Error {
|
|
@@ -367,6 +364,7 @@ const KERNEL_POSIX_BOOTSTRAP_DIRS = [
|
|
|
367
364
|
"/media",
|
|
368
365
|
"/home",
|
|
369
366
|
"/home/user",
|
|
367
|
+
"/workspace",
|
|
370
368
|
"/usr",
|
|
371
369
|
"/usr/bin",
|
|
372
370
|
"/usr/games",
|
|
@@ -488,7 +486,7 @@ function prepareCommandDirs(commandPackages) {
|
|
|
488
486
|
if (aliasEntries.length === 0) {
|
|
489
487
|
continue;
|
|
490
488
|
}
|
|
491
|
-
const aliasDir = mkdtempSync(join(tmpdir(), "
|
|
489
|
+
const aliasDir = mkdtempSync(join(tmpdir(), "agentos-command-aliases-"));
|
|
492
490
|
for (const [aliasName, sourcePath] of aliasEntries) {
|
|
493
491
|
writeFileSync(join(aliasDir, aliasName), readFileSync(sourcePath));
|
|
494
492
|
}
|
|
@@ -834,19 +832,19 @@ function collectSidecarMountPlan(options) {
|
|
|
834
832
|
hostPathMappings.sort((left, right) => right.vmPath.length - left.vmPath.length);
|
|
835
833
|
return { sidecarMounts, hostMounts, hostPathMappings };
|
|
836
834
|
}
|
|
837
|
-
function materializeToolShimDir(
|
|
838
|
-
const shimDir = mkdtempSync(join(tmpdir(), "
|
|
835
|
+
function materializeToolShimDir(bindingGroups) {
|
|
836
|
+
const shimDir = mkdtempSync(join(tmpdir(), "agentos-bindings-shims-"));
|
|
839
837
|
writeFileSync(join(shimDir, "agentos"), KERNEL_COMMAND_STUB, { mode: 0o755 });
|
|
840
|
-
for (const
|
|
841
|
-
writeFileSync(join(shimDir, `agentos-${
|
|
838
|
+
for (const group of bindingGroups) {
|
|
839
|
+
writeFileSync(join(shimDir, `agentos-${group.name}`), KERNEL_COMMAND_STUB, { mode: 0o755 });
|
|
842
840
|
}
|
|
843
841
|
return shimDir;
|
|
844
842
|
}
|
|
845
|
-
function collectToolkitBootstrapCommands(
|
|
846
|
-
if (
|
|
843
|
+
function collectToolkitBootstrapCommands(bindingGroups) {
|
|
844
|
+
if (bindingGroups.length === 0) {
|
|
847
845
|
return [];
|
|
848
846
|
}
|
|
849
|
-
return ["agentos", ...
|
|
847
|
+
return ["agentos", ...bindingGroups.map((group) => `agentos-${group.name}`)];
|
|
850
848
|
}
|
|
851
849
|
function validationMessage(error) {
|
|
852
850
|
if (typeof error === "object" &&
|
|
@@ -888,42 +886,42 @@ function combineInstructions(additionalInstructions, toolReference) {
|
|
|
888
886
|
}
|
|
889
887
|
return parts.join("\n\n");
|
|
890
888
|
}
|
|
891
|
-
function buildHostToolReference(
|
|
892
|
-
if (
|
|
889
|
+
function buildHostToolReference(bindingGroups) {
|
|
890
|
+
if (bindingGroups.length === 0) {
|
|
893
891
|
return "";
|
|
894
892
|
}
|
|
895
893
|
const lines = [
|
|
896
|
-
"## Available
|
|
894
|
+
"## Available Bindings",
|
|
897
895
|
"",
|
|
898
|
-
"Run `agentos list-tools` to see all available
|
|
896
|
+
"Run `agentos list-tools` to see all available bindings.",
|
|
899
897
|
"",
|
|
900
898
|
];
|
|
901
|
-
for (const
|
|
902
|
-
lines.push(`### ${
|
|
899
|
+
for (const group of bindingGroups) {
|
|
900
|
+
lines.push(`### ${group.name}`);
|
|
903
901
|
lines.push("");
|
|
904
|
-
lines.push(
|
|
902
|
+
lines.push(group.description);
|
|
905
903
|
lines.push("");
|
|
906
|
-
for (const [
|
|
904
|
+
for (const [bindingName, tool] of Object.entries(group.bindings)) {
|
|
907
905
|
const sidecarTool = toolToSidecarDefinition(tool);
|
|
908
906
|
const signature = buildToolFlagSignature(sidecarTool.inputSchema);
|
|
909
907
|
const suffix = signature.length > 0 ? ` ${signature}` : "";
|
|
910
|
-
lines.push(`- \`agentos-${
|
|
908
|
+
lines.push(`- \`agentos-${group.name} ${bindingName}${suffix}\` — ${tool.description}`);
|
|
911
909
|
}
|
|
912
910
|
lines.push("");
|
|
913
|
-
const toolsWithExamples = Object.entries(
|
|
911
|
+
const toolsWithExamples = Object.entries(group.bindings).filter(([, tool]) => tool.examples && tool.examples.length > 0);
|
|
914
912
|
if (toolsWithExamples.length > 0) {
|
|
915
913
|
lines.push("**Examples:**");
|
|
916
914
|
lines.push("");
|
|
917
|
-
for (const [
|
|
915
|
+
for (const [bindingName, tool] of toolsWithExamples) {
|
|
918
916
|
for (const example of tool.examples ?? []) {
|
|
919
917
|
const args = inputToToolFlags(example.input);
|
|
920
918
|
const suffix = args.length > 0 ? ` ${args}` : "";
|
|
921
|
-
lines.push(`- ${example.description}: \`agentos-${
|
|
919
|
+
lines.push(`- ${example.description}: \`agentos-${group.name} ${bindingName}${suffix}\``);
|
|
922
920
|
}
|
|
923
921
|
}
|
|
924
922
|
lines.push("");
|
|
925
923
|
}
|
|
926
|
-
lines.push(`Run \`agentos-${
|
|
924
|
+
lines.push(`Run \`agentos-${group.name} <binding> --help\` for details.`);
|
|
927
925
|
lines.push("");
|
|
928
926
|
}
|
|
929
927
|
return lines.join("\n");
|
|
@@ -1064,11 +1062,11 @@ async function handleHostCallback(request, context) {
|
|
|
1064
1062
|
};
|
|
1065
1063
|
}
|
|
1066
1064
|
}
|
|
1067
|
-
function buildToolMap(
|
|
1065
|
+
function buildToolMap(bindingGroups) {
|
|
1068
1066
|
const toolMap = new Map();
|
|
1069
|
-
for (const
|
|
1070
|
-
for (const [
|
|
1071
|
-
toolMap.set(`${
|
|
1067
|
+
for (const group of bindingGroups) {
|
|
1068
|
+
for (const [bindingName, tool] of Object.entries(group.bindings)) {
|
|
1069
|
+
toolMap.set(`${group.name}:${bindingName}`, tool);
|
|
1072
1070
|
}
|
|
1073
1071
|
}
|
|
1074
1072
|
return toolMap;
|
|
@@ -1090,33 +1088,33 @@ function parseHostCommandCallbackInput(input) {
|
|
|
1090
1088
|
};
|
|
1091
1089
|
}
|
|
1092
1090
|
async function handleHostCommandCallback(command, context) {
|
|
1093
|
-
const directToolKit = context.
|
|
1091
|
+
const directToolKit = context.bindings.find((group) => `agentos-${group.name}` === command.command);
|
|
1094
1092
|
if (command.command === "agentos") {
|
|
1095
|
-
return
|
|
1093
|
+
return handleAgentOSRegistryCommand(command, context);
|
|
1096
1094
|
}
|
|
1097
1095
|
if (directToolKit) {
|
|
1098
|
-
return
|
|
1096
|
+
return handleAgentOSToolkitCommand(command, context, directToolKit);
|
|
1099
1097
|
}
|
|
1100
1098
|
throw new Error(`Unknown host callback command "${command.command}"`);
|
|
1101
1099
|
}
|
|
1102
|
-
async function
|
|
1100
|
+
async function handleAgentOSRegistryCommand(command, context) {
|
|
1103
1101
|
const [subcommand, toolkitName, toolName, ...toolArgs] = command.args;
|
|
1104
1102
|
if (!subcommand || isHelpFlag(subcommand)) {
|
|
1105
1103
|
return {
|
|
1106
|
-
usage: "agentos <command>: list-tools [
|
|
1104
|
+
usage: "agentos <command>: list-tools [bindings], <bindings> --help, or <bindings> <binding> ...",
|
|
1107
1105
|
};
|
|
1108
1106
|
}
|
|
1109
1107
|
if (subcommand === "list-tools") {
|
|
1110
1108
|
return toolkitName
|
|
1111
|
-
? describeToolkitPayload(context.
|
|
1112
|
-
: listToolkitsPayload(context.
|
|
1109
|
+
? describeToolkitPayload(context.bindings, toolkitName)
|
|
1110
|
+
: listToolkitsPayload(context.bindings);
|
|
1113
1111
|
}
|
|
1114
|
-
const toolKit = context.
|
|
1112
|
+
const toolKit = context.bindings.find((kit) => kit.name === subcommand);
|
|
1115
1113
|
if (!toolKit) {
|
|
1116
|
-
throw new Error(`No
|
|
1114
|
+
throw new Error(`No bindings "${subcommand}". Available: ${toolkitNames(context.bindings)}`);
|
|
1117
1115
|
}
|
|
1118
1116
|
if (!toolkitName || isHelpFlag(toolkitName)) {
|
|
1119
|
-
return describeToolkitPayload(context.
|
|
1117
|
+
return describeToolkitPayload(context.bindings, subcommand);
|
|
1120
1118
|
}
|
|
1121
1119
|
if (toolName && isHelpFlag(toolName)) {
|
|
1122
1120
|
return describeToolPayload(toolKit, toolkitName);
|
|
@@ -1129,10 +1127,10 @@ async function handleAgentOsRegistryCommand(command, context) {
|
|
|
1129
1127
|
context,
|
|
1130
1128
|
});
|
|
1131
1129
|
}
|
|
1132
|
-
async function
|
|
1130
|
+
async function handleAgentOSToolkitCommand(command, context, toolKit) {
|
|
1133
1131
|
const [toolName, helpOrFirstArg, ...rest] = command.args;
|
|
1134
1132
|
if (!toolName || isHelpFlag(toolName)) {
|
|
1135
|
-
return describeToolkitPayload(context.
|
|
1133
|
+
return describeToolkitPayload(context.bindings, toolKit.name);
|
|
1136
1134
|
}
|
|
1137
1135
|
if (helpOrFirstArg && isHelpFlag(helpOrFirstArg)) {
|
|
1138
1136
|
return describeToolPayload(toolKit, toolName);
|
|
@@ -1146,14 +1144,14 @@ async function handleAgentOsToolkitCommand(command, context, toolKit) {
|
|
|
1146
1144
|
});
|
|
1147
1145
|
}
|
|
1148
1146
|
async function invokeHostTool({ toolKit, toolName, args, cwd, context, }) {
|
|
1149
|
-
const tool = toolKit.
|
|
1147
|
+
const tool = toolKit.bindings[toolName];
|
|
1150
1148
|
if (!tool) {
|
|
1151
|
-
throw new Error(`No
|
|
1149
|
+
throw new Error(`No binding "${toolName}" in bindings "${toolKit.name}". Available: ${toolNames(toolKit)}`);
|
|
1152
1150
|
}
|
|
1153
1151
|
const callbackKey = `${toolKit.name}:${toolName}`;
|
|
1154
1152
|
const permissionMode = toolPermissionMode(context.permissions, callbackKey);
|
|
1155
1153
|
if (permissionMode !== "allow") {
|
|
1156
|
-
throw new Error(`EACCES: blocked by
|
|
1154
|
+
throw new Error(`EACCES: blocked by binding.invoke policy for ${callbackKey}`);
|
|
1157
1155
|
}
|
|
1158
1156
|
const input = await parseHostToolInput(tool, args, cwd, context.readFile);
|
|
1159
1157
|
return executeHostTool(tool, callbackKey, input);
|
|
@@ -1266,25 +1264,25 @@ function parseToolArgv(schema, argv) {
|
|
|
1266
1264
|
}
|
|
1267
1265
|
return input;
|
|
1268
1266
|
}
|
|
1269
|
-
function listToolkitsPayload(
|
|
1267
|
+
function listToolkitsPayload(bindingGroups) {
|
|
1270
1268
|
return {
|
|
1271
|
-
|
|
1272
|
-
name:
|
|
1273
|
-
description:
|
|
1274
|
-
|
|
1269
|
+
bindings: bindingGroups.map((group) => ({
|
|
1270
|
+
name: group.name,
|
|
1271
|
+
description: group.description,
|
|
1272
|
+
bindings: Object.keys(group.bindings),
|
|
1275
1273
|
})),
|
|
1276
1274
|
};
|
|
1277
1275
|
}
|
|
1278
|
-
function describeToolkitPayload(
|
|
1279
|
-
const toolKit =
|
|
1276
|
+
function describeToolkitPayload(bindingGroups, toolkitName) {
|
|
1277
|
+
const toolKit = bindingGroups.find((kit) => kit.name === toolkitName);
|
|
1280
1278
|
if (!toolKit) {
|
|
1281
|
-
throw new Error(`No
|
|
1279
|
+
throw new Error(`No bindings "${toolkitName}". Available: ${toolkitNames(bindingGroups)}`);
|
|
1282
1280
|
}
|
|
1283
1281
|
return {
|
|
1284
1282
|
name: toolKit.name,
|
|
1285
1283
|
description: toolKit.description,
|
|
1286
|
-
|
|
1287
|
-
|
|
1284
|
+
bindings: Object.fromEntries(Object.entries(toolKit.bindings).map(([bindingName, tool]) => [
|
|
1285
|
+
bindingName,
|
|
1288
1286
|
{
|
|
1289
1287
|
description: tool.description,
|
|
1290
1288
|
flags: describeToolFlags(toolToSidecarDefinition(tool).inputSchema),
|
|
@@ -1293,13 +1291,13 @@ function describeToolkitPayload(toolKits, toolkitName) {
|
|
|
1293
1291
|
};
|
|
1294
1292
|
}
|
|
1295
1293
|
function describeToolPayload(toolKit, toolName) {
|
|
1296
|
-
const tool = toolKit.
|
|
1294
|
+
const tool = toolKit.bindings[toolName];
|
|
1297
1295
|
if (!tool) {
|
|
1298
|
-
throw new Error(`No
|
|
1296
|
+
throw new Error(`No binding "${toolName}" in bindings "${toolKit.name}". Available: ${toolNames(toolKit)}`);
|
|
1299
1297
|
}
|
|
1300
1298
|
return {
|
|
1301
|
-
|
|
1302
|
-
|
|
1299
|
+
bindings: toolKit.name,
|
|
1300
|
+
binding: toolName,
|
|
1303
1301
|
description: tool.description,
|
|
1304
1302
|
flags: describeToolFlags(toolToSidecarDefinition(tool).inputSchema),
|
|
1305
1303
|
examples: tool.examples?.map((example) => ({
|
|
@@ -1309,7 +1307,7 @@ function describeToolPayload(toolKit, toolName) {
|
|
|
1309
1307
|
};
|
|
1310
1308
|
}
|
|
1311
1309
|
function toolPermissionMode(permissions, callbackKey) {
|
|
1312
|
-
const scope = permissions.
|
|
1310
|
+
const scope = permissions.binding;
|
|
1313
1311
|
if (!scope) {
|
|
1314
1312
|
return "deny";
|
|
1315
1313
|
}
|
|
@@ -1343,11 +1341,11 @@ function permissionPatternMatches(pattern, value) {
|
|
|
1343
1341
|
.join("");
|
|
1344
1342
|
return new RegExp(`^${source}$`).test(value);
|
|
1345
1343
|
}
|
|
1346
|
-
function toolkitNames(
|
|
1347
|
-
return
|
|
1344
|
+
function toolkitNames(bindingGroups) {
|
|
1345
|
+
return bindingGroups.map((group) => group.name).join(", ");
|
|
1348
1346
|
}
|
|
1349
1347
|
function toolNames(toolKit) {
|
|
1350
|
-
return Object.keys(toolKit.
|
|
1348
|
+
return Object.keys(toolKit.bindings).join(", ");
|
|
1351
1349
|
}
|
|
1352
1350
|
function isHelpFlag(value) {
|
|
1353
1351
|
return value === "--help" || value === "-h";
|
|
@@ -1356,25 +1354,25 @@ function jsonSchemaType(schema) {
|
|
|
1356
1354
|
const schemaObject = asRecord(schema);
|
|
1357
1355
|
return typeof schemaObject.type === "string" ? schemaObject.type : undefined;
|
|
1358
1356
|
}
|
|
1359
|
-
async function registerToolkitsOnSidecar(client, session, vm,
|
|
1360
|
-
if (
|
|
1357
|
+
async function registerToolkitsOnSidecar(client, session, vm, bindingGroups) {
|
|
1358
|
+
if (bindingGroups.length === 0) {
|
|
1361
1359
|
return "";
|
|
1362
1360
|
}
|
|
1363
|
-
for (const
|
|
1361
|
+
for (const group of bindingGroups) {
|
|
1364
1362
|
await client.registerHostCallbacks(session, vm, {
|
|
1365
|
-
name:
|
|
1366
|
-
description:
|
|
1367
|
-
commandAliases: [`agentos-${
|
|
1363
|
+
name: group.name,
|
|
1364
|
+
description: group.description,
|
|
1365
|
+
commandAliases: [`agentos-${group.name}`],
|
|
1368
1366
|
registryCommandAliases: ["agentos"],
|
|
1369
|
-
callbacks: Object.fromEntries(Object.entries(
|
|
1370
|
-
|
|
1367
|
+
callbacks: Object.fromEntries(Object.entries(group.bindings).map(([bindingName, tool]) => [
|
|
1368
|
+
bindingName,
|
|
1371
1369
|
toolToSidecarDefinition(tool),
|
|
1372
1370
|
])),
|
|
1373
1371
|
});
|
|
1374
1372
|
}
|
|
1375
|
-
return buildHostToolReference(
|
|
1373
|
+
return buildHostToolReference(bindingGroups);
|
|
1376
1374
|
}
|
|
1377
|
-
export class
|
|
1375
|
+
export class AgentOS {
|
|
1378
1376
|
#kernel;
|
|
1379
1377
|
sidecar;
|
|
1380
1378
|
_sessions = new Map();
|
|
@@ -1391,7 +1389,7 @@ export class AgentOs {
|
|
|
1391
1389
|
_softwareRoots;
|
|
1392
1390
|
_softwareAgentConfigs;
|
|
1393
1391
|
_cronManager;
|
|
1394
|
-
|
|
1392
|
+
_bindings = [];
|
|
1395
1393
|
_toolReference = "";
|
|
1396
1394
|
_permissions = allowAll;
|
|
1397
1395
|
_hostMounts;
|
|
@@ -1416,7 +1414,7 @@ export class AgentOs {
|
|
|
1416
1414
|
this._disposeSidecarEventListener = this._sidecarClient.onEvent((event) => {
|
|
1417
1415
|
this._handleSidecarEvent(event);
|
|
1418
1416
|
});
|
|
1419
|
-
|
|
1417
|
+
agentOSRuntimeAdmins.set(this, {
|
|
1420
1418
|
kernel,
|
|
1421
1419
|
rootView: rootFilesystem,
|
|
1422
1420
|
env,
|
|
@@ -1424,21 +1422,28 @@ export class AgentOs {
|
|
|
1424
1422
|
});
|
|
1425
1423
|
}
|
|
1426
1424
|
static async createSidecar(options = {}) {
|
|
1427
|
-
return
|
|
1425
|
+
return createAgentOSSidecarInternal(options);
|
|
1428
1426
|
}
|
|
1429
1427
|
static async getSharedSidecar(options = {}) {
|
|
1430
|
-
return
|
|
1428
|
+
return getSharedAgentOSSidecarInternal(options);
|
|
1431
1429
|
}
|
|
1432
1430
|
static async create(options) {
|
|
1433
|
-
|
|
1431
|
+
// Prepend the default common software set, skipping any descriptors the
|
|
1432
|
+
// caller already passed (so an explicit `software: [common, ...]` is safe).
|
|
1433
|
+
const userSoftware = options?.software ?? [];
|
|
1434
|
+
const software = [
|
|
1435
|
+
...defaultCommonSoftware.filter((pkg) => !userSoftware.includes(pkg)),
|
|
1436
|
+
...userSoftware,
|
|
1437
|
+
];
|
|
1438
|
+
const processed = processSoftware(software);
|
|
1434
1439
|
const localMounts = await resolveCompatLocalMounts(options?.mounts);
|
|
1435
|
-
const
|
|
1436
|
-
if (
|
|
1437
|
-
|
|
1440
|
+
const bindingGroups = options?.bindings;
|
|
1441
|
+
if (bindingGroups && bindingGroups.length > 0) {
|
|
1442
|
+
validateBindings(bindingGroups);
|
|
1438
1443
|
}
|
|
1439
1444
|
const createVmAdmin = async () => {
|
|
1440
1445
|
const preparedCommandDirs = prepareCommandDirs(processed.commandPackages);
|
|
1441
|
-
const toolBootstrapCommands = collectToolkitBootstrapCommands(
|
|
1446
|
+
const toolBootstrapCommands = collectToolkitBootstrapCommands(bindingGroups ?? []);
|
|
1442
1447
|
const bootstrapLower = createKernelBootstrapLower(options?.rootFilesystem, [
|
|
1443
1448
|
...collectBootstrapWasmCommands(preparedCommandDirs.commandDirs),
|
|
1444
1449
|
...NODE_RUNTIME_BOOTSTRAP_COMMANDS,
|
|
@@ -1463,17 +1468,30 @@ export class AgentOs {
|
|
|
1463
1468
|
};
|
|
1464
1469
|
try {
|
|
1465
1470
|
const env = getBaseEnvironment();
|
|
1466
|
-
if (
|
|
1467
|
-
toolShimDir = materializeToolShimDir(
|
|
1471
|
+
if (bindingGroups && bindingGroups.length > 0) {
|
|
1472
|
+
toolShimDir = materializeToolShimDir(bindingGroups);
|
|
1468
1473
|
}
|
|
1469
1474
|
const commandGuestPaths = collectGuestCommandPaths(preparedCommandDirs.commandDirs);
|
|
1475
|
+
const requestedMounts = options?.moduleAccessCwd
|
|
1476
|
+
? [
|
|
1477
|
+
...(options.mounts ?? []),
|
|
1478
|
+
{
|
|
1479
|
+
path: "/root/node_modules",
|
|
1480
|
+
plugin: createHostDirBackend({
|
|
1481
|
+
hostPath: join(options.moduleAccessCwd, "node_modules"),
|
|
1482
|
+
readOnly: true,
|
|
1483
|
+
}),
|
|
1484
|
+
readOnly: true,
|
|
1485
|
+
},
|
|
1486
|
+
]
|
|
1487
|
+
: options?.mounts;
|
|
1470
1488
|
const { sidecarMounts, hostMounts, hostPathMappings } = collectSidecarMountPlan({
|
|
1471
|
-
mounts:
|
|
1489
|
+
mounts: requestedMounts,
|
|
1472
1490
|
softwareRoots: processed.softwareRoots,
|
|
1473
1491
|
commandDirs: preparedCommandDirs.commandDirs,
|
|
1474
1492
|
shimDir: toolShimDir,
|
|
1475
1493
|
});
|
|
1476
|
-
client =
|
|
1494
|
+
client = NativeSidecarProcessClient.spawn({
|
|
1477
1495
|
cwd: REPO_ROOT,
|
|
1478
1496
|
command: ensureNativeSidecarBinary(),
|
|
1479
1497
|
args: [],
|
|
@@ -1482,7 +1500,7 @@ export class AgentOs {
|
|
|
1482
1500
|
const session = await client.authenticateAndOpenSession();
|
|
1483
1501
|
const hostPermissions = options?.permissions ?? {
|
|
1484
1502
|
...allowAll,
|
|
1485
|
-
|
|
1503
|
+
binding: "allow",
|
|
1486
1504
|
};
|
|
1487
1505
|
const sidecarPermissions = serializePermissionsForSidecar(hostPermissions);
|
|
1488
1506
|
const createVmConfig = {
|
|
@@ -1519,11 +1537,11 @@ export class AgentOs {
|
|
|
1519
1537
|
commandPermissions: processed.commandPermissions,
|
|
1520
1538
|
loopbackExemptPorts: options?.loopbackExemptPorts,
|
|
1521
1539
|
});
|
|
1522
|
-
if (
|
|
1523
|
-
toolReference = await registerToolkitsOnSidecar(client, session, nativeVm,
|
|
1540
|
+
if (bindingGroups && bindingGroups.length > 0) {
|
|
1541
|
+
toolReference = await registerToolkitsOnSidecar(client, session, nativeVm, bindingGroups);
|
|
1524
1542
|
commandGuestPaths.set("agentos", "/bin/agentos");
|
|
1525
|
-
for (const
|
|
1526
|
-
commandGuestPaths.set(`agentos-${
|
|
1543
|
+
for (const group of bindingGroups) {
|
|
1544
|
+
commandGuestPaths.set(`agentos-${group.name}`, `/bin/agentos-${group.name}`);
|
|
1527
1545
|
}
|
|
1528
1546
|
}
|
|
1529
1547
|
rootBridge = new NativeSidecarKernelProxy({
|
|
@@ -1531,7 +1549,7 @@ export class AgentOs {
|
|
|
1531
1549
|
session,
|
|
1532
1550
|
vm: nativeVm,
|
|
1533
1551
|
env,
|
|
1534
|
-
cwd: "/
|
|
1552
|
+
cwd: "/workspace",
|
|
1535
1553
|
localMounts,
|
|
1536
1554
|
commandGuestPaths,
|
|
1537
1555
|
onDispose: cleanup,
|
|
@@ -1549,7 +1567,7 @@ export class AgentOs {
|
|
|
1549
1567
|
sidecarVm: nativeVm,
|
|
1550
1568
|
permissions: hostPermissions,
|
|
1551
1569
|
snapshotRootFilesystem: async () => createSnapshotExport(convertSidecarRootSnapshotEntries(await snapshotClient.snapshotRootFilesystem(session, nativeVm))),
|
|
1552
|
-
|
|
1570
|
+
bindings: bindingGroups ?? [],
|
|
1553
1571
|
toolReference,
|
|
1554
1572
|
async dispose() {
|
|
1555
1573
|
if (kernel) {
|
|
@@ -1581,16 +1599,16 @@ export class AgentOs {
|
|
|
1581
1599
|
throw error;
|
|
1582
1600
|
}
|
|
1583
1601
|
};
|
|
1584
|
-
const sidecar =
|
|
1602
|
+
const sidecar = resolveAgentOSSidecar(options?.sidecar);
|
|
1585
1603
|
let sidecarLease = null;
|
|
1586
1604
|
try {
|
|
1587
|
-
sidecarLease = await
|
|
1605
|
+
sidecarLease = await leaseAgentOSSidecarVm(sidecar, {
|
|
1588
1606
|
createVm: async () => createVmAdmin(),
|
|
1589
1607
|
});
|
|
1590
1608
|
const vmAdmin = sidecarLease.admin;
|
|
1591
|
-
const vm = new
|
|
1609
|
+
const vm = new AgentOS(vmAdmin.kernel, sidecar, processed.softwareRoots, processed.agentConfigs, vmAdmin.hostMounts, vmAdmin.env, vmAdmin.rootView, vmAdmin.sidecarClient, vmAdmin.sidecarSession, vmAdmin.sidecarVm);
|
|
1592
1610
|
vm._sidecarLease = sidecarLease;
|
|
1593
|
-
vm.
|
|
1611
|
+
vm._bindings = vmAdmin.bindings;
|
|
1594
1612
|
vm._toolReference = vmAdmin.toolReference;
|
|
1595
1613
|
vm._permissions = vmAdmin.permissions;
|
|
1596
1614
|
vm._installSidecarRequestHandler();
|
|
@@ -1605,6 +1623,10 @@ export class AgentOs {
|
|
|
1605
1623
|
async exec(command, options) {
|
|
1606
1624
|
return this.#kernel.exec(command, options);
|
|
1607
1625
|
}
|
|
1626
|
+
async execArgv(command, args = [], options) {
|
|
1627
|
+
const kernel = this.#kernel;
|
|
1628
|
+
return kernel.execArgv(command, args, options);
|
|
1629
|
+
}
|
|
1608
1630
|
_trackProcess(proc, command, args, stdoutHandlers, stderrHandlers, exitHandlers) {
|
|
1609
1631
|
const entry = {
|
|
1610
1632
|
proc,
|
|
@@ -2507,7 +2529,7 @@ export class AgentOs {
|
|
|
2507
2529
|
// skipOsInstructions plus the agent's static launch args and env.
|
|
2508
2530
|
const launchArgs = [...(config.launchArgs ?? [])];
|
|
2509
2531
|
let launchEnv = { ...config.defaultEnv, ...options?.env };
|
|
2510
|
-
const sessionCwd = options?.cwd ?? "/
|
|
2532
|
+
const sessionCwd = options?.cwd ?? "/workspace";
|
|
2511
2533
|
const adapterEntrypoint = this._resolveAdapterBin(config.acpAdapter);
|
|
2512
2534
|
if ((agentType === "pi" || agentType === "pi-cli") &&
|
|
2513
2535
|
!launchEnv.PI_ACP_PI_COMMAND) {
|
|
@@ -2563,70 +2585,6 @@ export class AgentOs {
|
|
|
2563
2585
|
}
|
|
2564
2586
|
return { sessionId: created.sessionId };
|
|
2565
2587
|
}
|
|
2566
|
-
/**
|
|
2567
|
-
* Resume a session that exists in durable storage but is not live in this VM
|
|
2568
|
-
* (e.g. after a Rivet actor slept and woke with a fresh VM). Thin forwarder:
|
|
2569
|
-
* resolves the agent config + adapter entrypoint exactly as {@link createSession}
|
|
2570
|
-
* does, then forwards a single `AcpResumeSessionRequest` to the sidecar, which
|
|
2571
|
-
* owns the resume state machine (native `session/load` when the agent supports
|
|
2572
|
-
* it, else `session/new` + a transcript-continuation preamble). The returned
|
|
2573
|
-
* `sessionId` is the live id in this VM (equal to the requested id for native
|
|
2574
|
-
* loads, freshly assigned for the fallback); the caller remaps `external -> live`.
|
|
2575
|
-
* The new live session is registered + hydrated locally so subsequent prompts
|
|
2576
|
-
* route to it.
|
|
2577
|
-
*
|
|
2578
|
-
* Resume depends on a durable root; on a non-durable (default in-memory) root
|
|
2579
|
-
* there is no surviving store and the fallback tier always runs.
|
|
2580
|
-
*/
|
|
2581
|
-
async resumeSession(sessionId, agentType, options) {
|
|
2582
|
-
const config = this._resolveAgentConfig(agentType);
|
|
2583
|
-
if (!config) {
|
|
2584
|
-
throw new Error(`Unknown agent type: ${agentType}`);
|
|
2585
|
-
}
|
|
2586
|
-
const adapterEntrypoint = this._resolveAdapterBin(config.acpAdapter);
|
|
2587
|
-
let launchEnv = { ...config.defaultEnv, ...options?.env };
|
|
2588
|
-
const sessionCwd = options?.cwd ?? "/home/user";
|
|
2589
|
-
if ((agentType === "pi" || agentType === "pi-cli") &&
|
|
2590
|
-
!launchEnv.PI_ACP_PI_COMMAND) {
|
|
2591
|
-
launchEnv = {
|
|
2592
|
-
...launchEnv,
|
|
2593
|
-
PI_ACP_PI_COMMAND: this._resolvePackageBin(config.agentPackage, "pi"),
|
|
2594
|
-
};
|
|
2595
|
-
}
|
|
2596
|
-
// The resume wire request has no dedicated `adapterEntrypoint` field; carry
|
|
2597
|
-
// the resolved entrypoint through env under the sidecar's reserved key. The
|
|
2598
|
-
// sidecar reads it and strips it before launching the adapter.
|
|
2599
|
-
launchEnv = {
|
|
2600
|
-
...launchEnv,
|
|
2601
|
-
[RESUME_ADAPTER_ENTRYPOINT_ENV]: adapterEntrypoint,
|
|
2602
|
-
};
|
|
2603
|
-
const response = await this._sendAcpRequest({
|
|
2604
|
-
tag: "AcpResumeSessionRequest",
|
|
2605
|
-
val: {
|
|
2606
|
-
sessionId,
|
|
2607
|
-
agentType: String(agentType),
|
|
2608
|
-
transcriptPath: options?.transcriptPath ?? null,
|
|
2609
|
-
cwd: sessionCwd,
|
|
2610
|
-
env: new Map(Object.entries(launchEnv)),
|
|
2611
|
-
},
|
|
2612
|
-
});
|
|
2613
|
-
if (response.tag !== "AcpSessionResumedResponse") {
|
|
2614
|
-
throw new Error(`unexpected resume_session response: ${response.tag}`);
|
|
2615
|
-
}
|
|
2616
|
-
const { sessionId: liveSessionId, mode } = response.val;
|
|
2617
|
-
// Register + hydrate the live session so subsequent prompts route to it.
|
|
2618
|
-
const session = sessionEntryFromInit(liveSessionId, String(agentType), {});
|
|
2619
|
-
this._closedSessionIds.delete(liveSessionId);
|
|
2620
|
-
this._sessions.set(liveSessionId, session);
|
|
2621
|
-
try {
|
|
2622
|
-
await this._hydrateSessionState(session);
|
|
2623
|
-
}
|
|
2624
|
-
catch (error) {
|
|
2625
|
-
this._removeSession(liveSessionId);
|
|
2626
|
-
throw error;
|
|
2627
|
-
}
|
|
2628
|
-
return { sessionId: liveSessionId, mode };
|
|
2629
|
-
}
|
|
2630
2588
|
/**
|
|
2631
2589
|
* Resolve the VM bin entry point of an ACP adapter package.
|
|
2632
2590
|
* Reads from the host filesystem since kernel.readFile() resolves through
|
|
@@ -2666,7 +2624,7 @@ export class AgentOs {
|
|
|
2666
2624
|
if (!nodeModulesRoot) {
|
|
2667
2625
|
throw new Error(`Cannot resolve package "${packageName}": no software root provides it and ` +
|
|
2668
2626
|
`no /root/node_modules mount was supplied. Pass ` +
|
|
2669
|
-
`mounts: [nodeModulesMount("<host>/node_modules")] to
|
|
2627
|
+
`mounts: [nodeModulesMount("<host>/node_modules")] to AgentOS.create().`);
|
|
2670
2628
|
}
|
|
2671
2629
|
hostPkgJsonPath = join(resolvePackageDir(nodeModulesRoot, packageName), "package.json");
|
|
2672
2630
|
}
|
|
@@ -2688,8 +2646,8 @@ export class AgentOs {
|
|
|
2688
2646
|
}
|
|
2689
2647
|
_installSidecarRequestHandler() {
|
|
2690
2648
|
const context = {
|
|
2691
|
-
|
|
2692
|
-
toolMap: buildToolMap(this.
|
|
2649
|
+
bindings: this._bindings,
|
|
2650
|
+
toolMap: buildToolMap(this._bindings),
|
|
2693
2651
|
permissions: this._permissions,
|
|
2694
2652
|
readFile: (path) => this.readFile(path),
|
|
2695
2653
|
};
|
|
@@ -3400,26 +3358,26 @@ export class AgentOs {
|
|
|
3400
3358
|
return this.#kernel.dispose();
|
|
3401
3359
|
}
|
|
3402
3360
|
}
|
|
3403
|
-
const
|
|
3404
|
-
export function
|
|
3405
|
-
const admin =
|
|
3361
|
+
const agentOSRuntimeAdmins = new WeakMap();
|
|
3362
|
+
export function getAgentOSRuntimeAdmin(vm) {
|
|
3363
|
+
const admin = agentOSRuntimeAdmins.get(vm);
|
|
3406
3364
|
if (!admin) {
|
|
3407
3365
|
throw new Error("Agent OS runtime admin is not available for this VM");
|
|
3408
3366
|
}
|
|
3409
3367
|
return admin;
|
|
3410
3368
|
}
|
|
3411
|
-
export function
|
|
3412
|
-
return
|
|
3369
|
+
export function getAgentOSKernel(vm) {
|
|
3370
|
+
return getAgentOSRuntimeAdmin(vm).kernel;
|
|
3413
3371
|
}
|
|
3414
|
-
function
|
|
3372
|
+
function resolveAgentOSSidecar(config) {
|
|
3415
3373
|
if (!config || config.kind === "shared") {
|
|
3416
|
-
return
|
|
3374
|
+
return getSharedAgentOSSidecarInternal(config?.kind === "shared" ? { pool: config.pool } : undefined);
|
|
3417
3375
|
}
|
|
3418
3376
|
return config.handle;
|
|
3419
3377
|
}
|
|
3420
3378
|
const sidecarStates = new WeakMap();
|
|
3421
3379
|
const sharedSidecars = new Map();
|
|
3422
|
-
export class
|
|
3380
|
+
export class AgentOSSidecar {
|
|
3423
3381
|
constructor(sidecarId, placement, sharedPool) {
|
|
3424
3382
|
sidecarStates.set(this, {
|
|
3425
3383
|
description: {
|
|
@@ -3462,9 +3420,9 @@ export class AgentOsSidecar {
|
|
|
3462
3420
|
}
|
|
3463
3421
|
}
|
|
3464
3422
|
}
|
|
3465
|
-
function
|
|
3423
|
+
function createAgentOSSidecarInternal(options = {}) {
|
|
3466
3424
|
const sidecarId = options.sidecarId ?? `agentos-sidecar-${randomUUID()}`;
|
|
3467
|
-
return new
|
|
3425
|
+
return new AgentOSSidecar(sidecarId, {
|
|
3468
3426
|
kind: "explicit",
|
|
3469
3427
|
sidecarId,
|
|
3470
3428
|
});
|
|
@@ -3472,7 +3430,7 @@ function createAgentOsSidecarInternal(options = {}) {
|
|
|
3472
3430
|
/**
|
|
3473
3431
|
* Test-only escape hatch: dispose every cached shared sidecar so vitest
|
|
3474
3432
|
* workers can exit cleanly. The shared sidecar is normally process-global and
|
|
3475
|
-
* keeps its native subprocess alive across `
|
|
3433
|
+
* keeps its native subprocess alive across `AgentOS.create()` calls; without
|
|
3476
3434
|
* this hook the vitest worker can hold open piped stdio handles after the
|
|
3477
3435
|
* test suite finishes and stall `pnpm test` indefinitely.
|
|
3478
3436
|
*/
|
|
@@ -3492,23 +3450,23 @@ export async function __disposeAllSharedSidecarsForTesting() {
|
|
|
3492
3450
|
throw new Error(`failed to dispose shared sidecars: ${errors.map((error) => error.message).join("; ")}`);
|
|
3493
3451
|
}
|
|
3494
3452
|
}
|
|
3495
|
-
function
|
|
3453
|
+
function getSharedAgentOSSidecarInternal(options = {}) {
|
|
3496
3454
|
const pool = options.pool ?? "default";
|
|
3497
3455
|
const existing = sharedSidecars.get(pool);
|
|
3498
3456
|
if (existing && existing.describe().state !== "disposed") {
|
|
3499
3457
|
return existing;
|
|
3500
3458
|
}
|
|
3501
|
-
const sidecar = new
|
|
3459
|
+
const sidecar = new AgentOSSidecar(`agentos-shared-sidecar:${pool}`, { kind: "shared", ...(pool ? { pool } : {}) }, pool);
|
|
3502
3460
|
sharedSidecars.set(pool, sidecar);
|
|
3503
3461
|
return sidecar;
|
|
3504
3462
|
}
|
|
3505
|
-
async function
|
|
3463
|
+
async function leaseAgentOSSidecarVm(sidecar, options) {
|
|
3506
3464
|
const state = getSidecarState(sidecar);
|
|
3507
3465
|
if (state.description.state !== "ready") {
|
|
3508
3466
|
throw new Error(`Cannot lease VM from sidecar ${state.description.sidecarId} while it is ${state.description.state}`);
|
|
3509
3467
|
}
|
|
3510
3468
|
let transport;
|
|
3511
|
-
const client =
|
|
3469
|
+
const client = createAgentOSSidecarClient({
|
|
3512
3470
|
async createSessionTransport(sessionBootstrap) {
|
|
3513
3471
|
transport = await createInProcessSidecarTransport(sessionBootstrap, options);
|
|
3514
3472
|
return transport;
|