@ai-sdk/harness-acp 1.0.37 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @ai-sdk/harness-acp
2
2
 
3
+ ## 1.0.39
4
+
5
+ ### Patch Changes
6
+
7
+ - 951c54d: feat(harness): support `askUserQuestions` tool including support for normalization across harness adapters
8
+ - Updated dependencies [951c54d]
9
+ - @ai-sdk/harness@1.0.101
10
+
11
+ ## 1.0.38
12
+
13
+ ### Patch Changes
14
+
15
+ - 74d252a: fix(harness-acp): preserve terminal events replayed during ACP continuation startup
16
+ - 0c37bf0: fix(harness): avoid warning about lack of credential brokering support when `credentialForwarding` callback is used to replace all credentials with ephemeral fake secrets
17
+ - Updated dependencies [0c37bf0]
18
+ - @ai-sdk/harness@1.0.100
19
+
3
20
  ## 1.0.37
4
21
 
5
22
  ### Patch Changes
@@ -12,7 +12,7 @@ import {
12
12
  ListToolsRequestSchema,
13
13
  McpError
14
14
  } from "@modelcontextprotocol/sdk/types.js";
15
- var VERSION = true ? "1.0.37" : "0.0.0-test";
15
+ var VERSION = true ? "1.0.39" : "0.0.0-test";
16
16
  function createHostToolMCPServer({
17
17
  tools: tools2,
18
18
  revision = 1,
@@ -230,6 +230,7 @@ async function runBridge(options) {
230
230
  }
231
231
  }
232
232
  const pendingToolResults = /* @__PURE__ */ new Map();
233
+ const bufferedToolResults = [];
233
234
  const pendingToolApprovals = /* @__PURE__ */ new Map();
234
235
  const writeBridgeMeta = async (state) => {
235
236
  try {
@@ -409,9 +410,23 @@ async function runBridge(options) {
409
410
  const userMessages = createBridgeUserMessageQueue({ respond: emit });
410
411
  const turn = {
411
412
  emit,
412
- requestToolResult: (toolCallId) => new Promise((resolve) => {
413
- pendingToolResults.set(toolCallId, resolve);
414
- }),
413
+ requestToolResult: (requestInput) => {
414
+ const request = typeof requestInput === "string" ? { toolCallId: requestInput } : requestInput;
415
+ const bufferedIndex = bufferedToolResults.findIndex(
416
+ (buffered) => buffered.toolCallId === request.toolCallId || request.matches?.(buffered.result) === true
417
+ );
418
+ if (bufferedIndex >= 0) {
419
+ return Promise.resolve(
420
+ bufferedToolResults.splice(bufferedIndex, 1)[0].result
421
+ );
422
+ }
423
+ return new Promise((resolve) => {
424
+ pendingToolResults.set(request.toolCallId, {
425
+ resolve,
426
+ matches: request.matches
427
+ });
428
+ });
429
+ },
415
430
  requestToolApproval: (approvalId) => new Promise((resolve) => {
416
431
  pendingToolApprovals.set(approvalId, resolve);
417
432
  }),
@@ -453,10 +468,25 @@ async function runBridge(options) {
453
468
  return;
454
469
  }
455
470
  case "tool-result": {
456
- const resolver = pendingToolResults.get(msg.toolCallId);
457
- if (resolver) {
458
- pendingToolResults.delete(msg.toolCallId);
459
- resolver({ output: msg.output, isError: msg.isError });
471
+ const result = {
472
+ output: msg.output,
473
+ isError: msg.isError,
474
+ toolResult: msg.toolResult
475
+ };
476
+ const exactPending = pendingToolResults.get(msg.toolCallId);
477
+ const matchingPending = exactPending == null ? Array.from(pendingToolResults.entries()).find(
478
+ ([, pending2]) => pending2.matches?.(result) === true
479
+ ) : void 0;
480
+ const pending = exactPending ?? matchingPending?.[1];
481
+ const pendingId = exactPending != null ? msg.toolCallId : matchingPending?.[0];
482
+ if (pending != null && pendingId != null) {
483
+ pendingToolResults.delete(pendingId);
484
+ pending.resolve(result);
485
+ } else {
486
+ bufferedToolResults.push({
487
+ toolCallId: msg.toolCallId,
488
+ result
489
+ });
460
490
  }
461
491
  return;
462
492
  }
@@ -684,7 +714,8 @@ var bridgeConfigurationSchema = z.object({
684
714
  providerAuthentication: providerAuthenticationSchema.optional(),
685
715
  providerEnvironment: z.record(z.string(), z.string()).optional(),
686
716
  sessionMeta: serializableRecordSchema.optional(),
687
- clientCapabilities: serializableRecordSchema.optional()
717
+ clientCapabilities: serializableRecordSchema.optional(),
718
+ askUserQuestionsRequestMethod: z.string().optional()
688
719
  });
689
720
  async function readACPBridgeEnvironment({
690
721
  env
@@ -1154,6 +1185,7 @@ function createACPStreamTranslator({
1154
1185
  builtinTools,
1155
1186
  builtinToolsByName
1156
1187
  });
1188
+ emitToolCallCandidate?.({ toolCall: createACPToolCall({ state }) });
1157
1189
  if (!forceEmit && builtin?.inputSchema != null && state.values.status !== "completed" && state.values.status !== "failed" && !hasRequiredBuiltinToolInput({
1158
1190
  rawInput: state.values.rawInput,
1159
1191
  inputSchema: builtin.inputSchema
@@ -1168,7 +1200,6 @@ function createACPStreamTranslator({
1168
1200
  programmaticName,
1169
1201
  toolCallId: state.toolCallId
1170
1202
  });
1171
- emitToolCallCandidate?.({ toolCall: createACPToolCall({ state }) });
1172
1203
  }
1173
1204
  emit({
1174
1205
  type: "tool-call",
@@ -1277,6 +1308,10 @@ function createACPStreamTranslator({
1277
1308
  close: closeBlock,
1278
1309
  hostToolCall,
1279
1310
  hostToolResult,
1311
+ getToolCall: ({ toolCallId }) => {
1312
+ const state = toolStates.get(toolCallId);
1313
+ return state == null ? void 0 : createACPToolCall({ state });
1314
+ },
1280
1315
  finish: (response) => {
1281
1316
  if (finished) return;
1282
1317
  finished = true;
@@ -1731,6 +1766,7 @@ function createHostToolCorrelation({
1731
1766
  const candidates = /* @__PURE__ */ new Map();
1732
1767
  const suppressedToolCallIds = /* @__PURE__ */ new Set();
1733
1768
  const releasedToolCallIds = /* @__PURE__ */ new Set();
1769
+ const observedToolCalls = /* @__PURE__ */ new Map();
1734
1770
  let nextCandidateOrder = 0;
1735
1771
  let buffered = [];
1736
1772
  let flushTimer;
@@ -1807,6 +1843,13 @@ function createHostToolCorrelation({
1807
1843
  return;
1808
1844
  }
1809
1845
  const toolCallId = message.update.toolCallId;
1846
+ observedToolCalls.set(
1847
+ toolCallId,
1848
+ mergeObservedToolCall({
1849
+ previous: observedToolCalls.get(toolCallId),
1850
+ update: message.update
1851
+ })
1852
+ );
1810
1853
  if (suppressedToolCallIds.has(toolCallId)) {
1811
1854
  if (isTerminalToolUpdate(message)) {
1812
1855
  suppressedToolCallIds.delete(toolCallId);
@@ -1890,6 +1933,8 @@ function createHostToolCorrelation({
1890
1933
  suppressToolCallUpdate({ toolCallId: toolCall.toolCallId });
1891
1934
  return true;
1892
1935
  },
1936
+ suppressToolCall: suppressToolCallUpdate,
1937
+ getToolCall: ({ toolCallId }) => observedToolCalls.get(toolCallId),
1893
1938
  flush,
1894
1939
  removeInvocation: ({ token }) => {
1895
1940
  deleteInvocation({ invocations, token });
@@ -1905,9 +1950,26 @@ function createHostToolCorrelation({
1905
1950
  candidates.clear();
1906
1951
  suppressedToolCallIds.clear();
1907
1952
  releasedToolCallIds.clear();
1953
+ observedToolCalls.clear();
1908
1954
  }
1909
1955
  };
1910
1956
  }
1957
+ function mergeObservedToolCall({
1958
+ previous,
1959
+ update
1960
+ }) {
1961
+ return {
1962
+ toolCallId: update.toolCallId,
1963
+ title: update.title ?? previous?.title ?? `Tool ${update.toolCallId}`,
1964
+ ...update.kind == null ? {} : { kind: update.kind },
1965
+ ...update.status == null ? {} : { status: update.status },
1966
+ ...update.content == null ? {} : { content: update.content },
1967
+ ...update.locations == null ? {} : { locations: update.locations },
1968
+ ...update.rawInput === void 0 ? {} : { rawInput: update.rawInput },
1969
+ ...update.rawOutput === void 0 ? {} : { rawOutput: update.rawOutput },
1970
+ ...update._meta === void 0 ? {} : { _meta: update._meta }
1971
+ };
1972
+ }
1911
1973
  function hasPortableEvidence({
1912
1974
  candidate,
1913
1975
  invocation
@@ -2218,7 +2280,9 @@ function createEmitStreamEvent({
2218
2280
  hostToolCall: translator.hostToolCall,
2219
2281
  hostToolResult: translator.hostToolResult,
2220
2282
  registerHostToolCorrelationInvocation: correlation.registerInvocation,
2221
- removeHostToolCorrelationInvocation: correlation.removeInvocation
2283
+ removeHostToolCorrelationInvocation: correlation.removeInvocation,
2284
+ suppressToolCall: correlation.suppressToolCall,
2285
+ getToolCall: ({ toolCallId }) => correlation.getToolCall({ toolCallId }) ?? translator.getToolCall({ toolCallId })
2222
2286
  };
2223
2287
  }
2224
2288
 
@@ -3150,6 +3214,7 @@ var sessionConfigurationFailure;
3150
3214
  var historicalUpdatesSuppressed = false;
3151
3215
  var coldRestorationMethod;
3152
3216
  var activePermissionController;
3217
+ var activeQuestionRequest;
3153
3218
  await runBridge({
3154
3219
  bridgeType,
3155
3220
  bridgeStateDir,
@@ -3293,15 +3358,31 @@ async function runTurn(start, turn) {
3293
3358
  const emitStreamEvent = createEmitStreamEvent({
3294
3359
  emit: (event) => turn.emit(event),
3295
3360
  emitToolCallCandidate: ({ toolCall }) => {
3361
+ const requestId = crypto.randomUUID();
3296
3362
  turn.emit({
3297
3363
  type: "acp-tool-call-candidate",
3364
+ requestId,
3298
3365
  toolCall
3299
3366
  });
3367
+ void turn.requestToolResult(requestId).then((result) => {
3368
+ if (result.output != null && typeof result.output === "object" && "suppress" in result.output && result.output.suppress === true) {
3369
+ emitStreamEvent.suppressToolCall({
3370
+ toolCallId: toolCall.toolCallId
3371
+ });
3372
+ }
3373
+ });
3300
3374
  },
3301
3375
  builtinTools: start.builtinTools,
3302
3376
  hostToolServerName: HOST_TOOL_MCP_SERVER_NAME,
3303
3377
  hostTools: start.tools ?? []
3304
3378
  });
3379
+ if (bridgeConfiguration.askUserQuestionsRequestMethod != null) {
3380
+ activeQuestionRequest = {
3381
+ method: bridgeConfiguration.askUserQuestionsRequestMethod,
3382
+ turn,
3383
+ emitStreamEvent
3384
+ };
3385
+ }
3305
3386
  const permissionController = createACPPermissionController({
3306
3387
  turn,
3307
3388
  sessionId: activeSession.sessionId,
@@ -3391,6 +3472,9 @@ async function runTurn(start, turn) {
3391
3472
  if (emitStreamEvent.message({ message })) return;
3392
3473
  }
3393
3474
  } finally {
3475
+ if (activeQuestionRequest?.turn === turn) {
3476
+ activeQuestionRequest = void 0;
3477
+ }
3394
3478
  permissionController.cancelAll();
3395
3479
  activePermissionController = void 0;
3396
3480
  activeHostToolRelay.unbindTurn({ turn: relayTurn });
@@ -3483,7 +3567,7 @@ async function ensureSession({
3483
3567
  stream: acp5.ndJsonStream(input, output)
3484
3568
  });
3485
3569
  streamCapture = capturedStream.capture;
3486
- connection = acp5.client({ name: clientApp.name }).onRequest(
3570
+ let client2 = acp5.client({ name: clientApp.name }).onRequest(
3487
3571
  acp5.methods.client.session.requestPermission,
3488
3572
  ({ params }) => activePermissionController?.requestPermission(params) ?? {
3489
3573
  outcome: { outcome: "cancelled" }
@@ -3496,7 +3580,52 @@ async function ensureSession({
3496
3580
  notification: params,
3497
3581
  update: params.update
3498
3582
  });
3499
- }).connect(capturedStream.stream);
3583
+ });
3584
+ if (bridgeConfiguration.askUserQuestionsRequestMethod != null) {
3585
+ const method = bridgeConfiguration.askUserQuestionsRequestMethod;
3586
+ client2 = client2.onRequest(
3587
+ method,
3588
+ (value) => value,
3589
+ async ({ params }) => {
3590
+ const active = activeQuestionRequest;
3591
+ if (active == null || active.method !== method) {
3592
+ throw acp5.RequestError.methodNotFound(method);
3593
+ }
3594
+ const requestId = crypto.randomUUID();
3595
+ const nativeToolCallId = getNativeQuestionToolCallId({ params });
3596
+ active.turn.emit({
3597
+ type: "acp-question-request",
3598
+ requestId,
3599
+ nativeRequest: params,
3600
+ ...nativeToolCallId == null ? {} : {
3601
+ nativeToolCall: active.emitStreamEvent.getToolCall({
3602
+ toolCallId: nativeToolCallId
3603
+ }) ?? void 0
3604
+ }
3605
+ });
3606
+ const result = await active.turn.requestToolResult(requestId);
3607
+ const classification = result.output;
3608
+ if (classification?.type !== "handled") {
3609
+ throw acp5.RequestError.methodNotFound(method);
3610
+ }
3611
+ active.emitStreamEvent.suppressToolCall({
3612
+ toolCallId: nativeToolCallId ?? classification.toolCallId
3613
+ });
3614
+ try {
3615
+ const nativeResult = await active.turn.requestToolResult(
3616
+ classification.toolCallId
3617
+ );
3618
+ return nativeResult.output;
3619
+ } finally {
3620
+ active.turn.emit({
3621
+ type: "acp-question-resolved",
3622
+ requestId
3623
+ });
3624
+ }
3625
+ }
3626
+ );
3627
+ }
3628
+ connection = client2.connect(capturedStream.stream);
3500
3629
  const initializeRequest = createACPInitializeRequest({
3501
3630
  protocolVersion: acp5.PROTOCOL_VERSION,
3502
3631
  clientApp,
@@ -3629,6 +3758,14 @@ async function ensureSession({
3629
3758
  sessionConfigurationFingerprint = fingerprint;
3630
3759
  return { initialHostToolCatalogRefreshRequired: tools.length > 0 };
3631
3760
  }
3761
+ function getNativeQuestionToolCallId({
3762
+ params
3763
+ }) {
3764
+ if (!isRecord7(params)) return void 0;
3765
+ if (typeof params.toolCallId === "string") return params.toolCallId;
3766
+ const nestedParams = params.params;
3767
+ return isRecord7(nestedParams) && typeof nestedParams.toolCallId === "string" ? nestedParams.toolCallId : void 0;
3768
+ }
3632
3769
  function createExternalMcpServers({
3633
3770
  mcpServers,
3634
3771
  initialization