@ai-sdk/harness-acp 1.0.30 → 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.30",
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.92",
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",
@@ -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
@@ -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,
@@ -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,13 +71,12 @@ 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,
@@ -88,7 +88,6 @@ import type {
88
88
  ACPV1Settings,
89
89
  } from './acp-v1-settings';
90
90
  import {
91
- createACPSkillsFingerprint,
92
91
  materializeACPSkills,
93
92
  resolveACPPrivateSessionDirectory,
94
93
  resolveACPSkillsDirectory,
@@ -159,11 +158,11 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
159
158
  `ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`,
160
159
  );
161
160
  }
162
- const implementation = createACPV1Implementation({ settings });
163
- validateACPV1Implementation(implementation);
161
+ const baseImplementation = createACPV1Implementation({ settings });
162
+ validateACPV1Implementation(baseImplementation);
164
163
  const bootstrap = createACPBootstrap({
165
164
  harnessId: settings.harnessId,
166
- implementation,
165
+ implementation: baseImplementation,
167
166
  });
168
167
  const permissionModeMapping = isCompletePermissionModeMapping({
169
168
  value: settings.permissionModeMapping,
@@ -187,6 +186,24 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
187
186
  'ACP built-in tool filtering is not available in this initial ACP v1 implementation.',
188
187
  });
189
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);
190
207
  const permissionMode = startOptions.permissionMode ?? 'allow-all';
191
208
  const env = { ...process.env };
192
209
  const authenticationEnvironment = resolveACPAuthenticationEnvironment({
@@ -381,24 +398,6 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
381
398
  sessionWorkDir: workDir,
382
399
  });
383
400
  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
401
  const report = startOptions.observability?.report;
403
402
  const onDiagnostic = report
404
403
  ? (frame: Parameters<typeof harnessV1DiagnosticFromBridgeFrame>[0]) =>
@@ -453,7 +452,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
453
452
  harnessId: settings.harnessId,
454
453
  channel: attachChannel,
455
454
  proc: undefined,
456
- modelId: settings.modelId,
455
+ modelId,
457
456
  sessionMeta: settings.session?.meta,
458
457
  instructionMapping: settings.instructionMapping,
459
458
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -469,7 +468,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
469
468
  isResume: true,
470
469
  lifecycleState: lifecycleData,
471
470
  }),
472
- skillsFingerprint,
471
+ instructionsFingerprint: lifecycleData.instructionsFingerprint,
472
+ sandbox: toolSafeSandboxSession,
473
+ sessionWorkDir: workDir,
473
474
  skillsDirectory,
474
475
  acpSessionId: lifecycleData.acpSessionId,
475
476
  bridgePort: coords.port,
@@ -543,7 +544,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
543
544
  }
544
545
  const turnStartConfig = validateACPColdSessionConfiguration({
545
546
  coldSession,
546
- modelId: settings.modelId,
547
+ modelId,
547
548
  permissionMode,
548
549
  authenticationProfile,
549
550
  sessionMeta: settings.session?.meta,
@@ -607,6 +608,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
607
608
  providerEnvironment:
608
609
  sandboxProviderEnvironment == null ? undefined : {},
609
610
  sessionMeta: settings.session?.meta,
611
+ implementationArgs: modelConfiguration?.args,
612
+ implementationEnv: modelConfiguration?.env,
610
613
  }),
611
614
  ...sandboxProviderAuthenticationEnvironment,
612
615
  BRIDGE_CHANNEL_TOKEN: token,
@@ -719,7 +722,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
719
722
  harnessId: settings.harnessId,
720
723
  channel,
721
724
  proc,
722
- modelId: settings.modelId,
725
+ modelId,
723
726
  sessionMeta: settings.session?.meta,
724
727
  instructionMapping: settings.instructionMapping,
725
728
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -735,7 +738,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
735
738
  isResume,
736
739
  lifecycleState: lifecycleData,
737
740
  }),
738
- skillsFingerprint,
741
+ instructionsFingerprint: lifecycleData?.instructionsFingerprint,
742
+ sandbox: toolSafeSandboxSession,
743
+ sessionWorkDir: workDir,
739
744
  skillsDirectory,
740
745
  acpSessionId: lifecycleData?.acpSessionId,
741
746
  bridgePort: boundPort,
