@ai-sdk/harness 1.0.35 → 1.0.37
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 +20 -0
- package/agent/index.ts +5 -0
- package/dist/agent/index.d.ts +36 -4
- package/dist/agent/index.js +290 -102
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/package.json +3 -3
- package/src/agent/harness-agent-session.ts +66 -20
- package/src/agent/harness-agent-tool-result-continuation.ts +62 -0
- package/src/agent/harness-agent-types.ts +2 -0
- package/src/agent/harness-agent.ts +23 -2
- package/src/agent/internal/harness-stream-text-result.ts +60 -35
- package/src/agent/internal/lifecycle-state-validation.ts +13 -0
- package/src/agent/internal/run-prompt.ts +159 -42
- package/src/agent/internal/translate-stream-part.ts +3 -2
- package/src/v1/harness-v1-lifecycle-state.ts +12 -0
- package/src/v1/index.ts +1 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type HarnessV1,
|
|
5
5
|
type HarnessV1BuiltinToolFiltering,
|
|
6
6
|
type HarnessV1PendingToolApproval,
|
|
7
|
+
type HarnessV1PendingToolResult,
|
|
7
8
|
type HarnessV1Prompt,
|
|
8
9
|
type HarnessV1PromptControl,
|
|
9
10
|
type HarnessV1Session,
|
|
@@ -26,8 +27,15 @@ import type {
|
|
|
26
27
|
LanguageModelV4Usage,
|
|
27
28
|
} from '@ai-sdk/provider';
|
|
28
29
|
import { parseToolCall } from 'ai/internal';
|
|
29
|
-
import type {
|
|
30
|
+
import type {
|
|
31
|
+
ContentPart,
|
|
32
|
+
ProviderMetadata,
|
|
33
|
+
StepResult,
|
|
34
|
+
TelemetryOptions,
|
|
35
|
+
TextStreamPart,
|
|
36
|
+
} from 'ai';
|
|
30
37
|
import type { HarnessAgentToolApprovalContinuation } from '../harness-agent-tool-approval-continuation';
|
|
38
|
+
import type { HarnessAgentToolResultContinuation } from '../harness-agent-tool-result-continuation';
|
|
31
39
|
import type { HarnessAgentToolApprovalConfiguration } from '../harness-agent-settings';
|
|
32
40
|
import { HarnessStreamTextResult } from './harness-stream-text-result';
|
|
33
41
|
import { translateStreamPart } from './translate-stream-part';
|
|
@@ -74,12 +82,19 @@ export function runPrompt<
|
|
|
74
82
|
telemetry?: TelemetryOptions | undefined;
|
|
75
83
|
toolApproval?: HarnessAgentToolApprovalConfiguration | undefined;
|
|
76
84
|
pendingToolApprovals?: readonly HarnessV1PendingToolApproval[];
|
|
85
|
+
pendingToolResults?: readonly HarnessV1PendingToolResult[];
|
|
77
86
|
toolApprovalContinuations?:
|
|
78
87
|
| readonly HarnessAgentToolApprovalContinuation[]
|
|
79
88
|
| undefined;
|
|
89
|
+
toolResultContinuations?:
|
|
90
|
+
| readonly HarnessAgentToolResultContinuation[]
|
|
91
|
+
| undefined;
|
|
80
92
|
onPendingToolApproval?: (approval: HarnessV1PendingToolApproval) => void;
|
|
81
93
|
onToolApprovalSettled?: (approvalId: string) => void;
|
|
94
|
+
onPendingToolResult?: (pendingResult: HarnessV1PendingToolResult) => void;
|
|
95
|
+
onToolResultSettled?: (toolCallId: string) => void;
|
|
82
96
|
onTurnFinished?: () => void;
|
|
97
|
+
onTurnFailed?: () => void;
|
|
83
98
|
}): {
|
|
84
99
|
result: HarnessStreamTextResult<TOOLS, RUNTIME_CONTEXT>;
|
|
85
100
|
done: Promise<void>;
|
|
@@ -93,8 +108,11 @@ export function runPrompt<
|
|
|
93
108
|
sessionId: input.session.sessionId,
|
|
94
109
|
});
|
|
95
110
|
const pendingToolApprovals = input.pendingToolApprovals ?? [];
|
|
111
|
+
const pendingToolResults = input.pendingToolResults ?? [];
|
|
96
112
|
const onPendingToolApproval = input.onPendingToolApproval ?? (() => {});
|
|
97
113
|
const onToolApprovalSettled = input.onToolApprovalSettled ?? (() => {});
|
|
114
|
+
const onPendingToolResult = input.onPendingToolResult ?? (() => {});
|
|
115
|
+
const onToolResultSettled = input.onToolResultSettled ?? (() => {});
|
|
98
116
|
const activeTools = input.activeTools ?? input.tools;
|
|
99
117
|
|
|
100
118
|
const telemetry = createTurnTelemetry({
|
|
@@ -141,6 +159,7 @@ export function runPrompt<
|
|
|
141
159
|
context: 'failed to start harness turn',
|
|
142
160
|
error: err,
|
|
143
161
|
});
|
|
162
|
+
input.onTurnFailed?.();
|
|
144
163
|
result.fail(err);
|
|
145
164
|
return;
|
|
146
165
|
}
|
|
@@ -164,7 +183,20 @@ export function runPrompt<
|
|
|
164
183
|
continuation,
|
|
165
184
|
]),
|
|
166
185
|
);
|
|
167
|
-
const
|
|
186
|
+
const pendingResultsByToolCallId = new Map(
|
|
187
|
+
pendingToolResults.map(pendingResult => [
|
|
188
|
+
pendingResult.toolCallId,
|
|
189
|
+
pendingResult,
|
|
190
|
+
]),
|
|
191
|
+
);
|
|
192
|
+
const continuationsByToolCallId = new Map(
|
|
193
|
+
(input.toolResultContinuations ?? []).map(continuation => [
|
|
194
|
+
continuation.toolCallId,
|
|
195
|
+
continuation,
|
|
196
|
+
]),
|
|
197
|
+
);
|
|
198
|
+
const settledHostToolCallIds = new Set<string>();
|
|
199
|
+
let closingResumedStep = false;
|
|
168
200
|
let finalFinish:
|
|
169
201
|
| Extract<HarnessV1StreamPart, { type: 'finish' }>
|
|
170
202
|
| undefined;
|
|
@@ -203,19 +235,35 @@ export function runPrompt<
|
|
|
203
235
|
unified: 'tool-calls',
|
|
204
236
|
raw: undefined,
|
|
205
237
|
};
|
|
206
|
-
const
|
|
238
|
+
const completeStep = (input: {
|
|
239
|
+
finishReason: LanguageModelV4FinishReason;
|
|
240
|
+
usage: LanguageModelV4Usage;
|
|
241
|
+
providerMetadata: ProviderMetadata | undefined;
|
|
242
|
+
}): StepResult<TOOLS, RUNTIME_CONTEXT> => {
|
|
207
243
|
telemetry.stepFinish({
|
|
208
|
-
finishReason:
|
|
209
|
-
usage:
|
|
244
|
+
finishReason: input.finishReason,
|
|
245
|
+
usage: input.usage,
|
|
246
|
+
providerMetadata: input.providerMetadata,
|
|
210
247
|
content: buildStepContent(),
|
|
211
248
|
});
|
|
212
249
|
resetStepContent();
|
|
213
|
-
result.finishStep({
|
|
214
|
-
finishReason:
|
|
215
|
-
usage:
|
|
216
|
-
providerMetadata:
|
|
250
|
+
return result.finishStep({
|
|
251
|
+
finishReason: input.finishReason,
|
|
252
|
+
usage: input.usage,
|
|
253
|
+
providerMetadata: input.providerMetadata,
|
|
217
254
|
warnings: [],
|
|
218
255
|
});
|
|
256
|
+
};
|
|
257
|
+
const finishForHostInputPause = async (options: {
|
|
258
|
+
completeCurrentStep: boolean;
|
|
259
|
+
}): Promise<void> => {
|
|
260
|
+
if (options.completeCurrentStep) {
|
|
261
|
+
completeStep({
|
|
262
|
+
finishReason: toolCallsFinishReason,
|
|
263
|
+
usage: zeroUsage,
|
|
264
|
+
providerMetadata: undefined,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
219
267
|
telemetry.end({
|
|
220
268
|
finishReason: toolCallsFinishReason,
|
|
221
269
|
usage: zeroUsage,
|
|
@@ -258,7 +306,7 @@ export function runPrompt<
|
|
|
258
306
|
approval: HarnessV1PendingToolApproval,
|
|
259
307
|
continuation: HarnessAgentToolApprovalContinuation,
|
|
260
308
|
): void => {
|
|
261
|
-
result.
|
|
309
|
+
result.enqueueContinuation({
|
|
262
310
|
type: 'tool-approval-response',
|
|
263
311
|
approvalId: approval.approvalId,
|
|
264
312
|
toolCall: continuation.toolCall,
|
|
@@ -271,15 +319,42 @@ export function runPrompt<
|
|
|
271
319
|
: {}),
|
|
272
320
|
} as TextStreamPart<TOOLS>);
|
|
273
321
|
};
|
|
322
|
+
const recordPendingToolResult = (options: {
|
|
323
|
+
toolCall: Extract<HarnessV1StreamPart, { type: 'tool-call' }>;
|
|
324
|
+
}): HarnessV1PendingToolResult => {
|
|
325
|
+
const pendingResult =
|
|
326
|
+
pendingResultsByToolCallId.get(options.toolCall.toolCallId) ??
|
|
327
|
+
({
|
|
328
|
+
toolCallId: options.toolCall.toolCallId,
|
|
329
|
+
toolName: options.toolCall.toolName,
|
|
330
|
+
input: options.toolCall.input,
|
|
331
|
+
} satisfies HarnessV1PendingToolResult);
|
|
332
|
+
pendingResultsByToolCallId.set(pendingResult.toolCallId, pendingResult);
|
|
333
|
+
onPendingToolResult(pendingResult);
|
|
334
|
+
return pendingResult;
|
|
335
|
+
};
|
|
336
|
+
const processPendingToolResultContinuation = async (
|
|
337
|
+
pendingResult: HarnessV1PendingToolResult,
|
|
338
|
+
continuation: HarnessAgentToolResultContinuation,
|
|
339
|
+
): Promise<void> => {
|
|
340
|
+
onToolResultSettled(pendingResult.toolCallId);
|
|
341
|
+
pendingResultsByToolCallId.delete(pendingResult.toolCallId);
|
|
342
|
+
settledHostToolCallIds.add(pendingResult.toolCallId);
|
|
343
|
+
await control.submitToolResult({
|
|
344
|
+
toolCallId: pendingResult.toolCallId,
|
|
345
|
+
output: continuation.output,
|
|
346
|
+
isError: continuation.isError,
|
|
347
|
+
});
|
|
348
|
+
};
|
|
274
349
|
const processPendingApprovalContinuation = async (
|
|
275
350
|
approval: HarnessV1PendingToolApproval,
|
|
276
351
|
continuation: HarnessAgentToolApprovalContinuation,
|
|
277
|
-
): Promise<
|
|
352
|
+
): Promise<'continued' | 'awaiting-tool-result'> => {
|
|
278
353
|
enqueueApprovalResponse(approval, continuation);
|
|
279
354
|
onToolApprovalSettled(approval.approvalId);
|
|
280
355
|
pendingApprovalsByApprovalId.delete(approval.approvalId);
|
|
281
356
|
pendingApprovalsByToolCallId.delete(approval.toolCallId);
|
|
282
|
-
|
|
357
|
+
settledHostToolCallIds.add(approval.toolCallId);
|
|
283
358
|
|
|
284
359
|
if (approval.kind === 'builtin') {
|
|
285
360
|
if (control.submitToolApproval == null) {
|
|
@@ -292,7 +367,7 @@ export function runPrompt<
|
|
|
292
367
|
approved: continuation.approvalResponse.approved,
|
|
293
368
|
reason: continuation.approvalResponse.reason,
|
|
294
369
|
});
|
|
295
|
-
return;
|
|
370
|
+
return 'continued';
|
|
296
371
|
}
|
|
297
372
|
|
|
298
373
|
if (!continuation.approvalResponse.approved) {
|
|
@@ -303,7 +378,7 @@ export function runPrompt<
|
|
|
303
378
|
reason: continuation.approvalResponse.reason,
|
|
304
379
|
},
|
|
305
380
|
});
|
|
306
|
-
return;
|
|
381
|
+
return 'continued';
|
|
307
382
|
}
|
|
308
383
|
|
|
309
384
|
const rawToolCall =
|
|
@@ -315,7 +390,7 @@ export function runPrompt<
|
|
|
315
390
|
input: approval.input,
|
|
316
391
|
} satisfies Extract<HarnessV1StreamPart, { type: 'tool-call' }>);
|
|
317
392
|
|
|
318
|
-
const
|
|
393
|
+
const execution = await maybeExecuteHostTool({
|
|
319
394
|
event: rawToolCall,
|
|
320
395
|
tools: activeTools,
|
|
321
396
|
sandboxSession: input.sandboxSession,
|
|
@@ -344,14 +419,37 @@ export function runPrompt<
|
|
|
344
419
|
} as TextStreamPart<TOOLS>);
|
|
345
420
|
},
|
|
346
421
|
});
|
|
347
|
-
|
|
422
|
+
if (!execution.executed) {
|
|
423
|
+
recordPendingToolResult({ toolCall: rawToolCall });
|
|
424
|
+
await finishForHostInputPause({ completeCurrentStep: false });
|
|
425
|
+
return 'awaiting-tool-result';
|
|
426
|
+
}
|
|
427
|
+
telemetry.toolEnd(rawToolCall.toolCallId, execution.outcome);
|
|
428
|
+
return 'continued';
|
|
348
429
|
};
|
|
349
430
|
|
|
350
431
|
try {
|
|
351
432
|
for (const approval of pendingToolApprovals) {
|
|
352
433
|
const continuation = continuationsByApprovalId.get(approval.approvalId);
|
|
353
434
|
if (continuation != null) {
|
|
354
|
-
await processPendingApprovalContinuation(
|
|
435
|
+
const outcome = await processPendingApprovalContinuation(
|
|
436
|
+
approval,
|
|
437
|
+
continuation,
|
|
438
|
+
);
|
|
439
|
+
if (outcome === 'awaiting-tool-result') return;
|
|
440
|
+
closingResumedStep = true;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
for (const pendingResult of pendingToolResults) {
|
|
444
|
+
const continuation = continuationsByToolCallId.get(
|
|
445
|
+
pendingResult.toolCallId,
|
|
446
|
+
);
|
|
447
|
+
if (continuation != null) {
|
|
448
|
+
await processPendingToolResultContinuation(
|
|
449
|
+
pendingResult,
|
|
450
|
+
continuation,
|
|
451
|
+
);
|
|
452
|
+
closingResumedStep = true;
|
|
355
453
|
}
|
|
356
454
|
}
|
|
357
455
|
|
|
@@ -383,12 +481,20 @@ export function runPrompt<
|
|
|
383
481
|
* against the sandbox root, so the strip is display-only.
|
|
384
482
|
*/
|
|
385
483
|
const displayValue = stripWorkDir(value, input.sessionWorkDir);
|
|
386
|
-
const
|
|
387
|
-
displayValue.type === 'tool-call'
|
|
388
|
-
|
|
389
|
-
|
|
484
|
+
const settledHostInputReplay =
|
|
485
|
+
(displayValue.type === 'tool-call' ||
|
|
486
|
+
displayValue.type === 'tool-result' ||
|
|
487
|
+
displayValue.type === 'tool-approval-request') &&
|
|
488
|
+
settledHostToolCallIds.has(displayValue.toolCallId);
|
|
390
489
|
|
|
391
|
-
if (
|
|
490
|
+
if (settledHostInputReplay) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (displayValue.type === 'finish-step' && closingResumedStep) {
|
|
495
|
+
closingResumedStep = false;
|
|
496
|
+
resetStepContent();
|
|
497
|
+
result.discardCurrentStepContent();
|
|
392
498
|
continue;
|
|
393
499
|
}
|
|
394
500
|
|
|
@@ -510,10 +616,12 @@ export function runPrompt<
|
|
|
510
616
|
pendingApproval.approvalId,
|
|
511
617
|
);
|
|
512
618
|
if (continuation != null) {
|
|
513
|
-
await processPendingApprovalContinuation(
|
|
619
|
+
const outcome = await processPendingApprovalContinuation(
|
|
514
620
|
pendingApproval,
|
|
515
621
|
continuation,
|
|
516
622
|
);
|
|
623
|
+
if (outcome === 'awaiting-tool-result') return;
|
|
624
|
+
closingResumedStep = true;
|
|
517
625
|
continue;
|
|
518
626
|
}
|
|
519
627
|
|
|
@@ -522,24 +630,16 @@ export function runPrompt<
|
|
|
522
630
|
approvalId: pendingApproval.approvalId,
|
|
523
631
|
toolCall,
|
|
524
632
|
});
|
|
525
|
-
await
|
|
633
|
+
await finishForHostInputPause({ completeCurrentStep: true });
|
|
526
634
|
return;
|
|
527
635
|
}
|
|
528
636
|
|
|
529
637
|
// Drive step boundaries.
|
|
530
638
|
if (value.type === 'finish-step') {
|
|
531
|
-
|
|
639
|
+
completeStep({
|
|
532
640
|
finishReason: value.finishReason,
|
|
533
641
|
usage: value.usage,
|
|
534
642
|
providerMetadata: value.harnessMetadata,
|
|
535
|
-
content: buildStepContent(),
|
|
536
|
-
});
|
|
537
|
-
resetStepContent();
|
|
538
|
-
result.finishStep({
|
|
539
|
-
finishReason: value.finishReason,
|
|
540
|
-
usage: value.usage,
|
|
541
|
-
providerMetadata: value.harnessMetadata,
|
|
542
|
-
warnings: [],
|
|
543
643
|
});
|
|
544
644
|
}
|
|
545
645
|
|
|
@@ -631,10 +731,12 @@ export function runPrompt<
|
|
|
631
731
|
pendingApproval.approvalId,
|
|
632
732
|
);
|
|
633
733
|
if (continuation != null) {
|
|
634
|
-
await processPendingApprovalContinuation(
|
|
734
|
+
const outcome = await processPendingApprovalContinuation(
|
|
635
735
|
pendingApproval,
|
|
636
736
|
continuation,
|
|
637
737
|
);
|
|
738
|
+
if (outcome === 'awaiting-tool-result') return;
|
|
739
|
+
closingResumedStep = true;
|
|
638
740
|
continue;
|
|
639
741
|
}
|
|
640
742
|
const pendingParsedToolCall = toolCallsByToolCallId.get(
|
|
@@ -650,10 +752,10 @@ export function runPrompt<
|
|
|
650
752
|
approvalId: pendingApproval.approvalId,
|
|
651
753
|
toolCall: pendingParsedToolCall,
|
|
652
754
|
});
|
|
653
|
-
await
|
|
755
|
+
await finishForHostInputPause({ completeCurrentStep: true });
|
|
654
756
|
return;
|
|
655
757
|
}
|
|
656
|
-
const
|
|
758
|
+
const execution = await maybeExecuteHostTool({
|
|
657
759
|
event: toolCall,
|
|
658
760
|
tools: activeTools,
|
|
659
761
|
sandboxSession: input.sandboxSession,
|
|
@@ -690,7 +792,12 @@ export function runPrompt<
|
|
|
690
792
|
} as TextStreamPart<TOOLS>);
|
|
691
793
|
},
|
|
692
794
|
});
|
|
693
|
-
|
|
795
|
+
if (!execution.executed) {
|
|
796
|
+
recordPendingToolResult({ toolCall });
|
|
797
|
+
await finishForHostInputPause({ completeCurrentStep: true });
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
telemetry.toolEnd(toolCall.toolCallId, execution.outcome);
|
|
694
801
|
}
|
|
695
802
|
|
|
696
803
|
if (value.type === 'error') {
|
|
@@ -701,11 +808,16 @@ export function runPrompt<
|
|
|
701
808
|
context: 'harness stream error',
|
|
702
809
|
error: value.error,
|
|
703
810
|
});
|
|
811
|
+
input.onTurnFailed?.();
|
|
704
812
|
result.fail(value.error);
|
|
705
813
|
return;
|
|
706
814
|
}
|
|
707
815
|
}
|
|
708
|
-
|
|
816
|
+
if (finalFinish != null) {
|
|
817
|
+
input.onTurnFinished?.();
|
|
818
|
+
} else {
|
|
819
|
+
input.onTurnFailed?.();
|
|
820
|
+
}
|
|
709
821
|
await result.finish(
|
|
710
822
|
finalFinish
|
|
711
823
|
? {
|
|
@@ -723,6 +835,7 @@ export function runPrompt<
|
|
|
723
835
|
context: 'harness turn failed',
|
|
724
836
|
error: err,
|
|
725
837
|
});
|
|
838
|
+
input.onTurnFailed?.();
|
|
726
839
|
result.fail(err);
|
|
727
840
|
} finally {
|
|
728
841
|
reader.releaseLock();
|
|
@@ -742,6 +855,10 @@ type HostToolOutcome =
|
|
|
742
855
|
| { ok: true; output: unknown }
|
|
743
856
|
| { ok: false; error: unknown };
|
|
744
857
|
|
|
858
|
+
type HostToolExecution =
|
|
859
|
+
| { executed: false }
|
|
860
|
+
| { executed: true; outcome: HostToolOutcome };
|
|
861
|
+
|
|
745
862
|
function asToolCallTextStreamPart<TOOLS extends ToolSet>(input: {
|
|
746
863
|
part: TextStreamPart<TOOLS>;
|
|
747
864
|
}): ToolCallTextStreamPart {
|
|
@@ -782,10 +899,10 @@ async function maybeExecuteHostTool<TOOLS extends ToolSet>(input: {
|
|
|
782
899
|
* stream. Never called for a plain (non-generator) `execute`.
|
|
783
900
|
*/
|
|
784
901
|
onPreliminaryResult: (output: unknown) => void;
|
|
785
|
-
}): Promise<
|
|
902
|
+
}): Promise<HostToolExecution> {
|
|
786
903
|
const tool = input.tools[input.event.toolName];
|
|
787
904
|
|
|
788
|
-
if (!isExecutableTool(tool)) return {
|
|
905
|
+
if (!isExecutableTool(tool)) return { executed: false };
|
|
789
906
|
|
|
790
907
|
const parsed = await safeParseJSON({ text: input.event.input });
|
|
791
908
|
const args = parsed.success ? parsed.value : input.event.input;
|
|
@@ -825,14 +942,14 @@ async function maybeExecuteHostTool<TOOLS extends ToolSet>(input: {
|
|
|
825
942
|
toolCallId: input.event.toolCallId,
|
|
826
943
|
output,
|
|
827
944
|
});
|
|
828
|
-
return { ok: true, output };
|
|
945
|
+
return { executed: true, outcome: { ok: true, output } };
|
|
829
946
|
} catch (err) {
|
|
830
947
|
await input.control.submitToolResult({
|
|
831
948
|
toolCallId: input.event.toolCallId,
|
|
832
949
|
output: { error: String(err) },
|
|
833
950
|
isError: true,
|
|
834
951
|
});
|
|
835
|
-
return { ok: false, error: err };
|
|
952
|
+
return { executed: true, outcome: { ok: false, error: err } };
|
|
836
953
|
}
|
|
837
954
|
}
|
|
838
955
|
|
|
@@ -29,8 +29,9 @@ export function translateStreamPart<TOOLS extends ToolSet>(
|
|
|
29
29
|
): ReadonlyArray<TextStreamPart<TOOLS>> {
|
|
30
30
|
switch (event.type) {
|
|
31
31
|
case 'stream-start':
|
|
32
|
-
// The agent emits its own `start` part
|
|
33
|
-
// the harness-level start
|
|
32
|
+
// The agent emits its own `start` part as the first chunk of the
|
|
33
|
+
// stream (see `HarnessStreamTextResult`); the harness-level start
|
|
34
|
+
// signal is consumed internally.
|
|
34
35
|
return [];
|
|
35
36
|
|
|
36
37
|
case 'text-start':
|
|
@@ -10,6 +10,12 @@ export type HarnessV1PendingToolApproval = {
|
|
|
10
10
|
readonly nativeName?: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
export type HarnessV1PendingToolResult = {
|
|
14
|
+
readonly toolCallId: string;
|
|
15
|
+
readonly toolName: string;
|
|
16
|
+
readonly input: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
13
19
|
type HarnessV1LifecycleStateBase = {
|
|
14
20
|
/**
|
|
15
21
|
* Identifier of the harness that produced this state. Used by adapters to
|
|
@@ -58,6 +64,12 @@ export type HarnessV1ContinueTurnState = HarnessV1LifecycleStateBase & {
|
|
|
58
64
|
* without the harness framework owning storage.
|
|
59
65
|
*/
|
|
60
66
|
readonly pendingToolApprovals?: readonly HarnessV1PendingToolApproval[];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Framework-owned client tool calls that are waiting for a caller-provided
|
|
70
|
+
* result before the underlying turn can continue.
|
|
71
|
+
*/
|
|
72
|
+
readonly pendingToolResults?: readonly HarnessV1PendingToolResult[];
|
|
61
73
|
};
|
|
62
74
|
|
|
63
75
|
export type HarnessV1LifecycleState =
|