@ai-sdk/harness 1.0.123 → 1.0.126
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 +29 -0
- package/README.md +9 -8
- package/agent/index.ts +2 -0
- package/dist/agent/index.d.ts +31 -19
- package/dist/agent/index.js +484 -262
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +39 -17
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +7 -14
- package/dist/utils/index.js +63 -97
- package/dist/utils/index.js.map +1 -1
- package/package.json +4 -4
- package/src/agent/create-harness-sandbox-template.ts +80 -0
- package/src/agent/harness-agent-settings.ts +1 -0
- package/src/agent/harness-agent-types.ts +2 -0
- package/src/agent/harness-agent.ts +23 -0
- package/src/agent/internal/on-bootstrap-marker.ts +70 -0
- package/src/agent/internal/prepared-sandbox-identity.ts +42 -0
- package/src/agent/internal/run-prompt.ts +134 -19
- package/src/agent/internal/sandbox-bootstrap.ts +19 -0
- package/src/agent/internal/strip-work-dir.ts +57 -0
- package/src/agent/prepare-harness-sandbox-template.ts +5 -2
- package/src/agent/prepare-sandbox-for-harness.ts +7 -51
- package/src/v1/harness-v1-network-sandbox-session.ts +7 -14
- package/src/v1/harness-v1-sandbox-provider.ts +3 -2
- package/src/v1/harness-v1-sandbox-session-create-options.ts +14 -0
- package/src/v1/harness-v1-sandbox-session-resume-options.ts +10 -0
- package/src/v1/harness-v1-sandbox-template.ts +9 -0
- package/src/v1/index.ts +3 -0
|
@@ -25,8 +25,8 @@ type SandboxBootstrapSettings = Omit<HarnessAgentSandboxConfig, 'onSession'>;
|
|
|
25
25
|
*
|
|
26
26
|
* The temporary network sandbox session created during preparation is stopped
|
|
27
27
|
* before the function resolves; the snapshot/template state persists in the
|
|
28
|
-
* provider's native storage
|
|
29
|
-
*
|
|
28
|
+
* provider's native storage.
|
|
29
|
+
* @deprecated Use `createHarnessSandboxTemplate` and pass its template to a sandbox session creator instead.
|
|
30
30
|
*/
|
|
31
31
|
export async function prepareHarnessSandboxTemplate(options: {
|
|
32
32
|
readonly harness: HarnessAgentAdapter;
|
|
@@ -34,6 +34,9 @@ export async function prepareHarnessSandboxTemplate(options: {
|
|
|
34
34
|
readonly sandboxConfig?: SandboxBootstrapSettings;
|
|
35
35
|
readonly abortSignal?: AbortSignal;
|
|
36
36
|
}): Promise<void> {
|
|
37
|
+
console.warn(
|
|
38
|
+
'prepareHarnessSandboxTemplate (prewarmHarness) is deprecated. Use createHarnessSandboxTemplate and a sandbox session creator instead.',
|
|
39
|
+
);
|
|
37
40
|
const sandboxConfig = options.sandboxConfig ?? {};
|
|
38
41
|
validateSandboxBootstrapSettings(sandboxConfig);
|
|
39
42
|
|
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
runSandboxBootstrap,
|
|
14
14
|
validateSandboxBootstrapSettings,
|
|
15
15
|
} from './internal/sandbox-bootstrap';
|
|
16
|
+
import { resolvePreparedSandboxIdentity } from './internal/prepared-sandbox-identity';
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
/** @deprecated Use `createHarnessSandboxTemplate` and `template.prepare` instead. */
|
|
19
19
|
export type PrepareSandboxForHarnessResult = {
|
|
20
20
|
readonly identity?: string;
|
|
21
21
|
readonly recipeIdentities: Record<string, string>;
|
|
@@ -41,6 +41,7 @@ export type PrepareSandboxForHarnessResult = {
|
|
|
41
41
|
*
|
|
42
42
|
* Repeated harness IDs are prepared once. When multiple adapters use the same
|
|
43
43
|
* ID, the last adapter in `harnesses` is used.
|
|
44
|
+
* @deprecated Use `createHarnessSandboxTemplate` and `template.prepare` instead.
|
|
44
45
|
*/
|
|
45
46
|
export async function prepareSandboxForHarness(options: {
|
|
46
47
|
readonly session: SandboxSession;
|
|
@@ -48,6 +49,9 @@ export async function prepareSandboxForHarness(options: {
|
|
|
48
49
|
readonly sandboxConfig?: HarnessAgentSandboxConfig;
|
|
49
50
|
readonly abortSignal?: AbortSignal;
|
|
50
51
|
}): Promise<PrepareSandboxForHarnessResult> {
|
|
52
|
+
console.warn(
|
|
53
|
+
'prepareSandboxForHarness is deprecated. Use createHarnessSandboxTemplate and template.prepare instead.',
|
|
54
|
+
);
|
|
51
55
|
const sandboxConfig = options.sandboxConfig ?? {};
|
|
52
56
|
validateSandboxBootstrapSettings(sandboxConfig);
|
|
53
57
|
|
|
@@ -107,6 +111,7 @@ export async function prepareSandboxForHarness(options: {
|
|
|
107
111
|
session: options.session,
|
|
108
112
|
workDir,
|
|
109
113
|
onBootstrap: sandboxConfig.onBootstrap,
|
|
114
|
+
bootstrapHash: sandboxConfig.bootstrapHash,
|
|
110
115
|
defaultWorkingDirectory,
|
|
111
116
|
abortSignal: options.abortSignal,
|
|
112
117
|
});
|
|
@@ -124,52 +129,3 @@ export async function prepareSandboxForHarness(options: {
|
|
|
124
129
|
skippedHarnessIds,
|
|
125
130
|
};
|
|
126
131
|
}
|
|
127
|
-
|
|
128
|
-
async function resolvePreparedSandboxIdentity({
|
|
129
|
-
recipeIdentities,
|
|
130
|
-
bootstrapHash,
|
|
131
|
-
workDir,
|
|
132
|
-
}: {
|
|
133
|
-
readonly recipeIdentities: Record<string, string>;
|
|
134
|
-
readonly bootstrapHash?: string;
|
|
135
|
-
readonly workDir?: string;
|
|
136
|
-
}): Promise<string | undefined> {
|
|
137
|
-
const entries = Object.entries(recipeIdentities).sort(([a], [b]) =>
|
|
138
|
-
a.localeCompare(b),
|
|
139
|
-
);
|
|
140
|
-
if (entries.length === 0 && bootstrapHash == null) {
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const encoder = new TextEncoder();
|
|
145
|
-
const chunks: Uint8Array[] = [];
|
|
146
|
-
const pushString = (value: string) => {
|
|
147
|
-
chunks.push(encoder.encode(value));
|
|
148
|
-
chunks.push(encoder.encode('\0'));
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
pushString(String(PREPARED_SANDBOX_IDENTITY_VERSION));
|
|
152
|
-
pushString(workDir ?? '');
|
|
153
|
-
pushString(bootstrapHash ?? '');
|
|
154
|
-
|
|
155
|
-
for (const [harnessId, identity] of entries) {
|
|
156
|
-
pushString(harnessId);
|
|
157
|
-
pushString(identity);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
161
|
-
const buffer = new Uint8Array(totalLength);
|
|
162
|
-
let offset = 0;
|
|
163
|
-
for (const chunk of chunks) {
|
|
164
|
-
buffer.set(chunk, offset);
|
|
165
|
-
offset += chunk.length;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const digest = await crypto.subtle.digest('SHA-256', buffer);
|
|
169
|
-
const bytes = new Uint8Array(digest);
|
|
170
|
-
let hex = '';
|
|
171
|
-
for (let i = 0; i < 8; i++) {
|
|
172
|
-
hex += bytes[i].toString(16).padStart(2, '0');
|
|
173
|
-
}
|
|
174
|
-
return hex;
|
|
175
|
-
}
|
|
@@ -34,8 +34,8 @@ export function harnessStateDirectoryPath({
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Network sandbox session returned by
|
|
38
|
-
* harness keeps this for the lifetime of a session. It is itself a
|
|
37
|
+
* Network sandbox session returned by sandbox adapter creation and resume
|
|
38
|
+
* functions. The harness keeps this for the lifetime of a session. It is itself a
|
|
39
39
|
* {@link SandboxSession} (file I/O, exec, spawn) and adds the infra surface on
|
|
40
40
|
* top: port resolution, lifecycle, and network-policy mutation.
|
|
41
41
|
*
|
|
@@ -46,22 +46,15 @@ export function harnessStateDirectoryPath({
|
|
|
46
46
|
*/
|
|
47
47
|
export interface HarnessV1NetworkSandboxSession extends SandboxSession {
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
* harness session
|
|
51
|
-
* resume — the framework persists this on lifecycle state so a future
|
|
52
|
-
* process can call `HarnessV1SandboxProvider.resume?({ sessionId })` and
|
|
53
|
-
* reach the same resource. Providers populate it from their native
|
|
54
|
-
* identifier (Vercel: the sandbox name; just-bash: a UUID minted at
|
|
55
|
-
* create time).
|
|
49
|
+
* Identifier for the sandbox session. Persist this separately from the
|
|
50
|
+
* harness session ID and resume state when reattaching across processes.
|
|
56
51
|
*/
|
|
57
52
|
readonly id: string;
|
|
58
53
|
|
|
59
54
|
/**
|
|
60
55
|
* The sandbox's default working directory — the absolute path that
|
|
61
56
|
* `run`/`spawn` resolve relative commands against when no `workingDirectory`
|
|
62
|
-
* is given. Read from the live sandbox
|
|
63
|
-
* configurable at create time: Vercel defaults to `/vercel/sandbox`,
|
|
64
|
-
* just-bash to `/home/user`), never hardcoded.
|
|
57
|
+
* is given. Read from the live sandbox, never hardcoded.
|
|
65
58
|
*
|
|
66
59
|
* The framework composes each session's working directory underneath this
|
|
67
60
|
* path (`<defaultWorkingDirectory>/<harnessId>-<sessionId>`) so adapters do
|
|
@@ -105,7 +98,7 @@ export interface HarnessV1NetworkSandboxSession extends SandboxSession {
|
|
|
105
98
|
|
|
106
99
|
/**
|
|
107
100
|
* Update the sandbox's outbound network policy. Optional — implementations
|
|
108
|
-
* without a local enforcement primitive
|
|
101
|
+
* without a local enforcement primitive omit this. Callers
|
|
109
102
|
* use optional-call (`sandboxSession.setNetworkPolicy?.(policy)`); a
|
|
110
103
|
* missing implementation is a no-op.
|
|
111
104
|
*/
|
|
@@ -139,7 +132,7 @@ export interface HarnessV1NetworkSandboxSession extends SandboxSession {
|
|
|
139
132
|
/**
|
|
140
133
|
* Replace the set of ports exposed by the sandbox. Full-replacement
|
|
141
134
|
* semantics: ports omitted from the array are deregistered. Optional —
|
|
142
|
-
* implementations that cannot expose ports
|
|
135
|
+
* implementations that cannot expose ports omit this.
|
|
143
136
|
*/
|
|
144
137
|
readonly setPorts?: (
|
|
145
138
|
ports: ReadonlyArray<number>,
|
|
@@ -7,6 +7,7 @@ import type { HarnessV1NetworkSandboxSession } from './harness-v1-network-sandbo
|
|
|
7
7
|
* `LanguageModelV4` providers, no I/O performed at construction. The actual
|
|
8
8
|
* sandbox is created (or wrapped) when `HarnessAgent` calls `createSession()`.
|
|
9
9
|
*/
|
|
10
|
+
/** @deprecated Supply a sandbox session to `HarnessAgent.createSession()` instead. */
|
|
10
11
|
export interface HarnessV1SandboxProvider {
|
|
11
12
|
readonly specificationVersion: 'harness-sandbox-v1';
|
|
12
13
|
readonly providerId: string;
|
|
@@ -54,8 +55,8 @@ export interface HarnessV1SandboxProvider {
|
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
57
|
* Reattach to an existing sandbox previously created with the same
|
|
57
|
-
* `sessionId`. Optional — providers that cannot rehydrate by id
|
|
58
|
-
*
|
|
58
|
+
* `sessionId`. Optional — providers that cannot rehydrate by id omit
|
|
59
|
+
* this; the harness throws
|
|
59
60
|
* `HarnessCapabilityUnsupportedError` when resume is attempted against
|
|
60
61
|
* them.
|
|
61
62
|
*
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HarnessV1SandboxTemplate } from './harness-v1-sandbox-template';
|
|
2
|
+
|
|
3
|
+
export type HarnessV1SandboxSessionCreateOptions<
|
|
4
|
+
TProviderOptions extends object,
|
|
5
|
+
> = TProviderOptions & {
|
|
6
|
+
/**
|
|
7
|
+
* Manually assign the ID of a newly created sandbox session. Creation never
|
|
8
|
+
* looks up or resumes an existing session. An existing sandbox resource with
|
|
9
|
+
* the same ID is a creation conflict.
|
|
10
|
+
*/
|
|
11
|
+
readonly sandboxId?: string;
|
|
12
|
+
readonly template?: HarnessV1SandboxTemplate;
|
|
13
|
+
readonly abortSignal?: AbortSignal;
|
|
14
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type HarnessV1SandboxSessionResumeOptions<
|
|
2
|
+
TProviderOptions extends object,
|
|
3
|
+
> = TProviderOptions & {
|
|
4
|
+
/**
|
|
5
|
+
* ID of the existing sandbox session to reattach. Resume never creates a
|
|
6
|
+
* sandbox when the ID cannot be found.
|
|
7
|
+
*/
|
|
8
|
+
readonly sandboxId: string;
|
|
9
|
+
readonly abortSignal?: AbortSignal;
|
|
10
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Experimental_SandboxSession } from '@ai-sdk/provider-utils';
|
|
2
|
+
|
|
3
|
+
export type HarnessV1SandboxTemplate = {
|
|
4
|
+
readonly identity: string;
|
|
5
|
+
readonly prepare: (options: {
|
|
6
|
+
readonly session: Experimental_SandboxSession;
|
|
7
|
+
readonly abortSignal?: AbortSignal;
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
};
|
package/src/v1/index.ts
CHANGED
|
@@ -48,6 +48,9 @@ export type {
|
|
|
48
48
|
HarnessV1ResponseFormat,
|
|
49
49
|
} from './harness-v1-response-format';
|
|
50
50
|
export type { HarnessV1SandboxProvider } from './harness-v1-sandbox-provider';
|
|
51
|
+
export type { HarnessV1SandboxTemplate } from './harness-v1-sandbox-template';
|
|
52
|
+
export type { HarnessV1SandboxSessionCreateOptions } from './harness-v1-sandbox-session-create-options';
|
|
53
|
+
export type { HarnessV1SandboxSessionResumeOptions } from './harness-v1-sandbox-session-resume-options';
|
|
51
54
|
export type {
|
|
52
55
|
HarnessV1ContinueTurnState,
|
|
53
56
|
HarnessV1LifecycleState,
|