@ai-sdk/harness 1.0.121 → 1.0.123
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/CHANGELOG.md +30 -0
- package/dist/agent/index.d.ts +5 -5
- package/dist/agent/index.js +128 -49
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.js +0 -1
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +28 -6
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +30 -5
- package/dist/utils/index.js +130 -16
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -5
- package/src/agent/harness-agent.ts +32 -12
- package/src/agent/internal/bootstrap-recipe.ts +16 -16
- package/src/agent/internal/harness-stream-text-result.ts +1 -3
- package/src/agent/internal/sandbox-bootstrap.ts +24 -10
- package/src/agent/prepare-harness-sandbox-template.ts +16 -3
- package/src/agent/prepare-sandbox-for-harness.ts +14 -5
- package/src/bridge/index.ts +0 -1
- package/src/utils/sandbox-channel.ts +172 -19
- package/src/utils/write-instructions.ts +1 -1
- package/src/utils/write-skills.ts +1 -1
- package/src/v1/harness-session-data-directory-path.ts +28 -0
- package/src/v1/harness-v1-bootstrap.ts +5 -5
- package/src/v1/harness-v1-network-sandbox-session.ts +24 -0
- package/src/v1/index.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @ai-sdk/harness
|
|
2
2
|
|
|
3
|
+
## 1.0.123
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9c8c0c1: feat (harness): keep harness-generated state out of the sandbox workspace. The framework and every bridge adapter now resolve their generated state — bootstrap recipes and their dependencies (`.harness-bootstrap/…`) and per-session run state (`.agent-runs/…`) — through the new `harnessV1StateDirectory()` helper, which always resolves to a fixed directory (`~/.ai-sdk-harness`) under the sandbox's own HOME, never the sandbox's working directory. This is not configurable: every sandbox provider gets the same layout, so harness infrastructure never lands in a user-owned workspace. This changes the on-disk layout for every provider (a breaking change, acceptable given the experimental nature of this API) — sandboxes bootstrapped under the previous layout re-bootstrap once under the new path.
|
|
8
|
+
- 771e74b: chore: enable dead code lint rules
|
|
9
|
+
- 7115a3f: fix(harness): preserve buffered SandboxChannel event order without blocking selective listeners and forward Claude Code compaction events
|
|
10
|
+
- Updated dependencies [dcdb011]
|
|
11
|
+
- Updated dependencies [8f72832]
|
|
12
|
+
- Updated dependencies [fe07867]
|
|
13
|
+
- Updated dependencies [b74c0cb]
|
|
14
|
+
- Updated dependencies [a4b0940]
|
|
15
|
+
- Updated dependencies [2693319]
|
|
16
|
+
- Updated dependencies [c93ee90]
|
|
17
|
+
- Updated dependencies [771e74b]
|
|
18
|
+
- ai@7.0.113
|
|
19
|
+
- @ai-sdk/provider-utils@5.0.47
|
|
20
|
+
|
|
21
|
+
## 1.0.122
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [9a98fd9]
|
|
26
|
+
- Updated dependencies [a0553d6]
|
|
27
|
+
- Updated dependencies [ffb0e76]
|
|
28
|
+
- Updated dependencies [fde0d66]
|
|
29
|
+
- ai@7.0.112
|
|
30
|
+
- @ai-sdk/provider@4.0.18
|
|
31
|
+
- @ai-sdk/provider-utils@5.0.46
|
|
32
|
+
|
|
3
33
|
## 1.0.121
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { JSONSchema7, JSONValue, LanguageModelV4StreamPart, LanguageModelV4ToolC
|
|
|
8
8
|
/**
|
|
9
9
|
* One file to write into the sandbox as part of an adapter's bootstrap recipe.
|
|
10
10
|
* Absolute paths are used as-is. Relative paths are resolved against the
|
|
11
|
-
*
|
|
11
|
+
* harness state directory (`$HOME/.ai-sdk-harness`). Paths should live under
|
|
12
12
|
* {@link HarnessV1Bootstrap.bootstrapDir}.
|
|
13
13
|
*/
|
|
14
14
|
interface HarnessV1BootstrapFile {
|
|
@@ -37,10 +37,10 @@ interface HarnessV1Bootstrap {
|
|
|
37
37
|
readonly harnessId: string;
|
|
38
38
|
/**
|
|
39
39
|
* Path inside the sandbox where this recipe writes its state. Absolute paths
|
|
40
|
-
* are used as-is. Relative paths are resolved against the
|
|
41
|
-
*
|
|
42
|
-
* declared in {@link files} should also use this prefix so an
|
|
43
|
-
* can sweep stale state by clearing the directory.
|
|
40
|
+
* are used as-is. Relative paths are resolved against the harness state
|
|
41
|
+
* directory (`$HOME/.ai-sdk-harness`). The marker file lives directly under
|
|
42
|
+
* it. Files declared in {@link files} should also use this prefix so an
|
|
43
|
+
* adapter upgrade can sweep stale state by clearing the directory.
|
|
44
44
|
*/
|
|
45
45
|
readonly bootstrapDir: string;
|
|
46
46
|
/** Files to write into the sandbox before any command runs. */
|
package/dist/agent/index.js
CHANGED
|
@@ -38,6 +38,34 @@ var HarnessCapabilityUnsupportedError = class extends (_b2 = HarnessError, _a2 =
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
// src/v1/harness-v1-network-sandbox-session.ts
|
|
42
|
+
import { posix } from "path";
|
|
43
|
+
var HARNESS_V1_STATE_DIRECTORY_NAME = ".ai-sdk-harness";
|
|
44
|
+
function harnessStateDirectoryPath({
|
|
45
|
+
sandboxHomeDir
|
|
46
|
+
}) {
|
|
47
|
+
return posix.join(sandboxHomeDir, HARNESS_V1_STATE_DIRECTORY_NAME);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/v1/harness-session-data-directory-path.ts
|
|
51
|
+
import { posix as posix2 } from "path";
|
|
52
|
+
function encodeHarnessPathSegment(value) {
|
|
53
|
+
const encoded = encodeURIComponent(value);
|
|
54
|
+
if (encoded === "") return "%";
|
|
55
|
+
if (encoded === ".") return "%2E";
|
|
56
|
+
if (encoded === "..") return "%2E%2E";
|
|
57
|
+
return encoded;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/v1/harness-v1-tool-filtering.ts
|
|
61
|
+
function isHarnessV1BuiltinToolIncluded(input) {
|
|
62
|
+
if (input.toolFiltering == null) return true;
|
|
63
|
+
return input.toolFiltering.mode === "allow" ? input.toolFiltering.toolNames.includes(input.toolName) : !input.toolFiltering.toolNames.includes(input.toolName);
|
|
64
|
+
}
|
|
65
|
+
function getHarnessV1BuiltinToolFilteringDenialReason(input) {
|
|
66
|
+
return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;
|
|
67
|
+
}
|
|
68
|
+
|
|
41
69
|
// src/agent/harness-agent.ts
|
|
42
70
|
import {
|
|
43
71
|
asArray as asArray2,
|
|
@@ -115,15 +143,6 @@ async function validateLifecycleStateData(input) {
|
|
|
115
143
|
};
|
|
116
144
|
}
|
|
117
145
|
|
|
118
|
-
// src/v1/harness-v1-tool-filtering.ts
|
|
119
|
-
function isHarnessV1BuiltinToolIncluded(input) {
|
|
120
|
-
if (input.toolFiltering == null) return true;
|
|
121
|
-
return input.toolFiltering.mode === "allow" ? input.toolFiltering.toolNames.includes(input.toolName) : !input.toolFiltering.toolNames.includes(input.toolName);
|
|
122
|
-
}
|
|
123
|
-
function getHarnessV1BuiltinToolFilteringDenialReason(input) {
|
|
124
|
-
return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
146
|
// src/agent/internal/to-harness-stream.ts
|
|
128
147
|
async function toHarnessStream(options) {
|
|
129
148
|
let controller;
|
|
@@ -764,9 +783,7 @@ var HarnessStreamTextResult = class {
|
|
|
764
783
|
this.currentStepContent.push({
|
|
765
784
|
...part
|
|
766
785
|
});
|
|
767
|
-
return;
|
|
768
786
|
default:
|
|
769
|
-
return;
|
|
770
787
|
}
|
|
771
788
|
}
|
|
772
789
|
};
|
|
@@ -3251,7 +3268,7 @@ function collectHarnessAgentToolResultContinuations(input) {
|
|
|
3251
3268
|
}
|
|
3252
3269
|
|
|
3253
3270
|
// src/agent/internal/bootstrap-recipe.ts
|
|
3254
|
-
import { posix } from "path";
|
|
3271
|
+
import { posix as posix3 } from "path";
|
|
3255
3272
|
var BOOTSTRAP_SCHEMA_VERSION = 1;
|
|
3256
3273
|
async function hashHarnessBootstrap(recipe) {
|
|
3257
3274
|
const encoder = new TextEncoder();
|
|
@@ -3260,6 +3277,7 @@ async function hashHarnessBootstrap(recipe) {
|
|
|
3260
3277
|
chunks.push(encoder.encode(value));
|
|
3261
3278
|
chunks.push(encoder.encode("\0"));
|
|
3262
3279
|
};
|
|
3280
|
+
pushString(harnessStateDirectoryPath({ sandboxHomeDir: "$HOME" }));
|
|
3263
3281
|
pushString(recipe.harnessId);
|
|
3264
3282
|
pushString(recipe.bootstrapDir);
|
|
3265
3283
|
const sortedFiles = [...recipe.files].sort(
|
|
@@ -3289,12 +3307,12 @@ async function hashHarnessBootstrap(recipe) {
|
|
|
3289
3307
|
function bootstrapMarkerPath({
|
|
3290
3308
|
recipe,
|
|
3291
3309
|
identity,
|
|
3292
|
-
|
|
3310
|
+
stateDirectory
|
|
3293
3311
|
}) {
|
|
3294
|
-
return
|
|
3312
|
+
return posix3.join(
|
|
3295
3313
|
resolveBootstrapPath({
|
|
3296
3314
|
path: recipe.bootstrapDir,
|
|
3297
|
-
|
|
3315
|
+
stateDirectory
|
|
3298
3316
|
}),
|
|
3299
3317
|
`.bootstrap-${identity}.ok`
|
|
3300
3318
|
);
|
|
@@ -3303,13 +3321,13 @@ async function applyBootstrapRecipe({
|
|
|
3303
3321
|
session,
|
|
3304
3322
|
recipe,
|
|
3305
3323
|
identity,
|
|
3306
|
-
|
|
3324
|
+
stateDirectory,
|
|
3307
3325
|
abortSignal
|
|
3308
3326
|
}) {
|
|
3309
3327
|
const markerPath = bootstrapMarkerPath({
|
|
3310
3328
|
recipe,
|
|
3311
3329
|
identity,
|
|
3312
|
-
|
|
3330
|
+
stateDirectory
|
|
3313
3331
|
});
|
|
3314
3332
|
const existingMarker = await session.readTextFile({
|
|
3315
3333
|
path: markerPath,
|
|
@@ -3320,11 +3338,10 @@ async function applyBootstrapRecipe({
|
|
|
3320
3338
|
}
|
|
3321
3339
|
const bootstrapDir = resolveBootstrapPath({
|
|
3322
3340
|
path: recipe.bootstrapDir,
|
|
3323
|
-
|
|
3341
|
+
stateDirectory
|
|
3324
3342
|
});
|
|
3325
3343
|
const mkdirResult = await session.run({
|
|
3326
3344
|
command: 'mkdir -p "$BOOTSTRAP_DIR"',
|
|
3327
|
-
workingDirectory: defaultWorkingDirectory,
|
|
3328
3345
|
env: { BOOTSTRAP_DIR: bootstrapDir },
|
|
3329
3346
|
abortSignal
|
|
3330
3347
|
});
|
|
@@ -3338,7 +3355,7 @@ ${mkdirResult.stderr || mkdirResult.stdout}`
|
|
|
3338
3355
|
await session.writeTextFile({
|
|
3339
3356
|
path: resolveBootstrapPath({
|
|
3340
3357
|
path: file.path,
|
|
3341
|
-
|
|
3358
|
+
stateDirectory
|
|
3342
3359
|
}),
|
|
3343
3360
|
content: file.content,
|
|
3344
3361
|
abortSignal
|
|
@@ -3364,17 +3381,17 @@ ${result.stderr || result.stdout}`
|
|
|
3364
3381
|
});
|
|
3365
3382
|
}
|
|
3366
3383
|
function resolveBootstrapPath({
|
|
3367
|
-
path,
|
|
3368
|
-
|
|
3384
|
+
path: path2,
|
|
3385
|
+
stateDirectory
|
|
3369
3386
|
}) {
|
|
3370
|
-
return
|
|
3387
|
+
return posix3.isAbsolute(path2) ? path2 : posix3.resolve(stateDirectory, path2);
|
|
3371
3388
|
}
|
|
3372
3389
|
|
|
3373
3390
|
// src/agent/internal/sandbox-bootstrap.ts
|
|
3374
|
-
import { posix as
|
|
3391
|
+
import { posix as posix5 } from "path";
|
|
3375
3392
|
|
|
3376
3393
|
// src/utils/resolve-sandbox-default-working-directory.ts
|
|
3377
|
-
import { posix as
|
|
3394
|
+
import { posix as posix4 } from "path";
|
|
3378
3395
|
async function resolveSandboxDefaultWorkingDirectory({
|
|
3379
3396
|
sandboxSession,
|
|
3380
3397
|
abortSignal
|
|
@@ -3392,7 +3409,7 @@ async function resolveSandboxDefaultWorkingDirectory({
|
|
|
3392
3409
|
);
|
|
3393
3410
|
}
|
|
3394
3411
|
const cwd = result.stdout.trim();
|
|
3395
|
-
if (!
|
|
3412
|
+
if (!posix4.isAbsolute(cwd)) {
|
|
3396
3413
|
throw new Error(
|
|
3397
3414
|
`Failed to resolve sandbox default working directory: expected an absolute path, got ${JSON.stringify(cwd)}.`
|
|
3398
3415
|
);
|
|
@@ -3400,6 +3417,25 @@ async function resolveSandboxDefaultWorkingDirectory({
|
|
|
3400
3417
|
return cwd === "/" ? cwd : cwd.replace(/\/+$/, "");
|
|
3401
3418
|
}
|
|
3402
3419
|
|
|
3420
|
+
// src/utils/sandbox-home-dir.ts
|
|
3421
|
+
import path from "path";
|
|
3422
|
+
async function resolveSandboxHomeDir({
|
|
3423
|
+
sandbox,
|
|
3424
|
+
abortSignal
|
|
3425
|
+
}) {
|
|
3426
|
+
const result = await sandbox.run({
|
|
3427
|
+
command: 'printf "%s" "$HOME"',
|
|
3428
|
+
abortSignal
|
|
3429
|
+
});
|
|
3430
|
+
const homeDir = result.stdout.trim();
|
|
3431
|
+
if (result.exitCode !== 0 || !homeDir || !path.posix.isAbsolute(homeDir)) {
|
|
3432
|
+
throw new Error(
|
|
3433
|
+
`Unable to resolve sandbox HOME directory: ${result.stderr || result.stdout}`
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
return homeDir;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3403
3439
|
// src/agent/internal/sandbox-bootstrap.ts
|
|
3404
3440
|
var SANDBOX_BOOTSTRAP_IDENTITY_VERSION = 1;
|
|
3405
3441
|
function validateSandboxBootstrapSettings(settings) {
|
|
@@ -3426,10 +3462,10 @@ function normalizeSandboxWorkDir(workDir) {
|
|
|
3426
3462
|
"HarnessAgent: `sandboxConfig.workDir` must use POSIX path separators."
|
|
3427
3463
|
);
|
|
3428
3464
|
}
|
|
3429
|
-
if (
|
|
3465
|
+
if (posix5.isAbsolute(workDir)) {
|
|
3430
3466
|
throw new Error("HarnessAgent: `sandboxConfig.workDir` must be relative.");
|
|
3431
3467
|
}
|
|
3432
|
-
const normalized =
|
|
3468
|
+
const normalized = posix5.normalize(workDir);
|
|
3433
3469
|
if (normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
3434
3470
|
throw new Error(
|
|
3435
3471
|
"HarnessAgent: `sandboxConfig.workDir` must stay inside the sandbox default working directory."
|
|
@@ -3445,7 +3481,7 @@ function resolveSessionWorkDir({
|
|
|
3445
3481
|
}) {
|
|
3446
3482
|
return joinSandboxPath({
|
|
3447
3483
|
base: defaultWorkingDirectory,
|
|
3448
|
-
path: workDir != null ? workDir : `${harnessId}-${sessionId}`
|
|
3484
|
+
path: workDir != null ? workDir : `${encodeHarnessPathSegment(harnessId)}-${encodeHarnessPathSegment(sessionId)}`
|
|
3449
3485
|
});
|
|
3450
3486
|
}
|
|
3451
3487
|
async function createSandboxBootstrapPlan({
|
|
@@ -3488,20 +3524,30 @@ async function runSandboxBootstrap({
|
|
|
3488
3524
|
abortSignal
|
|
3489
3525
|
}) {
|
|
3490
3526
|
if (recipe == null && onBootstrap == null) return;
|
|
3491
|
-
const resolvedDefaultWorkingDirectory = defaultWorkingDirectory != null ? defaultWorkingDirectory : await resolveSandboxDefaultWorkingDirectory({
|
|
3492
|
-
sandboxSession: session,
|
|
3493
|
-
abortSignal
|
|
3494
|
-
});
|
|
3495
3527
|
if (recipe != null && recipeIdentity != null) {
|
|
3496
3528
|
await applyBootstrapRecipe({
|
|
3497
3529
|
session,
|
|
3498
3530
|
recipe,
|
|
3499
3531
|
identity: recipeIdentity,
|
|
3500
|
-
|
|
3532
|
+
// Harness infrastructure always lives under the sandbox's own HOME,
|
|
3533
|
+
// never the working directory resolved below for the caller's own
|
|
3534
|
+
// `onBootstrap` hook. Resolved directly from `session` — this runs
|
|
3535
|
+
// from a provider's `onFirstCreate`, before a
|
|
3536
|
+
// `HarnessV1NetworkSandboxSession` even exists.
|
|
3537
|
+
stateDirectory: harnessStateDirectoryPath({
|
|
3538
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
3539
|
+
sandbox: session,
|
|
3540
|
+
abortSignal
|
|
3541
|
+
})
|
|
3542
|
+
}),
|
|
3501
3543
|
abortSignal
|
|
3502
3544
|
});
|
|
3503
3545
|
}
|
|
3504
3546
|
if (onBootstrap == null) return;
|
|
3547
|
+
const resolvedDefaultWorkingDirectory = defaultWorkingDirectory != null ? defaultWorkingDirectory : await resolveSandboxDefaultWorkingDirectory({
|
|
3548
|
+
sandboxSession: session,
|
|
3549
|
+
abortSignal
|
|
3550
|
+
});
|
|
3505
3551
|
const bootstrapWorkDir = workDir == null ? resolvedDefaultWorkingDirectory : joinSandboxPath({
|
|
3506
3552
|
base: resolvedDefaultWorkingDirectory,
|
|
3507
3553
|
path: workDir
|
|
@@ -3561,9 +3607,9 @@ async function hashSandboxBootstrapIdentity({
|
|
|
3561
3607
|
}
|
|
3562
3608
|
function joinSandboxPath({
|
|
3563
3609
|
base,
|
|
3564
|
-
path
|
|
3610
|
+
path: path2
|
|
3565
3611
|
}) {
|
|
3566
|
-
return
|
|
3612
|
+
return posix5.join(base, path2);
|
|
3567
3613
|
}
|
|
3568
3614
|
|
|
3569
3615
|
// src/agent/internal/resolve-observability.ts
|
|
@@ -3829,7 +3875,14 @@ var HarnessAgent = class {
|
|
|
3829
3875
|
session: toolSafeSandboxSession,
|
|
3830
3876
|
recipe,
|
|
3831
3877
|
identity: recipeIdentity,
|
|
3832
|
-
|
|
3878
|
+
// Harness infrastructure always lives under the sandbox's own
|
|
3879
|
+
// HOME, never the session's working directory.
|
|
3880
|
+
stateDirectory: harnessStateDirectoryPath({
|
|
3881
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
3882
|
+
sandbox: toolSafeSandboxSession,
|
|
3883
|
+
abortSignal
|
|
3884
|
+
})
|
|
3885
|
+
}),
|
|
3833
3886
|
abortSignal
|
|
3834
3887
|
});
|
|
3835
3888
|
} catch (err) {
|
|
@@ -3872,7 +3925,14 @@ var HarnessAgent = class {
|
|
|
3872
3925
|
session: resumedSandboxSession.restricted(),
|
|
3873
3926
|
recipe,
|
|
3874
3927
|
identity: recipeIdentity,
|
|
3875
|
-
|
|
3928
|
+
// Harness infrastructure always lives under the sandbox's own
|
|
3929
|
+
// HOME, never the working directory.
|
|
3930
|
+
stateDirectory: harnessStateDirectoryPath({
|
|
3931
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
3932
|
+
sandbox: resumedSandboxSession,
|
|
3933
|
+
abortSignal
|
|
3934
|
+
})
|
|
3935
|
+
}),
|
|
3876
3936
|
abortSignal
|
|
3877
3937
|
});
|
|
3878
3938
|
} catch (err) {
|
|
@@ -3907,7 +3967,14 @@ var HarnessAgent = class {
|
|
|
3907
3967
|
session: createdSandboxSession.restricted(),
|
|
3908
3968
|
recipe: sandboxBootstrapPlan.recipe,
|
|
3909
3969
|
identity: sandboxBootstrapPlan.recipeIdentity,
|
|
3910
|
-
|
|
3970
|
+
// Harness infrastructure always lives under the sandbox's own
|
|
3971
|
+
// HOME, never the working directory.
|
|
3972
|
+
stateDirectory: harnessStateDirectoryPath({
|
|
3973
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
3974
|
+
sandbox: createdSandboxSession,
|
|
3975
|
+
abortSignal
|
|
3976
|
+
})
|
|
3977
|
+
}),
|
|
3911
3978
|
abortSignal
|
|
3912
3979
|
});
|
|
3913
3980
|
} catch (err) {
|
|
@@ -4147,7 +4214,6 @@ var HarnessAgent = class {
|
|
|
4147
4214
|
};
|
|
4148
4215
|
}
|
|
4149
4216
|
}
|
|
4150
|
-
return void 0;
|
|
4151
4217
|
}
|
|
4152
4218
|
/*
|
|
4153
4219
|
* Reduce AI SDK input to the single user message the harness should run
|
|
@@ -4451,11 +4517,19 @@ async function prepareHarnessSandboxTemplate(options) {
|
|
|
4451
4517
|
});
|
|
4452
4518
|
try {
|
|
4453
4519
|
if (bootstrapPlan.recipe != null && bootstrapPlan.recipeIdentity != null) {
|
|
4520
|
+
const restrictedSession = sandboxSession.restricted();
|
|
4454
4521
|
await applyBootstrapRecipe({
|
|
4455
|
-
session:
|
|
4522
|
+
session: restrictedSession,
|
|
4456
4523
|
recipe: bootstrapPlan.recipe,
|
|
4457
4524
|
identity: bootstrapPlan.recipeIdentity,
|
|
4458
|
-
|
|
4525
|
+
// Harness infrastructure always lives under the sandbox's own HOME,
|
|
4526
|
+
// never the working directory.
|
|
4527
|
+
stateDirectory: harnessStateDirectoryPath({
|
|
4528
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
4529
|
+
sandbox: restrictedSession,
|
|
4530
|
+
abortSignal
|
|
4531
|
+
})
|
|
4532
|
+
}),
|
|
4459
4533
|
abortSignal
|
|
4460
4534
|
});
|
|
4461
4535
|
}
|
|
@@ -4485,7 +4559,7 @@ async function prepareSandboxForHarness(options) {
|
|
|
4485
4559
|
const workDir = sandboxConfig.workDir == null ? void 0 : normalizeSandboxWorkDir(sandboxConfig.workDir);
|
|
4486
4560
|
const recipeIdentities = {};
|
|
4487
4561
|
const skippedHarnessIds = [];
|
|
4488
|
-
let
|
|
4562
|
+
let stateDirectory;
|
|
4489
4563
|
for (const harness of harnesses) {
|
|
4490
4564
|
const recipe = await ((_b4 = harness.getBootstrap) == null ? void 0 : _b4.call(harness, {
|
|
4491
4565
|
abortSignal: options.abortSignal
|
|
@@ -4496,19 +4570,24 @@ async function prepareSandboxForHarness(options) {
|
|
|
4496
4570
|
}
|
|
4497
4571
|
const recipeIdentity = await hashHarnessBootstrap(recipe);
|
|
4498
4572
|
recipeIdentities[harness.harnessId] = recipeIdentity;
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4573
|
+
stateDirectory != null ? stateDirectory : stateDirectory = harnessStateDirectoryPath({
|
|
4574
|
+
sandboxHomeDir: await resolveSandboxHomeDir({
|
|
4575
|
+
sandbox: options.session,
|
|
4576
|
+
abortSignal: options.abortSignal
|
|
4577
|
+
})
|
|
4502
4578
|
});
|
|
4503
4579
|
await applyBootstrapRecipe({
|
|
4504
4580
|
session: options.session,
|
|
4505
4581
|
recipe,
|
|
4506
4582
|
identity: recipeIdentity,
|
|
4507
|
-
|
|
4583
|
+
stateDirectory,
|
|
4508
4584
|
abortSignal: options.abortSignal
|
|
4509
4585
|
});
|
|
4510
4586
|
}
|
|
4511
4587
|
if (sandboxConfig.onBootstrap != null) {
|
|
4588
|
+
const defaultWorkingDirectory = await resolveSandboxDefaultWorkingDirectory(
|
|
4589
|
+
{ sandboxSession: options.session, abortSignal: options.abortSignal }
|
|
4590
|
+
);
|
|
4512
4591
|
await runSandboxBootstrap({
|
|
4513
4592
|
session: options.session,
|
|
4514
4593
|
workDir,
|
|
@@ -4604,7 +4683,7 @@ import { appendFileSync, mkdirSync } from "fs";
|
|
|
4604
4683
|
function createFileReporter(options) {
|
|
4605
4684
|
var _a4, _b4;
|
|
4606
4685
|
const fileName = (_a4 = options.fileName) != null ? _a4 : "events.jsonl";
|
|
4607
|
-
const
|
|
4686
|
+
const path2 = `${options.dir}/${fileName}`;
|
|
4608
4687
|
const failOnly = (_b4 = options.failOnly) != null ? _b4 : false;
|
|
4609
4688
|
const turns = /* @__PURE__ */ new Map();
|
|
4610
4689
|
let lastOpenCallId;
|
|
@@ -4632,7 +4711,7 @@ function createFileReporter(options) {
|
|
|
4632
4711
|
mkdirSync(options.dir, { recursive: true });
|
|
4633
4712
|
dirReady = true;
|
|
4634
4713
|
}
|
|
4635
|
-
appendFileSync(
|
|
4714
|
+
appendFileSync(path2, lines.map((l) => JSON.stringify(l)).join("\n") + "\n");
|
|
4636
4715
|
} catch (e) {
|
|
4637
4716
|
}
|
|
4638
4717
|
};
|