@h-sandbox/deepagents 0.1.0-rc.1 → 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 +29 -8
- 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
|
@@ -35,17 +35,28 @@ verifies the original tests and returns a diff after confirmed cleanup.
|
|
|
35
35
|
|
|
36
36
|
**Developer preview on npm.** Install `@h-sandbox/deepagents@next` with the exact
|
|
37
37
|
SDK and framework peers below. Native tools and an independently verified model
|
|
38
|
-
repair have passed. Node 20
|
|
39
|
-
Node
|
|
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
53
|
# In your server-side application:
|
|
43
|
-
npm install --save-exact @h-sandbox/deepagents@next @h-sandbox/sdk@0.5.0-rc.
|
|
54
|
+
npm install --save-exact @h-sandbox/deepagents@next @h-sandbox/sdk@0.5.0-rc.12 \
|
|
44
55
|
deepagents@1.14.0 langchain@1.5.11 @langchain/core@1.2.12 \
|
|
45
56
|
@langchain/langgraph@1.4.17 langsmith@0.9.0 zod@4.4.3
|
|
46
57
|
```
|
|
47
58
|
|
|
48
|
-
The tested peers are **SDK 0.5.0-rc.
|
|
59
|
+
The tested peers are **SDK 0.5.0-rc.12 and Deep Agents 1.14.0**, both exact because
|
|
49
60
|
these preview contracts are evolving. `--save-exact` resolves the moving `next`
|
|
50
61
|
channel to a concrete version; commit your application's lockfile. Other
|
|
51
62
|
framework or SDK versions need a fresh compatibility run.
|
|
@@ -129,6 +140,13 @@ checkpointer, pause for approval and retrieve one command's result. It does not
|
|
|
129
140
|
claim process-restart durability. Production applications supply a persistent
|
|
130
141
|
checkpointer and their own authorized sandbox lookup.
|
|
131
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
|
+
|
|
132
150
|
The repair example requires **Node.js, Git,
|
|
133
151
|
bash and GNU file tools** in the selected template. Its blocked egress policy
|
|
134
152
|
requires enforcement support in your installation. It downloads no dependencies
|
|
@@ -176,10 +194,13 @@ distinguishes native qualification from package publication and deployment.
|
|
|
176
194
|
exits are ordinary tool results. The adapter never retries a mutation.
|
|
177
195
|
A framework or model can still request the same action again; approval and
|
|
178
196
|
idempotent application operations are required where repeat effects matter.
|
|
179
|
-
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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.
|
|
183
204
|
- Output is stdout followed by stderr, not a chronological merge. The default
|
|
184
205
|
combined UTF-8 log limit is 64 KiB; provider truncation flags remain visible.
|
|
185
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",
|