@ai-sdk/harness 1.0.132 → 1.0.133
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 +10 -0
- package/dist/agent/index.d.ts +113 -1
- package/dist/agent/index.js +110 -63
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +124 -6
- package/dist/index.js +28 -5
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +3 -2
- package/dist/utils/index.js +11 -3
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/agent/harness-agent-session.ts +46 -14
- package/src/agent/internal/run-prompt.ts +93 -62
- package/src/errors/harness-history-unavailable-error.ts +41 -0
- package/src/index.ts +1 -0
- package/src/utils/credential-forwarding.ts +15 -1
- package/src/utils/index.ts +1 -1
- package/src/v1/harness-v1-message.ts +150 -0
- package/src/v1/harness-v1-session.ts +38 -0
- package/src/v1/index.ts +17 -0
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
HarnessV1BuiltinToolFiltering,
|
|
18
18
|
HarnessV1NetworkSandboxSession,
|
|
19
19
|
HarnessV1PromptControl,
|
|
20
|
+
HarnessV1ReadHistoryResult,
|
|
20
21
|
HarnessV1ResponseFormat,
|
|
21
22
|
HarnessV1Skill,
|
|
22
23
|
HarnessV1TurnSettings,
|
|
@@ -482,22 +483,53 @@ export class HarnessAgentSession {
|
|
|
482
483
|
);
|
|
483
484
|
}
|
|
484
485
|
const session = this.underlyingSession;
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
486
|
+
const state =
|
|
487
|
+
this.turnState !== 'idle'
|
|
488
|
+
? this.toResumeStateWithContinuation({
|
|
489
|
+
continueFrom: await this.finalizeCurrentTurnSuspension({ session }),
|
|
490
|
+
})
|
|
491
|
+
: await validateLifecycleStateData({
|
|
492
|
+
harness: this.harness,
|
|
493
|
+
state: await session.doDetach(),
|
|
494
|
+
expectedType: 'resume-session',
|
|
495
|
+
});
|
|
496
|
+
this.endLocalHandle({ sessionState: 'detached' });
|
|
497
|
+
return state;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Read the conversation history the runtime itself persisted, normalized
|
|
502
|
+
* by the adapter. Includes exchanges that happened outside this process —
|
|
503
|
+
* the same conversation continued interactively in the agent's own CLI,
|
|
504
|
+
* for instance — which the live event stream never saw.
|
|
505
|
+
*
|
|
506
|
+
* Pass a previous result's `cursor` as `since` to read only the delta. A
|
|
507
|
+
* conversation with no recorded messages yet resolves to an empty
|
|
508
|
+
* `messages` array.
|
|
509
|
+
*
|
|
510
|
+
* Throws `HarnessCapabilityUnsupportedError` when the adapter does not
|
|
511
|
+
* implement history reads, and
|
|
512
|
+
* `HarnessHistoryUnavailableError` when the adapter supports them but
|
|
513
|
+
* cannot reach the runtime's store from this environment.
|
|
514
|
+
*/
|
|
515
|
+
async readHistory(options?: {
|
|
516
|
+
since?: string;
|
|
517
|
+
}): Promise<HarnessV1ReadHistoryResult> {
|
|
518
|
+
if (this.sessionState !== 'active' || this.underlyingSession == null) {
|
|
519
|
+
throw new Error(
|
|
520
|
+
`Harness session ${this.sessionId} is not active and cannot read history.`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const session = this.underlyingSession;
|
|
524
|
+
if (typeof session.doReadHistory !== 'function') {
|
|
525
|
+
throw new HarnessCapabilityUnsupportedError({
|
|
526
|
+
harnessId: this.harness.harnessId,
|
|
527
|
+
message: `Harness '${this.harness.harnessId}' does not support reading the runtime's conversation history.`,
|
|
496
528
|
});
|
|
497
|
-
return validated;
|
|
498
|
-
} finally {
|
|
499
|
-
this.endLocalHandle({ sessionState: 'detached' });
|
|
500
529
|
}
|
|
530
|
+
return await session.doReadHistory({
|
|
531
|
+
...(options?.since != null ? { since: options.since } : {}),
|
|
532
|
+
});
|
|
501
533
|
}
|
|
502
534
|
|
|
503
535
|
/**
|
|
@@ -366,34 +366,47 @@ export function runPrompt<
|
|
|
366
366
|
pendingStopBoundary = undefined;
|
|
367
367
|
};
|
|
368
368
|
|
|
369
|
-
// Accumulate the model response until its step boundary.
|
|
370
|
-
//
|
|
371
|
-
//
|
|
369
|
+
// Accumulate the model response until its step boundary. Tool lifecycle
|
|
370
|
+
// notifications and consumer-visible tool outcomes are published as each
|
|
371
|
+
// tool runs; `finish-step` remains the boundary for step accounting.
|
|
372
372
|
let stepText = '';
|
|
373
373
|
let stepReasoning = '';
|
|
374
374
|
let stepToolCalls: ContentPart<TOOLS>[] = [];
|
|
375
375
|
let stepProviderToolResults: ContentPart<TOOLS>[] = [];
|
|
376
376
|
let stepApprovalRequests: ContentPart<TOOLS>[] = [];
|
|
377
377
|
let bufferedToolOutcomes: Array<() => void> = [];
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
378
|
+
type ToolExecutionState = {
|
|
379
|
+
toolCall: TypedToolCall<TOOLS>;
|
|
380
|
+
toolOutput?: TypedToolResult<TOOLS> | TypedToolError<TOOLS>;
|
|
381
|
+
toolExecutionMs?: number;
|
|
382
|
+
executionStartedAt?: number;
|
|
383
|
+
startNotification?: Promise<void>;
|
|
384
|
+
endNotification?: Promise<void>;
|
|
385
|
+
};
|
|
386
|
+
const toolExecutions = new Map<string, ToolExecutionState>();
|
|
387
|
+
const publishToolExecutionStart = async (
|
|
388
|
+
execution: ToolExecutionState,
|
|
389
|
+
): Promise<void> => {
|
|
390
|
+
execution.startNotification ??= lifecycle.toolExecutionStart({
|
|
391
|
+
toolCall: execution.toolCall,
|
|
392
|
+
});
|
|
393
|
+
await execution.startNotification;
|
|
394
|
+
};
|
|
395
|
+
const publishToolExecutionEnd = async (
|
|
396
|
+
execution: ToolExecutionState,
|
|
397
|
+
): Promise<void> => {
|
|
398
|
+
if (execution.toolOutput == null) return;
|
|
399
|
+
await publishToolExecutionStart(execution);
|
|
400
|
+
execution.endNotification ??= lifecycle.toolExecutionEnd({
|
|
401
|
+
toolCall: execution.toolCall,
|
|
402
|
+
toolOutput: execution.toolOutput,
|
|
403
|
+
toolExecutionMs: execution.toolExecutionMs ?? 0,
|
|
404
|
+
});
|
|
405
|
+
await execution.endNotification;
|
|
406
|
+
};
|
|
386
407
|
const publishToolExecutions = async (): Promise<void> => {
|
|
387
408
|
for (const execution of toolExecutions.values()) {
|
|
388
|
-
|
|
389
|
-
await lifecycle.toolExecutionStart({
|
|
390
|
-
toolCall: execution.toolCall,
|
|
391
|
-
});
|
|
392
|
-
await lifecycle.toolExecutionEnd({
|
|
393
|
-
toolCall: execution.toolCall,
|
|
394
|
-
toolOutput: execution.toolOutput,
|
|
395
|
-
toolExecutionMs: execution.toolExecutionMs ?? 0,
|
|
396
|
-
});
|
|
409
|
+
await publishToolExecutionEnd(execution);
|
|
397
410
|
}
|
|
398
411
|
for (const publish of bufferedToolOutcomes) publish();
|
|
399
412
|
toolExecutions.clear();
|
|
@@ -749,6 +762,9 @@ export function runPrompt<
|
|
|
749
762
|
toolExecutions.set(rawToolCall.toolCallId, {
|
|
750
763
|
toolCall: toolCall as TypedToolCall<TOOLS>,
|
|
751
764
|
});
|
|
765
|
+
await publishToolExecutionStart(
|
|
766
|
+
toolExecutions.get(rawToolCall.toolCallId)!,
|
|
767
|
+
);
|
|
752
768
|
const executionStartedAt = Date.now();
|
|
753
769
|
const execution = await maybeExecuteHostTool({
|
|
754
770
|
event: rawToolCall,
|
|
@@ -772,16 +788,14 @@ export function runPrompt<
|
|
|
772
788
|
},
|
|
773
789
|
input.sessionWorkDir,
|
|
774
790
|
) as Extract<HarnessV1StreamPart, { type: 'tool-result' }>;
|
|
775
|
-
|
|
776
|
-
result
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
} as TextStreamPart<TOOLS>);
|
|
784
|
-
});
|
|
791
|
+
result.enqueue({
|
|
792
|
+
type: 'tool-result',
|
|
793
|
+
toolCallId: rawToolCall.toolCallId,
|
|
794
|
+
toolName: rawToolCall.toolName,
|
|
795
|
+
input: undefined,
|
|
796
|
+
output: stripped.result,
|
|
797
|
+
preliminary: true,
|
|
798
|
+
} as TextStreamPart<TOOLS>);
|
|
785
799
|
},
|
|
786
800
|
});
|
|
787
801
|
if (!execution.executed) {
|
|
@@ -795,13 +809,11 @@ export function runPrompt<
|
|
|
795
809
|
outcome: execution.outcome,
|
|
796
810
|
});
|
|
797
811
|
toolExecution.toolExecutionMs = Date.now() - executionStartedAt;
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
});
|
|
812
|
+
await publishToolExecutionEnd(toolExecution);
|
|
813
|
+
enqueueHostToolOutcome({
|
|
814
|
+
toolCall,
|
|
815
|
+
outcome: execution.outcome,
|
|
803
816
|
});
|
|
804
|
-
await publishToolExecutions();
|
|
805
817
|
return 'continued';
|
|
806
818
|
};
|
|
807
819
|
|
|
@@ -1007,11 +1019,7 @@ export function runPrompt<
|
|
|
1007
1019
|
displayValue,
|
|
1008
1020
|
translateOptions,
|
|
1009
1021
|
);
|
|
1010
|
-
if (value.type
|
|
1011
|
-
bufferedToolOutcomes.push(() => {
|
|
1012
|
-
for (const part of translatedParts) result.enqueue(part);
|
|
1013
|
-
});
|
|
1014
|
-
} else {
|
|
1022
|
+
if (value.type !== 'tool-result') {
|
|
1015
1023
|
for (const part of translatedParts) result.enqueue(part);
|
|
1016
1024
|
}
|
|
1017
1025
|
|
|
@@ -1059,9 +1067,13 @@ export function runPrompt<
|
|
|
1059
1067
|
const toolCall = toolCallsByToolCallId.get(value.toolCallId);
|
|
1060
1068
|
if (toolCall != null) {
|
|
1061
1069
|
stepToolCalls.push(toolCall as ContentPart<TOOLS>);
|
|
1062
|
-
|
|
1070
|
+
const execution: ToolExecutionState = {
|
|
1063
1071
|
toolCall: toolCall as TypedToolCall<TOOLS>,
|
|
1064
|
-
}
|
|
1072
|
+
};
|
|
1073
|
+
toolExecutions.set(value.toolCallId, execution);
|
|
1074
|
+
if (value.providerExecuted === true) {
|
|
1075
|
+
await publishToolExecutionStart(execution);
|
|
1076
|
+
}
|
|
1065
1077
|
}
|
|
1066
1078
|
}
|
|
1067
1079
|
|
|
@@ -1080,6 +1092,13 @@ export function runPrompt<
|
|
|
1080
1092
|
output: value.result,
|
|
1081
1093
|
} as TypedToolResult<TOOLS>);
|
|
1082
1094
|
}
|
|
1095
|
+
if (
|
|
1096
|
+
execution?.toolExecutionMs == null &&
|
|
1097
|
+
execution?.executionStartedAt != null
|
|
1098
|
+
) {
|
|
1099
|
+
execution.toolExecutionMs =
|
|
1100
|
+
Date.now() - execution.executionStartedAt;
|
|
1101
|
+
}
|
|
1083
1102
|
if (
|
|
1084
1103
|
rawToolCallsByToolCallId.get(value.toolCallId)?.providerExecuted ===
|
|
1085
1104
|
true &&
|
|
@@ -1089,6 +1108,10 @@ export function runPrompt<
|
|
|
1089
1108
|
execution.toolOutput as ContentPart<TOOLS>,
|
|
1090
1109
|
);
|
|
1091
1110
|
}
|
|
1111
|
+
if (execution != null) {
|
|
1112
|
+
await publishToolExecutionEnd(execution);
|
|
1113
|
+
}
|
|
1114
|
+
for (const part of translatedParts) result.enqueue(part);
|
|
1092
1115
|
}
|
|
1093
1116
|
|
|
1094
1117
|
if (value.type === 'tool-approval-request') {
|
|
@@ -1267,16 +1290,20 @@ export function runPrompt<
|
|
|
1267
1290
|
type: 'execution-denied',
|
|
1268
1291
|
reason: customToolApprovalDecision.reason,
|
|
1269
1292
|
};
|
|
1293
|
+
const execution = toolExecutions.get(toolCall.toolCallId);
|
|
1294
|
+
if (execution != null) {
|
|
1295
|
+
await publishToolExecutionStart(execution);
|
|
1296
|
+
}
|
|
1270
1297
|
await submitToolResult({
|
|
1271
1298
|
toolCallId: toolCall.toolCallId,
|
|
1272
1299
|
output,
|
|
1273
1300
|
});
|
|
1274
|
-
const execution = toolExecutions.get(toolCall.toolCallId);
|
|
1275
1301
|
if (execution != null) {
|
|
1276
1302
|
execution.toolOutput = toToolOutput({
|
|
1277
1303
|
toolCall: parsedToolCall,
|
|
1278
1304
|
outcome: { ok: true, output },
|
|
1279
1305
|
});
|
|
1306
|
+
await publishToolExecutionEnd(execution);
|
|
1280
1307
|
}
|
|
1281
1308
|
continue;
|
|
1282
1309
|
}
|
|
@@ -1353,7 +1380,15 @@ export function runPrompt<
|
|
|
1353
1380
|
}
|
|
1354
1381
|
startHostToolExecution(
|
|
1355
1382
|
(async () => {
|
|
1383
|
+
const toolExecution = toolExecutions.get(toolCall.toolCallId);
|
|
1384
|
+
if (toolExecution == null) {
|
|
1385
|
+
throw new Error(
|
|
1386
|
+
`Harness '${input.harness.harnessId}' could not track host tool '${toolCall.toolName}'.`,
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
await publishToolExecutionStart(toolExecution);
|
|
1356
1390
|
const executionStartedAt = Date.now();
|
|
1391
|
+
toolExecution.executionStartedAt = executionStartedAt;
|
|
1357
1392
|
const execution = await maybeExecuteHostTool({
|
|
1358
1393
|
event: toolCall,
|
|
1359
1394
|
parsedToolCall: validatedHostToolCall,
|
|
@@ -1384,16 +1419,14 @@ export function runPrompt<
|
|
|
1384
1419
|
},
|
|
1385
1420
|
input.sessionWorkDir,
|
|
1386
1421
|
) as Extract<HarnessV1StreamPart, { type: 'tool-result' }>;
|
|
1387
|
-
|
|
1388
|
-
result
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
} as TextStreamPart<TOOLS>);
|
|
1396
|
-
});
|
|
1422
|
+
result.enqueue({
|
|
1423
|
+
type: 'tool-result',
|
|
1424
|
+
toolCallId: toolCall.toolCallId,
|
|
1425
|
+
toolName: toolCall.toolName,
|
|
1426
|
+
input: undefined,
|
|
1427
|
+
output: stripped.result,
|
|
1428
|
+
preliminary: true,
|
|
1429
|
+
} as TextStreamPart<TOOLS>);
|
|
1397
1430
|
},
|
|
1398
1431
|
});
|
|
1399
1432
|
if (!execution.executed) {
|
|
@@ -1401,14 +1434,12 @@ export function runPrompt<
|
|
|
1401
1434
|
`Harness '${input.harness.harnessId}' could not execute host tool '${toolCall.toolName}'.`,
|
|
1402
1435
|
);
|
|
1403
1436
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
toolExecution.toolExecutionMs = Date.now() - executionStartedAt;
|
|
1411
|
-
}
|
|
1437
|
+
toolExecution.toolOutput = toToolOutput({
|
|
1438
|
+
toolCall: parsedToolCall,
|
|
1439
|
+
outcome: execution.outcome,
|
|
1440
|
+
});
|
|
1441
|
+
toolExecution.toolExecutionMs = Date.now() - executionStartedAt;
|
|
1442
|
+
await publishToolExecutionEnd(toolExecution);
|
|
1412
1443
|
})(),
|
|
1413
1444
|
);
|
|
1414
1445
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AISDKError } from '@ai-sdk/provider';
|
|
2
|
+
import { HarnessError } from './harness-error';
|
|
3
|
+
|
|
4
|
+
const name = 'AI_HarnessHistoryUnavailableError';
|
|
5
|
+
const marker = `vercel.ai.error.${name}`;
|
|
6
|
+
const symbol = Symbol.for(marker);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Thrown by `readHistory` when the adapter supports history reads but cannot
|
|
10
|
+
* reach the runtime's store from the current environment — for example the
|
|
11
|
+
* store lives inside a remote sandbox, or the transcript directory is
|
|
12
|
+
* missing or unreadable.
|
|
13
|
+
*
|
|
14
|
+
* Distinct from `HarnessCapabilityUnsupportedError` (the adapter does not
|
|
15
|
+
* implement history reads at all) so hosts can retry or degrade differently.
|
|
16
|
+
* A conversation with no recorded messages yet is not an error; it resolves
|
|
17
|
+
* to an empty result instead.
|
|
18
|
+
*/
|
|
19
|
+
export class HarnessHistoryUnavailableError extends HarnessError {
|
|
20
|
+
private readonly [symbol] = true;
|
|
21
|
+
|
|
22
|
+
readonly harnessId?: string;
|
|
23
|
+
|
|
24
|
+
constructor({
|
|
25
|
+
message,
|
|
26
|
+
harnessId,
|
|
27
|
+
cause,
|
|
28
|
+
}: {
|
|
29
|
+
message: string;
|
|
30
|
+
harnessId?: string;
|
|
31
|
+
cause?: unknown;
|
|
32
|
+
}) {
|
|
33
|
+
super({ message, cause });
|
|
34
|
+
Object.defineProperty(this, 'name', { value: name });
|
|
35
|
+
this.harnessId = harnessId;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static isInstance(error: unknown): error is HarnessHistoryUnavailableError {
|
|
39
|
+
return AISDKError.hasMarker(error, marker);
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -28,14 +28,16 @@ export async function applyCredentialForwarding({
|
|
|
28
28
|
return forwardedEnvironment;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export async function
|
|
31
|
+
export async function resolveSandboxCredentialEnvironment({
|
|
32
32
|
environment,
|
|
33
33
|
credentialEnvironmentVariables,
|
|
34
34
|
credentialForwarding,
|
|
35
|
+
previousSandboxCredentialEnvironment,
|
|
35
36
|
}: {
|
|
36
37
|
environment: Readonly<Record<string, string>>;
|
|
37
38
|
credentialEnvironmentVariables: ReadonlyArray<string>;
|
|
38
39
|
credentialForwarding: HarnessV1CredentialForwarding | undefined;
|
|
40
|
+
previousSandboxCredentialEnvironment?: Readonly<Record<string, string>>;
|
|
39
41
|
}): Promise<Record<string, string>> {
|
|
40
42
|
const sandboxCredentialEnvironment: Record<string, string> = {};
|
|
41
43
|
|
|
@@ -44,6 +46,18 @@ export async function createSandboxCredentialEnvironment({
|
|
|
44
46
|
)) {
|
|
45
47
|
if (environment[environmentVariableName] == null) continue;
|
|
46
48
|
|
|
49
|
+
if (
|
|
50
|
+
previousSandboxCredentialEnvironment != null &&
|
|
51
|
+
Object.prototype.hasOwnProperty.call(
|
|
52
|
+
previousSandboxCredentialEnvironment,
|
|
53
|
+
environmentVariableName,
|
|
54
|
+
)
|
|
55
|
+
) {
|
|
56
|
+
sandboxCredentialEnvironment[environmentVariableName] =
|
|
57
|
+
previousSandboxCredentialEnvironment[environmentVariableName];
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
const placeholder = generateSandboxCredentialPlaceholder();
|
|
48
62
|
sandboxCredentialEnvironment[environmentVariableName] =
|
|
49
63
|
credentialForwarding == null
|
package/src/utils/index.ts
CHANGED
|
@@ -28,7 +28,7 @@ export {
|
|
|
28
28
|
export { isLinux, isMacOS, isWindows } from './os';
|
|
29
29
|
export {
|
|
30
30
|
applyCredentialForwarding,
|
|
31
|
-
|
|
31
|
+
resolveSandboxCredentialEnvironment,
|
|
32
32
|
} from './credential-forwarding';
|
|
33
33
|
export {
|
|
34
34
|
createCredentialRequestTransformation,
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LanguageModelV4CustomPart,
|
|
3
|
+
LanguageModelV4FilePart,
|
|
4
|
+
LanguageModelV4ReasoningFilePart,
|
|
5
|
+
LanguageModelV4ReasoningPart,
|
|
6
|
+
LanguageModelV4TextPart,
|
|
7
|
+
LanguageModelV4ToolApprovalResponsePart,
|
|
8
|
+
LanguageModelV4ToolCallPart,
|
|
9
|
+
LanguageModelV4ToolResultOutput,
|
|
10
|
+
LanguageModelV4ToolResultPart,
|
|
11
|
+
} from '@ai-sdk/provider';
|
|
12
|
+
import type { HarnessV1Metadata } from './harness-v1-metadata';
|
|
13
|
+
|
|
14
|
+
type LanguageModelV4ToolResultContentPart = Extract<
|
|
15
|
+
LanguageModelV4ToolResultOutput,
|
|
16
|
+
{ type: 'content' }
|
|
17
|
+
>['value'][number];
|
|
18
|
+
|
|
19
|
+
export type HarnessV1TextPart = Omit<
|
|
20
|
+
LanguageModelV4TextPart,
|
|
21
|
+
'providerOptions'
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
export type HarnessV1FilePart = Omit<
|
|
25
|
+
LanguageModelV4FilePart,
|
|
26
|
+
'providerOptions'
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export type HarnessV1CustomPart = Omit<
|
|
30
|
+
LanguageModelV4CustomPart,
|
|
31
|
+
'providerOptions'
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
export type HarnessV1ReasoningPart = Omit<
|
|
35
|
+
LanguageModelV4ReasoningPart,
|
|
36
|
+
'providerOptions'
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export type HarnessV1ReasoningFilePart = Omit<
|
|
40
|
+
LanguageModelV4ReasoningFilePart,
|
|
41
|
+
'providerOptions'
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
export type HarnessV1ToolCallPart = Omit<
|
|
45
|
+
LanguageModelV4ToolCallPart,
|
|
46
|
+
'providerOptions'
|
|
47
|
+
> & {
|
|
48
|
+
nativeName?: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type HarnessV1ToolResultOutput =
|
|
52
|
+
| Omit<
|
|
53
|
+
Extract<LanguageModelV4ToolResultOutput, { type: 'text' }>,
|
|
54
|
+
'providerOptions'
|
|
55
|
+
>
|
|
56
|
+
| Omit<
|
|
57
|
+
Extract<LanguageModelV4ToolResultOutput, { type: 'json' }>,
|
|
58
|
+
'providerOptions'
|
|
59
|
+
>
|
|
60
|
+
| Omit<
|
|
61
|
+
Extract<LanguageModelV4ToolResultOutput, { type: 'execution-denied' }>,
|
|
62
|
+
'providerOptions'
|
|
63
|
+
>
|
|
64
|
+
| Omit<
|
|
65
|
+
Extract<LanguageModelV4ToolResultOutput, { type: 'error-text' }>,
|
|
66
|
+
'providerOptions'
|
|
67
|
+
>
|
|
68
|
+
| Omit<
|
|
69
|
+
Extract<LanguageModelV4ToolResultOutput, { type: 'error-json' }>,
|
|
70
|
+
'providerOptions'
|
|
71
|
+
>
|
|
72
|
+
| {
|
|
73
|
+
type: 'content';
|
|
74
|
+
value: Array<
|
|
75
|
+
| Omit<
|
|
76
|
+
Extract<LanguageModelV4ToolResultContentPart, { type: 'text' }>,
|
|
77
|
+
'providerOptions'
|
|
78
|
+
>
|
|
79
|
+
| Omit<
|
|
80
|
+
Extract<LanguageModelV4ToolResultContentPart, { type: 'file' }>,
|
|
81
|
+
'providerOptions'
|
|
82
|
+
>
|
|
83
|
+
| Omit<
|
|
84
|
+
Extract<LanguageModelV4ToolResultContentPart, { type: 'custom' }>,
|
|
85
|
+
'providerOptions'
|
|
86
|
+
>
|
|
87
|
+
>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type HarnessV1ToolResultPart = Omit<
|
|
91
|
+
LanguageModelV4ToolResultPart,
|
|
92
|
+
'output' | 'providerOptions'
|
|
93
|
+
> & {
|
|
94
|
+
output: HarnessV1ToolResultOutput;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type HarnessV1ToolApprovalResponsePart = Omit<
|
|
98
|
+
LanguageModelV4ToolApprovalResponsePart,
|
|
99
|
+
'providerOptions'
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
export type HarnessV1MessagePart =
|
|
103
|
+
| HarnessV1TextPart
|
|
104
|
+
| HarnessV1FilePart
|
|
105
|
+
| HarnessV1CustomPart
|
|
106
|
+
| HarnessV1ReasoningPart
|
|
107
|
+
| HarnessV1ReasoningFilePart
|
|
108
|
+
| HarnessV1ToolCallPart
|
|
109
|
+
| HarnessV1ToolResultPart
|
|
110
|
+
| HarnessV1ToolApprovalResponsePart;
|
|
111
|
+
|
|
112
|
+
export type HarnessV1UserMessage = {
|
|
113
|
+
readonly role: 'user';
|
|
114
|
+
readonly content: Array<HarnessV1TextPart | HarnessV1FilePart>;
|
|
115
|
+
readonly at?: string;
|
|
116
|
+
readonly harnessMetadata?: HarnessV1Metadata;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export type HarnessV1AssistantMessage = {
|
|
120
|
+
readonly role: 'assistant';
|
|
121
|
+
readonly content: Array<
|
|
122
|
+
| HarnessV1TextPart
|
|
123
|
+
| HarnessV1FilePart
|
|
124
|
+
| HarnessV1CustomPart
|
|
125
|
+
| HarnessV1ReasoningPart
|
|
126
|
+
| HarnessV1ReasoningFilePart
|
|
127
|
+
| HarnessV1ToolCallPart
|
|
128
|
+
| HarnessV1ToolResultPart
|
|
129
|
+
>;
|
|
130
|
+
readonly at?: string;
|
|
131
|
+
readonly harnessMetadata?: HarnessV1Metadata;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export type HarnessV1ToolMessage = {
|
|
135
|
+
readonly role: 'tool';
|
|
136
|
+
readonly content: Array<
|
|
137
|
+
HarnessV1ToolResultPart | HarnessV1ToolApprovalResponsePart
|
|
138
|
+
>;
|
|
139
|
+
readonly at?: string;
|
|
140
|
+
readonly harnessMetadata?: HarnessV1Metadata;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A persisted harness message using V4 prompt content shapes and metadata
|
|
145
|
+
* scoped to the adapter that produced it.
|
|
146
|
+
*/
|
|
147
|
+
export type HarnessV1Message =
|
|
148
|
+
| HarnessV1UserMessage
|
|
149
|
+
| HarnessV1AssistantMessage
|
|
150
|
+
| HarnessV1ToolMessage;
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
HarnessV1TurnSettings,
|
|
12
12
|
} from './harness-v1-lifecycle-state';
|
|
13
13
|
import type { HarnessV1StreamPart } from './harness-v1-stream-part';
|
|
14
|
+
import type { HarnessV1Message } from './harness-v1-message';
|
|
14
15
|
import type { HarnessV1BuiltinToolFiltering } from './harness-v1-tool-filtering';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -90,6 +91,15 @@ export type HarnessV1StartOptions = {
|
|
|
90
91
|
readonly sessionWorkDir: string;
|
|
91
92
|
};
|
|
92
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Result of `HarnessV1Session.doReadHistory`.
|
|
96
|
+
*/
|
|
97
|
+
export type HarnessV1ReadHistoryResult = {
|
|
98
|
+
readonly messages: ReadonlyArray<HarnessV1Message>;
|
|
99
|
+
/** Opaque position; pass back as `since` to read only what follows. */
|
|
100
|
+
readonly cursor: string;
|
|
101
|
+
};
|
|
102
|
+
|
|
93
103
|
/**
|
|
94
104
|
* Options passed to `HarnessV1Session.doPromptTurn`.
|
|
95
105
|
*/
|
|
@@ -192,6 +202,34 @@ export type HarnessV1Session = {
|
|
|
192
202
|
*/
|
|
193
203
|
doCompact(customInstructions?: string): PromiseLike<void>;
|
|
194
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Read the conversation history the runtime itself persisted, normalized
|
|
207
|
+
* to `HarnessV1Message`.
|
|
208
|
+
*
|
|
209
|
+
* The session's history can grow outside the harness contract: the same
|
|
210
|
+
* runtime conversation may be continued interactively (`claude --resume`),
|
|
211
|
+
* by another process, or before this session attached. Hosts that render a
|
|
212
|
+
* continuous record of the conversation — not just the turns they drove —
|
|
213
|
+
* need to read that history back, and the runtime's own store is the only
|
|
214
|
+
* source that has it. The adapter owns its runtime's persistence format,
|
|
215
|
+
* so the read belongs here rather than in every host.
|
|
216
|
+
*
|
|
217
|
+
* `since` is the `cursor` from a previous read; the result then contains
|
|
218
|
+
* only messages recorded after it. The cursor is adapter-owned and opaque
|
|
219
|
+
* to the host.
|
|
220
|
+
*
|
|
221
|
+
* Optional capability: adapters that cannot read their runtime's store
|
|
222
|
+
* omit the method entirely, and the agent surfaces that as
|
|
223
|
+
* `HarnessCapabilityUnsupportedError`. An adapter that implements it but
|
|
224
|
+
* cannot reach the store from the current environment (e.g. it lives
|
|
225
|
+
* inside a remote sandbox) throws `HarnessHistoryUnavailableError`. A
|
|
226
|
+
* conversation with no recorded messages yet is not an error — it resolves
|
|
227
|
+
* to an empty `messages` array.
|
|
228
|
+
*/
|
|
229
|
+
doReadHistory?(options: {
|
|
230
|
+
readonly since?: string;
|
|
231
|
+
}): PromiseLike<HarnessV1ReadHistoryResult>;
|
|
232
|
+
|
|
195
233
|
/**
|
|
196
234
|
* Continue the in-flight turn **without a new user prompt**, returning the
|
|
197
235
|
* same control surface as `doPromptTurn`. Used to keep consuming a turn that
|
package/src/v1/index.ts
CHANGED
|
@@ -13,9 +13,26 @@ export type {
|
|
|
13
13
|
export type {
|
|
14
14
|
HarnessV1ContinueTurnOptions,
|
|
15
15
|
HarnessV1PromptTurnOptions,
|
|
16
|
+
HarnessV1ReadHistoryResult,
|
|
16
17
|
HarnessV1Session,
|
|
17
18
|
HarnessV1StartOptions,
|
|
18
19
|
} from './harness-v1-session';
|
|
20
|
+
export type {
|
|
21
|
+
HarnessV1AssistantMessage,
|
|
22
|
+
HarnessV1CustomPart,
|
|
23
|
+
HarnessV1FilePart,
|
|
24
|
+
HarnessV1Message,
|
|
25
|
+
HarnessV1MessagePart,
|
|
26
|
+
HarnessV1ReasoningFilePart,
|
|
27
|
+
HarnessV1ReasoningPart,
|
|
28
|
+
HarnessV1TextPart,
|
|
29
|
+
HarnessV1ToolApprovalResponsePart,
|
|
30
|
+
HarnessV1ToolCallPart,
|
|
31
|
+
HarnessV1ToolMessage,
|
|
32
|
+
HarnessV1ToolResultOutput,
|
|
33
|
+
HarnessV1ToolResultPart,
|
|
34
|
+
HarnessV1UserMessage,
|
|
35
|
+
} from './harness-v1-message';
|
|
19
36
|
export type { HarnessV1Observability } from './harness-v1-observability';
|
|
20
37
|
export type { HarnessV1PromptControl } from './harness-v1-prompt-control';
|
|
21
38
|
export type { HarnessV1CallWarning } from './harness-v1-call-warning';
|