@ai-sdk/harness 1.0.100 → 1.0.102
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/agent/index.ts +2 -8
- package/dist/agent/index.d.ts +128 -48
- package/dist/agent/index.js +586 -512
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.d.ts +11 -1
- package/dist/bridge/index.js +37 -7
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +84 -2
- package/dist/index.js +286 -229
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +17 -3
- package/dist/utils/index.js +323 -19
- package/dist/utils/index.js.map +1 -1
- package/package.json +3 -3
- package/src/agent/harness-agent-session.ts +9 -8
- package/src/agent/harness-agent-settings.ts +82 -3
- package/src/agent/harness-agent-tool-approval-continuation.ts +6 -32
- package/src/agent/harness-agent-tool-result-continuation.ts +4 -53
- package/src/agent/harness-agent.ts +107 -18
- package/src/agent/internal/harness-stream-text-result.ts +33 -13
- package/src/agent/internal/run-prompt.ts +309 -122
- package/src/agent/internal/turn-telemetry.ts +293 -444
- package/src/bridge/index.ts +82 -11
- package/src/utils/index.ts +5 -0
- package/src/utils/write-instructions.ts +373 -0
- package/src/utils/write-skills.ts +59 -2
- package/src/v1/harness-v1-bridge-protocol.ts +1 -0
- package/src/v1/harness-v1-builtin-tool.ts +2 -0
- package/src/v1/harness-v1-lifecycle-state.ts +2 -0
- package/src/v1/harness-v1-prompt-control.ts +3 -0
- package/src/v1/harness-v1-questions-tool.ts +72 -0
- package/src/v1/harness-v1-session.ts +5 -0
- package/src/v1/index.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.102",
|
|
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.10",
|
|
48
48
|
"@ai-sdk/provider-utils": "5.0.36",
|
|
49
|
-
"ai": "7.0.
|
|
49
|
+
"ai": "7.0.93"
|
|
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.93",
|
|
62
62
|
"@opentelemetry/sdk-trace-base": "2.7.1",
|
|
63
63
|
"@types/node": "22.19.19",
|
|
64
64
|
"@types/ws": "^8.5.13",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Context,
|
|
3
3
|
Experimental_SandboxSession as SandboxSession,
|
|
4
|
+
ToolApprovalResponse,
|
|
5
|
+
ToolResultPart,
|
|
4
6
|
ToolSet,
|
|
5
7
|
} from '@ai-sdk/provider-utils';
|
|
6
8
|
import type {
|
|
@@ -29,11 +31,10 @@ import type {
|
|
|
29
31
|
HarnessAgentResumeSessionState,
|
|
30
32
|
HarnessAgentToolSpec,
|
|
31
33
|
} from './harness-agent-types';
|
|
32
|
-
import type { HarnessAgentToolApprovalContinuation } from './harness-agent-tool-approval-continuation';
|
|
33
|
-
import type { HarnessAgentToolResultContinuation } from './harness-agent-tool-result-continuation';
|
|
34
34
|
import { validateLifecycleStateData } from './internal/lifecycle-state-validation';
|
|
35
35
|
import { runPrompt } from './internal/run-prompt';
|
|
36
36
|
import { getRestrictedSandboxSession } from '../utils/get-restricted-sandbox-session';
|
|
37
|
+
import type { HarnessAgentLifecycleCallbacks } from './internal/turn-telemetry';
|
|
37
38
|
|
|
38
39
|
type HarnessAgentTurnResult<
|
|
39
40
|
TOOLS extends ToolSet,
|
|
@@ -207,6 +208,7 @@ export class HarnessAgentSession {
|
|
|
207
208
|
responseFormat: HarnessV1ResponseFormat | undefined;
|
|
208
209
|
output: OUTPUT | undefined;
|
|
209
210
|
telemetry: TelemetryOptions | undefined;
|
|
211
|
+
callbacks: HarnessAgentLifecycleCallbacks<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
210
212
|
stopConditions: ReadonlyArray<StopCondition<TOOLS, RUNTIME_CONTEXT>>;
|
|
211
213
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
212
214
|
const session = this.requireReusableSession();
|
|
@@ -246,6 +248,7 @@ export class HarnessAgentSession {
|
|
|
246
248
|
responseFormat: options.responseFormat,
|
|
247
249
|
output: options.output,
|
|
248
250
|
telemetry: options.telemetry,
|
|
251
|
+
callbacks: options.callbacks,
|
|
249
252
|
stopConditions: options.stopConditions,
|
|
250
253
|
toolApproval: this.toolApproval,
|
|
251
254
|
pendingToolApprovals: this.getPendingToolApprovals(),
|
|
@@ -305,13 +308,10 @@ export class HarnessAgentSession {
|
|
|
305
308
|
responseFormat: HarnessV1ResponseFormat | undefined;
|
|
306
309
|
output: OUTPUT | undefined;
|
|
307
310
|
telemetry: TelemetryOptions | undefined;
|
|
311
|
+
callbacks: HarnessAgentLifecycleCallbacks<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
308
312
|
stopConditions: ReadonlyArray<StopCondition<TOOLS, RUNTIME_CONTEXT>>;
|
|
309
|
-
toolApprovalContinuations?:
|
|
310
|
-
|
|
311
|
-
| undefined;
|
|
312
|
-
toolResultContinuations?:
|
|
313
|
-
| readonly HarnessAgentToolResultContinuation[]
|
|
314
|
-
| undefined;
|
|
313
|
+
toolApprovalContinuations?: readonly ToolApprovalResponse[] | undefined;
|
|
314
|
+
toolResultContinuations?: readonly ToolResultPart[] | undefined;
|
|
315
315
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
316
316
|
const session = this.requireReusableSession();
|
|
317
317
|
this.requireContinuableTurn();
|
|
@@ -345,6 +345,7 @@ export class HarnessAgentSession {
|
|
|
345
345
|
responseFormat: options.responseFormat,
|
|
346
346
|
output: options.output,
|
|
347
347
|
telemetry: options.telemetry,
|
|
348
|
+
callbacks: options.callbacks,
|
|
348
349
|
stopConditions: options.stopConditions,
|
|
349
350
|
toolApproval: this.toolApproval,
|
|
350
351
|
pendingToolApprovals: this.getPendingToolApprovals(),
|
|
@@ -19,6 +19,14 @@ import type {
|
|
|
19
19
|
import type {
|
|
20
20
|
ActiveTools,
|
|
21
21
|
AgentCallParameters,
|
|
22
|
+
GenerateTextOnEndCallback,
|
|
23
|
+
GenerateTextOnStartCallback,
|
|
24
|
+
GenerateTextOnStepEndCallback,
|
|
25
|
+
GenerateTextOnStepStartCallback,
|
|
26
|
+
OnLanguageModelCallEndCallback,
|
|
27
|
+
OnLanguageModelCallStartCallback,
|
|
28
|
+
OnToolExecutionEndCallback,
|
|
29
|
+
OnToolExecutionStartCallback,
|
|
22
30
|
OutputInterface as Output,
|
|
23
31
|
Prompt,
|
|
24
32
|
StopCondition,
|
|
@@ -78,10 +86,12 @@ type HarnessTools<TOOLS extends ToolSet> = ActiveTools<NoInfer<TOOLS>>;
|
|
|
78
86
|
/**
|
|
79
87
|
* Construction-time settings for a `HarnessAgent`.
|
|
80
88
|
*
|
|
81
|
-
* Prompt, abortSignal,
|
|
89
|
+
* Prompt, abortSignal, and custom call options belong on the
|
|
82
90
|
* `AgentCallParameters` / `AgentStreamParameters` passed to `generate` /
|
|
83
|
-
* `stream`.
|
|
84
|
-
*
|
|
91
|
+
* `stream`. Lifecycle callbacks can be configured here for every call, while
|
|
92
|
+
* the callbacks supported by `AgentCallParameters` can also be added per call.
|
|
93
|
+
* `prepareCall` can derive turn-scoped model, skills, instructions, and tools
|
|
94
|
+
* from custom call options.
|
|
85
95
|
*/
|
|
86
96
|
type HarnessAgentToolFilteringSettings<TOOLS extends ToolSet> =
|
|
87
97
|
| {
|
|
@@ -153,6 +163,14 @@ export type HarnessAgentSettings<
|
|
|
153
163
|
*/
|
|
154
164
|
readonly instructions?: string;
|
|
155
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Additional HTTP headers to be sent with every model request.
|
|
168
|
+
*
|
|
169
|
+
* `authorization`, `x-api-key`, `user-agent`, and `x-client-app` are
|
|
170
|
+
* managed by the harness and are not allowed.
|
|
171
|
+
*/
|
|
172
|
+
readonly headers?: Record<string, string | undefined>;
|
|
173
|
+
|
|
156
174
|
/**
|
|
157
175
|
* Schema for validating the custom options passed to each agent call.
|
|
158
176
|
*/
|
|
@@ -242,6 +260,67 @@ export type HarnessAgentSettings<
|
|
|
242
260
|
>
|
|
243
261
|
>;
|
|
244
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Called when an agent call begins, before any model steps.
|
|
265
|
+
*/
|
|
266
|
+
readonly onStart?: GenerateTextOnStartCallback<
|
|
267
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>,
|
|
268
|
+
RUNTIME_CONTEXT,
|
|
269
|
+
NoInfer<OUTPUT>
|
|
270
|
+
>;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Called when a model step begins.
|
|
274
|
+
*/
|
|
275
|
+
readonly onStepStart?: GenerateTextOnStepStartCallback<
|
|
276
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>,
|
|
277
|
+
NoInfer<RUNTIME_CONTEXT>,
|
|
278
|
+
NoInfer<OUTPUT>
|
|
279
|
+
>;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Called immediately before the harness begins emitting a model response.
|
|
283
|
+
*/
|
|
284
|
+
readonly onLanguageModelCallStart?: OnLanguageModelCallStartCallback;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Called after a model response is complete and before its tool execution
|
|
288
|
+
* lifecycle callbacks are delivered.
|
|
289
|
+
*/
|
|
290
|
+
readonly onLanguageModelCallEnd?: OnLanguageModelCallEndCallback<
|
|
291
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>
|
|
292
|
+
>;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Called before each harness or host tool execution is reported.
|
|
296
|
+
*/
|
|
297
|
+
readonly onToolExecutionStart?: OnToolExecutionStartCallback<
|
|
298
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>
|
|
299
|
+
>;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Called after each harness or host tool execution is reported.
|
|
303
|
+
*/
|
|
304
|
+
readonly onToolExecutionEnd?: OnToolExecutionEndCallback<
|
|
305
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>
|
|
306
|
+
>;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Called after each completed model step.
|
|
310
|
+
*/
|
|
311
|
+
readonly onStepEnd?: GenerateTextOnStepEndCallback<
|
|
312
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>,
|
|
313
|
+
NoInfer<RUNTIME_CONTEXT>
|
|
314
|
+
>;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Called when an agent call completes successfully.
|
|
318
|
+
*/
|
|
319
|
+
readonly onEnd?: GenerateTextOnEndCallback<
|
|
320
|
+
NoInfer<HarnessAllTools<THarness, TUserTools>>,
|
|
321
|
+
NoInfer<RUNTIME_CONTEXT>
|
|
322
|
+
>;
|
|
323
|
+
|
|
245
324
|
/**
|
|
246
325
|
* Built-in tool permission mode. Defaults to `'allow-all'`, preserving the
|
|
247
326
|
* existing bypass-permissions behavior unless users opt in.
|
|
@@ -5,17 +5,6 @@ import type {
|
|
|
5
5
|
ToolApprovalResponse,
|
|
6
6
|
} from '@ai-sdk/provider-utils';
|
|
7
7
|
|
|
8
|
-
export type HarnessAgentToolApprovalContinuation = {
|
|
9
|
-
readonly approvalResponse: ToolApprovalResponse;
|
|
10
|
-
readonly toolCall: {
|
|
11
|
-
readonly type: 'tool-call';
|
|
12
|
-
readonly toolCallId: string;
|
|
13
|
-
readonly toolName: string;
|
|
14
|
-
readonly input: unknown;
|
|
15
|
-
readonly providerExecuted?: boolean;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
8
|
/**
|
|
20
9
|
* Extract approval decisions that should continue a suspended harness turn.
|
|
21
10
|
*
|
|
@@ -28,14 +17,11 @@ export type HarnessAgentToolApprovalContinuation = {
|
|
|
28
17
|
*/
|
|
29
18
|
export function collectHarnessAgentToolApprovalContinuations(input: {
|
|
30
19
|
messages: readonly ModelMessage[];
|
|
31
|
-
}): readonly
|
|
20
|
+
}): readonly ToolApprovalResponse[] {
|
|
32
21
|
const lastMessage = input.messages.at(-1);
|
|
33
22
|
if (lastMessage?.role !== 'tool') return [];
|
|
34
23
|
|
|
35
|
-
const
|
|
36
|
-
string,
|
|
37
|
-
HarnessAgentToolApprovalContinuation['toolCall']
|
|
38
|
-
>();
|
|
24
|
+
const toolCallIds = new Set<string>();
|
|
39
25
|
const approvalRequestsByApprovalId = new Map<string, ToolApprovalRequest>();
|
|
40
26
|
for (const message of input.messages) {
|
|
41
27
|
if (message.role !== 'assistant' || typeof message.content === 'string') {
|
|
@@ -43,15 +29,7 @@ export function collectHarnessAgentToolApprovalContinuations(input: {
|
|
|
43
29
|
}
|
|
44
30
|
for (const part of message.content) {
|
|
45
31
|
if (part.type === 'tool-call') {
|
|
46
|
-
|
|
47
|
-
type: 'tool-call',
|
|
48
|
-
toolCallId: part.toolCallId,
|
|
49
|
-
toolName: part.toolName,
|
|
50
|
-
input: part.input,
|
|
51
|
-
...(part.providerExecuted !== undefined
|
|
52
|
-
? { providerExecuted: part.providerExecuted }
|
|
53
|
-
: {}),
|
|
54
|
-
});
|
|
32
|
+
toolCallIds.add(part.toolCallId);
|
|
55
33
|
} else if (part.type === 'tool-approval-request') {
|
|
56
34
|
approvalRequestsByApprovalId.set(part.approvalId, part);
|
|
57
35
|
}
|
|
@@ -65,7 +43,7 @@ export function collectHarnessAgentToolApprovalContinuations(input: {
|
|
|
65
43
|
}
|
|
66
44
|
}
|
|
67
45
|
|
|
68
|
-
const continuations:
|
|
46
|
+
const continuations: ToolApprovalResponse[] = [];
|
|
69
47
|
for (const part of lastMessage.content) {
|
|
70
48
|
if (part.type !== 'tool-approval-response') continue;
|
|
71
49
|
|
|
@@ -77,17 +55,13 @@ export function collectHarnessAgentToolApprovalContinuations(input: {
|
|
|
77
55
|
}
|
|
78
56
|
if (toolResultIds.has(approvalRequest.toolCallId)) continue;
|
|
79
57
|
|
|
80
|
-
|
|
81
|
-
if (toolCall == null) {
|
|
58
|
+
if (!toolCallIds.has(approvalRequest.toolCallId)) {
|
|
82
59
|
throw new HarnessError({
|
|
83
60
|
message: `Tool approval request '${approvalRequest.approvalId}' references unknown tool call '${approvalRequest.toolCallId}'.`,
|
|
84
61
|
});
|
|
85
62
|
}
|
|
86
63
|
|
|
87
|
-
continuations.push(
|
|
88
|
-
approvalResponse: part,
|
|
89
|
-
toolCall,
|
|
90
|
-
});
|
|
64
|
+
continuations.push(part);
|
|
91
65
|
}
|
|
92
66
|
|
|
93
67
|
return continuations;
|
|
@@ -1,62 +1,13 @@
|
|
|
1
|
-
import type { ModelMessage,
|
|
2
|
-
|
|
3
|
-
export type HarnessAgentToolResultContinuation = {
|
|
4
|
-
readonly toolCallId: string;
|
|
5
|
-
readonly output: unknown;
|
|
6
|
-
readonly isError?: boolean;
|
|
7
|
-
};
|
|
1
|
+
import type { ModelMessage, ToolResultPart } from '@ai-sdk/provider-utils';
|
|
8
2
|
|
|
9
3
|
/**
|
|
10
|
-
* Extract client-provided tool results from the trailing tool message
|
|
11
|
-
* convert AI SDK model-output wrappers back into values a harness runtime can
|
|
12
|
-
* return from its pending host-tool invocation.
|
|
4
|
+
* Extract client-provided tool results from the trailing tool message.
|
|
13
5
|
*/
|
|
14
6
|
export function collectHarnessAgentToolResultContinuations(input: {
|
|
15
7
|
messages: readonly ModelMessage[];
|
|
16
|
-
}): readonly
|
|
8
|
+
}): readonly ToolResultPart[] {
|
|
17
9
|
const lastMessage = input.messages.at(-1);
|
|
18
10
|
if (lastMessage?.role !== 'tool') return [];
|
|
19
11
|
|
|
20
|
-
return lastMessage.content
|
|
21
|
-
.filter(part => part.type === 'tool-result')
|
|
22
|
-
.map(part =>
|
|
23
|
-
toToolResultContinuation({
|
|
24
|
-
toolCallId: part.toolCallId,
|
|
25
|
-
output: part.output,
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function toToolResultContinuation(input: {
|
|
31
|
-
toolCallId: string;
|
|
32
|
-
output: ToolResultOutput;
|
|
33
|
-
}): HarnessAgentToolResultContinuation {
|
|
34
|
-
switch (input.output.type) {
|
|
35
|
-
case 'text':
|
|
36
|
-
case 'json':
|
|
37
|
-
return {
|
|
38
|
-
toolCallId: input.toolCallId,
|
|
39
|
-
output: input.output.value,
|
|
40
|
-
};
|
|
41
|
-
case 'error-text':
|
|
42
|
-
case 'error-json':
|
|
43
|
-
return {
|
|
44
|
-
toolCallId: input.toolCallId,
|
|
45
|
-
output: input.output.value,
|
|
46
|
-
isError: true,
|
|
47
|
-
};
|
|
48
|
-
case 'execution-denied':
|
|
49
|
-
return {
|
|
50
|
-
toolCallId: input.toolCallId,
|
|
51
|
-
output: {
|
|
52
|
-
type: input.output.type,
|
|
53
|
-
reason: input.output.reason,
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
case 'content':
|
|
57
|
-
return {
|
|
58
|
-
toolCallId: input.toolCallId,
|
|
59
|
-
output: input.output,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
12
|
+
return lastMessage.content.filter(part => part.type === 'tool-result');
|
|
62
13
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HarnessCapabilityUnsupportedError } from '../errors/harness-capability-unsupported-error';
|
|
2
2
|
import type {
|
|
3
|
+
HarnessV1,
|
|
3
4
|
HarnessV1BuiltinToolFiltering,
|
|
4
5
|
HarnessV1JSONSchema,
|
|
5
6
|
HarnessV1NetworkSandboxSession,
|
|
@@ -9,12 +10,16 @@ import {
|
|
|
9
10
|
asArray,
|
|
10
11
|
asSchema,
|
|
11
12
|
generateId,
|
|
13
|
+
normalizeHeaders,
|
|
12
14
|
validateTypes,
|
|
13
15
|
type Context,
|
|
14
16
|
type Experimental_SandboxSession as SandboxSession,
|
|
15
17
|
type ModelMessage,
|
|
18
|
+
type ToolApprovalResponse,
|
|
19
|
+
type ToolResultPart,
|
|
16
20
|
type ToolSet,
|
|
17
21
|
} from '@ai-sdk/provider-utils';
|
|
22
|
+
import { mergeCallbacks } from 'ai/internal';
|
|
18
23
|
import type {
|
|
19
24
|
Agent,
|
|
20
25
|
AgentCallParameters,
|
|
@@ -41,14 +46,8 @@ import type {
|
|
|
41
46
|
HarnessAgentSkill,
|
|
42
47
|
HarnessAgentToolSpec,
|
|
43
48
|
} from './harness-agent-types';
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
type HarnessAgentToolApprovalContinuation,
|
|
47
|
-
} from './harness-agent-tool-approval-continuation';
|
|
48
|
-
import {
|
|
49
|
-
collectHarnessAgentToolResultContinuations,
|
|
50
|
-
type HarnessAgentToolResultContinuation,
|
|
51
|
-
} from './harness-agent-tool-result-continuation';
|
|
49
|
+
import { collectHarnessAgentToolApprovalContinuations } from './harness-agent-tool-approval-continuation';
|
|
50
|
+
import { collectHarnessAgentToolResultContinuations } from './harness-agent-tool-result-continuation';
|
|
52
51
|
import {
|
|
53
52
|
applyBootstrapRecipe,
|
|
54
53
|
hashHarnessBootstrap,
|
|
@@ -68,6 +67,7 @@ import {
|
|
|
68
67
|
import { resolveHarnessAgentToolFiltering } from './internal/tool-filtering';
|
|
69
68
|
import { resolveSandboxDefaultWorkingDirectory } from '../utils/resolve-sandbox-default-working-directory';
|
|
70
69
|
import { getRestrictedSandboxSession } from '../utils/get-restricted-sandbox-session';
|
|
70
|
+
import type { HarnessAgentLifecycleCallbacks } from './internal/turn-telemetry';
|
|
71
71
|
|
|
72
72
|
export type { HarnessAllTools } from './harness-agent-tool-types';
|
|
73
73
|
|
|
@@ -86,8 +86,8 @@ export interface HarnessAgentCallExtensions {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
type HarnessAgentContinueTurnInput = {
|
|
89
|
-
toolApprovalContinuations: readonly
|
|
90
|
-
toolResultContinuations: readonly
|
|
89
|
+
toolApprovalContinuations: readonly ToolApprovalResponse[];
|
|
90
|
+
toolResultContinuations: readonly ToolResultPart[];
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
type PreparedHarnessAgentTurnSettings<
|
|
@@ -114,8 +114,8 @@ type PreparedHarnessAgentContinueTurnInput<
|
|
|
114
114
|
THarness extends HarnessAgentAdapter<any>,
|
|
115
115
|
TUserTools extends ToolSet,
|
|
116
116
|
> = PreparedHarnessAgentTurnSettings<THarness, TUserTools> & {
|
|
117
|
-
toolApprovalContinuations: readonly
|
|
118
|
-
toolResultContinuations: readonly
|
|
117
|
+
toolApprovalContinuations: readonly ToolApprovalResponse[];
|
|
118
|
+
toolResultContinuations: readonly ToolResultPart[];
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
type HarnessAgentTurnResult<
|
|
@@ -206,6 +206,7 @@ export class HarnessAgent<
|
|
|
206
206
|
| HarnessV1BuiltinToolFiltering
|
|
207
207
|
| undefined;
|
|
208
208
|
private readonly permissionMode: HarnessAgentPermissionMode;
|
|
209
|
+
private readonly headers: Readonly<Record<string, string>> | undefined;
|
|
209
210
|
|
|
210
211
|
constructor(
|
|
211
212
|
settings: HarnessAgentSettings<
|
|
@@ -222,8 +223,28 @@ export class HarnessAgent<
|
|
|
222
223
|
this.stopConditions =
|
|
223
224
|
settings.stopWhen == null ? [] : asArray(settings.stopWhen);
|
|
224
225
|
this.sandboxConfig = sandboxConfig;
|
|
226
|
+
const forbiddenHeaders = new Set([
|
|
227
|
+
'authorization',
|
|
228
|
+
'x-api-key',
|
|
229
|
+
'user-agent',
|
|
230
|
+
'x-client-app',
|
|
231
|
+
]);
|
|
232
|
+
const forbiddenHeader = Object.keys(settings.headers ?? {})
|
|
233
|
+
.map(name => name.toLowerCase())
|
|
234
|
+
.find(name => forbiddenHeaders.has(name));
|
|
235
|
+
if (forbiddenHeader != null) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`HarnessAgent: \`headers\` must not include the managed header \`${forbiddenHeader}\`.`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
const headers = normalizeHeaders(settings.headers);
|
|
241
|
+
this.headers = Object.keys(headers).length === 0 ? undefined : headers;
|
|
225
242
|
this.id = settings.id;
|
|
226
243
|
const userTools = settings.tools ?? ({} as TUserTools);
|
|
244
|
+
assertNoReservedQuestionTool({
|
|
245
|
+
harness: settings.harness,
|
|
246
|
+
userTools,
|
|
247
|
+
});
|
|
227
248
|
this.permissionMode = resolvePermissionMode({
|
|
228
249
|
permissionMode: settings.permissionMode,
|
|
229
250
|
});
|
|
@@ -501,6 +522,7 @@ export class HarnessAgent<
|
|
|
501
522
|
try {
|
|
502
523
|
const baseStartOptions = {
|
|
503
524
|
sessionId,
|
|
525
|
+
...(this.headers == null ? {} : { headers: this.headers }),
|
|
504
526
|
resumeFrom: validatedResumeFrom,
|
|
505
527
|
continueFrom: effectiveContinueFrom,
|
|
506
528
|
permissionMode: this.permissionMode,
|
|
@@ -609,8 +631,8 @@ export class HarnessAgent<
|
|
|
609
631
|
*/
|
|
610
632
|
async continueGenerate(options: {
|
|
611
633
|
session: HarnessAgentSession;
|
|
612
|
-
toolApprovalContinuations?: readonly
|
|
613
|
-
toolResultContinuations?: readonly
|
|
634
|
+
toolApprovalContinuations?: readonly ToolApprovalResponse[];
|
|
635
|
+
toolResultContinuations?: readonly ToolResultPart[];
|
|
614
636
|
abortSignal?: AbortSignal;
|
|
615
637
|
}): Promise<
|
|
616
638
|
GenerateTextResult<
|
|
@@ -643,8 +665,8 @@ export class HarnessAgent<
|
|
|
643
665
|
*/
|
|
644
666
|
async continueStream(options: {
|
|
645
667
|
session: HarnessAgentSession;
|
|
646
|
-
toolApprovalContinuations?: readonly
|
|
647
|
-
toolResultContinuations?: readonly
|
|
668
|
+
toolApprovalContinuations?: readonly ToolApprovalResponse[];
|
|
669
|
+
toolResultContinuations?: readonly ToolResultPart[];
|
|
648
670
|
abortSignal?: AbortSignal;
|
|
649
671
|
}): Promise<
|
|
650
672
|
StreamTextResult<
|
|
@@ -707,6 +729,7 @@ export class HarnessAgent<
|
|
|
707
729
|
runtimeContext: input.runtimeContext,
|
|
708
730
|
abortSignal: input.options.abortSignal,
|
|
709
731
|
responseFormat,
|
|
732
|
+
callbacks: this._resolveLifecycleCallbacks(input.options),
|
|
710
733
|
}),
|
|
711
734
|
prompt: turnInput.prompt,
|
|
712
735
|
});
|
|
@@ -733,6 +756,7 @@ export class HarnessAgent<
|
|
|
733
756
|
runtimeContext: input.runtimeContext,
|
|
734
757
|
abortSignal: input.abortSignal,
|
|
735
758
|
responseFormat,
|
|
759
|
+
callbacks: this._resolveLifecycleCallbacks(),
|
|
736
760
|
}),
|
|
737
761
|
toolApprovalContinuations: turnInput.toolApprovalContinuations,
|
|
738
762
|
toolResultContinuations: turnInput.toolResultContinuations,
|
|
@@ -744,6 +768,11 @@ export class HarnessAgent<
|
|
|
744
768
|
runtimeContext: RUNTIME_CONTEXT;
|
|
745
769
|
abortSignal: AbortSignal | undefined;
|
|
746
770
|
responseFormat: HarnessV1ResponseFormat | undefined;
|
|
771
|
+
callbacks: HarnessAgentLifecycleCallbacks<
|
|
772
|
+
HarnessAllTools<THarness, TUserTools>,
|
|
773
|
+
RUNTIME_CONTEXT,
|
|
774
|
+
OUTPUT
|
|
775
|
+
>;
|
|
747
776
|
}) {
|
|
748
777
|
return {
|
|
749
778
|
model: input.turnSettings.model,
|
|
@@ -758,10 +787,49 @@ export class HarnessAgent<
|
|
|
758
787
|
responseFormat: input.responseFormat,
|
|
759
788
|
output: this.settings.output,
|
|
760
789
|
telemetry: this.settings.telemetry,
|
|
790
|
+
callbacks: input.callbacks,
|
|
761
791
|
stopConditions: this.stopConditions,
|
|
762
792
|
};
|
|
763
793
|
}
|
|
764
794
|
|
|
795
|
+
private _resolveLifecycleCallbacks(
|
|
796
|
+
call?: AgentCallParameters<
|
|
797
|
+
CALL_OPTIONS,
|
|
798
|
+
HarnessAllTools<THarness, TUserTools>,
|
|
799
|
+
RUNTIME_CONTEXT
|
|
800
|
+
>,
|
|
801
|
+
): HarnessAgentLifecycleCallbacks<
|
|
802
|
+
HarnessAllTools<THarness, TUserTools>,
|
|
803
|
+
RUNTIME_CONTEXT,
|
|
804
|
+
OUTPUT
|
|
805
|
+
> {
|
|
806
|
+
return {
|
|
807
|
+
onStart: mergeCallbacks(
|
|
808
|
+
this.settings.onStart,
|
|
809
|
+
call?.onStart ?? call?.experimental_onStart,
|
|
810
|
+
),
|
|
811
|
+
onStepStart: mergeCallbacks(
|
|
812
|
+
this.settings.onStepStart,
|
|
813
|
+
call?.onStepStart ?? call?.experimental_onStepStart,
|
|
814
|
+
),
|
|
815
|
+
onLanguageModelCallStart: this.settings.onLanguageModelCallStart,
|
|
816
|
+
onLanguageModelCallEnd: this.settings.onLanguageModelCallEnd,
|
|
817
|
+
onToolExecutionStart: mergeCallbacks(
|
|
818
|
+
this.settings.onToolExecutionStart,
|
|
819
|
+
call?.onToolExecutionStart ?? call?.experimental_onToolCallStart,
|
|
820
|
+
),
|
|
821
|
+
onToolExecutionEnd: mergeCallbacks(
|
|
822
|
+
this.settings.onToolExecutionEnd,
|
|
823
|
+
call?.onToolExecutionEnd ?? call?.experimental_onToolCallFinish,
|
|
824
|
+
),
|
|
825
|
+
onStepEnd: mergeCallbacks(
|
|
826
|
+
this.settings.onStepEnd,
|
|
827
|
+
call?.onStepEnd ?? call?.onStepFinish,
|
|
828
|
+
),
|
|
829
|
+
onEnd: mergeCallbacks(this.settings.onEnd, call?.onEnd ?? call?.onFinish),
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
|
|
765
833
|
private _resolveContinueTurnInput(options: {
|
|
766
834
|
prompt?: string | ModelMessage[];
|
|
767
835
|
messages?: ModelMessage[];
|
|
@@ -903,8 +971,8 @@ export class HarnessAgent<
|
|
|
903
971
|
}
|
|
904
972
|
|
|
905
973
|
private _prepareContinueTurnInput(options: {
|
|
906
|
-
toolApprovalContinuations?: readonly
|
|
907
|
-
toolResultContinuations?: readonly
|
|
974
|
+
toolApprovalContinuations?: readonly ToolApprovalResponse[];
|
|
975
|
+
toolResultContinuations?: readonly ToolResultPart[];
|
|
908
976
|
}): PreparedHarnessAgentContinueTurnInput<THarness, TUserTools> {
|
|
909
977
|
return {
|
|
910
978
|
...this._prepareTurnSettings({
|
|
@@ -925,6 +993,10 @@ export class HarnessAgent<
|
|
|
925
993
|
tools?: TUserTools;
|
|
926
994
|
}): PreparedHarnessAgentTurnSettings<THarness, TUserTools> {
|
|
927
995
|
const userTools = options.tools ?? ({} as TUserTools);
|
|
996
|
+
assertNoReservedQuestionTool({
|
|
997
|
+
harness: this.settings.harness,
|
|
998
|
+
userTools,
|
|
999
|
+
});
|
|
928
1000
|
const tools = {
|
|
929
1001
|
...this.settings.harness.builtinTools,
|
|
930
1002
|
...userTools,
|
|
@@ -1028,6 +1100,23 @@ export class HarnessAgent<
|
|
|
1028
1100
|
}
|
|
1029
1101
|
}
|
|
1030
1102
|
|
|
1103
|
+
function assertNoReservedQuestionTool(input: {
|
|
1104
|
+
harness: HarnessV1;
|
|
1105
|
+
userTools: ToolSet;
|
|
1106
|
+
}): void {
|
|
1107
|
+
if (
|
|
1108
|
+
Object.prototype.hasOwnProperty.call(
|
|
1109
|
+
input.harness.builtinTools,
|
|
1110
|
+
'askUserQuestions',
|
|
1111
|
+
) &&
|
|
1112
|
+
Object.prototype.hasOwnProperty.call(input.userTools, 'askUserQuestions')
|
|
1113
|
+
) {
|
|
1114
|
+
throw new Error(
|
|
1115
|
+
"HarnessAgent tool name 'askUserQuestions' is reserved for harness question requests.",
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1031
1120
|
/*
|
|
1032
1121
|
* `GenerateTextResult` view over a drained `streamText` run. Non-deprecated
|
|
1033
1122
|
* members derive from `steps` (the single source of truth), and the deprecated
|