@h-sandbox/deepagents 0.1.0-rc.0 → 0.1.0-rc.2
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 +41 -25
- package/dist/backend.js +8 -5
- package/dist/execution.d.ts +5 -5
- package/dist/execution.js +25 -2
- package/dist/lifecycle.js +4 -2
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -33,28 +33,33 @@ verifies the original tests and returns a diff after confirmed cleanup.
|
|
|
33
33
|
|
|
34
34
|
## Availability
|
|
35
35
|
|
|
36
|
-
**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
**Developer preview on npm.** Install `@h-sandbox/deepagents@next` with the exact
|
|
37
|
+
SDK and framework peers below. Native tools and an independently verified model
|
|
38
|
+
repair have passed. Use Node 22 or 24 LTS. Node 20 remains a legacy compatibility target, not a supported
|
|
39
|
+
Node.js production line. This optional package has its
|
|
40
|
+
own release cycle, separate from the SDK.
|
|
41
|
+
|
|
42
|
+
Minimal backend installation:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install --save-exact @h-sandbox/deepagents@next @h-sandbox/sdk@0.5.0-rc.12 deepagents@1.14.0
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
For the complete model and checkpoint examples, start with the full direct
|
|
49
|
+
dependency set together. Adding older framework pins after auto-installed peers
|
|
50
|
+
can leave duplicate LangGraph types in a pnpm lockfile.
|
|
40
51
|
|
|
41
52
|
```bash
|
|
42
|
-
# In
|
|
43
|
-
|
|
44
|
-
pnpm --filter @h-sandbox/deepagents build
|
|
45
|
-
mkdir -p /tmp/harakiri-framework-candidate
|
|
46
|
-
pnpm --filter @h-sandbox/deepagents pack --pack-destination /tmp/harakiri-framework-candidate
|
|
47
|
-
|
|
48
|
-
# In your server-side application, using the resulting adapter archive path:
|
|
49
|
-
npm install --save-exact @h-sandbox/sdk@0.5.0-rc.11 "$DEEPAGENTS_TARBALL" \
|
|
53
|
+
# In your server-side application:
|
|
54
|
+
npm install --save-exact @h-sandbox/deepagents@next @h-sandbox/sdk@0.5.0-rc.12 \
|
|
50
55
|
deepagents@1.14.0 langchain@1.5.11 @langchain/core@1.2.12 \
|
|
51
56
|
@langchain/langgraph@1.4.17 langsmith@0.9.0 zod@4.4.3
|
|
52
57
|
```
|
|
53
58
|
|
|
54
|
-
The tested peers are **SDK 0.5.0-rc.
|
|
55
|
-
these preview contracts are evolving.
|
|
56
|
-
|
|
57
|
-
versions need a fresh compatibility run.
|
|
59
|
+
The tested peers are **SDK 0.5.0-rc.12 and Deep Agents 1.14.0**, both exact because
|
|
60
|
+
these preview contracts are evolving. `--save-exact` resolves the moving `next`
|
|
61
|
+
channel to a concrete version; commit your application's lockfile. Other
|
|
62
|
+
framework or SDK versions need a fresh compatibility run.
|
|
58
63
|
|
|
59
64
|
## Connect an Existing Sandbox
|
|
60
65
|
|
|
@@ -135,6 +140,13 @@ checkpointer, pause for approval and retrieve one command's result. It does not
|
|
|
135
140
|
claim process-restart durability. Production applications supply a persistent
|
|
136
141
|
checkpointer and their own authorized sandbox lookup.
|
|
137
142
|
|
|
143
|
+
The [persistent workflow guide](https://github.com/nabilblk/h-sandbox/blob/main/docs/integrations/reliable-framework-workflows.md)
|
|
144
|
+
adds a real `createDeepAgent`/PostgresSaver application with separate worker
|
|
145
|
+
processes, checkpoint-bound approval, acknowledged-command observation and
|
|
146
|
+
explicit retained-file recovery. Use adapter `0.1.0-rc.2` and SDK `0.5.0-rc.12`.
|
|
147
|
+
The application example is versioned source, not a database service in the package;
|
|
148
|
+
the guide shows how to run it against the published dependencies.
|
|
149
|
+
|
|
138
150
|
The repair example requires **Node.js, Git,
|
|
139
151
|
bash and GNU file tools** in the selected template. Its blocked egress policy
|
|
140
152
|
requires enforcement support in your installation. It downloads no dependencies
|
|
@@ -166,11 +178,12 @@ command exercises remote shell/file operations with scripted decisions. Real
|
|
|
166
178
|
model acceptance and publication are separate gates. On September 24, the
|
|
167
179
|
digest-pinned Qwen3 4B Instruct model completed this repair on an isolated amd64
|
|
168
180
|
runner: five responses, no truncated responses or invalid tool calls, unchanged
|
|
169
|
-
original tests, a verified patch and confirmed cleanup. The
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
181
|
+
original tests, a verified patch and confirmed cleanup. The
|
|
182
|
+
[full qualification run](https://github.com/nabilblk/h-sandbox/actions/runs/36007730164)
|
|
183
|
+
passed all 15 gates, including operator-key revocation. This is one small repair,
|
|
184
|
+
not a model-quality or production reliability benchmark. The
|
|
185
|
+
[delivery receipt](https://github.com/nabilblk/h-sandbox/blob/main/docs/release-notes/deepagents-0.1.0-delivery.md)
|
|
186
|
+
distinguishes native qualification from package publication and deployment.
|
|
174
187
|
|
|
175
188
|
## Boundaries
|
|
176
189
|
|
|
@@ -181,10 +194,13 @@ model-quality or production reliability benchmark.
|
|
|
181
194
|
exits are ordinary tool results. The adapter never retries a mutation.
|
|
182
195
|
A framework or model can still request the same action again; approval and
|
|
183
196
|
idempotent application operations are required where repeat effects matter.
|
|
184
|
-
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
197
|
+
- HTTP `requestTimeoutMs`, execution timeout,
|
|
198
|
+
observation timeout and sandbox TTL are separate. JSON HTTP requests default
|
|
199
|
+
to 120 seconds, including body reads. Per-call options and caller cancellation
|
|
200
|
+
also cover submissions, logs and transfers; the adapter's observation budget
|
|
201
|
+
includes final logs. None of these kill a remote command or authorize a retry.
|
|
202
|
+
Earlier rc.1 instead requires a bounded custom `fetch` for per-request
|
|
203
|
+
deadlines and its observation budget excludes final logs.
|
|
188
204
|
- Output is stdout followed by stderr, not a chronological merge. The default
|
|
189
205
|
combined UTF-8 log limit is 64 KiB; provider truncation flags remain visible.
|
|
190
206
|
A fixed-size termination notice is outside that limit so timeouts/kills are
|
package/dist/backend.js
CHANGED
|
@@ -21,7 +21,7 @@ export class HarakiriSandboxBackend extends BaseSandbox {
|
|
|
21
21
|
constructor(sandbox, options = {}) {
|
|
22
22
|
super();
|
|
23
23
|
if (typeof sandbox.files.readBytes !== "function" || typeof sandbox.processes.connect !== "function") {
|
|
24
|
-
throw new TypeError("This adapter requires Harakiri SDK 0.5.0-rc.
|
|
24
|
+
throw new TypeError("This adapter requires its tested Harakiri SDK peer, 0.5.0-rc.12.");
|
|
25
25
|
}
|
|
26
26
|
this.#sandbox = sandbox;
|
|
27
27
|
this.#execution = executionOptions(sandbox, options);
|
|
@@ -38,7 +38,7 @@ export class HarakiriSandboxBackend extends BaseSandbox {
|
|
|
38
38
|
try {
|
|
39
39
|
const process = await this.#sandbox.processes.start({
|
|
40
40
|
command, cwd: this.#execution.cwd, timeoutMs: this.#execution.timeoutMs, detached: true
|
|
41
|
-
});
|
|
41
|
+
}, { signal: this.#execution.signal, requestTimeoutMs: this.#execution.requestTimeoutMs });
|
|
42
42
|
reference = process.reference;
|
|
43
43
|
}
|
|
44
44
|
catch (cause) {
|
|
@@ -76,7 +76,9 @@ export class HarakiriSandboxBackend extends BaseSandbox {
|
|
|
76
76
|
results.push({ path, error: "invalid_path" });
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
|
-
await this.#sandbox.files.write(this.#path(path), content, {
|
|
79
|
+
await this.#sandbox.files.write(this.#path(path), content, {
|
|
80
|
+
createParents: true, signal: this.#execution.signal, requestTimeoutMs: this.#execution.requestTimeoutMs
|
|
81
|
+
});
|
|
80
82
|
results.push({ path, error: null });
|
|
81
83
|
}
|
|
82
84
|
catch (cause) {
|
|
@@ -101,13 +103,14 @@ export class HarakiriSandboxBackend extends BaseSandbox {
|
|
|
101
103
|
continue;
|
|
102
104
|
}
|
|
103
105
|
const absolute = this.#path(path);
|
|
104
|
-
const {
|
|
106
|
+
const request = { signal: this.#execution.signal, requestTimeoutMs: this.#execution.requestTimeoutMs };
|
|
107
|
+
const { file } = await this.#sandbox.files.stat(absolute, request);
|
|
105
108
|
if (file.type === "directory" || file.type === "dir") {
|
|
106
109
|
results.push({ path, content: null, error: "is_directory" });
|
|
107
110
|
continue;
|
|
108
111
|
}
|
|
109
112
|
this.#checkBytes(bytes + file.size);
|
|
110
|
-
const content = await this.#sandbox.files.readBytes(absolute);
|
|
113
|
+
const content = await this.#sandbox.files.readBytes(absolute, request);
|
|
111
114
|
bytes += content.byteLength;
|
|
112
115
|
this.#checkBytes(bytes);
|
|
113
116
|
results.push({ path, content, error: null });
|
package/dist/execution.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { HarakiriSandbox, SandboxCommandLogsResponse, SandboxCommandSummary } from "@h-sandbox/sdk";
|
|
1
|
+
import type { HarakiriSandbox, RequestOptions, SandboxCommandLogsResponse, SandboxCommandSummary } from "@h-sandbox/sdk";
|
|
2
2
|
import type { ExecuteResponse } from "deepagents";
|
|
3
3
|
import { type CommandReference } from "./errors.js";
|
|
4
|
-
export type ExecutionOptions = {
|
|
4
|
+
export type ExecutionOptions = RequestOptions & {
|
|
5
5
|
/** Remote execution budget. Defaults to the runtime's advertised command timeout. */
|
|
6
6
|
timeoutMs?: number;
|
|
7
|
-
/**
|
|
7
|
+
/** Total observation budget, including final log download; never extends TTL. */
|
|
8
8
|
observationTimeoutMs?: number;
|
|
9
9
|
/** Combined UTF-8 log limit, excluding a fixed termination notice. Default 64 KiB; at most 1 MiB. */
|
|
10
10
|
maxOutputBytes?: number;
|
|
11
11
|
/** Must be absolute. This is a working directory, not a security boundary. */
|
|
12
12
|
cwd?: string;
|
|
13
|
-
/**
|
|
13
|
+
/** Cancels local requests/observation. It does not kill the remote command. */
|
|
14
14
|
signal?: AbortSignal;
|
|
15
15
|
/** Persist the acknowledged reference before waiting. Never receives credentials. */
|
|
16
16
|
onCommandStarted?: (reference: CommandReference) => void | Promise<void>;
|
|
@@ -25,8 +25,8 @@ export declare function executionOptions(sandbox: HarakiriSandbox, options: Exec
|
|
|
25
25
|
timeoutMs: number;
|
|
26
26
|
observationTimeoutMs: number;
|
|
27
27
|
maxOutputBytes: number;
|
|
28
|
-
/** Stops observation. It does not kill the remote command. */
|
|
29
28
|
signal?: AbortSignal;
|
|
29
|
+
requestTimeoutMs?: number;
|
|
30
30
|
/** Persist the acknowledged reference before waiting. Never receives credentials. */
|
|
31
31
|
onCommandStarted?: (reference: CommandReference) => void | Promise<void>;
|
|
32
32
|
};
|
package/dist/execution.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HarakiriWaitTimeoutError } from "@h-sandbox/sdk";
|
|
1
2
|
import { HarakiriExecutionError } from "./errors.js";
|
|
2
3
|
export function positiveInteger(name, value, maximum = Number.MAX_SAFE_INTEGER) {
|
|
3
4
|
if (!Number.isSafeInteger(value) || value < 1 || value > maximum) {
|
|
@@ -10,9 +11,11 @@ export function executionOptions(sandbox, options) {
|
|
|
10
11
|
if (!cwd.startsWith("/") || cwd.includes("\0"))
|
|
11
12
|
throw new TypeError("cwd must be an absolute path without NUL characters.");
|
|
12
13
|
const timeoutMs = positiveInteger("timeoutMs", options.timeoutMs ?? sandbox.runtimeMetadata.limits.commandTimeoutMs);
|
|
14
|
+
if (options.requestTimeoutMs !== undefined)
|
|
15
|
+
positiveInteger("requestTimeoutMs", options.requestTimeoutMs, 2_147_483_647);
|
|
13
16
|
return {
|
|
14
17
|
...options, cwd, timeoutMs,
|
|
15
|
-
observationTimeoutMs: positiveInteger("observationTimeoutMs", options.observationTimeoutMs ?? timeoutMs + 10_000),
|
|
18
|
+
observationTimeoutMs: positiveInteger("observationTimeoutMs", options.observationTimeoutMs ?? timeoutMs + 10_000, 2_147_483_647),
|
|
16
19
|
maxOutputBytes: positiveInteger("maxOutputBytes", options.maxOutputBytes ?? 65_536, 1_048_576)
|
|
17
20
|
};
|
|
18
21
|
}
|
|
@@ -54,13 +57,33 @@ export async function observeCommand(sandbox, reference, options) {
|
|
|
54
57
|
}
|
|
55
58
|
try {
|
|
56
59
|
options.signal?.throwIfAborted();
|
|
60
|
+
const deadline = Date.now() + options.observationTimeoutMs;
|
|
57
61
|
const { command } = await sandbox.processes.wait(reference.commandId, {
|
|
58
62
|
statuses: ["succeeded", "failed", "killed"],
|
|
59
63
|
timeoutMs: options.observationTimeoutMs,
|
|
64
|
+
requestTimeoutMs: options.requestTimeoutMs,
|
|
60
65
|
signal: options.signal
|
|
61
66
|
});
|
|
62
67
|
options.signal?.throwIfAborted();
|
|
63
|
-
const
|
|
68
|
+
const remainingMs = deadline - Date.now();
|
|
69
|
+
const timeout = () => new HarakiriWaitTimeoutError("Observation deadline elapsed during log retrieval. Reconnect using the command reference.", "command", reference.commandId, command.status);
|
|
70
|
+
if (remainingMs <= 0)
|
|
71
|
+
throw timeout();
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
74
|
+
const timer = setTimeout(() => controller.abort(timeout()), remainingMs);
|
|
75
|
+
let logs;
|
|
76
|
+
try {
|
|
77
|
+
logs = await sandbox.processes.logs(reference.commandId, {
|
|
78
|
+
signal, requestTimeoutMs: options.requestTimeoutMs
|
|
79
|
+
});
|
|
80
|
+
signal.throwIfAborted();
|
|
81
|
+
if (Date.now() >= deadline)
|
|
82
|
+
throw timeout();
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
}
|
|
64
87
|
options.signal?.throwIfAborted();
|
|
65
88
|
const result = commandOutput(logs, options.maxOutputBytes);
|
|
66
89
|
const notice = terminationNotice(command);
|
package/dist/lifecycle.js
CHANGED
|
@@ -11,11 +11,13 @@ export async function withHarakiriSandbox(client, input, task, options = {}) {
|
|
|
11
11
|
const cleanupTimeoutMs = positiveInteger("cleanupTimeoutMs", options.cleanupTimeoutMs ?? 90_000);
|
|
12
12
|
options.backend?.signal?.throwIfAborted();
|
|
13
13
|
// Retain the accepted handle before readiness so failures still enter cleanup.
|
|
14
|
-
const sandbox = await client.sandboxes.create({ ...input, wait: false }
|
|
14
|
+
const sandbox = await client.sandboxes.create({ ...input, wait: false }, {
|
|
15
|
+
signal: options.backend?.signal, requestTimeoutMs: options.backend?.requestTimeoutMs
|
|
16
|
+
});
|
|
15
17
|
let result;
|
|
16
18
|
const failures = [];
|
|
17
19
|
try {
|
|
18
|
-
await sandbox.wait({ timeoutMs: readinessTimeoutMs, signal: options.backend?.signal });
|
|
20
|
+
await sandbox.wait({ timeoutMs: readinessTimeoutMs, signal: options.backend?.signal, requestTimeoutMs: options.backend?.requestTimeoutMs });
|
|
19
21
|
const backend = new HarakiriSandboxBackend(sandbox, options.backend);
|
|
20
22
|
result = await task({ sandbox, backend });
|
|
21
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-sandbox/deepagents",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.2",
|
|
4
4
|
"description": "Deep Agents sandbox backend for the Harakiri control plane.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -30,18 +30,21 @@
|
|
|
30
30
|
"LICENSE"
|
|
31
31
|
],
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@h-sandbox/sdk": "0.5.0-rc.
|
|
33
|
+
"@h-sandbox/sdk": "0.5.0-rc.12",
|
|
34
34
|
"deepagents": "1.14.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"deepagents": "1.14.0",
|
|
38
38
|
"@langchain/core": "1.2.12",
|
|
39
39
|
"@langchain/langgraph": "1.4.17",
|
|
40
|
+
"@langchain/langgraph-checkpoint-postgres": "1.0.5",
|
|
41
|
+
"@types/pg": "8.20.0",
|
|
40
42
|
"langchain": "1.5.11",
|
|
41
43
|
"langsmith": "0.9.0",
|
|
44
|
+
"pg": "8.21.0",
|
|
42
45
|
"zod": "4.4.3",
|
|
43
46
|
"tsx": "^4.23.13",
|
|
44
|
-
"@h-sandbox/sdk": "0.5.0-rc.
|
|
47
|
+
"@h-sandbox/sdk": "0.5.0-rc.12"
|
|
45
48
|
},
|
|
46
49
|
"scripts": {
|
|
47
50
|
"clean": "rm -rf dist",
|