agent-neckbeard 0.0.2 → 0.0.4
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 +33 -3
- package/dist/index.d.ts +14 -1
- package/dist/index.js +69 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ E2B provides sandboxed environments, but wiring up the deployment, bundling, and
|
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
import { Agent } from 'agent-neckbeard';
|
|
23
|
-
import { query } from '@anthropic-ai/claude-
|
|
23
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
24
24
|
import { z } from 'zod';
|
|
25
25
|
|
|
26
26
|
const summaryAgent = new Agent({
|
|
@@ -66,10 +66,11 @@ console.log(result.keyPoints); // string[] - validated
|
|
|
66
66
|
npm install agent-neckbeard
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
Set your
|
|
69
|
+
Set your API keys:
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
|
-
export E2B_API_KEY=your-api-key
|
|
72
|
+
export E2B_API_KEY=your-e2b-api-key
|
|
73
|
+
export ANTHROPIC_API_KEY=your-anthropic-api-key # Required for Claude Agent SDK
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
## Running Examples
|
|
@@ -92,6 +93,11 @@ const agent = new Agent({
|
|
|
92
93
|
run: (input, ctx) => Promise, // Your agent logic
|
|
93
94
|
maxDuration?: number, // Timeout in seconds (default: 300)
|
|
94
95
|
sandboxId?: string, // Reuse existing sandbox (skip deploy)
|
|
96
|
+
dependencies?: { // OS-level dependencies to install
|
|
97
|
+
apt?: string[], // APT packages (e.g., ['curl', 'git'])
|
|
98
|
+
npm?: string[], // Global npm packages
|
|
99
|
+
commands?: string[], // Custom shell commands
|
|
100
|
+
},
|
|
95
101
|
});
|
|
96
102
|
```
|
|
97
103
|
|
|
@@ -130,6 +136,30 @@ const agent = new Agent({
|
|
|
130
136
|
const result = await agent.run({ topic: 'hello' });
|
|
131
137
|
```
|
|
132
138
|
|
|
139
|
+
## External Packages
|
|
140
|
+
|
|
141
|
+
Some packages can't be bundled and need to be installed in the sandbox at runtime. These include packages that:
|
|
142
|
+
- Spawn child processes (like `@anthropic-ai/claude-agent-sdk` which spawns its CLI)
|
|
143
|
+
- Have native modules
|
|
144
|
+
|
|
145
|
+
These packages are automatically marked as external during bundling and installed via npm in the sandbox.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
149
|
+
|
|
150
|
+
const agent = new Agent({
|
|
151
|
+
// ...
|
|
152
|
+
run: async (input, ctx) => {
|
|
153
|
+
for await (const message of query({
|
|
154
|
+
prompt: `Do something with ${input.topic}`,
|
|
155
|
+
options: { maxTurns: 10, allowedTools: ['Bash', 'Read', 'Write'] },
|
|
156
|
+
})) {
|
|
157
|
+
// Handle Claude's responses
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
133
163
|
## Context
|
|
134
164
|
|
|
135
165
|
The `run` function receives a context object:
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,16 @@ interface AgentRunContext {
|
|
|
15
15
|
interface SchemaLike<T> {
|
|
16
16
|
parse: (data: unknown) => T;
|
|
17
17
|
}
|
|
18
|
+
interface OsDependencies {
|
|
19
|
+
/** APT packages to install (e.g., ['curl', 'git']) */
|
|
20
|
+
apt?: string[];
|
|
21
|
+
/** NPM packages to install globally (e.g., ['typescript', '@anthropic-ai/claude-code']) */
|
|
22
|
+
npm?: string[];
|
|
23
|
+
/** Custom shell commands to run during setup */
|
|
24
|
+
commands?: string[];
|
|
25
|
+
}
|
|
26
|
+
/** Default dependencies - empty by default, specify what you need */
|
|
27
|
+
declare const DEFAULT_DEPENDENCIES: OsDependencies;
|
|
18
28
|
interface AgentConfig<TInput, TOutput> {
|
|
19
29
|
id: string;
|
|
20
30
|
inputSchema: SchemaLike<TInput>;
|
|
@@ -22,12 +32,15 @@ interface AgentConfig<TInput, TOutput> {
|
|
|
22
32
|
run: (input: TInput, ctx: AgentRunContext) => Promise<TOutput>;
|
|
23
33
|
maxDuration?: number;
|
|
24
34
|
sandboxId?: string;
|
|
35
|
+
/** OS-level dependencies to install in the sandbox. Defaults to Claude Code. Set to {} to skip. */
|
|
36
|
+
dependencies?: OsDependencies;
|
|
25
37
|
}
|
|
26
38
|
declare class Agent<TInput, TOutput> {
|
|
27
39
|
readonly id: string;
|
|
28
40
|
readonly inputSchema: SchemaLike<TInput>;
|
|
29
41
|
readonly outputSchema: SchemaLike<TOutput>;
|
|
30
42
|
readonly maxDuration: number;
|
|
43
|
+
readonly dependencies: OsDependencies;
|
|
31
44
|
/** @internal Used by the sandbox runner - must be public for bundled code access */
|
|
32
45
|
_run: (input: TInput, ctx: AgentRunContext) => Promise<TOutput>;
|
|
33
46
|
private _sourceFile;
|
|
@@ -38,4 +51,4 @@ declare class Agent<TInput, TOutput> {
|
|
|
38
51
|
run(input: TInput): Promise<TOutput>;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
export { Agent, type AgentConfig, type AgentRunContext };
|
|
54
|
+
export { Agent, type AgentConfig, type AgentRunContext, DEFAULT_DEPENDENCIES, type OsDependencies };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { fileURLToPath } from "url";
|
|
3
3
|
var getEsbuild = () => import("esbuild");
|
|
4
4
|
var getE2b = () => import("e2b");
|
|
5
|
+
var DEFAULT_DEPENDENCIES = {};
|
|
5
6
|
function getCallerFile() {
|
|
6
7
|
const stack = new Error().stack?.split("\n") ?? [];
|
|
7
8
|
for (const line of stack.slice(2)) {
|
|
@@ -19,6 +20,7 @@ var Agent = class {
|
|
|
19
20
|
inputSchema;
|
|
20
21
|
outputSchema;
|
|
21
22
|
maxDuration;
|
|
23
|
+
dependencies;
|
|
22
24
|
/** @internal Used by the sandbox runner - must be public for bundled code access */
|
|
23
25
|
_run;
|
|
24
26
|
_sourceFile;
|
|
@@ -31,6 +33,7 @@ var Agent = class {
|
|
|
31
33
|
this._run = config.run;
|
|
32
34
|
this._sourceFile = getCallerFile();
|
|
33
35
|
this._sandboxId = config.sandboxId;
|
|
36
|
+
this.dependencies = config.dependencies ?? DEFAULT_DEPENDENCIES;
|
|
34
37
|
}
|
|
35
38
|
get sandboxId() {
|
|
36
39
|
return this._sandboxId;
|
|
@@ -39,6 +42,11 @@ var Agent = class {
|
|
|
39
42
|
if (this._sandboxId) return;
|
|
40
43
|
const esbuild = await getEsbuild();
|
|
41
44
|
const { Sandbox } = await getE2b();
|
|
45
|
+
const collectedExternals = /* @__PURE__ */ new Set();
|
|
46
|
+
const mustBeExternal = [
|
|
47
|
+
/^@anthropic-ai\/claude-agent-sdk/
|
|
48
|
+
// Spawns cli.js as child process
|
|
49
|
+
];
|
|
42
50
|
const result = await esbuild.build({
|
|
43
51
|
entryPoints: [this._sourceFile],
|
|
44
52
|
bundle: true,
|
|
@@ -49,7 +57,7 @@ var Agent = class {
|
|
|
49
57
|
minify: true,
|
|
50
58
|
keepNames: true,
|
|
51
59
|
plugins: [{
|
|
52
|
-
name: "agent-neckbeard-
|
|
60
|
+
name: "agent-neckbeard-externals",
|
|
53
61
|
setup(build) {
|
|
54
62
|
build.onResolve({ filter: /^agent-neckbeard$/ }, () => ({
|
|
55
63
|
path: "agent-neckbeard",
|
|
@@ -69,6 +77,21 @@ var Agent = class {
|
|
|
69
77
|
`,
|
|
70
78
|
loader: "js"
|
|
71
79
|
}));
|
|
80
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
81
|
+
if (args.path.startsWith(".") || args.path.startsWith("/") || args.path.startsWith("node:")) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
for (const pattern of mustBeExternal) {
|
|
85
|
+
if (pattern.test(args.path)) {
|
|
86
|
+
const match = args.path.match(/^(@[^/]+\/[^/]+|[^/]+)/);
|
|
87
|
+
if (match) {
|
|
88
|
+
collectedExternals.add(match[1]);
|
|
89
|
+
}
|
|
90
|
+
return { external: true };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
});
|
|
72
95
|
}
|
|
73
96
|
}]
|
|
74
97
|
});
|
|
@@ -107,8 +130,47 @@ try {
|
|
|
107
130
|
const sandbox = await Sandbox.create("base", {
|
|
108
131
|
apiKey: process.env.E2B_API_KEY
|
|
109
132
|
});
|
|
133
|
+
const { apt, npm, commands } = this.dependencies;
|
|
134
|
+
if (apt && apt.length > 0) {
|
|
135
|
+
const aptCmd = `apt-get update && apt-get install -y ${apt.join(" ")}`;
|
|
136
|
+
const aptResult = await sandbox.commands.run(aptCmd, { timeoutMs: 3e5 });
|
|
137
|
+
if (aptResult.exitCode !== 0) {
|
|
138
|
+
throw new Error(`Failed to install apt packages: ${aptResult.stderr}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (npm && npm.length > 0) {
|
|
142
|
+
const npmCmd = `npm install -g ${npm.join(" ")}`;
|
|
143
|
+
const npmResult = await sandbox.commands.run(npmCmd, { timeoutMs: 3e5 });
|
|
144
|
+
if (npmResult.exitCode !== 0) {
|
|
145
|
+
throw new Error(`Failed to install npm packages: ${npmResult.stderr}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (commands && commands.length > 0) {
|
|
149
|
+
for (const cmd of commands) {
|
|
150
|
+
const cmdResult = await sandbox.commands.run(cmd, { timeoutMs: 3e5 });
|
|
151
|
+
if (cmdResult.exitCode !== 0) {
|
|
152
|
+
throw new Error(`Failed to run command "${cmd}": ${cmdResult.stderr}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
110
156
|
await sandbox.files.write("/home/user/agent.mjs", result.outputFiles[0].text);
|
|
111
157
|
await sandbox.files.write("/home/user/runner.mjs", runnerCode);
|
|
158
|
+
if (collectedExternals.size > 0) {
|
|
159
|
+
const dependencies = {};
|
|
160
|
+
for (const pkg of collectedExternals) {
|
|
161
|
+
dependencies[pkg] = "*";
|
|
162
|
+
}
|
|
163
|
+
const pkgJson = JSON.stringify({
|
|
164
|
+
name: "agent-sandbox",
|
|
165
|
+
type: "module",
|
|
166
|
+
dependencies
|
|
167
|
+
});
|
|
168
|
+
await sandbox.files.write("/home/user/package.json", pkgJson);
|
|
169
|
+
const installResult = await sandbox.commands.run("cd /home/user && npm install", { timeoutMs: 3e5 });
|
|
170
|
+
if (installResult.exitCode !== 0) {
|
|
171
|
+
throw new Error(`Failed to install external packages: ${installResult.stderr}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
112
174
|
this._sandboxId = sandbox.sandboxId;
|
|
113
175
|
}
|
|
114
176
|
async run(input) {
|
|
@@ -123,7 +185,10 @@ try {
|
|
|
123
185
|
});
|
|
124
186
|
await sandbox.files.write("/home/user/input/task.json", JSON.stringify({ input: validatedInput, executionId }));
|
|
125
187
|
const result = await sandbox.commands.run("node /home/user/runner.mjs", {
|
|
126
|
-
timeoutMs: this.maxDuration * 1e3
|
|
188
|
+
timeoutMs: this.maxDuration * 1e3,
|
|
189
|
+
envs: {
|
|
190
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY ?? ""
|
|
191
|
+
}
|
|
127
192
|
});
|
|
128
193
|
if (result.exitCode !== 0) throw new Error(`Agent failed: ${result.stderr}`);
|
|
129
194
|
const output = JSON.parse(await sandbox.files.read("/home/user/output/result.json"));
|
|
@@ -136,5 +201,6 @@ try {
|
|
|
136
201
|
}
|
|
137
202
|
};
|
|
138
203
|
export {
|
|
139
|
-
Agent
|
|
204
|
+
Agent,
|
|
205
|
+
DEFAULT_DEPENDENCIES
|
|
140
206
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-neckbeard",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Deploy AI agents to E2B sandboxes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"esbuild": "^0.24.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"zod": "^3.0.0"
|
|
32
|
+
"zod": "^3.0.0 || ^4.0.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependenciesMeta": {
|
|
35
35
|
"zod": {
|