@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/dist/index.js CHANGED
@@ -33,7 +33,10 @@ import { WebSocket } from "ws";
33
33
 
34
34
  // src/acp-auth.ts
35
35
  import { createHash } from "crypto";
36
- import { getAiGatewayAuthFromEnv } from "@ai-sdk/harness/utils";
36
+ import {
37
+ getAiGatewayAuthFromEnv,
38
+ isHarnessAuthenticationEnvironment
39
+ } from "@ai-sdk/harness/utils";
37
40
  var DEFAULT_AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
38
41
  function createACPAuthenticationProfileIdentity({
39
42
  authentication,
@@ -67,6 +70,10 @@ function resolveACPProviderAuthentication({
67
70
  AI_SDK_ACP_CLIENT_APP_NAME: auth.clientApp.name,
68
71
  AI_SDK_ACP_CLIENT_APP_VERSION: auth.clientApp.version
69
72
  };
73
+ const resolvedEnv = resolveACPAuthenticationEnvironment({
74
+ auth: auth.mode,
75
+ env
76
+ });
70
77
  const providerAuthentication = auth.providerAuthentication;
71
78
  if (providerAuthentication == null) {
72
79
  return { providerAuthentication: void 0, env: clientAppEnv };
@@ -77,7 +84,7 @@ function resolveACPProviderAuthentication({
77
84
  env: clientAppEnv
78
85
  };
79
86
  }
80
- const mode = auth.mode ?? "auto";
87
+ const mode = resolveACPProviderAuthenticationMode(auth.mode);
81
88
  if (mode === "direct") {
82
89
  return {
83
90
  providerAuthentication: { type: "direct" },
@@ -86,11 +93,11 @@ function resolveACPProviderAuthentication({
86
93
  }
87
94
  const gateway = compatibility?.type === "ai-gateway" ? {
88
95
  apiKey: resolveGatewayCredential({
89
- env,
96
+ env: resolvedEnv,
90
97
  credentialSource: compatibility.credentialSource
91
98
  }),
92
99
  baseUrl: compatibility.baseUrl
93
- } : getAiGatewayAuthFromEnv({ env });
100
+ } : getAiGatewayAuthFromEnv({ env: resolvedEnv });
94
101
  const apiKey = gateway.apiKey;
95
102
  if (compatibility == null && mode === "auto" && apiKey == null) {
96
103
  return {
@@ -120,14 +127,16 @@ function resolveACPProviderAuthenticationCompatibility({
120
127
  providerAuthentication,
121
128
  env
122
129
  }) {
130
+ const resolvedEnv = resolveACPAuthenticationEnvironment({
131
+ auth,
132
+ env
133
+ });
123
134
  if (providerAuthentication == null) return void 0;
124
- const mode = auth;
135
+ const mode = resolveACPProviderAuthenticationMode(auth);
125
136
  if (mode === "direct") {
126
137
  return { type: "direct", mode };
127
138
  }
128
- const credentialSource = resolveGatewayCredentialSource({
129
- env
130
- });
139
+ const credentialSource = resolveGatewayCredentialSource({ env: resolvedEnv });
131
140
  if (mode === "auto" && credentialSource == null) {
132
141
  return { type: "direct", mode };
133
142
  }
@@ -136,9 +145,18 @@ function resolveACPProviderAuthenticationCompatibility({
136
145
  mode,
137
146
  env: providerAuthentication.gateway.env,
138
147
  credentialSource,
139
- baseUrl: env.AI_GATEWAY_BASE_URL ?? DEFAULT_AI_GATEWAY_BASE_URL
148
+ baseUrl: resolvedEnv.AI_GATEWAY_BASE_URL ?? DEFAULT_AI_GATEWAY_BASE_URL
140
149
  };
141
150
  }
151
+ function resolveACPProviderAuthenticationMode(auth) {
152
+ return typeof auth === "string" || auth == null ? auth ?? "auto" : "auto";
153
+ }
154
+ function resolveACPAuthenticationEnvironment({
155
+ auth,
156
+ env
157
+ }) {
158
+ return isHarnessAuthenticationEnvironment(auth) ? auth : env;
159
+ }
142
160
  function resolveGatewayCredentialSource({
143
161
  env
144
162
  }) {
@@ -366,18 +384,22 @@ ${implementation.source.command}
366
384
  }
367
385
  function resolveImplementationEnvironment({
368
386
  implementation,
369
- env
387
+ env,
388
+ credentialEnv = env
370
389
  }) {
371
390
  const forwardedEnvironment = {};
372
- for (const name of [
373
- ...implementation.forwardEnv ?? [],
374
- ...implementation.credentialEnv ?? []
375
- ]) {
391
+ for (const name of implementation.forwardEnv ?? []) {
376
392
  const value = env[name];
377
393
  if (value != null && value.length > 0) {
378
394
  forwardedEnvironment[name] = value;
379
395
  }
380
396
  }
397
+ for (const name of implementation.credentialEnv ?? []) {
398
+ const value = credentialEnv[name];
399
+ if (value != null && value.length > 0) {
400
+ forwardedEnvironment[name] = value;
401
+ }
402
+ }
381
403
  return {
382
404
  ...forwardedEnvironment,
383
405
  ...implementation.env
@@ -637,7 +659,7 @@ function convertHarnessPromptToACPTextBlocks({
637
659
  }
638
660
  return content;
639
661
  }
640
- function prependACPInitialGuidance({
662
+ function prependACPInstructionGuidance({
641
663
  prompt,
642
664
  instructions
643
665
  }) {
@@ -803,20 +825,26 @@ var bridgeConfigurationSchema = z3.object({
803
825
  authentication: authenticationSchema.optional(),
804
826
  providerAuthentication: providerAuthenticationSchema.optional(),
805
827
  providerEnvironment: z3.record(z3.string(), z3.string()).optional(),
806
- sessionMeta: serializableRecordSchema.optional()
828
+ sessionMeta: serializableRecordSchema.optional(),
829
+ implementationArgs: z3.array(z3.string()).optional(),
830
+ implementationEnv: z3.record(z3.string(), z3.string()).optional()
807
831
  });
808
832
  function createACPBridgeEnvironment({
809
833
  authentication,
810
834
  providerAuthentication,
811
835
  providerEnvironment,
812
- sessionMeta
836
+ sessionMeta,
837
+ implementationArgs,
838
+ implementationEnv
813
839
  }) {
814
840
  return {
815
841
  [ACP_BRIDGE_CONFIGURATION_ENV]: JSON.stringify({
816
842
  ...authentication == null ? {} : { authentication },
817
843
  ...providerAuthentication == null ? {} : { providerAuthentication },
818
844
  ...providerEnvironment == null ? {} : { providerEnvironment },
819
- ...sessionMeta == null ? {} : { sessionMeta }
845
+ ...sessionMeta == null ? {} : { sessionMeta },
846
+ ...implementationArgs == null ? {} : { implementationArgs },
847
+ ...implementationEnv == null ? {} : { implementationEnv }
820
848
  })
821
849
  };
822
850
  }
@@ -999,19 +1027,6 @@ function resolveACPInitialGuidanceApplied({
999
1027
  if (!isResume) return false;
1000
1028
  return lifecycleState?.initialGuidanceApplied ?? true;
1001
1029
  }
1002
- function shouldMaterializeACPSkills({
1003
- isResume,
1004
- lifecycleState,
1005
- skillsFingerprint,
1006
- skillsDirectory
1007
- }) {
1008
- if (isResume && lifecycleState?.skillsFingerprint != null && lifecycleState.skillsFingerprint !== skillsFingerprint) {
1009
- throw new Error(
1010
- "ACP lifecycle state was created with a different set of skills."
1011
- );
1012
- }
1013
- return !isResume || lifecycleState?.skillsMaterialized !== true || lifecycleState.skillsDirectory !== skillsDirectory;
1014
- }
1015
1030
  function validateACPLifecycleCompatibility({
1016
1031
  harnessId,
1017
1032
  lifecycleHarnessId,
@@ -1053,24 +1068,6 @@ import path from "path";
1053
1068
  import { writeSkills } from "@ai-sdk/harness/utils";
1054
1069
  var ACP_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1055
1070
  var DEFAULT_ACP_SKILLS_DIRECTORY = ".agents/skills";
1056
- function createACPSkillsFingerprint({
1057
- skills
1058
- }) {
1059
- const canonicalSkills = skills.map((skill) => ({
1060
- name: skill.name,
1061
- description: skill.description,
1062
- content: skill.content,
1063
- files: [...skill.files ?? []].map((file) => ({
1064
- path: path.posix.normalize(file.path),
1065
- content: file.content
1066
- })).sort(
1067
- (left, right) => compareCanonicalStrings({ left: left.path, right: right.path })
1068
- )
1069
- })).sort(
1070
- (left, right) => compareCanonicalStrings({ left: left.name, right: right.name })
1071
- );
1072
- return createHash4("sha256").update(JSON.stringify(canonicalSkills)).digest("hex");
1073
- }
1074
1071
  function resolveACPPrivateSessionDirectory({
1075
1072
  sandboxHomeDir,
1076
1073
  sessionWorkDir,
@@ -1093,24 +1090,21 @@ async function materializeACPSkills({
1093
1090
  rootDir,
1094
1091
  sessionWorkDir,
1095
1092
  skills,
1096
- shouldMaterialize,
1097
1093
  abortSignal
1098
1094
  }) {
1099
1095
  validateACPSkills({ skills });
1100
1096
  assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
1101
- if (shouldMaterialize) {
1102
- await writeSkills({
1103
- sandbox,
1104
- rootDir,
1105
- skills,
1106
- abortSignal,
1107
- skillNamePattern: ACP_SKILL_NAME_PATTERN,
1108
- invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
1109
- invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
1110
- skillName
1111
- )}: expected a relative POSIX path without traversal.`
1112
- });
1113
- }
1097
+ return writeSkills({
1098
+ sandbox,
1099
+ rootDir,
1100
+ skills,
1101
+ abortSignal,
1102
+ skillNamePattern: ACP_SKILL_NAME_PATTERN,
1103
+ invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
1104
+ invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
1105
+ skillName
1106
+ )}: expected a relative POSIX path without traversal.`
1107
+ });
1114
1108
  }
1115
1109
  function resolveACPSkillsDirectory({
1116
1110
  implementationHomeDir,
@@ -1198,12 +1192,6 @@ function assertOutsideSessionWorkDir({
1198
1192
  );
1199
1193
  }
1200
1194
  }
1201
- function compareCanonicalStrings({
1202
- left,
1203
- right
1204
- }) {
1205
- return left < right ? -1 : left > right ? 1 : 0;
1206
- }
1207
1195
 
1208
1196
  // src/v1/acp-v1-harness.ts
1209
1197
  var HARNESS_ID_REGEXP = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -1234,11 +1222,11 @@ function createACPV1({
1234
1222
  `ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`
1235
1223
  );
1236
1224
  }
1237
- const implementation = createACPV1Implementation({ settings });
1238
- validateACPV1Implementation(implementation);
1225
+ const baseImplementation = createACPV1Implementation({ settings });
1226
+ validateACPV1Implementation(baseImplementation);
1239
1227
  const bootstrap = createACPBootstrap({
1240
1228
  harnessId: settings.harnessId,
1241
- implementation
1229
+ implementation: baseImplementation
1242
1230
  });
1243
1231
  const permissionModeMapping = isCompletePermissionModeMapping({
1244
1232
  value: settings.permissionModeMapping
@@ -1258,8 +1246,25 @@ function createACPV1({
1258
1246
  message: "ACP built-in tool filtering is not available in this initial ACP v1 implementation."
1259
1247
  });
1260
1248
  }
1249
+ const modelId = startOptions.model ?? settings.modelId;
1250
+ const modelConfiguration = modelId == null ? void 0 : settings.resolveModel({ model: modelId });
1251
+ const implementation = {
1252
+ ...baseImplementation,
1253
+ ...modelConfiguration?.args == null ? {} : { args: modelConfiguration.args },
1254
+ ...modelConfiguration?.env == null ? {} : {
1255
+ env: {
1256
+ ...baseImplementation.env,
1257
+ ...modelConfiguration.env
1258
+ }
1259
+ }
1260
+ };
1261
+ validateACPV1Implementation(implementation);
1261
1262
  const permissionMode = startOptions.permissionMode ?? "allow-all";
1262
1263
  const env = { ...process.env };
1264
+ const authenticationEnvironment = resolveACPAuthenticationEnvironment({
1265
+ auth: settings.auth,
1266
+ env
1267
+ });
1263
1268
  const providerAuthenticationCompatibility = resolveACPProviderAuthenticationCompatibility({
1264
1269
  auth: settings.auth,
1265
1270
  providerAuthentication: settings.providerAuthentication,
@@ -1322,7 +1327,8 @@ function createACPV1({
1322
1327
  }
1323
1328
  const implementationEnvironment = resolveImplementationEnvironment({
1324
1329
  implementation,
1325
- env
1330
+ env,
1331
+ credentialEnv: authenticationEnvironment
1326
1332
  });
1327
1333
  let sandboxImplementationEnvironment = implementationEnvironment;
1328
1334
  let sandboxProviderAuthenticationEnvironment = resolvedProviderAuthentication.env;
@@ -1413,24 +1419,6 @@ function createACPV1({
1413
1419
  sessionWorkDir: workDir
1414
1420
  });
1415
1421
  const bridgeStateDir = `${privateSessionDir}/bridge`;
1416
- const skills = startOptions.skills ?? [];
1417
- const skillsFingerprint = createACPSkillsFingerprint({ skills });
1418
- const shouldMaterializeSkills = shouldMaterializeACPSkills({
1419
- isResume,
1420
- lifecycleState: lifecycleData,
1421
- skillsFingerprint,
1422
- skillsDirectory
1423
- });
1424
- if (skills.length > 0) {
1425
- await materializeACPSkills({
1426
- sandbox: toolSafeSandboxSession,
1427
- rootDir: skillsDirectory,
1428
- sessionWorkDir: workDir,
1429
- skills,
1430
- shouldMaterialize: shouldMaterializeSkills,
1431
- abortSignal: startOptions.abortSignal
1432
- });
1433
- }
1434
1422
  const report = startOptions.observability?.report;
1435
1423
  const onDiagnostic = report ? (frame) => report(
1436
1424
  harnessV1DiagnosticFromBridgeFrame(frame, {
@@ -1480,7 +1468,7 @@ function createACPV1({
1480
1468
  harnessId: settings.harnessId,
1481
1469
  channel: attachChannel,
1482
1470
  proc: void 0,
1483
- modelId: settings.modelId,
1471
+ modelId,
1484
1472
  sessionMeta: settings.session?.meta,
1485
1473
  instructionMapping: settings.instructionMapping,
1486
1474
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -1496,7 +1484,9 @@ function createACPV1({
1496
1484
  isResume: true,
1497
1485
  lifecycleState: lifecycleData
1498
1486
  }),
1499
- skillsFingerprint,
1487
+ instructionsFingerprint: lifecycleData.instructionsFingerprint,
1488
+ sandbox: toolSafeSandboxSession,
1489
+ sessionWorkDir: workDir,
1500
1490
  skillsDirectory,
1501
1491
  acpSessionId: lifecycleData.acpSessionId,
1502
1492
  bridgePort: coords.port,
@@ -1568,7 +1558,7 @@ function createACPV1({
1568
1558
  }
1569
1559
  const turnStartConfig = validateACPColdSessionConfiguration({
1570
1560
  coldSession,
1571
- modelId: settings.modelId,
1561
+ modelId,
1572
1562
  permissionMode,
1573
1563
  authenticationProfile,
1574
1564
  sessionMeta: settings.session?.meta,
@@ -1615,7 +1605,9 @@ function createACPV1({
1615
1605
  authentication: settings.authentication,
1616
1606
  providerAuthentication: resolvedProviderAuthentication.providerAuthentication,
1617
1607
  providerEnvironment: sandboxProviderEnvironment == null ? void 0 : {},
1618
- sessionMeta: settings.session?.meta
1608
+ sessionMeta: settings.session?.meta,
1609
+ implementationArgs: modelConfiguration?.args,
1610
+ implementationEnv: modelConfiguration?.env
1619
1611
  }),
1620
1612
  ...sandboxProviderAuthenticationEnvironment,
1621
1613
  BRIDGE_CHANNEL_TOKEN: token,
@@ -1718,7 +1710,7 @@ function createACPV1({
1718
1710
  harnessId: settings.harnessId,
1719
1711
  channel,
1720
1712
  proc,
1721
- modelId: settings.modelId,
1713
+ modelId,
1722
1714
  sessionMeta: settings.session?.meta,
1723
1715
  instructionMapping: settings.instructionMapping,
1724
1716
  outputSchemaMapping: settings.outputSchemaMapping,
@@ -1734,7 +1726,9 @@ function createACPV1({
1734
1726
  isResume,
1735
1727
  lifecycleState: lifecycleData
1736
1728
  }),
1737
- skillsFingerprint,
1729
+ instructionsFingerprint: lifecycleData?.instructionsFingerprint,
1730
+ sandbox: toolSafeSandboxSession,
1731
+ sessionWorkDir: workDir,
1738
1732
  skillsDirectory,
1739
1733
  acpSessionId: lifecycleData?.acpSessionId,
1740
1734
  bridgePort: boundPort,
@@ -1973,7 +1967,9 @@ function createSession({
1973
1967
  mcpServers,
1974
1968
  isMcpToolCall,
1975
1969
  initialGuidanceApplied: initialGuidanceAppliedAtStart,
1976
- skillsFingerprint,
1970
+ instructionsFingerprint: instructionsFingerprintAtStart,
1971
+ sandbox,
1972
+ sessionWorkDir,
1977
1973
  skillsDirectory,
1978
1974
  acpSessionId: acpSessionIdAtStart,
1979
1975
  bridgePort,
@@ -1992,6 +1988,7 @@ function createSession({
1992
1988
  let stopped = false;
1993
1989
  let turnInFlight = turnInFlightAtStart;
1994
1990
  let initialGuidanceApplied = initialGuidanceAppliedAtStart;
1991
+ let instructionsFingerprint = instructionsFingerprintAtStart;
1995
1992
  let latestACPSessionId = acpSessionIdAtStart;
1996
1993
  let latestTurnStartConfig = turnStartConfigAtStart;
1997
1994
  const markTurnFinished = () => {
@@ -2234,15 +2231,30 @@ function createSession({
2234
2231
  ...recoveryStatus == null ? {} : { recovery: recoveryStatus },
2235
2232
  ...restoration == null ? {} : { restoration },
2236
2233
  initialGuidanceApplied,
2237
- skillsMaterialized: true,
2238
- skillsFingerprint,
2234
+ ...instructionsFingerprint == null ? {} : { instructionsFingerprint },
2239
2235
  skillsDirectory
2240
2236
  });
2237
+ const synchronizeSkills = async ({
2238
+ skills,
2239
+ abortSignal
2240
+ }) => {
2241
+ await materializeACPSkills({
2242
+ sandbox,
2243
+ rootDir: skillsDirectory,
2244
+ sessionWorkDir,
2245
+ skills,
2246
+ abortSignal
2247
+ });
2248
+ };
2241
2249
  return {
2242
2250
  sessionId,
2243
2251
  isResume,
2244
2252
  ...modelId == null ? {} : { modelId },
2245
2253
  doPromptTurn: async (options) => {
2254
+ await synchronizeSkills({
2255
+ skills: options.skills,
2256
+ abortSignal: options.abortSignal
2257
+ });
2246
2258
  if (options.responseFormat?.type === "json") {
2247
2259
  if (options.responseFormat.schema == null) {
2248
2260
  throw unsupported({
@@ -2283,6 +2295,9 @@ function createSession({
2283
2295
  responseFormat: options.responseFormat,
2284
2296
  outputSchemaMapping
2285
2297
  });
2298
+ const nextInstructionsFingerprint = fingerprintValue({
2299
+ value: options.instructions ?? null
2300
+ });
2286
2301
  const control = wireTurn({
2287
2302
  emit: options.emit,
2288
2303
  abortSignal: options.abortSignal,
@@ -2295,10 +2310,10 @@ function createSession({
2295
2310
  turnInFlight = true;
2296
2311
  channel.send({
2297
2312
  type: "start",
2298
- prompt: initialGuidanceApplied ? prompt : prependACPInitialGuidance({
2313
+ prompt: instructionsFingerprint !== nextInstructionsFingerprint && (instructionMapping == null || initialGuidanceApplied) ? prependACPInstructionGuidance({
2299
2314
  prompt,
2300
- instructions: instructionMapping == null ? options.instructions : void 0
2301
- }),
2315
+ instructions: options.instructions
2316
+ }) : prompt,
2302
2317
  ...instructionMapping == null ? {} : {
2303
2318
  instructionMapping,
2304
2319
  ...options.instructions == null ? {} : { instructions: options.instructions }
@@ -2315,11 +2330,16 @@ function createSession({
2315
2330
  });
2316
2331
  latestTurnStartConfig = turnStartConfig;
2317
2332
  initialGuidanceApplied = true;
2333
+ instructionsFingerprint = nextInstructionsFingerprint;
2318
2334
  }
2319
2335
  });
2320
2336
  return control;
2321
2337
  },
2322
2338
  doContinueTurn: async (options) => {
2339
+ await synchronizeSkills({
2340
+ skills: options.skills,
2341
+ abortSignal: options.abortSignal
2342
+ });
2323
2343
  if (options.responseFormat?.type === "json") {
2324
2344
  if (options.responseFormat.schema == null) {
2325
2345
  throw unsupported({
@@ -2601,7 +2621,7 @@ function deserializeBridgeError({
2601
2621
  }
2602
2622
 
2603
2623
  // src/version.ts
2604
- var VERSION = true ? "1.0.29" : "0.0.0-test";
2624
+ var VERSION = true ? "1.0.31" : "0.0.0-test";
2605
2625
 
2606
2626
  // src/acp-harness.ts
2607
2627
  var ACP_CLIENT_APP = {
@@ -2640,8 +2660,7 @@ var acpResumeStateSchema = z4.object({
2640
2660
  method: z4.enum(["resume", "load"])
2641
2661
  }).optional(),
2642
2662
  initialGuidanceApplied: z4.boolean().optional(),
2643
- skillsMaterialized: z4.boolean().optional(),
2644
- skillsFingerprint: z4.string().optional(),
2663
+ instructionsFingerprint: z4.string().optional(),
2645
2664
  skillsDirectory: z4.string().optional()
2646
2665
  });
2647
2666
  function createACP(settings) {