@ai-sdk/harness 1.0.93 → 1.0.95

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/harness",
3
- "version": "1.0.93",
3
+ "version": "1.0.95",
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.8",
48
- "@ai-sdk/provider-utils": "5.0.33",
49
- "ai": "7.0.84"
47
+ "@ai-sdk/provider": "4.0.9",
48
+ "@ai-sdk/provider-utils": "5.0.34",
49
+ "ai": "7.0.86"
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.84",
61
+ "@ai-sdk/otel": "1.0.86",
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, and
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 passed to the harness adapter when a session starts.
126
- * Supported values are defined by the selected harness.
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;
@@ -137,12 +138,27 @@ export function runPrompt<
137
138
  const onPendingToolResult = input.onPendingToolResult ?? (() => {});
138
139
  const onToolResultSettled = input.onToolResultSettled ?? (() => {});
139
140
  const activeTools = input.activeTools ?? input.tools;
141
+ const activeToolNames = Object.keys(input.tools).filter(
142
+ toolName =>
143
+ Object.prototype.hasOwnProperty.call(activeTools, toolName) ||
144
+ (Object.prototype.hasOwnProperty.call(
145
+ input.harness.builtinTools,
146
+ toolName,
147
+ ) &&
148
+ isHarnessV1BuiltinToolIncluded({
149
+ toolName,
150
+ toolFiltering: input.builtinToolFiltering,
151
+ })),
152
+ );
140
153
 
141
154
  const telemetry = createTurnTelemetry({
142
155
  telemetry: input.telemetry,
143
156
  harnessId: input.harness.harnessId,
144
- modelId: input.session.modelId,
157
+ modelId: input.model,
145
158
  instructions: input.instructions,
159
+ tools: input.tools,
160
+ activeToolNames,
161
+ toolSpecs: input.toolSpecs,
146
162
  promptText: input.prompt != null ? promptToText(input.prompt) : '',
147
163
  runtimeContext: input.runtimeContext,
148
164
  });
@@ -181,6 +197,7 @@ export function runPrompt<
181
197
  input.mode === 'continue'
182
198
  ? emit =>
