@ai-sdk/harness 1.0.87 → 1.0.90
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 +27 -0
- package/dist/agent/index.d.ts +5 -0
- package/dist/agent/index.js +20 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +18 -3
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +16 -6
- package/dist/utils/index.js +62 -27
- package/dist/utils/index.js.map +1 -1
- package/package.json +4 -4
- package/src/agent/internal/run-prompt.ts +35 -4
- package/src/utils/credential-forwarding.ts +30 -0
- package/src/utils/index.ts +6 -1
- package/src/utils/sandbox-credential-brokering.ts +23 -6
- package/src/v1/harness-v1-credential-forwarding.ts +4 -2
- package/src/v1/harness-v1-network-sandbox-session.ts +6 -0
- package/src/v1/harness-v1-stream-part.ts +14 -3
- package/src/v1/index.ts +1 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HarnessV1CredentialForwarding } from '../v1';
|
|
2
|
+
import { generateSandboxCredentialPlaceholder } from './sandbox-credential-brokering';
|
|
2
3
|
|
|
3
4
|
export async function applyCredentialForwarding({
|
|
4
5
|
environment,
|
|
@@ -26,3 +27,32 @@ export async function applyCredentialForwarding({
|
|
|
26
27
|
|
|
27
28
|
return forwardedEnvironment;
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
export async function createSandboxCredentialEnvironment({
|
|
32
|
+
environment,
|
|
33
|
+
credentialEnvironmentVariables,
|
|
34
|
+
credentialForwarding,
|
|
35
|
+
}: {
|
|
36
|
+
environment: Readonly<Record<string, string>>;
|
|
37
|
+
credentialEnvironmentVariables: ReadonlyArray<string>;
|
|
38
|
+
credentialForwarding: HarnessV1CredentialForwarding | undefined;
|
|
39
|
+
}): Promise<Record<string, string>> {
|
|
40
|
+
const sandboxCredentialEnvironment: Record<string, string> = {};
|
|
41
|
+
|
|
42
|
+
for (const environmentVariableName of new Set(
|
|
43
|
+
credentialEnvironmentVariables,
|
|
44
|
+
)) {
|
|
45
|
+
if (environment[environmentVariableName] == null) continue;
|
|
46
|
+
|
|
47
|
+
const placeholder = generateSandboxCredentialPlaceholder();
|
|
48
|
+
sandboxCredentialEnvironment[environmentVariableName] =
|
|
49
|
+
credentialForwarding == null
|
|
50
|
+
? placeholder
|
|
51
|
+
: await credentialForwarding({
|
|
52
|
+
credential: placeholder,
|
|
53
|
+
environmentVariableName,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return sandboxCredentialEnvironment;
|
|
58
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -12,9 +12,14 @@ export {
|
|
|
12
12
|
} from './bridge-user-message-submitter';
|
|
13
13
|
export { classifyDiskLog, type DiskLogRecoveryMode } from './classify-disk-log';
|
|
14
14
|
export { getAiGatewayAuthFromEnv } from './ai-gateway-auth';
|
|
15
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
applyCredentialForwarding,
|
|
17
|
+
createSandboxCredentialEnvironment,
|
|
18
|
+
} from './credential-forwarding';
|
|
16
19
|
export {
|
|
17
20
|
createCredentialRequestTransformation,
|
|
21
|
+
generateSandboxCredentialPlaceholder,
|
|
22
|
+
isSandboxCredentialPlaceholder,
|
|
18
23
|
maskSandboxCredentials,
|
|
19
24
|
warnCredentialBrokeringUnavailable,
|
|
20
25
|
} from './sandbox-credential-brokering';
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
1
2
|
import type { HarnessV1RequestTransformation } from '../v1';
|
|
2
3
|
|
|
4
|
+
const SANDBOX_CREDENTIAL_PLACEHOLDER_PREFIX = 'aisdkhc_';
|
|
5
|
+
|
|
6
|
+
export function generateSandboxCredentialPlaceholder(): string {
|
|
7
|
+
return `${SANDBOX_CREDENTIAL_PLACEHOLDER_PREFIX}${randomBytes(32).toString('base64url')}`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isSandboxCredentialPlaceholder(value: string): boolean {
|
|
11
|
+
return /^aisdkhc_[A-Za-z0-9_-]{43}$/.test(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
3
14
|
export function warnCredentialBrokeringUnavailable(): void {
|
|
4
15
|
console.warn(
|
|
5
16
|
'The sandbox implementation does not support configuring request transformations, so credential brokering does not work. Falling back to less secure credential forwarding.',
|
|
@@ -23,19 +34,25 @@ export function maskSandboxCredentials({
|
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
export function createCredentialRequestTransformation({
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
matchUrl,
|
|
38
|
+
matchHeaders,
|
|
39
|
+
transformHeaders,
|
|
28
40
|
}: {
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
matchUrl: string;
|
|
42
|
+
matchHeaders: Readonly<Record<string, string>>;
|
|
43
|
+
transformHeaders: Readonly<Record<string, string>>;
|
|
31
44
|
}): HarnessV1RequestTransformation {
|
|
32
|
-
const url = new URL(
|
|
45
|
+
const url = new URL(matchUrl);
|
|
33
46
|
const pathname = url.pathname.replace(/\/+$/, '');
|
|
34
47
|
return {
|
|
35
48
|
match: {
|
|
36
49
|
host: url.hostname,
|
|
37
50
|
...(pathname.length === 0 ? {} : { path: { startsWith: pathname } }),
|
|
51
|
+
headers: Object.entries(matchHeaders).map(([key, value]) => ({
|
|
52
|
+
key: { exact: key },
|
|
53
|
+
value: { exact: value },
|
|
54
|
+
})),
|
|
38
55
|
},
|
|
39
|
-
transform: { headers },
|
|
56
|
+
transform: { headers: transformHeaders },
|
|
40
57
|
};
|
|
41
58
|
}
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export type HarnessV1CredentialForwarding = (options: {
|
|
10
10
|
/**
|
|
11
|
-
* The credential value that the adapter would otherwise forward
|
|
12
|
-
*
|
|
11
|
+
* The credential value that the adapter would otherwise forward. This is a
|
|
12
|
+
* generated sandbox placeholder when credential brokering is available and
|
|
13
|
+
* the real credential otherwise. Use `isSandboxCredentialPlaceholder` from
|
|
14
|
+
* `@ai-sdk/harness/utils` to distinguish generated placeholders.
|
|
13
15
|
*/
|
|
14
16
|
readonly credential: string;
|
|
15
17
|
/** The environment variable name used to expose the value in the sandbox. */
|
|
@@ -205,3 +205,9 @@ export type HarnessV1RequestTransformation = {
|
|
|
205
205
|
readonly headers: Readonly<Record<string, string>>;
|
|
206
206
|
};
|
|
207
207
|
};
|
|
208
|
+
|
|
209
|
+
export type HarnessV1RequestTransformationSources<AuthenticationMode> = {
|
|
210
|
+
env: Record<string, string>;
|
|
211
|
+
sandboxEnv: Record<string, string>;
|
|
212
|
+
auth: AuthenticationMode;
|
|
213
|
+
};
|
|
@@ -60,9 +60,14 @@ export type HarnessV1StreamPart =
|
|
|
60
60
|
|
|
61
61
|
// Tool calls, approvals, results — reuse V4 primitives.
|
|
62
62
|
//
|
|
63
|
-
// `nativeName`
|
|
64
|
-
//
|
|
65
|
-
//
|
|
63
|
+
// `nativeName` lets adapters surface the runtime's native name for a builtin
|
|
64
|
+
// when it differs from the wire `toolName` (e.g. `toolName: 'bash'`,
|
|
65
|
+
// `nativeName: 'Bash'`).
|
|
66
|
+
//
|
|
67
|
+
// `stepToolCallCount` lets adapters that know a step's complete tool-call
|
|
68
|
+
// set up front report its cardinality. The host uses it to collect every
|
|
69
|
+
// approval/result request from the step before pausing; adapters that cannot
|
|
70
|
+
// know the count omit it and retain pause-on-first behavior.
|
|
66
71
|
//
|
|
67
72
|
// Whether the call was executed by the underlying runtime (Claude Code's
|
|
68
73
|
// built-in `Bash`, Codex's `shell`) vs. needs host dispatch is signalled by
|
|
@@ -70,6 +75,11 @@ export type HarnessV1StreamPart =
|
|
|
70
75
|
// `true` for runtime-executed builtins, false/undefined for host tools.
|
|
71
76
|
| (LanguageModelV4ToolCall & {
|
|
72
77
|
nativeName?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Total tool calls in the current model step, when known before tool
|
|
80
|
+
* execution begins. Populate this on every tool call in the step.
|
|
81
|
+
*/
|
|
82
|
+
stepToolCallCount?: number;
|
|
73
83
|
})
|
|
74
84
|
| LanguageModelV4ToolApprovalRequest
|
|
75
85
|
| LanguageModelV4ToolResult
|
|
@@ -267,6 +277,7 @@ export const harnessV1ToolCallPartSchema = z.object({
|
|
|
267
277
|
dynamic: z.boolean().optional(),
|
|
268
278
|
providerMetadata: harnessV1ProviderMetadataSchema.optional(),
|
|
269
279
|
nativeName: z.string().optional(),
|
|
280
|
+
stepToolCallCount: z.number().int().positive().optional(),
|
|
270
281
|
});
|
|
271
282
|
|
|
272
283
|
export const harnessV1ToolApprovalRequestPartSchema = z.object({
|
package/src/v1/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ export type {
|
|
|
46
46
|
HarnessV1NetworkSandboxSession,
|
|
47
47
|
HarnessV1PortEndpoint,
|
|
48
48
|
HarnessV1RequestTransformation,
|
|
49
|
+
HarnessV1RequestTransformationSources,
|
|
49
50
|
} from './harness-v1-network-sandbox-session';
|
|
50
51
|
export type { HarnessV1Skill } from './harness-v1-skill';
|
|
51
52
|
export type { HarnessV1StreamPart } from './harness-v1-stream-part';
|