@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
3
11
|
## 1.0.38
|
|
4
12
|
|
|
5
13
|
### 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.
|
|
15
|
+
var VERSION = true ? "1.0.39" : "0.0.0-test";
|
|
16
16
|
function createHostToolMCPServer({
|
|
17
17
|
tools: tools2,
|
|
18
18
|
revision = 1,
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -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: (
|
|
413
|
-
|
|
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
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
-
|
|
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
|
-
})
|
|
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
|