@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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # @ai-sdk/harness
2
2
 
3
+ ## 1.0.126
4
+
5
+ ### Patch Changes
6
+
7
+ - af9597b: Compile packages for ES2022 runtime target
8
+ - 31742b9: feat(harness): refactor sandbox APIs for cleaner separation of concerns from harness layer, more intuitive DX regardless of how your sandbox is configured, and streamlined handling of sandbox templates/snapshots
9
+ - Updated dependencies [af9597b]
10
+ - Updated dependencies [bc49f78]
11
+ - ai@7.0.116
12
+ - @ai-sdk/provider-utils@5.0.49
13
+
14
+ ## 1.0.125
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [be877ff]
19
+ - Updated dependencies [be877ff]
20
+ - @ai-sdk/provider-utils@5.0.48
21
+ - ai@7.0.115
22
+
23
+ ## 1.0.124
24
+
25
+ ### Patch Changes
26
+
27
+ - 40231b6: fix(harness): enforce tool input schemas at execution and consistently reject invalid inputs
28
+ - Updated dependencies [b5679a7]
29
+ - Updated dependencies [ca31b89]
30
+ - ai@7.0.114
31
+
3
32
  ## 1.0.123
4
33
 
5
34
  ### Patch Changes
package/README.md CHANGED
@@ -15,7 +15,7 @@ npm i ai zod @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel
15
15
  ```ts
16
16
  import { HarnessAgent } from '@ai-sdk/harness/agent';
17
17
  import { claudeCode } from '@ai-sdk/harness-claude-code';
18
- import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
18
+ import { createVercelNetworkSandboxSession } from '@ai-sdk/sandbox-vercel';
19
19
  import { tool } from 'ai';
20
20
  import { z } from 'zod/v4';
21
21
 
@@ -25,14 +25,10 @@ const agent = new HarnessAgent({
25
25
  model: 'claude-sonnet-4-5',
26
26
  instructions:
27
27
  'You are a careful refactoring assistant. Prefer minimal diffs.',
28
- sandbox: createVercelSandbox({
29
- runtime: 'node24',
30
- ports: [4000],
31
- }),
32
28
  sandboxConfig: {
33
29
  bootstrapHash: 'ripgrep-v1',
34
30
  onBootstrap: async ({ session, abortSignal }) => {
35
- const streamResult = await session.run({
31
+ const result = await session.run({
36
32
  command:
37
33
  'command -v rg >/dev/null || (apt-get update && apt-get install -y ripgrep)',
38
34
  abortSignal,
@@ -58,7 +54,12 @@ const agent = new HarnessAgent({
58
54
  },
59
55
  });
60
56
 
61
- const session = await agent.createSession();
57
+ const sandboxSession = await createVercelNetworkSandboxSession({
58
+ runtime: 'node24',
59
+ ports: [4000],
60
+ template: await agent.getSandboxTemplate(),
61
+ });
62
+ const session = await agent.createSession({ sandboxSession });
62
63
 
63
64
  try {
64
65
  const generateResult = await agent.generate({
@@ -79,6 +80,7 @@ try {
79
80
  }
80
81
  } finally {
81
82
  await session.destroy();
83
+ await sandboxSession.destroy();
82
84
  }
83
85
  ```
84
86
 
@@ -92,7 +94,6 @@ import { Output } from 'ai';
92
94
 
