@ai-sdk/harness-acp 1.0.10 → 1.0.12
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 +15 -0
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +96 -21
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +70 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/acp-harness.ts +1 -0
- package/src/index.ts +1 -0
- package/src/v1/acp-v1-bridge-protocol.ts +19 -0
- package/src/v1/acp-v1-harness.ts +57 -0
- package/src/v1/acp-v1-settings.ts +10 -0
- package/src/v1/acp-v1-turn-start-config.ts +21 -0
- package/src/v1/bridge/index.ts +82 -1
- package/src/v1/bridge/recovered-session.ts +25 -0
- package/src/v1/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @ai-sdk/harness-acp
|
|
2
2
|
|
|
3
|
+
## 1.0.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @ai-sdk/harness@1.0.74
|
|
8
|
+
|
|
9
|
+
## 1.0.11
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 62a9c2a: feat(harness): add support for structured output to `HarnessAgent` via `output` property
|
|
14
|
+
- Updated dependencies [62a9c2a]
|
|
15
|
+
- Updated dependencies [d25cae2]
|
|
16
|
+
- @ai-sdk/harness@1.0.73
|
|
17
|
+
|
|
3
18
|
## 1.0.10
|
|
4
19
|
|
|
5
20
|
### 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.12" : "0.0.0-test";
|
|
16
16
|
function createHostToolMCPServer({
|
|
17
17
|
tools: tools2,
|
|
18
18
|
revision = 1,
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -69,7 +69,6 @@ async function runBridge(options) {
|
|
|
69
69
|
let currentBoundPort = 0;
|
|
70
70
|
let currentTurnState = "init";
|
|
71
71
|
let activeSocket;
|
|
72
|
-
let activeSocketReadyForLiveEvents = false;
|
|
73
72
|
let isFirstTurn = true;
|
|
74
73
|
let turnAbort;
|
|
75
74
|
let currentUserMessages;
|
|
@@ -153,14 +152,6 @@ async function runBridge(options) {
|
|
|
153
152
|
} catch {
|
|
154
153
|
}
|
|
155
154
|
};
|
|
156
|
-
const sendControl = (msg) => {
|
|
157
|
-
if (activeSocket?.readyState === WS_OPEN) {
|
|
158
|
-
try {
|
|
159
|
-
activeSocket.send(JSON.stringify(msg));
|
|
160
|
-
} catch {
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
155
|
const emit = (event) => {
|
|
165
156
|
const seq = ++seqCounter;
|
|
166
157
|
const line = JSON.stringify({ ...event, seq });
|
|
@@ -168,7 +159,7 @@ async function runBridge(options) {
|
|
|
168
159
|
diskBuffer += `${line}
|
|
169
160
|
`;
|
|
170
161
|
scheduleEventFlush();
|
|
171
|
-
if (
|
|
162
|
+
if (activeSocket?.readyState === WS_OPEN) {
|
|
172
163
|
try {
|
|
173
164
|
activeSocket.send(line);
|
|
174
165
|
} catch {
|
|
@@ -271,8 +262,7 @@ async function runBridge(options) {
|
|
|
271
262
|
const handleInbound = async (msg, ws) => {
|
|
272
263
|
switch (msg.type) {
|
|
273
264
|
case "start": {
|
|
274
|
-
|
|
275
|
-
activeSocketReadyForLiveEvents = true;
|
|
265
|
+
activeSocket = ws;
|
|
276
266
|
const firstTurn = isFirstTurn;
|
|
277
267
|
isFirstTurn = false;
|
|
278
268
|
eventLog = [];
|
|
@@ -352,9 +342,8 @@ async function runBridge(options) {
|
|
|
352
342
|
turnAbort?.abort();
|
|
353
343
|
return;
|
|
354
344
|
case "resume":
|
|
355
|
-
|
|
345
|
+
activeSocket = ws;
|
|
356
346
|
replay(ws, msg.lastSeenEventId);
|
|
357
|
-
activeSocketReadyForLiveEvents = true;
|
|
358
347
|
return;
|
|
359
348
|
case "destroy":
|
|
360
349
|
currentTurnState = "done";
|
|
@@ -366,7 +355,7 @@ async function runBridge(options) {
|
|
|
366
355
|
currentTurnState = "done";
|
|
367
356
|
void writeBridgeMeta("done");
|
|
368
357
|
const data = await onStop?.() ?? {};
|
|
369
|
-
sendControl({ type: "bridge-stop", data });
|
|
358
|
+
sendControl(ws, { type: "bridge-stop", data });
|
|
370
359
|
drainThenExit(ws, 1e3, "stop");
|
|
371
360
|
return;
|
|
372
361
|
}
|
|
@@ -419,9 +408,7 @@ async function runBridge(options) {
|
|
|
419
408
|
ws.close(1008, "unauthorized");
|
|
420
409
|
return;
|
|
421
410
|
}
|
|
422
|
-
|
|
423
|
-
activeSocketReadyForLiveEvents = false;
|
|
424
|
-
sendControl({
|
|
411
|
+
sendControl(ws, {
|
|
425
412
|
type: "bridge-hello",
|
|
426
413
|
state: currentTurnState,
|
|
427
414
|
lastSeq: seqCounter
|
|
@@ -432,7 +419,7 @@ async function runBridge(options) {
|
|
|
432
419
|
const text = typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
|
|
433
420
|
parsed = JSON.parse(text);
|
|
434
421
|
} catch (err) {
|
|
435
|
-
sendControl({
|
|
422
|
+
sendControl(ws, {
|
|
436
423
|
type: "error",
|
|
437
424
|
error: `protocol parse error: ${err.message}`
|
|
438
425
|
});
|
|
@@ -443,7 +430,6 @@ async function runBridge(options) {
|
|
|
443
430
|
ws.on("close", () => {
|
|
444
431
|
if (activeSocket === ws) {
|
|
445
432
|
activeSocket = void 0;
|
|
446
|
-
activeSocketReadyForLiveEvents = false;
|
|
447
433
|
}
|
|
448
434
|
});
|
|
449
435
|
ws.on("error", () => {
|
|
@@ -470,6 +456,14 @@ async function runBridge(options) {
|
|
|
470
456
|
})
|
|
471
457
|
};
|
|
472
458
|
}
|
|
459
|
+
function sendControl(socket, message) {
|
|
460
|
+
if (socket?.readyState === WS_OPEN) {
|
|
461
|
+
try {
|
|
462
|
+
socket.send(JSON.stringify(message));
|
|
463
|
+
} catch {
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
473
467
|
function serialiseError(err) {
|
|
474
468
|
if (err instanceof Error) {
|
|
475
469
|
return { name: err.name, message: err.message, stack: err.stack };
|
|
@@ -2740,6 +2734,27 @@ function createACPRecoveredSession({
|
|
|
2740
2734
|
);
|
|
2741
2735
|
return response;
|
|
2742
2736
|
},
|
|
2737
|
+
promptWithMeta: async ({ prompt, meta }) => {
|
|
2738
|
+
if (disposed) {
|
|
2739
|
+
throw new Error("Recovered ACP session is disposed.");
|
|
2740
|
+
}
|
|
2741
|
+
updates.clearErrors();
|
|
2742
|
+
const response = agent.request(
|
|
2743
|
+
acp2.methods.agent.session.prompt,
|
|
2744
|
+
{ sessionId, prompt, _meta: meta }
|
|
2745
|
+
);
|
|
2746
|
+
void response.then(
|
|
2747
|
+
(value) => {
|
|
2748
|
+
updates.enqueue({
|
|
2749
|
+
kind: "stop",
|
|
2750
|
+
response: value,
|
|
2751
|
+
stopReason: value.stopReason
|
|
2752
|
+
});
|
|
2753
|
+
},
|
|
2754
|
+
(error) => updates.reject(error)
|
|
2755
|
+
);
|
|
2756
|
+
return response;
|
|
2757
|
+
},
|
|
2743
2758
|
nextUpdate: () => updates.next(),
|
|
2744
2759
|
dispose: () => {
|
|
2745
2760
|
if (disposed) return;
|
|
@@ -3041,7 +3056,13 @@ async function runTurn(start, turn) {
|
|
|
3041
3056
|
};
|
|
3042
3057
|
hostToolRelay?.bindTurn({ turn: relayTurn });
|
|
3043
3058
|
try {
|
|
3044
|
-
|
|
3059
|
+
const promptMeta = createOutputSchemaPromptMeta({ start });
|
|
3060
|
+
void promptActiveSession({
|
|
3061
|
+
session: activeSession,
|
|
3062
|
+
agent: connection.agent,
|
|
3063
|
+
prompt: start.prompt,
|
|
3064
|
+
meta: promptMeta
|
|
3065
|
+
});
|
|
3045
3066
|
if (turn.abortSignal.aborted) {
|
|
3046
3067
|
await cancel();
|
|
3047
3068
|
} else {
|
|
@@ -3428,6 +3449,60 @@ function createChildEnvironment({
|
|
|
3428
3449
|
function isRecord7(value) {
|
|
3429
3450
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
3430
3451
|
}
|
|
3452
|
+
function createOutputSchemaPromptMeta({
|
|
3453
|
+
start
|
|
3454
|
+
}) {
|
|
3455
|
+
if (start.responseFormat?.type !== "json" || start.responseFormat.schema == null || start.outputSchemaMapping?.type !== "session-prompt-meta") {
|
|
3456
|
+
return void 0;
|
|
3457
|
+
}
|
|
3458
|
+
const root = {};
|
|
3459
|
+
let target = root;
|
|
3460
|
+
const path = start.outputSchemaMapping.path;
|
|
3461
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
3462
|
+
const child2 = {};
|
|
3463
|
+
target[path[index]] = child2;
|
|
3464
|
+
target = child2;
|
|
3465
|
+
}
|
|
3466
|
+
target[path[path.length - 1]] = start.responseFormat.schema;
|
|
3467
|
+
return root;
|
|
3468
|
+
}
|
|
3469
|
+
function promptActiveSession({
|
|
3470
|
+
session: session2,
|
|
3471
|
+
agent,
|
|
3472
|
+
prompt,
|
|
3473
|
+
meta
|
|
3474
|
+
}) {
|
|
3475
|
+
if (meta == null) return session2.prompt(prompt);
|
|
3476
|
+
if (session2.promptWithMeta != null) {
|
|
3477
|
+
return session2.promptWithMeta({ prompt, meta });
|
|
3478
|
+
}
|
|
3479
|
+
const updates = session2.updates;
|
|
3480
|
+
if (updates == null) {
|
|
3481
|
+
throw new Error(
|
|
3482
|
+
"The installed ACP SDK cannot send session prompt metadata while preserving streamed updates."
|
|
3483
|
+
);
|
|
3484
|
+
}
|
|
3485
|
+
updates.clearErrors();
|
|
3486
|
+
const response = agent.request(
|
|
3487
|
+
acp4.methods.agent.session.prompt,
|
|
3488
|
+
{
|
|
3489
|
+
sessionId: session2.sessionId,
|
|
3490
|
+
prompt,
|
|
3491
|
+
_meta: meta
|
|
3492
|
+
}
|
|
3493
|
+
);
|
|
3494
|
+
void response.then(
|
|
3495
|
+
(value) => {
|
|
3496
|
+
updates.enqueue({
|
|
3497
|
+
kind: "stop",
|
|
3498
|
+
response: value,
|
|
3499
|
+
stopReason: value.stopReason
|
|
3500
|
+
});
|
|
3501
|
+
},
|
|
3502
|
+
(error) => updates.reject(error)
|
|
3503
|
+
);
|
|
3504
|
+
return response;
|
|
3505
|
+
}
|
|
3431
3506
|
async function readImplementationDescriptor({
|
|
3432
3507
|
path
|
|
3433
3508
|
}) {
|