zeitlich 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -50
- package/dist/adapters/sandbox/daytona/index.cjs +205 -0
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -0
- package/dist/adapters/sandbox/daytona/index.d.cts +86 -0
- package/dist/adapters/sandbox/daytona/index.d.ts +86 -0
- package/dist/adapters/sandbox/daytona/index.js +202 -0
- package/dist/adapters/sandbox/daytona/index.js.map +1 -0
- package/dist/adapters/sandbox/inmemory/index.cjs +174 -0
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -0
- package/dist/adapters/sandbox/inmemory/index.d.cts +28 -0
- package/dist/adapters/sandbox/inmemory/index.d.ts +28 -0
- package/dist/adapters/sandbox/inmemory/index.js +172 -0
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -0
- package/dist/adapters/sandbox/virtual/index.cjs +405 -0
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -0
- package/dist/adapters/sandbox/virtual/index.d.cts +85 -0
- package/dist/adapters/sandbox/virtual/index.d.ts +85 -0
- package/dist/adapters/sandbox/virtual/index.js +400 -0
- package/dist/adapters/sandbox/virtual/index.js.map +1 -0
- package/dist/adapters/thread/google-genai/index.cjs +306 -0
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -0
- package/dist/adapters/thread/google-genai/index.d.cts +145 -0
- package/dist/adapters/thread/google-genai/index.d.ts +145 -0
- package/dist/adapters/thread/google-genai/index.js +300 -0
- package/dist/adapters/thread/google-genai/index.js.map +1 -0
- package/dist/adapters/{langchain → thread/langchain}/index.cjs +29 -9
- package/dist/adapters/thread/langchain/index.cjs.map +1 -0
- package/dist/adapters/{langchain → thread/langchain}/index.d.cts +17 -21
- package/dist/adapters/{langchain → thread/langchain}/index.d.ts +17 -21
- package/dist/adapters/{langchain → thread/langchain}/index.js +29 -9
- package/dist/adapters/thread/langchain/index.js.map +1 -0
- package/dist/index.cjs +866 -567
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +235 -74
- package/dist/index.d.ts +235 -74
- package/dist/index.js +854 -562
- package/dist/index.js.map +1 -1
- package/dist/{thread-manager-qc0g5Rvd.d.cts → types-35POpVfa.d.cts} +7 -6
- package/dist/{thread-manager-qc0g5Rvd.d.ts → types-35POpVfa.d.ts} +7 -6
- package/dist/types-BMXzv7TN.d.cts +476 -0
- package/dist/types-BMXzv7TN.d.ts +476 -0
- package/dist/types-BVP87m_W.d.cts +121 -0
- package/dist/types-BWvIYK28.d.ts +391 -0
- package/dist/types-CDubRtad.d.cts +115 -0
- package/dist/types-CDubRtad.d.ts +115 -0
- package/dist/types-CwwgQ_9H.d.ts +121 -0
- package/dist/types-Dje1TdH6.d.cts +391 -0
- package/dist/workflow.cjs +460 -321
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +271 -222
- package/dist/workflow.d.ts +271 -222
- package/dist/workflow.js +456 -319
- package/dist/workflow.js.map +1 -1
- package/package.json +65 -8
- package/src/adapters/sandbox/daytona/filesystem.ts +136 -0
- package/src/adapters/sandbox/daytona/index.ts +149 -0
- package/src/adapters/sandbox/daytona/types.ts +34 -0
- package/src/adapters/sandbox/inmemory/index.ts +213 -0
- package/src/adapters/sandbox/virtual/filesystem.ts +345 -0
- package/src/adapters/sandbox/virtual/index.ts +88 -0
- package/src/adapters/sandbox/virtual/mutations.ts +38 -0
- package/src/adapters/sandbox/virtual/provider.ts +101 -0
- package/src/adapters/sandbox/virtual/tree.ts +82 -0
- package/src/adapters/sandbox/virtual/types.ts +127 -0
- package/src/adapters/sandbox/virtual/virtual-sandbox.test.ts +523 -0
- package/src/adapters/sandbox/virtual/with-virtual-sandbox.ts +91 -0
- package/src/adapters/thread/google-genai/activities.ts +132 -0
- package/src/adapters/thread/google-genai/index.ts +41 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +154 -0
- package/src/adapters/thread/google-genai/thread-manager.ts +169 -0
- package/src/adapters/{langchain → thread/langchain}/activities.ts +22 -15
- package/src/adapters/{langchain → thread/langchain}/index.ts +1 -1
- package/src/adapters/{langchain → thread/langchain}/model-invoker.ts +15 -18
- package/src/adapters/{langchain → thread/langchain}/thread-manager.ts +1 -1
- package/src/index.ts +32 -24
- package/src/lib/activity.ts +87 -0
- package/src/lib/hooks/index.ts +11 -0
- package/src/lib/hooks/types.ts +98 -0
- package/src/lib/model/helpers.ts +6 -0
- package/src/lib/model/index.ts +13 -0
- package/src/lib/{model-invoker.ts → model/types.ts} +18 -1
- package/src/lib/sandbox/index.ts +19 -0
- package/src/lib/sandbox/manager.ts +76 -0
- package/src/lib/sandbox/sandbox.test.ts +158 -0
- package/src/lib/{fs.ts → sandbox/tree.ts} +6 -6
- package/src/lib/sandbox/types.ts +164 -0
- package/src/lib/session/index.ts +11 -0
- package/src/lib/{session.ts → session/session.ts} +83 -50
- package/src/lib/session/types.ts +95 -0
- package/src/lib/skills/fs-provider.ts +16 -15
- package/src/lib/skills/handler.ts +31 -0
- package/src/lib/skills/index.ts +5 -1
- package/src/lib/skills/register.ts +20 -0
- package/src/lib/skills/tool.ts +47 -0
- package/src/lib/state/index.ts +9 -0
- package/src/lib/{state-manager.ts → state/manager.ts} +10 -147
- package/src/lib/state/types.ts +134 -0
- package/src/lib/subagent/define.ts +71 -0
- package/src/lib/subagent/handler.ts +99 -0
- package/src/lib/subagent/index.ts +13 -0
- package/src/lib/subagent/register.ts +68 -0
- package/src/lib/subagent/tool.ts +80 -0
- package/src/lib/subagent/types.ts +92 -0
- package/src/lib/thread/index.ts +7 -0
- package/src/lib/{thread-manager.ts → thread/manager.ts} +20 -33
- package/src/lib/thread/types.ts +39 -0
- package/src/lib/tool-router/auto-append.ts +55 -0
- package/src/lib/tool-router/index.ts +41 -0
- package/src/lib/tool-router/router.ts +462 -0
- package/src/lib/tool-router/types.ts +478 -0
- package/src/lib/tool-router/with-sandbox.ts +70 -0
- package/src/lib/types.ts +5 -382
- package/src/tools/bash/bash.test.ts +53 -55
- package/src/tools/bash/handler.ts +23 -51
- package/src/tools/edit/handler.ts +67 -81
- package/src/tools/glob/handler.ts +60 -17
- package/src/tools/read-file/handler.ts +67 -0
- package/src/tools/read-skill/handler.ts +1 -31
- package/src/tools/read-skill/tool.ts +5 -47
- package/src/tools/subagent/handler.ts +1 -100
- package/src/tools/subagent/tool.ts +5 -93
- package/src/tools/task-create/handler.ts +1 -1
- package/src/tools/task-get/handler.ts +1 -1
- package/src/tools/task-list/handler.ts +1 -1
- package/src/tools/task-update/handler.ts +1 -1
- package/src/tools/write-file/handler.ts +47 -0
- package/src/workflow.ts +88 -47
- package/tsup.config.ts +8 -1
- package/dist/adapters/langchain/index.cjs.map +0 -1
- package/dist/adapters/langchain/index.js.map +0 -1
- package/dist/model-invoker-y_zlyMqu.d.cts +0 -892
- package/dist/model-invoker-y_zlyMqu.d.ts +0 -892
- package/src/lib/tool-router.ts +0 -977
- package/src/lib/workflow-helpers.ts +0 -50
- /package/src/lib/{thread-id.ts → thread/id.ts} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { InMemoryFs, Bash } from 'just-bash';
|
|
2
|
+
import { ApplicationFailure } from '@temporalio/common';
|
|
3
|
+
import { uuid4 } from '@temporalio/workflow';
|
|
4
|
+
|
|
5
|
+
// src/adapters/sandbox/inmemory/index.ts
|
|
6
|
+
var SandboxNotFoundError = class extends ApplicationFailure {
|
|
7
|
+
constructor(sandboxId) {
|
|
8
|
+
super(`Sandbox not found: ${sandboxId}`, "SandboxNotFoundError", true);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
12
|
+
function getShortId(length = 12) {
|
|
13
|
+
const hex = uuid4().replace(/-/g, "");
|
|
14
|
+
let result = "";
|
|
15
|
+
for (let i = 0; i < length; i++) {
|
|
16
|
+
const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
17
|
+
result += BASE62[byte % BASE62.length];
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/adapters/sandbox/inmemory/index.ts
|
|
23
|
+
function toSandboxFs(fs) {
|
|
24
|
+
return {
|
|
25
|
+
readFile: (path) => fs.readFile(path),
|
|
26
|
+
readFileBuffer: (path) => fs.readFileBuffer(path),
|
|
27
|
+
writeFile: (path, content) => fs.writeFile(path, content),
|
|
28
|
+
appendFile: (path, content) => fs.appendFile(path, content),
|
|
29
|
+
exists: (path) => fs.exists(path),
|
|
30
|
+
stat: async (path) => {
|
|
31
|
+
const s = await fs.stat(path);
|
|
32
|
+
return {
|
|
33
|
+
isFile: s.isFile,
|
|
34
|
+
isDirectory: s.isDirectory,
|
|
35
|
+
isSymbolicLink: s.isSymbolicLink,
|
|
36
|
+
size: s.size,
|
|
37
|
+
mtime: s.mtime
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
mkdir: (path, opts) => fs.mkdir(path, opts),
|
|
41
|
+
readdir: (path) => fs.readdir(path),
|
|
42
|
+
readdirWithFileTypes: async (path) => {
|
|
43
|
+
if (!fs.readdirWithFileTypes) {
|
|
44
|
+
const names = await fs.readdir(path);
|
|
45
|
+
return Promise.all(
|
|
46
|
+
names.map(async (name) => {
|
|
47
|
+
const s = await fs.stat(`${path}/${name}`);
|
|
48
|
+
return {
|
|
49
|
+
name,
|
|
50
|
+
isFile: s.isFile,
|
|
51
|
+
isDirectory: s.isDirectory,
|
|
52
|
+
isSymbolicLink: s.isSymbolicLink
|
|
53
|
+
};
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return fs.readdirWithFileTypes(path);
|
|
58
|
+
},
|
|
59
|
+
rm: (path, opts) => fs.rm(path, opts),
|
|
60
|
+
cp: (src, dest, opts) => fs.cp(src, dest, opts),
|
|
61
|
+
mv: (src, dest) => fs.mv(src, dest),
|
|
62
|
+
readlink: (path) => fs.readlink(path),
|
|
63
|
+
resolvePath: (base, p) => fs.resolvePath(base, p)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
var InMemorySandboxImpl = class {
|
|
67
|
+
constructor(id, justBashFs, options) {
|
|
68
|
+
this.id = id;
|
|
69
|
+
this.justBashFs = justBashFs;
|
|
70
|
+
this.fs = toSandboxFs(justBashFs);
|
|
71
|
+
this.bashOptions = {
|
|
72
|
+
executionLimits: { maxStringLength: 52428800 },
|
|
73
|
+
...options?.bashOptions
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
capabilities = {
|
|
77
|
+
filesystem: true,
|
|
78
|
+
execution: true,
|
|
79
|
+
persistence: true
|
|
80
|
+
};
|
|
81
|
+
fs;
|
|
82
|
+
bashOptions;
|
|
83
|
+
async exec(command, _options) {
|
|
84
|
+
const bash = new Bash({ ...this.bashOptions, fs: this.justBashFs });
|
|
85
|
+
const { exitCode, stderr, stdout } = await bash.exec(command);
|
|
86
|
+
return { exitCode, stdout, stderr };
|
|
87
|
+
}
|
|
88
|
+
async destroy() {
|
|
89
|
+
}
|
|
90
|
+
/** Expose the underlying IFileSystem for snapshot serialisation */
|
|
91
|
+
_getJustBashFs() {
|
|
92
|
+
return this.justBashFs;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var InMemorySandboxProvider = class {
|
|
96
|
+
constructor(defaultOptions) {
|
|
97
|
+
this.defaultOptions = defaultOptions;
|
|
98
|
+
}
|
|
99
|
+
id = "inmemory";
|
|
100
|
+
capabilities = {
|
|
101
|
+
filesystem: true,
|
|
102
|
+
execution: true,
|
|
103
|
+
persistence: true
|
|
104
|
+
};
|
|
105
|
+
sandboxes = /* @__PURE__ */ new Map();
|
|
106
|
+
async get(id) {
|
|
107
|
+
const sandbox = this.sandboxes.get(id);
|
|
108
|
+
if (!sandbox) throw new SandboxNotFoundError(id);
|
|
109
|
+
return sandbox;
|
|
110
|
+
}
|
|
111
|
+
async destroy(id) {
|
|
112
|
+
const sandbox = this.sandboxes.get(id);
|
|
113
|
+
if (sandbox) {
|
|
114
|
+
await sandbox.destroy();
|
|
115
|
+
this.sandboxes.delete(id);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async create(options) {
|
|
119
|
+
const id = options?.id ?? getShortId();
|
|
120
|
+
const initialFiles = {};
|
|
121
|
+
if (options?.initialFiles) {
|
|
122
|
+
for (const [path, content] of Object.entries(options.initialFiles)) {
|
|
123
|
+
initialFiles[path] = content;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const fs = new InMemoryFs(initialFiles);
|
|
127
|
+
const sandbox = new InMemorySandboxImpl(id, fs, this.defaultOptions);
|
|
128
|
+
this.sandboxes.set(id, sandbox);
|
|
129
|
+
return { sandbox };
|
|
130
|
+
}
|
|
131
|
+
async snapshot(sandboxId) {
|
|
132
|
+
const sandbox = this.sandboxes.get(sandboxId);
|
|
133
|
+
if (!sandbox) throw new SandboxNotFoundError(sandboxId);
|
|
134
|
+
const fs = sandbox._getJustBashFs();
|
|
135
|
+
const paths = fs.getAllPaths();
|
|
136
|
+
const files = {};
|
|
137
|
+
for (const p of paths) {
|
|
138
|
+
try {
|
|
139
|
+
const stat = await fs.stat(p);
|
|
140
|
+
if (stat.isFile) {
|
|
141
|
+
files[p] = await fs.readFile(p);
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
sandboxId,
|
|
148
|
+
providerId: this.id,
|
|
149
|
+
data: { files },
|
|
150
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async restore(snapshot) {
|
|
154
|
+
const { files } = snapshot.data;
|
|
155
|
+
const initialFiles = {};
|
|
156
|
+
for (const [path, content] of Object.entries(files)) {
|
|
157
|
+
initialFiles[path] = content;
|
|
158
|
+
}
|
|
159
|
+
const fs = new InMemoryFs(initialFiles);
|
|
160
|
+
const sandbox = new InMemorySandboxImpl(
|
|
161
|
+
snapshot.sandboxId,
|
|
162
|
+
fs,
|
|
163
|
+
this.defaultOptions
|
|
164
|
+
);
|
|
165
|
+
this.sandboxes.set(sandbox.id, sandbox);
|
|
166
|
+
return sandbox;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export { InMemorySandboxProvider };
|
|
171
|
+
//# sourceMappingURL=index.js.map
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/sandbox/types.ts","../../../../src/lib/thread/id.ts","../../../../src/adapters/sandbox/inmemory/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\n// Sandbox Filesystem\n// ============================================================================\n\nexport interface DirentEntry {\n name: string;\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n}\n\nexport interface FileStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n size: number;\n mtime: Date;\n}\n\n/**\n * Provider-agnostic filesystem interface.\n *\n * Implementations that don't support a method should throw\n * {@link SandboxNotSupportedError}.\n */\nexport interface SandboxFileSystem {\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: string | Uint8Array): Promise<void>;\n appendFile(path: string, content: string | Uint8Array): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FileStat>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n readdir(path: string): Promise<string[]>;\n readdirWithFileTypes(path: string): Promise<DirentEntry[]>;\n rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>;\n cp(src: string, dest: string, options?: { recursive?: boolean }): Promise<void>;\n mv(src: string, dest: string): Promise<void>;\n readlink(path: string): Promise<string>;\n resolvePath(base: string, path: string): string;\n}\n\n// ============================================================================\n// Execution\n// ============================================================================\n\nexport interface ExecOptions {\n timeout?: number;\n cwd?: string;\n env?: Record<string, string>;\n}\n\nexport interface ExecResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n// ============================================================================\n// Capabilities\n// ============================================================================\n\nexport interface SandboxCapabilities {\n /** Sandbox supports filesystem operations */\n filesystem: boolean;\n /** Sandbox supports shell/command execution */\n execution: boolean;\n /** Sandbox state can be persisted and restored */\n persistence: boolean;\n}\n\n// ============================================================================\n// Sandbox\n// ============================================================================\n\nexport interface Sandbox {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n readonly fs: SandboxFileSystem;\n\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n destroy(): Promise<void>;\n}\n\n// ============================================================================\n// Snapshots\n// ============================================================================\n\nexport interface SandboxSnapshot {\n sandboxId: string;\n providerId: string;\n /** Provider-specific serialised state */\n data: unknown;\n createdAt: string;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport interface SandboxCreateOptions {\n /** Preferred sandbox ID (provider may ignore) */\n id?: string;\n /** Seed the filesystem with these files */\n initialFiles?: Record<string, string | Uint8Array>;\n /** Environment variables available inside the sandbox */\n env?: Record<string, string>;\n}\n\nexport interface SandboxCreateResult {\n sandbox: Sandbox;\n /** Optional state to merge into the workflow's `AgentState` via the session. */\n stateUpdate?: Record<string, unknown>;\n}\n\nexport interface SandboxProvider<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n TSandbox extends Sandbox = Sandbox,\n> {\n readonly id: string;\n readonly capabilities: SandboxCapabilities;\n\n create(options?: TOptions): Promise<SandboxCreateResult>;\n get(sandboxId: string): Promise<TSandbox>;\n destroy(sandboxId: string): Promise<void>;\n snapshot(sandboxId: string): Promise<SandboxSnapshot>;\n restore(snapshot: SandboxSnapshot): Promise<Sandbox>;\n}\n\n// ============================================================================\n// SandboxOps — workflow-side activity interface (like ThreadOps)\n// ============================================================================\n\nexport interface SandboxOps<\n TOptions extends SandboxCreateOptions = SandboxCreateOptions,\n> {\n createSandbox(\n options?: TOptions,\n ): Promise<{ sandboxId: string; stateUpdate?: Record<string, unknown> }>;\n destroySandbox(sandboxId: string): Promise<void>;\n snapshotSandbox(sandboxId: string): Promise<SandboxSnapshot>;\n}\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nimport { ApplicationFailure } from \"@temporalio/common\";\n\nexport class SandboxNotSupportedError extends ApplicationFailure {\n constructor(operation: string) {\n super(\n `Sandbox does not support: ${operation}`,\n \"SandboxNotSupportedError\",\n true,\n );\n }\n}\n\nexport class SandboxNotFoundError extends ApplicationFailure {\n constructor(sandboxId: string) {\n super(`Sandbox not found: ${sandboxId}`, \"SandboxNotFoundError\", true);\n }\n}\n","import { uuid4 } from \"@temporalio/workflow\";\n\nconst BASE62 =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\n/**\n * Generate a compact, workflow-deterministic identifier.\n *\n * Uses Temporal's `uuid4()` internally (seeded by the workflow's RNG),\n * then re-encodes the hex bytes into a base-62 alphabet for a shorter,\n * more token-efficient identifier (~3 tokens vs ~10 for a full UUID).\n *\n * Suitable for thread IDs, child workflow IDs, or any workflow-scoped identifier.\n *\n * @param length - Number of base-62 characters (default 12, ~71 bits of entropy)\n */\nexport function getShortId(length = 12): string {\n const hex = uuid4().replace(/-/g, \"\");\n let result = \"\";\n for (let i = 0; i < length; i++) {\n const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n result += BASE62[byte % BASE62.length];\n }\n return result;\n}\n","import {\n Bash,\n InMemoryFs,\n type BashOptions,\n type IFileSystem,\n type InitialFiles,\n} from \"just-bash\";\nimport type {\n Sandbox,\n SandboxCapabilities,\n SandboxCreateOptions,\n SandboxCreateResult,\n SandboxFileSystem,\n SandboxProvider,\n SandboxSnapshot,\n ExecOptions,\n ExecResult,\n DirentEntry,\n FileStat,\n} from \"../../../lib/sandbox/types\";\nimport { SandboxNotFoundError } from \"../../../lib/sandbox/types\";\nimport { getShortId } from \"../../../lib/thread/id\";\n\n// ============================================================================\n// Adapter: IFileSystem → SandboxFileSystem\n// ============================================================================\n\nfunction toSandboxFs(fs: IFileSystem): SandboxFileSystem {\n return {\n readFile: (path) => fs.readFile(path),\n readFileBuffer: (path) => fs.readFileBuffer(path),\n writeFile: (path, content) => fs.writeFile(path, content),\n appendFile: (path, content) => fs.appendFile(path, content),\n exists: (path) => fs.exists(path),\n stat: async (path): Promise<FileStat> => {\n const s = await fs.stat(path);\n return {\n isFile: s.isFile,\n isDirectory: s.isDirectory,\n isSymbolicLink: s.isSymbolicLink,\n size: s.size,\n mtime: s.mtime,\n };\n },\n mkdir: (path, opts) => fs.mkdir(path, opts),\n readdir: (path) => fs.readdir(path),\n readdirWithFileTypes: async (path): Promise<DirentEntry[]> => {\n if (!fs.readdirWithFileTypes) {\n const names = await fs.readdir(path);\n return Promise.all(\n names.map(async (name) => {\n const s = await fs.stat(`${path}/${name}`);\n return {\n name,\n isFile: s.isFile,\n isDirectory: s.isDirectory,\n isSymbolicLink: s.isSymbolicLink,\n };\n })\n );\n }\n return fs.readdirWithFileTypes(path);\n },\n rm: (path, opts) => fs.rm(path, opts),\n cp: (src, dest, opts) => fs.cp(src, dest, opts),\n mv: (src, dest) => fs.mv(src, dest),\n readlink: (path) => fs.readlink(path),\n resolvePath: (base, p) => fs.resolvePath(base, p),\n };\n}\n\n// ============================================================================\n// InMemorySandbox\n// ============================================================================\n\nexport interface InMemorySandboxOptions {\n /** Options forwarded to `just-bash` `Bash` (minus `fs` which is managed) */\n bashOptions?: Omit<BashOptions, \"fs\">;\n}\n\n/**\n * An in-memory {@link Sandbox} backed by `just-bash`.\n */\nexport type InMemorySandbox = Sandbox & { fs: SandboxFileSystem };\n\nclass InMemorySandboxImpl implements Sandbox {\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: true,\n };\n\n readonly fs: SandboxFileSystem;\n private bashOptions: Omit<BashOptions, \"fs\">;\n\n constructor(\n readonly id: string,\n private justBashFs: IFileSystem,\n options?: InMemorySandboxOptions\n ) {\n this.fs = toSandboxFs(justBashFs);\n this.bashOptions = {\n executionLimits: { maxStringLength: 52_428_800 },\n ...options?.bashOptions,\n };\n }\n\n async exec(command: string, _options?: ExecOptions): Promise<ExecResult> {\n const bash = new Bash({ ...this.bashOptions, fs: this.justBashFs });\n const { exitCode, stderr, stdout } = await bash.exec(command);\n return { exitCode, stdout, stderr };\n }\n\n async destroy(): Promise<void> {\n // In-memory: nothing to clean up\n }\n\n /** Expose the underlying IFileSystem for snapshot serialisation */\n _getJustBashFs(): IFileSystem {\n return this.justBashFs;\n }\n}\n\n// ============================================================================\n// InMemorySandboxProvider\n// ============================================================================\n\nexport class InMemorySandboxProvider implements SandboxProvider {\n readonly id = \"inmemory\";\n readonly capabilities: SandboxCapabilities = {\n filesystem: true,\n execution: true,\n persistence: true,\n };\n\n private sandboxes = new Map<string, InMemorySandboxImpl>();\n\n constructor(private defaultOptions?: InMemorySandboxOptions) {}\n\n async get(id: string): Promise<Sandbox> {\n const sandbox = this.sandboxes.get(id);\n if (!sandbox) throw new SandboxNotFoundError(id);\n return sandbox;\n }\n\n async destroy(id: string): Promise<void> {\n const sandbox = this.sandboxes.get(id);\n if (sandbox) {\n await sandbox.destroy();\n this.sandboxes.delete(id);\n }\n }\n\n async create(options?: SandboxCreateOptions): Promise<SandboxCreateResult> {\n const id = options?.id ?? getShortId();\n const initialFiles: InitialFiles = {};\n\n if (options?.initialFiles) {\n for (const [path, content] of Object.entries(options.initialFiles)) {\n initialFiles[path] = content;\n }\n }\n\n const fs = new InMemoryFs(initialFiles);\n const sandbox = new InMemorySandboxImpl(id, fs, this.defaultOptions);\n this.sandboxes.set(id, sandbox);\n return { sandbox };\n }\n\n async snapshot(sandboxId: string): Promise<SandboxSnapshot> {\n const sandbox = this.sandboxes.get(sandboxId);\n if (!sandbox) throw new SandboxNotFoundError(sandboxId);\n\n const fs = sandbox._getJustBashFs();\n const paths = fs.getAllPaths();\n const files: Record<string, string> = {};\n\n for (const p of paths) {\n try {\n const stat = await fs.stat(p);\n if (stat.isFile) {\n files[p] = await fs.readFile(p);\n }\n } catch {\n // skip entries that can't be read (e.g. broken symlinks)\n }\n }\n\n return {\n sandboxId,\n providerId: this.id,\n data: { files },\n createdAt: new Date().toISOString(),\n };\n }\n\n async restore(snapshot: SandboxSnapshot): Promise<Sandbox> {\n const { files } = snapshot.data as { files: Record<string, string> };\n const initialFiles: InitialFiles = {};\n for (const [path, content] of Object.entries(files)) {\n initialFiles[path] = content;\n }\n\n const fs = new InMemoryFs(initialFiles);\n const sandbox = new InMemorySandboxImpl(\n snapshot.sandboxId,\n fs,\n this.defaultOptions\n );\n this.sandboxes.set(sandbox.id, sandbox);\n return sandbox;\n }\n}\n"]}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var common = require('@temporalio/common');
|
|
4
|
+
var workflow = require('@temporalio/workflow');
|
|
5
|
+
var activity = require('@temporalio/activity');
|
|
6
|
+
|
|
7
|
+
// src/lib/sandbox/types.ts
|
|
8
|
+
var SandboxNotSupportedError = class extends common.ApplicationFailure {
|
|
9
|
+
constructor(operation) {
|
|
10
|
+
super(
|
|
11
|
+
`Sandbox does not support: ${operation}`,
|
|
12
|
+
"SandboxNotSupportedError",
|
|
13
|
+
true
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/adapters/sandbox/virtual/filesystem.ts
|
|
19
|
+
function normalisePath(p) {
|
|
20
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
21
|
+
p = p.replace(/\/+/g, "/");
|
|
22
|
+
if (p.length > 1 && p.endsWith("/")) p = p.slice(0, -1);
|
|
23
|
+
return p;
|
|
24
|
+
}
|
|
25
|
+
function parentDir(p) {
|
|
26
|
+
const idx = p.lastIndexOf("/");
|
|
27
|
+
return idx <= 0 ? "/" : p.slice(0, idx);
|
|
28
|
+
}
|
|
29
|
+
function inferDirectories(entries) {
|
|
30
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
31
|
+
dirs.add("/");
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
let dir = parentDir(normalisePath(entry.path));
|
|
34
|
+
while (dir !== "/" && !dirs.has(dir)) {
|
|
35
|
+
dirs.add(dir);
|
|
36
|
+
dir = parentDir(dir);
|
|
37
|
+
}
|
|
38
|
+
dirs.add("/");
|
|
39
|
+
}
|
|
40
|
+
return dirs;
|
|
41
|
+
}
|
|
42
|
+
var VirtualSandboxFileSystem = class {
|
|
43
|
+
constructor(tree, resolver, ctx) {
|
|
44
|
+
this.resolver = resolver;
|
|
45
|
+
this.ctx = ctx;
|
|
46
|
+
this.entries = new Map(
|
|
47
|
+
tree.map((e) => [normalisePath(e.path), e])
|
|
48
|
+
);
|
|
49
|
+
this.directories = inferDirectories(tree);
|
|
50
|
+
}
|
|
51
|
+
entries;
|
|
52
|
+
directories;
|
|
53
|
+
mutations = [];
|
|
54
|
+
/** Return all mutations accumulated during this invocation. */
|
|
55
|
+
getMutations() {
|
|
56
|
+
return this.mutations;
|
|
57
|
+
}
|
|
58
|
+
/** Look up a file entry by virtual path. */
|
|
59
|
+
getEntry(path) {
|
|
60
|
+
return this.entries.get(normalisePath(path));
|
|
61
|
+
}
|
|
62
|
+
// --------------------------------------------------------------------------
|
|
63
|
+
// Read operations — delegate to resolver lazily
|
|
64
|
+
// --------------------------------------------------------------------------
|
|
65
|
+
async readFile(path) {
|
|
66
|
+
const entry = this.entries.get(normalisePath(path));
|
|
67
|
+
if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
|
|
68
|
+
return this.resolver.readFile(entry.id, this.ctx);
|
|
69
|
+
}
|
|
70
|
+
async readFileBuffer(path) {
|
|
71
|
+
const entry = this.entries.get(normalisePath(path));
|
|
72
|
+
if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
|
|
73
|
+
return this.resolver.readFileBuffer(entry.id, this.ctx);
|
|
74
|
+
}
|
|
75
|
+
// --------------------------------------------------------------------------
|
|
76
|
+
// Metadata operations — pure, resolved from the tree
|
|
77
|
+
// --------------------------------------------------------------------------
|
|
78
|
+
async exists(path) {
|
|
79
|
+
const norm = normalisePath(path);
|
|
80
|
+
return this.entries.has(norm) || this.directories.has(norm);
|
|
81
|
+
}
|
|
82
|
+
async stat(path) {
|
|
83
|
+
const norm = normalisePath(path);
|
|
84
|
+
const entry = this.entries.get(norm);
|
|
85
|
+
if (entry) {
|
|
86
|
+
return {
|
|
87
|
+
isFile: true,
|
|
88
|
+
isDirectory: false,
|
|
89
|
+
isSymbolicLink: false,
|
|
90
|
+
size: entry.size,
|
|
91
|
+
mtime: new Date(entry.mtime)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (this.directories.has(norm)) {
|
|
95
|
+
return {
|
|
96
|
+
isFile: false,
|
|
97
|
+
isDirectory: true,
|
|
98
|
+
isSymbolicLink: false,
|
|
99
|
+
size: 0,
|
|
100
|
+
mtime: /* @__PURE__ */ new Date()
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`ENOENT: no such file or directory: ${path}`);
|
|
104
|
+
}
|
|
105
|
+
async readdir(path) {
|
|
106
|
+
const norm = normalisePath(path);
|
|
107
|
+
if (!this.directories.has(norm)) {
|
|
108
|
+
throw new Error(`ENOENT: no such directory: ${path}`);
|
|
109
|
+
}
|
|
110
|
+
const prefix = norm === "/" ? "/" : norm + "/";
|
|
111
|
+
const names = /* @__PURE__ */ new Set();
|
|
112
|
+
for (const p of this.entries.keys()) {
|
|
113
|
+
if (p.startsWith(prefix)) {
|
|
114
|
+
const rest = p.slice(prefix.length);
|
|
115
|
+
const seg = rest.split("/")[0];
|
|
116
|
+
if (seg) names.add(seg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const d of this.directories) {
|
|
120
|
+
if (d.startsWith(prefix) && d !== norm) {
|
|
121
|
+
const rest = d.slice(prefix.length);
|
|
122
|
+
const seg = rest.split("/")[0];
|
|
123
|
+
if (seg) names.add(seg);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return [...names].sort();
|
|
127
|
+
}
|
|
128
|
+
async readdirWithFileTypes(path) {
|
|
129
|
+
const names = await this.readdir(path);
|
|
130
|
+
const norm = normalisePath(path);
|
|
131
|
+
const prefix = norm === "/" ? "/" : norm + "/";
|
|
132
|
+
return names.map((name) => {
|
|
133
|
+
const full = prefix + name;
|
|
134
|
+
const isFile = this.entries.has(full);
|
|
135
|
+
const isDirectory = this.directories.has(full);
|
|
136
|
+
return { name, isFile, isDirectory, isSymbolicLink: false };
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// --------------------------------------------------------------------------
|
|
140
|
+
// Write operations — delegate to resolver, record mutations
|
|
141
|
+
// --------------------------------------------------------------------------
|
|
142
|
+
async writeFile(path, content) {
|
|
143
|
+
const norm = normalisePath(path);
|
|
144
|
+
const existing = this.entries.get(norm);
|
|
145
|
+
if (existing) {
|
|
146
|
+
await this.resolver.writeFile(existing.id, content, this.ctx);
|
|
147
|
+
const size = typeof content === "string" ? new TextEncoder().encode(content).byteLength : content.byteLength;
|
|
148
|
+
const updated = {
|
|
149
|
+
...existing,
|
|
150
|
+
size,
|
|
151
|
+
mtime: (/* @__PURE__ */ new Date()).toISOString()
|
|
152
|
+
};
|
|
153
|
+
this.entries.set(norm, updated);
|
|
154
|
+
this.mutations.push({ type: "update", path: norm, entry: updated });
|
|
155
|
+
} else {
|
|
156
|
+
const entry = await this.resolver.createFile(norm, content, this.ctx);
|
|
157
|
+
const normalised = { ...entry, path: norm };
|
|
158
|
+
this.entries.set(norm, normalised);
|
|
159
|
+
this.addParentDirectories(norm);
|
|
160
|
+
this.mutations.push({ type: "add", entry: normalised });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async appendFile(path, content) {
|
|
164
|
+
const norm = normalisePath(path);
|
|
165
|
+
const existing = this.entries.get(norm);
|
|
166
|
+
if (!existing) {
|
|
167
|
+
return this.writeFile(path, content);
|
|
168
|
+
}
|
|
169
|
+
const current = await this.resolver.readFile(existing.id, this.ctx);
|
|
170
|
+
const appended = typeof content === "string" ? current + content : current + new TextDecoder().decode(content);
|
|
171
|
+
await this.resolver.writeFile(existing.id, appended, this.ctx);
|
|
172
|
+
const size = new TextEncoder().encode(appended).byteLength;
|
|
173
|
+
const updated = {
|
|
174
|
+
...existing,
|
|
175
|
+
size,
|
|
176
|
+
mtime: (/* @__PURE__ */ new Date()).toISOString()
|
|
177
|
+
};
|
|
178
|
+
this.entries.set(norm, updated);
|
|
179
|
+
this.mutations.push({ type: "update", path: norm, entry: updated });
|
|
180
|
+
}
|
|
181
|
+
async mkdir(_path, _options) {
|
|
182
|
+
const norm = normalisePath(_path);
|
|
183
|
+
if (this.directories.has(norm)) return;
|
|
184
|
+
if (_options?.recursive) {
|
|
185
|
+
this.addParentDirectories(norm + "/placeholder");
|
|
186
|
+
this.directories.add(norm);
|
|
187
|
+
} else {
|
|
188
|
+
const parent = parentDir(norm);
|
|
189
|
+
if (!this.directories.has(parent)) {
|
|
190
|
+
throw new Error(`ENOENT: no such directory: ${parent}`);
|
|
191
|
+
}
|
|
192
|
+
this.directories.add(norm);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async rm(path, options) {
|
|
196
|
+
const norm = normalisePath(path);
|
|
197
|
+
const entry = this.entries.get(norm);
|
|
198
|
+
if (entry) {
|
|
199
|
+
await this.resolver.deleteFile(entry.id, this.ctx);
|
|
200
|
+
this.entries.delete(norm);
|
|
201
|
+
this.mutations.push({ type: "remove", path: norm });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (this.directories.has(norm)) {
|
|
205
|
+
if (!options?.recursive) {
|
|
206
|
+
throw new Error(`EISDIR: is a directory (use recursive): ${path}`);
|
|
207
|
+
}
|
|
208
|
+
const prefix = norm === "/" ? "/" : norm + "/";
|
|
209
|
+
for (const [p, e] of this.entries) {
|
|
210
|
+
if (p.startsWith(prefix)) {
|
|
211
|
+
await this.resolver.deleteFile(e.id, this.ctx);
|
|
212
|
+
this.entries.delete(p);
|
|
213
|
+
this.mutations.push({ type: "remove", path: p });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
for (const d of this.directories) {
|
|
217
|
+
if (d.startsWith(prefix)) this.directories.delete(d);
|
|
218
|
+
}
|
|
219
|
+
this.directories.delete(norm);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!options?.force) {
|
|
223
|
+
throw new Error(`ENOENT: no such file or directory: ${path}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async cp(src, dest, _options) {
|
|
227
|
+
const normSrc = normalisePath(src);
|
|
228
|
+
const normDest = normalisePath(dest);
|
|
229
|
+
const entry = this.entries.get(normSrc);
|
|
230
|
+
if (entry) {
|
|
231
|
+
const content = await this.resolver.readFile(entry.id, this.ctx);
|
|
232
|
+
await this.writeFile(normDest, content);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!this.directories.has(normSrc)) {
|
|
236
|
+
throw new Error(`ENOENT: no such file or directory: ${src}`);
|
|
237
|
+
}
|
|
238
|
+
if (!_options?.recursive) {
|
|
239
|
+
throw new Error(`EISDIR: is a directory (use recursive): ${src}`);
|
|
240
|
+
}
|
|
241
|
+
const prefix = normSrc === "/" ? "/" : normSrc + "/";
|
|
242
|
+
for (const [p, e] of this.entries) {
|
|
243
|
+
if (p.startsWith(prefix)) {
|
|
244
|
+
const relative = p.slice(normSrc.length);
|
|
245
|
+
const content = await this.resolver.readFile(e.id, this.ctx);
|
|
246
|
+
await this.writeFile(normDest + relative, content);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async mv(src, dest) {
|
|
251
|
+
await this.cp(src, dest, { recursive: true });
|
|
252
|
+
await this.rm(src, { recursive: true });
|
|
253
|
+
}
|
|
254
|
+
// --------------------------------------------------------------------------
|
|
255
|
+
// Unsupported
|
|
256
|
+
// --------------------------------------------------------------------------
|
|
257
|
+
async readlink(_path) {
|
|
258
|
+
throw new SandboxNotSupportedError("readlink");
|
|
259
|
+
}
|
|
260
|
+
resolvePath(base, path) {
|
|
261
|
+
if (path.startsWith("/")) return normalisePath(path);
|
|
262
|
+
const combined = base.endsWith("/") ? base + path : base + "/" + path;
|
|
263
|
+
return normalisePath(combined);
|
|
264
|
+
}
|
|
265
|
+
// --------------------------------------------------------------------------
|
|
266
|
+
// Helpers
|
|
267
|
+
// --------------------------------------------------------------------------
|
|
268
|
+
addParentDirectories(filePath) {
|
|
269
|
+
let dir = parentDir(normalisePath(filePath));
|
|
270
|
+
while (!this.directories.has(dir)) {
|
|
271
|
+
this.directories.add(dir);
|
|
272
|
+
dir = parentDir(dir);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
277
|
+
function getShortId(length = 12) {
|
|
278
|
+
const hex = workflow.uuid4().replace(/-/g, "");
|
|
279
|
+
let result = "";
|
|
280
|
+
for (let i = 0; i < length; i++) {
|
|
281
|
+
const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
282
|
+
result += BASE62[byte % BASE62.length];
|
|
283
|
+
}
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/adapters/sandbox/virtual/provider.ts
|
|
288
|
+
var VirtualSandboxProvider = class {
|
|
289
|
+
id = "virtual";
|
|
290
|
+
capabilities = {
|
|
291
|
+
filesystem: true,
|
|
292
|
+
execution: false,
|
|
293
|
+
persistence: true
|
|
294
|
+
};
|
|
295
|
+
resolver;
|
|
296
|
+
constructor(resolver) {
|
|
297
|
+
this.resolver = resolver;
|
|
298
|
+
}
|
|
299
|
+
async create(options) {
|
|
300
|
+
if (!options || !("resolverContext" in options)) {
|
|
301
|
+
throw new Error("VirtualSandboxProvider.create requires resolverContext");
|
|
302
|
+
}
|
|
303
|
+
const sandboxId = options.id ?? getShortId();
|
|
304
|
+
const fileTree = await this.resolver.resolveEntries(
|
|
305
|
+
options.resolverContext
|
|
306
|
+
);
|
|
307
|
+
const sandbox = createVirtualSandbox(
|
|
308
|
+
sandboxId,
|
|
309
|
+
fileTree,
|
|
310
|
+
this.resolver,
|
|
311
|
+
options.resolverContext
|
|
312
|
+
);
|
|
313
|
+
return {
|
|
314
|
+
sandbox,
|
|
315
|
+
stateUpdate: {
|
|
316
|
+
sandboxId,
|
|
317
|
+
fileTree,
|
|
318
|
+
resolverContext: options.resolverContext
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async get() {
|
|
323
|
+
throw new SandboxNotSupportedError(
|
|
324
|
+
"get (virtual sandbox state lives in workflow AgentState)"
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
async destroy() {
|
|
328
|
+
}
|
|
329
|
+
async snapshot() {
|
|
330
|
+
throw new SandboxNotSupportedError(
|
|
331
|
+
"snapshot (virtual sandbox state lives in workflow AgentState)"
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
async restore() {
|
|
335
|
+
throw new SandboxNotSupportedError(
|
|
336
|
+
"restore (virtual sandbox state lives in workflow AgentState)"
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
async function queryParentWorkflowState(client) {
|
|
341
|
+
const { workflowExecution } = activity.Context.current().info;
|
|
342
|
+
const handle = client.getHandle(
|
|
343
|
+
workflowExecution.workflowId,
|
|
344
|
+
workflowExecution.runId
|
|
345
|
+
);
|
|
346
|
+
return handle.query("getAgentState");
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/adapters/sandbox/virtual/with-virtual-sandbox.ts
|
|
350
|
+
function withVirtualSandbox(client, provider, handler) {
|
|
351
|
+
return async (args, context) => {
|
|
352
|
+
const state = await queryParentWorkflowState(client);
|
|
353
|
+
const { sandboxId, fileTree, resolverContext } = state;
|
|
354
|
+
if (!fileTree || !sandboxId) {
|
|
355
|
+
return {
|
|
356
|
+
toolResponse: `Error: No fileTree/sandboxId in agent state. The ${context.toolName} tool requires a virtual sandbox.`,
|
|
357
|
+
data: null
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const sandbox = createVirtualSandbox(
|
|
361
|
+
sandboxId,
|
|
362
|
+
fileTree,
|
|
363
|
+
provider.resolver,
|
|
364
|
+
resolverContext
|
|
365
|
+
);
|
|
366
|
+
const response = await handler(args, { ...context, sandbox });
|
|
367
|
+
const mutations = sandbox.fs.getMutations();
|
|
368
|
+
return {
|
|
369
|
+
toolResponse: response.toolResponse,
|
|
370
|
+
data: {
|
|
371
|
+
...response.data ?? {},
|
|
372
|
+
treeMutations: mutations
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/adapters/sandbox/virtual/index.ts
|
|
379
|
+
var VirtualSandboxImpl = class {
|
|
380
|
+
constructor(id, tree, resolver, ctx) {
|
|
381
|
+
this.id = id;
|
|
382
|
+
this.fs = new VirtualSandboxFileSystem(tree, resolver, ctx);
|
|
383
|
+
}
|
|
384
|
+
capabilities = {
|
|
385
|
+
filesystem: true,
|
|
386
|
+
execution: false,
|
|
387
|
+
persistence: true
|
|
388
|
+
};
|
|
389
|
+
fs;
|
|
390
|
+
async exec(_command, _options) {
|
|
391
|
+
throw new SandboxNotSupportedError("exec");
|
|
392
|
+
}
|
|
393
|
+
async destroy() {
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
function createVirtualSandbox(id, tree, resolver, ctx) {
|
|
397
|
+
return new VirtualSandboxImpl(id, tree, resolver, ctx);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
exports.VirtualSandboxFileSystem = VirtualSandboxFileSystem;
|
|
401
|
+
exports.VirtualSandboxProvider = VirtualSandboxProvider;
|
|
402
|
+
exports.createVirtualSandbox = createVirtualSandbox;
|
|
403
|
+
exports.withVirtualSandbox = withVirtualSandbox;
|
|
404
|
+
//# sourceMappingURL=index.cjs.map
|
|
405
|
+
//# sourceMappingURL=index.cjs.map
|