@ai-sdk/harness 1.0.72 → 1.0.73

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.
@@ -24,9 +24,11 @@ import {
24
24
  type CallWarning,
25
25
  type ContentPart,
26
26
  type FinishReason,
27
- type GenerateTextResult,
28
27
  type InferUIMessageChunk,
28
+ type InferGenerateOutput,
29
+ type InferStreamOutput,
29
30
  type LanguageModelUsage,
31
+ type OutputInterface as Output,
30
32
  type ProviderMetadata,
31
33
  type StepResult,
32
34
  type StreamTextResult,
@@ -38,8 +40,17 @@ import {
38
40
  type StreamProp<
39
41
  TOOLS extends ToolSet,
40
42
  RUNTIME_CONTEXT extends Context,
41
- KEY extends keyof StreamTextResult<TOOLS, RUNTIME_CONTEXT, never>,
42
- > = Awaited<StreamTextResult<TOOLS, RUNTIME_CONTEXT, never>[KEY]>;
43
+ OUTPUT extends Output,
44
+ KEY extends keyof StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>,
45
+ > = Awaited<StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>[KEY]>;
46
+
47
+ type InferElementOutput<OUTPUT extends Output> =
48
+ OUTPUT extends Output<any, any, infer ELEMENT> ? ELEMENT : never;
49
+
50
+ type EnrichedStreamPart<TOOLS extends ToolSet, PARTIAL_OUTPUT> = {
51
+ part: TextStreamPart<TOOLS>;
52
+ partialOutput: PARTIAL_OUTPUT | undefined;
53
+ };
43
54
 
44
55
  /**
45
56
  * Concrete `StreamTextResult` implementation backed by a single
@@ -57,68 +68,68 @@ type StreamProp<
57
68
  * `text`, `toolCalls`, `toolResults`, `reasoning`, etc. via its getters.
58
69
  *
59
70
  * The Node.js response helpers (`pipeUIMessageStreamToResponse`,
60
- * `pipeTextStreamToResponse`, `toTextStreamResponse`) and the
61
- * output-specification surfaces (`partialOutputStream`/`elementStream`) are not
62
- * implemented yet — they throw a clear error.
71
+ * `pipeTextStreamToResponse`, `toTextStreamResponse`) are not implemented yet
72
+ * and throw a clear error.
63
73
  */
64
74
  export class HarnessStreamTextResult<
65
75
  TOOLS extends ToolSet,
66
76
  RUNTIME_CONTEXT extends Context,
67
- > implements StreamTextResult<TOOLS, RUNTIME_CONTEXT, never> {
77
+ OUTPUT extends Output,
78
+ > implements StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
68
79
  // Delayed promises backing every PromiseLike accessor. Each is typed
69
80
  // against the corresponding `StreamTextResult` property so the public
70
81
  // surface stays in lockstep with AI SDK's interface as it evolves.
71
82
  private readonly _content = new DelayedPromise<
72
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'content'>
83
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'content'>
73
84
  >();
74
85
  private readonly _text = new DelayedPromise<
75
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'text'>
86
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'text'>
76
87
  >();
77
88
  private readonly _reasoning = new DelayedPromise<
78
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'reasoning'>
89
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'reasoning'>
79
90
  >();
80
91
  private readonly _reasoningText = new DelayedPromise<
81
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'reasoningText'>
92
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'reasoningText'>
82
93
  >();
83
94
  private readonly _files = new DelayedPromise<
84
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'files'>
95
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'files'>
85
96
  >();
86
97
  private readonly _sources = new DelayedPromise<
87
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'sources'>
98
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'sources'>
88
99
  >();
89
100
  private readonly _toolCalls = new DelayedPromise<
90
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'toolCalls'>
101
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'toolCalls'>
91
102
  >();
92
103
  private readonly _staticToolCalls = new DelayedPromise<
93
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'staticToolCalls'>
104
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'staticToolCalls'>
94
105
  >();
95
106
  private readonly _dynamicToolCalls = new DelayedPromise<
96
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'dynamicToolCalls'>
107
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'dynamicToolCalls'>
97
108
  >();
98
109
  private readonly _toolResults = new DelayedPromise<
99
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'toolResults'>
110
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'toolResults'>
100
111
  >();
101
112
  private readonly _staticToolResults = new DelayedPromise<
102
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'staticToolResults'>
113
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'staticToolResults'>
103
114
  >();
104
115
  private readonly _dynamicToolResults = new DelayedPromise<
105
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'dynamicToolResults'>
116
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'dynamicToolResults'>
106
117
  >();
107
118
  private readonly _finishReason = new DelayedPromise<FinishReason>();
108
119
  private readonly _rawFinishReason = new DelayedPromise<string | undefined>();
109
120
  private readonly _usage = new DelayedPromise<LanguageModelUsage>();
110
121
  private readonly _warnings = new DelayedPromise<CallWarning[] | undefined>();
111
122
  private readonly _steps = new DelayedPromise<
112
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'steps'>
123
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'steps'>
113
124
  >();
114
125
  private readonly _finalStep = new DelayedPromise<
115
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'finalStep'>
126
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'finalStep'>
116
127
  >();
117
128
  private readonly _request = new DelayedPromise<
118
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'request'>
129
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'request'>
119
130
  >();
120
131
  private readonly _response = new DelayedPromise<
121
- StreamProp<TOOLS, RUNTIME_CONTEXT, 'response'>
132
+ StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'response'>
122
133
  >();
123
134
  private readonly _responseMessages = new DelayedPromise<
124
135
  Array<AssistantModelMessage | ToolModelMessage>
@@ -131,11 +142,9 @@ export class HarnessStreamTextResult<
131
142
  private readonly fullStreamController: ReadableStreamDefaultController<
132
143
  TextStreamPart<TOOLS>
133
144
  >;
134
- readonly stream: AsyncIterableStream<TextStreamPart<TOOLS>>;
135
- // `fullStream` is the deprecated alias that AI SDK still exposes on the
136
- // public interface. Backed by the same underlying stream as `stream`.
137
- readonly fullStream: AsyncIterableStream<TextStreamPart<TOOLS>>;
138
- readonly textStream: AsyncIterableStream<string>;
145
+ private baseStream: ReadableStream<
146
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>
147
+ >;
139
148
 
140
149
  private readonly stepsBuffer: StepResult<TOOLS, RUNTIME_CONTEXT>[] = [];
141
150
  private currentStepContent: ContentPart<TOOLS>[] = [];
@@ -148,6 +157,7 @@ export class HarnessStreamTextResult<
148
157
  private readonly toolsContext: never;
149
158
  private readonly providerName: string;
150
159
  private readonly modelId: string;
160
+ private readonly outputSpecification: OUTPUT | undefined;
151
161
 
152
162
  // Accumulators that span the whole turn.
153
163
  private accumulatedUsage: LanguageModelUsage = createNullLanguageModelUsage();
@@ -163,12 +173,14 @@ export class HarnessStreamTextResult<
163
173
  toolsContext: never;
164
174
  harnessId: string;
165
175
  sessionId: string;
176
+ output: OUTPUT | undefined;
166
177
  }) {
167
178
  this.tools = options.tools;
168
179
  this.runtimeContext = options.runtimeContext;
169
180
  this.toolsContext = options.toolsContext;
170
181
  this.providerName = `harness:${options.harnessId}`;
171
182
  this.modelId = options.sessionId;
183
+ this.outputSpecification = options.output;
172
184
 
173
185
  let controllerRef!: ReadableStreamDefaultController<TextStreamPart<TOOLS>>;
174
186
  const baseStream = new ReadableStream<TextStreamPart<TOOLS>>({
@@ -185,18 +197,19 @@ export class HarnessStreamTextResult<
185
197
  });
186
198
  this.fullStreamController = controllerRef;
187
199
 
188
- const [forFull, forText] = baseStream.tee();
189
- this.stream = forFull as AsyncIterableStream<TextStreamPart<TOOLS>>;
190
- this.fullStream = this.stream;
191
- this.textStream = forText.pipeThrough(
192
- new TransformStream<TextStreamPart<TOOLS>, string>({
193
- transform(part, controller) {
194
- if (part.type === 'text-delta') {
195
- controller.enqueue(part.text);
196
- }
197
- },
198
- }),
199
- ) as AsyncIterableStream<string>;
200
+ this.baseStream =
201
+ options.output == null
202
+ ? baseStream.pipeThrough(
203
+ new TransformStream<
204
+ TextStreamPart<TOOLS>,
205
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>
206
+ >({
207
+ transform(part, controller) {
208
+ controller.enqueue({ part, partialOutput: undefined });
209
+ },
210
+ }),
211
+ )
212
+ : baseStream.pipeThrough(createOutputTransformStream(options.output));
200
213
  }
201
214
 
202
215
  // ─── Writer-side methods used by the driver ────────────────────────
@@ -375,7 +388,12 @@ export class HarnessStreamTextResult<
375
388
  const aggregatedContent = this.stepsBuffer.flatMap(s => s.content);
376
389
 
377
390
  this._content.resolve(
378
- aggregatedContent as StreamProp<TOOLS, RUNTIME_CONTEXT, 'content'>,
391
+ aggregatedContent as StreamProp<
392
+ TOOLS,
393
+ RUNTIME_CONTEXT,
394
+ OUTPUT,
395
+ 'content'
396
+ >,
379
397
  );
380
398
  this._text.resolve(finalStep.text);
381
399
  // Reasoning content parts are not yet derived from harness events; the
@@ -383,7 +401,7 @@ export class HarnessStreamTextResult<
383
401
  // deltas can be wired up to produce real reasoning content in a later
384
402
  // pass.
385
403
  this._reasoning.resolve(
386
- [] as StreamProp<TOOLS, RUNTIME_CONTEXT, 'reasoning'>,
404
+ [] as StreamProp<TOOLS, RUNTIME_CONTEXT, OUTPUT, 'reasoning'>,
387
405
  );
388
406
  this._reasoningText.resolve(undefined);
389
407
  this._files.resolve(this.stepsBuffer.flatMap(s => s.files));
@@ -392,6 +410,7 @@ export class HarnessStreamTextResult<
392
410
  this.stepsBuffer.flatMap(s => s.toolCalls) as StreamProp<
393
411
  TOOLS,
394
412
  RUNTIME_CONTEXT,
413
+ OUTPUT,
395
414
  'toolCalls'
396
415
  >,
397
416
  );
