@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/harness-acp",
3
- "version": "1.0.29",
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.91",
30
- "@ai-sdk/provider-utils": "5.0.32",
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.2.1",
38
- "@modelcontextprotocol/sdk": "1.29.0",
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 { getAiGatewayAuthFromEnv } from '@ai-sdk/harness/utils';
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 ACPAuthOptions = ACPProviderAuthenticationMode;
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?: ACPAuthOptions;
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 ?? 'auto';
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?: ACPProviderAuthenticationMode;
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: env.AI_GATEWAY_BASE_URL ?? DEFAULT_AI_GATEWAY_BASE_URL,
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,
@@ -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
- skillsMaterialized: z.boolean().optional(),
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 { ACPAuthOptions, ACPClientApp } from './acp-auth';
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,
@@ -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
- prependACPInitialGuidance,
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 implementation = createACPV1Implementation({ settings });
162
- validateACPV1Implementation(implementation);
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: settings.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
- skillsFingerprint,
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: settings.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: settings.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
- skillsFingerprint,
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
- skillsFingerprint,
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
- skillsFingerprint: string;
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
- skillsMaterialized: true,
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: initialGuidanceApplied
1437
- ? prompt
1438
- : prependACPInitialGuidance({
1439
- prompt,
1440
- instructions:
1441
- instructionMapping == null
1442
- ? options.instructions
1443
- : undefined,
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 skillsMaterialized?: boolean;
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,
@@ -66,7 +66,7 @@ export function convertHarnessPromptToACPTextBlocks({
66
66
  return content;
67
67
  }
68
68
 
69
- export function prependACPInitialGuidance({
69
+ export function prependACPInstructionGuidance({
70
70
  prompt,
71
71
  instructions,
72
72
  }: {
@@ -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 ACPProviderAuthenticationMode = 'auto' | 'direct' | 'ai-gateway';
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?: ACPProviderAuthenticationMode;
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. When omitted, instructions are prepended to the first user 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
  /**