@ai-sdk/harness-acp 1.0.38 → 1.0.39

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { HarnessV1Authentication, HarnessV1RequestTransformation, HarnessV1CredentialForwarding, HarnessV1PermissionMode, HarnessV1PortEndpoint, HarnessV1 } from '@ai-sdk/harness';
2
- import { ToolSet } from '@ai-sdk/provider-utils';
1
+ import { HarnessV1StreamPart, HarnessV1Authentication, HarnessV1RequestTransformation, HarnessV1CredentialForwarding, HarnessV1PermissionMode, HarnessV1PortEndpoint, HarnessV1, HARNESS_V1_BUILTIN_TOOLS } from '@ai-sdk/harness';
2
+ import { ToolResultPart, ToolSet } from '@ai-sdk/provider-utils';
3
3
 
4
4
  type ACPMetadata = Record<string, unknown>;
5
5
  type ACPRole = 'assistant' | 'user';
@@ -182,6 +182,26 @@ type ACPOutputSchemaMapping = {
182
182
  readonly type: 'session-prompt-meta';
183
183
  readonly path: ReadonlyArray<string>;
184
184
  };
185
+ type ACPAskUserQuestionsSettings = {
186
+ readonly requestMethod: string;
187
+ readonly isNativeToolCall?: (options: {
188
+ nativeToolCall: ACPToolCall;
189
+ }) => boolean;
190
+ readonly fromNativeRequest: (options: {
191
+ nativeRequest: unknown;
192
+ nativeToolCall?: ACPToolCall;
193
+ }) => Extract<HarnessV1StreamPart, {
194
+ type: 'tool-call';
195
+ }> | null;
196
+ readonly toNativeResponse: (options: {
197
+ nativeRequest: unknown;
198
+ toolResult: ToolResultPart;
199
+ }) => unknown;
200
+ readonly matchesNativeRequest?: (options: {
201
+ previousNativeRequest: unknown;
202
+ nativeRequest: unknown;
203
+ }) => boolean;
204
+ };
185
205
  type ACPV1Settings = {
186
206
  readonly version?: 'v1';
187
207
  readonly harnessId: string;
@@ -232,6 +252,7 @@ type ACPV1Settings = {
232
252
  * below the ACP session prompt's `_meta` field.
233
253
  */
234
254
  readonly outputSchemaMapping?: ACPOutputSchemaMapping;
255
+ readonly askUserQuestions?: ACPAskUserQuestionsSettings;
235
256
  readonly permissionModeMapping?: ACPPermissionModeMapping;
236
257
  readonly session?: {
237
258
  readonly meta?: Readonly<Record<string, ACPSerializableValue>>;
@@ -249,7 +270,7 @@ type ACPClientApp = {
249
270
  readonly version: string;
250
271
  };
251
272
 
252
- type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}> = {
273
+ type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}, TAskUserQuestions extends ACPAskUserQuestionsSettings | undefined = ACPAskUserQuestionsSettings | undefined> = {
253
274
  readonly builtinTools?: TBuiltinTools;
254
275
  /**
255
276
  * MCP server definitions keyed by server name. Each definition uses the
@@ -295,12 +316,16 @@ type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}> = {
295
316
  readonly skillsDirectory?: ACPV1Settings['skillsDirectory'];
296
317
  readonly instructionMapping?: ACPV1Settings['instructionMapping'];
297
318
  readonly outputSchemaMapping?: ACPV1Settings['outputSchemaMapping'];
319
+ readonly askUserQuestions?: TAskUserQuestions;
298
320
  readonly permissionModeMapping?: ACPV1Settings['permissionModeMapping'];
299
321
  readonly session?: ACPV1Settings['session'];
300
322
  readonly mintBridgeToken?: ACPV1Settings['mintBridgeToken'];
301
323
  };
302
- declare function createACP<TBuiltinTools extends ToolSet = {}>(settings: ACPHarnessSettings<TBuiltinTools>): HarnessV1<TBuiltinTools>;
324
+ type ACPHarnessTools<TBuiltinTools extends ToolSet, TAskUserQuestions> = TBuiltinTools & ([TAskUserQuestions] extends [undefined] ? {} : {
325
+ askUserQuestions: typeof HARNESS_V1_BUILTIN_TOOLS.askUserQuestions;
326
+ });
327
+ declare function createACP<TBuiltinTools extends ToolSet = {}, TAskUserQuestions extends ACPAskUserQuestionsSettings | undefined = undefined>(settings: ACPHarnessSettings<TBuiltinTools, TAskUserQuestions>): HarnessV1<ACPHarnessTools<TBuiltinTools, TAskUserQuestions>>;
303
328
 
304
329
  declare const VERSION: string;
305
330
 
306
- export { type ACPAnnotations, type ACPAudioContent, type ACPAuthentication, type ACPAuthenticationMode, type ACPBlobResourceContents, type ACPClientApp, type ACPContentBlock, type ACPCredentialBrokering, type ACPEmbeddedResource, type ACPHarnessSettings, type ACPImageContent, type ACPInstallCommandSource, type ACPInstructionMapping, type ACPMetadata, type ACPModelMapping, type ACPNpmLockedSource, type ACPNpmSimpleSource, type ACPOutputSchemaMapping, type ACPPermissionModeMapping, type ACPPermissionModeTarget, type ACPProfileValue, type ACPProviderAuthentication, type ACPResourceLink, type ACPRole, type ACPSerializablePrimitive, type ACPSerializableValue, type ACPSource, type ACPTextContent, type ACPTextResourceContents, type ACPToolCall, type ACPToolCallContent, type ACPToolCallLocation, type ACPToolCallStatus, type ACPToolKind, type ACPV1Settings, type ACPValueSource, VERSION, createACP };
331
+ export { type ACPAnnotations, type ACPAskUserQuestionsSettings, type ACPAudioContent, type ACPAuthentication, type ACPAuthenticationMode, type ACPBlobResourceContents, type ACPClientApp, type ACPContentBlock, type ACPCredentialBrokering, type ACPEmbeddedResource, type ACPHarnessSettings, type ACPImageContent, type ACPInstallCommandSource, type ACPInstructionMapping, type ACPMetadata, type ACPModelMapping, type ACPNpmLockedSource, type ACPNpmSimpleSource, type ACPOutputSchemaMapping, type ACPPermissionModeMapping, type ACPPermissionModeTarget, type ACPProfileValue, type ACPProviderAuthentication, type ACPResourceLink, type ACPRole, type ACPSerializablePrimitive, type ACPSerializableValue, type ACPSource, type ACPTextContent, type ACPTextResourceContents, type ACPToolCall, type ACPToolCallContent, type ACPToolCallLocation, type ACPToolCallStatus, type ACPToolKind, type ACPV1Settings, type ACPValueSource, VERSION, createACP };
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
@@ -756,13 +759,26 @@ var coldRestoreSchema = z2.object({
756
759
  });
757
760
  var acpToolCallCandidateSchema = z2.object({
758
761
  type: z2.literal("acp-tool-call-candidate"),
762
+ requestId: z2.string(),
759
763
  toolCall: z2.custom(
760
764
  (value) => value != null && typeof value === "object" && typeof value.toolCallId === "string" && typeof value.title === "string"
761
765
  )
762
766
  });
767
+ var acpQuestionRequestSchema = z2.object({
768
+ type: z2.literal("acp-question-request"),
769
+ requestId: z2.string(),
770
+ nativeRequest: z2.unknown(),
771
+ nativeToolCall: acpToolCallCandidateSchema.shape.toolCall.optional()
772
+ });
773
+ var acpQuestionResolvedSchema = z2.object({
774
+ type: z2.literal("acp-question-resolved"),
775
+ requestId: z2.string()
776
+ });
763
777
  var outboundMessageSchema = z2.union([
764
778
  harnessV1BridgeOutboundMessageSchema,
765
- acpToolCallCandidateSchema
779
+ acpToolCallCandidateSchema,
780
+ acpQuestionRequestSchema,
781
+ acpQuestionResolvedSchema
766
782
  ]);
767
783
  var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
768
784
  prompt: z2.array(acpTextContentBlockSchema),
@@ -828,14 +844,16 @@ var bridgeConfigurationSchema = z3.object({
828
844
  providerAuthentication: providerAuthenticationSchema.optional(),
829
845
  providerEnvironment: z3.record(z3.string(), z3.string()).optional(),
830
846
  sessionMeta: serializableRecordSchema.optional(),
831
- clientCapabilities: serializableRecordSchema.optional()
847
+ clientCapabilities: serializableRecordSchema.optional(),
848
+ askUserQuestionsRequestMethod: z3.string().optional()
832
849
  });
833
850
  function createACPBridgeEnvironment({
834
851
  authentication,
835
852
  providerAuthentication,
836
853
  providerEnvironment,
837
854
  sessionMeta,
838
- clientCapabilities
855
+ clientCapabilities,
856
+ askUserQuestionsRequestMethod
839
857
  }) {
840
858
  return {
841
859
  [ACP_BRIDGE_CONFIGURATION_ENV]: JSON.stringify({
@@ -843,7 +861,8 @@ function createACPBridgeEnvironment({
843
861
  ...providerAuthentication == null ? {} : { providerAuthentication },
844
862
  ...providerEnvironment == null ? {} : { providerEnvironment },
845
863
  ...sessionMeta == null ? {} : { sessionMeta },
846
- ...clientCapabilities == null ? {} : { clientCapabilities }
864
+ ...clientCapabilities == null ? {} : { clientCapabilities },
865
+ ...askUserQuestionsRequestMethod == null ? {} : { askUserQuestionsRequestMethod }
847
866
  })
848
867
  };
849
868
  }
@@ -1461,6 +1480,7 @@ function createACPV1({
1461
1480
  sessionMeta: settings.session?.meta,
1462
1481
  instructionMapping: settings.instructionMapping,
1463
1482
  outputSchemaMapping: settings.outputSchemaMapping,
1483
+ askUserQuestions: settings.askUserQuestions,
1464
1484
  debug: startOptions.observability?.debug,
1465
1485
  implementationIdentity,
1466
1486
  authenticationProfile,
@@ -1612,7 +1632,8 @@ function createACPV1({
1612
1632
  providerAuthentication: resolvedProviderAuthentication.providerAuthentication,
1613
1633
  providerEnvironment: sandboxProviderEnvironment == null ? void 0 : {},
1614
1634
  sessionMeta: settings.session?.meta,
1615
- clientCapabilities: settings.clientCapabilities
1635
+ clientCapabilities: settings.clientCapabilities,
1636
+ askUserQuestionsRequestMethod: settings.askUserQuestions?.requestMethod
1616
1637
  }),
1617
1638
  ...sandboxProviderAuthenticationEnvironment,
1618
1639
  BRIDGE_CHANNEL_TOKEN: token,
@@ -1720,6 +1741,7 @@ function createACPV1({
1720
1741
  sessionMeta: settings.session?.meta,
1721
1742
  instructionMapping: settings.instructionMapping,
1722
1743
  outputSchemaMapping: settings.outputSchemaMapping,
1744
+ askUserQuestions: settings.askUserQuestions,
1723
1745
  debug: startOptions.observability?.debug,
1724
1746
  implementationIdentity,
1725
1747
  authenticationProfile,
@@ -1957,6 +1979,7 @@ function createSession({
1957
1979
  sessionMeta,
1958
1980
  instructionMapping,
1959
1981
  outputSchemaMapping,
1982
+ askUserQuestions,
1960
1983
  debug,
1961
1984
  implementationIdentity,
1962
1985
  authenticationProfile,
@@ -1990,6 +2013,7 @@ function createSession({
1990
2013
  let instructionsFingerprint = instructionsFingerprintAtStart;
1991
2014
  let latestACPSessionId = acpSessionIdAtStart;
1992
2015
  let latestTurnStartConfig = turnStartConfigAtStart;
2016
+ const bufferedQuestionResults = /* @__PURE__ */ new Map();
1993
2017
  const markTurnFinished = () => {
1994
2018
  turnInFlight = false;
1995
2019
  };
@@ -2019,6 +2043,8 @@ function createSession({
2019
2043
  let openBlock;
2020
2044
  const dynamicToolCalls = /* @__PURE__ */ new Map();
2021
2045
  const toolCallClassificationErrors = /* @__PURE__ */ new Map();
2046
+ const activeQuestionRequests = /* @__PURE__ */ new Map();
2047
+ const questionToolCallIdsByRequestId = /* @__PURE__ */ new Map();
2022
2048
  const subscriptions = [];
2023
2049
  const forward = (event) => {
2024
2050
  if (event.type === "text-start" || event.type === "reasoning-start") {
@@ -2082,12 +2108,115 @@ function createSession({
2082
2108
  subscriptions.push(
2083
2109
  channel.on("acp-tool-call-candidate", (event) => {
2084
2110
  try {
2111
+ const suppress = askUserQuestions?.isNativeToolCall?.({
2112
+ nativeToolCall: event.toolCall
2113
+ }) === true;
2085
2114
  dynamicToolCalls.set(
2086
2115
  event.toolCall.toolCallId,
2087
2116
  isMcpToolCall?.(event.toolCall) === true
2088
2117
  );
2118
+ channel.send({
2119
+ type: "tool-result",
2120
+ toolCallId: event.requestId,
2121
+ output: { suppress }
2122
+ });
2089
2123
  } catch (error) {
2090
2124
  toolCallClassificationErrors.set(event.toolCall.toolCallId, error);
2125
+ channel.send({
2126
+ type: "tool-result",
2127
+ toolCallId: event.requestId,
2128
+ output: { suppress: false }
2129
+ });
2130
+ }
2131
+ })
2132
+ );
2133
+ subscriptions.push(
2134
+ channel.on("acp-question-request", (event) => {
2135
+ if (askUserQuestions == null) {
2136
+ channel.send({
2137
+ type: "tool-result",
2138
+ toolCallId: event.requestId,
2139
+ output: { type: "unhandled" }
2140
+ });
2141
+ return;
2142
+ }
2143
+ try {
2144
+ const nativeToolCall = askUserQuestions.fromNativeRequest({
2145
+ nativeRequest: event.nativeRequest,
2146
+ nativeToolCall: event.nativeToolCall
2147
+ });
2148
+ if (nativeToolCall == null) {
2149
+ channel.send({
2150
+ type: "tool-result",
2151
+ toolCallId: event.requestId,
2152
+ output: { type: "unhandled" }
2153
+ });
2154
+ return;
2155
+ }
2156
+ if (nativeToolCall.toolName !== "askUserQuestions" || nativeToolCall.providerExecuted !== false) {
2157
+ throw new Error(
2158
+ `${harnessId} ACP askUserQuestions.fromNativeRequest must return a client-executed askUserQuestions tool call.`
2159
+ );
2160
+ }
2161
+ const toolCall = withNativeQuestionRequest({
2162
+ harnessId,
2163
+ nativeRequest: event.nativeRequest,
2164
+ toolCall: nativeToolCall
2165
+ });
2166
+ const bufferedResult = takeBufferedQuestionResult({
2167
+ bufferedQuestionResults,
2168
+ toolCallId: toolCall.toolCallId,
2169
+ nativeRequest: event.nativeRequest,
2170
+ matchesNativeRequest: askUserQuestions.matchesNativeRequest,
2171
+ harnessId
2172
+ });
2173
+ activeQuestionRequests.set(toolCall.toolCallId, {
2174
+ requestId: event.requestId,
2175
+ nativeRequest: event.nativeRequest
2176
+ });
2177
+ questionToolCallIdsByRequestId.set(
2178
+ event.requestId,
2179
+ toolCall.toolCallId
2180
+ );
2181
+ channel.send({
2182
+ type: "tool-result",
2183
+ toolCallId: event.requestId,
2184
+ output: {
2185
+ type: "handled",
2186
+ toolCallId: toolCall.toolCallId
2187
+ }
2188
+ });
2189
+ if (bufferedResult == null) {
2190
+ forward(toolCall);
2191
+ return;
2192
+ }
2193
+ channel.send({
2194
+ type: "tool-result",
2195
+ toolCallId: toolCall.toolCallId,
2196
+ output: askUserQuestions.toNativeResponse({
2197
+ nativeRequest: event.nativeRequest,
2198
+ toolResult: bufferedResult.toolResult
2199
+ }),
2200
+ isError: bufferedResult.isError,
2201
+ toolResult: bufferedResult.toolResult
2202
+ });
2203
+ } catch (error) {
2204
+ closeForwardedBlock();
2205
+ forward({ type: "error", error });
2206
+ try {
2207
+ channel.send({ type: "abort" });
2208
+ } catch {
2209
+ }
2210
+ settle({ error });
2211
+ }
2212
+ })
2213
+ );
2214
+ subscriptions.push(
2215
+ channel.on("acp-question-resolved", (event) => {
2216
+ const toolCallId = questionToolCallIdsByRequestId.get(event.requestId);
2217
+ if (toolCallId != null) {
2218
+ activeQuestionRequests.delete(toolCallId);
2219
+ questionToolCallIdsByRequestId.delete(event.requestId);
2091
2220
  }
2092
2221
  })
2093
2222
  );
@@ -2173,11 +2302,48 @@ function createSession({
2173
2302
  });
2174
2303
  },
2175
2304
  submitToolResult: async (input) => {
2305
+ if (askUserQuestions != null && input.toolResult?.toolName === "askUserQuestions") {
2306
+ const activeRequest = activeQuestionRequests.get(input.toolCallId);
2307
+ if (activeRequest == null) {
2308
+ const previousNativeRequest = input.toolResult.providerOptions?.[harnessId]?.nativeRequest;
2309
+ if (!lossyRerun && previousNativeRequest !== void 0) {
2310
+ channel.send({
2311
+ type: "tool-result",
2312
+ toolCallId: input.toolCallId,
2313
+ output: askUserQuestions.toNativeResponse({
2314
+ nativeRequest: previousNativeRequest,
2315
+ toolResult: input.toolResult
2316
+ }),
2317
+ isError: input.isError,
2318
+ toolResult: input.toolResult
2319
+ });
2320
+ return;
2321
+ }
2322
+ bufferedQuestionResults.set(input.toolCallId, {
2323
+ output: input.output,
2324
+ ...input.isError == null ? {} : { isError: input.isError },
2325
+ toolResult: input.toolResult
2326
+ });
2327
+ return;
2328
+ }
2329
+ channel.send({
2330
+ type: "tool-result",
2331
+ toolCallId: input.toolCallId,
2332
+ output: askUserQuestions.toNativeResponse({
2333
+ nativeRequest: activeRequest.nativeRequest,
2334
+ toolResult: input.toolResult
2335
+ }),
2336
+ isError: input.isError,
2337
+ toolResult: input.toolResult
2338
+ });
2339
+ return;
2340
+ }
2176
2341
  channel.send({
2177
2342
  type: "tool-result",
2178
2343
  toolCallId: input.toolCallId,
2179
2344
  output: input.output,
2180
- isError: input.isError
2345
+ isError: input.isError,
2346
+ toolResult: input.toolResult
2181
2347
  });
2182
2348
  },
2183
2349
  done
@@ -2491,6 +2657,45 @@ function isCompletePermissionModeMapping({
2491
2657
  }) {
2492
2658
  return isPermissionModeMappingValue({ value: value?.["allow-reads"] }) && isPermissionModeMappingValue({ value: value?.["allow-edits"] }) && isPermissionModeMappingValue({ value: value?.["allow-all"] });
2493
2659
  }
2660
+ function withNativeQuestionRequest({
2661
+ harnessId,
2662
+ nativeRequest,
2663
+ toolCall
2664
+ }) {
2665
+ const harnessMetadata = toolCall.providerMetadata?.[harnessId];
2666
+ return {
2667
+ ...toolCall,
2668
+ providerMetadata: {
2669
+ ...toolCall.providerMetadata,
2670
+ [harnessId]: {
2671
+ ...harnessMetadata ?? {},
2672
+ nativeRequest
2673
+ }
2674
+ }
2675
+ };
2676
+ }
2677
+ function takeBufferedQuestionResult({
2678
+ bufferedQuestionResults,
2679
+ toolCallId,
2680
+ nativeRequest,
2681
+ matchesNativeRequest,
2682
+ harnessId
2683
+ }) {
2684
+ const exact = bufferedQuestionResults.get(toolCallId);
2685
+ if (exact != null) {
2686
+ bufferedQuestionResults.delete(toolCallId);
2687
+ return exact;
2688
+ }
2689
+ if (matchesNativeRequest == null) return void 0;
2690
+ for (const [bufferedToolCallId, buffered] of bufferedQuestionResults) {
2691
+ const previousNativeRequest = buffered.toolResult.providerOptions?.[harnessId]?.nativeRequest;
2692
+ if (previousNativeRequest !== void 0 && matchesNativeRequest({ previousNativeRequest, nativeRequest })) {
2693
+ bufferedQuestionResults.delete(bufferedToolCallId);
2694
+ return buffered;
2695
+ }
2696
+ }
2697
+ return void 0;
2698
+ }
2494
2699
  function isPermissionModeMappingValue({
2495
2700
  value
2496
2701
  }) {
@@ -2636,7 +2841,7 @@ function deserializeBridgeError({
2636
2841
  }
2637
2842
 
2638
2843
  // src/version.ts
2639
- var VERSION = true ? "1.0.38" : "0.0.0-test";
2844
+ var VERSION = true ? "1.0.39" : "0.0.0-test";
2640
2845
 
2641
2846
  // src/acp-harness.ts
2642
2847
  var ACP_CLIENT_APP = {
@@ -2696,9 +2901,13 @@ function createACP(settings) {
2696
2901
  switch (version) {
2697
2902
  case "v1": {
2698
2903
  const clientApp = settings.clientApp ?? ACP_CLIENT_APP;
2904
+ const builtinTools = settings.askUserQuestions == null ? settings.builtinTools ?? ACP_BUILTIN_TOOLS : {
2905
+ ...settings.builtinTools ?? ACP_BUILTIN_TOOLS,
2906
+ askUserQuestions: HARNESS_V1_BUILTIN_TOOLS.askUserQuestions
2907
+ };
2699
2908
  return createACPV1({
2700
2909
  settings,
2701
- builtinTools: settings.builtinTools ?? ACP_BUILTIN_TOOLS,
2910
+ builtinTools,
2702
2911
  port: settings.port,
2703
2912
  portEndpoint: settings.portEndpoint,
2704
2913
  startupTimeoutMs: settings.startupTimeoutMs,