@@ -399,6 +418,7 @@ export class HarnessStreamTextResult<
399
418
  this.stepsBuffer.flatMap(s => s.staticToolCalls) as StreamProp<
400
419
  TOOLS,
401
420
  RUNTIME_CONTEXT,
421
+ OUTPUT,
402
422
  'staticToolCalls'
403
423
  >,
404
424
  );
@@ -406,6 +426,7 @@ export class HarnessStreamTextResult<
406
426
  this.stepsBuffer.flatMap(s => s.dynamicToolCalls) as StreamProp<
407
427
  TOOLS,
408
428
  RUNTIME_CONTEXT,
429
+ OUTPUT,
409
430
  'dynamicToolCalls'
410
431
  >,
411
432
  );
@@ -413,6 +434,7 @@ export class HarnessStreamTextResult<
413
434
  this.stepsBuffer.flatMap(s => s.toolResults) as StreamProp<
414
435
  TOOLS,
415
436
  RUNTIME_CONTEXT,
437
+ OUTPUT,
416
438
  'toolResults'
417
439
  >,
418
440
  );
@@ -420,6 +442,7 @@ export class HarnessStreamTextResult<
420
442
  this.stepsBuffer.flatMap(s => s.staticToolResults) as StreamProp<
421
443
  TOOLS,