183
199
  input.session.doContinueTurn({
200
+ model: input.model,
184
201
  skills: input.skills ?? [],
185
202
  responseFormat: input.responseFormat,
186
203
  tools: input.toolSpecs,
@@ -196,6 +213,7 @@ export function runPrompt<
196
213
  }
197
214
  return input.session.doPromptTurn({
198
215
  prompt: input.prompt,
216
+ model: input.model,
199
217
  skills: input.skills ?? [],
200
218
  responseFormat: input.responseFormat,
201
219
  tools: input.toolSpecs,
@@ -220,6 +238,9 @@ export function runPrompt<
220
238
  const { stream, control } = bridge;
221
239
  input.onPromptControlAvailable?.(control);
222
240
  const reader = stream.getReader();
241
+ const stripToolInputWorkDir = createToolInputWorkDirStripper({
242
+ sessionWorkDir: input.sessionWorkDir,
243
+ });
223
244
  const toolCallsByToolCallId = new Map<string, ToolCallTextStreamPart>();
224
245
  const rawToolCallsByToolCallId = new Map<
225
246
  string,
@@ -534,7 +555,7 @@ export function runPrompt<
534
555
  input: approval.input,
535
556
  } satisfies Extract<HarnessV1StreamPart, { type: 'tool-call' }>);
536
557
 
537
- await telemetry.start(input.session.modelId);
558
+ await telemetry.start(input.model);
538
559
  await telemetry.toolStart({
539
560
  toolCallId: rawToolCall.toolCallId,
540
561
  toolName: rawToolCall.toolName,
@@ -649,9 +670,9 @@ export function runPrompt<
649
670
  }
650
671
 
651
672
  // Begin the operation span on stream-start, using the runtime-resolved
652
- // model the adapter reports (falling back to the session's model).
673
+ // model the adapter reports (falling back to the requested turn model).
653
674
  if (value.type === 'stream-start') {
654
- await telemetry.start(value.modelId ?? input.session.modelId);
675
+ await telemetry.start(value.modelId ?? input.model);
655
676
  }
656
677
 
657
678
  // Open a step span lazily before the first content of each step.
@@ -664,6 +685,28 @@ export function runPrompt<
664
685
  await telemetry.ensureStepOpen();
665
686
  }
666
687
 
688
+ if (
689
+ value.type === 'tool-input-start' ||
690
+ value.type === 'tool-input-delta' ||
691
+ value.type === 'tool-input-end'
692
+ ) {
693
+ if (
694
+ settledHostToolCallIds.has(value.id) ||
695
+ settledBuiltinApprovalToolCallIds.has(value.id)
696
+ ) {
697
+ continue;
698
+ }
699
+ for (const displayValue of stripToolInputWorkDir(value)) {
700
+ for (const part of translateStreamPart<TOOLS>(
701
+ displayValue,
702
+ translateOptions,
703
+ )) {
704
+ result.enqueue(part);
705
+ }
706
+ }
707
+ continue;
708
+ }
709
+
667
710
  /*
668
711
  * Strip the session working-directory prefix for everything the
669
712
  * 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
@@ -1,6 +1,11 @@
1
- import { generateId, type ModelMessage } from '@ai-sdk/provider-utils';
1
+ import {
2
+ generateId,
3
+ type ModelMessage,
4
+ type ToolSet,
5
+ } from '@ai-sdk/provider-utils';
2
6
  import { createTelemetryDispatcher } from 'ai/internal';
3
7
  import type { LanguageModelUsage, TelemetryOptions } from 'ai';
8
+ import type { HarnessV1ToolSpec } from '../../v1';
4
9
 
5
10
  /*
6
11
  * Drives AI SDK's pluggable `Telemetry` lifecycle from a harness turn.
@@ -13,8 +18,9 @@ import type { LanguageModelUsage, TelemetryOptions } from 'ai';
13
18
  * step boundary, tool-calls = tool executions, `finish` = operation end. The
14
19
  * model-call-only event fields the harness has no value for (sampling params,
15
20
  * standardized prompt) are left `undefined` / cast; the fields the integrations
16
- * actually read (`callId`, `operationId`, `provider`, `modelId`, `messages`,
17
- * `toolCall`, `usage`, `finishReason`) carry real values.
21
+ * actually read (`callId`, `operationId`, `provider`, `modelId`,
22
+ * `instructions`, `messages`, `tools`, `toolCall`, `usage`, `finishReason`)
23
+ * carry real values.
18
24
  *
19
25
  * Telemetry is opt-in: the framework only drives it when `settings.telemetry`
20
26
  * is set (the dispatcher then also honours globally-registered integrations).
@@ -160,6 +166,9 @@ export function createTurnTelemetry(opts: {
160
166
  harnessId: string;
161
167
  modelId: string | undefined;
162
168
  instructions: string | undefined;
169
+ tools: ToolSet;
170
+ activeToolNames: string[];
171
+ toolSpecs: HarnessV1ToolSpec[];
163
172
  promptText: string;
164
173
  runtimeContext: unknown;
165
174
  }): TurnTelemetry {
@@ -177,6 +186,19 @@ export function createTurnTelemetry(opts: {
177
186
  const inputMessages: ModelMessage[] = [
178
187
  { role: 'user', content: opts.promptText },
179
188
  ];
189
+ const languageModelTools =
190
+ opts.toolSpecs.length === 0
191
+ ? undefined
192
+ : opts.toolSpecs.map(tool => ({
193
+ type: 'function' as const,
194
+ name: tool.name,
195
+ ...(tool.description != null
196
+ ? { description: tool.description }
197
+ : {}),
198
+ ...(tool.inputSchema != null
199
+ ? { inputSchema: tool.inputSchema }
200
+ : {}),
201
+ }));
180
202
 
181
203
  let started = false;
182
204
  let stepOpen = false;
@@ -211,9 +233,9 @@ export function createTurnTelemetry(opts: {
211
233
  operationId: 'ai.harness',
212
234
  provider,
213
235
  modelId,
214
- tools: undefined,
236
+ tools: opts.tools,
215
237
  toolChoice: undefined,
216
- activeTools: undefined,
238
+ activeTools: opts.activeToolNames,
217
239
  maxRetries: 0,
218
240
  timeout: undefined,
219
241
  headers: undefined,
@@ -243,13 +265,14 @@ export function createTurnTelemetry(opts: {
243
265
  provider,
244
266
  modelId,
245
267
  stepNumber,
246
- tools: undefined,
268
+ tools: opts.tools,
247
269
  toolChoice: undefined,
248
- activeTools: undefined,
270
+ activeTools: opts.activeToolNames,
249
271
  steps: new Array(stepNumber),
250
272
  providerOptions: undefined,
251
273
  output: undefined,
252
274
  runtimeContext,
275
+ instructions: opts.instructions,
253
276
  messages: inputMessages,
254
277
  }),
255
278
  );
@@ -260,8 +283,9 @@ export function createTurnTelemetry(opts: {
260
283
  callId,
261
284
  provider,
262
285
  modelId,
286
+ instructions: opts.instructions,
263
287
  messages: inputMessages,
264
- tools: undefined,
288
+ tools: languageModelTools,
265
289
  }),
266
290
  );
267
291
  };
@@ -279,6 +303,8 @@ export function createTurnTelemetry(opts: {
279
303
  await dispatcher.onLanguageModelCallEnd?.(
280
304
  cast<'onLanguageModelCallEnd'>({
281
305
  callId,
306
+ provider,
307
+ modelId,
282
308
  finishReason,
283
309
  responseId: callId,
284
310
  usage,
@@ -0,0 +1,18 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import type { HarnessV1PortEndpoint } from '../v1';
3
+
4
+ export function createBridgeToken(): string {
5
+ return randomBytes(32).toString('hex');
6
+ }
7
+
8
+ export function withBridgeToken({
9
+ endpoint,
10
+ token,
11
+ }: {
12
+ endpoint: HarnessV1PortEndpoint;
13
+ token: string;
14
+ }): HarnessV1PortEndpoint {
15
+ const bridgeUrl = new URL(endpoint.url);
16
+ bridgeUrl.searchParams.set('agent_bridge_token', token);
17
+ return { ...endpoint, url: bridgeUrl.toString() };
18
+ }
@@ -40,6 +40,7 @@ export {
40
40
  type WaitForBridgeReadyOptions,
41
41
  type WaitForBridgeReadyResult,
42
42
  } from './bridge-ready';
43
+ export { createBridgeToken, withBridgeToken } from './bridge-token';
43
44
  export {
44
45
  createBridgeErrorHandler,
45
46
  createBridgeStartupError,
@@ -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