@ai-sdk/harness-acp 1.0.29 → 1.0.31
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 +23 -0
- package/README.md +10 -0
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +41 -12
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/bridge/package.json +2 -2
- package/dist/bridge/pnpm-lock.yaml +57 -55
- package/dist/index.d.ts +34 -6
- package/dist/index.js +125 -106
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/acp-auth.ts +38 -13
- package/src/acp-harness.ts +8 -2
- package/src/index.ts +3 -2
- package/src/v1/acp-v1-harness.ts +84 -42
- package/src/v1/acp-v1-lifecycle.ts +1 -29
- package/src/v1/acp-v1-prompt.ts +1 -1
- package/src/v1/acp-v1-settings.ts +27 -3
- package/src/v1/acp-v1-skills.ts +15 -56
- package/src/v1/bridge/acp-v1-bridge-environment.ts +8 -0
- package/src/v1/bridge/index.ts +9 -6
- package/src/v1/bridge/package.json +2 -2
- package/src/v1/bridge/pnpm-lock.yaml +57 -55
- package/src/v1/implementation.ts +9 -4
- package/src/v1/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness-acp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,16 +26,16 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ai-sdk/harness": "1.0.
|
|
30
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
29
|
+
"@ai-sdk/harness": "1.0.93",
|
|
30
|
+
"@ai-sdk/provider-utils": "5.0.33",
|
|
31
31
|
"ws": "^8.21.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"zod": "^3.25.76 || ^4.1.8"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@agentclientprotocol/sdk": "1.
|
|
38
|
-
"@modelcontextprotocol/sdk": "1.
|
|
37
|
+
"@agentclientprotocol/sdk": "1.4.0",
|
|
38
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
39
39
|
"@types/node": "22.19.19",
|
|
40
40
|
"@types/ws": "^8.5.13",
|
|
41
41
|
"@vercel/ai-tsconfig": "0.0.0",
|
package/src/acp-auth.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getAiGatewayAuthFromEnv,
|
|
4
|
+
isHarnessAuthenticationEnvironment,
|
|
5
|
+
} from '@ai-sdk/harness/utils';
|
|
3
6
|
import type {
|
|
4
7
|
ACPAuthentication,
|
|
8
|
+
ACPAuthenticationMode as ACPV1AuthenticationMode,
|
|
5
9
|
ACPProviderAuthentication,
|
|
6
|
-
ACPProviderAuthenticationMode,
|
|
7
10
|
} from './v1';
|
|
8
11
|
import type { ACPResolvedProviderAuthentication } from './v1/bridge/acp-v1-bridge-environment';
|
|
9
12
|
|
|
10
13
|
const DEFAULT_AI_GATEWAY_BASE_URL = 'https://ai-gateway.vercel.sh';
|
|
11
14
|
|
|
12
|
-
export type
|
|
15
|
+
export type ACPAuthenticationMode = ACPV1AuthenticationMode;
|
|
13
16
|
|
|
14
17
|
export type ACPClientApp = {
|
|
15
18
|
readonly name: string;
|
|
@@ -17,7 +20,7 @@ export type ACPClientApp = {
|
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
type ACPAuthResolutionOptions = {
|
|
20
|
-
readonly mode?:
|
|
23
|
+
readonly mode?: ACPAuthenticationMode;
|
|
21
24
|
readonly providerAuthentication: ACPProviderAuthentication | undefined;
|
|
22
25
|
readonly clientApp: ACPClientApp;
|
|
23
26
|
};
|
|
@@ -102,6 +105,10 @@ export function resolveACPProviderAuthentication({
|
|
|
102
105
|
AI_SDK_ACP_CLIENT_APP_NAME: auth.clientApp.name,
|
|
103
106
|
AI_SDK_ACP_CLIENT_APP_VERSION: auth.clientApp.version,
|
|
104
107
|
};
|
|
108
|
+
const resolvedEnv = resolveACPAuthenticationEnvironment({
|
|
109
|
+
auth: auth.mode,
|
|
110
|
+
env,
|
|
111
|
+
});
|
|
105
112
|
const providerAuthentication = auth.providerAuthentication;
|
|
106
113
|
if (providerAuthentication == null) {
|
|
107
114
|
return { providerAuthentication: undefined, env: clientAppEnv };
|
|
@@ -114,7 +121,7 @@ export function resolveACPProviderAuthentication({
|
|
|
114
121
|
};
|
|
115
122
|
}
|
|
116
123
|
|
|
117
|
-
const mode = auth.mode
|
|
124
|
+
const mode = resolveACPProviderAuthenticationMode(auth.mode);
|
|
118
125
|
if (mode === 'direct') {
|
|
119
126
|
return {
|
|
120
127
|
providerAuthentication: { type: 'direct' },
|
|
@@ -126,12 +133,12 @@ export function resolveACPProviderAuthentication({
|
|
|
126
133
|
compatibility?.type === 'ai-gateway'
|
|
127
134
|
? {
|
|
128
135
|
apiKey: resolveGatewayCredential({
|
|
129
|
-
env,
|
|
136
|
+
env: resolvedEnv,
|
|
130
137
|
credentialSource: compatibility.credentialSource,
|
|
131
138
|
}),
|
|
132
139
|
baseUrl: compatibility.baseUrl,
|
|
133
140
|
}
|
|
134
|
-
: getAiGatewayAuthFromEnv({ env });
|
|
141
|
+
: getAiGatewayAuthFromEnv({ env: resolvedEnv });
|
|
135
142
|
const apiKey = gateway.apiKey;
|
|
136
143
|
if (compatibility == null && mode === 'auto' && apiKey == null) {
|
|
137
144
|
return {
|
|
@@ -166,20 +173,22 @@ export function resolveACPProviderAuthenticationCompatibility({
|
|
|
166
173
|
providerAuthentication,
|
|
167
174
|
env,
|
|
168
175
|
}: {
|
|
169
|
-
auth?:
|
|
176
|
+
auth?: ACPAuthenticationMode;
|
|
170
177
|
providerAuthentication: ACPProviderAuthentication | undefined;
|
|
171
178
|
env: Record<string, string | undefined>;
|
|
172
179
|
}): ACPProviderAuthenticationCompatibility | undefined {
|
|
180
|
+
const resolvedEnv = resolveACPAuthenticationEnvironment({
|
|
181
|
+
auth,
|
|
182
|
+
env,
|
|
183
|
+
});
|
|
173
184
|
if (providerAuthentication == null) return undefined;
|
|
174
185
|
|
|
175
|
-
const mode = auth;
|
|
186
|
+
const mode = resolveACPProviderAuthenticationMode(auth);
|
|
176
187
|
if (mode === 'direct') {
|
|
177
188
|
return { type: 'direct', mode };
|
|
178
189
|
}
|
|
179
190
|
|
|
180
|
-
const credentialSource = resolveGatewayCredentialSource({
|
|
181
|
-
env,
|
|
182
|
-
});
|
|
191
|
+
const credentialSource = resolveGatewayCredentialSource({ env: resolvedEnv });
|
|
183
192
|
if (mode === 'auto' && credentialSource == null) {
|
|
184
193
|
return { type: 'direct', mode };
|
|
185
194
|
}
|
|
@@ -189,10 +198,26 @@ export function resolveACPProviderAuthenticationCompatibility({
|
|
|
189
198
|
mode,
|
|
190
199
|
env: providerAuthentication.gateway.env,
|
|
191
200
|
credentialSource,
|
|
192
|
-
baseUrl:
|
|
201
|
+
baseUrl: resolvedEnv.AI_GATEWAY_BASE_URL ?? DEFAULT_AI_GATEWAY_BASE_URL,
|
|
193
202
|
};
|
|
194
203
|
}
|
|
195
204
|
|
|
205
|
+
function resolveACPProviderAuthenticationMode(
|
|
206
|
+
auth: ACPAuthenticationMode | undefined,
|
|
207
|
+
): Extract<ACPAuthenticationMode, string> {
|
|
208
|
+
return typeof auth === 'string' || auth == null ? (auth ?? 'auto') : 'auto';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function resolveACPAuthenticationEnvironment({
|
|
212
|
+
auth,
|
|
213
|
+
env,
|
|
214
|
+
}: {
|
|
215
|
+
auth: ACPAuthenticationMode | undefined;
|
|
216
|
+
env: Record<string, string | undefined>;
|
|
217
|
+
}): Record<string, string | undefined> {
|
|
218
|
+
return isHarnessAuthenticationEnvironment(auth) ? auth : env;
|
|
219
|
+
}
|
|
220
|
+
|
|
196
221
|
export function resolveACPEnv({
|
|
197
222
|
auth,
|
|
198
223
|
env,
|
package/src/acp-harness.ts
CHANGED
|
@@ -49,6 +49,13 @@ export type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}> = {
|
|
|
49
49
|
readonly env?: ACPV1Settings['env'];
|
|
50
50
|
readonly authentication?: ACPV1Settings['authentication'];
|
|
51
51
|
readonly providerAuthentication?: ACPV1Settings['providerAuthentication'];
|
|
52
|
+
/**
|
|
53
|
+
* Maps a HarnessAgent model identifier to implementation launch settings.
|
|
54
|
+
*/
|
|
55
|
+
readonly resolveModel: ACPV1Settings['resolveModel'];
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated Use `model` on `HarnessAgent` instead.
|
|
58
|
+
*/
|
|
52
59
|
readonly modelId?: ACPV1Settings['modelId'];
|
|
53
60
|
readonly skillsDirectory?: ACPV1Settings['skillsDirectory'];
|
|
54
61
|
readonly instructionMapping?: ACPV1Settings['instructionMapping'];
|
|
@@ -103,8 +110,7 @@ const acpResumeStateSchema = z.object({
|
|
|
103
110
|
})
|
|
104
111
|
.optional(),
|
|
105
112
|
initialGuidanceApplied: z.boolean().optional(),
|
|
106
|
-
|
|
107
|
-
skillsFingerprint: z.string().optional(),
|
|
113
|
+
instructionsFingerprint: z.string().optional(),
|
|
108
114
|
skillsDirectory: z.string().optional(),
|
|
109
115
|
});
|
|
110
116
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createACP } from './acp-harness';
|
|
2
|
-
export type {
|
|
2
|
+
export type { ACPAuthenticationMode, ACPClientApp } from './acp-auth';
|
|
3
3
|
export type { ACPHarnessSettings } from './acp-harness';
|
|
4
4
|
export type {
|
|
5
5
|
ACPAnnotations,
|
|
@@ -24,6 +24,8 @@ export type {
|
|
|
24
24
|
ACPAuthentication,
|
|
25
25
|
ACPInstallCommandSource,
|
|
26
26
|
ACPInstructionMapping,
|
|
27
|
+
ACPModelResolution,
|
|
28
|
+
ACPModelResolver,
|
|
27
29
|
ACPNpmLockedSource,
|
|
28
30
|
ACPNpmSimpleSource,
|
|
29
31
|
ACPOutputSchemaMapping,
|
|
@@ -31,7 +33,6 @@ export type {
|
|
|
31
33
|
ACPPermissionModeTarget,
|
|
32
34
|
ACPProfileValue,
|
|
33
35
|
ACPProviderAuthentication,
|
|
34
|
-
ACPProviderAuthenticationMode,
|
|
35
36
|
ACPSerializablePrimitive,
|
|
36
37
|
ACPSerializableValue,
|
|
37
38
|
ACPSource,
|
package/src/v1/acp-v1-harness.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type HarnessV1PortEndpoint,
|
|
10
10
|
type HarnessV1PromptControl,
|
|
11
11
|
type HarnessV1Session,
|
|
12
|
+
type HarnessV1Skill,
|
|
12
13
|
type HarnessV1StreamPart,
|
|
13
14
|
type HarnessV1ToolSpec,
|
|
14
15
|
} from '@ai-sdk/harness';
|
|
@@ -39,6 +40,7 @@ import {
|
|
|
39
40
|
import { WebSocket } from 'ws';
|
|
40
41
|
import {
|
|
41
42
|
createACPAuthenticationProfileIdentity,
|
|
43
|
+
resolveACPAuthenticationEnvironment,
|
|
42
44
|
resolveACPProviderAuthentication,
|
|
43
45
|
resolveACPProviderAuthenticationCompatibility,
|
|
44
46
|
type ACPAuthenticationProfileIdentity,
|
|
@@ -69,13 +71,12 @@ import {
|
|
|
69
71
|
} from './acp-v1-turn-start-config';
|
|
70
72
|
import {
|
|
71
73
|
resolveACPInitialGuidanceApplied,
|
|
72
|
-
shouldMaterializeACPSkills,
|
|
73
74
|
validateACPLifecycleCompatibility,
|
|
74
75
|
type ACPLifecycleData,
|
|
75
76
|
} from './acp-v1-lifecycle';
|
|
76
77
|
import {
|
|
77
78
|
convertHarnessPromptToACPTextBlocks,
|
|
78
|
-
|
|
79
|
+
prependACPInstructionGuidance,
|
|
79
80
|
} from './acp-v1-prompt';
|
|
80
81
|
import type {
|
|
81
82
|
ACPInstructionMapping,
|
|
@@ -87,7 +88,6 @@ import type {
|
|
|
87
88
|
ACPV1Settings,
|
|
88
89
|
} from './acp-v1-settings';
|
|
89
90
|
import {
|
|
90
|
-
createACPSkillsFingerprint,
|
|
91
91
|
materializeACPSkills,
|
|
92
92
|
resolveACPPrivateSessionDirectory,
|
|
93
93
|
resolveACPSkillsDirectory,
|
|
@@ -158,11 +158,11 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
158
158
|
`ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`,
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
|
-
const
|
|
162
|
-
validateACPV1Implementation(
|
|
161
|
+
const baseImplementation = createACPV1Implementation({ settings });
|
|
162
|
+
validateACPV1Implementation(baseImplementation);
|
|
163
163
|
const bootstrap = createACPBootstrap({
|
|
164
164
|
harnessId: settings.harnessId,
|
|
165
|
-
implementation,
|
|
165
|
+
implementation: baseImplementation,
|
|
166
166
|
});
|
|
167
167
|
const permissionModeMapping = isCompletePermissionModeMapping({
|
|
168
168
|
value: settings.permissionModeMapping,
|
|
@@ -186,8 +186,30 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
186
186
|
'ACP built-in tool filtering is not available in this initial ACP v1 implementation.',
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
|
+
const modelId = startOptions.model ?? settings.modelId;
|
|
190
|
+
const modelConfiguration =
|
|
191
|
+
modelId == null ? undefined : settings.resolveModel({ model: modelId });
|
|
192
|
+
const implementation = {
|
|
193
|
+
...baseImplementation,
|
|
194
|
+
...(modelConfiguration?.args == null
|
|
195
|
+
? {}
|
|
196
|
+
: { args: modelConfiguration.args }),
|
|
197
|
+
...(modelConfiguration?.env == null
|
|
198
|
+
? {}
|
|
199
|
+
: {
|
|
200
|
+
env: {
|
|
201
|
+
...baseImplementation.env,
|
|
202
|
+
...modelConfiguration.env,
|
|
203
|
+
},
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
validateACPV1Implementation(implementation);
|
|
189
207
|
const permissionMode = startOptions.permissionMode ?? 'allow-all';
|
|
190
208
|
const env = { ...process.env };
|
|
209
|
+
const authenticationEnvironment = resolveACPAuthenticationEnvironment({
|
|
210
|
+
auth: settings.auth,
|
|
211
|
+
env,
|
|
212
|
+
});
|
|
191
213
|
const providerAuthenticationCompatibility =
|
|
192
214
|
resolveACPProviderAuthenticationCompatibility({
|
|
193
215
|
auth: settings.auth,
|
|
@@ -259,6 +281,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
259
281
|
const implementationEnvironment = resolveImplementationEnvironment({
|
|
260
282
|
implementation,
|
|
261
283
|
env,
|
|
284
|
+
credentialEnv: authenticationEnvironment,
|
|
262
285
|
});
|
|
263
286
|
let sandboxImplementationEnvironment = implementationEnvironment;
|
|
264
287
|
let sandboxProviderAuthenticationEnvironment =
|
|
@@ -375,24 +398,6 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
375
398
|
sessionWorkDir: workDir,
|
|
376
399
|
});
|
|
377
400
|
const bridgeStateDir = `${privateSessionDir}/bridge`;
|
|
378
|
-
const skills = startOptions.skills ?? [];
|
|
379
|
-
const skillsFingerprint = createACPSkillsFingerprint({ skills });
|
|
380
|
-
const shouldMaterializeSkills = shouldMaterializeACPSkills({
|
|
381
|
-
isResume,
|
|
382
|
-
lifecycleState: lifecycleData,
|
|
383
|
-
skillsFingerprint,
|
|
384
|
-
skillsDirectory,
|
|
385
|
-
});
|
|
386
|
-
if (skills.length > 0) {
|
|
387
|
-
await materializeACPSkills({
|
|
388
|
-
sandbox: toolSafeSandboxSession,
|
|
389
|
-
rootDir: skillsDirectory,
|
|
390
|
-
sessionWorkDir: workDir,
|
|
391
|
-
skills,
|
|
392
|
-
shouldMaterialize: shouldMaterializeSkills,
|
|
393
|
-
abortSignal: startOptions.abortSignal,
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
401
|
const report = startOptions.observability?.report;
|
|
397
402
|
const onDiagnostic = report
|
|
398
403
|
? (frame: Parameters<typeof harnessV1DiagnosticFromBridgeFrame>[0]) =>
|
|
@@ -447,7 +452,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
447
452
|
harnessId: settings.harnessId,
|
|
448
453
|
channel: attachChannel,
|
|
449
454
|
proc: undefined,
|
|
450
|
-
modelId
|
|
455
|
+
modelId,
|
|
451
456
|
sessionMeta: settings.session?.meta,
|
|
452
457
|
instructionMapping: settings.instructionMapping,
|
|
453
458
|
outputSchemaMapping: settings.outputSchemaMapping,
|
|
@@ -463,7 +468,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
463
468
|
isResume: true,
|
|
464
469
|
lifecycleState: lifecycleData,
|
|
465
470
|
}),
|
|
466
|
-
|
|
471
|
+
instructionsFingerprint: lifecycleData.instructionsFingerprint,
|
|
472
|
+
sandbox: toolSafeSandboxSession,
|
|
473
|
+
sessionWorkDir: workDir,
|
|
467
474
|
skillsDirectory,
|
|
468
475
|
acpSessionId: lifecycleData.acpSessionId,
|
|
469
476
|
bridgePort: coords.port,
|
|
@@ -537,7 +544,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
537
544
|
}
|
|
538
545
|
const turnStartConfig = validateACPColdSessionConfiguration({
|
|
539
546
|
coldSession,
|
|
540
|
-
modelId
|
|
547
|
+
modelId,
|
|
541
548
|
permissionMode,
|
|
542
549
|
authenticationProfile,
|
|
543
550
|
sessionMeta: settings.session?.meta,
|
|
@@ -601,6 +608,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
601
608
|
providerEnvironment:
|
|
602
609
|
sandboxProviderEnvironment == null ? undefined : {},
|
|
603
610
|
sessionMeta: settings.session?.meta,
|
|
611
|
+
implementationArgs: modelConfiguration?.args,
|
|
612
|
+
implementationEnv: modelConfiguration?.env,
|
|
604
613
|
}),
|
|
605
614
|
...sandboxProviderAuthenticationEnvironment,
|
|
606
615
|
BRIDGE_CHANNEL_TOKEN: token,
|
|
@@ -713,7 +722,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
713
722
|
harnessId: settings.harnessId,
|
|
714
723
|
channel,
|
|
715
724
|
proc,
|
|
716
|
-
modelId
|
|
725
|
+
modelId,
|
|
717
726
|
sessionMeta: settings.session?.meta,
|
|
718
727
|
instructionMapping: settings.instructionMapping,
|
|
719
728
|
outputSchemaMapping: settings.outputSchemaMapping,
|
|
@@ -729,7 +738,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
729
738
|
isResume,
|
|
730
739
|
lifecycleState: lifecycleData,
|
|
731
740
|
}),
|
|
732
|
-
|
|
741
|
+
instructionsFingerprint: lifecycleData?.instructionsFingerprint,
|
|
742
|
+
sandbox: toolSafeSandboxSession,
|
|
743
|
+
sessionWorkDir: workDir,
|
|
733
744
|
skillsDirectory,
|
|
734
745
|
acpSessionId: lifecycleData?.acpSessionId,
|
|
735
746
|
bridgePort: boundPort,
|
|
@@ -1048,7 +1059,9 @@ function createSession({
|
|
|
1048
1059
|
mcpServers,
|
|
1049
1060
|
isMcpToolCall,
|
|
1050
1061
|
initialGuidanceApplied: initialGuidanceAppliedAtStart,
|
|
1051
|
-
|
|
1062
|
+
instructionsFingerprint: instructionsFingerprintAtStart,
|
|
1063
|
+
sandbox,
|
|
1064
|
+
sessionWorkDir,
|
|
1052
1065
|
skillsDirectory,
|
|
1053
1066
|
acpSessionId: acpSessionIdAtStart,
|
|
1054
1067
|
bridgePort,
|
|
@@ -1081,7 +1094,9 @@ function createSession({
|
|
|
1081
1094
|
mcpServers: Record<string, unknown> | undefined;
|
|
1082
1095
|
isMcpToolCall: ((toolCall: ACPToolCall) => boolean) | undefined;
|
|
1083
1096
|
initialGuidanceApplied: boolean;
|
|
1084
|
-
|
|
1097
|
+
instructionsFingerprint: string | undefined;
|
|
1098
|
+
sandbox: SandboxSession;
|
|
1099
|
+
sessionWorkDir: string;
|
|
1085
1100
|
skillsDirectory: string;
|
|
1086
1101
|
acpSessionId: string | undefined;
|
|
1087
1102
|
bridgePort: number;
|
|
@@ -1100,6 +1115,7 @@ function createSession({
|
|
|
1100
1115
|
let stopped = false;
|
|
1101
1116
|
let turnInFlight = turnInFlightAtStart;
|
|
1102
1117
|
let initialGuidanceApplied = initialGuidanceAppliedAtStart;
|
|
1118
|
+
let instructionsFingerprint = instructionsFingerprintAtStart;
|
|
1103
1119
|
let latestACPSessionId = acpSessionIdAtStart;
|
|
1104
1120
|
let latestTurnStartConfig = turnStartConfigAtStart;
|
|
1105
1121
|
|
|
@@ -1368,16 +1384,35 @@ function createSession({
|
|
|
1368
1384
|
...(recoveryStatus == null ? {} : { recovery: recoveryStatus }),
|
|
1369
1385
|
...(restoration == null ? {} : { restoration }),
|
|
1370
1386
|
initialGuidanceApplied,
|
|
1371
|
-
|
|
1372
|
-
skillsFingerprint,
|
|
1387
|
+
...(instructionsFingerprint == null ? {} : { instructionsFingerprint }),
|
|
1373
1388
|
skillsDirectory,
|
|
1374
1389
|
});
|
|
1375
1390
|
|
|
1391
|
+
const synchronizeSkills = async ({
|
|
1392
|
+
skills,
|
|
1393
|
+
abortSignal,
|
|
1394
|
+
}: {
|
|
1395
|
+
skills: ReadonlyArray<HarnessV1Skill>;
|
|
1396
|
+
abortSignal?: AbortSignal;
|
|
1397
|
+
}): Promise<void> => {
|
|
1398
|
+
await materializeACPSkills({
|
|
1399
|
+
sandbox,
|
|
1400
|
+
rootDir: skillsDirectory,
|
|
1401
|
+
sessionWorkDir,
|
|
1402
|
+
skills,
|
|
1403
|
+
abortSignal,
|
|
1404
|
+
});
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1376
1407
|
return {
|
|
1377
1408
|
sessionId,
|
|
1378
1409
|
isResume,
|
|
1379
1410
|
...(modelId == null ? {} : { modelId }),
|
|
1380
1411
|
doPromptTurn: async options => {
|
|
1412
|
+
await synchronizeSkills({
|
|
1413
|
+
skills: options.skills,
|
|
1414
|
+
abortSignal: options.abortSignal,
|
|
1415
|
+
});
|
|
1381
1416
|
if (options.responseFormat?.type === 'json') {
|
|
1382
1417
|
if (options.responseFormat.schema == null) {
|
|
1383
1418
|
throw unsupported({
|
|
@@ -1421,6 +1456,9 @@ function createSession({
|
|
|
1421
1456
|
responseFormat: options.responseFormat,
|
|
1422
1457
|
outputSchemaMapping,
|
|
1423
1458
|
});
|
|
1459
|
+
const nextInstructionsFingerprint = fingerprintValue({
|
|
1460
|
+
value: options.instructions ?? null,
|
|
1461
|
+
});
|
|
1424
1462
|
const control = wireTurn({
|
|
1425
1463
|
emit: options.emit,
|
|
1426
1464
|
abortSignal: options.abortSignal,
|
|
@@ -1433,15 +1471,14 @@ function createSession({
|
|
|
1433
1471
|
turnInFlight = true;
|
|
1434
1472
|
channel.send({
|
|
1435
1473
|
type: 'start',
|
|
1436
|
-
prompt:
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
}),
|
|
1474
|
+
prompt:
|
|
1475
|
+
instructionsFingerprint !== nextInstructionsFingerprint &&
|
|
1476
|
+
(instructionMapping == null || initialGuidanceApplied)
|
|
1477
|
+
? prependACPInstructionGuidance({
|
|
1478
|
+
prompt,
|
|
1479
|
+
instructions: options.instructions,
|
|
1480
|
+
})
|
|
1481
|
+
: prompt,
|
|
1445
1482
|
...(instructionMapping == null
|
|
1446
1483
|
? {}
|
|
1447
1484
|
: {
|
|
@@ -1466,11 +1503,16 @@ function createSession({
|
|
|
1466
1503
|
});
|
|
1467
1504
|
latestTurnStartConfig = turnStartConfig;
|
|
1468
1505
|
initialGuidanceApplied = true;
|
|
1506
|
+
instructionsFingerprint = nextInstructionsFingerprint;
|
|
1469
1507
|
},
|
|
1470
1508
|
});
|
|
1471
1509
|
return control;
|
|
1472
1510
|
},
|
|
1473
1511
|
doContinueTurn: async options => {
|
|
1512
|
+
await synchronizeSkills({
|
|
1513
|
+
skills: options.skills,
|
|
1514
|
+
abortSignal: options.abortSignal,
|
|
1515
|
+
});
|
|
1474
1516
|
if (options.responseFormat?.type === 'json') {
|
|
1475
1517
|
if (options.responseFormat.schema == null) {
|
|
1476
1518
|
throw unsupported({
|
|
@@ -6,8 +6,7 @@ import type {
|
|
|
6
6
|
|
|
7
7
|
export type ACPPromptGuidanceLifecycleState = {
|
|
8
8
|
readonly initialGuidanceApplied?: boolean;
|
|
9
|
-
readonly
|
|
10
|
-
readonly skillsFingerprint?: string;
|
|
9
|
+
readonly instructionsFingerprint?: string;
|
|
11
10
|
readonly skillsDirectory?: string;
|
|
12
11
|
};
|
|
13
12
|
|
|
@@ -47,33 +46,6 @@ export function resolveACPInitialGuidanceApplied({
|
|
|
47
46
|
return lifecycleState?.initialGuidanceApplied ?? true;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
export function shouldMaterializeACPSkills({
|
|
51
|
-
isResume,
|
|
52
|
-
lifecycleState,
|
|
53
|
-
skillsFingerprint,
|
|
54
|
-
skillsDirectory,
|
|
55
|
-
}: {
|
|
56
|
-
isResume: boolean;
|
|
57
|
-
lifecycleState: ACPPromptGuidanceLifecycleState | undefined;
|
|
58
|
-
skillsFingerprint: string;
|
|
59
|
-
skillsDirectory: string;
|
|
60
|
-
}): boolean {
|
|
61
|
-
if (
|
|
62
|
-
isResume &&
|
|
63
|
-
lifecycleState?.skillsFingerprint != null &&
|
|
64
|
-
lifecycleState.skillsFingerprint !== skillsFingerprint
|
|
65
|
-
) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
'ACP lifecycle state was created with a different set of skills.',
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
return (
|
|
71
|
-
!isResume ||
|
|
72
|
-
lifecycleState?.skillsMaterialized !== true ||
|
|
73
|
-
lifecycleState.skillsDirectory !== skillsDirectory
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
49
|
export function validateACPLifecycleCompatibility({
|
|
78
50
|
harnessId,
|
|
79
51
|
lifecycleHarnessId,
|
package/src/v1/acp-v1-prompt.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
HarnessV1Authentication,
|
|
2
3
|
HarnessV1CredentialForwarding,
|
|
3
4
|
HarnessV1PermissionMode,
|
|
4
5
|
HarnessV1RequestTransformation,
|
|
@@ -66,7 +67,7 @@ export type ACPAuthentication = {
|
|
|
66
67
|
readonly clientCapabilities?: Readonly<Record<string, ACPSerializableValue>>;
|
|
67
68
|
};
|
|
68
69
|
|
|
69
|
-
export type
|
|
70
|
+
export type ACPAuthenticationMode = HarnessV1Authentication;
|
|
70
71
|
|
|
71
72
|
export type ACPProviderAuthentication = {
|
|
72
73
|
readonly gateway: {
|
|
@@ -74,6 +75,21 @@ export type ACPProviderAuthentication = {
|
|
|
74
75
|
};
|
|
75
76
|
};
|
|
76
77
|
|
|
78
|
+
export type ACPModelResolution = {
|
|
79
|
+
/**
|
|
80
|
+
* Replaces the implementation's static launch arguments.
|
|
81
|
+
*/
|
|
82
|
+
readonly args?: ReadonlyArray<string>;
|
|
83
|
+
/**
|
|
84
|
+
* Overlays the implementation's static launch environment.
|
|
85
|
+
*/
|
|
86
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export type ACPModelResolver = (options: {
|
|
90
|
+
readonly model: string;
|
|
91
|
+
}) => ACPModelResolution;
|
|
92
|
+
|
|
77
93
|
export type ACPCredentialBrokering = ({
|
|
78
94
|
env,
|
|
79
95
|
sandboxEnv,
|
|
@@ -123,7 +139,7 @@ export type ACPV1Settings = {
|
|
|
123
139
|
readonly harnessId: string;
|
|
124
140
|
readonly mcpServers?: Record<string, unknown>;
|
|
125
141
|
readonly isMcpToolCall?: (toolCall: ACPToolCall) => boolean;
|
|
126
|
-
readonly auth?:
|
|
142
|
+
readonly auth?: ACPAuthenticationMode;
|
|
127
143
|
readonly source: ACPSource;
|
|
128
144
|
readonly executable: string;
|
|
129
145
|
readonly args?: ReadonlyArray<string>;
|
|
@@ -143,6 +159,13 @@ export type ACPV1Settings = {
|
|
|
143
159
|
readonly env?: Readonly<Record<string, string>>;
|
|
144
160
|
readonly authentication?: ACPAuthentication;
|
|
145
161
|
readonly providerAuthentication?: ACPProviderAuthentication;
|
|
162
|
+
/**
|
|
163
|
+
* Maps a HarnessAgent model identifier to implementation launch settings.
|
|
164
|
+
*/
|
|
165
|
+
readonly resolveModel: ACPModelResolver;
|
|
166
|
+
/**
|
|
167
|
+
* @deprecated Use `model` on `HarnessAgent` instead.
|
|
168
|
+
*/
|
|
146
169
|
readonly modelId?: string;
|
|
147
170
|
/**
|
|
148
171
|
* Native skills directory relative to the ACP implementation's home
|
|
@@ -151,7 +174,8 @@ export type ACPV1Settings = {
|
|
|
151
174
|
readonly skillsDirectory?: string;
|
|
152
175
|
/**
|
|
153
176
|
* Routes HarnessAgent instructions to a runtime-native system or developer
|
|
154
|
-
* prompt.
|
|
177
|
+
* prompt. Changed instructions are prepended to the next user prompt when
|
|
178
|
+
* ACP does not expose a native per-turn instruction update.
|
|
155
179
|
*/
|
|
156
180
|
readonly instructionMapping?: ACPInstructionMapping;
|
|
157
181
|
/**
|