93
95
  const agent = new HarnessAgent({
94
96
  harness: claudeCode,
95
- sandbox,
96
97
  output: Output.object({
97
98
  schema: z.object({ answer: z.string() }),
98
99
  }),
package/agent/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { HarnessAgent } from '../src/agent/harness-agent';
2
+ export { createHarnessSandboxTemplate } from '../src/agent/create-harness-sandbox-template';
2
3
  export type { HarnessAllTools } from '../src/agent/harness-agent-tool-types';
3
4
  export type {
4
5
  HarnessAgentSandboxConfig,
@@ -26,6 +27,7 @@ export type {
26
27
  HarnessAgentStartOptions,
27
28
  HarnessAgentStreamPart,
28
29
  HarnessAgentToolSpec,
30
+ HarnessSandboxTemplate,
29
31
  } from '../src/agent/harness-agent-types';
30
32
  export { HarnessAgentSession } from '../src/agent/harness-agent-session';
31
33
  export { collectHarnessAgentToolApprovalContinuations } from '../src/agent/harness-agent-tool-approval-continuation';
@@ -58,8 +58,8 @@ type HarnessV1PortEndpoint = {
58
58
  readonly headers?: Readonly<Record<string, string>>;
59
59
  };
60
60
  /**
61
- * Network sandbox session returned by `HarnessV1SandboxProvider.createSession()`. The
62
- * harness keeps this for the lifetime of a session. It is itself a
61
+ * Network sandbox session returned by sandbox adapter creation and resume
62
+ * functions. The harness keeps this for the lifetime of a session. It is itself a
63
63
  * {@link SandboxSession} (file I/O, exec, spawn) and adds the infra surface on
64
64
  * top: port resolution, lifecycle, and network-policy mutation.
65
65
  *
@@ -70,21 +70,14 @@ type HarnessV1PortEndpoint = {
70
70
  */
71
71
  interface HarnessV1NetworkSandboxSession extends Experimental_SandboxSession {
72
72
  /**
73
- * Stable identifier for the underlying sandbox resource. Used by the
74
- * harness session manager as the durable lookup key for cross-process
75
- * resume — the framework persists this on lifecycle state so a future
76
- * process can call `HarnessV1SandboxProvider.resume?({ sessionId })` and
77
- * reach the same resource. Providers populate it from their native
78
- * identifier (Vercel: the sandbox name; just-bash: a UUID minted at
79
- * create time).
73
+ * Identifier for the sandbox session. Persist this separately from the
74
+ * harness session ID and resume state when reattaching across processes.
80
75
  */
81
76
  readonly id: string;
82
77
  /**
83
78
  * The sandbox's default working directory — the absolute path that
84
79
  * `run`/`spawn` resolve relative commands against when no `workingDirectory`
85
- * is given. Read from the live sandbox (it is provider-specific and
86
- * configurable at create time: Vercel defaults to `/vercel/sandbox`,
87
- * just-bash to `/home/user`), never hardcoded.
80
+ * is given. Read from the live sandbox, never hardcoded.
88
81
  *
89
82
  * The framework composes each session's working directory underneath this
90
83
  * path (`<defaultWorkingDirectory>/<harnessId>-<sessionId>`) so adapters do
@@ -122,7 +115,7 @@ interface HarnessV1NetworkSandboxSession extends Experimental_SandboxSession {
122
115
  readonly destroy: () => PromiseLike<void>;
123
116
  /**
124
117
  * Update the sandbox's outbound network policy. Optional — implementations
125
- * without a local enforcement primitive (e.g. just-bash) omit this. Callers
118
+ * without a local enforcement primitive omit this. Callers
126
119
  * use optional-call (`sandboxSession.setNetworkPolicy?.(policy)`); a
127
120
  * missing implementation is a no-op.
128
121
  */
@@ -147,7 +140,7 @@ interface HarnessV1NetworkSandboxSession extends Experimental_SandboxSession {
147
140
  /**
148
141
  * Replace the set of ports exposed by the sandbox. Full-replacement
149
142
  * semantics: ports omitted from the array are deregistered. Optional —
150
- * implementations that cannot expose ports (e.g. just-bash) omit this.
143
+ * implementations that cannot expose ports omit this.
151
144
  */
152
145
  readonly setPorts?: (ports: ReadonlyArray<number>, options?: {
153
146
  abortSignal?: AbortSignal;
@@ -1095,6 +1088,7 @@ type HarnessV1BuiltinTool<INPUT = unknown, OUTPUT = unknown> = Tool<INPUT, OUTPU
1095
1088
  * `LanguageModelV4` providers, no I/O performed at construction. The actual
1096
1089
  * sandbox is created (or wrapped) when `HarnessAgent` calls `createSession()`.
1097
1090
  */
1091
+ /** @deprecated Supply a sandbox session to `HarnessAgent.createSession()` instead. */
1098
1092
  interface HarnessV1SandboxProvider {
1099
1093
  readonly specificationVersion: 'harness-sandbox-v1';
1100
1094
  readonly providerId: string;
@@ -1139,8 +1133,8 @@ interface HarnessV1SandboxProvider {
1139
1133
  }) => PromiseLike<HarnessV1NetworkSandboxSession>;
1140
1134
  /**
1141
1135
  * Reattach to an existing sandbox previously created with the same
1142
- * `sessionId`. Optional — providers that cannot rehydrate by id (e.g.
1143
- * just-bash) omit this; the harness throws
1136
+ * `sessionId`. Optional — providers that cannot rehydrate by id omit
1137
+ * this; the harness throws
1144
1138
  * `HarnessCapabilityUnsupportedError` when resume is attempted against
1145
1139
  * them.
1146
1140
  *
@@ -1154,6 +1148,14 @@ interface HarnessV1SandboxProvider {
1154
1148
  }) => PromiseLike<HarnessV1NetworkSandboxSession>;
1155
1149
  }
1156
1150
 
1151
+ type HarnessV1SandboxTemplate = {
1152
+ readonly identity: string;
1153
+ readonly prepare: (options: {
1154
+ readonly session: Experimental_SandboxSession;
1155
+ readonly abortSignal?: AbortSignal;
1156
+ }) => Promise<void>;
1157
+ };
1158
+
1157
1159
  /** Severity of a diagnostic. */
1158
1160
  type HarnessDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';
1159
1161
  /**
@@ -1224,6 +1226,7 @@ interface HarnessDiagnosticConsumer {
1224
1226
  }
1225
1227
 
1226
1228
  type HarnessAgentAdapter<TBuiltinTools extends ToolSet = ToolSet> = HarnessV1<TBuiltinTools>;
1229
+ type HarnessSandboxTemplate = HarnessV1SandboxTemplate;
1227
1230
  type HarnessAgentBuiltinTool<INPUT = unknown, OUTPUT = unknown> = HarnessV1BuiltinTool<INPUT, OUTPUT>;
1228
1231
  type HarnessAgentBuiltinToolName = HarnessV1BuiltinToolName;
1229
1232
  type HarnessAgentBuiltinToolUseKind = HarnessV1BuiltinToolUseKind;
@@ -1462,6 +1465,7 @@ type HarnessAgentSettings<THarness extends HarnessAgentAdapter<any> = HarnessAge
1462
1465
  * sessions. When omitted, every `createSession()` call must provide an
1463
1466
  * existing network sandbox session.
1464
1467
  */
1468
+ /** @deprecated Supply `sandboxSession` to `HarnessAgent.createSession()` instead. */
1465
1469
  readonly sandbox?: HarnessV1SandboxProvider;
1466
1470
  /**
1467
1471
  * Sandbox working-directory and lifecycle hook configuration.
@@ -1743,6 +1747,7 @@ declare class HarnessAgent<THarness extends HarnessAgentAdapter<any> = HarnessAg
1743
1747
  get harnessId(): string;
1744
1748
  /** Whether this agent parses completed turns with its configured output. */
1745
1749
  get hasOutput(): boolean;
1750
+ getSandboxTemplate(): Promise<HarnessSandboxTemplate | undefined>;
1746
1751
  /**
1747
1752
  * Start a fresh session, or resume from state previously returned by
1748
1753
  * `session.detach()` or `session.stop()`. The returned
@@ -1837,6 +1842,11 @@ declare class HarnessAgent<THarness extends HarnessAgentAdapter<any> = HarnessAg
1837
1842
  private _resolveResponseFormat;
1838
1843
  }
1839
1844
 
1845
+ declare function createHarnessSandboxTemplate(options: {
1846
+ readonly harnesses: ReadonlyArray<HarnessAgentAdapter>;
1847
+ readonly sandboxConfig?: Omit<HarnessAgentSandboxConfig, 'onSession'>;
1848
+ }): Promise<HarnessSandboxTemplate | undefined>;
1849
+
1840
1850
  /**
1841
1851
  * Extract approval decisions that should continue a suspended harness turn.
1842
1852
  *
@@ -1870,8 +1880,8 @@ type SandboxBootstrapSettings = Omit<HarnessAgentSandboxConfig, 'onSession'>;
1870
1880
  *
1871
1881
  * The temporary network sandbox session created during preparation is stopped
1872
1882
  * before the function resolves; the snapshot/template state persists in the
1873
- * provider's native storage (for Vercel: as the `currentSnapshotId` of the
1874
- * named template sandbox).
1883
+ * provider's native storage.
1884
+ * @deprecated Use `createHarnessSandboxTemplate` and pass its template to a sandbox session creator instead.
1875
1885
  */
1876
1886
  declare function prepareHarnessSandboxTemplate(options: {
1877
1887
  readonly harness: HarnessAgentAdapter;
@@ -1882,6 +1892,7 @@ declare function prepareHarnessSandboxTemplate(options: {
1882
1892
  /** @deprecated Use `prepareHarnessSandboxTemplate` instead. */
1883
1893
  declare const prewarmHarness: typeof prepareHarnessSandboxTemplate;
1884
1894
 
1895
+ /** @deprecated Use `createHarnessSandboxTemplate` and `template.prepare` instead. */
1885
1896
  type PrepareSandboxForHarnessResult = {
1886
1897
  readonly identity?: string;
1887
1898
  readonly recipeIdentities: Record<string, string>;
@@ -1906,6 +1917,7 @@ type PrepareSandboxForHarnessResult = {
1906
1917
  *
1907
1918
  * Repeated harness IDs are prepared once. When multiple adapters use the same
1908
1919
  * ID, the last adapter in `harnesses` is used.
1920
+ * @deprecated Use `createHarnessSandboxTemplate` and `template.prepare` instead.
1909
1921
  */
1910
1922
  declare function prepareSandboxForHarness(options: {
1911
1923
  readonly session: Experimental_SandboxSession;
@@ -2015,4 +2027,4 @@ interface TraceTreeReporterOptions {
2015
2027
  }
2016
2028
  declare function createTraceTreeReporter(options?: TraceTreeReporterOptions): Telemetry;
2017
2029
 
2018
- export { type FileReporter, type FileReporterOptions, HarnessAgent, type HarnessAgentAdapter, type HarnessAgentAdapterSession, type HarnessAgentBuiltinTool, type HarnessAgentBuiltinToolName, type HarnessAgentBuiltinToolUseKind, type HarnessAgentBuiltinTools, type HarnessAgentContinueTurnOptions, type HarnessAgentContinueTurnState, type HarnessAgentLifecycleState, type HarnessAgentPendingToolApproval, type HarnessAgentPendingToolResult, type HarnessAgentPermissionMode, type HarnessAgentPrompt, type HarnessAgentPromptControl, type HarnessAgentPromptTurnOptions, type HarnessAgentResumeSessionState, type HarnessAgentSandboxConfig, HarnessAgentSession, type HarnessAgentSettings, type HarnessAgentSkill, type HarnessAgentStartOptions, type HarnessAgentStreamPart, type HarnessAgentToolApprovalConfiguration, type HarnessAgentToolSpec, type HarnessAllTools, HarnessCapabilityUnsupportedError, type HarnessDebugConfig, type HarnessDebugLevel, type HarnessDiagnostic, type HarnessDiagnosticConsumer, HarnessError, HarnessSandboxAuthenticationError, type PrepareSandboxForHarnessResult, type TraceTreeReporterOptions, collectHarnessAgentToolApprovalContinuations, collectHarnessAgentToolResultContinuations, createFileReporter, createTraceTreeReporter, getHarnessErrorMessage, prepareHarnessSandboxTemplate, prepareSandboxForHarness, prewarmHarness };
2030
+ export { type FileReporter, type FileReporterOptions, HarnessAgent, type HarnessAgentAdapter, type HarnessAgentAdapterSession, type HarnessAgentBuiltinTool, type HarnessAgentBuiltinToolName, type HarnessAgentBuiltinToolUseKind, type HarnessAgentBuiltinTools, type HarnessAgentContinueTurnOptions, type HarnessAgentContinueTurnState, type HarnessAgentLifecycleState, type HarnessAgentPendingToolApproval, type HarnessAgentPendingToolResult, type HarnessAgentPermissionMode, type HarnessAgentPrompt, type HarnessAgentPromptControl, type HarnessAgentPromptTurnOptions, type HarnessAgentResumeSessionState, type HarnessAgentSandboxConfig, HarnessAgentSession, type HarnessAgentSettings, type HarnessAgentSkill, type HarnessAgentStartOptions, type HarnessAgentStreamPart, type HarnessAgentToolApprovalConfiguration, type HarnessAgentToolSpec, type HarnessAllTools, HarnessCapabilityUnsupportedError, type HarnessDebugConfig, type HarnessDebugLevel, type HarnessDiagnostic, type HarnessDiagnosticConsumer, HarnessError, HarnessSandboxAuthenticationError, type HarnessSandboxTemplate, type PrepareSandboxForHarnessResult, type TraceTreeReporterOptions, collectHarnessAgentToolApprovalContinuations, collectHarnessAgentToolResultContinuations, createFileReporter, createHarnessSandboxTemplate, createTraceTreeReporter, getHarnessErrorMessage, prepareHarnessSandboxTemplate, prepareSandboxForHarness, prewarmHarness };