@@ -1054,7 +1059,9 @@ function createSession({
1054
1059
  mcpServers,
1055
1060
  isMcpToolCall,
1056
1061
  initialGuidanceApplied: initialGuidanceAppliedAtStart,
1057
- skillsFingerprint,
1062
+ instructionsFingerprint: instructionsFingerprintAtStart,
1063
+ sandbox,
1064
+ sessionWorkDir,
1058
1065
  skillsDirectory,
1059
1066
  acpSessionId: acpSessionIdAtStart,
1060
1067
  bridgePort,
@@ -1087,7 +1094,9 @@ function createSession({
1087
1094
  mcpServers: Record<string, unknown> | undefined;
1088
1095
  isMcpToolCall: ((toolCall: ACPToolCall) => boolean) | undefined;
1089
1096
  initialGuidanceApplied: boolean;
1090
- skillsFingerprint: string;
1097
+ instructionsFingerprint: string | undefined;
1098
+ sandbox: SandboxSession;
1099
+ sessionWorkDir: string;
1091
1100
  skillsDirectory: string;
1092
1101
  acpSessionId: string | undefined;
1093
1102
  bridgePort: number;
@@ -1106,6 +1115,7 @@ function createSession({
1106
1115
  let stopped = false;
1107
1116
  let turnInFlight = turnInFlightAtStart;
1108
1117
  let initialGuidanceApplied = initialGuidanceAppliedAtStart;
1118
+ let instructionsFingerprint = instructionsFingerprintAtStart;
1109
1119
  let latestACPSessionId = acpSessionIdAtStart;
1110
1120
  let latestTurnStartConfig = turnStartConfigAtStart;
1111
1121
 
@@ -1374,16 +1384,35 @@ function createSession({
1374
1384
  ...(recoveryStatus == null ? {} : { recovery: recoveryStatus }),
1375
1385
  ...(restoration == null ? {} : { restoration }),
1376
1386
  initialGuidanceApplied,
1377
- skillsMaterialized: true,
1378
- skillsFingerprint,
1387
+ ...(instructionsFingerprint == null ? {} : { instructionsFingerprint }),
1379
1388
  skillsDirectory,
1380
1389
  });
1381
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
+
1382
1407
  return {
1383
1408
  sessionId,
1384
1409
  isResume,
1385
1410
  ...(modelId == null ? {} : { modelId }),
1386
1411
  doPromptTurn: async options => {
1412
+ await synchronizeSkills({
1413
+ skills: options.skills,
1414
+ abortSignal: options.abortSignal,
1415
+ });
1387
1416
  if (options.responseFormat?.type === 'json') {
1388
1417
  if (options.responseFormat.schema == null) {
1389
1418
  throw unsupported({
@@ -1427,6 +1456,9 @@ function createSession({
1427
1456
  responseFormat: options.responseFormat,
1428
1457
  outputSchemaMapping,
1429
1458
  });
1459
+ const nextInstructionsFingerprint = fingerprintValue({
1460
+ value: options.instructions ?? null,
1461
+ });
1430
1462
  const control = wireTurn({
1431
1463
  emit: options.emit,
1432
1464
  abortSignal: options.abortSignal,
@@ -1439,15 +1471,14 @@ function createSession({
1439
1471
  turnInFlight = true;
1440
1472
  channel.send({
1441
1473
  type: 'start',
1442
- prompt: initialGuidanceApplied
1443
- ? prompt
1444
- : prependACPInitialGuidance({
1445
- prompt,
1446
- instructions:
1447
- instructionMapping == null
1448
- ? options.instructions
1449
- : undefined,
1450
- }),
1474
+ prompt:
1475
+ instructionsFingerprint !== nextInstructionsFingerprint &&
1476
+ (instructionMapping == null || initialGuidanceApplied)
1477
+ ? prependACPInstructionGuidance({
1478
+ prompt,
1479
+ instructions: options.instructions,
1480
+ })
1481
+ : prompt,
1451
1482
  ...(instructionMapping == null
1452
1483
  ? {}
1453
1484
  : {
@@ -1472,11 +1503,16 @@ function createSession({
1472
1503
  });
1473
1504
  latestTurnStartConfig = turnStartConfig;
1474
1505
  initialGuidanceApplied = true;
1506
+ instructionsFingerprint = nextInstructionsFingerprint;
1475
1507
  },
1476
1508
  });
1477
1509
  return control;
1478
1510
  },
1479
1511
  doContinueTurn: async options => {
1512
+ await synchronizeSkills({
1513
+ skills: options.skills,
1514
+ abortSignal: options.abortSignal,
1515
+ });
1480
1516
  if (options.responseFormat?.type === 'json') {
1481
1517
  if (options.responseFormat.schema == null) {
1482
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
  }: {
@@ -75,6 +75,21 @@ export type ACPProviderAuthentication = {
75
75
  };
76
76
  };
77
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
+
78
93
  export type ACPCredentialBrokering = ({
79
94
  env,
80
95
  sandboxEnv,
@@ -144,6 +159,13 @@ export type ACPV1Settings = {
144
159
  readonly env?: Readonly<Record<string, string>>;
145
160
  readonly authentication?: ACPAuthentication;
146
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
+ */
147
169
  readonly modelId?: string;
148
170
  /**
149
171
  * Native skills directory relative to the ACP implementation's home
@@ -152,7 +174,8 @@ export type ACPV1Settings = {
152
174
  readonly skillsDirectory?: string;
153
175
  /**
154
176
  * Routes HarnessAgent instructions to a runtime-native system or developer
155
- * 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.
156
179
  */
157
180
  readonly instructionMapping?: ACPInstructionMapping;
158
181
  /**
@@ -1,39 +1,12 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import path from 'node:path';
3
3
  import type { HarnessV1Skill } from '@ai-sdk/harness';
4
- import { writeSkills } from '@ai-sdk/harness/utils';
4
+ import { writeSkills, type WriteSkillsResult } from '@ai-sdk/harness/utils';
5
5
  import type { Experimental_SandboxSession } from '@ai-sdk/provider-utils';
6
6
 
7
7
  const ACP_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
8
8
  export const DEFAULT_ACP_SKILLS_DIRECTORY = '.agents/skills';
9
9
 
10
- export function createACPSkillsFingerprint({
11
- skills,
12
- }: {
13
- skills: ReadonlyArray<HarnessV1Skill>;
14
- }): string {
15
- const canonicalSkills = skills
16
- .map(skill => ({
17
- name: skill.name,
18
- description: skill.description,
19
- content: skill.content,
20
- files: [...(skill.files ?? [])]
21
- .map(file => ({
22
- path: path.posix.normalize(file.path),
23
- content: file.content,
24
- }))
25
- .sort((left, right) =>
26
- compareCanonicalStrings({ left: left.path, right: right.path }),
27
- ),
28
- }))
29
- .sort((left, right) =>
30
- compareCanonicalStrings({ left: left.name, right: right.name }),
31
- );
32
- return createHash('sha256')
33
- .update(JSON.stringify(canonicalSkills))
34
- .digest('hex');
35
- }
36
-
37
10
  export function resolveACPPrivateSessionDirectory({
38
11
  sandboxHomeDir,
39
12
  sessionWorkDir,
@@ -62,34 +35,30 @@ export async function materializeACPSkills({
62
35
  rootDir,
63
36
  sessionWorkDir,
64
37
  skills,
65
- shouldMaterialize,
66
38
  abortSignal,
67
39
  }: {
68
40
  sandbox: Experimental_SandboxSession;
69
41
  rootDir: string;
70
42
  sessionWorkDir: string;
71
43
  skills: ReadonlyArray<HarnessV1Skill>;
72
- shouldMaterialize: boolean;
73
44
  abortSignal?: AbortSignal;
74
- }): Promise<void> {
45
+ }): Promise<WriteSkillsResult> {
75
46
  validateACPSkills({ skills });
76
47
  assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
77
48
 
78
- if (shouldMaterialize) {
79
- await writeSkills({
80
- sandbox,
81
- rootDir,
82
- skills,
83
- abortSignal,
84
- skillNamePattern: ACP_SKILL_NAME_PATTERN,
85
- invalidSkillNameMessage: ({ name }) =>
86
- `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
87
- invalidSkillFilePathMessage: ({ skillName, filePath }) =>
88
- `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
89
- skillName,
90
- )}: expected a relative POSIX path without traversal.`,
91
- });
92
- }
49
+ return writeSkills({
50
+ sandbox,
51
+ rootDir,
52
+ skills,
53
+ abortSignal,
54
+ skillNamePattern: ACP_SKILL_NAME_PATTERN,
55
+ invalidSkillNameMessage: ({ name }) =>
56
+ `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
57
+ invalidSkillFilePathMessage: ({ skillName, filePath }) =>
58
+ `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
59
+ skillName,
60
+ )}: expected a relative POSIX path without traversal.`,
61
+ });
93
62
  }
94
63
 
95
64
  export function resolveACPSkillsDirectory({
@@ -225,13 +194,3 @@ function assertOutsideSessionWorkDir({
225
194
  );
226
195
  }
227
196
  }
228
-
229
- function compareCanonicalStrings({
230
- left,
231
- right,
232
- }: {
233
- left: string;
234
- right: string;
235
- }): number {
236
- return left < right ? -1 : left > right ? 1 : 0;
237
- }
@@ -59,6 +59,8 @@ export type ACPBridgeConfiguration = {
59
59
  readonly providerAuthentication?: ACPResolvedProviderAuthentication;
60
60
  readonly providerEnvironment?: Readonly<Record<string, string>>;
61
61
  readonly sessionMeta?: Readonly<Record<string, ACPSerializableValue>>;
62
+ readonly implementationArgs?: ReadonlyArray<string>;
63
+ readonly implementationEnv?: Readonly<Record<string, string>>;
62
64
  };
63
65
 
64
66
  const bridgeConfigurationSchema: z.ZodType<ACPBridgeConfiguration> = z.object({
@@ -66,6 +68,8 @@ const bridgeConfigurationSchema: z.ZodType<ACPBridgeConfiguration> = z.object({
66
68
  providerAuthentication: providerAuthenticationSchema.optional(),
67
69
  providerEnvironment: z.record(z.string(), z.string()).optional(),
68
70
  sessionMeta: serializableRecordSchema.optional(),
71
+ implementationArgs: z.array(z.string()).optional(),
72
+ implementationEnv: z.record(z.string(), z.string()).optional(),
69
73
  });
70
74
 
71
75
  export function createACPBridgeEnvironment({
@@ -73,6 +77,8 @@ export function createACPBridgeEnvironment({
73
77
  providerAuthentication,
74
78
  providerEnvironment,
75
79
  sessionMeta,
80
+ implementationArgs,
81
+ implementationEnv,
76
82
  }: ACPBridgeConfiguration): Record<string, string> {
77
83
  return {
78
84
  [ACP_BRIDGE_CONFIGURATION_ENV]: JSON.stringify({
@@ -80,6 +86,8 @@ export function createACPBridgeEnvironment({
80
86
  ...(providerAuthentication == null ? {} : { providerAuthentication }),
81
87
  ...(providerEnvironment == null ? {} : { providerEnvironment }),
82
88
  ...(sessionMeta == null ? {} : { sessionMeta }),
89
+ ...(implementationArgs == null ? {} : { implementationArgs }),
90
+ ...(implementationEnv == null ? {} : { implementationEnv }),
83
91
  }),
84
92
  };
85
93
  }
@@ -413,15 +413,18 @@ async function ensureSession({
413
413
  instructions: start.instructions,
414
414
  instructionMapping: start.instructionMapping,
415
415
  sessionMeta: bridgeConfiguration.sessionMeta,
416
- environment: createChildEnvironment({
417
- launchEnv,
418
- implementationDir,
419
- privateHome: implementation.privateHome,
420
- }),
416
+ environment: {
417
+ ...createChildEnvironment({
418
+ launchEnv,
419
+ implementationDir,
420
+ privateHome: implementation.privateHome,
421
+ }),
422
+ ...bridgeConfiguration.implementationEnv,
423
+ },
421
424
  });
422
425
  child = spawn(
423
426
  `${implementationDir}/${implementation.executablePath}`,
424
- [...implementation.args],
427
+ [...(bridgeConfiguration.implementationArgs ?? implementation.args)],
425
428
  {
426
429
  cwd: workDir,
427
430
  env: instructionConfiguration.environment,
@@ -4,8 +4,8 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@agentclientprotocol/sdk": "1.2.1",
8
- "@modelcontextprotocol/sdk": "1.29.0",
7
+ "@agentclientprotocol/sdk": "1.4.0",
8
+ "@modelcontextprotocol/sdk": "1.30.0",
9
9
  "ws": "8.21.0",
10
10
  "zod": "4.4.3"
11
11
  }