@ai-sdk/harness-acp 1.0.30 → 1.0.32

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.30",
3
+ "version": "1.0.32",
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.92",
30
- "@ai-sdk/provider-utils": "5.0.32",
29
+ "@ai-sdk/harness": "1.0.94",
30
+ "@ai-sdk/provider-utils": "5.0.34",
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",
@@ -48,7 +48,15 @@ export type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}> = {
48
48
  readonly credentialForwarding?: ACPV1Settings['credentialForwarding'];
49
49
  readonly env?: ACPV1Settings['env'];
50
50
  readonly authentication?: ACPV1Settings['authentication'];
51
+ readonly clientCapabilities?: ACPV1Settings['clientCapabilities'];
51
52
  readonly providerAuthentication?: ACPV1Settings['providerAuthentication'];
53
+ /**
54
+ * Maps the HarnessAgent model identifier to an ACP session operation.
55
+ */
56
+ readonly modelMapping: ACPV1Settings['modelMapping'];
57
+ /**
58
+ * @deprecated Use `model` on `HarnessAgent` instead.
59
+ */
52
60
  readonly modelId?: ACPV1Settings['modelId'];
53
61
  readonly skillsDirectory?: ACPV1Settings['skillsDirectory'];
54
62
  readonly instructionMapping?: ACPV1Settings['instructionMapping'];
@@ -103,8 +111,7 @@ const acpResumeStateSchema = z.object({
103
111
  })
104
112
  .optional(),
105
113
  initialGuidanceApplied: z.boolean().optional(),
106
- skillsMaterialized: z.boolean().optional(),
107
- skillsFingerprint: z.string().optional(),
114
+ instructionsFingerprint: z.string().optional(),
108
115
  skillsDirectory: z.string().optional(),
109
116
  });
110
117
 
package/src/index.ts CHANGED
@@ -24,6 +24,7 @@ export type {
24
24
  ACPAuthentication,
25
25
  ACPInstallCommandSource,
26
26
  ACPInstructionMapping,
27
+ ACPModelMapping,
27
28
  ACPNpmLockedSource,
28
29
  ACPNpmSimpleSource,
29
30
  ACPOutputSchemaMapping,
@@ -14,6 +14,7 @@ import { z } from 'zod/v4';
14
14
  import type { ACPToolCall } from '../acp-tool-call';
15
15
  import type {
16
16
  ACPInstructionMapping,
17
+ ACPModelMapping,
17
18
  ACPPermissionModeMapping,
18
19
  } from './acp-v1-settings';
19
20
  import { acpTextContentBlockSchema } from './acp-v1-prompt';
@@ -125,6 +126,20 @@ const outputSchemaMappingSchema: z.ZodType<ACPSerializableOutputSchemaMapping> =
125
126
  path: z.array(z.string().min(1)).min(1),
126
127
  });
127
128
 
