@ai-sdk/harness 1.0.93 → 1.0.94
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 +14 -0
- package/dist/agent/index.d.ts +22 -19
- package/dist/agent/index.js +108 -4
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +48 -14
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/index.js +26 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -5
- package/src/agent/harness-agent-session.ts +8 -0
- package/src/agent/harness-agent-settings.ts +7 -6
- package/src/agent/harness-agent.ts +7 -1
- package/src/agent/internal/run-prompt.ts +33 -5
- package/src/agent/internal/strip-work-dir.ts +102 -0
- package/src/agent/internal/translate-stream-part.ts +5 -0
- package/src/v1/harness-v1-bridge-protocol.ts +6 -0
- package/src/v1/harness-v1-lifecycle-state.ts +7 -0
- package/src/v1/harness-v1-session.ts +0 -14
- package/src/v1/harness-v1-stream-part.ts +31 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.94",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@ai-sdk/provider": "4.0.
|
|
48
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
49
|
-
"ai": "7.0.
|
|
47
|
+
"@ai-sdk/provider": "4.0.9",
|
|
48
|
+
"@ai-sdk/provider-utils": "5.0.34",
|
|
49
|
+
"ai": "7.0.85"
|
|
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.85",
|
|
62
62
|
"@opentelemetry/sdk-trace-base": "2.7.1",
|
|
63
63
|
"@types/node": "22.19.19",
|
|
64
64
|
"@types/ws": "^8.5.13",
|
|
@@ -195,6 +195,7 @@ export class HarnessAgentSession {
|
|
|
195
195
|
OUTPUT extends Output,
|
|
196
196
|
>(options: {
|
|
197
197
|
prompt: HarnessAgentPrompt;
|
|
198
|
+
model: string | undefined;
|
|
198
199
|
skills: ReadonlyArray<HarnessV1Skill>;
|
|
199
200
|
instructions: string | undefined;
|
|
200
201
|
tools: TOOLS;
|
|
@@ -211,6 +212,7 @@ export class HarnessAgentSession {
|
|
|
211
212
|
const session = this.requireReusableSession();
|
|
212
213
|
this.requirePromptableTurn();
|
|
213
214
|
this.persistedTurnSettings = {
|
|
215
|
+
...(options.model == null ? {} : { model: options.model }),
|
|
214
216
|
skills: options.skills,
|
|
215
217
|
...(options.instructions == null
|
|
216
218
|
? {}
|
|
@@ -230,6 +232,7 @@ export class HarnessAgentSession {
|
|
|
230
232
|
harness: this.harness,
|
|
231
233
|
session,
|
|
232
234
|
prompt: options.prompt,
|
|
235
|
+
model: options.model,
|
|
233
236
|
skills: options.skills,
|
|
234
237
|
instructions: options.instructions,
|
|
235
238
|
tools: options.tools,
|
|
@@ -290,6 +293,7 @@ export class HarnessAgentSession {
|
|
|
290
293
|
RUNTIME_CONTEXT extends Context,
|
|
291
294
|
OUTPUT extends Output,
|
|
292
295
|
>(options: {
|
|
296
|
+
model: string | undefined;
|
|
293
297
|
skills: ReadonlyArray<HarnessV1Skill>;
|
|
294
298
|
instructions: string | undefined;
|
|
295
299
|
tools: TOOLS;
|
|
@@ -312,6 +316,7 @@ export class HarnessAgentSession {
|
|
|
312
316
|
const session = this.requireReusableSession();
|
|
313
317
|
this.requireContinuableTurn();
|
|
314
318
|
const turnSettings = this.resolveActiveTurnSettings({
|
|
319
|
+
model: options.model,
|
|
315
320
|
skills: options.skills,
|
|
316
321
|
instructions: options.instructions,
|
|
317
322
|
tools: options.tools,
|
|
@@ -326,6 +331,7 @@ export class HarnessAgentSession {
|
|
|
326
331
|
harness: this.harness,
|
|
327
332
|
session,
|
|
328
333
|
mode: 'continue',
|
|
334
|
+
model: turnSettings.persisted.model,
|
|
329
335
|
skills: turnSettings.persisted.skills,
|
|
330
336
|
instructions: turnSettings.persisted.instructions,
|
|
331
337
|
tools: turnSettings.tools as TOOLS,
|
|
@@ -753,6 +759,7 @@ export class HarnessAgentSession {
|
|
|
753
759
|
}
|
|
754
760
|
|
|
755
761
|
private resolveActiveTurnSettings(options: {
|
|
762
|
+
model: string | undefined;
|
|
756
763
|
skills: ReadonlyArray<HarnessV1Skill>;
|
|
757
764
|
instructions: string | undefined;
|
|
758
765
|
tools: ToolSet;
|
|
@@ -766,6 +773,7 @@ export class HarnessAgentSession {
|
|
|
766
773
|
const persisted =
|
|
767
774
|
this.persistedTurnSettings ??
|
|
768
775
|
({
|
|
776
|
+
...(options.model == null ? {} : { model: options.model }),
|
|
769
777
|
skills: options.skills,
|
|
770
778
|
...(options.instructions == null
|
|
771
779
|
? {}
|
|
@@ -80,8 +80,8 @@ type HarnessTools<TOOLS extends ToolSet> = ActiveTools<NoInfer<TOOLS>>;
|
|
|
80
80
|
*
|
|
81
81
|
* Prompt, abortSignal, callbacks, and custom call options belong on the
|
|
82
82
|
* `AgentCallParameters` / `AgentStreamParameters` passed to `generate` /
|
|
83
|
-
* `stream`. `prepareCall` can derive turn-scoped skills, instructions,
|
|
84
|
-
* tools from those custom call options.
|
|
83
|
+
* `stream`. `prepareCall` can derive turn-scoped model, skills, instructions,
|
|
84
|
+
* and tools from those custom call options.
|
|
85
85
|
*/
|
|
86
86
|
type HarnessAgentToolFilteringSettings<TOOLS extends ToolSet> =
|
|
87
87
|
| {
|
|
@@ -122,8 +122,9 @@ export type HarnessAgentSettings<
|
|
|
122
122
|
readonly id?: string;
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
|
-
* Model identifier
|
|
126
|
-
*
|
|
125
|
+
* Model identifier used by the harness adapter. Supported values are
|
|
126
|
+
* defined by the selected harness. `prepareCall` can replace it between
|
|
127
|
+
* completed turns.
|
|
127
128
|
*/
|
|
128
129
|
readonly model?: string;
|
|
129
130
|
|
|
@@ -203,7 +204,7 @@ export type HarnessAgentSettings<
|
|
|
203
204
|
NoInfer<OUTPUT>,
|
|
204
205
|
CALL_OPTIONS
|
|
205
206
|
>,
|
|
206
|
-
'skills' | 'instructions' | 'tools'
|
|
207
|
+
'model' | 'skills' | 'instructions' | 'tools'
|
|
207
208
|
>,
|
|
208
209
|
) => MaybePromiseLike<
|
|
209
210
|
Pick<
|
|
@@ -214,7 +215,7 @@ export type HarnessAgentSettings<
|
|
|
214
215
|
NoInfer<OUTPUT>,
|
|
215
216
|
CALL_OPTIONS
|
|
216
217
|
>,
|
|
217
|
-
'skills' | 'instructions' | 'tools'
|
|
218
|
+
'model' | 'skills' | 'instructions' | 'tools'
|
|
218
219
|
> &
|
|
219
220
|
Omit<Prompt, 'system' | 'instructions' | 'allowSystemInMessages'>
|
|
220
221
|
>;
|
|
@@ -94,6 +94,7 @@ type PreparedHarnessAgentTurnSettings<
|
|
|
94
94
|
THarness extends HarnessAgentAdapter<any>,
|
|
95
95
|
TUserTools extends ToolSet,
|
|
96
96
|
> = {
|
|
97
|
+
model: string | undefined;
|
|
97
98
|
skills: ReadonlyArray<HarnessAgentSkill>;
|
|
98
99
|
instructions: string | undefined;
|
|
99
100
|
tools: HarnessAllTools<THarness, TUserTools>;
|
|
@@ -499,7 +500,6 @@ export class HarnessAgent<
|
|
|
499
500
|
|
|
500
501
|
try {
|
|
501
502
|
const baseStartOptions = {
|
|
502
|
-
model: this.settings.model,
|
|
503
503
|
sessionId,
|
|
504
504
|
resumeFrom: validatedResumeFrom,
|
|
505
505
|
continueFrom: effectiveContinueFrom,
|
|
@@ -746,6 +746,7 @@ export class HarnessAgent<
|
|
|
746
746
|
responseFormat: HarnessV1ResponseFormat | undefined;
|
|
747
747
|
}) {
|
|
748
748
|
return {
|
|
749
|
+
model: input.turnSettings.model,
|
|
749
750
|
skills: input.turnSettings.skills,
|
|
750
751
|
instructions: input.turnSettings.instructions,
|
|
751
752
|
tools: input.turnSettings.tools,
|
|
@@ -864,6 +865,7 @@ export class HarnessAgent<
|
|
|
864
865
|
} = callOptions;
|
|
865
866
|
|
|
866
867
|
const baseCallArgs = {
|
|
868
|
+
model: this.settings.model,
|
|
867
869
|
skills: this.settings.skills,
|
|
868
870
|
instructions: this.settings.instructions,
|
|
869
871
|
tools: this.settings.tools,
|
|
@@ -892,6 +894,7 @@ export class HarnessAgent<
|
|
|
892
894
|
return {
|
|
893
895
|
prompt: this._resolvePromptTurnInput(preparedCallArgs),
|
|
894
896
|
...this._prepareTurnSettings({
|
|
897
|
+
model: preparedCallArgs.model,
|
|
895
898
|
skills: preparedCallArgs.skills,
|
|
896
899
|
instructions: preparedCallArgs.instructions,
|
|
897
900
|
tools: preparedCallArgs.tools,
|
|
@@ -905,6 +908,7 @@ export class HarnessAgent<
|
|
|
905
908
|
}): PreparedHarnessAgentContinueTurnInput<THarness, TUserTools> {
|
|
906
909
|
return {
|
|
907
910
|
...this._prepareTurnSettings({
|
|
911
|
+
model: this.settings.model,
|
|
908
912
|
skills: this.settings.skills,
|
|
909
913
|
instructions: this.settings.instructions,
|
|
910
914
|
tools: this.settings.tools,
|
|
@@ -915,6 +919,7 @@ export class HarnessAgent<
|
|
|
915
919
|
}
|
|
916
920
|
|
|
917
921
|
private _prepareTurnSettings(options: {
|
|
922
|
+
model?: string;
|
|
918
923
|
skills?: ReadonlyArray<HarnessAgentSkill>;
|
|
919
924
|
instructions?: string;
|
|
920
925
|
tools?: TUserTools;
|
|
@@ -932,6 +937,7 @@ export class HarnessAgent<
|
|
|
932
937
|
inactiveTools: this.settings.inactiveTools,
|
|
933
938
|
});
|
|
934
939
|
return {
|
|
940
|
+
model: options.model,
|
|
935
941
|
skills: options.skills ?? [],
|
|
936
942
|
instructions: options.instructions,
|
|
937
943
|
tools,
|
|
@@ -44,7 +44,7 @@ import type { HarnessAgentToolResultContinuation } from '../harness-agent-tool-r
|
|
|
44
44
|
import type { HarnessAgentToolApprovalConfiguration } from '../harness-agent-settings';
|
|
45
45
|
import { HarnessStreamTextResult } from './harness-stream-text-result';
|
|
46
46
|
import { translateStreamPart } from './translate-stream-part';
|
|
47
|
-
import { stripWorkDir } from './strip-work-dir';
|
|
47
|
+
import { createToolInputWorkDirStripper, stripWorkDir } from './strip-work-dir';
|
|
48
48
|
import {
|
|
49
49
|
createTurnTelemetry,
|
|
50
50
|
type TurnContentPart,
|
|
@@ -81,6 +81,7 @@ export function runPrompt<
|
|
|
81
81
|
mode?: 'prompt' | 'continue';
|
|
82
82
|
/** Required for `mode: 'prompt'`; absent for `mode: 'continue'`. */
|
|
83
83
|
prompt?: HarnessV1Prompt;
|
|
84
|
+
model?: string;
|
|
84
85
|
skills?: ReadonlyArray<HarnessV1Skill>;
|
|
85
86
|
instructions: string | undefined;
|
|
86
87
|
tools: TOOLS;
|
|
@@ -141,7 +142,7 @@ export function runPrompt<
|
|
|
141
142
|
const telemetry = createTurnTelemetry({
|
|
142
143
|
telemetry: input.telemetry,
|
|
143
144
|
harnessId: input.harness.harnessId,
|
|
144
|
-
modelId: input.
|
|
145
|
+
modelId: input.model,
|
|
145
146
|
instructions: input.instructions,
|
|
146
147
|
promptText: input.prompt != null ? promptToText(input.prompt) : '',
|
|
147
148
|
runtimeContext: input.runtimeContext,
|
|
@@ -181,6 +182,7 @@ export function runPrompt<
|
|
|
181
182
|
input.mode === 'continue'
|
|
182
183
|
? emit =>
|
|
183
184
|
input.session.doContinueTurn({
|
|
185
|
+
model: input.model,
|
|
184
186
|
skills: input.skills ?? [],
|
|
185
187
|
responseFormat: input.responseFormat,
|
|
186
188
|
tools: input.toolSpecs,
|
|
@@ -196,6 +198,7 @@ export function runPrompt<
|
|
|
196
198
|
}
|
|
197
199
|
return input.session.doPromptTurn({
|
|
198
200
|
prompt: input.prompt,
|
|
201
|
+
model: input.model,
|
|
199
202
|
skills: input.skills ?? [],
|
|
200
203
|
responseFormat: input.responseFormat,
|
|
201
204
|
tools: input.toolSpecs,
|
|
@@ -220,6 +223,9 @@ export function runPrompt<
|
|
|
220
223
|
const { stream, control } = bridge;
|
|
221
224
|
input.onPromptControlAvailable?.(control);
|
|
222
225
|
const reader = stream.getReader();
|
|
226
|
+
const stripToolInputWorkDir = createToolInputWorkDirStripper({
|
|
227
|
+
sessionWorkDir: input.sessionWorkDir,
|
|
228
|
+
});
|
|
223
229
|
const toolCallsByToolCallId = new Map<string, ToolCallTextStreamPart>();
|
|
224
230
|
const rawToolCallsByToolCallId = new Map<
|
|
225
231
|
string,
|
|
@@ -534,7 +540,7 @@ export function runPrompt<
|
|
|
534
540
|
input: approval.input,
|
|
535
541
|
} satisfies Extract<HarnessV1StreamPart, { type: 'tool-call' }>);
|
|
536
542
|
|
|
537
|
-
await telemetry.start(input.
|
|
543
|
+
await telemetry.start(input.model);
|
|
538
544
|
await telemetry.toolStart({
|
|
539
545
|
toolCallId: rawToolCall.toolCallId,
|
|
540
546
|
toolName: rawToolCall.toolName,
|
|
@@ -649,9 +655,9 @@ export function runPrompt<
|
|
|
649
655
|
}
|
|
650
656
|
|
|
651
657
|
// Begin the operation span on stream-start, using the runtime-resolved
|
|
652
|
-
// model the adapter reports (falling back to the
|
|
658
|
+
// model the adapter reports (falling back to the requested turn model).
|
|
653
659
|
if (value.type === 'stream-start') {
|
|
654
|
-
await telemetry.start(value.modelId ?? input.
|
|
660
|
+
await telemetry.start(value.modelId ?? input.model);
|
|
655
661
|
}
|
|
656
662
|
|
|
657
663
|
// Open a step span lazily before the first content of each step.
|
|
@@ -664,6 +670,28 @@ export function runPrompt<
|
|
|
664
670
|
await telemetry.ensureStepOpen();
|
|
665
671
|
}
|
|
666
672
|
|
|
673
|
+
if (
|
|
674
|
+
value.type === 'tool-input-start' ||
|
|
675
|
+
value.type === 'tool-input-delta' ||
|
|
676
|
+
value.type === 'tool-input-end'
|
|
677
|
+
) {
|
|
678
|
+
if (
|
|
679
|
+
settledHostToolCallIds.has(value.id) ||
|
|
680
|
+
settledBuiltinApprovalToolCallIds.has(value.id)
|
|
681
|
+
) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
for (const displayValue of stripToolInputWorkDir(value)) {
|
|
685
|
+
for (const part of translateStreamPart<TOOLS>(
|
|
686
|
+
displayValue,
|
|
687
|
+
translateOptions,
|
|
688
|
+
)) {
|
|
689
|
+
result.enqueue(part);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
|
|
667
695
|
/*
|
|
668
696
|
* Strip the session working-directory prefix for everything the
|
|
669
697
|
* consumer sees. The original `value` is kept intact for host tool
|
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
import type { HarnessV1StreamPart } from '../../v1';
|
|
2
2
|
|
|
3
|
+
type ToolInputStreamPart = Extract<
|
|
4
|
+
HarnessV1StreamPart,
|
|
5
|
+
{
|
|
6
|
+
type: 'tool-input-start' | 'tool-input-delta' | 'tool-input-end';
|
|
7
|
+
}
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export function createToolInputWorkDirStripper({
|
|
11
|
+
sessionWorkDir,
|
|
12
|
+
}: {
|
|
13
|
+
sessionWorkDir: string;
|
|
14
|
+
}): (part: ToolInputStreamPart) => ToolInputStreamPart[] {
|
|
15
|
+
const pendingByToolCallId = new Map<string, string>();
|
|
16
|
+
|
|
17
|
+
return part => {
|
|
18
|
+
if (sessionWorkDir.length === 0) return [part];
|
|
19
|
+
|
|
20
|
+
if (part.type === 'tool-input-start') {
|
|
21
|
+
pendingByToolCallId.set(part.id, '');
|
|
22
|
+
return [part];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (part.type === 'tool-input-delta') {
|
|
26
|
+
const stripped = stripStreamingString({
|
|
27
|
+
value: (pendingByToolCallId.get(part.id) ?? '') + part.delta,
|
|
28
|
+
workDir: sessionWorkDir,
|
|
29
|
+
final: false,
|
|
30
|
+
});
|
|
31
|
+
pendingByToolCallId.set(part.id, stripped.pending);
|
|
32
|
+
return stripped.output.length === 0
|
|
33
|
+
? []
|
|
34
|
+
: [{ ...part, delta: stripped.output }];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const pending = pendingByToolCallId.get(part.id);
|
|
38
|
+
pendingByToolCallId.delete(part.id);
|
|
39
|
+
if (pending == null || pending.length === 0) return [part];
|
|
40
|
+
|
|
41
|
+
const stripped = stripStreamingString({
|
|
42
|
+
value: pending,
|
|
43
|
+
workDir: sessionWorkDir,
|
|
44
|
+
final: true,
|
|
45
|
+
});
|
|
46
|
+
return stripped.output.length === 0
|
|
47
|
+
? [part]
|
|
48
|
+
: [
|
|
49
|
+
{ type: 'tool-input-delta', id: part.id, delta: stripped.output },
|
|
50
|
+
part,
|
|
51
|
+
];
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
3
55
|
/**
|
|
4
56
|
* Remove the session working-directory prefix from path-bearing fields of a
|
|
5
57
|
* stream event, returning a new event for display to consumers.
|
|
@@ -23,6 +75,8 @@ export function stripWorkDir(
|
|
|
23
75
|
if (sessionWorkDir.length === 0) return part;
|
|
24
76
|
|
|
25
77
|
switch (part.type) {
|
|
78
|
+
case 'tool-input-delta':
|
|
79
|
+
return { ...part, delta: stripString(part.delta, sessionWorkDir) };
|
|
26
80
|
case 'tool-call':
|
|
27
81
|
return { ...part, input: stripString(part.input, sessionWorkDir) };
|
|
28
82
|
case 'tool-result':
|
|
@@ -50,6 +104,54 @@ function stripString(value: string, workDir: string): string {
|
|
|
50
104
|
return value.split(`${workDir}/`).join('').split(workDir).join('.');
|
|
51
105
|
}
|
|
52
106
|
|
|
107
|
+
function stripStreamingString({
|
|
108
|
+
value,
|
|
109
|
+
workDir,
|
|
110
|
+
final,
|
|
111
|
+
}: {
|
|
112
|
+
value: string;
|
|
113
|
+
workDir: string;
|
|
114
|
+
final: boolean;
|
|
115
|
+
}): { output: string; pending: string } {
|
|
116
|
+
let remaining = value;
|
|
117
|
+
let output = '';
|
|
118
|
+
|
|
119
|
+
while (remaining.length > 0) {
|
|
120
|
+
const matchIndex = remaining.indexOf(workDir);
|
|
121
|
+
if (matchIndex >= 0) {
|
|
122
|
+
output += remaining.slice(0, matchIndex);
|
|
123
|
+
const followingIndex = matchIndex + workDir.length;
|
|
124
|
+
if (followingIndex === remaining.length && !final) {
|
|
125
|
+
return { output, pending: remaining.slice(matchIndex) };
|
|
126
|
+
}
|
|
127
|
+
if (remaining[followingIndex] === '/') {
|
|
128
|
+
remaining = remaining.slice(followingIndex + 1);
|
|
129
|
+
} else {
|
|
130
|
+
output += '.';
|
|
131
|
+
remaining = remaining.slice(followingIndex);
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (final) return { output: output + remaining, pending: '' };
|
|
137
|
+
|
|
138
|
+
let pendingLength = Math.min(remaining.length, workDir.length - 1);
|
|
139
|
+
while (
|
|
140
|
+
pendingLength > 0 &&
|
|
141
|
+
!workDir.startsWith(remaining.slice(-pendingLength))
|
|
142
|
+
) {
|
|
143
|
+
pendingLength -= 1;
|
|
144
|
+
}
|
|
145
|
+
const outputLength = remaining.length - pendingLength;
|
|
146
|
+
return {
|
|
147
|
+
output: output + remaining.slice(0, outputLength),
|
|
148
|
+
pending: remaining.slice(outputLength),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { output, pending: '' };
|
|
153
|
+
}
|
|
154
|
+
|
|
53
155
|
/**
|
|
54
156
|
* Recursively strip the working directory from every string nested in an
|
|
55
157
|
* arbitrary JSON-like value. Non-string leaves are returned unchanged.
|
|
@@ -103,6 +103,11 @@ export function translateStreamPart<TOOLS extends ToolSet>(
|
|
|
103
103
|
} as TextStreamPart<TOOLS>,
|
|
104
104
|
];
|
|
105
105
|
|
|
106
|
+
case 'tool-input-start':
|
|
107
|
+
case 'tool-input-delta':
|
|
108
|
+
case 'tool-input-end':
|
|
109
|
+
return [event as TextStreamPart<TOOLS>];
|
|
110
|
+
|
|
106
111
|
case 'tool-call':
|
|
107
112
|
// Tool-call validation is async (it parses input against the tool's
|
|
108
113
|
// schema) and lives in `run-prompt.ts` where the merged tool set is in
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
harnessV1TextStartPartSchema,
|
|
22
22
|
harnessV1ToolApprovalRequestPartSchema,
|
|
23
23
|
harnessV1ToolCallPartSchema,
|
|
24
|
+
harnessV1ToolInputDeltaPartSchema,
|
|
25
|
+
harnessV1ToolInputEndPartSchema,
|
|
26
|
+
harnessV1ToolInputStartPartSchema,
|
|
24
27
|
harnessV1ToolResultPartSchema,
|
|
25
28
|
} from './harness-v1-stream-part';
|
|
26
29
|
|
|
@@ -213,6 +216,9 @@ export const harnessV1BridgeOutboundMessageSchema = z.discriminatedUnion(
|
|
|
213
216
|
harnessV1ReasoningStartPartSchema,
|
|
214
217
|
harnessV1ReasoningDeltaPartSchema,
|
|
215
218
|
harnessV1ReasoningEndPartSchema,
|
|
219
|
+
harnessV1ToolInputStartPartSchema,
|
|
220
|
+
harnessV1ToolInputDeltaPartSchema,
|
|
221
|
+
harnessV1ToolInputEndPartSchema,
|
|
216
222
|
harnessV1ToolCallPartSchema,
|
|
217
223
|
harnessV1ToolApprovalRequestPartSchema,
|
|
218
224
|
harnessV1ToolResultPartSchema,
|
|
@@ -24,6 +24,13 @@ export type HarnessV1PendingToolResult = {
|
|
|
24
24
|
* so a resumed continuation cannot pick up configuration from a later turn.
|
|
25
25
|
*/
|
|
26
26
|
export type HarnessV1TurnSettings = {
|
|
27
|
+
/**
|
|
28
|
+
* Model identifier selected for this turn. Adapters interpret this value
|
|
29
|
+
* according to the underlying harness runtime. Rerun-based continuations
|
|
30
|
+
* reuse it when reconstructing the turn.
|
|
31
|
+
*/
|
|
32
|
+
readonly model?: string;
|
|
33
|
+
|
|
27
34
|
/**
|
|
28
35
|
* Skills made available to the underlying runtime for this turn. Adapters
|
|
29
36
|
* must replace skills from the preceding completed turn before starting a
|
|
@@ -21,12 +21,6 @@ import type { HarnessV1BuiltinToolFiltering } from './harness-v1-tool-filtering'
|
|
|
21
21
|
* calling the adapter, so adapters never need to derive provider-specific paths.
|
|
22
22
|
*/
|
|
23
23
|
export type HarnessV1StartOptions = {
|
|
24
|
-
/**
|
|
25
|
-
* Model identifier selected by the consumer. Adapters interpret this value
|
|
26
|
-
* according to the underlying harness runtime.
|
|
27
|
-
*/
|
|
28
|
-
readonly model?: string;
|
|
29
|
-
|
|
30
24
|
/**
|
|
31
25
|
* Stable identifier for this harness session. Used as the underlying
|
|
32
26
|
* resource name where the adapter has a notion of a named session
|
|
@@ -171,14 +165,6 @@ export type HarnessV1Session = {
|
|
|
171
165
|
*/
|
|
172
166
|
readonly isResume: boolean;
|
|
173
167
|
|
|
174
|
-
/**
|
|
175
|
-
* The model id the underlying runtime is configured to use, if the adapter
|
|
176
|
-
* knows it (e.g. from its settings). Surfaced into telemetry as
|
|
177
|
-
* `gen_ai.request.model` and the trace span labels. Omitted when the adapter
|
|
178
|
-
* defers to the runtime's own default and has no concrete id.
|
|
179
|
-
*/
|
|
180
|
-
readonly modelId?: string;
|
|
181
|
-
|
|
182
168
|
/**
|
|
183
169
|
* Run one prompt turn. Returns a control handle the host uses to feed
|
|
184
170
|
* tool results, approvals, and user messages back into the turn while it
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
JSONValue,
|
|
3
3
|
LanguageModelV4FinishReason,
|
|
4
|
+
LanguageModelV4StreamPart,
|
|
4
5
|
LanguageModelV4ToolApprovalRequest,
|
|
5
6
|
LanguageModelV4ToolCall,
|
|
6
7
|
LanguageModelV4ToolResult,
|
|
@@ -58,7 +59,7 @@ export type HarnessV1StreamPart =
|
|
|
58
59
|
}
|
|
59
60
|
| { type: 'reasoning-end'; id: string; harnessMetadata?: HarnessV1Metadata }
|
|
60
61
|
|
|
61
|
-
// Tool calls, approvals, results — reuse V4 primitives.
|
|
62
|
+
// Tool inputs, calls, approvals, results — reuse V4 primitives.
|
|
62
63
|
//
|
|
63
64
|
// `nativeName` lets adapters surface the runtime's native name for a builtin
|
|
64
65
|
// when it differs from the wire `toolName` (e.g. `toolName: 'bash'`,
|
|
@@ -73,6 +74,9 @@ export type HarnessV1StreamPart =
|
|
|
73
74
|
// built-in `Bash`, Codex's `shell`) vs. needs host dispatch is signalled by
|
|
74
75
|
// the standard `providerExecuted` field on `LanguageModelV4ToolCall` —
|
|
75
76
|
// `true` for runtime-executed builtins, false/undefined for host tools.
|
|
77
|
+
| Extract<LanguageModelV4StreamPart, { type: 'tool-input-start' }>
|
|
78
|
+
| Extract<LanguageModelV4StreamPart, { type: 'tool-input-delta' }>
|
|
79
|
+
| Extract<LanguageModelV4StreamPart, { type: 'tool-input-end' }>
|
|
76
80
|
| (LanguageModelV4ToolCall & {
|
|
77
81
|
nativeName?: string;
|
|
78
82
|
/**
|
|
@@ -268,6 +272,29 @@ export const harnessV1ReasoningEndPartSchema = z.object({
|
|
|
268
272
|
harnessMetadata: harnessV1MetadataSchema.optional(),
|
|
269
273
|
});
|
|
270
274
|
|
|
275
|
+
export const harnessV1ToolInputStartPartSchema = z.object({
|
|
276
|
+
type: z.literal('tool-input-start'),
|
|
277
|
+
id: z.string(),
|
|
278
|
+
toolName: z.string(),
|
|
279
|
+
providerMetadata: harnessV1ProviderMetadataSchema.optional(),
|
|
280
|
+
providerExecuted: z.boolean().optional(),
|
|
281
|
+
dynamic: z.boolean().optional(),
|
|
282
|
+
title: z.string().optional(),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
export const harnessV1ToolInputDeltaPartSchema = z.object({
|
|
286
|
+
type: z.literal('tool-input-delta'),
|
|
287
|
+
id: z.string(),
|
|
288
|
+
delta: z.string(),
|
|
289
|
+
providerMetadata: harnessV1ProviderMetadataSchema.optional(),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
export const harnessV1ToolInputEndPartSchema = z.object({
|
|
293
|
+
type: z.literal('tool-input-end'),
|
|
294
|
+
id: z.string(),
|
|
295
|
+
providerMetadata: harnessV1ProviderMetadataSchema.optional(),
|
|
296
|
+
});
|
|
297
|
+
|
|
271
298
|
export const harnessV1ToolCallPartSchema = z.object({
|
|
272
299
|
type: z.literal('tool-call'),
|
|
273
300
|
toolCallId: z.string(),
|
|
@@ -352,6 +379,9 @@ export const harnessV1StreamPartSchema = z.discriminatedUnion('type', [
|
|
|
352
379
|
harnessV1ReasoningStartPartSchema,
|
|
353
380
|
harnessV1ReasoningDeltaPartSchema,
|
|
354
381
|
harnessV1ReasoningEndPartSchema,
|
|
382
|
+
harnessV1ToolInputStartPartSchema,
|
|
383
|
+
harnessV1ToolInputDeltaPartSchema,
|
|
384
|
+
harnessV1ToolInputEndPartSchema,
|
|
355
385
|
harnessV1ToolCallPartSchema,
|
|
356
386
|
harnessV1ToolApprovalRequestPartSchema,
|
|
357
387
|
harnessV1ToolResultPartSchema,
|