@ai-sdk/harness-acp 1.0.38 → 1.0.40

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
@@ -1,4 +1,7 @@
1
1
  // src/acp-harness.ts
2
+ import {
3
+ HARNESS_V1_BUILTIN_TOOLS
4
+ } from "@ai-sdk/harness";
2
5
  import { z as z4 } from "zod/v4";
3
6
 
4
7
  // src/v1/acp-v1-harness.ts
@@ -26,7 +29,9 @@ import {
26
29
  shellQuote,
27
30
  warnCredentialBrokeringUnavailable,
28
31
  waitForBridgeReady,
29
- withBridgeToken
32
+ withBridgeToken,
33
+ writeInstructions,
34
+ writeSkills
30
35
  } from "@ai-sdk/harness/utils";
31
36
  import {
32
37
  asSchema
@@ -706,6 +711,10 @@ var instructionMappingSchema = z2.discriminatedUnion("type", [
706
711
  type: z2.literal("launch-env-json"),
707
712
  variable: z2.string().min(1),
708
713
  path: instructionMappingPathSchema
714
+ }),
715
+ z2.object({
716
+ type: z2.literal("filesystem"),
717
+ path: z2.string().min(1)
709
718
  })
710
719
  ]);
711
720
  var outputSchemaMappingSchema = z2.object({
@@ -756,13 +765,26 @@ var coldRestoreSchema = z2.object({
756
765
  });
757
766
  var acpToolCallCandidateSchema = z2.object({
758
767
  type: z2.literal("acp-tool-call-candidate"),
768
+ requestId: z2.string(),
759
769
  toolCall: z2.custom(
760
770
  (value) => value != null && typeof value === "object" && typeof value.toolCallId === "string" && typeof value.title === "string"
761
771
  )
762
772
  });
773
+ var acpQuestionRequestSchema = z2.object({
774
+ type: z2.literal("acp-question-request"),
775
+ requestId: z2.string(),
776
+ nativeRequest: z2.unknown(),
777
+ nativeToolCall: acpToolCallCandidateSchema.shape.toolCall.optional()
778
+ });
779
+ var acpQuestionResolvedSchema = z2.object({
780
+ type: z2.literal("acp-question-resolved"),
781
+ requestId: z2.string()
782
+ });
763
783
  var outboundMessageSchema = z2.union([
764
784
  harnessV1BridgeOutboundMessageSchema,
765
- acpToolCallCandidateSchema
785
+ acpToolCallCandidateSchema,
786
+ acpQuestionRequestSchema,
787
+ acpQuestionResolvedSchema
766
788
  ]);
767
789
  var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
768
790
  prompt: z2.array(acpTextContentBlockSchema),
@@ -809,6 +831,10 @@ var profileValueSchema = z3.lazy(
809
831
  z3.record(z3.string(), profileValueSchema)
810
832
  ])
811
833
  );
834
+ var hostToolMcpTransportSchema = z3.enum([
835
+ "stdio",
836
+ "http"
837
+ ]);
812
838
  var serializableRecordSchema = z3.record(z3.string(), serializableValueSchema);
813
839
  var profileRecordSchema = z3.record(z3.string(), profileValueSchema);