129
+ const modelMappingSchema: z.ZodType<ACPModelMapping> = z.discriminatedUnion(
130
+ 'type',
131
+ [
132
+ z.object({
133
+ type: z.literal('session-config-option'),
134
+ path: z.string().min(1),
135
+ }),
136
+ z.object({
137
+ type: z.literal('session-model'),
138
+ path: z.string().min(1),
139
+ }),
140
+ ],
141
+ );
142
+
128
143
  export type ACPTurnStartConfig = {
129
144
  readonly version: 1;
130
145
  readonly configurationFingerprint: string;
@@ -133,6 +148,8 @@ export type ACPTurnStartConfig = {
133
148
  readonly builtinTools: Array<ACPBuiltinToolMapping>;
134
149
  readonly permissionMode: HarnessV1PermissionMode;
135
150
  readonly permissionModeMapping?: ACPPermissionModeMapping;
151
+ readonly model?: string;
152
+ readonly modelMapping?: ACPModelMapping;
136
153
  readonly debug?: HarnessV1DebugConfig;
137
154
  readonly responseFormat?: z.infer<
138
155
  typeof harnessV1BridgeStartBaseSchema
@@ -148,6 +165,8 @@ export const acpTurnStartConfigSchema = z.object({
148
165
  builtinTools: z.array(builtinToolSchema).default([]),
149
166
  permissionMode: harnessV1BridgeStartBaseSchema.shape.permissionMode.unwrap(),
150
167
  permissionModeMapping: permissionModeMappingSchema.optional(),
168
+ model: harnessV1BridgeStartBaseSchema.shape.model.optional(),
169
+ modelMapping: modelMappingSchema.optional(),
151
170
  debug: harnessV1BridgeStartBaseSchema.shape.debug.optional(),
152
171
  responseFormat:
153
172
  harnessV1BridgeStartBaseSchema.shape.responseFormat.optional(),
@@ -156,14 +175,15 @@ export const acpTurnStartConfigSchema = z.object({
156
175
 
157
176
  export type ACPColdSessionState = Omit<
158
177
  ACPTurnStartConfig,
159
- 'prompt' | 'debug'
160
- > & {
161
- readonly modelId?: string;
162
- };
178
+ 'prompt' | 'debug' | 'model' | 'modelMapping'
179
+ >;
163
180
 
164
181
  export const acpColdSessionStateSchema: z.ZodType<ACPColdSessionState> =
165
- acpTurnStartConfigSchema.omit({ prompt: true, debug: true }).extend({
166
- modelId: z.string().optional(),
182
+ acpTurnStartConfigSchema.omit({
183
+ prompt: true,
184
+ debug: true,
185
+ model: true,
186
+ modelMapping: true,
167
187
  });
168
188
 
169
189
  const lossyRecoverySchema = z.object({
@@ -203,6 +223,7 @@ export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
203
223
  tools: z.array(acpSerializableToolSpecSchema).optional(),
204
224
  builtinTools: z.array(builtinToolSchema).readonly().default([]),
205
225
  permissionModeMapping: permissionModeMappingSchema.optional(),
226
+ modelMapping: modelMappingSchema.optional(),
206
227
  turnStartConfig: acpTurnStartConfigSchema,
207
228
  recoveryMode: z
208
229
  .discriminatedUnion('type', [lossyRecoverySchema, coldRestoreSchema])
@@ -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';
@@ -70,16 +71,16 @@ import {
70
71
  } from './acp-v1-turn-start-config';
71
72
  import {
72
73
  resolveACPInitialGuidanceApplied,
73
- shouldMaterializeACPSkills,
74
74
  validateACPLifecycleCompatibility,
75
75
  type ACPLifecycleData,
76
76
  } from './acp-v1-lifecycle';
77
77
  import {
78
78
  convertHarnessPromptToACPTextBlocks,
79
- prependACPInitialGuidance,
79
+ prependACPInstructionGuidance,
80
80
  } from './acp-v1-prompt';
81
81
  import type {
82
82
  ACPInstructionMapping,
83
+ ACPModelMapping,
83
84
  ACPOutputSchemaMapping,
84
85
  ACPPermissionModeMapping,
85
86
  ACPPermissionModeTarget,
@@ -88,7 +89,6 @@ import type {
88
89
  ACPV1Settings,
89
90
  } from './acp-v1-settings';
90
91
  import {
91
- createACPSkillsFingerprint,
92
92
  materializeACPSkills,
93
93
  resolveACPPrivateSessionDirectory,
94
94
  resolveACPSkillsDirectory,
@@ -204,6 +204,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
204
204
  acpVersion: 'v1',
205
205
  implementation,
206
206
  clientApp,
207
+ clientCapabilities: settings.clientCapabilities,
208
+ modelMapping: settings.modelMapping,
207
209
  providerAuthentication: providerAuthenticationCompatibility,
208
210
  permissionModeMapping: settings.permissionModeMapping,
209
211
  });
@@ -381,24 +383,6 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
381
383
  sessionWorkDir: workDir,
382
384
  });
383
385
  const bridgeStateDir = `${privateSessionDir}/bridge`;
384
- const skills = startOptions.skills ?? [];
385
- const skillsFingerprint = createACPSkillsFingerprint({ skills });
386
- const shouldMaterializeSkills = shouldMaterializeACPSkills({
387
- isResume,
388
- lifecycleState: lifecycleData,
389
- skillsFingerprint,
390
- skillsDirectory,
391
- });
392
- if (skills.length > 0) {
393
- await materializeACPSkills({
394
- sandbox: toolSafeSandboxSession,
395
- rootDir: skillsDirectory,
396
- sessionWorkDir: workDir,
397
- skills,
398
- shouldMaterialize: shouldMaterializeSkills,
399
- abortSignal: startOptions.abortSignal,
400
- });
401
- }
402
386
  const report = startOptions.observability?.report;
403
387
  const onDiagnostic = report
404
388
  ? (frame: Parameters<typeof harnessV1DiagnosticFromBridgeFrame>[0]) =>
@@ -453,7 +437,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
453
437
  harnessId: settings.harnessId,
454
438
  channel: attachChannel,
455
439
  proc: undefined,
456
- modelId: settings.modelId,
440
+ modelMapping: settings.modelMapping,
441
+ defaultModelId: settings.modelId,
457
442
  sessionMeta: settings.session?.meta,
458
443
  instructionMapping: settings.instructionMapping,
459
444
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -469,7 +454,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
469
454
  isResume: true,
470
455
  lifecycleState: lifecycleData,
471
456
  }),
472
- skillsFingerprint,
457
+ instructionsFingerprint: lifecycleData.instructionsFingerprint,
458
+ sandbox: toolSafeSandboxSession,
459
+ sessionWorkDir: workDir,
473
460
  skillsDirectory,
474
461
  acpSessionId: lifecycleData.acpSessionId,
475
462
  bridgePort: coords.port,
@@ -517,6 +504,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
517
504
  sessionMeta: settings.session?.meta,
518
505
  instructionMapping: settings.instructionMapping,
519
506
  outputSchemaMapping: settings.outputSchemaMapping,
507
+ modelMapping: settings.modelMapping,
520
508
  builtinTools: builtinToolCatalog,
521
509
  permissionModeMapping,
522
510
  mcpServers: settings.mcpServers,
@@ -543,12 +531,12 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
543
531
  }
544
532
  const turnStartConfig = validateACPColdSessionConfiguration({
545
533
  coldSession,
546
- modelId: settings.modelId,
547
534
  permissionMode,
548
535
  authenticationProfile,
549
536
  sessionMeta: settings.session?.meta,
550
537
  instructionMapping: settings.instructionMapping,
551
538
  outputSchemaMapping: settings.outputSchemaMapping,
539
+ modelMapping: settings.modelMapping,
552
540
  builtinTools: builtinToolCatalog,
553
541
  permissionModeMapping,
554
542
  mcpServers: settings.mcpServers,
@@ -607,6 +595,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
607
595
  providerEnvironment:
608
596
  sandboxProviderEnvironment == null ? undefined : {},
609
597
  sessionMeta: settings.session?.meta,
598
+ clientCapabilities: settings.clientCapabilities,
610
599
  }),
611
600
  ...sandboxProviderAuthenticationEnvironment,
612
601
  BRIDGE_CHANNEL_TOKEN: token,
@@ -719,7 +708,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
719
708
  harnessId: settings.harnessId,
720
709
  channel,
721
710
  proc,
722
- modelId: settings.modelId,
711
+ modelMapping: settings.modelMapping,
712
+ defaultModelId: settings.modelId,
723
713
  sessionMeta: settings.session?.meta,
724
714
  instructionMapping: settings.instructionMapping,
725
715
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -735,7 +725,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
735
725
  isResume,
736
726
  lifecycleState: lifecycleData,
737
727
  }),
738
- skillsFingerprint,
728
+ instructionsFingerprint: lifecycleData?.instructionsFingerprint,
729
+ sandbox: toolSafeSandboxSession,
730
+ sessionWorkDir: workDir,
739
731
  skillsDirectory,
740
732
  acpSessionId: lifecycleData?.acpSessionId,
741
733
  bridgePort: boundPort,
@@ -1041,7 +1033,8 @@ function createSession({
1041
1033
  harnessId,
1042
1034
  channel,
1043
1035
  proc,
1044
- modelId,
1036
+ modelMapping,
1037
+ defaultModelId,
1045
1038
  sessionMeta,
1046
1039
  instructionMapping,
1047
1040
  outputSchemaMapping,
@@ -1054,7 +1047,9 @@ function createSession({
1054
1047
  mcpServers,
1055
1048
  isMcpToolCall,
1056
1049
  initialGuidanceApplied: initialGuidanceAppliedAtStart,
1057
- skillsFingerprint,
1050
+ instructionsFingerprint: instructionsFingerprintAtStart,
1051
+ sandbox,
1052
+ sessionWorkDir,
1058
1053
  skillsDirectory,
1059
1054
  acpSessionId: acpSessionIdAtStart,
1060
1055
  bridgePort,
@@ -1074,7 +1069,8 @@ function createSession({
1074
1069
  harnessId: string;
1075
1070
  channel: ACPChannel;
1076
1071
  proc: Experimental_SandboxProcess | undefined;
1077
- modelId: string | undefined;
1072
+ modelMapping: ACPModelMapping;
1073
+ defaultModelId: string | undefined;
1078
1074
  sessionMeta: Readonly<Record<string, ACPSerializableValue>> | undefined;
1079
1075
  instructionMapping: ACPInstructionMapping | undefined;
1080
1076
  outputSchemaMapping: ACPOutputSchemaMapping | undefined;
@@ -1087,7 +1083,9 @@ function createSession({
1087
1083
  mcpServers: Record<string, unknown> | undefined;
1088
1084
  isMcpToolCall: ((toolCall: ACPToolCall) => boolean) | undefined;
1089
1085
  initialGuidanceApplied: boolean;
1090
- skillsFingerprint: string;
1086
+ instructionsFingerprint: string | undefined;
1087
+ sandbox: SandboxSession;
1088
+ sessionWorkDir: string;
1091
1089
  skillsDirectory: string;
1092
1090
  acpSessionId: string | undefined;
1093
1091
  bridgePort: number;
@@ -1106,6 +1104,7 @@ function createSession({
1106
1104
  let stopped = false;
1107
1105
  let turnInFlight = turnInFlightAtStart;
1108
1106
  let initialGuidanceApplied = initialGuidanceAppliedAtStart;
1107
+ let instructionsFingerprint = instructionsFingerprintAtStart;
1109
1108
  let latestACPSessionId = acpSessionIdAtStart;
1110
1109
  let latestTurnStartConfig = turnStartConfigAtStart;
1111
1110
 
@@ -1365,7 +1364,6 @@ function createSession({
1365
1364
  : {
1366
1365
  coldSession: createACPColdSessionState({
1367
1366
  turnStartConfig: latestTurnStartConfig,
1368
- modelId,
1369
1367
  }),
1370
1368
  }),
1371
1369
  ...(!includeTurnStartConfig || latestTurnStartConfig == null
@@ -1374,16 +1372,34 @@ function createSession({
1374
1372
  ...(recoveryStatus == null ? {} : { recovery: recoveryStatus }),
1375
1373
  ...(restoration == null ? {} : { restoration }),
1376
1374
  initialGuidanceApplied,
1377
- skillsMaterialized: true,
1378
- skillsFingerprint,
1375
+ ...(instructionsFingerprint == null ? {} : { instructionsFingerprint }),
1379
1376
  skillsDirectory,
1380
1377
  });
1381
1378
 
1379
+ const synchronizeSkills = async ({
1380
+ skills,
1381
+ abortSignal,
1382
+ }: {
1383
+ skills: ReadonlyArray<HarnessV1Skill>;
1384
+ abortSignal?: AbortSignal;
1385
+ }): Promise<void> => {
1386
+ await materializeACPSkills({
1387
+ sandbox,
1388
+ rootDir: skillsDirectory,
1389
+ sessionWorkDir,
1390
+ skills,
1391
+ abortSignal,
1392
+ });
1393
+ };
1394
+
1382
1395
  return {
1383
1396
  sessionId,
1384
1397
  isResume,
1385
- ...(modelId == null ? {} : { modelId }),
1386
1398
  doPromptTurn: async options => {
1399
+ await synchronizeSkills({
1400
+ skills: options.skills,
1401
+ abortSignal: options.abortSignal,
1402
+ });
1387
1403
  if (options.responseFormat?.type === 'json') {
1388
1404
  if (options.responseFormat.schema == null) {
1389
1405
  throw unsupported({
@@ -1413,6 +1429,7 @@ function createSession({
1413
1429
  prompt: options.prompt,
1414
1430
  harnessId,
1415
1431
  });
1432
+ const model = options.model ?? defaultModelId;
1416
1433
  const turnStartConfig = createACPTurnStartConfig({
1417
1434
  prompt,
1418
1435
  tools: options.tools ?? [],
@@ -1426,6 +1443,11 @@ function createSession({
1426
1443
  instructionMapping,
1427
1444
  responseFormat: options.responseFormat,
1428
1445
  outputSchemaMapping,
1446
+ model,
1447
+ modelMapping,
1448
+ });
1449
+ const nextInstructionsFingerprint = fingerprintValue({
1450
+ value: options.instructions ?? null,
1429
1451
  });
1430
1452
  const control = wireTurn({
1431
1453
  emit: options.emit,
@@ -1439,15 +1461,14 @@ function createSession({
1439
1461
  turnInFlight = true;
1440
1462
  channel.send({
1441
1463
  type: 'start',
1442
- prompt: initialGuidanceApplied
1443
- ? prompt
1444
- : prependACPInitialGuidance({
1445
- prompt,
1446
- instructions:
1447
- instructionMapping == null
1448
- ? options.instructions
1449
- : undefined,
1450
- }),
1464
+ prompt:
1465
+ instructionsFingerprint !== nextInstructionsFingerprint &&
1466
+ (instructionMapping == null || initialGuidanceApplied)
1467
+ ? prependACPInstructionGuidance({
1468
+ prompt,
1469
+ instructions: options.instructions,
1470
+ })
1471
+ : prompt,
1451
1472
  ...(instructionMapping == null
1452
1473
  ? {}
1453
1474
  : {
@@ -1460,6 +1481,7 @@ function createSession({
1460
1481
  builtinTools,
1461
1482
  permissionMode,
1462
1483
  permissionModeMapping,
1484
+ ...(model == null ? {} : { model, modelMapping }),
1463
1485
  ...(options.responseFormat == null
1464
1486
  ? {}
1465
1487
  : { responseFormat: options.responseFormat }),
@@ -1472,11 +1494,16 @@ function createSession({
1472
1494
  });
1473
1495
  latestTurnStartConfig = turnStartConfig;
1474
1496
  initialGuidanceApplied = true;
1497
+ instructionsFingerprint = nextInstructionsFingerprint;
1475
1498
  },
1476
1499
  });
1477
1500
  return control;
1478
1501
  },
1479
1502
  doContinueTurn: async options => {
1503
+ await synchronizeSkills({
1504
+ skills: options.skills,
1505
+ abortSignal: options.abortSignal,
1506
+ });
1480
1507
  if (options.responseFormat?.type === 'json') {
1481
1508
  if (options.responseFormat.schema == null) {
1482
1509
  throw unsupported({
@@ -1518,6 +1545,12 @@ function createSession({
1518
1545
  builtinTools: turnStartConfig.builtinTools,
1519
1546
  permissionMode: turnStartConfig.permissionMode,
1520
1547
  permissionModeMapping: turnStartConfig.permissionModeMapping,
1548
+ ...(turnStartConfig.model == null
1549
+ ? {}
1550
+ : {
1551
+ model: turnStartConfig.model,
1552
+ modelMapping: turnStartConfig.modelMapping,
1553
+ }),
1521
1554
  ...(turnStartConfig.responseFormat == null
1522
1555
  ? {}
1523
1556
  : { responseFormat: turnStartConfig.responseFormat }),
@@ -1715,6 +1748,7 @@ function validateACPTurnStartConfig({
1715
1748
  sessionMeta,
1716
1749
  instructionMapping,
1717
1750
  outputSchemaMapping,
1751
+ modelMapping,
1718
1752
  builtinTools,
1719
1753
  permissionModeMapping,
1720
1754
  mcpServers,
@@ -1724,6 +1758,7 @@ function validateACPTurnStartConfig({
1724
1758
  sessionMeta: Readonly<Record<string, ACPSerializableValue>> | undefined;
1725
1759
  instructionMapping: ACPInstructionMapping | undefined;
1726
1760
  outputSchemaMapping: ACPOutputSchemaMapping | undefined;
1761
+ modelMapping: ACPModelMapping;
1727
1762
  builtinTools: ReadonlyArray<ACPBuiltinToolMapping>;
1728
1763
  permissionModeMapping: ACPPermissionModeMapping | undefined;
1729
1764
  mcpServers: Record<string, unknown> | undefined;
@@ -1741,6 +1776,8 @@ function validateACPTurnStartConfig({
1741
1776
  instructionMapping,
1742
1777
  responseFormat: turnStartConfig.responseFormat,
1743
1778
  outputSchemaMapping,
1779
+ model: turnStartConfig.model,
1780
+ modelMapping,
1744
1781
  });
1745
1782
  if (
1746
1783
  current.configurationFingerprint !==
@@ -1754,24 +1791,24 @@ function validateACPTurnStartConfig({
1754
1791
 
1755
1792
  function validateACPColdSessionConfiguration({
1756
1793
  coldSession,
1757
- modelId,
1758
1794
  permissionMode,
1759
1795
  authenticationProfile,
1760
1796
  sessionMeta,
1761
1797
  instructionMapping,
1762
1798
  outputSchemaMapping,
1799
+ modelMapping,
1763
1800
  builtinTools,
1764
1801
  permissionModeMapping,
1765
1802
  mcpServers,
1766
1803
  debug,
1767
1804
  }: {
1768
1805
  coldSession: ACPColdSessionState;
1769
- modelId: string | undefined;
1770
1806
  permissionMode: NonNullable<StartMessage['permissionMode']>;
1771
1807
  authenticationProfile: ACPAuthenticationProfileIdentity;
1772
1808
  sessionMeta: Readonly<Record<string, ACPSerializableValue>> | undefined;
1773
1809
  instructionMapping: ACPInstructionMapping | undefined;
1774
1810
  outputSchemaMapping: ACPOutputSchemaMapping | undefined;
1811
+ modelMapping: ACPModelMapping;
1775
1812
  builtinTools: ReadonlyArray<ACPBuiltinToolMapping>;
1776
1813
  permissionModeMapping: ACPPermissionModeMapping | undefined;
1777
1814
  mcpServers: Record<string, unknown> | undefined;
@@ -1790,11 +1827,12 @@ function validateACPColdSessionConfiguration({
1790
1827
  instructionMapping,
1791
1828
  responseFormat: coldSession.responseFormat,
1792
1829
  outputSchemaMapping,
1830
+ model: undefined,
1831
+ modelMapping,
1793
1832
  });
1794
1833
  if (
1795
1834
  current.configurationFingerprint !== coldSession.configurationFingerprint ||
1796
- coldSession.permissionMode !== permissionMode ||
1797
- coldSession.modelId !== modelId
1835
+ coldSession.permissionMode !== permissionMode
1798
1836
  ) {
1799
1837
  throw new Error(
1800
1838
  'ACP cold-session state is incompatible with the current non-secret session configuration.',
@@ -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
  }: {
@@ -75,6 +75,16 @@ export type ACPProviderAuthentication = {
75
75
  };
76
76
  };
77
77
 
78
+ export type ACPModelMapping =
79
+ | {
80
+ readonly type: 'session-config-option';
81
+ readonly path: string;
82
+ }
83
+ | {
84
+ readonly type: 'session-model';
85
+ readonly path: string;
86
+ };
87
+
78
88
  export type ACPCredentialBrokering = ({
79
89
  env,
80
90
  sandboxEnv,
@@ -143,7 +153,15 @@ export type ACPV1Settings = {
143
153
  */
144
154
  readonly env?: Readonly<Record<string, string>>;
145
155
  readonly authentication?: ACPAuthentication;
156
+ readonly clientCapabilities?: Readonly<Record<string, ACPSerializableValue>>;
146
157
  readonly providerAuthentication?: ACPProviderAuthentication;
158
+ /**
159
+ * Maps the HarnessAgent model identifier to an ACP session operation.
160
+ */
161
+ readonly modelMapping: ACPModelMapping;
162
+ /**
163
+ * @deprecated Use `model` on `HarnessAgent` instead.
164
+ */
147
165
  readonly modelId?: string;
148
166
  /**
149
167
  * Native skills directory relative to the ACP implementation's home
@@ -152,7 +170,8 @@ export type ACPV1Settings = {
152
170
  readonly skillsDirectory?: string;
153
171
  /**
154
172
  * Routes HarnessAgent instructions to a runtime-native system or developer
155
- * prompt. When omitted, instructions are prepended to the first user prompt.
173
+ * prompt. Changed instructions are prepended to the next user prompt when
174
+ * ACP does not expose a native per-turn instruction update.
156
175
  */
157
176
  readonly instructionMapping?: ACPInstructionMapping;
158
177
  /**