@ai-sdk/harness 1.0.92 → 1.0.93
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 +15 -0
- package/README.md +5 -1
- package/dist/agent/index.d.ts +155 -110
- package/dist/agent/index.js +292 -99
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.d.ts +20 -1
- package/dist/bridge/index.js +29 -5
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +100 -94
- package/dist/utils/index.d.ts +8 -2
- package/dist/utils/index.js +313 -33
- package/dist/utils/index.js.map +1 -1
- package/package.json +4 -4
- package/src/agent/harness-agent-session.ts +107 -7
- package/src/agent/harness-agent-settings.ts +86 -7
- package/src/agent/harness-agent.ts +322 -112
- package/src/agent/internal/lifecycle-state-validation.ts +3 -0
- package/src/agent/internal/run-prompt.ts +16 -6
- package/src/bridge/index.ts +73 -6
- package/src/utils/index.ts +1 -0
- package/src/utils/write-skills.ts +419 -32
- package/src/v1/harness-v1-lifecycle-state.ts +38 -0
- package/src/v1/harness-v1-session.ts +9 -40
- package/src/v1/index.ts +1 -0
|
@@ -15,6 +15,8 @@ import type {
|
|
|
15
15
|
HarnessV1NetworkSandboxSession,
|
|
16
16
|
HarnessV1PromptControl,
|
|
17
17
|
HarnessV1ResponseFormat,
|
|
18
|
+
HarnessV1Skill,
|
|
19
|
+
HarnessV1TurnSettings,
|
|
18
20
|
} from '../v1';
|
|
19
21
|
import { HarnessCapabilityUnsupportedError } from '../errors/harness-capability-unsupported-error';
|
|
20
22
|
import type {
|
|
@@ -40,6 +42,7 @@ type HarnessAgentTurnResult<
|
|
|
40
42
|
> = {
|
|
41
43
|
result: StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
42
44
|
done: Promise<void>;
|
|
45
|
+
ready: Promise<void>;
|
|
43
46
|
};
|
|
44
47
|
|
|
45
48
|
type HarnessAgentSessionState = 'active' | 'detached' | 'stopped' | 'destroyed';
|
|
@@ -58,6 +61,13 @@ type ActivePromptControl = {
|
|
|
58
61
|
settled: boolean;
|
|
59
62
|
};
|
|
60
63
|
|
|
64
|
+
type ActiveTurnSettings = {
|
|
65
|
+
readonly persisted: HarnessV1TurnSettings;
|
|
66
|
+
readonly tools: ToolSet;
|
|
67
|
+
readonly activeTools: ToolSet;
|
|
68
|
+
readonly builtinToolFiltering: HarnessV1BuiltinToolFiltering | undefined;
|
|
69
|
+
};
|
|
70
|
+
|
|
61
71
|
/**
|
|
62
72
|
* Live harness session held by the caller.
|
|
63
73
|
*
|
|
@@ -105,6 +115,8 @@ export class HarnessAgentSession {
|
|
|
105
115
|
private suspendedTurnState:
|
|
106
116
|
| Promise<HarnessAgentContinueTurnState>
|
|
107
117
|
| undefined;
|
|
118
|
+
private activeTurnSettings: ActiveTurnSettings | undefined;
|
|
119
|
+
private persistedTurnSettings: HarnessV1TurnSettings | undefined;
|
|
108
120
|
|
|
109
121
|
/**
|
|
110
122
|
* Whether this session was created from `resumeFrom` or `continueFrom`.
|
|
@@ -122,6 +134,7 @@ export class HarnessAgentSession {
|
|
|
122
134
|
toolApproval: HarnessAgentToolApprovalConfiguration | undefined;
|
|
123
135
|
pendingToolApprovals?: readonly HarnessAgentPendingToolApproval[];
|
|
124
136
|
pendingToolResults?: readonly HarnessAgentPendingToolResult[];
|
|
137
|
+
turnSettings?: HarnessV1TurnSettings;
|
|
125
138
|
turnState?: HarnessAgentTurnState;
|
|
126
139
|
}) {
|
|
127
140
|
this.sessionId = options.sessionId;
|
|
@@ -137,6 +150,7 @@ export class HarnessAgentSession {
|
|
|
137
150
|
for (const pendingResult of options.pendingToolResults ?? []) {
|
|
138
151
|
this.pendingToolResults.set(pendingResult.toolCallId, pendingResult);
|
|
139
152
|
}
|
|
153
|
+
this.persistedTurnSettings = options.turnSettings;
|
|
140
154
|
this.turnState =
|
|
141
155
|
options.turnState ??
|
|
142
156
|
(this.pendingToolApprovals.size > 0
|
|
@@ -181,6 +195,7 @@ export class HarnessAgentSession {
|
|
|
181
195
|
OUTPUT extends Output,
|
|
182
196
|
>(options: {
|
|
183
197
|
prompt: HarnessAgentPrompt;
|
|
198
|
+
skills: ReadonlyArray<HarnessV1Skill>;
|
|
184
199
|
instructions: string | undefined;
|
|
185
200
|
tools: TOOLS;
|
|
186
201
|
activeTools: ToolSet;
|
|
@@ -195,6 +210,19 @@ export class HarnessAgentSession {
|
|
|
195
210
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
196
211
|
const session = this.requireReusableSession();
|
|
197
212
|
this.requirePromptableTurn();
|
|
213
|
+
this.persistedTurnSettings = {
|
|
214
|
+
skills: options.skills,
|
|
215
|
+
...(options.instructions == null
|
|
216
|
+
? {}
|
|
217
|
+
: { instructions: options.instructions }),
|
|
218
|
+
tools: options.toolSpecs,
|
|
219
|
+
};
|
|
220
|
+
this.activeTurnSettings = {
|
|
221
|
+
persisted: this.persistedTurnSettings,
|
|
222
|
+
tools: options.tools,
|
|
223
|
+
activeTools: options.activeTools,
|
|
224
|
+
builtinToolFiltering: options.builtinToolFiltering,
|
|
225
|
+
};
|
|
198
226
|
const sandboxSession = this.getSandboxSession();
|
|
199
227
|
const turnId = this.startTrackedTurn();
|
|
200
228
|
try {
|
|
@@ -202,6 +230,7 @@ export class HarnessAgentSession {
|
|
|
202
230
|
harness: this.harness,
|
|
203
231
|
session,
|
|
204
232
|
prompt: options.prompt,
|
|
233
|
+
skills: options.skills,
|
|
205
234
|
instructions: options.instructions,
|
|
206
235
|
tools: options.tools,
|
|
207
236
|
activeTools: options.activeTools,
|
|
@@ -246,7 +275,10 @@ export class HarnessAgentSession {
|
|
|
246
275
|
onStopConditionMet: () =>
|
|
247
276
|
this.captureStopConditionBoundary({ session, turnId }),
|
|
248
277
|
});
|
|
249
|
-
return
|
|
278
|
+
return {
|
|
279
|
+
...turn,
|
|
280
|
+
ready: this.waitForPromptControl({ turnId }),
|
|
281
|
+
};
|
|
250
282
|
} catch (error) {
|
|
251
283
|
this.finishTrackedTurn({ turnId });
|
|
252
284
|
throw error;
|
|
@@ -258,6 +290,7 @@ export class HarnessAgentSession {
|
|
|
258
290
|
RUNTIME_CONTEXT extends Context,
|
|
259
291
|
OUTPUT extends Output,
|
|
260
292
|
>(options: {
|
|
293
|
+
skills: ReadonlyArray<HarnessV1Skill>;
|
|
261
294
|
instructions: string | undefined;
|
|
262
295
|
tools: TOOLS;
|
|
263
296
|
activeTools: ToolSet;
|
|
@@ -278,6 +311,14 @@ export class HarnessAgentSession {
|
|
|
278
311
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
279
312
|
const session = this.requireReusableSession();
|
|
280
313
|
this.requireContinuableTurn();
|
|
314
|
+
const turnSettings = this.resolveActiveTurnSettings({
|
|
315
|
+
skills: options.skills,
|
|
316
|
+
instructions: options.instructions,
|
|
317
|
+
tools: options.tools,
|
|
318
|
+
activeTools: options.activeTools,
|
|
319
|
+
toolSpecs: options.toolSpecs,
|
|
320
|
+
builtinToolFiltering: options.builtinToolFiltering,
|
|
321
|
+
});
|
|
281
322
|
const sandboxSession = this.getSandboxSession();
|
|
282
323
|
const turnId = this.startTrackedTurn();
|
|
283
324
|
try {
|
|
@@ -285,11 +326,12 @@ export class HarnessAgentSession {
|
|
|
285
326
|
harness: this.harness,
|
|
286
327
|
session,
|
|
287
328
|
mode: 'continue',
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
329
|
+
skills: turnSettings.persisted.skills,
|
|
330
|
+
instructions: turnSettings.persisted.instructions,
|
|
331
|
+
tools: turnSettings.tools as TOOLS,
|
|
332
|
+
activeTools: turnSettings.activeTools,
|
|
333
|
+
toolSpecs: [...turnSettings.persisted.tools],
|
|
334
|
+
builtinToolFiltering: turnSettings.builtinToolFiltering,
|
|
293
335
|
sandboxSession: getRestrictedSandboxSession(sandboxSession),
|
|
294
336
|
sessionWorkDir: this.sessionWorkDir,
|
|
295
337
|
runtimeContext: options.runtimeContext,
|
|
@@ -331,7 +373,10 @@ export class HarnessAgentSession {
|
|
|
331
373
|
onStopConditionMet: () =>
|
|
332
374
|
this.captureStopConditionBoundary({ session, turnId }),
|
|
333
375
|
});
|
|
334
|
-
return
|
|
376
|
+
return {
|
|
377
|
+
...turn,
|
|
378
|
+
ready: this.waitForPromptControl({ turnId }),
|
|
379
|
+
};
|
|
335
380
|
} catch (error) {
|
|
336
381
|
this.finishTrackedTurn({ turnId });
|
|
337
382
|
throw error;
|
|
@@ -521,6 +566,7 @@ export class HarnessAgentSession {
|
|
|
521
566
|
private addPendingToolState(
|
|
522
567
|
state: HarnessAgentContinueTurnState,
|
|
523
568
|
): HarnessAgentContinueTurnState {
|
|
569
|
+
const turnSettings = this.persistedTurnSettings;
|
|
524
570
|
const pendingToolApprovals = this.getPendingToolApprovals();
|
|
525
571
|
const pendingToolResults = this.getPendingToolResults();
|
|
526
572
|
if (pendingToolApprovals.length === 0 && pendingToolResults.length === 0) {
|
|
@@ -529,10 +575,12 @@ export class HarnessAgentSession {
|
|
|
529
575
|
harnessId: state.harnessId,
|
|
530
576
|
specificationVersion: state.specificationVersion,
|
|
531
577
|
data: state.data,
|
|
578
|
+
...(turnSettings == null ? {} : { turnSettings }),
|
|
532
579
|
};
|
|
533
580
|
}
|
|
534
581
|
return {
|
|
535
582
|
...state,
|
|
583
|
+
...(turnSettings == null ? {} : { turnSettings }),
|
|
536
584
|
...(pendingToolApprovals.length > 0 ? { pendingToolApprovals } : {}),
|
|
537
585
|
...(pendingToolResults.length > 0 ? { pendingToolResults } : {}),
|
|
538
586
|
};
|
|
@@ -663,6 +711,14 @@ export class HarnessAgentSession {
|
|
|
663
711
|
this.settleActivePromptControl(options.control);
|
|
664
712
|
}
|
|
665
713
|
|
|
714
|
+
private async waitForPromptControl(options: {
|
|
715
|
+
turnId: number;
|
|
716
|
+
}): Promise<void> {
|
|
717
|
+
const activePromptControl = this.activePromptControl;
|
|
718
|
+
if (activePromptControl?.turnId !== options.turnId) return;
|
|
719
|
+
await activePromptControl.promise;
|
|
720
|
+
}
|
|
721
|
+
|
|
666
722
|
private settleActivePromptControl(
|
|
667
723
|
control: HarnessV1PromptControl | undefined,
|
|
668
724
|
): void {
|
|
@@ -691,9 +747,53 @@ export class HarnessAgentSession {
|
|
|
691
747
|
this.pendingToolApprovals.clear();
|
|
692
748
|
this.pendingToolResults.clear();
|
|
693
749
|
this.suspendedTurnState = undefined;
|
|
750
|
+
this.activeTurnSettings = undefined;
|
|
751
|
+
this.persistedTurnSettings = undefined;
|
|
694
752
|
this.turnState = 'idle';
|
|
695
753
|
}
|
|
696
754
|
|
|
755
|
+
private resolveActiveTurnSettings(options: {
|
|
756
|
+
skills: ReadonlyArray<HarnessV1Skill>;
|
|
757
|
+
instructions: string | undefined;
|
|
758
|
+
tools: ToolSet;
|
|
759
|
+
activeTools: ToolSet;
|
|
760
|
+
toolSpecs: HarnessAgentToolSpec[];
|
|
761
|
+
builtinToolFiltering: HarnessV1BuiltinToolFiltering | undefined;
|
|
762
|
+
}): ActiveTurnSettings {
|
|
763
|
+
if (this.activeTurnSettings != null) {
|
|
764
|
+
return this.activeTurnSettings;
|
|
765
|
+
}
|
|
766
|
+
const persisted =
|
|
767
|
+
this.persistedTurnSettings ??
|
|
768
|
+
({
|
|
769
|
+
skills: options.skills,
|
|
770
|
+
...(options.instructions == null
|
|
771
|
+
? {}
|
|
772
|
+
: { instructions: options.instructions }),
|
|
773
|
+
tools: options.toolSpecs,
|
|
774
|
+
} satisfies HarnessV1TurnSettings);
|
|
775
|
+
this.persistedTurnSettings = persisted;
|
|
776
|
+
|
|
777
|
+
const activeTools: ToolSet = {};
|
|
778
|
+
for (const toolSpec of persisted.tools) {
|
|
779
|
+
const tool = options.activeTools[toolSpec.name];
|
|
780
|
+
if (tool == null) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
`HarnessAgent cannot continue turn because tool '${toolSpec.name}' is no longer available.`,
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
activeTools[toolSpec.name] = tool;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
this.activeTurnSettings = {
|
|
789
|
+
persisted,
|
|
790
|
+
tools: options.tools,
|
|
791
|
+
activeTools,
|
|
792
|
+
builtinToolFiltering: options.builtinToolFiltering,
|
|
793
|
+
};
|
|
794
|
+
return this.activeTurnSettings;
|
|
795
|
+
}
|
|
796
|
+
|
|
697
797
|
private endLocalHandle(options: {
|
|
698
798
|
sessionState: Exclude<HarnessAgentSessionState, 'active'>;
|
|
699
799
|
}): void {
|
|
@@ -12,11 +12,15 @@ import type {
|
|
|
12
12
|
Arrayable,
|
|
13
13
|
Context,
|
|
14
14
|
Experimental_SandboxSession as SandboxSession,
|
|
15
|
+
FlexibleSchema,
|
|
16
|
+
MaybePromiseLike,
|
|
15
17
|
ToolSet,
|
|
16
18
|
} from '@ai-sdk/provider-utils';
|
|
17
19
|
import type {
|
|
18
20
|
ActiveTools,
|
|
21
|
+
AgentCallParameters,
|
|
19
22
|
OutputInterface as Output,
|
|
23
|
+
Prompt,
|
|
20
24
|
StopCondition,
|
|
21
25
|
TelemetryOptions,
|
|
22
26
|
ToolApprovalStatus,
|
|
@@ -74,9 +78,10 @@ type HarnessTools<TOOLS extends ToolSet> = ActiveTools<NoInfer<TOOLS>>;
|
|
|
74
78
|
/**
|
|
75
79
|
* Construction-time settings for a `HarnessAgent`.
|
|
76
80
|
*
|
|
77
|
-
*
|
|
81
|
+
* Prompt, abortSignal, callbacks, and custom call options belong on the
|
|
78
82
|
* `AgentCallParameters` / `AgentStreamParameters` passed to `generate` /
|
|
79
|
-
* `stream`
|
|
83
|
+
* `stream`. `prepareCall` can derive turn-scoped skills, instructions, and
|
|
84
|
+
* tools from those custom call options.
|
|
80
85
|
*/
|
|
81
86
|
type HarnessAgentToolFilteringSettings<TOOLS extends ToolSet> =
|
|
82
87
|
| {
|
|
@@ -101,6 +106,7 @@ export type HarnessAgentSettings<
|
|
|
101
106
|
TUserTools extends ToolSet = {},
|
|
102
107
|
RUNTIME_CONTEXT extends Context = Context,
|
|
103
108
|
OUTPUT extends Output = never,
|
|
109
|
+
CALL_OPTIONS = never,
|
|
104
110
|
> = {
|
|
105
111
|
/**
|
|
106
112
|
* The harness adapter driving the underlying agent runtime. Its
|
|
@@ -115,6 +121,12 @@ export type HarnessAgentSettings<
|
|
|
115
121
|
*/
|
|
116
122
|
readonly id?: string;
|
|
117
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Model identifier passed to the harness adapter when a session starts.
|
|
126
|
+
* Supported values are defined by the selected harness.
|
|
127
|
+
*/
|
|
128
|
+
readonly model?: string;
|
|
129
|
+
|
|
118
130
|
/**
|
|
119
131
|
* Tools available to the underlying runtime in addition to the harness's
|
|
120
132
|
* own builtins. The agent forwards each tool to the harness as a
|
|
@@ -127,19 +139,86 @@ export type HarnessAgentSettings<
|
|
|
127
139
|
readonly tools?: TUserTools;
|
|
128
140
|
|
|
129
141
|
/**
|
|
130
|
-
* Skills made available to the underlying runtime
|
|
131
|
-
*
|
|
132
|
-
* working tree, prompt prefix, …).
|
|
142
|
+
* Skills made available to the underlying runtime. Each adapter decides how
|
|
143
|
+
* to surface skills. `prepareCall` can replace them between completed turns.
|
|
133
144
|
*/
|
|
134
145
|
readonly skills?: ReadonlyArray<HarnessAgentSkill>;
|
|
135
146
|
|
|
136
147
|
/**
|
|
137
|
-
* Instructions for the underlying agent runtime. Adapters append
|
|
148
|
+
* Instructions for the underlying agent runtime. Adapters append these to a
|
|
138
149
|
* native system or developer prompt when supported. Otherwise, they prepend
|
|
139
|
-
*
|
|
150
|
+
* them to the user message. `prepareCall` can replace them between completed
|
|
151
|
+
* turns.
|
|
140
152
|
*/
|
|
141
153
|
readonly instructions?: string;
|
|
142
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Schema for validating the custom options passed to each agent call.
|
|
157
|
+
*/
|
|
158
|
+
readonly callOptionsSchema?: FlexibleSchema<CALL_OPTIONS>;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Prepares the prompt and the settings that may vary between completed
|
|
162
|
+
* turns. The prepared values are frozen for the lifetime of the turn,
|
|
163
|
+
* including any suspended-turn continuations.
|
|
164
|
+
*
|
|
165
|
+
* Preserve the remaining arguments with the rest-spread pattern when a
|
|
166
|
+
* field should be removable by returning `undefined`:
|
|
167
|
+
*
|
|
168
|
+
* ```ts
|
|
169
|
+
* prepareCall: ({ options, ...rest }) => ({
|
|
170
|
+
* ...rest,
|
|
171
|
+
* instructions: options.instructions,
|
|
172
|
+
* })
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
readonly prepareCall?: (
|
|
176
|
+
options: Omit<
|
|
177
|
+
AgentCallParameters<
|
|
178
|
+
CALL_OPTIONS,
|
|
179
|
+
HarnessAllTools<THarness, TUserTools>,
|
|
180
|
+
RUNTIME_CONTEXT
|
|
181
|
+
>,
|
|
182
|
+
| 'abortSignal'
|
|
183
|
+
| 'timeout'
|
|
184
|
+
| 'onStart'
|
|
185
|
+
| 'experimental_onStart'
|
|
186
|
+
| 'onStepStart'
|
|
187
|
+
| 'experimental_onStepStart'
|
|
188
|
+
| 'onToolExecutionStart'
|
|
189
|
+
| 'experimental_onToolCallStart'
|
|
190
|
+
| 'onToolExecutionEnd'
|
|
191
|
+
| 'experimental_onToolCallFinish'
|
|
192
|
+
| 'onStepEnd'
|
|
193
|
+
| 'onStepFinish'
|
|
194
|
+
| 'onEnd'
|
|
195
|
+
| 'onFinish'
|
|
196
|
+
| 'experimental_sandbox'
|
|
197
|
+
> &
|
|
198
|
+
Pick<
|
|
199
|
+
HarnessAgentSettings<
|
|
200
|
+
THarness,
|
|
201
|
+
TUserTools,
|
|
202
|
+
RUNTIME_CONTEXT,
|
|
203
|
+
NoInfer<OUTPUT>,
|
|
204
|
+
CALL_OPTIONS
|
|
205
|
+
>,
|
|
206
|
+
'skills' | 'instructions' | 'tools'
|
|
207
|
+
>,
|
|
208
|
+
) => MaybePromiseLike<
|
|
209
|
+
Pick<
|
|
210
|
+
HarnessAgentSettings<
|
|
211
|
+
THarness,
|
|
212
|
+
TUserTools,
|
|
213
|
+
RUNTIME_CONTEXT,
|
|
214
|
+
NoInfer<OUTPUT>,
|
|
215
|
+
CALL_OPTIONS
|
|
216
|
+
>,
|
|
217
|
+
'skills' | 'instructions' | 'tools'
|
|
218
|
+
> &
|
|
219
|
+
Omit<Prompt, 'system' | 'instructions' | 'allowSystemInMessages'>
|
|
220
|
+
>;
|
|
221
|
+
|
|
143
222
|
/**
|
|
144
223
|
* Optional specification for generating typed output. The same output
|
|
145
224
|
* requirement is active for every turn run by this agent.
|