agen-vektor 0.3.21 → 0.3.22
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 +1 -0
- package/dist/agent/agent.js +4 -0
- package/dist/tools/e2b.js +144 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -359,6 +359,7 @@ Every shell command is classified:
|
|
|
359
359
|
| `vector-tui.methatech.eu.org` (VectorHead Free gateway) | Only if you pick the free tier; the shared provider key stays server-side, users never see it |
|
|
360
360
|
| Brave / Exa / Serper | Only when you use the web-search tool with your own key |
|
|
361
361
|
| `vector-tui.methatech.eu.org/v1/web-search` | Web search when you have NO search key of your own — the query is relayed by the gateway; your own key, when set, always takes precedence and bypasses the relay |
|
|
362
|
+
| `vector-tui.methatech.eu.org/v1/e2b/run` | `e2b_run` tool — run a command in a disposable cloud sandbox (E2B VM) when the local machine is too weak/restricted; relayed by the gateway, no E2B key needed client-side |
|
|
362
363
|
| Raw model catalog (public JSON) | To populate the free-tier model list |
|
|
363
364
|
|
|
364
365
|
**Stored locally** (all in `~/.vector/`): `config.json` (preferences, no secrets), `credentials.json` (only keys *you* enter, file mode 0600), sessions, memory, logs. Nothing else is written anywhere.
|
package/dist/agent/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ const search_1 = require("../tools/search");
|
|
|
8
8
|
const shell_1 = require("../tools/shell");
|
|
9
9
|
const git_1 = require("../tools/git");
|
|
10
10
|
const web_1 = require("../tools/web");
|
|
11
|
+
const e2b_1 = require("../tools/e2b");
|
|
11
12
|
const extras_1 = require("../tools/extras");
|
|
12
13
|
const apply_patch_1 = require("../tools/apply-patch");
|
|
13
14
|
const permissions_1 = require("../security/permissions");
|
|
@@ -59,6 +60,9 @@ class Agent {
|
|
|
59
60
|
(0, shell_1.createShellTool)(),
|
|
60
61
|
(0, git_1.createGitTool)(),
|
|
61
62
|
...(0, web_1.createWebTools)(),
|
|
63
|
+
// E2B cloud sandbox (via gateway relay): e2b_run / e2b_status —
|
|
64
|
+
// eksekusi di VM cloud utk perangkat lemah, zero-config (key di gateway).
|
|
65
|
+
...(0, e2b_1.createE2bTools)(),
|
|
62
66
|
// Freebuff-style extras: glob, read_subtree, task_completed,
|
|
63
67
|
// suggest_followups, render_ui.
|
|
64
68
|
...(0, extras_1.createExtrasTools)(),
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createE2bTools = createE2bTools;
|
|
4
|
+
const credentials_1 = require("../config/credentials");
|
|
5
|
+
const free_tier_1 = require("../config/free-tier");
|
|
6
|
+
const GW_BASE = free_tier_1.FREE_GATEWAY_URL.replace(/\/v1$/, '');
|
|
7
|
+
// Poll interval env-overridable (test memakai VECTOR_E2B_POLL_MS=10).
|
|
8
|
+
const POLL_INTERVAL_MS = Math.max(10, Number(process.env.VECTOR_E2B_POLL_MS) || 3_000);
|
|
9
|
+
const POLL_MAX_MS = 320_000; // > E2B_MAX_TIMEOUT_MS worker (300s) + margin
|
|
10
|
+
const OUT_CAP = 20_000;
|
|
11
|
+
async function postRun(command, timeoutMs) {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timer = setTimeout(() => controller.abort(), 30_000);
|
|
14
|
+
try {
|
|
15
|
+
const res = await fetch(GW_BASE + '/v1/e2b/run', {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
signal: controller.signal,
|
|
18
|
+
headers: { 'Content-Type': 'application/json', 'User-Agent': 'VectorHead-AI-Agent/0.1' },
|
|
19
|
+
body: JSON.stringify({ command, timeout_ms: timeoutMs }),
|
|
20
|
+
});
|
|
21
|
+
const data = (await res.json().catch(() => null));
|
|
22
|
+
return { res, data };
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function fetchStatus(id) {
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const timer = setTimeout(() => controller.abort(), 20_000);
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch(GW_BASE + '/v1/e2b/status?id=' + encodeURIComponent(id), {
|
|
33
|
+
signal: controller.signal,
|
|
34
|
+
headers: { 'User-Agent': 'VectorHead-AI-Agent/0.1' },
|
|
35
|
+
});
|
|
36
|
+
const data = (await res.json().catch(() => null));
|
|
37
|
+
return { res, data };
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function formatResult(s) {
|
|
44
|
+
const exit = s.exitCode === null || s.exitCode === undefined ? '?' : s.exitCode;
|
|
45
|
+
let out = `exit ${exit}`;
|
|
46
|
+
if (s.stdout)
|
|
47
|
+
out += '\n' + s.stdout.slice(0, OUT_CAP);
|
|
48
|
+
if (s.stderr)
|
|
49
|
+
out += (s.stdout ? '\n[stderr]\n' : '') + s.stderr.slice(0, Math.min(OUT_CAP, 10_000));
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
async function pollUntilDone(id) {
|
|
53
|
+
const deadline = Date.now() + POLL_MAX_MS;
|
|
54
|
+
let last = null;
|
|
55
|
+
while (Date.now() < deadline) {
|
|
56
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
57
|
+
const { res, data } = await fetchStatus(id);
|
|
58
|
+
if (!res.ok || !data)
|
|
59
|
+
continue; // gesit — coba lagi sampai deadline
|
|
60
|
+
last = data;
|
|
61
|
+
if (data.status === 'done' || data.status === 'error')
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
return last;
|
|
65
|
+
}
|
|
66
|
+
function createE2bTools() {
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
definition: {
|
|
70
|
+
name: 'e2b_run',
|
|
71
|
+
description: 'Run a shell command inside a disposable cloud sandbox (E2B VM via the VectorHead gateway relay) and wait for the result. Use when the local machine is too weak/restricted for a task — builds, installs, or tests that do not fit locally. Network is available in the sandbox. Returns exit code + stdout/stderr (this tool blocks until the command finishes; timeout default 120s, max 300s). Destructive commands (mkfs, fork bombs, pipe-to-shell) are rejected by the relay policy.',
|
|
72
|
+
parameters: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
command: { type: 'string', description: 'The shell command to run in the sandbox (bash -lc; use && to chain)' },
|
|
76
|
+
timeout_ms: { type: 'number', description: 'Timeout in ms (default 120000, max 300000)' },
|
|
77
|
+
},
|
|
78
|
+
required: ['command'],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
async execute(args, ctx) {
|
|
82
|
+
const command = String(args.command || '').trim();
|
|
83
|
+
if (!command)
|
|
84
|
+
return { output: 'ERROR: provide a "command"' };
|
|
85
|
+
const timeoutMs = Math.min(300_000, Math.max(5_000, Number(args.timeout_ms) || 120_000));
|
|
86
|
+
ctx.onActivity?.('e2b', `sandbox: ${command.slice(0, 80)}`);
|
|
87
|
+
const { res, data } = await postRun(command, timeoutMs);
|
|
88
|
+
if (!res.ok || !data || !data.id) {
|
|
89
|
+
const why = data?.error ? ` — ${(0, credentials_1.redact)(data.error)}` : '';
|
|
90
|
+
return { output: `ERROR: e2b relay HTTP ${res.status}${why}`, summary: 'e2b relay error' };
|
|
91
|
+
}
|
|
92
|
+
const done = await pollUntilDone(data.id);
|
|
93
|
+
if (!done) {
|
|
94
|
+
return {
|
|
95
|
+
output: `ERROR: e2b job ${data.id} belum selesai dan polling kehabisan waktu — cek manual: curl '${GW_BASE}/v1/e2b/status?id=${data.id}'`,
|
|
96
|
+
summary: 'e2b polling timeout',
|
|
97
|
+
data: { id: data.id },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (done.status === 'error') {
|
|
101
|
+
return {
|
|
102
|
+
output: `ERROR: e2b job failed${done.error ? ': ' + (0, credentials_1.redact)(done.error) : ''}`,
|
|
103
|
+
summary: 'e2b job error',
|
|
104
|
+
data: { id: data.id },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const out = formatResult(done);
|
|
108
|
+
return {
|
|
109
|
+
output: out,
|
|
110
|
+
summary: `e2b sandbox → exit ${done.exitCode ?? '?'}`,
|
|
111
|
+
data: { id: data.id, exitCode: done.exitCode, stdout: done.stdout, stderr: done.stderr },
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
definition: {
|
|
117
|
+
name: 'e2b_status',
|
|
118
|
+
description: 'Check the result of an E2B sandbox job by id (from e2b_run): status (running|done|error), exit code, stdout/stderr. Only needed when you kept an id and want the latest state without polling yourself.',
|
|
119
|
+
parameters: {
|
|
120
|
+
type: 'object',
|
|
121
|
+
properties: {
|
|
122
|
+
id: { type: 'string', description: 'Job id returned by e2b_run' },
|
|
123
|
+
},
|
|
124
|
+
required: ['id'],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
async execute(args) {
|
|
128
|
+
const id = String(args.id || '').trim();
|
|
129
|
+
if (!/^[A-Za-z0-9-]{8,80}$/.test(id))
|
|
130
|
+
return { output: 'ERROR: invalid job id' };
|
|
131
|
+
const { res, data } = await fetchStatus(id);
|
|
132
|
+
if (!res.ok || !data) {
|
|
133
|
+
const why = data?.error ? ` — ${(0, credentials_1.redact)(data.error)}` : '';
|
|
134
|
+
return { output: `ERROR: e2b status HTTP ${res.status}${why}`, summary: 'e2b status error' };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
output: data.status === 'done' || data.status === 'error' ? formatResult(data) : `status: ${data.status}`,
|
|
138
|
+
summary: `e2b job ${id}: ${data.status}`,
|
|
139
|
+
data,
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
}
|
package/package.json
CHANGED