@rivet-dev/agentos-core 0.0.0-agentos-dylib-plugin.473700e

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.
Files changed (75) hide show
  1. package/README.md +204 -0
  2. package/dist/agent-os.d.ts +560 -0
  3. package/dist/agent-os.js +3624 -0
  4. package/dist/agent-session-types.d.ts +67 -0
  5. package/dist/agent-session-types.js +1 -0
  6. package/dist/agents.d.ts +63 -0
  7. package/dist/agents.js +42 -0
  8. package/dist/base-filesystem.d.ts +34 -0
  9. package/dist/base-filesystem.js +173 -0
  10. package/dist/cron/cron-manager.d.ts +22 -0
  11. package/dist/cron/cron-manager.js +160 -0
  12. package/dist/cron/index.d.ts +5 -0
  13. package/dist/cron/index.js +3 -0
  14. package/dist/cron/parse-schedule.d.ts +25 -0
  15. package/dist/cron/parse-schedule.js +66 -0
  16. package/dist/cron/schedule-driver.d.ts +19 -0
  17. package/dist/cron/schedule-driver.js +1 -0
  18. package/dist/cron/timer-driver.d.ts +17 -0
  19. package/dist/cron/timer-driver.js +61 -0
  20. package/dist/cron/types.d.ts +55 -0
  21. package/dist/cron/types.js +1 -0
  22. package/dist/filesystem-snapshot.d.ts +14 -0
  23. package/dist/filesystem-snapshot.js +105 -0
  24. package/dist/host-dir-mount.d.ts +38 -0
  25. package/dist/host-dir-mount.js +34 -0
  26. package/dist/host-tools-zod.d.ts +7 -0
  27. package/dist/host-tools-zod.js +243 -0
  28. package/dist/host-tools.d.ts +45 -0
  29. package/dist/host-tools.js +26 -0
  30. package/dist/index.d.ts +10 -0
  31. package/dist/index.js +10 -0
  32. package/dist/js-bridge.d.ts +3 -0
  33. package/dist/js-bridge.js +2 -0
  34. package/dist/json-rpc.d.ts +50 -0
  35. package/dist/json-rpc.js +22 -0
  36. package/dist/layers.d.ts +51 -0
  37. package/dist/layers.js +185 -0
  38. package/dist/overlay-filesystem.d.ts +19 -0
  39. package/dist/overlay-filesystem.js +645 -0
  40. package/dist/packages.d.ts +127 -0
  41. package/dist/packages.js +335 -0
  42. package/dist/runtime-compat.d.ts +471 -0
  43. package/dist/runtime-compat.js +2009 -0
  44. package/dist/runtime.d.ts +336 -0
  45. package/dist/runtime.js +1 -0
  46. package/dist/sidecar/agent-os-protocol.d.ts +219 -0
  47. package/dist/sidecar/agent-os-protocol.js +594 -0
  48. package/dist/sidecar/binary.d.ts +9 -0
  49. package/dist/sidecar/binary.js +30 -0
  50. package/dist/sidecar/cargo.d.ts +2 -0
  51. package/dist/sidecar/cargo.js +142 -0
  52. package/dist/sidecar/native-process-client.d.ts +2 -0
  53. package/dist/sidecar/native-process-client.js +1 -0
  54. package/dist/sidecar/permissions.d.ts +3 -0
  55. package/dist/sidecar/permissions.js +54 -0
  56. package/dist/sidecar/process.d.ts +6 -0
  57. package/dist/sidecar/process.js +8 -0
  58. package/dist/sidecar/rpc-client.d.ts +244 -0
  59. package/dist/sidecar/rpc-client.js +2028 -0
  60. package/dist/test/docker.d.ts +133 -0
  61. package/dist/test/docker.js +336 -0
  62. package/dist/test/file-system.d.ts +39 -0
  63. package/dist/test/file-system.js +562 -0
  64. package/dist/test/mock-s3.d.ts +42 -0
  65. package/dist/test/mock-s3.js +292 -0
  66. package/dist/test/runtime.d.ts +11 -0
  67. package/dist/test/runtime.js +9 -0
  68. package/dist/test/sandbox-agent.d.ts +9 -0
  69. package/dist/test/sandbox-agent.js +395 -0
  70. package/dist/test/terminal-harness.d.ts +27 -0
  71. package/dist/test/terminal-harness.js +122 -0
  72. package/dist/types.d.ts +10 -0
  73. package/dist/types.js +1 -0
  74. package/fixtures/AGENTOS_SYSTEM_PROMPT.md +21 -0
  75. package/package.json +111 -0
