@ai-sdk/harness 1.0.119 → 1.0.120
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 +6 -0
- package/README.md +4 -108
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -99,112 +99,8 @@ const agent = new HarnessAgent({
|
|
|
99
99
|
});
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
## Documentation
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`sandbox` is an optional `HarnessV1SandboxProvider`. When omitted, pass a `HarnessV1NetworkSandboxSession` to every `agent.createSession({ sandboxSession })` call. Use `sandboxConfig` for agent specific sandbox configuration that works independently from the sandbox provider that is used:
|
|
108
|
-
|
|
109
|
-
- Use `sandboxConfig.onSession` to prepare the acquired sandbox before the harness adapter starts. The hook runs for fresh and resumed sessions, so keep it idempotent.
|
|
110
|
-
- Use `sandboxConfig.onBootstrap` for expensive sandbox setup that should be baked into a reusable snapshot, such as installing tools or cloning a large repository. Provide `sandboxConfig.bootstrapHash` with it and change that value whenever the bootstrap output should invalidate the cached snapshot.
|
|
111
|
-
- Use `sandboxConfig.workDir` to set a stable working directory for the agent, relative to the sandbox's default working directory; otherwise regular sessions use the existing `<harnessId>-<sessionId>` directory. In that case, the `onBootstrap` callback receives the sandbox's default working directory.
|
|
112
|
-
|
|
113
|
-
Use `prepareHarnessSandboxTemplate()` to create or refresh the sandbox provider's
|
|
114
|
-
own reusable template for one harness before serving traffic. This is the
|
|
115
|
-
replacement for `prewarmHarness()`, which remains as a deprecated alias.
|
|
116
|
-
|
|
117
|
-
Use `prepareSandboxForHarness()` when you own an existing sandbox and want to
|
|
118
|
-
prepare it before creating your own snapshot. It applies the selected harness
|
|
119
|
-
bootstrap recipes and `sandboxConfig.onBootstrap`, returns the computed
|
|
120
|
-
preparation identity and per-harness recipe identities, and leaves snapshotting
|
|
121
|
-
or stopping the sandbox to your code. Later, create a sandbox from that snapshot
|
|
122
|
-
and pass the native sandbox object to `createVercelSandbox({ sandbox })` for the
|
|
123
|
-
`HarnessAgent`. When several bridge-backed harnesses share a caller-provided
|
|
124
|
-
sandbox, create that sandbox with one exposed port for each harness. Then pass
|
|
125
|
-
each harness's assigned port to that harness's `create*` function.
|
|
126
|
-
|
|
127
|
-
### Available harnesses
|
|
128
|
-
|
|
129
|
-
See the [harness adapters documentation](https://ai-sdk.dev/v7/docs/ai-sdk-harnesses/harness-adapters).
|
|
130
|
-
|
|
131
|
-
## Implementing a harness
|
|
132
|
-
|
|
133
|
-
Implement the `HarnessV1` factory and a `HarnessV1Session` whose `doPromptTurn` emits events; the agent surface, streaming, tool execution, and multi-turn state are handled for you. Read `startOpts.model` for the consumer-selected model and `startOpts.sandboxSession` for the selected network sandbox session. The harness layer stops or destroys sessions it acquires from the provider, while a session passed to `agent.createSession({ sandboxSession })` remains caller-owned. Call `sandboxSession.restricted()` for the tool-safe file-IO/exec/spawn surface.
|
|
134
|
-
|
|
135
|
-
Each prompt and continuation receives an optional `responseFormat`. JSON
|
|
136
|
-
formats carry a caller-provided JSON Schema plus optional name and description;
|
|
137
|
-
the adapter must enforce the schema and emit the resulting JSON through normal
|
|
138
|
-
text parts. If the runtime cannot honor the format, throw
|
|
139
|
-
`HarnessCapabilityUnsupportedError` before starting the turn.
|
|
140
|
-
|
|
141
|
-
Bootstrap recipe paths may be absolute or relative. Relative `bootstrapDir` and
|
|
142
|
-
file paths are resolved against `sandboxSession.defaultWorkingDirectory`.
|
|
143
|
-
The framework creates `bootstrapDir` before writing files, and bootstrap
|
|
144
|
-
commands always run from that directory. Prefer a relative directory such as
|
|
145
|
-
`.harness-bootstrap/my-harness` so bootstrap assets are kept with the sandbox's
|
|
146
|
-
snapshot-persistent working tree.
|
|
147
|
-
|
|
148
|
-
```ts
|
|
149
|
-
import type { HarnessV1, HarnessV1Session } from '@ai-sdk/harness';
|
|
150
|
-
|
|
151
|
-
export function myHarness(): HarnessV1 {
|
|
152
|
-
return {
|
|
153
|
-
specificationVersion: 'harness-v1',
|
|
154
|
-
harnessId: 'my-harness',
|
|
155
|
-
builtinTools: {},
|
|
156
|
-
doStart: async startOpts => {
|
|
157
|
-
const usage = {
|
|
158
|
-
inputTokens: { total: 0, noCache: 0 },
|
|
159
|
-
outputTokens: { total: 0, text: 0 },
|
|
160
|
-
};
|
|
161
|
-
const resumeState = {
|
|
162
|
-
type: 'resume-session' as const,
|
|
163
|
-
harnessId: 'my-harness',
|
|
164
|
-
specificationVersion: 'harness-v1' as const,
|
|
165
|
-
data: {},
|
|
166
|
-
};
|
|
167
|
-
const continueState = {
|
|
168
|
-
type: 'continue-turn' as const,
|
|
169
|
-
harnessId: 'my-harness',
|
|
170
|
-
specificationVersion: 'harness-v1' as const,
|
|
171
|
-
data: {},
|
|
172
|
-
};
|
|
173
|
-
const session: HarnessV1Session = {
|
|
174
|
-
sessionId: startOpts.sessionId,
|
|
175
|
-
isResume:
|
|
176
|
-
startOpts.resumeFrom != null || startOpts.continueFrom != null,
|
|
177
|
-
doPromptTurn: async promptOpts => {
|
|
178
|
-
const done = Promise.resolve().then(() => {
|
|
179
|
-
promptOpts.emit({ type: 'text-start', id: 't' });
|
|
180
|
-
promptOpts.emit({ type: 'text-delta', id: 't', delta: 'Hello.' });
|
|
181
|
-
promptOpts.emit({ type: 'text-end', id: 't' });
|
|
182
|
-
promptOpts.emit({
|
|
183
|
-
type: 'finish',
|
|
184
|
-
finishReason: { unified: 'stop', raw: 'stop' },
|
|
185
|
-
totalUsage: usage,
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
return { submitToolResult: async () => {}, done };
|
|
189
|
-
},
|
|
190
|
-
doContinueTurn: async continueOpts => {
|
|
191
|
-
const done = Promise.resolve().then(() => {
|
|
192
|
-
continueOpts.emit({
|
|
193
|
-
type: 'finish',
|
|
194
|
-
finishReason: { unified: 'stop', raw: 'stop' },
|
|
195
|
-
totalUsage: usage,
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
return { submitToolResult: async () => {}, done };
|
|
199
|
-
},
|
|
200
|
-
doCompact: async () => {},
|
|
201
|
-
doDetach: async () => resumeState,
|
|
202
|
-
doStop: async () => resumeState,
|
|
203
|
-
doDestroy: async () => {},
|
|
204
|
-
doSuspendTurn: async () => continueState,
|
|
205
|
-
};
|
|
206
|
-
return session;
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
```
|
|
104
|
+
- [Detailed usage documentation](https://ai-sdk.dev/docs/ai-sdk-harnesses)
|
|
105
|
+
- [Harness abstraction architecture](https://github.com/vercel/ai/blob/main/architecture/harness-abstraction.md)
|
|
106
|
+
- [Sandbox abstraction architecture](https://github.com/vercel/ai/blob/main/architecture/sandbox-abstraction.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.120",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@ai-sdk/provider": "4.0.17",
|
|
48
48
|
"@ai-sdk/provider-utils": "5.0.45",
|
|
49
|
-
"ai": "7.0.
|
|
49
|
+
"ai": "7.0.110"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"ws": "^8.21.0",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@ai-sdk/otel": "1.0.
|
|
61
|
+
"@ai-sdk/otel": "1.0.110",
|
|
62
62
|
"@opentelemetry/sdk-trace-base": "2.7.1",
|
|
63
63
|
"@types/node": "22.19.19",
|
|
64
64
|
"@types/ws": "^8.5.13",
|