rivetkit 2.3.0-rc.9 → 2.3.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/dist/browser/client.d.ts +498 -62
- package/dist/browser/client.js +227 -171
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +50 -20
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/actor/errors.cjs +2 -2
- package/dist/tsup/actor/errors.d.cts +1 -1
- package/dist/tsup/actor/errors.d.ts +1 -1
- package/dist/tsup/actor/errors.js +1 -1
- package/dist/tsup/agent-os/index.cjs +2163 -2087
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +496 -69
- package/dist/tsup/agent-os/index.d.ts +496 -69
- package/dist/tsup/agent-os/index.js +2163 -2087
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-W7EYSYVI.js → chunk-2OTRTA3J.js} +134 -20
- package/dist/tsup/chunk-2OTRTA3J.js.map +1 -0
- package/dist/tsup/{chunk-VJFRBJVQ.cjs → chunk-3677IIOV.cjs} +138 -24
- package/dist/tsup/chunk-3677IIOV.cjs.map +1 -0
- package/dist/tsup/{chunk-4CGA6QJO.cjs → chunk-47HHIEXH.cjs} +24 -9
- package/dist/tsup/chunk-47HHIEXH.cjs.map +1 -0
- package/dist/tsup/{chunk-F3Q5BFQ6.js → chunk-4JDSFJS5.js} +66 -79
- package/dist/tsup/chunk-4JDSFJS5.js.map +1 -0
- package/dist/tsup/{chunk-GVTOE34S.cjs → chunk-7QKCIVAY.cjs} +222 -235
- package/dist/tsup/chunk-7QKCIVAY.cjs.map +1 -0
- package/dist/tsup/{chunk-CPA4Y3RG.cjs → chunk-B6VUNZUD.cjs} +10 -10
- package/dist/tsup/chunk-B6VUNZUD.cjs.map +1 -0
- package/dist/tsup/{chunk-H37XQU3I.js → chunk-BEI24WTI.js} +2 -2
- package/dist/tsup/{chunk-KIWH5H3K.js → chunk-BRP62GZC.js} +3 -3
- package/dist/tsup/chunk-BRP62GZC.js.map +1 -0
- package/dist/tsup/{chunk-T6YVRM4K.js → chunk-DPIMKYNB.js} +63 -2
- package/dist/tsup/chunk-DPIMKYNB.js.map +1 -0
- package/dist/tsup/{chunk-Y5NSCZA2.cjs → chunk-DXXJPH55.cjs} +44 -15
- package/dist/tsup/chunk-DXXJPH55.cjs.map +1 -0
- package/dist/tsup/{chunk-3YY5S6TV.js → chunk-HXUEHHJF.js} +2 -2
- package/dist/tsup/chunk-HXUEHHJF.js.map +1 -0
- package/dist/tsup/{chunk-4WPEZBK4.cjs → chunk-I4LN3FNT.cjs} +10 -10
- package/dist/tsup/chunk-I4LN3FNT.cjs.map +1 -0
- package/dist/tsup/{chunk-PCBNKI2J.js → chunk-JZ7TWV65.js} +1 -1
- package/dist/tsup/chunk-JZ7TWV65.js.map +1 -0
- package/dist/tsup/{chunk-QAZLM4WT.cjs → chunk-KORQB2IR.cjs} +3 -3
- package/dist/tsup/{chunk-QAZLM4WT.cjs.map → chunk-KORQB2IR.cjs.map} +1 -1
- package/dist/tsup/{chunk-MALSPBAF.cjs → chunk-LVTBW2RE.cjs} +3 -3
- package/dist/tsup/{chunk-MALSPBAF.cjs.map → chunk-LVTBW2RE.cjs.map} +1 -1
- package/dist/tsup/{chunk-H7P7WR2Y.js → chunk-MEHBWPLJ.js} +6 -6
- package/dist/tsup/chunk-MEHBWPLJ.js.map +1 -0
- package/dist/tsup/{chunk-WQ4HNA4W.cjs → chunk-NIY3RSPX.cjs} +64 -3
- package/dist/tsup/chunk-NIY3RSPX.cjs.map +1 -0
- package/dist/tsup/{chunk-MMMEZM5J.js → chunk-P2GNQ4RN.js} +4 -4
- package/dist/tsup/chunk-P2GNQ4RN.js.map +1 -0
- package/dist/tsup/{chunk-KJTA3ATT.js → chunk-UMZVD6DQ.js} +22 -7
- package/dist/tsup/chunk-UMZVD6DQ.js.map +1 -0
- package/dist/tsup/{chunk-LD5YASJU.cjs → chunk-VE2X4KMG.cjs} +2 -2
- package/dist/tsup/{chunk-LD5YASJU.cjs.map → chunk-VE2X4KMG.cjs.map} +1 -1
- package/dist/tsup/{chunk-VRCIXJRN.js → chunk-VTTFNQQI.js} +36 -7
- package/dist/tsup/chunk-VTTFNQQI.js.map +1 -0
- package/dist/tsup/{chunk-2NDZ7JCR.cjs → chunk-ZA7FLHKH.cjs} +1 -1
- package/dist/tsup/chunk-ZA7FLHKH.cjs.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +5 -5
- package/dist/tsup/client/mod.d.ts +5 -5
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{config-0Ta55UV0.d.ts → config-BxWAw3iH.d.ts} +529 -23
- package/dist/tsup/{config-Ca8dN4cS.d.cts → config-CZQQ-mso.d.cts} +529 -23
- package/dist/tsup/{config-CxjGYf4K.d.cts → config-D49x8NpL.d.cts} +1 -2
- package/dist/tsup/{config-CxjGYf4K.d.ts → config-D49x8NpL.d.ts} +1 -2
- package/dist/tsup/{context-B_IWbWne.d.ts → context-Bw7xq8w3.d.cts} +8 -8
- package/dist/tsup/{context-CUrQ9MHc.d.cts → context-D8QA76sV.d.ts} +8 -8
- package/dist/tsup/db/drizzle.cjs +3 -3
- package/dist/tsup/db/drizzle.d.cts +1 -1
- package/dist/tsup/db/drizzle.d.ts +1 -1
- package/dist/tsup/db/drizzle.js +1 -1
- package/dist/tsup/db/mod.cjs +2 -2
- package/dist/tsup/db/mod.d.cts +2 -2
- package/dist/tsup/db/mod.d.ts +2 -2
- package/dist/tsup/db/mod.js +1 -1
- package/dist/tsup/dynamic/mod.cjs +24 -0
- package/dist/tsup/dynamic/mod.cjs.map +1 -0
- package/dist/tsup/dynamic/mod.d.cts +37 -0
- package/dist/tsup/dynamic/mod.d.ts +37 -0
- package/dist/tsup/dynamic/mod.js +24 -0
- package/dist/tsup/dynamic/mod.js.map +1 -0
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/inspector-tab/mod.cjs +173 -0
- package/dist/tsup/inspector-tab/mod.cjs.map +1 -0
- package/dist/tsup/inspector-tab/mod.d.cts +250 -0
- package/dist/tsup/inspector-tab/mod.d.ts +250 -0
- package/dist/tsup/inspector-tab/mod.js +173 -0
- package/dist/tsup/inspector-tab/mod.js.map +1 -0
- package/dist/tsup/mod.cjs +730 -336
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +5 -5
- package/dist/tsup/mod.d.ts +5 -5
- package/dist/tsup/mod.js +633 -239
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +21 -18
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +4 -4
- package/dist/tsup/test/mod.d.ts +4 -4
- package/dist/tsup/test/mod.js +18 -15
- package/dist/tsup/test/mod.js.map +1 -1
- package/dist/tsup/{utils-DVekpm4I.d.cts → utils-DQosb24I.d.cts} +1 -1
- package/dist/tsup/{utils-DVekpm4I.d.ts → utils-DQosb24I.d.ts} +1 -1
- package/dist/tsup/utils.cjs +3 -3
- package/dist/tsup/utils.d.cts +1 -1
- package/dist/tsup/utils.d.ts +1 -1
- package/dist/tsup/utils.js +2 -2
- package/dist/tsup/workflow/mod.cjs +307 -282
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +6 -6
- package/dist/tsup/workflow/mod.d.ts +6 -6
- package/dist/tsup/workflow/mod.js +501 -476
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +32 -11
- package/src/actor/config.ts +159 -51
- package/src/actor/contexts/index.ts +7 -2
- package/src/actor/definition.ts +17 -19
- package/src/actor/driver.ts +3 -3
- package/src/actor/errors.ts +9 -3
- package/src/actor/instance/mod.ts +26 -34
- package/src/actor/keys.ts +1 -1
- package/src/actor/mod.ts +22 -20
- package/src/actor/schema.ts +2 -2
- package/src/agent-os/actor/index.ts +38 -18
- package/src/agent-os/actor/preview.ts +1 -2
- package/src/agent-os/actor/session.ts +2 -2
- package/src/agent-os/config.ts +1 -1
- package/src/agent-os/fs/database-vfs.ts +1 -1
- package/src/agent-os/index.ts +16 -15
- package/src/client/actor-common.ts +87 -54
- package/src/client/actor-conn.ts +8 -36
- package/src/client/actor-handle.ts +69 -51
- package/src/client/actor-query.ts +5 -5
- package/src/client/errors.ts +1 -1
- package/src/client/lifecycle-errors.ts +2 -4
- package/src/client/query.ts +1 -1
- package/src/client/queue.ts +8 -3
- package/src/client/raw-utils.ts +8 -6
- package/src/client/resolve-gateway-target.ts +1 -1
- package/src/client/utils.ts +2 -7
- package/src/common/actor-websocket.ts +3 -1
- package/src/common/bare/actor-persist/v1.ts +205 -163
- package/src/common/bare/actor-persist/v2.ts +265 -213
- package/src/common/bare/actor-persist/v3.ts +176 -172
- package/src/common/bare/actor-persist/v4.ts +254 -253
- package/src/common/bare/transport/v1.ts +659 -543
- package/src/common/client-protocol-versioned.ts +66 -64
- package/src/common/database/config.ts +2 -8
- package/src/common/database/native-database.ts +1 -1
- package/src/common/database/shared.ts +1 -0
- package/src/common/encoding.ts +250 -16
- package/src/common/engine.ts +28 -1
- package/src/common/eventsource.ts +1 -1
- package/src/common/inline-websocket-adapter.ts +14 -13
- package/src/common/log.ts +1 -0
- package/src/common/router.ts +13 -17
- package/src/common/utils.ts +1 -150
- package/src/common/websocket-interface.ts +1 -1
- package/src/db/mod.ts +1 -1
- package/src/devtools-loader/index.ts +4 -7
- package/src/devtools-loader/serve-devtools.ts +26 -0
- package/src/drivers/engine/actor-driver.ts +58 -56
- package/src/dynamic/instance.ts +32 -0
- package/src/dynamic/internal.ts +50 -0
- package/src/dynamic/isolate-runtime.ts +66 -0
- package/src/dynamic/mod.ts +32 -0
- package/src/engine-client/actor-http-client.ts +3 -3
- package/src/engine-client/actor-websocket-client.ts +6 -5
- package/src/engine-client/api-endpoints.ts +51 -2
- package/src/engine-client/api-utils.ts +2 -2
- package/src/engine-client/driver.ts +1 -1
- package/src/engine-client/mod.ts +6 -3
- package/src/engine-client/ws-proxy.ts +9 -4
- package/src/inspector/client.browser.ts +5 -11
- package/src/inspector/mod.ts +1 -3
- package/src/inspector-tab/mod.ts +315 -0
- package/src/registry/config/envoy.ts +1 -2
- package/src/registry/config/index.ts +40 -16
- package/src/registry/index.ts +154 -74
- package/src/registry/napi-runtime.ts +13 -2
- package/src/registry/native-validation.ts +10 -12
- package/src/registry/native.ts +367 -181
- package/src/registry/process-metrics.ts +250 -0
- package/src/registry/runtime.ts +41 -1
- package/src/registry/wasm-runtime.ts +18 -2
- package/src/registry/write-through-proxy.ts +40 -0
- package/src/serde.ts +2 -2
- package/src/serverless/configure.ts +18 -7
- package/src/test/mod.ts +11 -8
- package/src/utils/endpoint-parser.ts +1 -1
- package/src/utils/env-vars.ts +6 -0
- package/src/utils/router.ts +1 -1
- package/src/utils/serve.ts +4 -5
- package/src/utils.ts +1 -2
- package/src/workflow/context.ts +61 -33
- package/src/workflow/driver.ts +4 -6
- package/src/workflow/inspector.ts +4 -3
- package/src/workflow/mod.ts +15 -17
- package/dist/tsup/chunk-2NDZ7JCR.cjs.map +0 -1
- package/dist/tsup/chunk-3YY5S6TV.js.map +0 -1
- package/dist/tsup/chunk-4CGA6QJO.cjs.map +0 -1
- package/dist/tsup/chunk-4WPEZBK4.cjs.map +0 -1
- package/dist/tsup/chunk-CPA4Y3RG.cjs.map +0 -1
- package/dist/tsup/chunk-F3Q5BFQ6.js.map +0 -1
- package/dist/tsup/chunk-GVTOE34S.cjs.map +0 -1
- package/dist/tsup/chunk-H7P7WR2Y.js.map +0 -1
- package/dist/tsup/chunk-KIWH5H3K.js.map +0 -1
- package/dist/tsup/chunk-KJTA3ATT.js.map +0 -1
- package/dist/tsup/chunk-MMMEZM5J.js.map +0 -1
- package/dist/tsup/chunk-PCBNKI2J.js.map +0 -1
- package/dist/tsup/chunk-T6YVRM4K.js.map +0 -1
- package/dist/tsup/chunk-VJFRBJVQ.cjs.map +0 -1
- package/dist/tsup/chunk-VRCIXJRN.js.map +0 -1
- package/dist/tsup/chunk-W7EYSYVI.js.map +0 -1
- package/dist/tsup/chunk-WQ4HNA4W.cjs.map +0 -1
- package/dist/tsup/chunk-Y5NSCZA2.cjs.map +0 -1
- /package/dist/tsup/{chunk-H37XQU3I.js.map → chunk-BEI24WTI.js.map} +0 -0
|
@@ -1,1394 +1,1812 @@
|
|
|
1
|
-
// src/agent-os/actor/
|
|
2
|
-
|
|
3
|
-
await db2.execute(`
|
|
4
|
-
CREATE TABLE IF NOT EXISTS agent_os_preview_tokens (
|
|
5
|
-
token TEXT PRIMARY KEY,
|
|
6
|
-
port INTEGER NOT NULL,
|
|
7
|
-
created_at INTEGER NOT NULL,
|
|
8
|
-
expires_at INTEGER NOT NULL
|
|
9
|
-
);
|
|
10
|
-
|
|
11
|
-
CREATE INDEX IF NOT EXISTS idx_preview_tokens_expires_at
|
|
12
|
-
ON agent_os_preview_tokens(expires_at);
|
|
13
|
-
|
|
14
|
-
CREATE TABLE IF NOT EXISTS agent_os_fs_entries (
|
|
15
|
-
path TEXT PRIMARY KEY,
|
|
16
|
-
is_directory INTEGER NOT NULL DEFAULT 0,
|
|
17
|
-
content BLOB,
|
|
18
|
-
mode INTEGER NOT NULL DEFAULT 33188,
|
|
19
|
-
uid INTEGER NOT NULL DEFAULT 0,
|
|
20
|
-
gid INTEGER NOT NULL DEFAULT 0,
|
|
21
|
-
size INTEGER NOT NULL DEFAULT 0,
|
|
22
|
-
atime_ms INTEGER NOT NULL,
|
|
23
|
-
mtime_ms INTEGER NOT NULL,
|
|
24
|
-
ctime_ms INTEGER NOT NULL,
|
|
25
|
-
birthtime_ms INTEGER NOT NULL,
|
|
26
|
-
symlink_target TEXT,
|
|
27
|
-
nlink INTEGER NOT NULL DEFAULT 1
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
CREATE INDEX IF NOT EXISTS idx_fs_entries_parent
|
|
31
|
-
ON agent_os_fs_entries(path);
|
|
32
|
-
|
|
33
|
-
CREATE TABLE IF NOT EXISTS agent_os_sessions (
|
|
34
|
-
session_id TEXT PRIMARY KEY,
|
|
35
|
-
agent_type TEXT NOT NULL,
|
|
36
|
-
capabilities TEXT NOT NULL,
|
|
37
|
-
agent_info TEXT,
|
|
38
|
-
created_at INTEGER NOT NULL
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
CREATE TABLE IF NOT EXISTS agent_os_session_events (
|
|
42
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
-
session_id TEXT NOT NULL,
|
|
44
|
-
seq INTEGER NOT NULL,
|
|
45
|
-
event TEXT NOT NULL,
|
|
46
|
-
created_at INTEGER NOT NULL,
|
|
47
|
-
FOREIGN KEY (session_id) REFERENCES agent_os_sessions(session_id) ON DELETE CASCADE
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
CREATE INDEX IF NOT EXISTS idx_session_events_session_seq
|
|
51
|
-
ON agent_os_session_events(session_id, seq);
|
|
52
|
-
`);
|
|
53
|
-
}
|
|
1
|
+
// src/agent-os/actor/index.ts
|
|
2
|
+
import { AgentOs, createInMemoryFileSystem } from "@rivet-dev/agent-os-core";
|
|
54
3
|
|
|
55
|
-
// src/
|
|
56
|
-
import
|
|
57
|
-
var
|
|
58
|
-
var
|
|
59
|
-
var
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
birthtimeMs: row.birthtime_ms,
|
|
113
|
-
ino: 0,
|
|
114
|
-
nlink: row.nlink,
|
|
115
|
-
uid: row.uid,
|
|
116
|
-
gid: row.gid
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function createDatabaseVfs(options) {
|
|
120
|
-
const { db: db2 } = options;
|
|
121
|
-
async function getEntry(path) {
|
|
122
|
-
const rows = await db2.execute(
|
|
123
|
-
"SELECT * FROM agent_os_fs_entries WHERE path = ?",
|
|
124
|
-
path
|
|
4
|
+
// src/actor/config.ts
|
|
5
|
+
import { z } from "zod/v4";
|
|
6
|
+
var DEFAULT_SLEEP_GRACE_PERIOD = 15e3;
|
|
7
|
+
var zFunction = () => z.custom((val) => typeof val === "function");
|
|
8
|
+
var WorkflowInspectorConfigSchema = z.object({
|
|
9
|
+
getHistory: zFunction(),
|
|
10
|
+
onHistoryUpdated: zFunction().optional(),
|
|
11
|
+
replayFromStep: zFunction().optional()
|
|
12
|
+
});
|
|
13
|
+
var RunInspectorConfigSchema = z.object({
|
|
14
|
+
workflow: WorkflowInspectorConfigSchema.optional()
|
|
15
|
+
}).optional();
|
|
16
|
+
var BUILTIN_INSPECTOR_TAB_IDS = [
|
|
17
|
+
"workflow",
|
|
18
|
+
"database",
|
|
19
|
+
"state",
|
|
20
|
+
"queue",
|
|
21
|
+
"connections",
|
|
22
|
+
"console"
|
|
23
|
+
];
|
|
24
|
+
var BuiltinInspectorTabIdSchema = z.enum(BUILTIN_INSPECTOR_TAB_IDS);
|
|
25
|
+
var CUSTOM_INSPECTOR_TAB_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
26
|
+
var CustomInspectorTabEntrySchema = z.object({
|
|
27
|
+
id: z.string().regex(
|
|
28
|
+
CUSTOM_INSPECTOR_TAB_ID_RE,
|
|
29
|
+
"inspector.tabs[].id must contain only letters, digits, underscore, or dash"
|
|
30
|
+
),
|
|
31
|
+
label: z.string().min(1),
|
|
32
|
+
source: z.string().min(1),
|
|
33
|
+
/**
|
|
34
|
+
* Optional icon id. The dashboard maps strings to glyphs (see its
|
|
35
|
+
* icon registry); unknown ids fall back to a generic icon.
|
|
36
|
+
*/
|
|
37
|
+
icon: z.string().min(1).optional(),
|
|
38
|
+
hidden: z.literal(false).optional()
|
|
39
|
+
}).strict();
|
|
40
|
+
var HideInspectorTabEntrySchema = z.object({
|
|
41
|
+
id: BuiltinInspectorTabIdSchema,
|
|
42
|
+
hidden: z.literal(true)
|
|
43
|
+
}).strict();
|
|
44
|
+
var InspectorTabEntrySchema = z.union([
|
|
45
|
+
CustomInspectorTabEntrySchema,
|
|
46
|
+
HideInspectorTabEntrySchema
|
|
47
|
+
]);
|
|
48
|
+
var ActorInspectorConfigSchema = z.object({
|
|
49
|
+
tabs: z.array(InspectorTabEntrySchema).default(() => [])
|
|
50
|
+
}).strict().refine(
|
|
51
|
+
(data) => {
|
|
52
|
+
const ids = data.tabs.map((t) => t.id);
|
|
53
|
+
return new Set(ids).size === ids.length;
|
|
54
|
+
},
|
|
55
|
+
{ message: "Duplicate id in inspector.tabs", path: ["tabs"] }
|
|
56
|
+
).refine(
|
|
57
|
+
(data) => {
|
|
58
|
+
const builtinSet = new Set(BUILTIN_INSPECTOR_TAB_IDS);
|
|
59
|
+
return data.tabs.every(
|
|
60
|
+
(t) => t.hidden === true || !builtinSet.has(t.id)
|
|
125
61
|
);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (!entry) {
|
|
131
|
-
throwENOENT(path);
|
|
132
|
-
}
|
|
133
|
-
return entry;
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
message: "Custom inspector tab id collides with a built-in (use hidden: true to hide a built-in)",
|
|
65
|
+
path: ["tabs"]
|
|
134
66
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
67
|
+
);
|
|
68
|
+
var RunConfigSchema = z.object({
|
|
69
|
+
/** Display name for the actor in the Inspector UI. */
|
|
70
|
+
name: z.string().optional(),
|
|
71
|
+
/** Icon for the actor in the Inspector UI. Can be an emoji or FontAwesome icon name. */
|
|
72
|
+
icon: z.string().optional(),
|
|
73
|
+
/** The run handler function. */
|
|
74
|
+
run: zFunction(),
|
|
75
|
+
/** Inspector integration for long-running run handlers. */
|
|
76
|
+
inspector: RunInspectorConfigSchema.optional()
|
|
77
|
+
});
|
|
78
|
+
var zRunHandler = z.union([zFunction(), RunConfigSchema]).optional();
|
|
79
|
+
var GlobalActorOptionsBaseSchema = z.object({
|
|
80
|
+
/** Display name for the actor in the Inspector UI. */
|
|
81
|
+
name: z.string().optional(),
|
|
82
|
+
/** Icon for the actor in the Inspector UI. Can be an emoji or FontAwesome icon name. */
|
|
83
|
+
icon: z.string().optional(),
|
|
84
|
+
/**
|
|
85
|
+
* Can hibernate WebSockets for onWebSocket.
|
|
86
|
+
*
|
|
87
|
+
* WebSockets using actions/events are hibernatable by default.
|
|
88
|
+
*
|
|
89
|
+
* @experimental
|
|
90
|
+
**/
|
|
91
|
+
canHibernateWebSocket: z.union([z.boolean(), zFunction()]).default(false)
|
|
92
|
+
}).strict();
|
|
93
|
+
var GlobalActorOptionsSchema = GlobalActorOptionsBaseSchema.prefault(
|
|
94
|
+
() => ({})
|
|
95
|
+
);
|
|
96
|
+
var InstanceActorOptionsBaseSchema = z.object({
|
|
97
|
+
createVarsTimeout: z.number().positive().default(5e3),
|
|
98
|
+
createConnStateTimeout: z.number().positive().default(5e3),
|
|
99
|
+
onBeforeConnectTimeout: z.number().positive().default(5e3),
|
|
100
|
+
onConnectTimeout: z.number().positive().default(5e3),
|
|
101
|
+
onMigrateTimeout: z.number().positive().default(3e4),
|
|
102
|
+
sleepGracePeriod: z.number().positive().default(DEFAULT_SLEEP_GRACE_PERIOD),
|
|
103
|
+
/** @deprecated `onDestroyTimeout` is folded into `sleepGracePeriod`, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0. */
|
|
104
|
+
onDestroyTimeout: z.number().positive().optional(),
|
|
105
|
+
/** @deprecated `waitUntilTimeout` is folded into `sleepGracePeriod`, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0. */
|
|
106
|
+
waitUntilTimeout: z.number().positive().optional(),
|
|
107
|
+
stateSaveInterval: z.number().positive().default(1e3),
|
|
108
|
+
actionTimeout: z.number().positive().default(6e4),
|
|
109
|
+
connectionLivenessTimeout: z.number().positive().default(2500),
|
|
110
|
+
connectionLivenessInterval: z.number().positive().default(5e3),
|
|
111
|
+
/** @deprecated Use `c.keepAwake(promise)` to scope keep-awake to a specific operation, or keep `noSleep` for actors that must stay awake indefinitely. Will be removed in 2.2.0. */
|
|
112
|
+
noSleep: z.boolean().default(false),
|
|
113
|
+
sleepTimeout: z.number().positive().default(3e4),
|
|
114
|
+
maxQueueSize: z.number().positive().default(1e3),
|
|
115
|
+
maxQueueMessageSize: z.number().positive().default(64 * 1024),
|
|
116
|
+
/** Override RivetKit's workflow preload budget for this actor. Set to 0 to disable workflow preloading. */
|
|
117
|
+
preloadMaxWorkflowBytes: z.number().nonnegative().optional(),
|
|
118
|
+
/** Override RivetKit's connections preload budget for this actor. Set to 0 to disable connections preloading. */
|
|
119
|
+
preloadMaxConnectionsBytes: z.number().nonnegative().optional()
|
|
120
|
+
}).strict();
|
|
121
|
+
var InstanceActorOptionsSchema = InstanceActorOptionsBaseSchema.prefault(() => ({}));
|
|
122
|
+
var ActorOptionsSchema = GlobalActorOptionsBaseSchema.extend(
|
|
123
|
+
InstanceActorOptionsBaseSchema.shape
|
|
124
|
+
).strict().prefault(() => ({}));
|
|
125
|
+
var ActorConfigSchema = z.object({
|
|
126
|
+
onCreate: zFunction().optional(),
|
|
127
|
+
onDestroy: zFunction().optional(),
|
|
128
|
+
onMigrate: zFunction().optional(),
|
|
129
|
+
onWake: zFunction().optional(),
|
|
130
|
+
onSleep: zFunction().optional(),
|
|
131
|
+
run: zRunHandler,
|
|
132
|
+
onStateChange: zFunction().optional(),
|
|
133
|
+
onBeforeConnect: zFunction().optional(),
|
|
134
|
+
onConnect: zFunction().optional(),
|
|
135
|
+
onDisconnect: zFunction().optional(),
|
|
136
|
+
onBeforeActionResponse: zFunction().optional(),
|
|
137
|
+
onRequest: zFunction().optional(),
|
|
138
|
+
onWebSocket: zFunction().optional(),
|
|
139
|
+
actions: z.record(z.string(), zFunction()).default(() => ({})),
|
|
140
|
+
actionInputSchemas: z.record(z.string(), z.any()).optional(),
|
|
141
|
+
connParamsSchema: z.any().optional(),
|
|
142
|
+
events: z.record(z.string(), z.any()).optional(),
|
|
143
|
+
queues: z.record(z.string(), z.any()).optional(),
|
|
144
|
+
state: z.any().optional(),
|
|
145
|
+
createState: zFunction().optional(),
|
|
146
|
+
connState: z.any().optional(),
|
|
147
|
+
createConnState: zFunction().optional(),
|
|
148
|
+
vars: z.any().optional(),
|
|
149
|
+
db: z.any().optional(),
|
|
150
|
+
createVars: zFunction().optional(),
|
|
151
|
+
options: ActorOptionsSchema,
|
|
152
|
+
inspector: ActorInspectorConfigSchema.optional()
|
|
153
|
+
}).strict().refine(
|
|
154
|
+
(data) => !(data.state !== void 0 && data.createState !== void 0),
|
|
155
|
+
{
|
|
156
|
+
message: "Cannot define both 'state' and 'createState'",
|
|
157
|
+
path: ["state"]
|
|
145
158
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
dirPath
|
|
152
|
-
);
|
|
153
|
-
return rows.filter((row) => {
|
|
154
|
-
const relative = row.path.slice(prefix.length);
|
|
155
|
-
return relative.length > 0 && !relative.includes("/");
|
|
156
|
-
});
|
|
159
|
+
).refine(
|
|
160
|
+
(data) => !(data.connState !== void 0 && data.createConnState !== void 0),
|
|
161
|
+
{
|
|
162
|
+
message: "Cannot define both 'connState' and 'createConnState'",
|
|
163
|
+
path: ["connState"]
|
|
157
164
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
165
|
+
).refine(
|
|
166
|
+
(data) => !(data.vars !== void 0 && data.createVars !== void 0),
|
|
167
|
+
{
|
|
168
|
+
message: "Cannot define both 'vars' and 'createVars'",
|
|
169
|
+
path: ["vars"]
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
var DocActorOptionsSchema = z.object({
|
|
173
|
+
name: z.string().optional().describe("Display name for the actor in the Inspector UI."),
|
|
174
|
+
icon: z.string().optional().describe(
|
|
175
|
+
"Icon for the actor in the Inspector UI. Can be an emoji (e.g., '\u{1F680}') or FontAwesome icon name (e.g., 'rocket')."
|
|
176
|
+
),
|
|
177
|
+
createVarsTimeout: z.number().optional().describe("Timeout in ms for createVars handler. Default: 5000"),
|
|
178
|
+
createConnStateTimeout: z.number().optional().describe(
|
|
179
|
+
"Timeout in ms for createConnState handler. Default: 5000"
|
|
180
|
+
),
|
|
181
|
+
onMigrateTimeout: z.number().optional().describe("Timeout in ms for onMigrate handler. Default: 30000"),
|
|
182
|
+
onBeforeConnectTimeout: z.number().optional().describe(
|
|
183
|
+
"Timeout in ms for onBeforeConnect handler. Default: 5000"
|
|
184
|
+
),
|
|
185
|
+
onConnectTimeout: z.number().optional().describe("Timeout in ms for onConnect handler. Default: 5000"),
|
|
186
|
+
sleepGracePeriod: z.number().optional().describe(
|
|
187
|
+
`Max time in ms for the graceful shutdown window. Covers lifecycle hooks (onSleep, onDestroy), the run handler wait, async raw WebSocket handlers, disconnect callbacks, and final state serialization. Default: ${DEFAULT_SLEEP_GRACE_PERIOD}.`
|
|
188
|
+
),
|
|
189
|
+
onDestroyTimeout: z.number().optional().describe(
|
|
190
|
+
"Deprecated. Folded into sleepGracePeriod, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0."
|
|
191
|
+
),
|
|
192
|
+
waitUntilTimeout: z.number().optional().describe(
|
|
193
|
+
"Deprecated. Folded into sleepGracePeriod, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0."
|
|
194
|
+
),
|
|
195
|
+
stateSaveInterval: z.number().optional().describe(
|
|
196
|
+
"Interval in ms between automatic state saves. Default: 1000"
|
|
197
|
+
),
|
|
198
|
+
actionTimeout: z.number().optional().describe("Timeout in ms for action handlers. Default: 60000"),
|
|
199
|
+
connectionLivenessTimeout: z.number().optional().describe(
|
|
200
|
+
"Timeout in ms for connection liveness checks. Default: 2500"
|
|
201
|
+
),
|
|
202
|
+
connectionLivenessInterval: z.number().optional().describe(
|
|
203
|
+
"Interval in ms between connection liveness checks. Default: 5000"
|
|
204
|
+
),
|
|
205
|
+
noSleep: z.boolean().optional().describe(
|
|
206
|
+
"Deprecated. If true, the actor will never sleep. Use c.keepAwake(promise) to scope keep-awake to a specific operation instead. Default: false"
|
|
207
|
+
),
|
|
208
|
+
sleepTimeout: z.number().optional().describe(
|
|
209
|
+
"Time in ms of inactivity before the actor sleeps. Default: 30000"
|
|
210
|
+
),
|
|
211
|
+
maxQueueSize: z.number().optional().describe(
|
|
212
|
+
"Maximum number of queue messages before rejecting new messages. Default: 1000"
|
|
213
|
+
),
|
|
214
|
+
maxQueueMessageSize: z.number().optional().describe(
|
|
215
|
+
"Maximum size of each queue message in bytes. Default: 65536"
|
|
216
|
+
),
|
|
217
|
+
canHibernateWebSocket: z.boolean().optional().describe(
|
|
218
|
+
"Whether WebSockets using onWebSocket can be hibernated. WebSockets using actions/events are hibernatable by default. Default: false"
|
|
219
|
+
),
|
|
220
|
+
preloadMaxWorkflowBytes: z.number().optional().describe(
|
|
221
|
+
"Override RivetKit's workflow preload budget for this actor. Set to 0 to disable workflow preloading."
|
|
222
|
+
),
|
|
223
|
+
preloadMaxConnectionsBytes: z.number().optional().describe(
|
|
224
|
+
"Override RivetKit's connections preload budget for this actor. Set to 0 to disable connections preloading."
|
|
225
|
+
)
|
|
226
|
+
}).describe("Actor options for timeouts and behavior configuration.");
|
|
227
|
+
var DocActorConfigSchema = z.object({
|
|
228
|
+
state: z.unknown().optional().describe(
|
|
229
|
+
"Initial state value for the actor. Cannot be used with createState."
|
|
230
|
+
),
|
|
231
|
+
createState: z.unknown().optional().describe(
|
|
232
|
+
"Function to create initial state. Receives context and input. Cannot be used with state."
|
|
233
|
+
),
|
|
234
|
+
connState: z.unknown().optional().describe(
|
|
235
|
+
"Initial connection state value. Cannot be used with createConnState."
|
|
236
|
+
),
|
|
237
|
+
createConnState: z.unknown().optional().describe(
|
|
238
|
+
"Function to create connection state. Receives context and connection params. The pending connection is not visible in c.conns until this succeeds. Cannot be used with connState."
|
|
239
|
+
),
|
|
240
|
+
vars: z.unknown().optional().describe(
|
|
241
|
+
"Initial ephemeral variables value. Cannot be used with createVars."
|
|
242
|
+
),
|
|
243
|
+
createVars: z.unknown().optional().describe(
|
|
244
|
+
"Function to create ephemeral variables. Receives context and driver context. Cannot be used with vars."
|
|
245
|
+
),
|
|
246
|
+
db: z.unknown().optional().describe("Database provider instance for the actor."),
|
|
247
|
+
onCreate: z.unknown().optional().describe(
|
|
248
|
+
"Called when the actor is first initialized. Use to initialize state."
|
|
249
|
+
),
|
|
250
|
+
onDestroy: z.unknown().optional().describe("Called when the actor is destroyed."),
|
|
251
|
+
onMigrate: z.unknown().optional().describe(
|
|
252
|
+
"Called on every actor start after persisted state loads and before onWake. Use for repeatable schema migrations."
|
|
253
|
+
),
|
|
254
|
+
onWake: z.unknown().optional().describe(
|
|
255
|
+
"Called when the actor wakes up and is ready to receive connections and actions."
|
|
256
|
+
),
|
|
257
|
+
onSleep: z.unknown().optional().describe(
|
|
258
|
+
"Called when the actor is stopping or sleeping. Use to clean up resources."
|
|
259
|
+
),
|
|
260
|
+
run: z.unknown().optional().describe(
|
|
261
|
+
"Called after actor starts. Does not block startup. Use for background tasks like queue processing or tick loops. If it exits, the actor follows the normal idle sleep timeout once idle. If it throws, the actor logs the error and then follows the normal idle sleep timeout once idle."
|
|
262
|
+
),
|
|
263
|
+
onStateChange: z.unknown().optional().describe(
|
|
264
|
+
"Called when the actor's state changes. State changes within this hook won't trigger recursion."
|
|
265
|
+
),
|
|
266
|
+
onBeforeConnect: z.unknown().optional().describe(
|
|
267
|
+
"Called before a client connects. Throw an error to reject the connection. The pending connection is not visible in c.conns while this runs."
|
|
268
|
+
),
|
|
269
|
+
onConnect: z.unknown().optional().describe(
|
|
270
|
+
"Called when a client successfully connects. The connection is visible in c.conns before this runs."
|
|
271
|
+
),
|
|
272
|
+
onDisconnect: z.unknown().optional().describe("Called when a client disconnects."),
|
|
273
|
+
onBeforeActionResponse: z.unknown().optional().describe(
|
|
274
|
+
"Called before sending an action response. Use to transform output."
|
|
275
|
+
),
|
|
276
|
+
onRequest: z.unknown().optional().describe(
|
|
277
|
+
"Called for raw HTTP requests to /actors/{name}/http/* endpoints."
|
|
278
|
+
),
|
|
279
|
+
onWebSocket: z.unknown().optional().describe(
|
|
280
|
+
"Called for raw WebSocket connections to /actors/{name}/websocket/* endpoints."
|
|
281
|
+
),
|
|
282
|
+
actions: z.record(z.string(), z.unknown()).optional().describe(
|
|
283
|
+
"Map of action name to handler function. Defaults to an empty object."
|
|
284
|
+
),
|
|
285
|
+
actionInputSchemas: z.record(z.string(), z.unknown()).optional().describe(
|
|
286
|
+
"Optional schema map for validating action argument tuples in native runtimes."
|
|
287
|
+
),
|
|
288
|
+
connParamsSchema: z.unknown().optional().describe(
|
|
289
|
+
"Optional schema for validating connection params in native runtimes."
|
|
290
|
+
),
|
|
291
|
+
events: z.record(z.string(), z.unknown()).optional().describe("Map of event names to schemas."),
|
|
292
|
+
queues: z.record(z.string(), z.unknown()).optional().describe("Map of queue names to schemas."),
|
|
293
|
+
options: DocActorOptionsSchema.optional()
|
|
294
|
+
}).describe("Actor configuration passed to the actor() function.");
|
|
295
|
+
|
|
296
|
+
// src/common/log.ts
|
|
297
|
+
import {
|
|
298
|
+
pino,
|
|
299
|
+
stdTimeFunctions
|
|
300
|
+
} from "pino";
|
|
301
|
+
import { z as z2 } from "zod/v4";
|
|
302
|
+
|
|
303
|
+
// src/actor/errors.ts
|
|
304
|
+
function isTypedErrorTag(value) {
|
|
305
|
+
return value === "ActorError" || value === "RivetError";
|
|
306
|
+
}
|
|
307
|
+
function isRivetErrorLike(error) {
|
|
308
|
+
return typeof error === "object" && error !== null && "group" in error && typeof error.group === "string" && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string" && (!("__type" in error) || isTypedErrorTag(error.__type));
|
|
309
|
+
}
|
|
310
|
+
function isRivetErrorCode(error, group, code) {
|
|
311
|
+
return isRivetErrorLike(error) && error.group === group && error.code === code;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// package.json
|
|
315
|
+
var package_default = {
|
|
316
|
+
name: "rivetkit",
|
|
317
|
+
version: "2.3.0",
|
|
318
|
+
description: "Lightweight libraries for building stateful actors on edge platforms",
|
|
319
|
+
license: "Apache-2.0",
|
|
320
|
+
keywords: [
|
|
321
|
+
"rivetkit",
|
|
322
|
+
"stateful",
|
|
323
|
+
"serverless",
|
|
324
|
+
"actors",
|
|
325
|
+
"agents",
|
|
326
|
+
"realtime",
|
|
327
|
+
"websocket",
|
|
328
|
+
"actors",
|
|
329
|
+
"framework"
|
|
330
|
+
],
|
|
331
|
+
files: [
|
|
332
|
+
"dist",
|
|
333
|
+
"schemas",
|
|
334
|
+
"src",
|
|
335
|
+
"package.json"
|
|
336
|
+
],
|
|
337
|
+
type: "module",
|
|
338
|
+
exports: {
|
|
339
|
+
".": {
|
|
340
|
+
import: {
|
|
341
|
+
types: "./dist/tsup/mod.d.ts",
|
|
342
|
+
default: "./dist/tsup/mod.js"
|
|
343
|
+
},
|
|
344
|
+
require: {
|
|
345
|
+
types: "./dist/tsup/mod.d.cts",
|
|
346
|
+
default: "./dist/tsup/mod.cjs"
|
|
180
347
|
}
|
|
181
|
-
return entry.content ?? new Uint8Array(0);
|
|
182
|
-
},
|
|
183
|
-
async readTextFile(p) {
|
|
184
|
-
const data = await backend.readFile(p);
|
|
185
|
-
return new TextDecoder().decode(data);
|
|
186
348
|
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
349
|
+
"./workflow": {
|
|
350
|
+
import: {
|
|
351
|
+
types: "./dist/tsup/workflow/mod.d.ts",
|
|
352
|
+
default: "./dist/tsup/workflow/mod.js"
|
|
353
|
+
},
|
|
354
|
+
require: {
|
|
355
|
+
types: "./dist/tsup/workflow/mod.d.cts",
|
|
356
|
+
default: "./dist/tsup/workflow/mod.cjs"
|
|
193
357
|
}
|
|
194
|
-
const children = await getChildEntries(path);
|
|
195
|
-
return children.map((child) => posixPath.basename(child.path));
|
|
196
358
|
},
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
359
|
+
"./test": {
|
|
360
|
+
import: {
|
|
361
|
+
types: "./dist/tsup/test/mod.d.ts",
|
|
362
|
+
default: "./dist/tsup/test/mod.js"
|
|
363
|
+
},
|
|
364
|
+
require: {
|
|
365
|
+
types: "./dist/tsup/test/mod.d.cts",
|
|
366
|
+
default: "./dist/tsup/test/mod.cjs"
|
|
203
367
|
}
|
|
204
|
-
const children = await getChildEntries(path);
|
|
205
|
-
return children.map((child) => ({
|
|
206
|
-
name: posixPath.basename(child.path),
|
|
207
|
-
isDirectory: child.is_directory === 1,
|
|
208
|
-
isSymbolicLink: child.symlink_target !== null,
|
|
209
|
-
ino: 0
|
|
210
|
-
}));
|
|
211
368
|
},
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
221
|
-
const now = Date.now();
|
|
222
|
-
if (existing) {
|
|
223
|
-
await db2.execute(
|
|
224
|
-
`UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ?, atime_ms = ? WHERE path = ?`,
|
|
225
|
-
data,
|
|
226
|
-
data.byteLength,
|
|
227
|
-
now,
|
|
228
|
-
now,
|
|
229
|
-
now,
|
|
230
|
-
path
|
|
231
|
-
);
|
|
232
|
-
} else {
|
|
233
|
-
await db2.execute(
|
|
234
|
-
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 0, ?, ?, 0, 0, ?, ?, ?, ?, ?, NULL, 1)`,
|
|
235
|
-
path,
|
|
236
|
-
data,
|
|
237
|
-
DEFAULT_FILE_MODE,
|
|
238
|
-
data.byteLength,
|
|
239
|
-
now,
|
|
240
|
-
now,
|
|
241
|
-
now,
|
|
242
|
-
now
|
|
243
|
-
);
|
|
369
|
+
"./db": {
|
|
370
|
+
import: {
|
|
371
|
+
types: "./dist/tsup/db/mod.d.ts",
|
|
372
|
+
default: "./dist/tsup/db/mod.js"
|
|
373
|
+
},
|
|
374
|
+
require: {
|
|
375
|
+
types: "./dist/tsup/db/mod.d.cts",
|
|
376
|
+
default: "./dist/tsup/db/mod.cjs"
|
|
244
377
|
}
|
|
245
378
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
379
|
+
"./db/drizzle": {
|
|
380
|
+
import: {
|
|
381
|
+
types: "./dist/tsup/db/drizzle.d.ts",
|
|
382
|
+
default: "./dist/tsup/db/drizzle.js"
|
|
383
|
+
},
|
|
384
|
+
require: {
|
|
385
|
+
types: "./dist/tsup/db/drizzle.d.cts",
|
|
386
|
+
default: "./dist/tsup/db/drizzle.cjs"
|
|
253
387
|
}
|
|
254
|
-
const now = Date.now();
|
|
255
|
-
await db2.execute(
|
|
256
|
-
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 1, NULL, ?, 0, 0, 0, ?, ?, ?, ?, NULL, 2)`,
|
|
257
|
-
path,
|
|
258
|
-
DEFAULT_DIR_MODE,
|
|
259
|
-
now,
|
|
260
|
-
now,
|
|
261
|
-
now,
|
|
262
|
-
now
|
|
263
|
-
);
|
|
264
388
|
},
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const existing = await getEntry(current);
|
|
274
|
-
if (!existing) {
|
|
275
|
-
const now = Date.now();
|
|
276
|
-
await db2.execute(
|
|
277
|
-
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 1, NULL, ?, 0, 0, 0, ?, ?, ?, ?, NULL, 2)`,
|
|
278
|
-
current,
|
|
279
|
-
DEFAULT_DIR_MODE,
|
|
280
|
-
now,
|
|
281
|
-
now,
|
|
282
|
-
now,
|
|
283
|
-
now
|
|
284
|
-
);
|
|
285
|
-
} else if (existing.is_directory !== 1) {
|
|
286
|
-
throwENOTDIR(current);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
} else {
|
|
290
|
-
await backend.createDir(p);
|
|
389
|
+
"./dynamic": {
|
|
390
|
+
import: {
|
|
391
|
+
types: "./dist/tsup/dynamic/mod.d.ts",
|
|
392
|
+
default: "./dist/tsup/dynamic/mod.js"
|
|
393
|
+
},
|
|
394
|
+
require: {
|
|
395
|
+
types: "./dist/tsup/dynamic/mod.d.cts",
|
|
396
|
+
default: "./dist/tsup/dynamic/mod.cjs"
|
|
291
397
|
}
|
|
292
398
|
},
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
async removeFile(p) {
|
|
306
|
-
await rootInit;
|
|
307
|
-
const path = normPath(p);
|
|
308
|
-
const entry = await getEntryOrThrow(path);
|
|
309
|
-
if (entry.is_directory === 1) {
|
|
310
|
-
throwEISDIR(path);
|
|
399
|
+
"./client": {
|
|
400
|
+
import: {
|
|
401
|
+
browser: {
|
|
402
|
+
types: "./dist/browser/client.d.ts",
|
|
403
|
+
default: "./dist/browser/client.js"
|
|
404
|
+
},
|
|
405
|
+
types: "./dist/tsup/client/mod.d.ts",
|
|
406
|
+
default: "./dist/tsup/client/mod.js"
|
|
407
|
+
},
|
|
408
|
+
require: {
|
|
409
|
+
types: "./dist/tsup/client/mod.d.cts",
|
|
410
|
+
default: "./dist/tsup/client/mod.cjs"
|
|
311
411
|
}
|
|
312
|
-
await db2.execute(
|
|
313
|
-
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
314
|
-
path
|
|
315
|
-
);
|
|
316
412
|
},
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (children.length > 0) {
|
|
326
|
-
throwENOTEMPTY(path);
|
|
413
|
+
"./log": {
|
|
414
|
+
import: {
|
|
415
|
+
types: "./dist/tsup/common/log.d.ts",
|
|
416
|
+
default: "./dist/tsup/common/log.js"
|
|
417
|
+
},
|
|
418
|
+
require: {
|
|
419
|
+
types: "./dist/tsup/common/log.d.cts",
|
|
420
|
+
default: "./dist/tsup/common/log.cjs"
|
|
327
421
|
}
|
|
328
|
-
await db2.execute(
|
|
329
|
-
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
330
|
-
path
|
|
331
|
-
);
|
|
332
422
|
},
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (destEntry.is_directory === 1) {
|
|
342
|
-
const children = await getChildEntries(to);
|
|
343
|
-
if (children.length > 0) {
|
|
344
|
-
throwENOTEMPTY(to);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
await db2.execute(
|
|
348
|
-
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
349
|
-
to
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
if (entry.is_directory === 1) {
|
|
353
|
-
const prefix = from === "/" ? "/" : `${from}/`;
|
|
354
|
-
const newPrefix = to === "/" ? "/" : `${to}/`;
|
|
355
|
-
const descendants = await db2.execute(
|
|
356
|
-
"SELECT path FROM agent_os_fs_entries WHERE path LIKE ?",
|
|
357
|
-
`${prefix}%`
|
|
358
|
-
);
|
|
359
|
-
for (const desc of descendants) {
|
|
360
|
-
const newDescPath = newPrefix + desc.path.slice(prefix.length);
|
|
361
|
-
await db2.execute(
|
|
362
|
-
"UPDATE agent_os_fs_entries SET path = ? WHERE path = ?",
|
|
363
|
-
newDescPath,
|
|
364
|
-
desc.path
|
|
365
|
-
);
|
|
366
|
-
}
|
|
423
|
+
"./errors": {
|
|
424
|
+
import: {
|
|
425
|
+
types: "./dist/tsup/actor/errors.d.ts",
|
|
426
|
+
default: "./dist/tsup/actor/errors.js"
|
|
427
|
+
},
|
|
428
|
+
require: {
|
|
429
|
+
types: "./dist/tsup/actor/errors.d.cts",
|
|
430
|
+
default: "./dist/tsup/actor/errors.cjs"
|
|
367
431
|
}
|
|
368
|
-
const now = Date.now();
|
|
369
|
-
await db2.execute(
|
|
370
|
-
"UPDATE agent_os_fs_entries SET path = ?, ctime_ms = ? WHERE path = ?",
|
|
371
|
-
to,
|
|
372
|
-
now,
|
|
373
|
-
from
|
|
374
|
-
);
|
|
375
432
|
},
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
433
|
+
"./inspector": {
|
|
434
|
+
import: {
|
|
435
|
+
types: "./dist/tsup/inspector/mod.d.ts",
|
|
436
|
+
default: "./dist/tsup/inspector/mod.js"
|
|
437
|
+
},
|
|
438
|
+
require: {
|
|
439
|
+
types: "./dist/tsup/inspector/mod.d.cts",
|
|
440
|
+
default: "./dist/tsup/inspector/mod.cjs"
|
|
382
441
|
}
|
|
383
|
-
return path;
|
|
384
442
|
},
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
443
|
+
"./inspector-tab": {
|
|
444
|
+
import: {
|
|
445
|
+
types: "./dist/tsup/inspector-tab/mod.d.ts",
|
|
446
|
+
default: "./dist/tsup/inspector-tab/mod.js"
|
|
447
|
+
},
|
|
448
|
+
require: {
|
|
449
|
+
types: "./dist/tsup/inspector-tab/mod.d.cts",
|
|
450
|
+
default: "./dist/tsup/inspector-tab/mod.cjs"
|
|
392
451
|
}
|
|
393
|
-
const now = Date.now();
|
|
394
|
-
await db2.execute(
|
|
395
|
-
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 0, NULL, ?, 0, 0, ?, ?, ?, ?, ?, ?, 1)`,
|
|
396
|
-
link,
|
|
397
|
-
S_IFLNK | 511,
|
|
398
|
-
target.length,
|
|
399
|
-
now,
|
|
400
|
-
now,
|
|
401
|
-
now,
|
|
402
|
-
now,
|
|
403
|
-
target
|
|
404
|
-
);
|
|
405
452
|
},
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (entry.symlink_target === null) {
|
|
411
|
-
const err = new Error(`EINVAL: not a symlink: ${path}`);
|
|
412
|
-
err.name = "EINVAL";
|
|
413
|
-
throw err;
|
|
453
|
+
"./inspector/client": {
|
|
454
|
+
import: {
|
|
455
|
+
types: "./dist/browser/inspector/client.d.ts",
|
|
456
|
+
default: "./dist/browser/inspector/client.js"
|
|
414
457
|
}
|
|
415
|
-
return entry.symlink_target;
|
|
416
458
|
},
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const path = normPath(p);
|
|
426
|
-
await getEntryOrThrow(path);
|
|
427
|
-
const now = Date.now();
|
|
428
|
-
await db2.execute(
|
|
429
|
-
"UPDATE agent_os_fs_entries SET mode = ?, ctime_ms = ? WHERE path = ?",
|
|
430
|
-
mode,
|
|
431
|
-
now,
|
|
432
|
-
path
|
|
433
|
-
);
|
|
434
|
-
},
|
|
435
|
-
async chown(p, uid, gid) {
|
|
436
|
-
await rootInit;
|
|
437
|
-
const path = normPath(p);
|
|
438
|
-
await getEntryOrThrow(path);
|
|
439
|
-
const now = Date.now();
|
|
440
|
-
await db2.execute(
|
|
441
|
-
"UPDATE agent_os_fs_entries SET uid = ?, gid = ?, ctime_ms = ? WHERE path = ?",
|
|
442
|
-
uid,
|
|
443
|
-
gid,
|
|
444
|
-
now,
|
|
445
|
-
path
|
|
446
|
-
);
|
|
447
|
-
},
|
|
448
|
-
async utimes(p, atime, mtime) {
|
|
449
|
-
await rootInit;
|
|
450
|
-
const path = normPath(p);
|
|
451
|
-
await getEntryOrThrow(path);
|
|
452
|
-
const now = Date.now();
|
|
453
|
-
await db2.execute(
|
|
454
|
-
"UPDATE agent_os_fs_entries SET atime_ms = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?",
|
|
455
|
-
atime,
|
|
456
|
-
mtime,
|
|
457
|
-
now,
|
|
458
|
-
path
|
|
459
|
-
);
|
|
460
|
-
},
|
|
461
|
-
async truncate(p, length) {
|
|
462
|
-
await rootInit;
|
|
463
|
-
const path = normPath(p);
|
|
464
|
-
const entry = await getEntryOrThrow(path);
|
|
465
|
-
if (entry.is_directory === 1) {
|
|
466
|
-
throwEISDIR(path);
|
|
467
|
-
}
|
|
468
|
-
const existing = entry.content ?? new Uint8Array(0);
|
|
469
|
-
let newContent;
|
|
470
|
-
if (length >= existing.byteLength) {
|
|
471
|
-
newContent = new Uint8Array(length);
|
|
472
|
-
newContent.set(existing);
|
|
473
|
-
} else {
|
|
474
|
-
newContent = existing.slice(0, length);
|
|
459
|
+
"./utils": {
|
|
460
|
+
import: {
|
|
461
|
+
types: "./dist/tsup/utils.d.ts",
|
|
462
|
+
default: "./dist/tsup/utils.js"
|
|
463
|
+
},
|
|
464
|
+
require: {
|
|
465
|
+
types: "./dist/tsup/utils.d.cts",
|
|
466
|
+
default: "./dist/tsup/utils.cjs"
|
|
475
467
|
}
|
|
476
|
-
const now = Date.now();
|
|
477
|
-
await db2.execute(
|
|
478
|
-
"UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?",
|
|
479
|
-
newContent,
|
|
480
|
-
length,
|
|
481
|
-
now,
|
|
482
|
-
now,
|
|
483
|
-
path
|
|
484
|
-
);
|
|
485
468
|
},
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const end = Math.min(offset + length, content.byteLength);
|
|
495
|
-
if (offset >= content.byteLength) {
|
|
496
|
-
return new Uint8Array(0);
|
|
469
|
+
"./agent-os": {
|
|
470
|
+
import: {
|
|
471
|
+
types: "./dist/tsup/agent-os/index.d.ts",
|
|
472
|
+
default: "./dist/tsup/agent-os/index.js"
|
|
473
|
+
},
|
|
474
|
+
require: {
|
|
475
|
+
types: "./dist/tsup/agent-os/index.d.cts",
|
|
476
|
+
default: "./dist/tsup/agent-os/index.cjs"
|
|
497
477
|
}
|
|
498
|
-
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
engines: {
|
|
481
|
+
node: ">=22.0.0"
|
|
482
|
+
},
|
|
483
|
+
sideEffects: [
|
|
484
|
+
"./dist/tsup/chunk-*.js",
|
|
485
|
+
"./dist/tsup/chunk-*.cjs"
|
|
486
|
+
],
|
|
487
|
+
scripts: {
|
|
488
|
+
build: "tsup src/mod.ts src/client/mod.ts src/common/log.ts src/common/websocket.ts src/actor/errors.ts src/utils.ts src/workflow/mod.ts src/test/mod.ts src/inspector/mod.ts src/inspector-tab/mod.ts src/db/mod.ts src/db/drizzle.ts src/dynamic/mod.ts && tsup src/agent-os/index.ts --no-clean --out-dir dist/tsup/agent-os",
|
|
489
|
+
"build:browser": "tsup --config tsup.browser.config.ts",
|
|
490
|
+
"check-types": "tsc --noEmit",
|
|
491
|
+
lint: "biome check . && pnpm run check:test-skips && pnpm run check:wait-for-comments",
|
|
492
|
+
"lint:fix": "biome check --write .",
|
|
493
|
+
"check:test-skips": "tsx scripts/check-annotated-skips.ts",
|
|
494
|
+
"check:wait-for-comments": "tsx scripts/check-wait-for-comments.ts",
|
|
495
|
+
format: "biome format .",
|
|
496
|
+
"format:write": "biome format --write .",
|
|
497
|
+
test: "vitest run",
|
|
498
|
+
"test:platforms": "pnpm run build && RIVETKIT_INCLUDE_PLATFORM_TESTS=1 vitest run tests/platforms --passWithNoTests",
|
|
499
|
+
"test:watch": "vitest",
|
|
500
|
+
"dump-asyncapi": "tsx scripts/dump-asyncapi.ts",
|
|
501
|
+
"registry-config-schema-gen": "tsx scripts/registry-config-schema-gen.ts",
|
|
502
|
+
"actor-config-schema-gen": "tsx scripts/actor-config-schema-gen.ts"
|
|
503
|
+
},
|
|
504
|
+
dependencies: {
|
|
505
|
+
"@hono/node-server": "^1.18.2",
|
|
506
|
+
"@hono/node-ws": "^1.1.1",
|
|
507
|
+
"@hono/zod-openapi": "^1.1.5",
|
|
508
|
+
"@rivet-dev/agent-os-core": "^0.1.1",
|
|
509
|
+
"@rivetkit/bare-ts": "^0.6.2",
|
|
510
|
+
"@rivetkit/engine-cli": "workspace:*",
|
|
511
|
+
"@rivetkit/engine-envoy-protocol": "workspace:*",
|
|
512
|
+
"@rivetkit/on-change": "6.0.1",
|
|
513
|
+
"@rivetkit/rivetkit-napi": "workspace:*",
|
|
514
|
+
"@rivetkit/rivetkit-wasm": "workspace:*",
|
|
515
|
+
"@rivetkit/traces": "workspace:*",
|
|
516
|
+
"@rivetkit/virtual-websocket": "workspace:*",
|
|
517
|
+
"@rivetkit/workflow-engine": "workspace:*",
|
|
518
|
+
"cbor-x": "^1.6.0",
|
|
519
|
+
"drizzle-orm": "^0.44.2",
|
|
520
|
+
"get-port": "^7.1.0",
|
|
521
|
+
hono: "^4.7.0",
|
|
522
|
+
invariant: "^2.2.4",
|
|
523
|
+
"p-retry": "^6.2.1",
|
|
524
|
+
pino: "^9.5.0",
|
|
525
|
+
uuid: "^12.0.0",
|
|
526
|
+
vbare: "^0.0.4",
|
|
527
|
+
zod: "^4.1.0"
|
|
528
|
+
},
|
|
529
|
+
devDependencies: {
|
|
530
|
+
"@biomejs/biome": "^2.3",
|
|
531
|
+
"@copilotkit/llmock": "^1.6.0",
|
|
532
|
+
"@rivet-dev/agent-os-common": "*",
|
|
533
|
+
"@rivet-dev/agent-os-pi": "^0.1.1",
|
|
534
|
+
"@standard-schema/spec": "^1.0.0",
|
|
535
|
+
"@types/invariant": "^2",
|
|
536
|
+
"@types/node": "^22.13.1",
|
|
537
|
+
eventsource: "^4.0.0",
|
|
538
|
+
tsup: "^8.4.0",
|
|
539
|
+
tsx: "^4.19.4",
|
|
540
|
+
typescript: "^5.7.3",
|
|
541
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
542
|
+
vitest: "^3.1.1",
|
|
543
|
+
ws: "^8.18.1"
|
|
544
|
+
},
|
|
545
|
+
peerDependencies: {
|
|
546
|
+
"drizzle-kit": "^0.31.2",
|
|
547
|
+
eventsource: "^4.0.0",
|
|
548
|
+
ws: "^8.0.0"
|
|
549
|
+
},
|
|
550
|
+
peerDependenciesMeta: {
|
|
551
|
+
"drizzle-kit": {
|
|
552
|
+
optional: true
|
|
499
553
|
},
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
throwEISDIR(path);
|
|
506
|
-
}
|
|
507
|
-
const content = entry.content ?? new Uint8Array(0);
|
|
508
|
-
const end = offset + data.byteLength;
|
|
509
|
-
const newSize = Math.max(content.byteLength, end);
|
|
510
|
-
const buf = new Uint8Array(newSize);
|
|
511
|
-
buf.set(content);
|
|
512
|
-
buf.set(data, offset);
|
|
513
|
-
const now = Date.now();
|
|
514
|
-
await db2.execute(
|
|
515
|
-
`UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?`,
|
|
516
|
-
buf,
|
|
517
|
-
newSize,
|
|
518
|
-
now,
|
|
519
|
-
now,
|
|
520
|
-
path
|
|
521
|
-
);
|
|
554
|
+
eventsource: {
|
|
555
|
+
optional: true
|
|
556
|
+
},
|
|
557
|
+
ws: {
|
|
558
|
+
optional: true
|
|
522
559
|
}
|
|
523
|
-
}
|
|
524
|
-
|
|
560
|
+
},
|
|
561
|
+
stableVersion: "0.8.0"
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
// src/utils.ts
|
|
565
|
+
var VERSION = package_default.version;
|
|
566
|
+
function getEnvUniversal(key) {
|
|
567
|
+
if (typeof Deno !== "undefined") {
|
|
568
|
+
return Deno.env.get(key);
|
|
569
|
+
} else if (typeof process !== "undefined") {
|
|
570
|
+
return process.env[key];
|
|
571
|
+
}
|
|
525
572
|
}
|
|
526
573
|
|
|
527
|
-
// src/
|
|
528
|
-
|
|
574
|
+
// src/utils/env-vars.ts
|
|
575
|
+
var getLogLevel = () => getEnvUniversal("RIVET_LOG_LEVEL") ?? getEnvUniversal("LOG_LEVEL");
|
|
576
|
+
var getLogTarget = () => getEnvUniversal("RIVET_LOG_TARGET") === "1";
|
|
577
|
+
var getLogTimestamp = () => getEnvUniversal("RIVET_LOG_TIMESTAMP") === "1";
|
|
529
578
|
|
|
530
|
-
// src/
|
|
531
|
-
|
|
532
|
-
var
|
|
533
|
-
var
|
|
534
|
-
var
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
icon: z.string().optional(),
|
|
547
|
-
/** The run handler function. */
|
|
548
|
-
run: zFunction(),
|
|
549
|
-
/** Inspector integration for long-running run handlers. */
|
|
550
|
-
inspector: RunInspectorConfigSchema.optional()
|
|
551
|
-
});
|
|
552
|
-
var zRunHandler = z.union([zFunction(), RunConfigSchema]).optional();
|
|
553
|
-
var GlobalActorOptionsBaseSchema = z.object({
|
|
554
|
-
/** Display name for the actor in the Inspector UI. */
|
|
555
|
-
name: z.string().optional(),
|
|
556
|
-
/** Icon for the actor in the Inspector UI. Can be an emoji or FontAwesome icon name. */
|
|
557
|
-
icon: z.string().optional(),
|
|
558
|
-
/**
|
|
559
|
-
* Can hibernate WebSockets for onWebSocket.
|
|
560
|
-
*
|
|
561
|
-
* WebSockets using actions/events are hibernatable by default.
|
|
562
|
-
*
|
|
563
|
-
* @experimental
|
|
564
|
-
**/
|
|
565
|
-
canHibernateWebSocket: z.union([z.boolean(), zFunction()]).default(false)
|
|
566
|
-
}).strict();
|
|
567
|
-
var GlobalActorOptionsSchema = GlobalActorOptionsBaseSchema.prefault(
|
|
568
|
-
() => ({})
|
|
569
|
-
);
|
|
570
|
-
var InstanceActorOptionsBaseSchema = z.object({
|
|
571
|
-
createVarsTimeout: z.number().positive().default(5e3),
|
|
572
|
-
createConnStateTimeout: z.number().positive().default(5e3),
|
|
573
|
-
onBeforeConnectTimeout: z.number().positive().default(5e3),
|
|
574
|
-
onConnectTimeout: z.number().positive().default(5e3),
|
|
575
|
-
onMigrateTimeout: z.number().positive().default(3e4),
|
|
576
|
-
sleepGracePeriod: z.number().positive().default(DEFAULT_SLEEP_GRACE_PERIOD),
|
|
577
|
-
/** @deprecated `onDestroyTimeout` is folded into `sleepGracePeriod`, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0. */
|
|
578
|
-
onDestroyTimeout: z.number().positive().optional(),
|
|
579
|
-
/** @deprecated `waitUntilTimeout` is folded into `sleepGracePeriod`, which now bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0. */
|
|
580
|
-
waitUntilTimeout: z.number().positive().optional(),
|
|
581
|
-
stateSaveInterval: z.number().positive().default(1e3),
|
|
582
|
-
actionTimeout: z.number().positive().default(6e4),
|
|
583
|
-
connectionLivenessTimeout: z.number().positive().default(2500),
|
|
584
|
-
connectionLivenessInterval: z.number().positive().default(5e3),
|
|
585
|
-
/** @deprecated Use `c.keepAwake(promise)` to scope keep-awake to a specific operation, or keep `noSleep` for actors that must stay awake indefinitely. Will be removed in 2.2.0. */
|
|
586
|
-
noSleep: z.boolean().default(false),
|
|
587
|
-
sleepTimeout: z.number().positive().default(3e4),
|
|
588
|
-
maxQueueSize: z.number().positive().default(1e3),
|
|
589
|
-
maxQueueMessageSize: z.number().positive().default(64 * 1024),
|
|
590
|
-
/** Override RivetKit's workflow preload budget for this actor. Set to 0 to disable workflow preloading. */
|
|
591
|
-
preloadMaxWorkflowBytes: z.number().nonnegative().optional(),
|
|
592
|
-
/** Override RivetKit's connections preload budget for this actor. Set to 0 to disable connections preloading. */
|
|
593
|
-
preloadMaxConnectionsBytes: z.number().nonnegative().optional()
|
|
594
|
-
}).strict();
|
|
595
|
-
var InstanceActorOptionsSchema = InstanceActorOptionsBaseSchema.prefault(() => ({}));
|
|
596
|
-
var ActorOptionsSchema = GlobalActorOptionsBaseSchema.extend(
|
|
597
|
-
InstanceActorOptionsBaseSchema.shape
|
|
598
|
-
).strict().prefault(() => ({}));
|
|
599
|
-
var ActorConfigSchema = z.object({
|
|
600
|
-
onCreate: zFunction().optional(),
|
|
601
|
-
onDestroy: zFunction().optional(),
|
|
602
|
-
onMigrate: zFunction().optional(),
|
|
603
|
-
onWake: zFunction().optional(),
|
|
604
|
-
onSleep: zFunction().optional(),
|
|
605
|
-
run: zRunHandler,
|
|
606
|
-
onStateChange: zFunction().optional(),
|
|
607
|
-
onBeforeConnect: zFunction().optional(),
|
|
608
|
-
onConnect: zFunction().optional(),
|
|
609
|
-
onDisconnect: zFunction().optional(),
|
|
610
|
-
onBeforeActionResponse: zFunction().optional(),
|
|
611
|
-
onRequest: zFunction().optional(),
|
|
612
|
-
onWebSocket: zFunction().optional(),
|
|
613
|
-
actions: z.record(z.string(), zFunction()).default(() => ({})),
|
|
614
|
-
actionInputSchemas: z.record(z.string(), z.any()).optional(),
|
|
615
|
-
connParamsSchema: z.any().optional(),
|
|
616
|
-
events: z.record(z.string(), z.any()).optional(),
|
|
617
|
-
queues: z.record(z.string(), z.any()).optional(),
|
|
618
|
-
state: z.any().optional(),
|
|
619
|
-
createState: zFunction().optional(),
|
|
620
|
-
connState: z.any().optional(),
|
|
621
|
-
createConnState: zFunction().optional(),
|
|
622
|
-
vars: z.any().optional(),
|
|
623
|
-
db: z.any().optional(),
|
|
624
|
-
createVars: zFunction().optional(),
|
|
625
|
-
options: ActorOptionsSchema
|
|
626
|
-
}).strict().refine(
|
|
627
|
-
(data) => !(data.state !== void 0 && data.createState !== void 0),
|
|
628
|
-
{
|
|
629
|
-
message: "Cannot define both 'state' and 'createState'",
|
|
630
|
-
path: ["state"]
|
|
579
|
+
// src/common/log.ts
|
|
580
|
+
var baseLogger;
|
|
581
|
+
var configuredLogLevel;
|
|
582
|
+
var loggerCache = /* @__PURE__ */ new Map();
|
|
583
|
+
var LogLevelSchema = z2.enum([
|
|
584
|
+
"trace",
|
|
585
|
+
"debug",
|
|
586
|
+
"info",
|
|
587
|
+
"warn",
|
|
588
|
+
"error",
|
|
589
|
+
"fatal",
|
|
590
|
+
"silent"
|
|
591
|
+
]);
|
|
592
|
+
function getPinoLevel(logLevel) {
|
|
593
|
+
if (logLevel) {
|
|
594
|
+
return logLevel;
|
|
631
595
|
}
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
596
|
+
if (configuredLogLevel) {
|
|
597
|
+
return configuredLogLevel;
|
|
598
|
+
}
|
|
599
|
+
const raw = (getLogLevel() || "warn").toString().toLowerCase();
|
|
600
|
+
const parsed = LogLevelSchema.safeParse(raw);
|
|
601
|
+
if (parsed.success) {
|
|
602
|
+
return parsed.data;
|
|
603
|
+
}
|
|
604
|
+
return "info";
|
|
605
|
+
}
|
|
606
|
+
function getIncludeTarget() {
|
|
607
|
+
return getLogTarget();
|
|
608
|
+
}
|
|
609
|
+
function configureDefaultLogger(logLevel) {
|
|
610
|
+
if (logLevel) {
|
|
611
|
+
configuredLogLevel = logLevel;
|
|
612
|
+
}
|
|
613
|
+
baseLogger = pino(
|
|
614
|
+
{
|
|
615
|
+
level: getPinoLevel(logLevel),
|
|
616
|
+
messageKey: "msg",
|
|
617
|
+
// Do not include pid/hostname in output
|
|
618
|
+
base: {},
|
|
619
|
+
errorKey: "error",
|
|
620
|
+
// Keep the numeric level so the logfmt sink can match Pino's levels.
|
|
621
|
+
formatters: {
|
|
622
|
+
level(_label, number) {
|
|
623
|
+
return { level: number };
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
timestamp: getLogTimestamp() ? stdTimeFunctions.epochTime : false
|
|
627
|
+
},
|
|
628
|
+
createLogfmtDestination()
|
|
629
|
+
);
|
|
630
|
+
loggerCache.clear();
|
|
631
|
+
}
|
|
632
|
+
function getBaseLogger() {
|
|
633
|
+
if (!baseLogger) {
|
|
634
|
+
configureDefaultLogger();
|
|
635
|
+
}
|
|
636
|
+
return baseLogger;
|
|
637
|
+
}
|
|
638
|
+
function getLogger(name = "default") {
|
|
639
|
+
const cached = loggerCache.get(name);
|
|
640
|
+
if (cached) {
|
|
641
|
+
return cached;
|
|
642
|
+
}
|
|
643
|
+
const base = getBaseLogger();
|
|
644
|
+
const child = getIncludeTarget() ? base.child({ target: name }) : base;
|
|
645
|
+
loggerCache.set(name, child);
|
|
646
|
+
return child;
|
|
647
|
+
}
|
|
648
|
+
var PINO_LEVEL_LABELS = {
|
|
649
|
+
10: "trace",
|
|
650
|
+
20: "debug",
|
|
651
|
+
30: "info",
|
|
652
|
+
40: "warn",
|
|
653
|
+
50: "error",
|
|
654
|
+
60: "fatal"
|
|
655
|
+
};
|
|
656
|
+
function createLogfmtDestination() {
|
|
657
|
+
return {
|
|
658
|
+
write(msg) {
|
|
659
|
+
var _a;
|
|
660
|
+
const line = formatLogfmtLine(msg);
|
|
661
|
+
if (typeof process !== "undefined" && ((_a = process.stdout) == null ? void 0 : _a.write)) {
|
|
662
|
+
process.stdout.write(`${line}
|
|
663
|
+
`);
|
|
664
|
+
} else {
|
|
665
|
+
console.log(line);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function formatLogfmtLine(raw) {
|
|
671
|
+
let data;
|
|
672
|
+
try {
|
|
673
|
+
data = JSON.parse(raw);
|
|
674
|
+
} catch {
|
|
675
|
+
return raw.trimEnd();
|
|
676
|
+
}
|
|
677
|
+
const parts = [];
|
|
678
|
+
appendLogfmtEntry(parts, "level", formatPinoLevel(data.level));
|
|
679
|
+
if (data.time !== void 0) {
|
|
680
|
+
appendLogfmtEntry(parts, "ts", data.time);
|
|
681
|
+
}
|
|
682
|
+
for (const [key, value] of Object.entries(data)) {
|
|
683
|
+
if (key === "level" || key === "time") {
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
appendLogfmtEntry(parts, key, value);
|
|
687
|
+
}
|
|
688
|
+
return parts.join(" ");
|
|
689
|
+
}
|
|
690
|
+
function formatPinoLevel(level) {
|
|
691
|
+
if (typeof level === "number") {
|
|
692
|
+
return PINO_LEVEL_LABELS[level] ?? level.toString();
|
|
693
|
+
}
|
|
694
|
+
if (typeof level === "string") {
|
|
695
|
+
return level.toLowerCase();
|
|
696
|
+
}
|
|
697
|
+
return "info";
|
|
698
|
+
}
|
|
699
|
+
function appendLogfmtEntry(parts, key, value) {
|
|
700
|
+
const safeKey = key.replace(/[\s="]/g, "");
|
|
701
|
+
if (safeKey.length === 0) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
parts.push(`${safeKey}=${formatLogfmtValue(value)}`);
|
|
705
|
+
}
|
|
706
|
+
function formatLogfmtValue(value) {
|
|
707
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
708
|
+
return String(value);
|
|
709
|
+
}
|
|
710
|
+
if (value === null || value === void 0) {
|
|
711
|
+
return "null";
|
|
712
|
+
}
|
|
713
|
+
if (typeof value === "string") {
|
|
714
|
+
return quoteLogfmtString(value);
|
|
715
|
+
}
|
|
716
|
+
return quoteLogfmtString(JSON.stringify(value));
|
|
717
|
+
}
|
|
718
|
+
function quoteLogfmtString(value) {
|
|
719
|
+
if (!/[\s="]/.test(value)) {
|
|
720
|
+
return value;
|
|
721
|
+
}
|
|
722
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// src/actor/log.ts
|
|
726
|
+
function loggerWithoutContext() {
|
|
727
|
+
return getLogger("actor-runtime");
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// src/actor/definition.ts
|
|
731
|
+
var warnedDeprecatedTimeoutKeys = /* @__PURE__ */ new Set();
|
|
732
|
+
function warnDeprecatedShutdownTimeoutKeys(options) {
|
|
733
|
+
if (!options || typeof options !== "object") return;
|
|
734
|
+
const opts = options;
|
|
735
|
+
for (const key of ["onDestroyTimeout", "waitUntilTimeout"]) {
|
|
736
|
+
if (opts[key] !== void 0 && !warnedDeprecatedTimeoutKeys.has(key)) {
|
|
737
|
+
warnedDeprecatedTimeoutKeys.add(key);
|
|
738
|
+
loggerWithoutContext().warn({
|
|
739
|
+
msg: `actor option \`${key}\` is deprecated and is now ignored. Configure \`sleepGracePeriod\` instead, which bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0.`
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
var ActorDefinition = class {
|
|
745
|
+
#config;
|
|
746
|
+
constructor(config) {
|
|
747
|
+
this.#config = config;
|
|
748
|
+
}
|
|
749
|
+
get config() {
|
|
750
|
+
return this.#config;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
function actor(input) {
|
|
754
|
+
warnDeprecatedShutdownTimeoutKeys(
|
|
755
|
+
input == null ? void 0 : input.options
|
|
756
|
+
);
|
|
757
|
+
const config = ActorConfigSchema.parse(input);
|
|
758
|
+
return new ActorDefinition(config);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/actor/schema.ts
|
|
762
|
+
function event(options) {
|
|
763
|
+
return options ?? {};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/common/database/shared.ts
|
|
767
|
+
function isSqliteBindingValue(value) {
|
|
768
|
+
if (value === null || typeof value === "number" || typeof value === "string" || typeof value === "bigint" || value instanceof Uint8Array) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
if (Array.isArray(value)) {
|
|
772
|
+
return value.every((item) => typeof item === "number");
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function isPlainObject(value) {
|
|
777
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
return Object.getPrototypeOf(value) === Object.prototype;
|
|
781
|
+
}
|
|
782
|
+
function isSqliteBindingObject(value) {
|
|
783
|
+
if (!isPlainObject(value)) {
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
return Object.values(value).every((entry) => isSqliteBindingValue(entry));
|
|
787
|
+
}
|
|
788
|
+
function toSqliteBindings(input) {
|
|
789
|
+
if (Array.isArray(input)) {
|
|
790
|
+
for (const value of input) {
|
|
791
|
+
if (!isSqliteBindingValue(value)) {
|
|
792
|
+
throw new Error(
|
|
793
|
+
`unsupported sqlite binding type: ${typeof value}`
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return input;
|
|
798
|
+
}
|
|
799
|
+
if (isSqliteBindingObject(input)) {
|
|
800
|
+
return input;
|
|
801
|
+
}
|
|
802
|
+
throw new Error("unsupported sqlite binding collection");
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// src/common/database/mod.ts
|
|
806
|
+
function hasMultipleStatements(query) {
|
|
807
|
+
const trimmed = query.trim().replace(/;+$/, "").trimEnd();
|
|
808
|
+
return trimmed.includes(";");
|
|
809
|
+
}
|
|
810
|
+
function db({
|
|
811
|
+
onMigrate
|
|
812
|
+
} = {}) {
|
|
813
|
+
return {
|
|
814
|
+
createClient: async (ctx) => {
|
|
815
|
+
const nativeDatabaseProvider = ctx.nativeDatabaseProvider;
|
|
816
|
+
if (!nativeDatabaseProvider) {
|
|
817
|
+
throw new Error(
|
|
818
|
+
"native SQLite is required, but the current runtime did not provide a native database provider"
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
const db2 = await nativeDatabaseProvider.open(ctx.actorId);
|
|
822
|
+
let closed = false;
|
|
823
|
+
const ensureOpen = () => {
|
|
824
|
+
if (closed) {
|
|
825
|
+
throw new Error(
|
|
826
|
+
"Database is closed. This usually means a background timer (setInterval, setTimeout) or a stray promise is still running after the actor stopped. Use c.abortSignal to clean up timers before the actor shuts down."
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
const client = {
|
|
831
|
+
execute: async (query, ...args) => {
|
|
832
|
+
var _a, _b, _c, _d;
|
|
833
|
+
ensureOpen();
|
|
834
|
+
const kvReadsBefore = ((_a = ctx.metrics) == null ? void 0 : _a.totalKvReads) ?? 0;
|
|
835
|
+
const kvWritesBefore = ((_b = ctx.metrics) == null ? void 0 : _b.totalKvWrites) ?? 0;
|
|
836
|
+
const start = performance.now();
|
|
837
|
+
try {
|
|
838
|
+
if (args.length > 0) {
|
|
839
|
+
const bindings = args.length === 1 && isSqliteBindingObject(args[0]) ? toSqliteBindings(args[0]) : toSqliteBindings(args);
|
|
840
|
+
const { rows, columns } = await db2.execute(
|
|
841
|
+
query,
|
|
842
|
+
bindings
|
|
843
|
+
);
|
|
844
|
+
return rows.map(
|
|
845
|
+
(row) => rowToObject(row, columns)
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
if (!hasMultipleStatements(query)) {
|
|
849
|
+
const { rows, columns } = await db2.execute(query);
|
|
850
|
+
return rows.map(
|
|
851
|
+
(row) => rowToObject(row, columns)
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
return await execMultiStatement(db2, query);
|
|
855
|
+
} finally {
|
|
856
|
+
const durationMs = performance.now() - start;
|
|
857
|
+
(_c = ctx.metrics) == null ? void 0 : _c.trackSql(query, durationMs);
|
|
858
|
+
if (ctx.metrics) {
|
|
859
|
+
const kvReads = ctx.metrics.totalKvReads - kvReadsBefore;
|
|
860
|
+
const kvWrites = ctx.metrics.totalKvWrites - kvWritesBefore;
|
|
861
|
+
(_d = ctx.log) == null ? void 0 : _d.debug({
|
|
862
|
+
msg: "sql query",
|
|
863
|
+
query: query.slice(0, 120),
|
|
864
|
+
durationMs,
|
|
865
|
+
kvReads,
|
|
866
|
+
kvWrites
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
close: async () => {
|
|
872
|
+
if (!closed) {
|
|
873
|
+
closed = true;
|
|
874
|
+
await db2.close();
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
nativeMetrics: () => {
|
|
878
|
+
var _a;
|
|
879
|
+
return ((_a = db2.nativeMetrics) == null ? void 0 : _a.call(db2)) ?? null;
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
return client;
|
|
883
|
+
},
|
|
884
|
+
onMigrate: async (client) => {
|
|
885
|
+
if (onMigrate) {
|
|
886
|
+
await withMigrationSavepoint(client, () => onMigrate(client));
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
function rowToObject(row, columns) {
|
|
892
|
+
const rowObj = {};
|
|
893
|
+
for (let i = 0; i < columns.length; i++) {
|
|
894
|
+
rowObj[columns[i]] = row[i];
|
|
637
895
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
896
|
+
return rowObj;
|
|
897
|
+
}
|
|
898
|
+
async function execMultiStatement(db2, query) {
|
|
899
|
+
const results = [];
|
|
900
|
+
let columnNames = null;
|
|
901
|
+
await db2.exec(query, (row, columns) => {
|
|
902
|
+
if (!columnNames) {
|
|
903
|
+
columnNames = columns;
|
|
904
|
+
}
|
|
905
|
+
results.push(rowToObject(row, columnNames));
|
|
906
|
+
});
|
|
907
|
+
return results;
|
|
908
|
+
}
|
|
909
|
+
async function withMigrationSavepoint(client, callback) {
|
|
910
|
+
await client.execute("SAVEPOINT __rivet_on_migrate");
|
|
911
|
+
try {
|
|
912
|
+
const result = await callback();
|
|
913
|
+
await client.execute("RELEASE SAVEPOINT __rivet_on_migrate");
|
|
914
|
+
return result;
|
|
915
|
+
} catch (error) {
|
|
916
|
+
try {
|
|
917
|
+
await client.execute("ROLLBACK TO SAVEPOINT __rivet_on_migrate");
|
|
918
|
+
} finally {
|
|
919
|
+
await client.execute("RELEASE SAVEPOINT __rivet_on_migrate");
|
|
920
|
+
}
|
|
921
|
+
throw error;
|
|
643
922
|
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/agent-os/config.ts
|
|
926
|
+
import { z as z3 } from "zod/v4";
|
|
927
|
+
var zFunction2 = () => z3.custom((val) => typeof val === "function");
|
|
928
|
+
var AgentOsOptionsSchema = z3.custom(
|
|
929
|
+
(val) => typeof val === "object" && val !== null
|
|
644
930
|
);
|
|
645
|
-
var
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
)
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
),
|
|
696
|
-
preloadMaxConnectionsBytes: z.number().optional().describe(
|
|
697
|
-
"Override RivetKit's connections preload budget for this actor. Set to 0 to disable connections preloading."
|
|
698
|
-
)
|
|
699
|
-
}).describe("Actor options for timeouts and behavior configuration.");
|
|
700
|
-
var DocActorConfigSchema = z.object({
|
|
701
|
-
state: z.unknown().optional().describe(
|
|
702
|
-
"Initial state value for the actor. Cannot be used with createState."
|
|
703
|
-
),
|
|
704
|
-
createState: z.unknown().optional().describe(
|
|
705
|
-
"Function to create initial state. Receives context and input. Cannot be used with state."
|
|
706
|
-
),
|
|
707
|
-
connState: z.unknown().optional().describe(
|
|
708
|
-
"Initial connection state value. Cannot be used with createConnState."
|
|
709
|
-
),
|
|
710
|
-
createConnState: z.unknown().optional().describe(
|
|
711
|
-
"Function to create connection state. Receives context and connection params. The pending connection is not visible in c.conns until this succeeds. Cannot be used with connState."
|
|
712
|
-
),
|
|
713
|
-
vars: z.unknown().optional().describe(
|
|
714
|
-
"Initial ephemeral variables value. Cannot be used with createVars."
|
|
715
|
-
),
|
|
716
|
-
createVars: z.unknown().optional().describe(
|
|
717
|
-
"Function to create ephemeral variables. Receives context and driver context. Cannot be used with vars."
|
|
718
|
-
),
|
|
719
|
-
db: z.unknown().optional().describe("Database provider instance for the actor."),
|
|
720
|
-
onCreate: z.unknown().optional().describe(
|
|
721
|
-
"Called when the actor is first initialized. Use to initialize state."
|
|
722
|
-
),
|
|
723
|
-
onDestroy: z.unknown().optional().describe("Called when the actor is destroyed."),
|
|
724
|
-
onMigrate: z.unknown().optional().describe(
|
|
725
|
-
"Called on every actor start after persisted state loads and before onWake. Use for repeatable schema migrations."
|
|
726
|
-
),
|
|
727
|
-
onWake: z.unknown().optional().describe(
|
|
728
|
-
"Called when the actor wakes up and is ready to receive connections and actions."
|
|
729
|
-
),
|
|
730
|
-
onSleep: z.unknown().optional().describe(
|
|
731
|
-
"Called when the actor is stopping or sleeping. Use to clean up resources."
|
|
732
|
-
),
|
|
733
|
-
run: z.unknown().optional().describe(
|
|
734
|
-
"Called after actor starts. Does not block startup. Use for background tasks like queue processing or tick loops. If it exits, the actor follows the normal idle sleep timeout once idle. If it throws, the actor logs the error and then follows the normal idle sleep timeout once idle."
|
|
735
|
-
),
|
|
736
|
-
onStateChange: z.unknown().optional().describe(
|
|
737
|
-
"Called when the actor's state changes. State changes within this hook won't trigger recursion."
|
|
738
|
-
),
|
|
739
|
-
onBeforeConnect: z.unknown().optional().describe(
|
|
740
|
-
"Called before a client connects. Throw an error to reject the connection. The pending connection is not visible in c.conns while this runs."
|
|
741
|
-
),
|
|
742
|
-
onConnect: z.unknown().optional().describe(
|
|
743
|
-
"Called when a client successfully connects. The connection is visible in c.conns before this runs."
|
|
744
|
-
),
|
|
745
|
-
onDisconnect: z.unknown().optional().describe("Called when a client disconnects."),
|
|
746
|
-
onBeforeActionResponse: z.unknown().optional().describe(
|
|
747
|
-
"Called before sending an action response. Use to transform output."
|
|
748
|
-
),
|
|
749
|
-
onRequest: z.unknown().optional().describe(
|
|
750
|
-
"Called for raw HTTP requests to /actors/{name}/http/* endpoints."
|
|
751
|
-
),
|
|
752
|
-
onWebSocket: z.unknown().optional().describe(
|
|
753
|
-
"Called for raw WebSocket connections to /actors/{name}/websocket/* endpoints."
|
|
754
|
-
),
|
|
755
|
-
actions: z.record(z.string(), z.unknown()).optional().describe(
|
|
756
|
-
"Map of action name to handler function. Defaults to an empty object."
|
|
757
|
-
),
|
|
758
|
-
actionInputSchemas: z.record(z.string(), z.unknown()).optional().describe(
|
|
759
|
-
"Optional schema map for validating action argument tuples in native runtimes."
|
|
760
|
-
),
|
|
761
|
-
connParamsSchema: z.unknown().optional().describe(
|
|
762
|
-
"Optional schema for validating connection params in native runtimes."
|
|
763
|
-
),
|
|
764
|
-
events: z.record(z.string(), z.unknown()).optional().describe("Map of event names to schemas."),
|
|
765
|
-
queues: z.record(z.string(), z.unknown()).optional().describe("Map of queue names to schemas."),
|
|
766
|
-
options: DocActorOptionsSchema.optional()
|
|
767
|
-
}).describe("Actor configuration passed to the actor() function.");
|
|
931
|
+
var agentOsActorConfigSchema = z3.object({
|
|
932
|
+
options: AgentOsOptionsSchema.optional(),
|
|
933
|
+
preview: z3.object({
|
|
934
|
+
defaultExpiresInSeconds: z3.number().positive().default(3600),
|
|
935
|
+
maxExpiresInSeconds: z3.number().positive().default(86400)
|
|
936
|
+
}).strict().prefault(() => ({})),
|
|
937
|
+
onBeforeConnect: zFunction2().optional(),
|
|
938
|
+
onSessionEvent: zFunction2().optional(),
|
|
939
|
+
onPermissionRequest: zFunction2().optional()
|
|
940
|
+
}).strict();
|
|
941
|
+
|
|
942
|
+
// src/agent-os/actor/db.ts
|
|
943
|
+
async function migrateAgentOsTables(db2) {
|
|
944
|
+
await db2.execute(`
|
|
945
|
+
CREATE TABLE IF NOT EXISTS agent_os_preview_tokens (
|
|
946
|
+
token TEXT PRIMARY KEY,
|
|
947
|
+
port INTEGER NOT NULL,
|
|
948
|
+
created_at INTEGER NOT NULL,
|
|
949
|
+
expires_at INTEGER NOT NULL
|
|
950
|
+
);
|
|
951
|
+
|
|
952
|
+
CREATE INDEX IF NOT EXISTS idx_preview_tokens_expires_at
|
|
953
|
+
ON agent_os_preview_tokens(expires_at);
|
|
954
|
+
|
|
955
|
+
CREATE TABLE IF NOT EXISTS agent_os_fs_entries (
|
|
956
|
+
path TEXT PRIMARY KEY,
|
|
957
|
+
is_directory INTEGER NOT NULL DEFAULT 0,
|
|
958
|
+
content BLOB,
|
|
959
|
+
mode INTEGER NOT NULL DEFAULT 33188,
|
|
960
|
+
uid INTEGER NOT NULL DEFAULT 0,
|
|
961
|
+
gid INTEGER NOT NULL DEFAULT 0,
|
|
962
|
+
size INTEGER NOT NULL DEFAULT 0,
|
|
963
|
+
atime_ms INTEGER NOT NULL,
|
|
964
|
+
mtime_ms INTEGER NOT NULL,
|
|
965
|
+
ctime_ms INTEGER NOT NULL,
|
|
966
|
+
birthtime_ms INTEGER NOT NULL,
|
|
967
|
+
symlink_target TEXT,
|
|
968
|
+
nlink INTEGER NOT NULL DEFAULT 1
|
|
969
|
+
);
|
|
970
|
+
|
|
971
|
+
CREATE INDEX IF NOT EXISTS idx_fs_entries_parent
|
|
972
|
+
ON agent_os_fs_entries(path);
|
|
973
|
+
|
|
974
|
+
CREATE TABLE IF NOT EXISTS agent_os_sessions (
|
|
975
|
+
session_id TEXT PRIMARY KEY,
|
|
976
|
+
agent_type TEXT NOT NULL,
|
|
977
|
+
capabilities TEXT NOT NULL,
|
|
978
|
+
agent_info TEXT,
|
|
979
|
+
created_at INTEGER NOT NULL
|
|
980
|
+
);
|
|
768
981
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
982
|
+
CREATE TABLE IF NOT EXISTS agent_os_session_events (
|
|
983
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
984
|
+
session_id TEXT NOT NULL,
|
|
985
|
+
seq INTEGER NOT NULL,
|
|
986
|
+
event TEXT NOT NULL,
|
|
987
|
+
created_at INTEGER NOT NULL,
|
|
988
|
+
FOREIGN KEY (session_id) REFERENCES agent_os_sessions(session_id) ON DELETE CASCADE
|
|
989
|
+
);
|
|
775
990
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
function isRivetErrorLike(error) {
|
|
781
|
-
return typeof error === "object" && error !== null && "group" in error && typeof error.group === "string" && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string" && (!("__type" in error) || isTypedErrorTag(error.__type));
|
|
782
|
-
}
|
|
783
|
-
function isRivetErrorCode(error, group, code) {
|
|
784
|
-
return isRivetErrorLike(error) && error.group === group && error.code === code;
|
|
991
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session_seq
|
|
992
|
+
ON agent_os_session_events(session_id, seq);
|
|
993
|
+
`);
|
|
785
994
|
}
|
|
786
995
|
|
|
787
|
-
//
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
keywords: [
|
|
794
|
-
"rivetkit",
|
|
795
|
-
"stateful",
|
|
796
|
-
"serverless",
|
|
797
|
-
"actors",
|
|
798
|
-
"agents",
|
|
799
|
-
"realtime",
|
|
800
|
-
"websocket",
|
|
801
|
-
"actors",
|
|
802
|
-
"framework"
|
|
803
|
-
],
|
|
804
|
-
files: [
|
|
805
|
-
"dist",
|
|
806
|
-
"schemas",
|
|
807
|
-
"src",
|
|
808
|
-
"package.json"
|
|
809
|
-
],
|
|
810
|
-
type: "module",
|
|
811
|
-
exports: {
|
|
812
|
-
".": {
|
|
813
|
-
import: {
|
|
814
|
-
types: "./dist/tsup/mod.d.ts",
|
|
815
|
-
default: "./dist/tsup/mod.js"
|
|
816
|
-
},
|
|
817
|
-
require: {
|
|
818
|
-
types: "./dist/tsup/mod.d.cts",
|
|
819
|
-
default: "./dist/tsup/mod.cjs"
|
|
820
|
-
}
|
|
996
|
+
// src/agent-os/actor/filesystem.ts
|
|
997
|
+
function buildFilesystemActions(config) {
|
|
998
|
+
return {
|
|
999
|
+
readFile: async (c, path) => {
|
|
1000
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1001
|
+
return agentOs2.readFile(path);
|
|
821
1002
|
},
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
default: "./dist/tsup/workflow/mod.js"
|
|
826
|
-
},
|
|
827
|
-
require: {
|
|
828
|
-
types: "./dist/tsup/workflow/mod.d.cts",
|
|
829
|
-
default: "./dist/tsup/workflow/mod.cjs"
|
|
830
|
-
}
|
|
1003
|
+
writeFile: async (c, path, content) => {
|
|
1004
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1005
|
+
await agentOs2.writeFile(path, content);
|
|
831
1006
|
},
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
default: "./dist/tsup/test/mod.js"
|
|
836
|
-
},
|
|
837
|
-
require: {
|
|
838
|
-
types: "./dist/tsup/test/mod.d.cts",
|
|
839
|
-
default: "./dist/tsup/test/mod.cjs"
|
|
840
|
-
}
|
|
1007
|
+
readFiles: async (c, paths) => {
|
|
1008
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1009
|
+
return agentOs2.readFiles(paths);
|
|
841
1010
|
},
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1011
|
+
writeFiles: async (c, entries) => {
|
|
1012
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1013
|
+
return agentOs2.writeFiles(entries);
|
|
1014
|
+
},
|
|
1015
|
+
mkdir: async (c, path, options) => {
|
|
1016
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1017
|
+
await agentOs2.mkdir(path, options);
|
|
1018
|
+
},
|
|
1019
|
+
readdir: async (c, path) => {
|
|
1020
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1021
|
+
return agentOs2.readdir(path);
|
|
1022
|
+
},
|
|
1023
|
+
readdirRecursive: async (c, path, options) => {
|
|
1024
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1025
|
+
return agentOs2.readdirRecursive(path, options);
|
|
1026
|
+
},
|
|
1027
|
+
stat: async (c, path) => {
|
|
1028
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1029
|
+
return agentOs2.stat(path);
|
|
1030
|
+
},
|
|
1031
|
+
exists: async (c, path) => {
|
|
1032
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1033
|
+
return agentOs2.exists(path);
|
|
1034
|
+
},
|
|
1035
|
+
move: async (c, from, to) => {
|
|
1036
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1037
|
+
await agentOs2.move(from, to);
|
|
1038
|
+
},
|
|
1039
|
+
deleteFile: async (c, path, options) => {
|
|
1040
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1041
|
+
await agentOs2.delete(path, options);
|
|
1042
|
+
},
|
|
1043
|
+
// TODO: mountFs and unmountFs are not exposed as actor actions because
|
|
1044
|
+
// filesystem drivers (VirtualFileSystem) are not serializable over the
|
|
1045
|
+
// network. Mount filesystems via the `options.mounts` config in agentOs()
|
|
1046
|
+
// instead. See: https://github.com/rivet-dev/rivet/issues/XXXX
|
|
1047
|
+
listAgents: async (c) => {
|
|
1048
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1049
|
+
return agentOs2.listAgents();
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// src/agent-os/actor/network.ts
|
|
1055
|
+
function buildNetworkActions(config) {
|
|
1056
|
+
return {
|
|
1057
|
+
vmFetch: async (c, port, url, options) => {
|
|
1058
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1059
|
+
const headers = new Headers(options == null ? void 0 : options.headers);
|
|
1060
|
+
const request = new Request(url, {
|
|
1061
|
+
method: (options == null ? void 0 : options.method) ?? "GET",
|
|
1062
|
+
headers,
|
|
1063
|
+
body: (options == null ? void 0 : options.body) ?? null
|
|
1064
|
+
});
|
|
1065
|
+
const response = await agentOs2.fetch(port, request);
|
|
1066
|
+
const responseHeaders = {};
|
|
1067
|
+
response.headers.forEach((value, key) => {
|
|
1068
|
+
responseHeaders[key] = value;
|
|
1069
|
+
});
|
|
1070
|
+
const body = new Uint8Array(await response.arrayBuffer());
|
|
1071
|
+
return {
|
|
1072
|
+
status: response.status,
|
|
1073
|
+
statusText: response.statusText,
|
|
1074
|
+
headers: responseHeaders,
|
|
1075
|
+
body
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// src/agent-os/actor/preview.ts
|
|
1082
|
+
import crypto from "crypto";
|
|
1083
|
+
function generateToken() {
|
|
1084
|
+
const bytes = crypto.randomBytes(32);
|
|
1085
|
+
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
1086
|
+
let token = "";
|
|
1087
|
+
for (let i = 0; i < 32; i++) {
|
|
1088
|
+
token += alphabet[bytes[i] % alphabet.length];
|
|
1089
|
+
}
|
|
1090
|
+
return token;
|
|
1091
|
+
}
|
|
1092
|
+
var CORS_HEADERS = {
|
|
1093
|
+
"Access-Control-Allow-Origin": "*",
|
|
1094
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
1095
|
+
"Access-Control-Allow-Headers": "*"
|
|
1096
|
+
};
|
|
1097
|
+
function addCorsHeaders(response) {
|
|
1098
|
+
const headers = new Headers(response.headers);
|
|
1099
|
+
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
1100
|
+
headers.set(key, value);
|
|
1101
|
+
}
|
|
1102
|
+
return new Response(response.body, {
|
|
1103
|
+
status: response.status,
|
|
1104
|
+
statusText: response.statusText,
|
|
1105
|
+
headers
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
function buildOnRequestHandler(config) {
|
|
1109
|
+
return async (c, request) => {
|
|
1110
|
+
var _a;
|
|
1111
|
+
const url = new URL(request.url);
|
|
1112
|
+
const pathname = url.pathname;
|
|
1113
|
+
const match = pathname.match(/^\/fetch\/([a-z0-9]+)(\/.*)?$/);
|
|
1114
|
+
if (!match) {
|
|
1115
|
+
return new Response("Not Found", { status: 404 });
|
|
1116
|
+
}
|
|
1117
|
+
if (request.method === "OPTIONS") {
|
|
1118
|
+
return new Response(null, { status: 204, headers: CORS_HEADERS });
|
|
1119
|
+
}
|
|
1120
|
+
const token = match[1];
|
|
1121
|
+
const remainingPath = match[2] ?? "/";
|
|
1122
|
+
const now = Date.now();
|
|
1123
|
+
const rows = await c.db.execute(
|
|
1124
|
+
`SELECT port FROM agent_os_preview_tokens WHERE token = ? AND expires_at > ?`,
|
|
1125
|
+
token,
|
|
1126
|
+
now
|
|
1127
|
+
);
|
|
1128
|
+
if (rows.length === 0) {
|
|
1129
|
+
c.log.warn({ msg: "agent-os preview auth failed", token });
|
|
1130
|
+
return addCorsHeaders(new Response("Forbidden", { status: 403 }));
|
|
1131
|
+
}
|
|
1132
|
+
const port = (_a = rows[0]) == null ? void 0 : _a.port;
|
|
1133
|
+
const agentOs2 = await ensureVm(
|
|
1134
|
+
c,
|
|
1135
|
+
config
|
|
1136
|
+
);
|
|
1137
|
+
const vmUrl = `http://localhost:${port}${remainingPath}${url.search}`;
|
|
1138
|
+
const vmRequest = new Request(vmUrl, {
|
|
1139
|
+
method: request.method,
|
|
1140
|
+
headers: request.headers,
|
|
1141
|
+
body: request.body,
|
|
1142
|
+
duplex: "half"
|
|
1143
|
+
});
|
|
1144
|
+
const vmResponse = await agentOs2.fetch(port, vmRequest);
|
|
1145
|
+
c.log.info({
|
|
1146
|
+
msg: "agent-os preview request proxied",
|
|
1147
|
+
port,
|
|
1148
|
+
method: request.method,
|
|
1149
|
+
path: remainingPath,
|
|
1150
|
+
status: vmResponse.status
|
|
1151
|
+
});
|
|
1152
|
+
return addCorsHeaders(vmResponse);
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
function buildPreviewActions(config) {
|
|
1156
|
+
return {
|
|
1157
|
+
createSignedPreviewUrl: async (c, port, expiresInSeconds) => {
|
|
1158
|
+
await ensureVm(c, config);
|
|
1159
|
+
const effectiveExpires = expiresInSeconds ?? config.preview.defaultExpiresInSeconds;
|
|
1160
|
+
const maxExpires = config.preview.maxExpiresInSeconds;
|
|
1161
|
+
if (effectiveExpires < 1 || effectiveExpires > maxExpires) {
|
|
1162
|
+
throw new Error(
|
|
1163
|
+
`expiresInSeconds must be between 1 and ${maxExpires}`
|
|
1164
|
+
);
|
|
850
1165
|
}
|
|
1166
|
+
const token = generateToken();
|
|
1167
|
+
const now = Date.now();
|
|
1168
|
+
const expiresAt = now + effectiveExpires * 1e3;
|
|
1169
|
+
await c.db.execute(
|
|
1170
|
+
`INSERT INTO agent_os_preview_tokens (token, port, created_at, expires_at)
|
|
1171
|
+
VALUES (?, ?, ?, ?)`,
|
|
1172
|
+
token,
|
|
1173
|
+
port,
|
|
1174
|
+
now,
|
|
1175
|
+
expiresAt
|
|
1176
|
+
);
|
|
1177
|
+
await c.db.execute(
|
|
1178
|
+
`DELETE FROM agent_os_preview_tokens WHERE expires_at <= ?`,
|
|
1179
|
+
now
|
|
1180
|
+
);
|
|
1181
|
+
const path = `/request/fetch/${token}`;
|
|
1182
|
+
c.log.info({
|
|
1183
|
+
msg: "agent-os preview token created",
|
|
1184
|
+
port,
|
|
1185
|
+
expiresInSeconds: effectiveExpires
|
|
1186
|
+
});
|
|
1187
|
+
return { path, token, port, expiresAt };
|
|
851
1188
|
},
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1189
|
+
expireSignedPreviewUrl: async (c, token) => {
|
|
1190
|
+
await c.db.execute(
|
|
1191
|
+
`DELETE FROM agent_os_preview_tokens WHERE token = ?`,
|
|
1192
|
+
token
|
|
1193
|
+
);
|
|
1194
|
+
c.log.info({ msg: "agent-os preview token expired", token });
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// src/agent-os/actor/process.ts
|
|
1200
|
+
function broadcastProcessEvent(c, name, payload) {
|
|
1201
|
+
try {
|
|
1202
|
+
c.broadcast(name, payload);
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
if (isRivetErrorCode(error, "actor", "stopping")) {
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
throw error;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
function buildProcessActions(config) {
|
|
1211
|
+
return {
|
|
1212
|
+
exec: async (c, command, options) => {
|
|
1213
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1214
|
+
return agentOs2.exec(command, options);
|
|
861
1215
|
},
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1216
|
+
spawn: async (c, command, args, options) => {
|
|
1217
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1218
|
+
const { pid } = agentOs2.spawn(command, args, {
|
|
1219
|
+
...options,
|
|
1220
|
+
onStdout: (data) => {
|
|
1221
|
+
var _a;
|
|
1222
|
+
broadcastProcessEvent(c, "processOutput", {
|
|
1223
|
+
pid,
|
|
1224
|
+
stream: "stdout",
|
|
1225
|
+
data
|
|
1226
|
+
});
|
|
1227
|
+
(_a = options == null ? void 0 : options.onStdout) == null ? void 0 : _a.call(options, data);
|
|
867
1228
|
},
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1229
|
+
onStderr: (data) => {
|
|
1230
|
+
var _a;
|
|
1231
|
+
broadcastProcessEvent(c, "processOutput", {
|
|
1232
|
+
pid,
|
|
1233
|
+
stream: "stderr",
|
|
1234
|
+
data
|
|
1235
|
+
});
|
|
1236
|
+
(_a = options == null ? void 0 : options.onStderr) == null ? void 0 : _a.call(options, data);
|
|
1237
|
+
}
|
|
1238
|
+
});
|
|
1239
|
+
c.vars.activeProcesses.add(pid);
|
|
1240
|
+
syncPreventSleep(c);
|
|
1241
|
+
c.log.info({
|
|
1242
|
+
msg: "agent-os process spawned",
|
|
1243
|
+
pid,
|
|
1244
|
+
command
|
|
1245
|
+
});
|
|
1246
|
+
agentOs2.waitProcess(pid).then((exitCode) => {
|
|
1247
|
+
broadcastProcessEvent(c, "processExit", { pid, exitCode });
|
|
1248
|
+
c.log.info({
|
|
1249
|
+
msg: "agent-os process exited",
|
|
1250
|
+
pid,
|
|
1251
|
+
exitCode
|
|
1252
|
+
});
|
|
1253
|
+
}).catch(() => {
|
|
1254
|
+
}).finally(() => {
|
|
1255
|
+
c.vars.activeProcesses.delete(pid);
|
|
1256
|
+
syncPreventSleep(c);
|
|
1257
|
+
});
|
|
1258
|
+
return { pid };
|
|
875
1259
|
},
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
default: "./dist/tsup/common/log.js"
|
|
880
|
-
},
|
|
881
|
-
require: {
|
|
882
|
-
types: "./dist/tsup/common/log.d.cts",
|
|
883
|
-
default: "./dist/tsup/common/log.cjs"
|
|
884
|
-
}
|
|
1260
|
+
writeProcessStdin: async (c, pid, data) => {
|
|
1261
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1262
|
+
agentOs2.writeProcessStdin(pid, data);
|
|
885
1263
|
},
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
default: "./dist/tsup/actor/errors.js"
|
|
890
|
-
},
|
|
891
|
-
require: {
|
|
892
|
-
types: "./dist/tsup/actor/errors.d.cts",
|
|
893
|
-
default: "./dist/tsup/actor/errors.cjs"
|
|
894
|
-
}
|
|
1264
|
+
closeProcessStdin: async (c, pid) => {
|
|
1265
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1266
|
+
agentOs2.closeProcessStdin(pid);
|
|
895
1267
|
},
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
default: "./dist/tsup/inspector/mod.js"
|
|
900
|
-
},
|
|
901
|
-
require: {
|
|
902
|
-
types: "./dist/tsup/inspector/mod.d.cts",
|
|
903
|
-
default: "./dist/tsup/inspector/mod.cjs"
|
|
904
|
-
}
|
|
1268
|
+
waitProcess: async (c, pid) => {
|
|
1269
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1270
|
+
return agentOs2.waitProcess(pid);
|
|
905
1271
|
},
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
default: "./dist/browser/inspector/client.js"
|
|
910
|
-
}
|
|
1272
|
+
listProcesses: async (c) => {
|
|
1273
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1274
|
+
return agentOs2.listProcesses();
|
|
911
1275
|
},
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
default: "./dist/tsup/utils.js"
|
|
916
|
-
},
|
|
917
|
-
require: {
|
|
918
|
-
types: "./dist/tsup/utils.d.cts",
|
|
919
|
-
default: "./dist/tsup/utils.cjs"
|
|
920
|
-
}
|
|
1276
|
+
allProcesses: async (c) => {
|
|
1277
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1278
|
+
return agentOs2.allProcesses();
|
|
921
1279
|
},
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
default: "./dist/tsup/agent-os/index.cjs"
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
},
|
|
933
|
-
engines: {
|
|
934
|
-
node: ">=22.0.0"
|
|
935
|
-
},
|
|
936
|
-
sideEffects: [
|
|
937
|
-
"./dist/tsup/chunk-*.js",
|
|
938
|
-
"./dist/tsup/chunk-*.cjs"
|
|
939
|
-
],
|
|
940
|
-
scripts: {
|
|
941
|
-
build: "tsup src/mod.ts src/client/mod.ts src/common/log.ts src/common/websocket.ts src/actor/errors.ts src/utils.ts src/workflow/mod.ts src/test/mod.ts src/inspector/mod.ts src/db/mod.ts src/db/drizzle.ts && tsup src/agent-os/index.ts --no-clean --out-dir dist/tsup/agent-os",
|
|
942
|
-
"build:browser": "tsup --config tsup.browser.config.ts",
|
|
943
|
-
"check-types": "tsc --noEmit",
|
|
944
|
-
lint: "biome check . && pnpm run check:test-skips && pnpm run check:wait-for-comments",
|
|
945
|
-
"lint:fix": "biome check --write .",
|
|
946
|
-
"check:test-skips": "tsx scripts/check-annotated-skips.ts",
|
|
947
|
-
"check:wait-for-comments": "tsx scripts/check-wait-for-comments.ts",
|
|
948
|
-
format: "biome format .",
|
|
949
|
-
"format:write": "biome format --write .",
|
|
950
|
-
test: "vitest run",
|
|
951
|
-
"test:platforms": "pnpm run build && RIVETKIT_INCLUDE_PLATFORM_TESTS=1 vitest run tests/platforms --passWithNoTests",
|
|
952
|
-
"test:watch": "vitest",
|
|
953
|
-
"dump-asyncapi": "tsx scripts/dump-asyncapi.ts",
|
|
954
|
-
"registry-config-schema-gen": "tsx scripts/registry-config-schema-gen.ts",
|
|
955
|
-
"actor-config-schema-gen": "tsx scripts/actor-config-schema-gen.ts"
|
|
956
|
-
},
|
|
957
|
-
dependencies: {
|
|
958
|
-
"@rivet-dev/agent-os-core": "^0.1.1",
|
|
959
|
-
"@hono/node-server": "^1.18.2",
|
|
960
|
-
"@hono/node-ws": "^1.1.1",
|
|
961
|
-
"@hono/zod-openapi": "^1.1.5",
|
|
962
|
-
"@rivetkit/bare-ts": "^0.6.2",
|
|
963
|
-
"@rivetkit/engine-cli": "workspace:*",
|
|
964
|
-
"@rivetkit/engine-envoy-protocol": "workspace:*",
|
|
965
|
-
"@rivetkit/rivetkit-napi": "workspace:*",
|
|
966
|
-
"@rivetkit/rivetkit-wasm": "workspace:*",
|
|
967
|
-
"@rivetkit/traces": "workspace:*",
|
|
968
|
-
"@rivetkit/virtual-websocket": "workspace:*",
|
|
969
|
-
"@rivetkit/workflow-engine": "workspace:*",
|
|
970
|
-
"cbor-x": "^1.6.0",
|
|
971
|
-
"drizzle-orm": "^0.44.2",
|
|
972
|
-
"get-port": "^7.1.0",
|
|
973
|
-
hono: "^4.7.0",
|
|
974
|
-
invariant: "^2.2.4",
|
|
975
|
-
"p-retry": "^6.2.1",
|
|
976
|
-
pino: "^9.5.0",
|
|
977
|
-
uuid: "^12.0.0",
|
|
978
|
-
vbare: "^0.0.4",
|
|
979
|
-
zod: "^4.1.0"
|
|
980
|
-
},
|
|
981
|
-
devDependencies: {
|
|
982
|
-
"@copilotkit/llmock": "^1.6.0",
|
|
983
|
-
"@rivet-dev/agent-os-common": "*",
|
|
984
|
-
"@rivet-dev/agent-os-pi": "^0.1.1",
|
|
985
|
-
"@biomejs/biome": "^2.3",
|
|
986
|
-
"@standard-schema/spec": "^1.0.0",
|
|
987
|
-
"@types/invariant": "^2",
|
|
988
|
-
"@types/node": "^22.13.1",
|
|
989
|
-
eventsource: "^4.0.0",
|
|
990
|
-
tsup: "^8.4.0",
|
|
991
|
-
tsx: "^4.19.4",
|
|
992
|
-
typescript: "^5.7.3",
|
|
993
|
-
"vite-tsconfig-paths": "^5.1.4",
|
|
994
|
-
vitest: "^3.1.1",
|
|
995
|
-
ws: "^8.18.1"
|
|
996
|
-
},
|
|
997
|
-
peerDependencies: {
|
|
998
|
-
"drizzle-kit": "^0.31.2",
|
|
999
|
-
eventsource: "^4.0.0",
|
|
1000
|
-
ws: "^8.0.0"
|
|
1001
|
-
},
|
|
1002
|
-
peerDependenciesMeta: {
|
|
1003
|
-
"drizzle-kit": {
|
|
1004
|
-
optional: true
|
|
1280
|
+
processTree: async (c) => {
|
|
1281
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1282
|
+
return agentOs2.processTree();
|
|
1283
|
+
},
|
|
1284
|
+
getProcess: async (c, pid) => {
|
|
1285
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1286
|
+
return agentOs2.getProcess(pid);
|
|
1005
1287
|
},
|
|
1006
|
-
|
|
1007
|
-
|
|
1288
|
+
stopProcess: async (c, pid) => {
|
|
1289
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1290
|
+
agentOs2.stopProcess(pid);
|
|
1008
1291
|
},
|
|
1009
|
-
|
|
1010
|
-
|
|
1292
|
+
killProcess: async (c, pid) => {
|
|
1293
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1294
|
+
agentOs2.killProcess(pid);
|
|
1011
1295
|
}
|
|
1012
|
-
}
|
|
1013
|
-
stableVersion: "0.8.0"
|
|
1014
|
-
};
|
|
1015
|
-
|
|
1016
|
-
// src/utils.ts
|
|
1017
|
-
var VERSION = package_default.version;
|
|
1018
|
-
function getEnvUniversal(key) {
|
|
1019
|
-
if (typeof Deno !== "undefined") {
|
|
1020
|
-
return Deno.env.get(key);
|
|
1021
|
-
} else if (typeof process !== "undefined") {
|
|
1022
|
-
return process.env[key];
|
|
1023
|
-
}
|
|
1296
|
+
};
|
|
1024
1297
|
}
|
|
1025
1298
|
|
|
1026
|
-
// src/
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
"debug",
|
|
1038
|
-
"info",
|
|
1039
|
-
"warn",
|
|
1040
|
-
"error",
|
|
1041
|
-
"fatal",
|
|
1042
|
-
"silent"
|
|
1043
|
-
]);
|
|
1044
|
-
function getPinoLevel(logLevel) {
|
|
1045
|
-
if (logLevel) {
|
|
1046
|
-
return logLevel;
|
|
1047
|
-
}
|
|
1048
|
-
if (configuredLogLevel) {
|
|
1049
|
-
return configuredLogLevel;
|
|
1299
|
+
// src/agent-os/actor/session.ts
|
|
1300
|
+
function stripFunctions(value) {
|
|
1301
|
+
if (value === null || value === void 0) return value;
|
|
1302
|
+
if (typeof value === "function") return void 0;
|
|
1303
|
+
if (typeof value !== "object") return value;
|
|
1304
|
+
if (Array.isArray(value)) return value.map(stripFunctions);
|
|
1305
|
+
const out = {};
|
|
1306
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1307
|
+
if (typeof v !== "function") {
|
|
1308
|
+
out[k] = stripFunctions(v);
|
|
1309
|
+
}
|
|
1050
1310
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1311
|
+
return out;
|
|
1312
|
+
}
|
|
1313
|
+
function assertSessionExists(c, sessionId) {
|
|
1314
|
+
if (!c.vars.sessions.has(sessionId)) {
|
|
1315
|
+
throw new Error(`session not found: ${sessionId}`);
|
|
1055
1316
|
}
|
|
1056
|
-
return "info";
|
|
1057
1317
|
}
|
|
1058
|
-
function
|
|
1059
|
-
return
|
|
1318
|
+
function toSessionRecord(agentOs2, sessionId, agentType) {
|
|
1319
|
+
return {
|
|
1320
|
+
sessionId,
|
|
1321
|
+
agentType,
|
|
1322
|
+
capabilities: agentOs2.getSessionCapabilities(sessionId) ?? {},
|
|
1323
|
+
agentInfo: agentOs2.getSessionAgentInfo(sessionId)
|
|
1324
|
+
};
|
|
1060
1325
|
}
|
|
1061
|
-
function
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1326
|
+
async function persistSession(c, agentOs2, sessionId, agentType) {
|
|
1327
|
+
const now = Date.now();
|
|
1328
|
+
const capabilities = agentOs2.getSessionCapabilities(sessionId) ?? {};
|
|
1329
|
+
const agentInfo = agentOs2.getSessionAgentInfo(sessionId);
|
|
1330
|
+
await c.db.execute(
|
|
1331
|
+
`INSERT OR REPLACE INTO agent_os_sessions (session_id, agent_type, capabilities, agent_info, created_at)
|
|
1332
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
1333
|
+
sessionId,
|
|
1334
|
+
agentType,
|
|
1335
|
+
JSON.stringify(capabilities),
|
|
1336
|
+
agentInfo ? JSON.stringify(agentInfo) : null,
|
|
1337
|
+
now
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
async function persistSessionEvent(c, sessionId, event2) {
|
|
1341
|
+
var _a;
|
|
1342
|
+
const now = Date.now();
|
|
1343
|
+
const rows = await c.db.execute(
|
|
1344
|
+
`SELECT MAX(seq) as max_seq FROM agent_os_session_events WHERE session_id = ?`,
|
|
1345
|
+
sessionId
|
|
1346
|
+
);
|
|
1347
|
+
const nextSeq = (((_a = rows[0]) == null ? void 0 : _a.max_seq) ?? -1) + 1;
|
|
1348
|
+
await c.db.execute(
|
|
1349
|
+
`INSERT INTO agent_os_session_events (session_id, seq, event, created_at)
|
|
1350
|
+
VALUES (?, ?, ?, ?)`,
|
|
1351
|
+
sessionId,
|
|
1352
|
+
nextSeq,
|
|
1353
|
+
JSON.stringify(event2),
|
|
1354
|
+
now
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
async function deletePersistedSession(c, sessionId) {
|
|
1358
|
+
await c.db.execute(
|
|
1359
|
+
`DELETE FROM agent_os_session_events WHERE session_id = ?`,
|
|
1360
|
+
sessionId
|
|
1361
|
+
);
|
|
1362
|
+
await c.db.execute(
|
|
1363
|
+
`DELETE FROM agent_os_sessions WHERE session_id = ?`,
|
|
1364
|
+
sessionId
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
function subscribeToSession(c, agentOs2, sessionId, parsedConfig) {
|
|
1368
|
+
agentOs2.onSessionEvent(sessionId, (event2) => {
|
|
1369
|
+
c.broadcast(
|
|
1370
|
+
"sessionEvent",
|
|
1371
|
+
JSON.parse(JSON.stringify({ sessionId, event: event2 }))
|
|
1372
|
+
);
|
|
1373
|
+
persistSessionEvent(c, sessionId, event2).catch(
|
|
1374
|
+
(error) => c.log.error({
|
|
1375
|
+
msg: "agent-os failed to persist session event",
|
|
1376
|
+
sessionId,
|
|
1377
|
+
error
|
|
1378
|
+
})
|
|
1379
|
+
);
|
|
1380
|
+
if (parsedConfig.onSessionEvent) {
|
|
1381
|
+
runHook(
|
|
1382
|
+
c,
|
|
1383
|
+
"onSessionEvent",
|
|
1384
|
+
() => {
|
|
1385
|
+
var _a;
|
|
1386
|
+
return (_a = parsedConfig.onSessionEvent) == null ? void 0 : _a.call(parsedConfig, c, sessionId, event2);
|
|
1075
1387
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
agentOs2.onPermissionRequest(sessionId, (request) => {
|
|
1392
|
+
c.broadcast(
|
|
1393
|
+
"permissionRequest",
|
|
1394
|
+
JSON.parse(JSON.stringify({ sessionId, request }))
|
|
1395
|
+
);
|
|
1396
|
+
if (parsedConfig.onPermissionRequest) {
|
|
1397
|
+
runHook(
|
|
1398
|
+
c,
|
|
1399
|
+
"onPermissionRequest",
|
|
1400
|
+
() => {
|
|
1401
|
+
var _a;
|
|
1402
|
+
return (_a = parsedConfig.onPermissionRequest) == null ? void 0 : _a.call(parsedConfig, c, sessionId, request);
|
|
1403
|
+
}
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
});
|
|
1407
|
+
c.vars.sessions.add(sessionId);
|
|
1408
|
+
}
|
|
1409
|
+
function buildSessionActions(config) {
|
|
1410
|
+
return {
|
|
1411
|
+
createSession: async (c, agentType, options) => {
|
|
1412
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1413
|
+
const { sessionId } = await agentOs2.createSession(
|
|
1414
|
+
agentType,
|
|
1415
|
+
options
|
|
1416
|
+
);
|
|
1417
|
+
subscribeToSession(c, agentOs2, sessionId, config);
|
|
1418
|
+
await persistSession(c, agentOs2, sessionId, agentType);
|
|
1419
|
+
c.log.info({
|
|
1420
|
+
msg: "agent-os session created",
|
|
1421
|
+
sessionId,
|
|
1422
|
+
agentType
|
|
1423
|
+
});
|
|
1424
|
+
return toSessionRecord(agentOs2, sessionId, agentType);
|
|
1425
|
+
},
|
|
1426
|
+
listSessions: async (c) => {
|
|
1427
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1428
|
+
return agentOs2.listSessions();
|
|
1429
|
+
},
|
|
1430
|
+
getSession: async (c, sessionId) => {
|
|
1431
|
+
assertSessionExists(c, sessionId);
|
|
1432
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1433
|
+
const info = agentOs2.listSessions().find((s) => s.sessionId === sessionId);
|
|
1434
|
+
if (!info) {
|
|
1435
|
+
throw new Error(`session not found: ${sessionId}`);
|
|
1436
|
+
}
|
|
1437
|
+
return toSessionRecord(agentOs2, sessionId, info.agentType);
|
|
1438
|
+
},
|
|
1439
|
+
destroySession: async (c, sessionId) => {
|
|
1440
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1441
|
+
await agentOs2.destroySession(sessionId);
|
|
1442
|
+
c.vars.sessions.delete(sessionId);
|
|
1443
|
+
c.vars.activeSessionIds.delete(sessionId);
|
|
1444
|
+
syncPreventSleep(c);
|
|
1445
|
+
await deletePersistedSession(c, sessionId);
|
|
1446
|
+
c.log.info({ msg: "agent-os session destroyed", sessionId });
|
|
1447
|
+
},
|
|
1448
|
+
resumeSession: async (c, sessionId) => {
|
|
1449
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1450
|
+
return agentOs2.resumeSession(sessionId);
|
|
1451
|
+
},
|
|
1452
|
+
closeSession: async (c, sessionId) => {
|
|
1453
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1454
|
+
agentOs2.closeSession(sessionId);
|
|
1455
|
+
c.vars.sessions.delete(sessionId);
|
|
1456
|
+
c.vars.activeSessionIds.delete(sessionId);
|
|
1457
|
+
syncPreventSleep(c);
|
|
1458
|
+
await deletePersistedSession(c, sessionId);
|
|
1459
|
+
c.log.info({ msg: "agent-os session closed", sessionId });
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
function buildPromptActions(_config) {
|
|
1464
|
+
return {
|
|
1465
|
+
sendPrompt: async (c, sessionId, text) => {
|
|
1466
|
+
if (c.aborted) {
|
|
1467
|
+
throw new Error(
|
|
1468
|
+
"actor is shutting down, cannot start new prompt"
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
assertSessionExists(c, sessionId);
|
|
1472
|
+
const agentOs2 = c.vars.agentOs;
|
|
1473
|
+
if (!agentOs2) {
|
|
1474
|
+
throw new Error("VM not initialized");
|
|
1475
|
+
}
|
|
1476
|
+
c.vars.activeSessionIds.add(sessionId);
|
|
1477
|
+
syncPreventSleep(c);
|
|
1478
|
+
c.log.info({ msg: "agent-os prompt turn started", sessionId });
|
|
1479
|
+
const start = Date.now();
|
|
1480
|
+
try {
|
|
1481
|
+
const result = await agentOs2.prompt(sessionId, text);
|
|
1482
|
+
return {
|
|
1483
|
+
response: JSON.parse(JSON.stringify(result.response)),
|
|
1484
|
+
text: result.text
|
|
1485
|
+
};
|
|
1486
|
+
} finally {
|
|
1487
|
+
c.vars.activeSessionIds.delete(sessionId);
|
|
1488
|
+
syncPreventSleep(c);
|
|
1489
|
+
c.log.info({
|
|
1490
|
+
msg: "agent-os prompt turn ended",
|
|
1491
|
+
sessionId,
|
|
1492
|
+
durationMs: Date.now() - start
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1078
1495
|
},
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1496
|
+
cancelPrompt: async (c, sessionId) => {
|
|
1497
|
+
assertSessionExists(c, sessionId);
|
|
1498
|
+
const agentOs2 = c.vars.agentOs;
|
|
1499
|
+
if (!agentOs2) {
|
|
1500
|
+
throw new Error("VM not initialized");
|
|
1501
|
+
}
|
|
1502
|
+
return stripFunctions(
|
|
1503
|
+
agentOs2.cancelSession(sessionId)
|
|
1504
|
+
);
|
|
1505
|
+
},
|
|
1506
|
+
respondPermission: async (c, sessionId, permissionId, reply) => {
|
|
1507
|
+
assertSessionExists(c, sessionId);
|
|
1508
|
+
const agentOs2 = c.vars.agentOs;
|
|
1509
|
+
if (!agentOs2) {
|
|
1510
|
+
throw new Error("VM not initialized");
|
|
1511
|
+
}
|
|
1512
|
+
return stripFunctions(
|
|
1513
|
+
agentOs2.respondPermission(sessionId, permissionId, reply)
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1098
1517
|
}
|
|
1099
|
-
|
|
1100
|
-
10: "trace",
|
|
1101
|
-
20: "debug",
|
|
1102
|
-
30: "info",
|
|
1103
|
-
40: "warn",
|
|
1104
|
-
50: "error",
|
|
1105
|
-
60: "fatal"
|
|
1106
|
-
};
|
|
1107
|
-
function createLogfmtDestination() {
|
|
1518
|
+
function buildConfigActions(_config) {
|
|
1108
1519
|
return {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
const
|
|
1112
|
-
if (
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1520
|
+
setMode: async (c, sessionId, modeId) => {
|
|
1521
|
+
assertSessionExists(c, sessionId);
|
|
1522
|
+
const agentOs2 = c.vars.agentOs;
|
|
1523
|
+
if (!agentOs2) {
|
|
1524
|
+
throw new Error("VM not initialized");
|
|
1525
|
+
}
|
|
1526
|
+
return stripFunctions(
|
|
1527
|
+
agentOs2.setSessionMode(sessionId, modeId)
|
|
1528
|
+
);
|
|
1529
|
+
},
|
|
1530
|
+
getModes: async (c, sessionId) => {
|
|
1531
|
+
assertSessionExists(c, sessionId);
|
|
1532
|
+
const agentOs2 = c.vars.agentOs;
|
|
1533
|
+
if (!agentOs2) {
|
|
1534
|
+
throw new Error("VM not initialized");
|
|
1535
|
+
}
|
|
1536
|
+
return agentOs2.getSessionModes(sessionId);
|
|
1537
|
+
},
|
|
1538
|
+
setModel: async (c, sessionId, model) => {
|
|
1539
|
+
assertSessionExists(c, sessionId);
|
|
1540
|
+
const agentOs2 = c.vars.agentOs;
|
|
1541
|
+
if (!agentOs2) {
|
|
1542
|
+
throw new Error("VM not initialized");
|
|
1543
|
+
}
|
|
1544
|
+
return stripFunctions(
|
|
1545
|
+
agentOs2.setSessionModel(sessionId, model)
|
|
1546
|
+
);
|
|
1547
|
+
},
|
|
1548
|
+
setThoughtLevel: async (c, sessionId, level) => {
|
|
1549
|
+
assertSessionExists(c, sessionId);
|
|
1550
|
+
const agentOs2 = c.vars.agentOs;
|
|
1551
|
+
if (!agentOs2) {
|
|
1552
|
+
throw new Error("VM not initialized");
|
|
1553
|
+
}
|
|
1554
|
+
return stripFunctions(
|
|
1555
|
+
agentOs2.setSessionThoughtLevel(sessionId, level)
|
|
1556
|
+
);
|
|
1557
|
+
},
|
|
1558
|
+
getConfigOptions: async (c, sessionId) => {
|
|
1559
|
+
assertSessionExists(c, sessionId);
|
|
1560
|
+
const agentOs2 = c.vars.agentOs;
|
|
1561
|
+
if (!agentOs2) {
|
|
1562
|
+
throw new Error("VM not initialized");
|
|
1563
|
+
}
|
|
1564
|
+
return agentOs2.getSessionConfigOptions(sessionId);
|
|
1565
|
+
},
|
|
1566
|
+
getEvents: async (c, sessionId, options) => {
|
|
1567
|
+
assertSessionExists(c, sessionId);
|
|
1568
|
+
const agentOs2 = c.vars.agentOs;
|
|
1569
|
+
if (!agentOs2) {
|
|
1570
|
+
throw new Error("VM not initialized");
|
|
1571
|
+
}
|
|
1572
|
+
return agentOs2.getSessionEvents(sessionId, options).map((e) => e.notification);
|
|
1573
|
+
},
|
|
1574
|
+
getSequencedEvents: async (c, sessionId, options) => {
|
|
1575
|
+
assertSessionExists(c, sessionId);
|
|
1576
|
+
const agentOs2 = c.vars.agentOs;
|
|
1577
|
+
if (!agentOs2) {
|
|
1578
|
+
throw new Error("VM not initialized");
|
|
1579
|
+
}
|
|
1580
|
+
return agentOs2.getSessionEvents(sessionId, options);
|
|
1581
|
+
},
|
|
1582
|
+
rawSend: async (c, sessionId, method, params) => {
|
|
1583
|
+
assertSessionExists(c, sessionId);
|
|
1584
|
+
const agentOs2 = c.vars.agentOs;
|
|
1585
|
+
if (!agentOs2) {
|
|
1586
|
+
throw new Error("VM not initialized");
|
|
1117
1587
|
}
|
|
1588
|
+
return stripFunctions(
|
|
1589
|
+
agentOs2.rawSessionSend(sessionId, method, params)
|
|
1590
|
+
);
|
|
1118
1591
|
}
|
|
1119
1592
|
};
|
|
1120
1593
|
}
|
|
1121
|
-
function
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1594
|
+
function buildSessionPersistenceActions(_config) {
|
|
1595
|
+
return {
|
|
1596
|
+
listPersistedSessions: async (c) => {
|
|
1597
|
+
const rows = await c.db.execute(
|
|
1598
|
+
`SELECT session_id, agent_type, capabilities, agent_info, created_at
|
|
1599
|
+
FROM agent_os_sessions
|
|
1600
|
+
ORDER BY created_at ASC`
|
|
1601
|
+
);
|
|
1602
|
+
return rows.map((row) => ({
|
|
1603
|
+
sessionId: row.session_id,
|
|
1604
|
+
agentType: row.agent_type,
|
|
1605
|
+
capabilities: JSON.parse(row.capabilities),
|
|
1606
|
+
agentInfo: row.agent_info ? JSON.parse(row.agent_info) : null,
|
|
1607
|
+
createdAt: row.created_at
|
|
1608
|
+
}));
|
|
1609
|
+
},
|
|
1610
|
+
getSessionEvents: async (c, sessionId) => {
|
|
1611
|
+
const rows = await c.db.execute(
|
|
1612
|
+
`SELECT session_id, seq, event, created_at
|
|
1613
|
+
FROM agent_os_session_events
|
|
1614
|
+
WHERE session_id = ?
|
|
1615
|
+
ORDER BY seq ASC`,
|
|
1616
|
+
sessionId
|
|
1617
|
+
);
|
|
1618
|
+
return rows.map((row) => ({
|
|
1619
|
+
sessionId: row.session_id,
|
|
1620
|
+
seq: row.seq,
|
|
1621
|
+
event: JSON.parse(row.event),
|
|
1622
|
+
createdAt: row.created_at
|
|
1623
|
+
}));
|
|
1136
1624
|
}
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1139
|
-
return parts.join(" ");
|
|
1140
|
-
}
|
|
1141
|
-
function formatPinoLevel(level) {
|
|
1142
|
-
if (typeof level === "number") {
|
|
1143
|
-
return PINO_LEVEL_LABELS[level] ?? level.toString();
|
|
1144
|
-
}
|
|
1145
|
-
if (typeof level === "string") {
|
|
1146
|
-
return level.toLowerCase();
|
|
1147
|
-
}
|
|
1148
|
-
return "info";
|
|
1149
|
-
}
|
|
1150
|
-
function appendLogfmtEntry(parts, key, value) {
|
|
1151
|
-
const safeKey = key.replace(/[\s="]/g, "");
|
|
1152
|
-
if (safeKey.length === 0) {
|
|
1153
|
-
return;
|
|
1154
|
-
}
|
|
1155
|
-
parts.push(`${safeKey}=${formatLogfmtValue(value)}`);
|
|
1156
|
-
}
|
|
1157
|
-
function formatLogfmtValue(value) {
|
|
1158
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
1159
|
-
return String(value);
|
|
1160
|
-
}
|
|
1161
|
-
if (value === null || value === void 0) {
|
|
1162
|
-
return "null";
|
|
1163
|
-
}
|
|
1164
|
-
if (typeof value === "string") {
|
|
1165
|
-
return quoteLogfmtString(value);
|
|
1166
|
-
}
|
|
1167
|
-
return quoteLogfmtString(JSON.stringify(value));
|
|
1168
|
-
}
|
|
1169
|
-
function quoteLogfmtString(value) {
|
|
1170
|
-
if (!/[\s="]/.test(value)) {
|
|
1171
|
-
return value;
|
|
1172
|
-
}
|
|
1173
|
-
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
// src/actor/log.ts
|
|
1177
|
-
function loggerWithoutContext() {
|
|
1178
|
-
return getLogger("actor-runtime");
|
|
1625
|
+
};
|
|
1179
1626
|
}
|
|
1180
1627
|
|
|
1181
|
-
// src/actor/
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
loggerWithoutContext().warn({
|
|
1190
|
-
msg: `actor option \`${key}\` is deprecated and is now ignored. Configure \`sleepGracePeriod\` instead, which bounds the entire graceful shutdown window for both sleep and destroy. Will be removed in 2.2.0.`
|
|
1628
|
+
// src/agent-os/actor/shell.ts
|
|
1629
|
+
function buildShellActions(config) {
|
|
1630
|
+
return {
|
|
1631
|
+
openShell: async (c, options) => {
|
|
1632
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1633
|
+
const { shellId } = agentOs2.openShell(options);
|
|
1634
|
+
agentOs2.onShellData(shellId, (data) => {
|
|
1635
|
+
c.broadcast("shellData", { shellId, data });
|
|
1191
1636
|
});
|
|
1637
|
+
c.vars.activeShells.add(shellId);
|
|
1638
|
+
syncPreventSleep(c);
|
|
1639
|
+
c.log.info({ msg: "agent-os shell opened", shellId });
|
|
1640
|
+
return { shellId };
|
|
1641
|
+
},
|
|
1642
|
+
writeShell: async (c, shellId, data) => {
|
|
1643
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1644
|
+
agentOs2.writeShell(shellId, data);
|
|
1645
|
+
},
|
|
1646
|
+
resizeShell: async (c, shellId, cols, rows) => {
|
|
1647
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1648
|
+
agentOs2.resizeShell(shellId, cols, rows);
|
|
1649
|
+
},
|
|
1650
|
+
closeShell: async (c, shellId) => {
|
|
1651
|
+
const agentOs2 = await ensureVm(c, config);
|
|
1652
|
+
agentOs2.closeShell(shellId);
|
|
1653
|
+
c.vars.activeShells.delete(shellId);
|
|
1654
|
+
syncPreventSleep(c);
|
|
1655
|
+
c.log.info({ msg: "agent-os shell closed", shellId });
|
|
1192
1656
|
}
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
var ActorDefinition = class {
|
|
1196
|
-
#config;
|
|
1197
|
-
constructor(config) {
|
|
1198
|
-
this.#config = config;
|
|
1199
|
-
}
|
|
1200
|
-
get config() {
|
|
1201
|
-
return this.#config;
|
|
1202
|
-
}
|
|
1203
|
-
};
|
|
1204
|
-
function actor(input) {
|
|
1205
|
-
warnDeprecatedShutdownTimeoutKeys(
|
|
1206
|
-
input == null ? void 0 : input.options
|
|
1207
|
-
);
|
|
1208
|
-
const config = ActorConfigSchema.parse(input);
|
|
1209
|
-
return new ActorDefinition(config);
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
// src/actor/schema.ts
|
|
1213
|
-
function event(options) {
|
|
1214
|
-
return options ?? {};
|
|
1657
|
+
};
|
|
1215
1658
|
}
|
|
1216
1659
|
|
|
1217
|
-
// src/
|
|
1218
|
-
function
|
|
1219
|
-
if (
|
|
1220
|
-
return
|
|
1221
|
-
}
|
|
1222
|
-
if (Array.isArray(value)) {
|
|
1223
|
-
return value.every((item) => typeof item === "number");
|
|
1224
|
-
}
|
|
1225
|
-
return false;
|
|
1226
|
-
}
|
|
1227
|
-
function isPlainObject(value) {
|
|
1228
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1229
|
-
return false;
|
|
1660
|
+
// src/agent-os/actor/index.ts
|
|
1661
|
+
async function ensureVm(c, config) {
|
|
1662
|
+
if (c.vars.agentOs) {
|
|
1663
|
+
return c.vars.agentOs;
|
|
1230
1664
|
}
|
|
1231
|
-
|
|
1665
|
+
const start = Date.now();
|
|
1666
|
+
const options = buildVmOptions(config.options);
|
|
1667
|
+
const agentOs2 = await AgentOs.create(options);
|
|
1668
|
+
c.vars.agentOs = agentOs2;
|
|
1669
|
+
agentOs2.onCronEvent((cronEvent) => {
|
|
1670
|
+
c.broadcast("cronEvent", { event: cronEvent });
|
|
1671
|
+
});
|
|
1672
|
+
c.broadcast("vmBooted", {});
|
|
1673
|
+
c.log.info({
|
|
1674
|
+
msg: "agent-os vm booted",
|
|
1675
|
+
bootDurationMs: Date.now() - start
|
|
1676
|
+
});
|
|
1677
|
+
return agentOs2;
|
|
1232
1678
|
}
|
|
1233
|
-
function
|
|
1234
|
-
|
|
1235
|
-
|
|
1679
|
+
function buildVmOptions(userOptions) {
|
|
1680
|
+
const userMounts = (userOptions == null ? void 0 : userOptions.mounts) ?? [];
|
|
1681
|
+
const hasWorkdirMount = userMounts.some(
|
|
1682
|
+
(m) => m.path === "/home/user"
|
|
1683
|
+
);
|
|
1684
|
+
if (hasWorkdirMount) {
|
|
1685
|
+
return userOptions ?? {};
|
|
1236
1686
|
}
|
|
1237
|
-
|
|
1687
|
+
const memMount = {
|
|
1688
|
+
path: "/home/user",
|
|
1689
|
+
driver: createInMemoryFileSystem()
|
|
1690
|
+
};
|
|
1691
|
+
return {
|
|
1692
|
+
...userOptions,
|
|
1693
|
+
mounts: [memMount, ...userMounts]
|
|
1694
|
+
};
|
|
1238
1695
|
}
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}
|
|
1250
|
-
if (isSqliteBindingObject(input)) {
|
|
1251
|
-
return input;
|
|
1252
|
-
}
|
|
1253
|
-
throw new Error("unsupported sqlite binding collection");
|
|
1696
|
+
function syncPreventSleep(c) {
|
|
1697
|
+
const shouldPrevent = c.vars.activeSessionIds.size > 0 || c.vars.activeProcesses.size > 0 || c.vars.activeHooks.size > 0 || c.vars.activeShells.size > 0;
|
|
1698
|
+
c.setPreventSleep(shouldPrevent);
|
|
1699
|
+
c.log.info({
|
|
1700
|
+
msg: "agent-os prevent sleep sync",
|
|
1701
|
+
preventSleep: shouldPrevent,
|
|
1702
|
+
activeSessions: c.vars.activeSessionIds.size,
|
|
1703
|
+
activeProcesses: c.vars.activeProcesses.size,
|
|
1704
|
+
activeHooks: c.vars.activeHooks.size,
|
|
1705
|
+
activeShells: c.vars.activeShells.size
|
|
1706
|
+
});
|
|
1254
1707
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1708
|
+
function runHook(c, name, callback) {
|
|
1709
|
+
const promise = Promise.resolve(callback()).catch(
|
|
1710
|
+
(error) => c.log.error({ msg: "agent-os hook failed", hookName: name, error })
|
|
1711
|
+
).finally(() => {
|
|
1712
|
+
c.vars.activeHooks.delete(promise);
|
|
1713
|
+
syncPreventSleep(c);
|
|
1714
|
+
});
|
|
1715
|
+
c.vars.activeHooks.add(promise);
|
|
1716
|
+
syncPreventSleep(c);
|
|
1717
|
+
c.waitUntil(promise);
|
|
1260
1718
|
}
|
|
1261
|
-
function
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
const client = {
|
|
1282
|
-
execute: async (query, ...args) => {
|
|
1283
|
-
var _a, _b, _c, _d;
|
|
1284
|
-
ensureOpen();
|
|
1285
|
-
const kvReadsBefore = ((_a = ctx.metrics) == null ? void 0 : _a.totalKvReads) ?? 0;
|
|
1286
|
-
const kvWritesBefore = ((_b = ctx.metrics) == null ? void 0 : _b.totalKvWrites) ?? 0;
|
|
1287
|
-
const start = performance.now();
|
|
1288
|
-
try {
|
|
1289
|
-
if (args.length > 0) {
|
|
1290
|
-
const bindings = args.length === 1 && isSqliteBindingObject(args[0]) ? toSqliteBindings(args[0]) : toSqliteBindings(args);
|
|
1291
|
-
const { rows, columns } = await db2.execute(
|
|
1292
|
-
query,
|
|
1293
|
-
bindings
|
|
1294
|
-
);
|
|
1295
|
-
return rows.map(
|
|
1296
|
-
(row) => rowToObject(row, columns)
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1299
|
-
if (!hasMultipleStatements(query)) {
|
|
1300
|
-
const { rows, columns } = await db2.execute(query);
|
|
1301
|
-
return rows.map(
|
|
1302
|
-
(row) => rowToObject(row, columns)
|
|
1303
|
-
);
|
|
1304
|
-
}
|
|
1305
|
-
return await execMultiStatement(db2, query);
|
|
1306
|
-
} finally {
|
|
1307
|
-
const durationMs = performance.now() - start;
|
|
1308
|
-
(_c = ctx.metrics) == null ? void 0 : _c.trackSql(query, durationMs);
|
|
1309
|
-
if (ctx.metrics) {
|
|
1310
|
-
const kvReads = ctx.metrics.totalKvReads - kvReadsBefore;
|
|
1311
|
-
const kvWrites = ctx.metrics.totalKvWrites - kvWritesBefore;
|
|
1312
|
-
(_d = ctx.log) == null ? void 0 : _d.debug({
|
|
1313
|
-
msg: "sql query",
|
|
1314
|
-
query: query.slice(0, 120),
|
|
1315
|
-
durationMs,
|
|
1316
|
-
kvReads,
|
|
1317
|
-
kvWrites
|
|
1318
|
-
});
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
},
|
|
1322
|
-
close: async () => {
|
|
1323
|
-
if (!closed) {
|
|
1324
|
-
closed = true;
|
|
1325
|
-
await db2.close();
|
|
1326
|
-
}
|
|
1327
|
-
},
|
|
1328
|
-
nativeMetrics: () => {
|
|
1329
|
-
var _a;
|
|
1330
|
-
return ((_a = db2.nativeMetrics) == null ? void 0 : _a.call(db2)) ?? null;
|
|
1331
|
-
}
|
|
1332
|
-
};
|
|
1333
|
-
return client;
|
|
1719
|
+
function agentOs(config) {
|
|
1720
|
+
const parsedConfig = agentOsActorConfigSchema.parse(
|
|
1721
|
+
config
|
|
1722
|
+
);
|
|
1723
|
+
const actions = {
|
|
1724
|
+
...buildSessionActions(parsedConfig),
|
|
1725
|
+
...buildPromptActions(parsedConfig),
|
|
1726
|
+
...buildConfigActions(parsedConfig),
|
|
1727
|
+
...buildSessionPersistenceActions(parsedConfig),
|
|
1728
|
+
...buildProcessActions(parsedConfig),
|
|
1729
|
+
...buildFilesystemActions(parsedConfig),
|
|
1730
|
+
...buildPreviewActions(parsedConfig),
|
|
1731
|
+
...buildShellActions(parsedConfig),
|
|
1732
|
+
...buildCronActions(parsedConfig),
|
|
1733
|
+
...buildNetworkActions(parsedConfig)
|
|
1734
|
+
};
|
|
1735
|
+
return actor({
|
|
1736
|
+
options: {
|
|
1737
|
+
sleepGracePeriod: 9e5,
|
|
1738
|
+
actionTimeout: 9e5
|
|
1334
1739
|
},
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1740
|
+
createState: async () => ({}),
|
|
1741
|
+
createVars: () => ({
|
|
1742
|
+
agentOs: null,
|
|
1743
|
+
activeSessionIds: /* @__PURE__ */ new Set(),
|
|
1744
|
+
activeProcesses: /* @__PURE__ */ new Set(),
|
|
1745
|
+
activeHooks: /* @__PURE__ */ new Set(),
|
|
1746
|
+
activeShells: /* @__PURE__ */ new Set(),
|
|
1747
|
+
sessions: /* @__PURE__ */ new Set()
|
|
1748
|
+
}),
|
|
1749
|
+
db: db({
|
|
1750
|
+
onMigrate: migrateAgentOsTables
|
|
1751
|
+
}),
|
|
1752
|
+
events: {
|
|
1753
|
+
sessionEvent: sessionEventToken,
|
|
1754
|
+
permissionRequest: permissionRequestToken,
|
|
1755
|
+
vmBooted: vmBootedToken,
|
|
1756
|
+
vmShutdown: vmShutdownToken,
|
|
1757
|
+
processOutput: processOutputToken,
|
|
1758
|
+
processExit: processExitToken,
|
|
1759
|
+
shellData: shellDataToken,
|
|
1760
|
+
cronEvent: cronEventToken
|
|
1761
|
+
},
|
|
1762
|
+
onBeforeConnect: parsedConfig.onBeforeConnect ? async (ctx, params) => {
|
|
1763
|
+
var _a;
|
|
1764
|
+
if (ctx.request) {
|
|
1765
|
+
const url = new URL(ctx.request.url);
|
|
1766
|
+
if (url.pathname.startsWith("/fetch/")) {
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1338
1769
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1770
|
+
await ((_a = parsedConfig.onBeforeConnect) == null ? void 0 : _a.call(parsedConfig, ctx, params));
|
|
1771
|
+
} : void 0,
|
|
1772
|
+
onRequest: buildOnRequestHandler(parsedConfig),
|
|
1773
|
+
onSleep: async (c) => {
|
|
1774
|
+
c.log.info({
|
|
1775
|
+
msg: "agent-os vm shutdown for sleep",
|
|
1776
|
+
activeSessions: c.vars.sessions.size,
|
|
1777
|
+
activeProcesses: c.vars.activeProcesses.size,
|
|
1778
|
+
activeShells: c.vars.activeShells.size
|
|
1779
|
+
});
|
|
1780
|
+
if (c.vars.agentOs) {
|
|
1781
|
+
await c.vars.agentOs.dispose();
|
|
1782
|
+
c.vars.agentOs = null;
|
|
1783
|
+
}
|
|
1784
|
+
c.broadcast("vmShutdown", { reason: "sleep" });
|
|
1785
|
+
},
|
|
1786
|
+
onDestroy: async (c) => {
|
|
1787
|
+
c.log.info({
|
|
1788
|
+
msg: "agent-os vm shutdown for destroy",
|
|
1789
|
+
activeSessions: c.vars.sessions.size,
|
|
1790
|
+
activeProcesses: c.vars.activeProcesses.size,
|
|
1791
|
+
activeShells: c.vars.activeShells.size
|
|
1792
|
+
});
|
|
1793
|
+
if (c.vars.agentOs) {
|
|
1794
|
+
await c.vars.agentOs.dispose();
|
|
1795
|
+
c.vars.agentOs = null;
|
|
1796
|
+
}
|
|
1797
|
+
c.broadcast("vmShutdown", { reason: "destroy" });
|
|
1798
|
+
},
|
|
1799
|
+
actions
|
|
1357
1800
|
});
|
|
1358
|
-
return results;
|
|
1359
|
-
}
|
|
1360
|
-
async function withMigrationSavepoint(client, callback) {
|
|
1361
|
-
await client.execute("SAVEPOINT __rivet_on_migrate");
|
|
1362
|
-
try {
|
|
1363
|
-
const result = await callback();
|
|
1364
|
-
await client.execute("RELEASE SAVEPOINT __rivet_on_migrate");
|
|
1365
|
-
return result;
|
|
1366
|
-
} catch (error) {
|
|
1367
|
-
try {
|
|
1368
|
-
await client.execute("ROLLBACK TO SAVEPOINT __rivet_on_migrate");
|
|
1369
|
-
} finally {
|
|
1370
|
-
await client.execute("RELEASE SAVEPOINT __rivet_on_migrate");
|
|
1371
|
-
}
|
|
1372
|
-
throw error;
|
|
1373
|
-
}
|
|
1374
1801
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
var
|
|
1379
|
-
var
|
|
1380
|
-
|
|
1381
|
-
);
|
|
1382
|
-
var
|
|
1383
|
-
options: AgentOsOptionsSchema.optional(),
|
|
1384
|
-
preview: z3.object({
|
|
1385
|
-
defaultExpiresInSeconds: z3.number().positive().default(3600),
|
|
1386
|
-
maxExpiresInSeconds: z3.number().positive().default(86400)
|
|
1387
|
-
}).strict().prefault(() => ({})),
|
|
1388
|
-
onBeforeConnect: zFunction2().optional(),
|
|
1389
|
-
onSessionEvent: zFunction2().optional(),
|
|
1390
|
-
onPermissionRequest: zFunction2().optional()
|
|
1391
|
-
}).strict();
|
|
1802
|
+
var sessionEventToken = event();
|
|
1803
|
+
var permissionRequestToken = event();
|
|
1804
|
+
var vmBootedToken = event();
|
|
1805
|
+
var vmShutdownToken = event();
|
|
1806
|
+
var processOutputToken = event();
|
|
1807
|
+
var processExitToken = event();
|
|
1808
|
+
var shellDataToken = event();
|
|
1809
|
+
var cronEventToken = event();
|
|
1392
1810
|
|
|
1393
1811
|
// src/agent-os/actor/cron.ts
|
|
1394
1812
|
function serializeCronAction(action) {
|
|
@@ -1412,859 +1830,517 @@ function serializeCronAction(action) {
|
|
|
1412
1830
|
}
|
|
1413
1831
|
}
|
|
1414
1832
|
function serializeCronJob(job) {
|
|
1415
|
-
var _a, _b;
|
|
1416
|
-
return {
|
|
1417
|
-
id: job.id,
|
|
1418
|
-
schedule: job.schedule,
|
|
1419
|
-
action: serializeCronAction(job.action),
|
|
1420
|
-
overlap: job.overlap,
|
|
1421
|
-
lastRun: (_a = job.lastRun) == null ? void 0 : _a.toISOString(),
|
|
1422
|
-
nextRun: (_b = job.nextRun) == null ? void 0 : _b.toISOString(),
|
|
1423
|
-
runCount: job.runCount,
|
|
1424
|
-
running: job.running
|
|
1425
|
-
};
|
|
1426
|
-
}
|
|
1427
|
-
function buildCronActions(config) {
|
|
1428
|
-
return {
|
|
1429
|
-
scheduleCron: async (c, options) => {
|
|
1430
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1431
|
-
const job = agentOs2.scheduleCron({
|
|
1432
|
-
id: options.id,
|
|
1433
|
-
schedule: options.schedule,
|
|
1434
|
-
action: options.action,
|
|
1435
|
-
overlap: options.overlap
|
|
1436
|
-
});
|
|
1437
|
-
c.log.info({
|
|
1438
|
-
msg: "agent-os cron job scheduled",
|
|
1439
|
-
jobId: job.id,
|
|
1440
|
-
schedule: options.schedule
|
|
1441
|
-
});
|
|
1442
|
-
return { id: job.id };
|
|
1443
|
-
},
|
|
1444
|
-
listCronJobs: async (c) => {
|
|
1445
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1446
|
-
return agentOs2.listCronJobs().map(serializeCronJob);
|
|
1447
|
-
},
|
|
1448
|
-
cancelCronJob: async (c, id) => {
|
|
1449
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1450
|
-
agentOs2.cancelCronJob(id);
|
|
1451
|
-
c.log.info({ msg: "agent-os cron job cancelled", jobId: id });
|
|
1452
|
-
}
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
// src/agent-os/actor/network.ts
|
|
1457
|
-
function buildNetworkActions(config) {
|
|
1458
|
-
return {
|
|
1459
|
-
vmFetch: async (c, port, url, options) => {
|
|
1460
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1461
|
-
const headers = new Headers(options == null ? void 0 : options.headers);
|
|
1462
|
-
const request = new Request(url, {
|
|
1463
|
-
method: (options == null ? void 0 : options.method) ?? "GET",
|
|
1464
|
-
headers,
|
|
1465
|
-
body: (options == null ? void 0 : options.body) ?? null
|
|
1466
|
-
});
|
|
1467
|
-
const response = await agentOs2.fetch(port, request);
|
|
1468
|
-
const responseHeaders = {};
|
|
1469
|
-
response.headers.forEach((value, key) => {
|
|
1470
|
-
responseHeaders[key] = value;
|
|
1471
|
-
});
|
|
1472
|
-
const body = new Uint8Array(await response.arrayBuffer());
|
|
1473
|
-
return {
|
|
1474
|
-
status: response.status,
|
|
1475
|
-
statusText: response.statusText,
|
|
1476
|
-
headers: responseHeaders,
|
|
1477
|
-
body
|
|
1478
|
-
};
|
|
1479
|
-
}
|
|
1480
|
-
};
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
// src/agent-os/actor/preview.ts
|
|
1484
|
-
import crypto from "crypto";
|
|
1485
|
-
function generateToken() {
|
|
1486
|
-
const bytes = crypto.randomBytes(32);
|
|
1487
|
-
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
1488
|
-
let token = "";
|
|
1489
|
-
for (let i = 0; i < 32; i++) {
|
|
1490
|
-
token += alphabet[bytes[i] % alphabet.length];
|
|
1491
|
-
}
|
|
1492
|
-
return token;
|
|
1493
|
-
}
|
|
1494
|
-
var CORS_HEADERS = {
|
|
1495
|
-
"Access-Control-Allow-Origin": "*",
|
|
1496
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
1497
|
-
"Access-Control-Allow-Headers": "*"
|
|
1498
|
-
};
|
|
1499
|
-
function addCorsHeaders(response) {
|
|
1500
|
-
const headers = new Headers(response.headers);
|
|
1501
|
-
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
1502
|
-
headers.set(key, value);
|
|
1503
|
-
}
|
|
1504
|
-
return new Response(response.body, {
|
|
1505
|
-
status: response.status,
|
|
1506
|
-
statusText: response.statusText,
|
|
1507
|
-
headers
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
function buildOnRequestHandler(config) {
|
|
1511
|
-
return async (c, request) => {
|
|
1512
|
-
var _a;
|
|
1513
|
-
const url = new URL(request.url);
|
|
1514
|
-
const pathname = url.pathname;
|
|
1515
|
-
const match = pathname.match(/^\/fetch\/([a-z0-9]+)(\/.*)?$/);
|
|
1516
|
-
if (!match) {
|
|
1517
|
-
return new Response("Not Found", { status: 404 });
|
|
1518
|
-
}
|
|
1519
|
-
if (request.method === "OPTIONS") {
|
|
1520
|
-
return new Response(null, { status: 204, headers: CORS_HEADERS });
|
|
1521
|
-
}
|
|
1522
|
-
const token = match[1];
|
|
1523
|
-
const remainingPath = match[2] ?? "/";
|
|
1524
|
-
const now = Date.now();
|
|
1525
|
-
const rows = await c.db.execute(
|
|
1526
|
-
`SELECT port FROM agent_os_preview_tokens WHERE token = ? AND expires_at > ?`,
|
|
1527
|
-
token,
|
|
1528
|
-
now
|
|
1529
|
-
);
|
|
1530
|
-
if (rows.length === 0) {
|
|
1531
|
-
c.log.warn({ msg: "agent-os preview auth failed", token });
|
|
1532
|
-
return addCorsHeaders(new Response("Forbidden", { status: 403 }));
|
|
1533
|
-
}
|
|
1534
|
-
const port = (_a = rows[0]) == null ? void 0 : _a.port;
|
|
1535
|
-
const agentOs2 = await ensureVm(
|
|
1536
|
-
c,
|
|
1537
|
-
config
|
|
1538
|
-
);
|
|
1539
|
-
const vmUrl = `http://localhost:${port}${remainingPath}${url.search}`;
|
|
1540
|
-
const vmRequest = new Request(vmUrl, {
|
|
1541
|
-
method: request.method,
|
|
1542
|
-
headers: request.headers,
|
|
1543
|
-
body: request.body,
|
|
1544
|
-
duplex: "half"
|
|
1545
|
-
});
|
|
1546
|
-
const vmResponse = await agentOs2.fetch(port, vmRequest);
|
|
1547
|
-
c.log.info({
|
|
1548
|
-
msg: "agent-os preview request proxied",
|
|
1549
|
-
port,
|
|
1550
|
-
method: request.method,
|
|
1551
|
-
path: remainingPath,
|
|
1552
|
-
status: vmResponse.status
|
|
1553
|
-
});
|
|
1554
|
-
return addCorsHeaders(vmResponse);
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
function buildPreviewActions(config) {
|
|
1558
|
-
return {
|
|
1559
|
-
createSignedPreviewUrl: async (c, port, expiresInSeconds) => {
|
|
1560
|
-
await ensureVm(c, config);
|
|
1561
|
-
const effectiveExpires = expiresInSeconds ?? config.preview.defaultExpiresInSeconds;
|
|
1562
|
-
const maxExpires = config.preview.maxExpiresInSeconds;
|
|
1563
|
-
if (effectiveExpires < 1 || effectiveExpires > maxExpires) {
|
|
1564
|
-
throw new Error(
|
|
1565
|
-
`expiresInSeconds must be between 1 and ${maxExpires}`
|
|
1566
|
-
);
|
|
1567
|
-
}
|
|
1568
|
-
const token = generateToken();
|
|
1569
|
-
const now = Date.now();
|
|
1570
|
-
const expiresAt = now + effectiveExpires * 1e3;
|
|
1571
|
-
await c.db.execute(
|
|
1572
|
-
`INSERT INTO agent_os_preview_tokens (token, port, created_at, expires_at)
|
|
1573
|
-
VALUES (?, ?, ?, ?)`,
|
|
1574
|
-
token,
|
|
1575
|
-
port,
|
|
1576
|
-
now,
|
|
1577
|
-
expiresAt
|
|
1578
|
-
);
|
|
1579
|
-
await c.db.execute(
|
|
1580
|
-
`DELETE FROM agent_os_preview_tokens WHERE expires_at <= ?`,
|
|
1581
|
-
now
|
|
1582
|
-
);
|
|
1583
|
-
const path = `/request/fetch/${token}`;
|
|
1584
|
-
c.log.info({
|
|
1585
|
-
msg: "agent-os preview token created",
|
|
1586
|
-
port,
|
|
1587
|
-
expiresInSeconds: effectiveExpires
|
|
1588
|
-
});
|
|
1589
|
-
return { path, token, port, expiresAt };
|
|
1590
|
-
},
|
|
1591
|
-
expireSignedPreviewUrl: async (c, token) => {
|
|
1592
|
-
await c.db.execute(
|
|
1593
|
-
`DELETE FROM agent_os_preview_tokens WHERE token = ?`,
|
|
1594
|
-
token
|
|
1595
|
-
);
|
|
1596
|
-
c.log.info({ msg: "agent-os preview token expired", token });
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
// src/agent-os/actor/process.ts
|
|
1602
|
-
function broadcastProcessEvent(c, name, payload) {
|
|
1603
|
-
try {
|
|
1604
|
-
c.broadcast(name, payload);
|
|
1605
|
-
} catch (error) {
|
|
1606
|
-
if (isRivetErrorCode(error, "actor", "stopping")) {
|
|
1607
|
-
return;
|
|
1608
|
-
}
|
|
1609
|
-
throw error;
|
|
1610
|
-
}
|
|
1833
|
+
var _a, _b;
|
|
1834
|
+
return {
|
|
1835
|
+
id: job.id,
|
|
1836
|
+
schedule: job.schedule,
|
|
1837
|
+
action: serializeCronAction(job.action),
|
|
1838
|
+
overlap: job.overlap,
|
|
1839
|
+
lastRun: (_a = job.lastRun) == null ? void 0 : _a.toISOString(),
|
|
1840
|
+
nextRun: (_b = job.nextRun) == null ? void 0 : _b.toISOString(),
|
|
1841
|
+
runCount: job.runCount,
|
|
1842
|
+
running: job.running
|
|
1843
|
+
};
|
|
1611
1844
|
}
|
|
1612
|
-
function
|
|
1845
|
+
function buildCronActions(config) {
|
|
1613
1846
|
return {
|
|
1614
|
-
|
|
1615
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1616
|
-
return agentOs2.exec(command, options);
|
|
1617
|
-
},
|
|
1618
|
-
spawn: async (c, command, args, options) => {
|
|
1847
|
+
scheduleCron: async (c, options) => {
|
|
1619
1848
|
const agentOs2 = await ensureVm(c, config);
|
|
1620
|
-
const
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
pid,
|
|
1626
|
-
stream: "stdout",
|
|
1627
|
-
data
|
|
1628
|
-
});
|
|
1629
|
-
(_a = options == null ? void 0 : options.onStdout) == null ? void 0 : _a.call(options, data);
|
|
1630
|
-
},
|
|
1631
|
-
onStderr: (data) => {
|
|
1632
|
-
var _a;
|
|
1633
|
-
broadcastProcessEvent(c, "processOutput", {
|
|
1634
|
-
pid,
|
|
1635
|
-
stream: "stderr",
|
|
1636
|
-
data
|
|
1637
|
-
});
|
|
1638
|
-
(_a = options == null ? void 0 : options.onStderr) == null ? void 0 : _a.call(options, data);
|
|
1639
|
-
}
|
|
1849
|
+
const job = agentOs2.scheduleCron({
|
|
1850
|
+
id: options.id,
|
|
1851
|
+
schedule: options.schedule,
|
|
1852
|
+
action: options.action,
|
|
1853
|
+
overlap: options.overlap
|
|
1640
1854
|
});
|
|
1641
|
-
c.vars.activeProcesses.add(pid);
|
|
1642
|
-
syncPreventSleep(c);
|
|
1643
1855
|
c.log.info({
|
|
1644
|
-
msg: "agent-os
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
});
|
|
1648
|
-
agentOs2.waitProcess(pid).then((exitCode) => {
|
|
1649
|
-
broadcastProcessEvent(c, "processExit", { pid, exitCode });
|
|
1650
|
-
c.log.info({
|
|
1651
|
-
msg: "agent-os process exited",
|
|
1652
|
-
pid,
|
|
1653
|
-
exitCode
|
|
1654
|
-
});
|
|
1655
|
-
}).catch(() => {
|
|
1656
|
-
}).finally(() => {
|
|
1657
|
-
c.vars.activeProcesses.delete(pid);
|
|
1658
|
-
syncPreventSleep(c);
|
|
1856
|
+
msg: "agent-os cron job scheduled",
|
|
1857
|
+
jobId: job.id,
|
|
1858
|
+
schedule: options.schedule
|
|
1659
1859
|
});
|
|
1660
|
-
return {
|
|
1661
|
-
},
|
|
1662
|
-
writeProcessStdin: async (c, pid, data) => {
|
|
1663
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1664
|
-
agentOs2.writeProcessStdin(pid, data);
|
|
1665
|
-
},
|
|
1666
|
-
closeProcessStdin: async (c, pid) => {
|
|
1667
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1668
|
-
agentOs2.closeProcessStdin(pid);
|
|
1669
|
-
},
|
|
1670
|
-
waitProcess: async (c, pid) => {
|
|
1671
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1672
|
-
return agentOs2.waitProcess(pid);
|
|
1673
|
-
},
|
|
1674
|
-
listProcesses: async (c) => {
|
|
1675
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1676
|
-
return agentOs2.listProcesses();
|
|
1677
|
-
},
|
|
1678
|
-
allProcesses: async (c) => {
|
|
1679
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1680
|
-
return agentOs2.allProcesses();
|
|
1681
|
-
},
|
|
1682
|
-
processTree: async (c) => {
|
|
1683
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1684
|
-
return agentOs2.processTree();
|
|
1685
|
-
},
|
|
1686
|
-
getProcess: async (c, pid) => {
|
|
1687
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1688
|
-
return agentOs2.getProcess(pid);
|
|
1860
|
+
return { id: job.id };
|
|
1689
1861
|
},
|
|
1690
|
-
|
|
1862
|
+
listCronJobs: async (c) => {
|
|
1691
1863
|
const agentOs2 = await ensureVm(c, config);
|
|
1692
|
-
agentOs2.
|
|
1864
|
+
return agentOs2.listCronJobs().map(serializeCronJob);
|
|
1693
1865
|
},
|
|
1694
|
-
|
|
1866
|
+
cancelCronJob: async (c, id) => {
|
|
1695
1867
|
const agentOs2 = await ensureVm(c, config);
|
|
1696
|
-
agentOs2.
|
|
1868
|
+
agentOs2.cancelCronJob(id);
|
|
1869
|
+
c.log.info({ msg: "agent-os cron job cancelled", jobId: id });
|
|
1697
1870
|
}
|
|
1698
1871
|
};
|
|
1699
1872
|
}
|
|
1700
1873
|
|
|
1701
|
-
// src/agent-os/
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1874
|
+
// src/agent-os/fs/database-vfs.ts
|
|
1875
|
+
import * as posixPath from "path/posix";
|
|
1876
|
+
var S_IFDIR = 16384;
|
|
1877
|
+
var S_IFREG = 32768;
|
|
1878
|
+
var S_IFLNK = 40960;
|
|
1879
|
+
var DEFAULT_FILE_MODE = S_IFREG | 420;
|
|
1880
|
+
var DEFAULT_DIR_MODE = S_IFDIR | 493;
|
|
1881
|
+
function normPath(p) {
|
|
1882
|
+
const normalized = posixPath.normalize(`/${p}`);
|
|
1883
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
1884
|
+
return normalized.slice(0, -1);
|
|
1712
1885
|
}
|
|
1713
|
-
return
|
|
1886
|
+
return normalized;
|
|
1714
1887
|
}
|
|
1715
|
-
function
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
}
|
|
1888
|
+
function parentPath(p) {
|
|
1889
|
+
const parent = posixPath.dirname(p);
|
|
1890
|
+
return parent;
|
|
1719
1891
|
}
|
|
1720
|
-
function
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
capabilities: agentOs2.getSessionCapabilities(sessionId) ?? {},
|
|
1725
|
-
agentInfo: agentOs2.getSessionAgentInfo(sessionId)
|
|
1726
|
-
};
|
|
1892
|
+
function throwENOENT(path) {
|
|
1893
|
+
const err = new Error(`ENOENT: no such file or directory: ${path}`);
|
|
1894
|
+
err.name = "ENOENT";
|
|
1895
|
+
throw err;
|
|
1727
1896
|
}
|
|
1728
|
-
|
|
1729
|
-
const
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
await c.db.execute(
|
|
1733
|
-
`INSERT OR REPLACE INTO agent_os_sessions (session_id, agent_type, capabilities, agent_info, created_at)
|
|
1734
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
1735
|
-
sessionId,
|
|
1736
|
-
agentType,
|
|
1737
|
-
JSON.stringify(capabilities),
|
|
1738
|
-
agentInfo ? JSON.stringify(agentInfo) : null,
|
|
1739
|
-
now
|
|
1740
|
-
);
|
|
1897
|
+
function throwEEXIST(path) {
|
|
1898
|
+
const err = new Error(`EEXIST: file already exists: ${path}`);
|
|
1899
|
+
err.name = "EEXIST";
|
|
1900
|
+
throw err;
|
|
1741
1901
|
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
`SELECT MAX(seq) as max_seq FROM agent_os_session_events WHERE session_id = ?`,
|
|
1747
|
-
sessionId
|
|
1748
|
-
);
|
|
1749
|
-
const nextSeq = (((_a = rows[0]) == null ? void 0 : _a.max_seq) ?? -1) + 1;
|
|
1750
|
-
await c.db.execute(
|
|
1751
|
-
`INSERT INTO agent_os_session_events (session_id, seq, event, created_at)
|
|
1752
|
-
VALUES (?, ?, ?, ?)`,
|
|
1753
|
-
sessionId,
|
|
1754
|
-
nextSeq,
|
|
1755
|
-
JSON.stringify(event2),
|
|
1756
|
-
now
|
|
1757
|
-
);
|
|
1902
|
+
function throwENOTDIR(path) {
|
|
1903
|
+
const err = new Error(`ENOTDIR: not a directory: ${path}`);
|
|
1904
|
+
err.name = "ENOTDIR";
|
|
1905
|
+
throw err;
|
|
1758
1906
|
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
);
|
|
1764
|
-
await c.db.execute(
|
|
1765
|
-
`DELETE FROM agent_os_sessions WHERE session_id = ?`,
|
|
1766
|
-
sessionId
|
|
1767
|
-
);
|
|
1907
|
+
function throwEISDIR(path) {
|
|
1908
|
+
const err = new Error(`EISDIR: illegal operation on a directory: ${path}`);
|
|
1909
|
+
err.name = "EISDIR";
|
|
1910
|
+
throw err;
|
|
1768
1911
|
}
|
|
1769
|
-
function
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1912
|
+
function throwENOTEMPTY(path) {
|
|
1913
|
+
const err = new Error(`ENOTEMPTY: directory not empty: ${path}`);
|
|
1914
|
+
err.name = "ENOTEMPTY";
|
|
1915
|
+
throw err;
|
|
1916
|
+
}
|
|
1917
|
+
function throwENOSYS(op) {
|
|
1918
|
+
const err = new Error(`ENOSYS: function not implemented: ${op}`);
|
|
1919
|
+
err.name = "ENOSYS";
|
|
1920
|
+
throw err;
|
|
1921
|
+
}
|
|
1922
|
+
function rowToStat(row) {
|
|
1923
|
+
return {
|
|
1924
|
+
mode: row.mode,
|
|
1925
|
+
size: row.size,
|
|
1926
|
+
isDirectory: row.is_directory === 1,
|
|
1927
|
+
isSymbolicLink: row.symlink_target !== null,
|
|
1928
|
+
atimeMs: row.atime_ms,
|
|
1929
|
+
mtimeMs: row.mtime_ms,
|
|
1930
|
+
ctimeMs: row.ctime_ms,
|
|
1931
|
+
birthtimeMs: row.birthtime_ms,
|
|
1932
|
+
ino: 0,
|
|
1933
|
+
nlink: row.nlink,
|
|
1934
|
+
uid: row.uid,
|
|
1935
|
+
gid: row.gid
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
function createDatabaseVfs(options) {
|
|
1939
|
+
const { db: db2 } = options;
|
|
1940
|
+
async function getEntry(path) {
|
|
1941
|
+
const rows = await db2.execute(
|
|
1942
|
+
"SELECT * FROM agent_os_fs_entries WHERE path = ?",
|
|
1943
|
+
path
|
|
1781
1944
|
);
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1945
|
+
return rows[0];
|
|
1946
|
+
}
|
|
1947
|
+
async function getEntryOrThrow(path) {
|
|
1948
|
+
const entry = await getEntry(path);
|
|
1949
|
+
if (!entry) {
|
|
1950
|
+
throwENOENT(path);
|
|
1951
|
+
}
|
|
1952
|
+
return entry;
|
|
1953
|
+
}
|
|
1954
|
+
async function ensureParentExists(path) {
|
|
1955
|
+
const parent = parentPath(path);
|
|
1956
|
+
if (parent === path) return;
|
|
1957
|
+
const entry = await getEntry(parent);
|
|
1958
|
+
if (!entry) {
|
|
1959
|
+
throwENOENT(parent);
|
|
1791
1960
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1961
|
+
if (entry.is_directory !== 1) {
|
|
1962
|
+
throwENOTDIR(parent);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
async function getChildEntries(dirPath) {
|
|
1966
|
+
const prefix = dirPath === "/" ? "/" : `${dirPath}/`;
|
|
1967
|
+
const rows = await db2.execute(
|
|
1968
|
+
"SELECT * FROM agent_os_fs_entries WHERE path LIKE ? AND path != ?",
|
|
1969
|
+
`${prefix}%`,
|
|
1970
|
+
dirPath
|
|
1797
1971
|
);
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1972
|
+
return rows.filter((row) => {
|
|
1973
|
+
const relative = row.path.slice(prefix.length);
|
|
1974
|
+
return relative.length > 0 && !relative.includes("/");
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
const rootInit = (async () => {
|
|
1978
|
+
const root = await getEntry("/");
|
|
1979
|
+
if (!root) {
|
|
1980
|
+
const now = Date.now();
|
|
1981
|
+
await db2.execute(
|
|
1982
|
+
`INSERT OR IGNORE INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 1, NULL, ?, 0, 0, 0, ?, ?, ?, ?, NULL, 2)`,
|
|
1983
|
+
"/",
|
|
1984
|
+
DEFAULT_DIR_MODE,
|
|
1985
|
+
now,
|
|
1986
|
+
now,
|
|
1987
|
+
now,
|
|
1988
|
+
now
|
|
1806
1989
|
);
|
|
1807
1990
|
}
|
|
1808
|
-
});
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
agentType,
|
|
1817
|
-
options
|
|
1818
|
-
);
|
|
1819
|
-
subscribeToSession(c, agentOs2, sessionId, config);
|
|
1820
|
-
await persistSession(c, agentOs2, sessionId, agentType);
|
|
1821
|
-
c.log.info({
|
|
1822
|
-
msg: "agent-os session created",
|
|
1823
|
-
sessionId,
|
|
1824
|
-
agentType
|
|
1825
|
-
});
|
|
1826
|
-
return toSessionRecord(agentOs2, sessionId, agentType);
|
|
1827
|
-
},
|
|
1828
|
-
listSessions: async (c) => {
|
|
1829
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1830
|
-
return agentOs2.listSessions();
|
|
1831
|
-
},
|
|
1832
|
-
getSession: async (c, sessionId) => {
|
|
1833
|
-
assertSessionExists(c, sessionId);
|
|
1834
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1835
|
-
const info = agentOs2.listSessions().find((s) => s.sessionId === sessionId);
|
|
1836
|
-
if (!info) {
|
|
1837
|
-
throw new Error(`session not found: ${sessionId}`);
|
|
1991
|
+
})();
|
|
1992
|
+
const backend = {
|
|
1993
|
+
async readFile(p) {
|
|
1994
|
+
await rootInit;
|
|
1995
|
+
const path = normPath(p);
|
|
1996
|
+
const entry = await getEntryOrThrow(path);
|
|
1997
|
+
if (entry.is_directory === 1) {
|
|
1998
|
+
throwEISDIR(path);
|
|
1838
1999
|
}
|
|
1839
|
-
return
|
|
1840
|
-
},
|
|
1841
|
-
destroySession: async (c, sessionId) => {
|
|
1842
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1843
|
-
await agentOs2.destroySession(sessionId);
|
|
1844
|
-
c.vars.sessions.delete(sessionId);
|
|
1845
|
-
c.vars.activeSessionIds.delete(sessionId);
|
|
1846
|
-
syncPreventSleep(c);
|
|
1847
|
-
await deletePersistedSession(c, sessionId);
|
|
1848
|
-
c.log.info({ msg: "agent-os session destroyed", sessionId });
|
|
1849
|
-
},
|
|
1850
|
-
resumeSession: async (c, sessionId) => {
|
|
1851
|
-
const agentOs2 = await ensureVm(c, config);
|
|
1852
|
-
return agentOs2.resumeSession(sessionId);
|
|
2000
|
+
return entry.content ?? new Uint8Array(0);
|
|
1853
2001
|
},
|
|
1854
|
-
|
|
1855
|
-
const
|
|
1856
|
-
|
|
1857
|
-
c.vars.sessions.delete(sessionId);
|
|
1858
|
-
c.vars.activeSessionIds.delete(sessionId);
|
|
1859
|
-
syncPreventSleep(c);
|
|
1860
|
-
await deletePersistedSession(c, sessionId);
|
|
1861
|
-
c.log.info({ msg: "agent-os session closed", sessionId });
|
|
1862
|
-
}
|
|
1863
|
-
};
|
|
1864
|
-
}
|
|
1865
|
-
function buildPromptActions(_config) {
|
|
1866
|
-
return {
|
|
1867
|
-
sendPrompt: async (c, sessionId, text) => {
|
|
1868
|
-
if (c.aborted) {
|
|
1869
|
-
throw new Error(
|
|
1870
|
-
"actor is shutting down, cannot start new prompt"
|
|
1871
|
-
);
|
|
1872
|
-
}
|
|
1873
|
-
assertSessionExists(c, sessionId);
|
|
1874
|
-
const agentOs2 = c.vars.agentOs;
|
|
1875
|
-
if (!agentOs2) {
|
|
1876
|
-
throw new Error("VM not initialized");
|
|
1877
|
-
}
|
|
1878
|
-
c.vars.activeSessionIds.add(sessionId);
|
|
1879
|
-
syncPreventSleep(c);
|
|
1880
|
-
c.log.info({ msg: "agent-os prompt turn started", sessionId });
|
|
1881
|
-
const start = Date.now();
|
|
1882
|
-
try {
|
|
1883
|
-
const result = await agentOs2.prompt(sessionId, text);
|
|
1884
|
-
return {
|
|
1885
|
-
response: JSON.parse(JSON.stringify(result.response)),
|
|
1886
|
-
text: result.text
|
|
1887
|
-
};
|
|
1888
|
-
} finally {
|
|
1889
|
-
c.vars.activeSessionIds.delete(sessionId);
|
|
1890
|
-
syncPreventSleep(c);
|
|
1891
|
-
c.log.info({
|
|
1892
|
-
msg: "agent-os prompt turn ended",
|
|
1893
|
-
sessionId,
|
|
1894
|
-
durationMs: Date.now() - start
|
|
1895
|
-
});
|
|
1896
|
-
}
|
|
2002
|
+
async readTextFile(p) {
|
|
2003
|
+
const data = await backend.readFile(p);
|
|
2004
|
+
return new TextDecoder().decode(data);
|
|
1897
2005
|
},
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
const
|
|
1901
|
-
|
|
1902
|
-
|
|
2006
|
+
async readDir(p) {
|
|
2007
|
+
await rootInit;
|
|
2008
|
+
const path = normPath(p);
|
|
2009
|
+
const entry = await getEntryOrThrow(path);
|
|
2010
|
+
if (entry.is_directory !== 1) {
|
|
2011
|
+
throwENOTDIR(path);
|
|
1903
2012
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
);
|
|
2013
|
+
const children = await getChildEntries(path);
|
|
2014
|
+
return children.map((child) => posixPath.basename(child.path));
|
|
1907
2015
|
},
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
const
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
return stripFunctions(
|
|
1915
|
-
agentOs2.respondPermission(sessionId, permissionId, reply)
|
|
1916
|
-
);
|
|
1917
|
-
}
|
|
1918
|
-
};
|
|
1919
|
-
}
|
|
1920
|
-
function buildConfigActions(_config) {
|
|
1921
|
-
return {
|
|
1922
|
-
setMode: async (c, sessionId, modeId) => {
|
|
1923
|
-
assertSessionExists(c, sessionId);
|
|
1924
|
-
const agentOs2 = c.vars.agentOs;
|
|
1925
|
-
if (!agentOs2) {
|
|
1926
|
-
throw new Error("VM not initialized");
|
|
2016
|
+
async readDirWithTypes(p) {
|
|
2017
|
+
await rootInit;
|
|
2018
|
+
const path = normPath(p);
|
|
2019
|
+
const entry = await getEntryOrThrow(path);
|
|
2020
|
+
if (entry.is_directory !== 1) {
|
|
2021
|
+
throwENOTDIR(path);
|
|
1927
2022
|
}
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2023
|
+
const children = await getChildEntries(path);
|
|
2024
|
+
return children.map((child) => ({
|
|
2025
|
+
name: posixPath.basename(child.path),
|
|
2026
|
+
isDirectory: child.is_directory === 1,
|
|
2027
|
+
isSymbolicLink: child.symlink_target !== null,
|
|
2028
|
+
ino: 0
|
|
2029
|
+
}));
|
|
1931
2030
|
},
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
|
|
2031
|
+
async writeFile(p, content) {
|
|
2032
|
+
await rootInit;
|
|
2033
|
+
const path = normPath(p);
|
|
2034
|
+
await ensureParentExists(path);
|
|
2035
|
+
const existing = await getEntry(path);
|
|
2036
|
+
if (existing && existing.is_directory === 1) {
|
|
2037
|
+
throwEISDIR(path);
|
|
1937
2038
|
}
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2039
|
+
const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
2040
|
+
const now = Date.now();
|
|
2041
|
+
if (existing) {
|
|
2042
|
+
await db2.execute(
|
|
2043
|
+
`UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ?, atime_ms = ? WHERE path = ?`,
|
|
2044
|
+
data,
|
|
2045
|
+
data.byteLength,
|
|
2046
|
+
now,
|
|
2047
|
+
now,
|
|
2048
|
+
now,
|
|
2049
|
+
path
|
|
2050
|
+
);
|
|
2051
|
+
} else {
|
|
2052
|
+
await db2.execute(
|
|
2053
|
+
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 0, ?, ?, 0, 0, ?, ?, ?, ?, ?, NULL, 1)`,
|
|
2054
|
+
path,
|
|
2055
|
+
data,
|
|
2056
|
+
DEFAULT_FILE_MODE,
|
|
2057
|
+
data.byteLength,
|
|
2058
|
+
now,
|
|
2059
|
+
now,
|
|
2060
|
+
now,
|
|
2061
|
+
now
|
|
2062
|
+
);
|
|
1945
2063
|
}
|
|
1946
|
-
return stripFunctions(
|
|
1947
|
-
agentOs2.setSessionModel(sessionId, model)
|
|
1948
|
-
);
|
|
1949
2064
|
},
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
const
|
|
1953
|
-
|
|
1954
|
-
|
|
2065
|
+
async createDir(p) {
|
|
2066
|
+
await rootInit;
|
|
2067
|
+
const path = normPath(p);
|
|
2068
|
+
await ensureParentExists(path);
|
|
2069
|
+
const existing = await getEntry(path);
|
|
2070
|
+
if (existing) {
|
|
2071
|
+
throwEEXIST(path);
|
|
1955
2072
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
2073
|
+
const now = Date.now();
|
|
2074
|
+
await db2.execute(
|
|
2075
|
+
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 1, NULL, ?, 0, 0, 0, ?, ?, ?, ?, NULL, 2)`,
|
|
2076
|
+
path,
|
|
2077
|
+
DEFAULT_DIR_MODE,
|
|
2078
|
+
now,
|
|
2079
|
+
now,
|
|
2080
|
+
now,
|
|
2081
|
+
now
|
|
1958
2082
|
);
|
|
1959
2083
|
},
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
const
|
|
1963
|
-
if (
|
|
1964
|
-
|
|
2084
|
+
async mkdir(p, options2) {
|
|
2085
|
+
await rootInit;
|
|
2086
|
+
const path = normPath(p);
|
|
2087
|
+
if (options2 == null ? void 0 : options2.recursive) {
|
|
2088
|
+
const parts = path.split("/").filter(Boolean);
|
|
2089
|
+
let current = "";
|
|
2090
|
+
for (const part of parts) {
|
|
2091
|
+
current += `/${part}`;
|
|
2092
|
+
const existing = await getEntry(current);
|
|
2093
|
+
if (!existing) {
|
|
2094
|
+
const now = Date.now();
|
|
2095
|
+
await db2.execute(
|
|
2096
|
+
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 1, NULL, ?, 0, 0, 0, ?, ?, ?, ?, NULL, 2)`,
|
|
2097
|
+
current,
|
|
2098
|
+
DEFAULT_DIR_MODE,
|
|
2099
|
+
now,
|
|
2100
|
+
now,
|
|
2101
|
+
now,
|
|
2102
|
+
now
|
|
2103
|
+
);
|
|
2104
|
+
} else if (existing.is_directory !== 1) {
|
|
2105
|
+
throwENOTDIR(current);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
} else {
|
|
2109
|
+
await backend.createDir(p);
|
|
1965
2110
|
}
|
|
1966
|
-
return agentOs2.getSessionConfigOptions(sessionId);
|
|
1967
2111
|
},
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
const
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
}
|
|
1974
|
-
return agentOs2.getSessionEvents(sessionId, options).map((e) => e.notification);
|
|
2112
|
+
async exists(p) {
|
|
2113
|
+
await rootInit;
|
|
2114
|
+
const path = normPath(p);
|
|
2115
|
+
const entry = await getEntry(path);
|
|
2116
|
+
return entry !== void 0;
|
|
1975
2117
|
},
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
const
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
}
|
|
1982
|
-
return agentOs2.getSessionEvents(sessionId, options);
|
|
2118
|
+
async stat(p) {
|
|
2119
|
+
await rootInit;
|
|
2120
|
+
const path = normPath(p);
|
|
2121
|
+
const entry = await getEntryOrThrow(path);
|
|
2122
|
+
return rowToStat(entry);
|
|
1983
2123
|
},
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
const
|
|
1987
|
-
|
|
1988
|
-
|
|
2124
|
+
async removeFile(p) {
|
|
2125
|
+
await rootInit;
|
|
2126
|
+
const path = normPath(p);
|
|
2127
|
+
const entry = await getEntryOrThrow(path);
|
|
2128
|
+
if (entry.is_directory === 1) {
|
|
2129
|
+
throwEISDIR(path);
|
|
1989
2130
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
}
|
|
1994
|
-
};
|
|
1995
|
-
}
|
|
1996
|
-
function buildSessionPersistenceActions(_config) {
|
|
1997
|
-
return {
|
|
1998
|
-
listPersistedSessions: async (c) => {
|
|
1999
|
-
const rows = await c.db.execute(
|
|
2000
|
-
`SELECT session_id, agent_type, capabilities, agent_info, created_at
|
|
2001
|
-
FROM agent_os_sessions
|
|
2002
|
-
ORDER BY created_at ASC`
|
|
2131
|
+
await db2.execute(
|
|
2132
|
+
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
2133
|
+
path
|
|
2003
2134
|
);
|
|
2004
|
-
return rows.map((row) => ({
|
|
2005
|
-
sessionId: row.session_id,
|
|
2006
|
-
agentType: row.agent_type,
|
|
2007
|
-
capabilities: JSON.parse(row.capabilities),
|
|
2008
|
-
agentInfo: row.agent_info ? JSON.parse(row.agent_info) : null,
|
|
2009
|
-
createdAt: row.created_at
|
|
2010
|
-
}));
|
|
2011
2135
|
},
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2136
|
+
async removeDir(p) {
|
|
2137
|
+
await rootInit;
|
|
2138
|
+
const path = normPath(p);
|
|
2139
|
+
const entry = await getEntryOrThrow(path);
|
|
2140
|
+
if (entry.is_directory !== 1) {
|
|
2141
|
+
throwENOTDIR(path);
|
|
2142
|
+
}
|
|
2143
|
+
const children = await getChildEntries(path);
|
|
2144
|
+
if (children.length > 0) {
|
|
2145
|
+
throwENOTEMPTY(path);
|
|
2146
|
+
}
|
|
2147
|
+
await db2.execute(
|
|
2148
|
+
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
2149
|
+
path
|
|
2019
2150
|
);
|
|
2020
|
-
return rows.map((row) => ({
|
|
2021
|
-
sessionId: row.session_id,
|
|
2022
|
-
seq: row.seq,
|
|
2023
|
-
event: JSON.parse(row.event),
|
|
2024
|
-
createdAt: row.created_at
|
|
2025
|
-
}));
|
|
2026
|
-
}
|
|
2027
|
-
};
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
|
-
// src/agent-os/actor/shell.ts
|
|
2031
|
-
function buildShellActions(config) {
|
|
2032
|
-
return {
|
|
2033
|
-
openShell: async (c, options) => {
|
|
2034
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2035
|
-
const { shellId } = agentOs2.openShell(options);
|
|
2036
|
-
agentOs2.onShellData(shellId, (data) => {
|
|
2037
|
-
c.broadcast("shellData", { shellId, data });
|
|
2038
|
-
});
|
|
2039
|
-
c.vars.activeShells.add(shellId);
|
|
2040
|
-
syncPreventSleep(c);
|
|
2041
|
-
c.log.info({ msg: "agent-os shell opened", shellId });
|
|
2042
|
-
return { shellId };
|
|
2043
|
-
},
|
|
2044
|
-
writeShell: async (c, shellId, data) => {
|
|
2045
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2046
|
-
agentOs2.writeShell(shellId, data);
|
|
2047
|
-
},
|
|
2048
|
-
resizeShell: async (c, shellId, cols, rows) => {
|
|
2049
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2050
|
-
agentOs2.resizeShell(shellId, cols, rows);
|
|
2051
|
-
},
|
|
2052
|
-
closeShell: async (c, shellId) => {
|
|
2053
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2054
|
-
agentOs2.closeShell(shellId);
|
|
2055
|
-
c.vars.activeShells.delete(shellId);
|
|
2056
|
-
syncPreventSleep(c);
|
|
2057
|
-
c.log.info({ msg: "agent-os shell closed", shellId });
|
|
2058
|
-
}
|
|
2059
|
-
};
|
|
2060
|
-
}
|
|
2061
|
-
|
|
2062
|
-
// src/agent-os/actor/index.ts
|
|
2063
|
-
async function ensureVm(c, config) {
|
|
2064
|
-
if (c.vars.agentOs) {
|
|
2065
|
-
return c.vars.agentOs;
|
|
2066
|
-
}
|
|
2067
|
-
const start = Date.now();
|
|
2068
|
-
const options = buildVmOptions(config.options);
|
|
2069
|
-
const agentOs2 = await AgentOs.create(options);
|
|
2070
|
-
c.vars.agentOs = agentOs2;
|
|
2071
|
-
agentOs2.onCronEvent((cronEvent) => {
|
|
2072
|
-
c.broadcast("cronEvent", { event: cronEvent });
|
|
2073
|
-
});
|
|
2074
|
-
c.broadcast("vmBooted", {});
|
|
2075
|
-
c.log.info({
|
|
2076
|
-
msg: "agent-os vm booted",
|
|
2077
|
-
bootDurationMs: Date.now() - start
|
|
2078
|
-
});
|
|
2079
|
-
return agentOs2;
|
|
2080
|
-
}
|
|
2081
|
-
function buildVmOptions(userOptions) {
|
|
2082
|
-
const userMounts = (userOptions == null ? void 0 : userOptions.mounts) ?? [];
|
|
2083
|
-
const hasWorkdirMount = userMounts.some(
|
|
2084
|
-
(m) => m.path === "/home/user"
|
|
2085
|
-
);
|
|
2086
|
-
if (hasWorkdirMount) {
|
|
2087
|
-
return userOptions ?? {};
|
|
2088
|
-
}
|
|
2089
|
-
const memMount = {
|
|
2090
|
-
path: "/home/user",
|
|
2091
|
-
driver: createInMemoryFileSystem()
|
|
2092
|
-
};
|
|
2093
|
-
return {
|
|
2094
|
-
...userOptions,
|
|
2095
|
-
mounts: [memMount, ...userMounts]
|
|
2096
|
-
};
|
|
2097
|
-
}
|
|
2098
|
-
function syncPreventSleep(c) {
|
|
2099
|
-
const shouldPrevent = c.vars.activeSessionIds.size > 0 || c.vars.activeProcesses.size > 0 || c.vars.activeHooks.size > 0 || c.vars.activeShells.size > 0;
|
|
2100
|
-
c.setPreventSleep(shouldPrevent);
|
|
2101
|
-
c.log.info({
|
|
2102
|
-
msg: "agent-os prevent sleep sync",
|
|
2103
|
-
preventSleep: shouldPrevent,
|
|
2104
|
-
activeSessions: c.vars.activeSessionIds.size,
|
|
2105
|
-
activeProcesses: c.vars.activeProcesses.size,
|
|
2106
|
-
activeHooks: c.vars.activeHooks.size,
|
|
2107
|
-
activeShells: c.vars.activeShells.size
|
|
2108
|
-
});
|
|
2109
|
-
}
|
|
2110
|
-
function runHook(c, name, callback) {
|
|
2111
|
-
const promise = Promise.resolve(callback()).catch(
|
|
2112
|
-
(error) => c.log.error({ msg: "agent-os hook failed", hookName: name, error })
|
|
2113
|
-
).finally(() => {
|
|
2114
|
-
c.vars.activeHooks.delete(promise);
|
|
2115
|
-
syncPreventSleep(c);
|
|
2116
|
-
});
|
|
2117
|
-
c.vars.activeHooks.add(promise);
|
|
2118
|
-
syncPreventSleep(c);
|
|
2119
|
-
c.waitUntil(promise);
|
|
2120
|
-
}
|
|
2121
|
-
function agentOs(config) {
|
|
2122
|
-
const parsedConfig = agentOsActorConfigSchema.parse(
|
|
2123
|
-
config
|
|
2124
|
-
);
|
|
2125
|
-
return actor({
|
|
2126
|
-
options: {
|
|
2127
|
-
sleepGracePeriod: 9e5,
|
|
2128
|
-
actionTimeout: 9e5
|
|
2129
|
-
},
|
|
2130
|
-
createState: async () => ({}),
|
|
2131
|
-
createVars: () => ({
|
|
2132
|
-
agentOs: null,
|
|
2133
|
-
activeSessionIds: /* @__PURE__ */ new Set(),
|
|
2134
|
-
activeProcesses: /* @__PURE__ */ new Set(),
|
|
2135
|
-
activeHooks: /* @__PURE__ */ new Set(),
|
|
2136
|
-
activeShells: /* @__PURE__ */ new Set(),
|
|
2137
|
-
sessions: /* @__PURE__ */ new Set()
|
|
2138
|
-
}),
|
|
2139
|
-
db: db({
|
|
2140
|
-
onMigrate: migrateAgentOsTables
|
|
2141
|
-
}),
|
|
2142
|
-
events: {
|
|
2143
|
-
sessionEvent: sessionEventToken,
|
|
2144
|
-
permissionRequest: permissionRequestToken,
|
|
2145
|
-
vmBooted: vmBootedToken,
|
|
2146
|
-
vmShutdown: vmShutdownToken,
|
|
2147
|
-
processOutput: processOutputToken,
|
|
2148
|
-
processExit: processExitToken,
|
|
2149
|
-
shellData: shellDataToken,
|
|
2150
|
-
cronEvent: cronEventToken
|
|
2151
2151
|
},
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2152
|
+
async rename(oldPath, newPath) {
|
|
2153
|
+
await rootInit;
|
|
2154
|
+
const from = normPath(oldPath);
|
|
2155
|
+
const to = normPath(newPath);
|
|
2156
|
+
const entry = await getEntryOrThrow(from);
|
|
2157
|
+
await ensureParentExists(to);
|
|
2158
|
+
const destEntry = await getEntry(to);
|
|
2159
|
+
if (destEntry) {
|
|
2160
|
+
if (destEntry.is_directory === 1) {
|
|
2161
|
+
const children = await getChildEntries(to);
|
|
2162
|
+
if (children.length > 0) {
|
|
2163
|
+
throwENOTEMPTY(to);
|
|
2164
|
+
}
|
|
2158
2165
|
}
|
|
2166
|
+
await db2.execute(
|
|
2167
|
+
"DELETE FROM agent_os_fs_entries WHERE path = ?",
|
|
2168
|
+
to
|
|
2169
|
+
);
|
|
2159
2170
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2171
|
+
if (entry.is_directory === 1) {
|
|
2172
|
+
const prefix = from === "/" ? "/" : `${from}/`;
|
|
2173
|
+
const newPrefix = to === "/" ? "/" : `${to}/`;
|
|
2174
|
+
const descendants = await db2.execute(
|
|
2175
|
+
"SELECT path FROM agent_os_fs_entries WHERE path LIKE ?",
|
|
2176
|
+
`${prefix}%`
|
|
2177
|
+
);
|
|
2178
|
+
for (const desc of descendants) {
|
|
2179
|
+
const newDescPath = newPrefix + desc.path.slice(prefix.length);
|
|
2180
|
+
await db2.execute(
|
|
2181
|
+
"UPDATE agent_os_fs_entries SET path = ? WHERE path = ?",
|
|
2182
|
+
newDescPath,
|
|
2183
|
+
desc.path
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2173
2186
|
}
|
|
2174
|
-
|
|
2187
|
+
const now = Date.now();
|
|
2188
|
+
await db2.execute(
|
|
2189
|
+
"UPDATE agent_os_fs_entries SET path = ?, ctime_ms = ? WHERE path = ?",
|
|
2190
|
+
to,
|
|
2191
|
+
now,
|
|
2192
|
+
from
|
|
2193
|
+
);
|
|
2175
2194
|
},
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
});
|
|
2183
|
-
if (c.vars.agentOs) {
|
|
2184
|
-
await c.vars.agentOs.dispose();
|
|
2185
|
-
c.vars.agentOs = null;
|
|
2195
|
+
async realpath(p) {
|
|
2196
|
+
await rootInit;
|
|
2197
|
+
const path = normPath(p);
|
|
2198
|
+
const entry = await getEntryOrThrow(path);
|
|
2199
|
+
if (entry.symlink_target !== null) {
|
|
2200
|
+
return normPath(entry.symlink_target);
|
|
2186
2201
|
}
|
|
2187
|
-
|
|
2188
|
-
},
|
|
2189
|
-
actions: {
|
|
2190
|
-
...buildSessionActions(parsedConfig),
|
|
2191
|
-
...buildPromptActions(parsedConfig),
|
|
2192
|
-
...buildConfigActions(parsedConfig),
|
|
2193
|
-
...buildSessionPersistenceActions(parsedConfig),
|
|
2194
|
-
...buildProcessActions(parsedConfig),
|
|
2195
|
-
...buildFilesystemActions(parsedConfig),
|
|
2196
|
-
...buildPreviewActions(parsedConfig),
|
|
2197
|
-
...buildShellActions(parsedConfig),
|
|
2198
|
-
...buildCronActions(parsedConfig),
|
|
2199
|
-
...buildNetworkActions(parsedConfig)
|
|
2200
|
-
}
|
|
2201
|
-
});
|
|
2202
|
-
}
|
|
2203
|
-
var sessionEventToken = event();
|
|
2204
|
-
var permissionRequestToken = event();
|
|
2205
|
-
var vmBootedToken = event();
|
|
2206
|
-
var vmShutdownToken = event();
|
|
2207
|
-
var processOutputToken = event();
|
|
2208
|
-
var processExitToken = event();
|
|
2209
|
-
var shellDataToken = event();
|
|
2210
|
-
var cronEventToken = event();
|
|
2211
|
-
|
|
2212
|
-
// src/agent-os/actor/filesystem.ts
|
|
2213
|
-
function buildFilesystemActions(config) {
|
|
2214
|
-
return {
|
|
2215
|
-
readFile: async (c, path) => {
|
|
2216
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2217
|
-
return agentOs2.readFile(path);
|
|
2218
|
-
},
|
|
2219
|
-
writeFile: async (c, path, content) => {
|
|
2220
|
-
const agentOs2 = await ensureVm(c, config);
|
|
2221
|
-
await agentOs2.writeFile(path, content);
|
|
2202
|
+
return path;
|
|
2222
2203
|
},
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2204
|
+
async symlink(target, linkPath) {
|
|
2205
|
+
await rootInit;
|
|
2206
|
+
const link = normPath(linkPath);
|
|
2207
|
+
await ensureParentExists(link);
|
|
2208
|
+
const existing = await getEntry(link);
|
|
2209
|
+
if (existing) {
|
|
2210
|
+
throwEEXIST(link);
|
|
2211
|
+
}
|
|
2212
|
+
const now = Date.now();
|
|
2213
|
+
await db2.execute(
|
|
2214
|
+
`INSERT INTO agent_os_fs_entries (path, is_directory, content, mode, uid, gid, size, atime_ms, mtime_ms, ctime_ms, birthtime_ms, symlink_target, nlink) VALUES (?, 0, NULL, ?, 0, 0, ?, ?, ?, ?, ?, ?, 1)`,
|
|
2215
|
+
link,
|
|
2216
|
+
S_IFLNK | 511,
|
|
2217
|
+
target.length,
|
|
2218
|
+
now,
|
|
2219
|
+
now,
|
|
2220
|
+
now,
|
|
2221
|
+
now,
|
|
2222
|
+
target
|
|
2223
|
+
);
|
|
2226
2224
|
},
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2225
|
+
async readlink(p) {
|
|
2226
|
+
await rootInit;
|
|
2227
|
+
const path = normPath(p);
|
|
2228
|
+
const entry = await getEntryOrThrow(path);
|
|
2229
|
+
if (entry.symlink_target === null) {
|
|
2230
|
+
const err = new Error(`EINVAL: not a symlink: ${path}`);
|
|
2231
|
+
err.name = "EINVAL";
|
|
2232
|
+
throw err;
|
|
2233
|
+
}
|
|
2234
|
+
return entry.symlink_target;
|
|
2230
2235
|
},
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
await agentOs2.mkdir(path, options);
|
|
2236
|
+
async lstat(p) {
|
|
2237
|
+
return backend.stat(p);
|
|
2234
2238
|
},
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
return agentOs2.readdir(path);
|
|
2239
|
+
async link(_oldPath, _newPath) {
|
|
2240
|
+
throwENOSYS("link");
|
|
2238
2241
|
},
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
+
async chmod(p, mode) {
|
|
2243
|
+
await rootInit;
|
|
2244
|
+
const path = normPath(p);
|
|
2245
|
+
await getEntryOrThrow(path);
|
|
2246
|
+
const now = Date.now();
|
|
2247
|
+
await db2.execute(
|
|
2248
|
+
"UPDATE agent_os_fs_entries SET mode = ?, ctime_ms = ? WHERE path = ?",
|
|
2249
|
+
mode,
|
|
2250
|
+
now,
|
|
2251
|
+
path
|
|
2252
|
+
);
|
|
2242
2253
|
},
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2254
|
+
async chown(p, uid, gid) {
|
|
2255
|
+
await rootInit;
|
|
2256
|
+
const path = normPath(p);
|
|
2257
|
+
await getEntryOrThrow(path);
|
|
2258
|
+
const now = Date.now();
|
|
2259
|
+
await db2.execute(
|
|
2260
|
+
"UPDATE agent_os_fs_entries SET uid = ?, gid = ?, ctime_ms = ? WHERE path = ?",
|
|
2261
|
+
uid,
|
|
2262
|
+
gid,
|
|
2263
|
+
now,
|
|
2264
|
+
path
|
|
2265
|
+
);
|
|
2246
2266
|
},
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2267
|
+
async utimes(p, atime, mtime) {
|
|
2268
|
+
await rootInit;
|
|
2269
|
+
const path = normPath(p);
|
|
2270
|
+
await getEntryOrThrow(path);
|
|
2271
|
+
const now = Date.now();
|
|
2272
|
+
await db2.execute(
|
|
2273
|
+
"UPDATE agent_os_fs_entries SET atime_ms = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?",
|
|
2274
|
+
atime,
|
|
2275
|
+
mtime,
|
|
2276
|
+
now,
|
|
2277
|
+
path
|
|
2278
|
+
);
|
|
2250
2279
|
},
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2280
|
+
async truncate(p, length) {
|
|
2281
|
+
await rootInit;
|
|
2282
|
+
const path = normPath(p);
|
|
2283
|
+
const entry = await getEntryOrThrow(path);
|
|
2284
|
+
if (entry.is_directory === 1) {
|
|
2285
|
+
throwEISDIR(path);
|
|
2286
|
+
}
|
|
2287
|
+
const existing = entry.content ?? new Uint8Array(0);
|
|
2288
|
+
let newContent;
|
|
2289
|
+
if (length >= existing.byteLength) {
|
|
2290
|
+
newContent = new Uint8Array(length);
|
|
2291
|
+
newContent.set(existing);
|
|
2292
|
+
} else {
|
|
2293
|
+
newContent = existing.slice(0, length);
|
|
2294
|
+
}
|
|
2295
|
+
const now = Date.now();
|
|
2296
|
+
await db2.execute(
|
|
2297
|
+
"UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?",
|
|
2298
|
+
newContent,
|
|
2299
|
+
length,
|
|
2300
|
+
now,
|
|
2301
|
+
now,
|
|
2302
|
+
path
|
|
2303
|
+
);
|
|
2254
2304
|
},
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2305
|
+
async pread(p, offset, length) {
|
|
2306
|
+
await rootInit;
|
|
2307
|
+
const path = normPath(p);
|
|
2308
|
+
const entry = await getEntryOrThrow(path);
|
|
2309
|
+
if (entry.is_directory === 1) {
|
|
2310
|
+
throwEISDIR(path);
|
|
2311
|
+
}
|
|
2312
|
+
const content = entry.content ?? new Uint8Array(0);
|
|
2313
|
+
const end = Math.min(offset + length, content.byteLength);
|
|
2314
|
+
if (offset >= content.byteLength) {
|
|
2315
|
+
return new Uint8Array(0);
|
|
2316
|
+
}
|
|
2317
|
+
return content.slice(offset, end);
|
|
2258
2318
|
},
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2319
|
+
async pwrite(p, offset, data) {
|
|
2320
|
+
await rootInit;
|
|
2321
|
+
const path = normPath(p);
|
|
2322
|
+
const entry = await getEntryOrThrow(path);
|
|
2323
|
+
if (entry.is_directory === 1) {
|
|
2324
|
+
throwEISDIR(path);
|
|
2325
|
+
}
|
|
2326
|
+
const content = entry.content ?? new Uint8Array(0);
|
|
2327
|
+
const end = offset + data.byteLength;
|
|
2328
|
+
const newSize = Math.max(content.byteLength, end);
|
|
2329
|
+
const buf = new Uint8Array(newSize);
|
|
2330
|
+
buf.set(content);
|
|
2331
|
+
buf.set(data, offset);
|
|
2332
|
+
const now = Date.now();
|
|
2333
|
+
await db2.execute(
|
|
2334
|
+
`UPDATE agent_os_fs_entries SET content = ?, size = ?, mtime_ms = ?, ctime_ms = ? WHERE path = ?`,
|
|
2335
|
+
buf,
|
|
2336
|
+
newSize,
|
|
2337
|
+
now,
|
|
2338
|
+
now,
|
|
2339
|
+
path
|
|
2340
|
+
);
|
|
2266
2341
|
}
|
|
2267
2342
|
};
|
|
2343
|
+
return backend;
|
|
2268
2344
|
}
|
|
2269
2345
|
export {
|
|
2270
2346
|
agentOs,
|