422
444
  RUNTIME_CONTEXT,
445
+ OUTPUT,
423
446
  'staticToolResults'
424
447
  >,
425
448
  );
@@ -427,6 +450,7 @@ export class HarnessStreamTextResult<
427
450
  this.stepsBuffer.flatMap(s => s.dynamicToolResults) as StreamProp<
428
451
  TOOLS,
429
452
  RUNTIME_CONTEXT,
453
+ OUTPUT,
430
454
  'dynamicToolResults'
431
455
  >,
432
456
  );
@@ -529,6 +553,47 @@ export class HarnessStreamTextResult<
529
553
 
530
554
  // ─── Reader-side public surface (StreamTextResult contract) ────────
531
555
 
556
+ private teeStream(): ReadableStream<
557
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>
558
+ > {
559
+ const [stream, remainingStream] = this.baseStream.tee();
560
+ this.baseStream = remainingStream;
561
+ return stream;
562
+ }
563
+
564
+ get stream(): AsyncIterableStream<TextStreamPart<TOOLS>> {
565
+ return createAsyncIterableStream(
566
+ this.teeStream().pipeThrough(
567
+ new TransformStream<
568
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>,
569
+ TextStreamPart<TOOLS>
570
+ >({
571
+ transform({ part }, controller) {
572
+ controller.enqueue(part);
573
+ },
574
+ }),
575
+ ),
576
+ ) as AsyncIterableStream<TextStreamPart<TOOLS>>;
577
+ }
578
+
579
+ get fullStream(): AsyncIterableStream<TextStreamPart<TOOLS>> {
580
+ return this.stream;
581
+ }
582
+
583
+ get textStream(): AsyncIterableStream<string> {
584
+ return createAsyncIterableStream(
585
+ this.stream.pipeThrough(
586
+ new TransformStream<TextStreamPart<TOOLS>, string>({
587
+ transform(part, controller) {
588
+ if (part.type === 'text-delta') {
589
+ controller.enqueue(part.text);
590
+ }
591
+ },
592
+ }),
593
+ ),
594
+ ) as AsyncIterableStream<string>;
595
+ }
596
+
532
597
  get content() {
533
598
  return this._content.promise;
534
599
  }