814
840
  var authenticationSchema = z3.object({
@@ -828,14 +854,18 @@ var bridgeConfigurationSchema = z3.object({
828
854
  providerAuthentication: providerAuthenticationSchema.optional(),
829
855
  providerEnvironment: z3.record(z3.string(), z3.string()).optional(),
830
856
  sessionMeta: serializableRecordSchema.optional(),
831
- clientCapabilities: serializableRecordSchema.optional()
857
+ clientCapabilities: serializableRecordSchema.optional(),
858
+ askUserQuestionsRequestMethod: z3.string().optional(),
859
+ hostToolMcpTransport: hostToolMcpTransportSchema.optional()
832
860
  });
833
861
  function createACPBridgeEnvironment({
834
862
  authentication,
835
863
  providerAuthentication,
836
864
  providerEnvironment,
837
865
  sessionMeta,
838
- clientCapabilities
866
+ clientCapabilities,
867
+ askUserQuestionsRequestMethod,
868
+ hostToolMcpTransport
839
869
  }) {
840
870
  return {
841
871
  [ACP_BRIDGE_CONFIGURATION_ENV]: JSON.stringify({
@@ -843,7 +873,9 @@ function createACPBridgeEnvironment({
843
873
  ...providerAuthentication == null ? {} : { providerAuthentication },
844
874
  ...providerEnvironment == null ? {} : { providerEnvironment },
845
875
  ...sessionMeta == null ? {} : { sessionMeta },
846
- ...clientCapabilities == null ? {} : { clientCapabilities }
876
+ ...clientCapabilities == null ? {} : { clientCapabilities },
877
+ ...askUserQuestionsRequestMethod == null ? {} : { askUserQuestionsRequestMethod },
878
+ ...hostToolMcpTransport == null ? {} : { hostToolMcpTransport }
847
879
  })
848
880
  };
849
881
  }
@@ -1066,51 +1098,25 @@ function validateACPLifecycleCompatibility({
1066
1098
  // src/v1/acp-v1-skills.ts
1067
1099
  import { createHash as createHash4 } from "crypto";
1068
1100
  import path from "path";
1069
- import { writeSkills } from "@ai-sdk/harness/utils";
1070
1101
  var ACP_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1071
1102
  var DEFAULT_ACP_SKILLS_DIRECTORY = ".agents/skills";
1072
1103
  function resolveACPPrivateSessionDirectory({
1073
1104
  sandboxHomeDir,
1074
- sessionWorkDir,
1075
1105
  harnessId,
1076
1106
  sessionId
1077
1107
  }) {
1078
1108
  const sessionKey = createHash4("sha256").update(sessionId).digest("hex");
1079
- const rootDir = path.posix.join(
1109
+ return path.posix.join(
1080
1110
  sandboxHomeDir,
1081
1111
  ".ai-sdk",
1082
1112
  "harness-acp",
1083
1113
  harnessId,
1084
1114
  sessionKey
1085
1115
  );
1086
- assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
1087
- return rootDir;
1088
- }
1089
- async function materializeACPSkills({
1090
- sandbox,
1091
- rootDir,
1092
- sessionWorkDir,
1093
- skills,
1094
- abortSignal
1095
- }) {
1096
- validateACPSkills({ skills });
1097
- assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
1098
- return writeSkills({
1099
- sandbox,
1100
- rootDir,
1101
- skills,
1102
- abortSignal,
1103
- skillNamePattern: ACP_SKILL_NAME_PATTERN,
1104
- invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
1105
- invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
1106
- skillName
1107
- )}: expected a relative POSIX path without traversal.`
1108
- });
1109
1116
  }
1110
1117
  function resolveACPSkillsDirectory({
1111
1118
  implementationHomeDir,
1112
- skillsDirectory = DEFAULT_ACP_SKILLS_DIRECTORY,
1113
- sessionWorkDir
1119
+ skillsDirectory = DEFAULT_ACP_SKILLS_DIRECTORY
1114
1120
  }) {
1115
1121
  const containsTraversal = skillsDirectory.split(/[\\/]/).some((segment) => segment === "..");
1116
1122
  const normalizedDirectory = path.posix.normalize(skillsDirectory);
@@ -1119,9 +1125,7 @@ function resolveACPSkillsDirectory({
1119
1125
  `ACP skillsDirectory ${JSON.stringify(skillsDirectory)} must be a relative POSIX path without traversal.`
1120
1126
  );
1121
1127
  }
1122
- const rootDir = path.posix.join(implementationHomeDir, normalizedDirectory);
1123
- assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
1124
- return rootDir;
1128
+ return path.posix.join(implementationHomeDir, normalizedDirectory);
1125
1129
  }
1126
1130
  function validateACPSkills({
1127
1131
  skills
@@ -1179,20 +1183,6 @@ function validateACPAttachedFilePath({
1179
1183
  }
1180
1184
  return normalizedPath;
1181
1185
  }
1182
- function assertOutsideSessionWorkDir({
1183
- rootDir,
1184
- sessionWorkDir
1185
- }) {
1186
- const relative = path.posix.relative(sessionWorkDir, rootDir);
1187
- const isInside = relative === "" || !relative.startsWith("../") && !path.posix.isAbsolute(relative);
1188
- if (isInside) {
1189
- throw new Error(
1190
- `ACP skill directory ${JSON.stringify(rootDir)} must be outside sessionWorkDir ${JSON.stringify(
1191
- sessionWorkDir
1192
- )}.`
1193
- );
1194
- }
1195
- }
1196
1186
 
1197
1187
  // src/v1/acp-v1-harness.ts
1198
1188
  var HARNESS_ID_REGEXP = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -1359,7 +1349,8 @@ function createACPV1({
1359
1349
  };
1360
1350
  const requestTransformations = settings.credentialBrokering({
1361
1351
  env: brokeringEnvironment,
1362
- sandboxEnv: sandboxImplementationEnvironment
1352
+ sandboxEnv: sandboxImplementationEnvironment,
1353
+ ...startOptions.headers == null ? {} : { headers: startOptions.headers }
1363
1354
  });
1364
1355
  if (requestTransformations.length > 0) {
1365
1356
  await sandboxSession.addRequestTransformations(
@@ -1397,14 +1388,14 @@ function createACPV1({
1397
1388
  });
1398
1389
  const privateSessionDir = resolveACPPrivateSessionDirectory({
1399
1390
  sandboxHomeDir,
1400
- sessionWorkDir: workDir,
1401
1391
  harnessId: settings.harnessId,
1402
1392
  sessionId: startOptions.sessionId
1403
1393
  });
1394
+ const implementationHomeDir = implementation.source.type === "install-command" ? `${resolvedImplementationDir}/home` : sandboxHomeDir;
1395
+ const skillsDir = settings.skillsDirectory ?? DEFAULT_ACP_SKILLS_DIRECTORY;
1404
1396
  const skillsDirectory = resolveACPSkillsDirectory({
1405
- implementationHomeDir: implementation.source.type === "install-command" ? `${resolvedImplementationDir}/home` : sandboxHomeDir,
1406
- skillsDirectory: settings.skillsDirectory,
1407
- sessionWorkDir: workDir
1397
+ implementationHomeDir,
1398
+ skillsDirectory: settings.skillsDirectory
1408
1399
  });
1409
1400
  const bridgeStateDir = `${privateSessionDir}/bridge`;
1410
1401
  const report = startOptions.observability?.report;
@@ -1461,6 +1452,7 @@ function createACPV1({
1461
1452
  sessionMeta: settings.session?.meta,
1462
1453
  instructionMapping: settings.instructionMapping,
1463
1454
  outputSchemaMapping: settings.outputSchemaMapping,
1455
+ askUserQuestions: settings.askUserQuestions,
1464
1456
  debug: startOptions.observability?.debug,
1465
1457
  implementationIdentity,
1466
1458
  authenticationProfile,
@@ -1475,7 +1467,8 @@ function createACPV1({
1475
1467
  }),
1476
1468
  instructionsFingerprint: lifecycleData.instructionsFingerprint,
1477
1469
  sandbox: toolSafeSandboxSession,
1478
- sessionWorkDir: workDir,
1470
+ homePath: implementationHomeDir,
1471
+ skillsDir,
1479
1472
  skillsDirectory,
1480
1473
  acpSessionId: lifecycleData.acpSessionId,
1481
1474
  bridgePort: coords.port,
@@ -1612,7 +1605,9 @@ function createACPV1({
1612
1605
  providerAuthentication: resolvedProviderAuthentication.providerAuthentication,
1613
1606
  providerEnvironment: sandboxProviderEnvironment == null ? void 0 : {},
1614
1607
  sessionMeta: settings.session?.meta,
1615
- clientCapabilities: settings.clientCapabilities
1608
+ clientCapabilities: settings.clientCapabilities,
1609
+ askUserQuestionsRequestMethod: settings.askUserQuestions?.requestMethod,
1610
+ hostToolMcpTransport: settings.hostToolMcpTransport
1616
1611
  }),
1617
1612
  ...sandboxProviderAuthenticationEnvironment,
1618
1613
  BRIDGE_CHANNEL_TOKEN: token,
@@ -1720,6 +1715,7 @@ function createACPV1({
1720
1715
  sessionMeta: settings.session?.meta,
1721
1716
  instructionMapping: settings.instructionMapping,
1722
1717
  outputSchemaMapping: settings.outputSchemaMapping,
1718
+ askUserQuestions: settings.askUserQuestions,
1723
1719
  debug: startOptions.observability?.debug,
1724
1720
  implementationIdentity,
1725
1721
  authenticationProfile,
@@ -1734,7 +1730,8 @@ function createACPV1({
1734
1730
  }),
1735
1731
  instructionsFingerprint: lifecycleData?.instructionsFingerprint,
1736
1732
  sandbox: toolSafeSandboxSession,
1737
- sessionWorkDir: workDir,
1733
+ homePath: implementationHomeDir,
1734
+ skillsDir,
1738
1735
  skillsDirectory,
1739
1736
  acpSessionId: lifecycleData?.acpSessionId,
1740
1737
  bridgePort: boundPort,
@@ -1957,6 +1954,7 @@ function createSession({
1957
1954
  sessionMeta,
1958
1955
  instructionMapping,
1959
1956
  outputSchemaMapping,
1957
+ askUserQuestions,
1960
1958
  debug,
1961
1959
  implementationIdentity,
1962
1960
  authenticationProfile,
@@ -1968,7 +1966,8 @@ function createSession({
1968
1966
  initialGuidanceApplied: initialGuidanceAppliedAtStart,
1969
1967
  instructionsFingerprint: instructionsFingerprintAtStart,
1970
1968
  sandbox,
1971
- sessionWorkDir,
1969
+ homePath,
1970
+ skillsDir,
1972
1971
  skillsDirectory,
1973
1972
  acpSessionId: acpSessionIdAtStart,
1974
1973
  bridgePort,
@@ -1990,6 +1989,7 @@ function createSession({
1990
1989
  let instructionsFingerprint = instructionsFingerprintAtStart;
1991
1990
  let latestACPSessionId = acpSessionIdAtStart;
1992
1991
  let latestTurnStartConfig = turnStartConfigAtStart;
1992
+ const bufferedQuestionResults = /* @__PURE__ */ new Map();
1993
1993
  const markTurnFinished = () => {
1994
1994
  turnInFlight = false;
1995
1995
  };
@@ -2019,6 +2019,8 @@ function createSession({
2019
2019
  let openBlock;
2020
2020
  const dynamicToolCalls = /* @__PURE__ */ new Map();
2021
2021
  const toolCallClassificationErrors = /* @__PURE__ */ new Map();
2022
+ const activeQuestionRequests = /* @__PURE__ */ new Map();
2023
+ const questionToolCallIdsByRequestId = /* @__PURE__ */ new Map();
2022
2024
  const subscriptions = [];
2023
2025
  const forward = (event) => {
2024
2026
  if (event.type === "text-start" || event.type === "reasoning-start") {
@@ -2082,12 +2084,115 @@ function createSession({
2082
2084
  subscriptions.push(
2083
2085
  channel.on("acp-tool-call-candidate", (event) => {
2084
2086
  try {
2087
+ const suppress = askUserQuestions?.isNativeToolCall?.({
2088
+ nativeToolCall: event.toolCall
2089
+ }) === true;
2085
2090
  dynamicToolCalls.set(
2086
2091
  event.toolCall.toolCallId,
2087
2092
  isMcpToolCall?.(event.toolCall) === true
2088
2093
  );
2094
+ channel.send({
2095
+ type: "tool-result",
2096
+ toolCallId: event.requestId,
2097
+ output: { suppress }
2098
+ });
2089
2099
  } catch (error) {
2090
2100
  toolCallClassificationErrors.set(event.toolCall.toolCallId, error);
2101
+ channel.send({
2102
+ type: "tool-result",
2103
+ toolCallId: event.requestId,
2104
+ output: { suppress: false }
2105
+ });
2106
+ }
2107
+ })
2108
+ );
2109
+ subscriptions.push(
2110
+ channel.on("acp-question-request", (event) => {
2111
+ if (askUserQuestions == null) {
2112
+ channel.send({
2113
+ type: "tool-result",
2114
+ toolCallId: event.requestId,
2115
+ output: { type: "unhandled" }
2116
+ });
2117
+ return;
2118
+ }
2119
+ try {
2120
+ const nativeToolCall = askUserQuestions.fromNativeRequest({
2121
+ nativeRequest: event.nativeRequest,
2122
+ nativeToolCall: event.nativeToolCall
2123
+ });
2124
+ if (nativeToolCall == null) {
2125
+ channel.send({
2126
+ type: "tool-result",
2127
+ toolCallId: event.requestId,
2128
+ output: { type: "unhandled" }
2129
+ });
2130
+ return;
2131
+ }
2132
+ if (nativeToolCall.toolName !== "askUserQuestions" || nativeToolCall.providerExecuted !== false) {
2133
+ throw new Error(
2134
+ `${harnessId} ACP askUserQuestions.fromNativeRequest must return a client-executed askUserQuestions tool call.`
2135
+ );
2136
+ }
2137
+ const toolCall = withNativeQuestionRequest({
2138
+ harnessId,
2139
+ nativeRequest: event.nativeRequest,
2140
+ toolCall: nativeToolCall
2141
+ });
2142
+ const bufferedResult = takeBufferedQuestionResult({
2143
+ bufferedQuestionResults,
2144
+ toolCallId: toolCall.toolCallId,
2145
+ nativeRequest: event.nativeRequest,
2146
+ matchesNativeRequest: askUserQuestions.matchesNativeRequest,
2147
+ harnessId
2148
+ });
2149
+ activeQuestionRequests.set(toolCall.toolCallId, {
2150
+ requestId: event.requestId,
2151
+ nativeRequest: event.nativeRequest
2152
+ });
2153
+ questionToolCallIdsByRequestId.set(
2154
+ event.requestId,
2155
+ toolCall.toolCallId
2156
+ );
2157
+ channel.send({
2158
+ type: "tool-result",
2159
+ toolCallId: event.requestId,
2160
+ output: {
2161
+ type: "handled",
2162
+ toolCallId: toolCall.toolCallId
2163
+ }
2164
+ });
2165
+ if (bufferedResult == null) {
2166
+ forward(toolCall);
2167
+ return;
2168
+ }
2169
+ channel.send({
2170
+ type: "tool-result",
2171
+ toolCallId: toolCall.toolCallId,
2172
+ output: askUserQuestions.toNativeResponse({
2173
+ nativeRequest: event.nativeRequest,
2174
+ toolResult: bufferedResult.toolResult
2175
+ }),
2176
+ isError: bufferedResult.isError,
2177
+ toolResult: bufferedResult.toolResult
2178
+ });
2179
+ } catch (error) {
2180
+ closeForwardedBlock();
2181
+ forward({ type: "error", error });
2182
+ try {
2183
+ channel.send({ type: "abort" });
2184
+ } catch {
2185
+ }
2186
+ settle({ error });
2187
+ }
2188
+ })
2189
+ );
2190
+ subscriptions.push(
2191
+ channel.on("acp-question-resolved", (event) => {
2192
+ const toolCallId = questionToolCallIdsByRequestId.get(event.requestId);
2193
+ if (toolCallId != null) {
2194
+ activeQuestionRequests.delete(toolCallId);
2195
+ questionToolCallIdsByRequestId.delete(event.requestId);
2091
2196
  }
2092
2197
  })
2093
2198
  );
@@ -2173,11 +2278,48 @@ function createSession({
2173
2278
  });
2174
2279
  },
2175
2280
  submitToolResult: async (input) => {
2281
+ if (askUserQuestions != null && input.toolResult?.toolName === "askUserQuestions") {
2282
+ const activeRequest = activeQuestionRequests.get(input.toolCallId);
2283
+ if (activeRequest == null) {
2284
+ const previousNativeRequest = input.toolResult.providerOptions?.[harnessId]?.nativeRequest;
2285
+ if (!lossyRerun && previousNativeRequest !== void 0) {
2286
+ channel.send({
2287
+ type: "tool-result",
2288
+ toolCallId: input.toolCallId,
2289
+ output: askUserQuestions.toNativeResponse({
2290
+ nativeRequest: previousNativeRequest,
2291
+ toolResult: input.toolResult
2292
+ }),
2293
+ isError: input.isError,
2294
+ toolResult: input.toolResult
2295
+ });
2296
+ return;
2297
+ }
2298
+ bufferedQuestionResults.set(input.toolCallId, {
2299
+ output: input.output,
2300
+ ...input.isError == null ? {} : { isError: input.isError },
2301
+ toolResult: input.toolResult
2302
+ });
2303
+ return;
2304
+ }
2305
+ channel.send({
2306
+ type: "tool-result",
2307
+ toolCallId: input.toolCallId,
2308
+ output: askUserQuestions.toNativeResponse({
2309
+ nativeRequest: activeRequest.nativeRequest,
2310
+ toolResult: input.toolResult
2311
+ }),
2312
+ isError: input.isError,
2313
+ toolResult: input.toolResult
2314
+ });
2315
+ return;
2316
+ }
2176
2317
  channel.send({
2177
2318
  type: "tool-result",
2178
2319
  toolCallId: input.toolCallId,
2179
2320
  output: input.output,
2180
- isError: input.isError
2321
+ isError: input.isError,
2322
+ toolResult: input.toolResult
2181
2323
  });
2182
2324
  },
2183
2325
  done
@@ -2241,14 +2383,34 @@ function createSession({
2241
2383
  skills,
2242
2384
  abortSignal
2243
2385
  }) => {
2244
- await materializeACPSkills({
2386
+ validateACPSkills({ skills });
2387
+ await writeSkills({
2245
2388
  sandbox,
2246
- rootDir: skillsDirectory,
2247
- sessionWorkDir,
2389
+ homePath,
2390
+ skillsDir,
2248
2391
  skills,
2249
- abortSignal
2392
+ abortSignal,
2393
+ skillNamePattern: ACP_SKILL_NAME_PATTERN,
2394
+ invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
2395
+ invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
2396
+ skillName
2397
+ )}: expected a relative POSIX path without traversal.`
2250
2398
  });
2251
2399
  };
2400
+ const synchronizeInstructions = async ({
2401
+ instructions,
2402
+ abortSignal
2403
+ }) => {
2404
+ if (instructionMapping?.type === "filesystem") {
2405
+ await writeInstructions({
2406
+ sandbox,
2407
+ homePath,
2408
+ instructionsFile: instructionMapping.path,
2409
+ instructions,
2410
+ abortSignal
2411
+ });
2412
+ }
2413
+ };
2252
2414
  return {
2253
2415
  sessionId,
2254
2416
  isResume,
@@ -2257,6 +2419,10 @@ function createSession({
2257
2419
  skills: options.skills,
2258
2420
  abortSignal: options.abortSignal
2259
2421
  });
2422
+ await synchronizeInstructions({
2423
+ instructions: options.instructions,
2424
+ abortSignal: options.abortSignal
2425
+ });
2260
2426
  if (options.responseFormat?.type === "json") {
2261
2427
  if (options.responseFormat.schema == null) {
2262
2428
  throw unsupported({
@@ -2315,7 +2481,7 @@ function createSession({
2315
2481
  turnInFlight = true;
2316
2482
  channel.send({
2317
2483
  type: "start",
2318
- prompt: instructionsFingerprint !== nextInstructionsFingerprint && (instructionMapping == null || initialGuidanceApplied) ? prependACPInstructionGuidance({
2484
+ prompt: instructionMapping?.type !== "filesystem" && instructionsFingerprint !== nextInstructionsFingerprint && (instructionMapping == null || initialGuidanceApplied) ? prependACPInstructionGuidance({
2319
2485
  prompt,
2320
2486
  instructions: options.instructions
2321
2487
  }) : prompt,
@@ -2346,6 +2512,10 @@ function createSession({
2346
2512
  skills: options.skills,
2347
2513
  abortSignal: options.abortSignal
2348
2514
  });
2515
+ await synchronizeInstructions({
2516
+ instructions: options.instructions,
2517
+ abortSignal: options.abortSignal
2518
+ });
2349
2519
  if (options.responseFormat?.type === "json") {
2350
2520
  if (options.responseFormat.schema == null) {
2351
2521
  throw unsupported({
@@ -2421,11 +2591,6 @@ function createSession({
2421
2591
  `${harnessId} ACP session ${sessionId} is stopped; cannot suspend.`
2422
2592
  );
2423
2593
  }
2424
- if (!turnInFlight) {
2425
- throw new Error(
2426
- `${harnessId} ACP session ${sessionId} has no in-flight turn to suspend.`
2427
- );
2428
- }
2429
2594
  stopped = true;
2430
2595
  const lastSeenEventId = await channel.suspend();
2431
2596
  return {
@@ -2491,6 +2656,45 @@ function isCompletePermissionModeMapping({
2491
2656
  }) {
2492
2657
  return isPermissionModeMappingValue({ value: value?.["allow-reads"] }) && isPermissionModeMappingValue({ value: value?.["allow-edits"] }) && isPermissionModeMappingValue({ value: value?.["allow-all"] });
2493
2658
  }
2659
+ function withNativeQuestionRequest({
2660
+ harnessId,
2661
+ nativeRequest,
2662
+ toolCall
2663
+ }) {
2664
+ const harnessMetadata = toolCall.providerMetadata?.[harnessId];
2665
+ return {
2666
+ ...toolCall,
2667
+ providerMetadata: {
2668
+ ...toolCall.providerMetadata,
2669
+ [harnessId]: {
2670
+ ...harnessMetadata ?? {},
2671
+ nativeRequest
2672
+ }
2673
+ }
2674
+ };
2675
+ }
2676
+ function takeBufferedQuestionResult({
2677
+ bufferedQuestionResults,
2678
+ toolCallId,
2679
+ nativeRequest,
2680
+ matchesNativeRequest,
2681
+ harnessId
2682
+ }) {
2683
+ const exact = bufferedQuestionResults.get(toolCallId);
2684
+ if (exact != null) {
2685
+ bufferedQuestionResults.delete(toolCallId);
2686
+ return exact;
2687
+ }
2688
+ if (matchesNativeRequest == null) return void 0;
2689
+ for (const [bufferedToolCallId, buffered] of bufferedQuestionResults) {
2690
+ const previousNativeRequest = buffered.toolResult.providerOptions?.[harnessId]?.nativeRequest;
2691
+ if (previousNativeRequest !== void 0 && matchesNativeRequest({ previousNativeRequest, nativeRequest })) {
2692
+ bufferedQuestionResults.delete(bufferedToolCallId);
2693
+ return buffered;
2694
+ }
2695
+ }
2696
+ return void 0;
2697
+ }
2494
2698
  function isPermissionModeMappingValue({
2495
2699
  value
2496
2700
  }) {
@@ -2636,7 +2840,7 @@ function deserializeBridgeError({
2636
2840
  }
2637
2841
 
2638
2842
  // src/version.ts
2639
- var VERSION = true ? "1.0.38" : "0.0.0-test";
2843
+ var VERSION = true ? "1.0.40" : "0.0.0-test";
2640
2844
 
2641
2845
  // src/acp-harness.ts
2642
2846
  var ACP_CLIENT_APP = {
@@ -2696,9 +2900,13 @@ function createACP(settings) {
2696
2900
  switch (version) {
2697
2901
  case "v1": {
2698
2902
  const clientApp = settings.clientApp ?? ACP_CLIENT_APP;
2903
+ const builtinTools = settings.askUserQuestions == null ? settings.builtinTools ?? ACP_BUILTIN_TOOLS : {
2904
+ ...settings.builtinTools ?? ACP_BUILTIN_TOOLS,
2905
+ askUserQuestions: HARNESS_V1_BUILTIN_TOOLS.askUserQuestions
2906
+ };
2699
2907
  return createACPV1({
2700
2908
  settings,
2701
- builtinTools: settings.builtinTools ?? ACP_BUILTIN_TOOLS,
2909
+ builtinTools,
2702
2910
  port: settings.port,
2703
2911
  portEndpoint: settings.portEndpoint,
2704
2912
  startupTimeoutMs: settings.startupTimeoutMs,