@@ -0,0 +1,17 @@
1
+ import type { ScheduleDriver, ScheduleEntry, ScheduleHandle } from "./schedule-driver.js";
2
+ /**
3
+ * Default ScheduleDriver that uses in-process timers. For cron expressions
4
+ * it parses via croner and sets a single timeout for the next fire time,
5
+ * rescheduling after each fire. For ISO 8601 one-shot timestamps it fires
6
+ * once and removes the entry.
7
+ *
8
+ * Uses long-timeout to support delays exceeding setTimeout's 2^31ms limit.
9
+ */
10
+ export declare class TimerScheduleDriver implements ScheduleDriver {
11
+ private timers;
12
+ private entries;
13
+ schedule(entry: ScheduleEntry): ScheduleHandle;
14
+ cancel(handle: ScheduleHandle): void;
15
+ dispose(): void;
16
+ private scheduleNext;
17
+ }
@@ -0,0 +1,61 @@
1
+ import { clearTimeout as clearLongTimeout, setTimeout as longSetTimeout, } from "long-timeout";
2
+ import { resolveSchedule, validateScheduleForRegistration, } from "./parse-schedule.js";
3
+ /**
4
+ * Default ScheduleDriver that uses in-process timers. For cron expressions
5
+ * it parses via croner and sets a single timeout for the next fire time,
6
+ * rescheduling after each fire. For ISO 8601 one-shot timestamps it fires
7
+ * once and removes the entry.
8
+ *
9
+ * Uses long-timeout to support delays exceeding setTimeout's 2^31ms limit.
10
+ */
11
+ export class TimerScheduleDriver {
12
+ timers = new Map();
13
+ entries = new Map();
14
+ schedule(entry) {
15
+ const resolved = validateScheduleForRegistration(entry.schedule);
16
+ this.entries.set(entry.id, entry);
17
+ this.scheduleNext(entry, resolved);
18
+ return { id: entry.id };
19
+ }
20
+ cancel(handle) {
21
+ const timer = this.timers.get(handle.id);
22
+ if (timer) {
23
+ clearLongTimeout(timer);
24
+ this.timers.delete(handle.id);
25
+ }
26
+ this.entries.delete(handle.id);
27
+ }
28
+ dispose() {
29
+ for (const timer of this.timers.values()) {
30
+ clearLongTimeout(timer);
31
+ }
32
+ this.timers.clear();
33
+ this.entries.clear();
34
+ }
35
+ scheduleNext(entry, resolved = resolveSchedule(entry.schedule)) {
36
+ const { parsed, nextRun: next } = resolved;
37
+ const isCron = parsed.kind === "cron";
38
+ if (!next) {
39
+ this.timers.delete(entry.id);
40
+ this.entries.delete(entry.id);
41
+ return;
42
+ }
43
+ const delay = Math.max(0, next.getTime() - Date.now());
44
+ const timer = longSetTimeout(async () => {
45
+ this.timers.delete(entry.id);
46
+ try {
47
+ await entry.callback();
48
+ }
49
+ catch {
50
+ // The driver is fire-and-forget; error handling is the caller's responsibility.
51
+ }
52
+ if (isCron && this.entries.has(entry.id)) {
53
+ this.scheduleNext(entry);
54
+ }
55
+ else {
56
+ this.entries.delete(entry.id);
57
+ }
58
+ }, delay);
59
+ this.timers.set(entry.id, timer);
60
+ }
61
+ }
@@ -0,0 +1,55 @@
1
+ import type { CreateSessionOptions } from "../agent-os.js";
2
+ import type { AgentType } from "../agents.js";
3
+ export type CronAction = {
4
+ type: "session";
5
+ agentType: AgentType;
6
+ prompt: string;
7
+ options?: CreateSessionOptions;
8
+ } | {
9
+ type: "exec";
10
+ command: string;
11
+ args?: string[];
12
+ } | {
13
+ type: "callback";
14
+ fn: () => void | Promise<void>;
15
+ };
16
+ export interface CronJobOptions {
17
+ /** Optional ID. Auto-generated UUID if omitted. */
18
+ id?: string;
19
+ /** Standard 5-field cron expression or ISO 8601 timestamp for one-shot. */
20
+ schedule: string;
21
+ /** What to do when the schedule fires. */
22
+ action: CronAction;
23
+ /** What to do if previous execution is still running. Default: 'allow'. */
24
+ overlap?: "allow" | "skip" | "queue";
25
+ }
26
+ export interface CronJob {
27
+ id: string;
28
+ cancel(): void;
29
+ }
30
+ export interface CronJobInfo {
31
+ id: string;
32
+ schedule: string;
33
+ action: CronAction;
34
+ overlap: "allow" | "skip" | "queue";
35
+ lastRun?: Date;
36
+ nextRun?: Date;
37
+ runCount: number;
38
+ running: boolean;
39
+ }
40
+ export type CronEvent = {
41
+ type: "cron:fire";
42
+ jobId: string;
43
+ time: Date;
44
+ } | {
45
+ type: "cron:complete";
46
+ jobId: string;
47
+ time: Date;
48
+ durationMs: number;
49
+ } | {
50
+ type: "cron:error";
51
+ jobId: string;
52
+ time: Date;
53
+ error: Error;
54
+ };
55
+ export type CronEventHandler = (event: CronEvent) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { type VirtualFileSystem } from "./runtime-compat.js";
2
+ export interface FilesystemEntry {
3
+ path: string;
4
+ type: "directory" | "file" | "symlink";
5
+ mode: string;
6
+ uid: number;
7
+ gid: number;
8
+ content?: string;
9
+ encoding?: "utf8" | "base64";
10
+ target?: string;
11
+ }
12
+ export declare function sortFilesystemEntries(entries: FilesystemEntry[]): FilesystemEntry[];
13
+ export declare function createFilesystemFromEntries(entries: FilesystemEntry[]): Promise<VirtualFileSystem>;
14
+ export declare function snapshotVirtualFilesystem(filesystem: VirtualFileSystem, rootPath?: string): Promise<FilesystemEntry[]>;
@@ -0,0 +1,105 @@
1
+ import * as posixPath from "node:path/posix";
2
+ import { createInMemoryFileSystem, } from "./runtime-compat.js";
3
+ function parseMode(mode) {
4
+ return Number.parseInt(mode, 8);
5
+ }
6
+ export function sortFilesystemEntries(entries) {
7
+ return [...entries].sort((a, b) => {
8
+ const depthA = a.path === "/" ? 0 : a.path.split("/").filter(Boolean).length;
9
+ const depthB = b.path === "/" ? 0 : b.path.split("/").filter(Boolean).length;
10
+ if (depthA !== depthB) {
11
+ return depthA - depthB;
12
+ }
13
+ return a.path.localeCompare(b.path);
14
+ });
15
+ }
16
+ async function applyDirectory(filesystem, entry) {
17
+ if (entry.path !== "/") {
18
+ await filesystem.mkdir(entry.path, { recursive: true });
19
+ }
20
+ await filesystem.chmod(entry.path, parseMode(entry.mode));
21
+ await filesystem.chown(entry.path, entry.uid, entry.gid);
22
+ }
23
+ async function applyFile(filesystem, entry) {
24
+ const content = entry.content ?? "";
25
+ await filesystem.writeFile(entry.path, entry.encoding === "base64" ? Buffer.from(content, "base64") : content);
26
+ await filesystem.chmod(entry.path, parseMode(entry.mode));
27
+ await filesystem.chown(entry.path, entry.uid, entry.gid);
28
+ }
29
+ async function applySymlink(filesystem, entry) {
30
+ if (!entry.target) {
31
+ throw new Error(`Missing symlink target for ${entry.path}`);
32
+ }
33
+ await filesystem.symlink(entry.target, entry.path);
34
+ }
35
+ export async function createFilesystemFromEntries(entries) {
36
+ const filesystem = createInMemoryFileSystem();
37
+ const sortedEntries = sortFilesystemEntries(entries);
38
+ for (const entry of sortedEntries) {
39
+ if (entry.type === "directory") {
40
+ await applyDirectory(filesystem, entry);
41
+ }
42
+ }
43
+ for (const entry of sortedEntries) {
44
+ if (entry.type === "file") {
45
+ await applyFile(filesystem, entry);
46
+ }
47
+ }
48
+ for (const entry of sortedEntries) {
49
+ if (entry.type === "symlink") {
50
+ await applySymlink(filesystem, entry);
51
+ }
52
+ }
53
+ return filesystem;
54
+ }
55
+ function toModeString(mode) {
56
+ return `0${(mode & 0o7777).toString(8)}`;
57
+ }
58
+ async function snapshotPath(filesystem, path, entries) {
59
+ const stat = path === "/" ? await filesystem.stat(path) : await filesystem.lstat(path);
60
+ if (stat.isSymbolicLink) {
61
+ entries.push({
62
+ path,
63
+ type: "symlink",
64
+ mode: toModeString(stat.mode),
65
+ uid: stat.uid,
66
+ gid: stat.gid,
67
+ target: await filesystem.readlink(path),
68
+ });
69
+ return;
70
+ }
71
+ if (stat.isDirectory) {
72
+ entries.push({
73
+ path,
74
+ type: "directory",
75
+ mode: toModeString(stat.mode),
76
+ uid: stat.uid,
77
+ gid: stat.gid,
78
+ });
79
+ const dirEntries = await filesystem.readDirWithTypes(path);
80
+ const children = dirEntries
81
+ .map((entry) => entry.name)
82
+ .filter((name) => name !== "." && name !== "..")
83
+ .sort((a, b) => a.localeCompare(b));
84
+ for (const child of children) {
85
+ const childPath = path === "/" ? posixPath.join("/", child) : posixPath.join(path, child);
86
+ await snapshotPath(filesystem, childPath, entries);
87
+ }
88
+ return;
89
+ }
90
+ const content = Buffer.from(await filesystem.readFile(path)).toString("base64");
91
+ entries.push({
92
+ path,
93
+ type: "file",
94
+ mode: toModeString(stat.mode),
95
+ uid: stat.uid,
96
+ gid: stat.gid,
97
+ content,
98
+ encoding: "base64",
99
+ });
100
+ }
101
+ export async function snapshotVirtualFilesystem(filesystem, rootPath = "/") {
102
+ const entries = [];
103
+ await snapshotPath(filesystem, rootPath, entries);
104
+ return entries;
105
+ }
@@ -0,0 +1,38 @@
1
+ import type { MountConfigJsonObject, NativeMountPluginDescriptor } from "@secure-exec/core/descriptors";
2
+ export interface HostDirBackendOptions {
3
+ /** Absolute path to the host directory to project into the VM. */
4
+ hostPath: string;
5
+ /** If true (default), write operations are blocked for the mount. */
6
+ readOnly?: boolean;
7
+ }
8
+ export interface HostDirMountPluginConfig extends MountConfigJsonObject {
9
+ hostPath: string;
10
+ readOnly: boolean;
11
+ }
12
+ /**
13
+ * Create a declarative host-dir mount plugin descriptor.
14
+ *
15
+ * This keeps the legacy helper name while routing first-party host-dir
16
+ * mounts through the native `host_dir` plugin instead of a JS VFS backend.
17
+ */
18
+ export declare function createHostDirBackend(options: HostDirBackendOptions): NativeMountPluginDescriptor<HostDirMountPluginConfig>;
19
+ /** A native `host_dir` mount, the serializable form `AgentOsOptions.mounts` accepts. */
20
+ export interface NodeModulesMountConfig {
21
+ path: string;
22
+ plugin: NativeMountPluginDescriptor<HostDirMountPluginConfig>;
23
+ readOnly: boolean;
24
+ }
25
+ /**
26
+ * Mount a host `node_modules` directory into the VM at `/root/node_modules`.
27
+ *
28
+ * This is the explicit replacement for the removed `moduleAccessCwd` option:
29
+ * the VM's module resolver reads the mounted tree through the kernel VFS, so the
30
+ * caller supplies exactly the `node_modules` directory whose packages should be
31
+ * resolvable in the guest (e.g. the agent SDK + its transitive deps).
32
+ *
33
+ * @param hostNodeModulesDir Absolute host path to a `node_modules` directory.
34
+ * @param opts.readOnly Defaults to `true`; the mount is read-only.
35
+ */
36
+ export declare function nodeModulesMount(hostNodeModulesDir: string, opts?: {
37
+ readOnly?: boolean;
38
+ }): NodeModulesMountConfig;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Create a declarative host-dir mount plugin descriptor.
3
+ *
4
+ * This keeps the legacy helper name while routing first-party host-dir
5
+ * mounts through the native `host_dir` plugin instead of a JS VFS backend.
6
+ */
7
+ export function createHostDirBackend(options) {
8
+ return {
9
+ id: "host_dir",
10
+ config: {
11
+ hostPath: options.hostPath,
12
+ readOnly: options.readOnly ?? true,
13
+ },
14
+ };
15
+ }
16
+ /**
17
+ * Mount a host `node_modules` directory into the VM at `/root/node_modules`.
18
+ *
19
+ * This is the explicit replacement for the removed `moduleAccessCwd` option:
20
+ * the VM's module resolver reads the mounted tree through the kernel VFS, so the
21
+ * caller supplies exactly the `node_modules` directory whose packages should be
22
+ * resolvable in the guest (e.g. the agent SDK + its transitive deps).
23
+ *
24
+ * @param hostNodeModulesDir Absolute host path to a `node_modules` directory.
25
+ * @param opts.readOnly Defaults to `true`; the mount is read-only.
26
+ */
27
+ export function nodeModulesMount(hostNodeModulesDir, opts) {
28
+ const readOnly = opts?.readOnly ?? true;
29
+ return {
30
+ path: "/root/node_modules",
31
+ plugin: createHostDirBackend({ hostPath: hostNodeModulesDir, readOnly }),
32
+ readOnly,
33
+ };
34
+ }
@@ -0,0 +1,7 @@
1
+ import type { ZodType } from "zod";
2
+ export declare class HostToolSchemaConversionError extends Error {
3
+ readonly path: string;
4
+ readonly zodType: string;
5
+ constructor(path: string, zodType: string, details?: string);
6
+ }
7
+ export declare function zodToJsonSchema(schema: ZodType): unknown;
@@ -0,0 +1,243 @@
1
+ const OPTIONAL_WRAPPER_TYPES = new Set(["default", "optional"]);
2
+ const TRANSPARENT_WRAPPER_TYPES = new Set([
3
+ ...OPTIONAL_WRAPPER_TYPES,
4
+ "branded",
5
+ "catch",
6
+ "readonly",
7
+ ]);
8
+ const UNSUPPORTED_TYPES = new Set([
9
+ "bigint",
10
+ "date",
11
+ "effects",
12
+ "intersection",
13
+ "pipeline",
14
+ "pipe",
15
+ "tuple",
16
+ ]);
17
+ export class HostToolSchemaConversionError extends Error {
18
+ path;
19
+ zodType;
20
+ constructor(path, zodType, details) {
21
+ super([
22
+ `Unsupported Zod schema at ${path}: ${zodType}`,
23
+ details ? `(${details})` : undefined,
24
+ ]
25
+ .filter(Boolean)
26
+ .join(" "));
27
+ this.name = "HostToolSchemaConversionError";
28
+ this.path = path;
29
+ this.zodType = zodType;
30
+ }
31
+ }
32
+ function getSchemaDef(schema) {
33
+ return (schema._def ??
34
+ schema.def ??
35
+ {});
36
+ }
37
+ function getInnerSchema(schema) {
38
+ const def = getSchemaDef(schema);
39
+ return (def.innerType ?? def.schema ?? def.type ?? def.in);
40
+ }
41
+ function normalizeTypeName(schema) {
42
+ const def = getSchemaDef(schema);
43
+ const constructorName = String(schema.constructor?.name ?? "")
44
+ .replace(/^Zod/, "")
45
+ .toLowerCase();
46
+ if (constructorName === "discriminatedunion" || "discriminator" in def) {
47
+ return "discriminatedunion";
48
+ }
49
+ const rawTypeName = String(def.typeName ?? def.type ?? schema.type ?? constructorName);
50
+ return rawTypeName.replace(/^Zod/, "").toLowerCase();
51
+ }
52
+ function displayTypeName(typeName) {
53
+ switch (typeName) {
54
+ case "discriminatedunion":
55
+ return "discriminatedUnion";
56
+ case "nativeenum":
57
+ return "nativeEnum";
58
+ default:
59
+ return typeName;
60
+ }
61
+ }
62
+ function getDescription(schema) {
63
+ const def = getSchemaDef(schema);
64
+ if (typeof def.description === "string") {
65
+ return def.description;
66
+ }
67
+ const instanceDescription = schema.description;
68
+ return typeof instanceDescription === "string"
69
+ ? instanceDescription
70
+ : undefined;
71
+ }
72
+ function joinPath(parent, segment) {
73
+ return parent === "$" ? `$.${segment}` : `${parent}.${segment}`;
74
+ }
75
+ function metadataProducesRefs(schema) {
76
+ const meta = schema.meta?.();
77
+ return (typeof meta === "object" &&
78
+ meta !== null &&
79
+ ("id" in meta || "$ref" in meta || "$defs" in meta));
80
+ }
81
+ function getChecks(schema) {
82
+ const checks = getSchemaDef(schema).checks;
83
+ return Array.isArray(checks) ? checks : [];
84
+ }
85
+ function isCustomRefinement(check) {
86
+ const checkDef = getSchemaDef(check);
87
+ const nestedDef = getSchemaDef(check._zod);
88
+ return (String(checkDef.check ?? nestedDef.check ?? "").toLowerCase() === "custom");
89
+ }
90
+ function validateChecks(schema, path, typeName) {
91
+ if (getChecks(schema).some(isCustomRefinement)) {
92
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "custom refinements cannot be represented faithfully in JSON Schema");
93
+ }
94
+ }
95
+ function validateSchema(schema, path) {
96
+ const typeName = normalizeTypeName(schema);
97
+ if (metadataProducesRefs(schema)) {
98
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "metadata that emits $ref/$defs is not supported");
99
+ }
100
+ if (UNSUPPORTED_TYPES.has(typeName)) {
101
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
102
+ }
103
+ if (typeName === "discriminatedunion") {
104
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
105
+ }
106
+ if (TRANSPARENT_WRAPPER_TYPES.has(typeName)) {
107
+ const inner = getInnerSchema(schema);
108
+ if (!inner) {
109
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "wrapper schema is missing its inner schema");
110
+ }
111
+ validateSchema(inner, path);
112
+ return;
113
+ }
114
+ if (typeName === "nullable") {
115
+ const inner = getInnerSchema(schema);
116
+ if (!inner) {
117
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "nullable schema is missing its inner schema");
118
+ }
119
+ validateSchema(inner, path);
120
+ return;
121
+ }
122
+ validateChecks(schema, path, typeName);
123
+ if (typeName === "object") {
124
+ const rawShape = getSchemaDef(schema).shape;
125
+ const shape = typeof rawShape === "function"
126
+ ? rawShape()
127
+ : (rawShape ?? {});
128
+ for (const [fieldName, fieldSchema] of Object.entries(shape)) {
129
+ validateSchema(fieldSchema, joinPath(path, fieldName));
130
+ }
131
+ return;
132
+ }
133
+ if (typeName === "array") {
134
+ const itemSchema = getSchemaDef(schema).element;
135
+ if (!itemSchema) {
136
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "array schema is missing its item schema");
137
+ }
138
+ validateSchema(itemSchema, `${path}[]`);
139
+ return;
140
+ }
141
+ if (typeName === "record") {
142
+ const def = getSchemaDef(schema);
143
+ const keySchema = def.keyType;
144
+ const valueSchema = def.valueType;
145
+ if (!keySchema || !valueSchema) {
146
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "record schema is missing its key or value schema");
147
+ }
148
+ const keyTypeName = normalizeTypeName(keySchema);
149
+ if (keyTypeName !== "string" || getChecks(keySchema).length > 0) {
150
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "record keys must be unconstrained strings");
151
+ }
152
+ validateSchema(valueSchema, `${path}<record-value>`);
153
+ return;
154
+ }
155
+ if (typeName === "union") {
156
+ const options = getSchemaDef(schema).options;
157
+ if (!Array.isArray(options) || options.length === 0) {
158
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "union schema is missing its options");
159
+ }
160
+ for (let index = 0; index < options.length; index += 1) {
161
+ validateSchema(options[index], `${path}<union:${index}>`);
162
+ }
163
+ return;
164
+ }
165
+ if (typeName === "literal") {
166
+ const values = getSchemaDef(schema).values;
167
+ const literalValues = Array.isArray(values) ? values : [];
168
+ const [literalValue] = literalValues;
169
+ if (literalValues.length !== 1 ||
170
+ !("string number boolean".split(" ").includes(typeof literalValue) || literalValue === null)) {
171
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName), "literal values must be JSON primitives");
172
+ }
173
+ return;
174
+ }
175
+ if (typeName === "string" ||
176
+ typeName === "number" ||
177
+ typeName === "boolean" ||
178
+ typeName === "enum" ||
179
+ typeName === "nativeenum") {
180
+ return;
181
+ }
182
+ throw new HostToolSchemaConversionError(path, displayTypeName(typeName));
183
+ }
184
+ function sanitizeJsonSchema(value) {
185
+ if (Array.isArray(value)) {
186
+ return value.map((item) => sanitizeJsonSchema(item));
187
+ }
188
+ if (!value || typeof value !== "object") {
189
+ return value;
190
+ }
191
+ const record = value;
192
+ const sanitized = {};
193
+ for (const [key, entry] of Object.entries(record)) {
194
+ if (key === "$schema") {
195
+ continue;
196
+ }
197
+ if (key === "additionalProperties" && entry === false && record.type === "object") {
198
+ continue;
199
+ }
200
+ sanitized[key] = sanitizeJsonSchema(entry);
201
+ }
202
+ return sanitized;
203
+ }
204
+ function findUnsupportedGeneratedKeyword(value, path) {
205
+ if (Array.isArray(value)) {
206
+ for (let index = 0; index < value.length; index += 1) {
207
+ const match = findUnsupportedGeneratedKeyword(value[index], `${path}[${index}]`);
208
+ if (match) {
209
+ return match;
210
+ }
211
+ }
212
+ return null;
213
+ }
214
+ if (!value || typeof value !== "object") {
215
+ return null;
216
+ }
217
+ for (const [key, entry] of Object.entries(value)) {
218
+ if (key === "$ref" || key === "$defs") {
219
+ return { keyword: key, path };
220
+ }
221
+ const match = findUnsupportedGeneratedKeyword(entry, joinPath(path, key));
222
+ if (match) {
223
+ return match;
224
+ }
225
+ }
226
+ return null;
227
+ }
228
+ export function zodToJsonSchema(schema) {
229
+ validateSchema(schema, "$");
230
+ const jsonSchema = schema.toJSONSchema?.();
231
+ if (!jsonSchema) {
232
+ throw new HostToolSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), "schema does not expose toJSONSchema()");
233
+ }
234
+ const unsupportedKeyword = findUnsupportedGeneratedKeyword(jsonSchema, "$");
235
+ if (unsupportedKeyword) {
236
+ throw new HostToolSchemaConversionError("$", displayTypeName(normalizeTypeName(schema)), `${unsupportedKeyword.keyword} emitted at ${unsupportedKeyword.path} is not supported`);
237
+ }
238
+ const sanitized = sanitizeJsonSchema(jsonSchema);
239
+ const description = getDescription(schema);
240
+ return description && typeof sanitized === "object" && sanitized !== null
241
+ ? { ...sanitized, description }
242
+ : sanitized;
243
+ }
@@ -0,0 +1,45 @@
1
+ import type { ZodType } from "zod";
2
+ /** Maximum length for tool and toolkit descriptions (characters). */
3
+ export declare const MAX_TOOL_DESCRIPTION_LENGTH = 200;
4
+ /**
5
+ * A single tool that executes on the host.
6
+ * Mirrors the shape of AI SDK's tool() but with host-execution semantics.
7
+ */
8
+ export interface HostTool<INPUT = any, OUTPUT = any> {
9
+ /** Description shown to the agent in --help and prompt docs. Max 200 characters. */
10
+ description: string;
11
+ /** Zod schema for the input. Drives CLI flag generation and validation. */
12
+ inputSchema: ZodType<INPUT>;
13
+ /** Runs on the host when the agent invokes the tool. */
14
+ execute: (input: INPUT) => Promise<OUTPUT> | OUTPUT;
15
+ /** Examples included in auto-generated prompt docs. */
16
+ examples?: ToolExample<INPUT>[];
17
+ /** Timeout in ms. Default: 30000. */
18
+ timeout?: number;
19
+ }
20
+ export interface ToolExample<INPUT = any> {
21
+ /** Human description of what this example does. */
22
+ description: string;
23
+ /** The input args for the example. */
24
+ input: INPUT;
25
+ }
26
+ /**
27
+ * A named group of tools. Becomes a CLI binary: agentos-{name}.
28
+ */
29
+ export interface ToolKit {
30
+ /** Toolkit name. Must be lowercase alphanumeric + hyphens. Becomes the CLI suffix: agentos-{name}. */
31
+ name: string;
32
+ /** Description shown in `agentos list-tools` and prompt docs. */
33
+ description: string;
34
+ /** The tools in this toolkit. Keys become subcommands. */
35
+ tools: Record<string, HostTool>;
36
+ }
37
+ /** Helper to create a HostTool with type inference. */
38
+ export declare function hostTool<INPUT, OUTPUT>(def: HostTool<INPUT, OUTPUT>): HostTool<INPUT, OUTPUT>;
39
+ /** Helper to create a ToolKit. */
40
+ export declare function toolKit(def: ToolKit): ToolKit;
41
+ /**
42
+ * Validate all description lengths in the given toolkits.
43
+ * Throws if any toolkit or tool description exceeds MAX_TOOL_DESCRIPTION_LENGTH.
44
+ */
45
+ export declare function validateToolkits(toolKits: ToolKit[]): void;
@@ -0,0 +1,26 @@
1
+ /** Maximum length for tool and toolkit descriptions (characters). */
2
+ export const MAX_TOOL_DESCRIPTION_LENGTH = 200;
3
+ /** Helper to create a HostTool with type inference. */
4
+ export function hostTool(def) {
5
+ return def;
6
+ }
7
+ /** Helper to create a ToolKit. */
8
+ export function toolKit(def) {
9
+ return def;
10
+ }
11
+ /**
12
+ * Validate all description lengths in the given toolkits.
13
+ * Throws if any toolkit or tool description exceeds MAX_TOOL_DESCRIPTION_LENGTH.
14
+ */
15
+ export function validateToolkits(toolKits) {
16
+ for (const tk of toolKits) {
17
+ if (tk.description.length > MAX_TOOL_DESCRIPTION_LENGTH) {
18
+ throw new Error(`Toolkit "${tk.name}" description is ${tk.description.length} characters, max is ${MAX_TOOL_DESCRIPTION_LENGTH}`);
19
+ }
20
+ for (const [toolName, tool] of Object.entries(tk.tools)) {
21
+ if (tool.description.length > MAX_TOOL_DESCRIPTION_LENGTH) {
22
+ throw new Error(`Tool "${tk.name}/${toolName}" description is ${tool.description.length} characters, max is ${MAX_TOOL_DESCRIPTION_LENGTH}`);
23
+ }
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ export { AgentOs, AgentOsSidecar } from "./agent-os.js";
2
+ export { AGENT_CONFIGS } from "./agents.js";
3
+ export { CronManager, InvalidScheduleError, PastScheduleError, TimerScheduleDriver, } from "./cron/index.js";
4
+ export { createHostDirBackend, nodeModulesMount } from "./host-dir-mount.js";
5
+ export { hostTool, MAX_TOOL_DESCRIPTION_LENGTH, toolKit, validateToolkits, } from "./host-tools.js";
6
+ export { createInMemoryLayerStore, createSnapshotExport, } from "./layers.js";
7
+ export { defineSoftware } from "./packages.js";
8
+ export { isAcpTimeoutErrorData, isUnknownSessionErrorData, } from "./json-rpc.js";
9
+ export { createInMemoryFileSystem, KernelError } from "./runtime-compat.js";
10
+ export type * from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ // @rivet-dev/agent-os
2
+ export { AgentOs, AgentOsSidecar } from "./agent-os.js";
3
+ export { AGENT_CONFIGS } from "./agents.js";
4
+ export { CronManager, InvalidScheduleError, PastScheduleError, TimerScheduleDriver, } from "./cron/index.js";
5
+ export { createHostDirBackend, nodeModulesMount } from "./host-dir-mount.js";
6
+ export { hostTool, MAX_TOOL_DESCRIPTION_LENGTH, toolKit, validateToolkits, } from "./host-tools.js";
7
+ export { createInMemoryLayerStore, createSnapshotExport, } from "./layers.js";
8
+ export { defineSoftware } from "./packages.js";
9
+ export { isAcpTimeoutErrorData, isUnknownSessionErrorData, } from "./json-rpc.js";
10
+ export { createInMemoryFileSystem, KernelError } from "./runtime-compat.js";