@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/CHANGELOG.md +8 -0
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +149 -12
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +30 -5
- package/dist/index.js +217 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/acp-harness.ts +43 -9
- package/src/index.ts +1 -0
- package/src/v1/acp-v1-bridge-protocol.ts +15 -0
- package/src/v1/acp-v1-harness.ts +245 -0
- package/src/v1/acp-v1-settings.ts +22 -0
- package/src/v1/bridge/acp-v1-bridge-environment.ts +6 -0
- package/src/v1/bridge/create-emit-stream-event.ts +6 -0
- package/src/v1/bridge/host-tool-correlation.ts +34 -0
- package/src/v1/bridge/index.ts +97 -3
- package/src/v1/bridge/stream-translator.ts +6 -1
- package/src/v1/index.ts +1 -0
package/src/v1/bridge/index.ts
CHANGED
|
@@ -104,6 +104,13 @@ let coldRestorationMethod: ACPSessionRestorationMethod | undefined;
|
|
|
104
104
|
let activePermissionController:
|
|
105
105
|
| ReturnType<typeof createACPPermissionController>
|
|
106
106
|
| undefined;
|
|
107
|
+
let activeQuestionRequest:
|
|
108
|
+
| {
|
|
109
|
+
method: string;
|
|
110
|
+
turn: BridgeTurn;
|
|
111
|
+
emitStreamEvent: ReturnType<typeof createEmitStreamEvent>;
|
|
112
|
+
}
|
|
113
|
+
| undefined;
|
|
107
114
|
|
|
108
115
|
await runBridge<StartMessage>({
|
|
109
116
|
bridgeType,
|
|
@@ -252,15 +259,36 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
252
259
|
const emitStreamEvent = createEmitStreamEvent({
|
|
253
260
|
emit: event => turn.emit(event as BridgeEvent),
|
|
254
261
|
emitToolCallCandidate: ({ toolCall }) => {
|
|
262
|
+
const requestId = crypto.randomUUID();
|
|
255
263
|
turn.emit({
|
|
256
264
|
type: 'acp-tool-call-candidate',
|
|
265
|
+
requestId,
|
|
257
266
|
toolCall,
|
|
258
267
|
});
|
|
268
|
+
void turn.requestToolResult(requestId).then(result => {
|
|
269
|
+
if (
|
|
270
|
+
result.output != null &&
|
|
271
|
+
typeof result.output === 'object' &&
|
|
272
|
+
'suppress' in result.output &&
|
|
273
|
+
result.output.suppress === true
|
|
274
|
+
) {
|
|
275
|
+
emitStreamEvent.suppressToolCall({
|
|
276
|
+
toolCallId: toolCall.toolCallId,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
});
|
|
259
280
|
},
|
|
260
281
|
builtinTools: start.builtinTools,
|
|
261
282
|
hostToolServerName: HOST_TOOL_MCP_SERVER_NAME,
|
|
262
283
|
hostTools: start.tools ?? [],
|
|
263
284
|
});
|
|
285
|
+
if (bridgeConfiguration.askUserQuestionsRequestMethod != null) {
|
|
286
|
+
activeQuestionRequest = {
|
|
287
|
+
method: bridgeConfiguration.askUserQuestionsRequestMethod,
|
|
288
|
+
turn,
|
|
289
|
+
emitStreamEvent,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
264
292
|
const permissionController = createACPPermissionController({
|
|
265
293
|
turn,
|
|
266
294
|
sessionId: activeSession.sessionId,
|
|
@@ -353,6 +381,9 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
353
381
|
if (emitStreamEvent.message({ message })) return;
|
|
354
382
|
}
|
|
355
383
|
} finally {
|
|
384
|
+
if (activeQuestionRequest?.turn === turn) {
|
|
385
|
+
activeQuestionRequest = undefined;
|
|
386
|
+
}
|
|
356
387
|
permissionController.cancelAll();
|
|
357
388
|
activePermissionController = undefined;
|
|
358
389
|
activeHostToolRelay.unbindTurn({ turn: relayTurn });
|
|
@@ -458,7 +489,7 @@ async function ensureSession({
|
|
|
458
489
|
stream: acp.ndJsonStream(input, output),
|
|
459
490
|
});
|
|
460
491
|
streamCapture = capturedStream.capture;
|
|
461
|
-
|
|
492
|
+
let client = acp
|
|
462
493
|
.client({ name: clientApp.name })
|
|
463
494
|
.onRequest(
|
|
464
495
|
acp.methods.client.session.requestPermission,
|
|
@@ -475,8 +506,58 @@ async function ensureSession({
|
|
|
475
506
|
notification: params,
|
|
476
507
|
update: params.update,
|
|
477
508
|
});
|
|
478
|
-
})
|
|
479
|
-
|
|
509
|
+
});
|
|
510
|
+
if (bridgeConfiguration.askUserQuestionsRequestMethod != null) {
|
|
511
|
+
const method = bridgeConfiguration.askUserQuestionsRequestMethod;
|
|
512
|
+
client = client.onRequest<unknown, unknown>(
|
|
513
|
+
method,
|
|
514
|
+
value => value,
|
|
515
|
+
async ({ params }) => {
|
|
516
|
+
const active = activeQuestionRequest;
|
|
517
|
+
if (active == null || active.method !== method) {
|
|
518
|
+
throw acp.RequestError.methodNotFound(method);
|
|
519
|
+
}
|
|
520
|
+
const requestId = crypto.randomUUID();
|
|
521
|
+
const nativeToolCallId = getNativeQuestionToolCallId({ params });
|
|
522
|
+
active.turn.emit({
|
|
523
|
+
type: 'acp-question-request',
|
|
524
|
+
requestId,
|
|
525
|
+
nativeRequest: params,
|
|
526
|
+
...(nativeToolCallId == null
|
|
527
|
+
? {}
|
|
528
|
+
: {
|
|
529
|
+
nativeToolCall:
|
|
530
|
+
active.emitStreamEvent.getToolCall({
|
|
531
|
+
toolCallId: nativeToolCallId,
|
|
532
|
+
}) ?? undefined,
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
const result = await active.turn.requestToolResult(requestId);
|
|
536
|
+
const classification = result.output as
|
|
537
|
+
| { type: 'unhandled' }
|
|
538
|
+
| { type: 'handled'; toolCallId: string }
|
|
539
|
+
| undefined;
|
|
540
|
+
if (classification?.type !== 'handled') {
|
|
541
|
+
throw acp.RequestError.methodNotFound(method);
|
|
542
|
+
}
|
|
543
|
+
active.emitStreamEvent.suppressToolCall({
|
|
544
|
+
toolCallId: nativeToolCallId ?? classification.toolCallId,
|
|
545
|
+
});
|
|
546
|
+
try {
|
|
547
|
+
const nativeResult = await active.turn.requestToolResult(
|
|
548
|
+
classification.toolCallId,
|
|
549
|
+
);
|
|
550
|
+
return nativeResult.output;
|
|
551
|
+
} finally {
|
|
552
|
+
active.turn.emit({
|
|
553
|
+
type: 'acp-question-resolved',
|
|
554
|
+
requestId,
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
connection = client.connect(capturedStream.stream);
|
|
480
561
|
|
|
481
562
|
const initializeRequest = createACPInitializeRequest({
|
|
482
563
|
protocolVersion: acp.PROTOCOL_VERSION,
|
|
@@ -627,6 +708,19 @@ async function ensureSession({
|
|
|
627
708
|
return { initialHostToolCatalogRefreshRequired: tools.length > 0 };
|
|
628
709
|
}
|
|
629
710
|
|
|
711
|
+
function getNativeQuestionToolCallId({
|
|
712
|
+
params,
|
|
713
|
+
}: {
|
|
714
|
+
params: unknown;
|
|
715
|
+
}): string | undefined {
|
|
716
|
+
if (!isRecord(params)) return undefined;
|
|
717
|
+
if (typeof params.toolCallId === 'string') return params.toolCallId;
|
|
718
|
+
const nestedParams = params.params;
|
|
719
|
+
return isRecord(nestedParams) && typeof nestedParams.toolCallId === 'string'
|
|
720
|
+
? nestedParams.toolCallId
|
|
721
|
+
: undefined;
|
|
722
|
+
}
|
|
723
|
+
|
|
630
724
|
function createExternalMcpServers({
|
|
631
725
|
mcpServers,
|
|
632
726
|
initialization,
|
|
@@ -68,6 +68,7 @@ export function createACPStreamTranslator({
|
|
|
68
68
|
output: unknown;
|
|
69
69
|
isError?: boolean;
|
|
70
70
|
}) => void;
|
|
71
|
+
getToolCall: (options: { toolCallId: string }) => ACPToolCall | undefined;
|
|
71
72
|
} {
|
|
72
73
|
let openBlock:
|
|
73
74
|
| {
|
|
@@ -215,6 +216,7 @@ export function createACPStreamTranslator({
|
|
|
215
216
|
builtinTools,
|
|
216
217
|
builtinToolsByName,
|
|
217
218
|
});
|
|
219
|
+
emitToolCallCandidate?.({ toolCall: createACPToolCall({ state }) });
|
|
218
220
|
if (
|
|
219
221
|
!forceEmit &&
|
|
220
222
|
builtin?.inputSchema != null &&
|
|
@@ -238,7 +240,6 @@ export function createACPStreamTranslator({
|
|
|
238
240
|
programmaticName,
|
|
239
241
|
toolCallId: state.toolCallId,
|
|
240
242
|
});
|
|
241
|
-
emitToolCallCandidate?.({ toolCall: createACPToolCall({ state }) });
|
|
242
243
|
}
|
|
243
244
|
emit({
|
|
244
245
|
type: 'tool-call',
|
|
@@ -381,6 +382,10 @@ export function createACPStreamTranslator({
|
|
|
381
382
|
close: closeBlock,
|
|
382
383
|
hostToolCall,
|
|
383
384
|
hostToolResult,
|
|
385
|
+
getToolCall: ({ toolCallId }) => {
|
|
386
|
+
const state = toolStates.get(toolCallId);
|
|
387
|
+
return state == null ? undefined : createACPToolCall({ state });
|
|
388
|
+
},
|
|
384
389
|
finish: response => {
|
|
385
390
|
if (finished) return;
|
|
386
391
|
finished = true;
|