@@ -599,18 +664,55 @@ export class HarnessStreamTextResult<
599
664
  return this._providerMetadata.promise;
600
665
  }
601
666
 
602
- // Output-specification surfaces are not yet supported.
603
- get experimental_partialOutputStream(): never {
604
- throw notSupportedYet('partial output stream');
605
- }
606
- get partialOutputStream(): never {
607
- throw notSupportedYet('partial output stream');
667
+ get experimental_partialOutputStream(): AsyncIterableStream<
668
+ InferStreamOutput<OUTPUT>
669
+ > {
670
+ return this.partialOutputStream;
608
671
  }
609
- get elementStream(): never {
610
- throw notSupportedYet('element stream');
672
+
673
+ get partialOutputStream(): AsyncIterableStream<InferStreamOutput<OUTPUT>> {
674
+ return createAsyncIterableStream(
675
+ this.teeStream().pipeThrough(
676
+ new TransformStream<
677
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>,
678
+ InferStreamOutput<OUTPUT>
679
+ >({
680
+ transform({ partialOutput }, controller) {
681
+ if (partialOutput != null) {
682
+ controller.enqueue(partialOutput);
683
+ }
684
+ },
685
+ }),
686
+ ),
687
+ ) as AsyncIterableStream<InferStreamOutput<OUTPUT>>;
688
+ }
689
+
690
+ get elementStream(): AsyncIterableStream<InferElementOutput<OUTPUT>> {
691
+ const transform = this.outputSpecification?.createElementStreamTransform();
692
+ if (transform == null) {
693
+ throw notSupportedYet(
694
+ `element streams in ${this.outputSpecification?.name ?? 'text'} mode`,
695
+ );
696
+ }
697
+ return createAsyncIterableStream(
698
+ this.teeStream().pipeThrough(transform),
699
+ ) as AsyncIterableStream<InferElementOutput<OUTPUT>>;
611
700
  }
612
- get output(): never {
613
- throw notSupportedYet('structured output');
701
+
702
+ get output(): Promise<InferGenerateOutput<OUTPUT>> {
703
+ return this.finalStep.then(step => {
704
+ if (this.outputSpecification == null) {
705
+ throw notSupportedYet('structured output');
706
+ }
707
+ return this.outputSpecification.parseCompleteOutput(
708
+ { text: step.text },
709
+ {
710
+ response: step.response,
711
+ usage: step.usage,
712
+ finishReason: step.finishReason,
713
+ },
714
+ );
715
+ });
614
716
  }
615
717
 
616
718
  async consumeStream(): Promise<void> {
@@ -750,6 +852,103 @@ export class HarnessStreamTextResult<
750
852
  }
751
853
  }
752
854
 
855
+ function createOutputTransformStream<
856
+ TOOLS extends ToolSet,
857
+ OUTPUT extends Output,
858
+ >(
859
+ output: OUTPUT,
860
+ ): TransformStream<
861
+ TextStreamPart<TOOLS>,
862
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>
863
+ > {
864
+ let firstTextChunkId: string | undefined;
865
+ let text = '';
866
+ let textChunk = '';
867
+ let textProviderMetadata: ProviderMetadata | undefined;
868
+ let lastPublishedValue = '';
869
+
870
+ const publishTextChunk = (options: {
871
+ controller: TransformStreamDefaultController<
872
+ EnrichedStreamPart<TOOLS, InferStreamOutput<OUTPUT>>
873
+ >;
874
+ partialOutput?: InferStreamOutput<OUTPUT>;
875
+ }): void => {
876
+ options.controller.enqueue({
877
+ part: {
878
+ type: 'text-delta',
879
+ id: firstTextChunkId!,
880
+ text: textChunk,
881
+ providerMetadata: textProviderMetadata,
882
+ },
883
+ partialOutput: options.partialOutput,
884
+ });
885
+ textChunk = '';
886
+ };
887
+
888
+ return new TransformStream({
889
+ async transform(chunk, controller) {
890
+ if (chunk.type === 'finish-step' && textChunk.length > 0) {
891
+ publishTextChunk({ controller });
892
+ }
893
+
894
+ if (
895
+ chunk.type !== 'text-delta' &&
896
+ chunk.type !== 'text-start' &&
897
+ chunk.type !== 'text-end'
898
+ ) {
899
+ controller.enqueue({ part: chunk, partialOutput: undefined });
900
+ return;
901
+ }
902
+
903
+ if (firstTextChunkId == null) {
904
+ firstTextChunkId = chunk.id;
905
+ } else if (chunk.id !== firstTextChunkId) {
906
+ controller.enqueue({ part: chunk, partialOutput: undefined });
907
+ return;
908
+ }
909
+
910
+ if (chunk.type === 'text-start') {
911
+ controller.enqueue({ part: chunk, partialOutput: undefined });
912
+ return;
913
+ }
914
+
915
+ if (chunk.type === 'text-end') {
916
+ if (textChunk.length > 0) {
917
+ publishTextChunk({ controller });
918
+ }
919
+ controller.enqueue({ part: chunk, partialOutput: undefined });
920
+ return;
921
+ }
922
+
923
+ text += chunk.text;
924
+ textChunk += chunk.text;
925
+ textProviderMetadata = chunk.providerMetadata ?? textProviderMetadata;
926
+
927
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
928
+ controller.enqueue({ part: chunk, partialOutput: undefined });
929
+ return;
930
+ }
931
+
932
+ const result = await output.parsePartialOutput({ text });
933
+ if (result === undefined) {
934
+ return;
935
+ }
936
+
937
+ const currentValue =
938
+ typeof result.partial === 'string'
939
+ ? result.partial
940
+ : JSON.stringify(result.partial);
941
+ if (currentValue !== lastPublishedValue) {
942
+ publishTextChunk({
943
+ controller,
944
+ partialOutput: result.partial,
945
+ });
946
+ lastPublishedValue = currentValue;
947
+ }
948
+ },
949
+ });
950
+ }
951
+
753
952
  function createEmptyPerformance(): StepResult<ToolSet, Context>['performance'] {
754
953
  return {
755
954
  effectiveOutputTokensPerSecond: 0,
@@ -774,10 +973,3 @@ function notSupportedYet(feature: string): Error {
774
973
  // async-iterator contract in modern runtimes; we expose them under the same
775
974
  // nominal type AI SDK does.
776
975
  type AsyncIterableStream<T> = ReadableStream<T> & AsyncIterable<T>;
777
-
778
- // `GenerateTextResult` is re-exported only so downstream code can keep this
779
- // file as the single source of return-shape constants; not otherwise used here.
780
- export type _GenerateTextResultMarker<
781
- TOOLS extends ToolSet,
782
- RUNTIME_CONTEXT extends Context,
783
- > = GenerateTextResult<TOOLS, RUNTIME_CONTEXT, never>;
@@ -7,6 +7,7 @@ import {
7
7
  type HarnessV1PendingToolResult,
8
8
  type HarnessV1Prompt,
9
9
  type HarnessV1PromptControl,
10
+ type HarnessV1ResponseFormat,
10
11
  type HarnessV1Session,
11
12
  type HarnessV1StreamPart,
12
13
  type HarnessV1ToolSpec,
@@ -30,6 +31,7 @@ import {
30
31
  import { parseToolCall } from 'ai/internal';
31
32
  import type {
32
33
  ContentPart,
34
+ OutputInterface as Output,
33
35
  ProviderMetadata,
34
36
  StepResult,
35
37
  StopCondition,
@@ -66,6 +68,7 @@ import { pinSandboxChannelEventCheckpoint } from '../../utils/sandbox-channel';
66
68
  export function runPrompt<
67
69
  TOOLS extends ToolSet,
68
70
  RUNTIME_CONTEXT extends Context,
71
+ OUTPUT extends Output,
69
72
  >(input: {
70
73
  harness: HarnessV1;
71
74
  session: HarnessV1Session;
@@ -86,6 +89,8 @@ export function runPrompt<
86
89
  sessionWorkDir: string;
87
90
  runtimeContext: RUNTIME_CONTEXT;
88
91
  abortSignal: AbortSignal | undefined;
92
+ responseFormat?: HarnessV1ResponseFormat | undefined;
93
+ output?: OUTPUT | undefined;
89
94
  telemetry?: TelemetryOptions | undefined;
90
95
  stopConditions?: ReadonlyArray<StopCondition<TOOLS, RUNTIME_CONTEXT>>;
91
96
  toolApproval?: HarnessAgentToolApprovalConfiguration | undefined;
@@ -110,16 +115,17 @@ export function runPrompt<
110
115
  isTurnSuspending?: () => boolean;
111
116
  onStopConditionMet?: () => Promise<void>;
112
117
  }): {
113
- result: HarnessStreamTextResult<TOOLS, RUNTIME_CONTEXT>;
118
+ result: HarnessStreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
114
119
  done: Promise<void>;
115
120
  } {
116
- const result = new HarnessStreamTextResult<TOOLS, RUNTIME_CONTEXT>({
121
+ const result = new HarnessStreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>({
117
122
  tools: input.tools,
118
123
  runtimeContext: input.runtimeContext,
119
124
  // toolsContext is not configurable for harnesses; pass undefined cast.
120
125
  toolsContext: undefined as never,
121
126
  harnessId: input.harness.harnessId,
122
127
  sessionId: input.session.sessionId,
128
+ output: input.output,
123
129
  });
124
130
  const pendingToolApprovals = input.pendingToolApprovals ?? [];
125
131
  const pendingToolResults = input.pendingToolResults ?? [];
@@ -172,6 +178,7 @@ export function runPrompt<
172
178
  input.mode === 'continue'
173
179
  ? emit =>
174
180
  input.session.doContinueTurn({
181
+ responseFormat: input.responseFormat,
175
182
  tools: input.toolSpecs,
176
183
  instructions: input.instructions,
177
184
  abortSignal: input.abortSignal,
@@ -185,6 +192,7 @@ export function runPrompt<
185
192
  }
186
193
  return input.session.doPromptTurn({
187
194
  prompt: input.prompt,
195
+ responseFormat: input.responseFormat,
188
196
  tools: input.toolSpecs,
189
197
  instructions: input.instructions,
190
198
  abortSignal: input.abortSignal,