@wrongstack/acp 0.306.4 → 0.307.0
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/agent/protocol-handler.d.ts +3 -49
- package/dist/agent/protocol-session-management.d.ts +36 -0
- package/dist/agent/protocol-session-ops.d.ts +59 -0
- package/dist/agent.js +430 -517
- package/dist/client/acp-session-ops.d.ts +33 -0
- package/dist/client/acp-session.d.ts +1 -98
- package/dist/client.js +242 -300
- package/dist/index.js +677 -822
- package/dist/wrongstack-acp-agent.js +430 -517
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -1402,6 +1402,220 @@ function isBestEffortAckMethod(method) {
|
|
|
1402
1402
|
return method === "mcp/connect" || method === "mcp/message" || method === "mcp/disconnect" || method === "elicitation/create" || method === "elicitation/complete";
|
|
1403
1403
|
}
|
|
1404
1404
|
|
|
1405
|
+
// src/client/acp-session-ops.ts
|
|
1406
|
+
function filterMcpServers(agentCapabilities, servers) {
|
|
1407
|
+
if (!servers || servers.length === 0) return [];
|
|
1408
|
+
const mcpCaps = agentCapabilities.mcpCapabilities ?? {};
|
|
1409
|
+
return servers.filter((s) => {
|
|
1410
|
+
if ("type" in s && s.type === "http") return mcpCaps.http === true;
|
|
1411
|
+
if ("type" in s && s.type === "sse") return mcpCaps.sse === true;
|
|
1412
|
+
return true;
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
async function executeLoadSession(ctx, sessionId, mcpServers, cwd) {
|
|
1416
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1417
|
+
if (!ctx.agentCapabilities.loadSession) {
|
|
1418
|
+
throw new ACPSessionError(
|
|
1419
|
+
"unsupported_capability",
|
|
1420
|
+
"agent does not support session/load (loadSession capability not advertised)"
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
if (ctx.sessionId) {
|
|
1424
|
+
await ctx.closeSession();
|
|
1425
|
+
}
|
|
1426
|
+
ctx.resetScratch();
|
|
1427
|
+
const servers = filterMcpServers(ctx.agentCapabilities, mcpServers ?? ctx.opts.mcpServers);
|
|
1428
|
+
const id = ctx.allocId();
|
|
1429
|
+
const result = await ctx.sendRequest(id, "session/load", {
|
|
1430
|
+
sessionId,
|
|
1431
|
+
cwd: cwd ?? ctx.opts.cwd ?? ctx.opts.projectRoot,
|
|
1432
|
+
mcpServers: servers
|
|
1433
|
+
});
|
|
1434
|
+
if (isJsonRpcError(result)) {
|
|
1435
|
+
throw new ACPSessionError("prompt_failed", `session/load failed: ${result.message}`, result);
|
|
1436
|
+
}
|
|
1437
|
+
ctx.setSessionId(sessionId);
|
|
1438
|
+
}
|
|
1439
|
+
async function executeResumeSession(ctx, sessionId, mcpServers, cwd) {
|
|
1440
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1441
|
+
if (!ctx.agentCapabilities.sessionCapabilities?.resume) {
|
|
1442
|
+
throw new ACPSessionError(
|
|
1443
|
+
"unsupported_capability",
|
|
1444
|
+
"agent does not support session/resume (sessionCapabilities.resume not advertised)"
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
if (ctx.sessionId) {
|
|
1448
|
+
await ctx.closeSession();
|
|
1449
|
+
}
|
|
1450
|
+
const servers = filterMcpServers(ctx.agentCapabilities, mcpServers ?? ctx.opts.mcpServers);
|
|
1451
|
+
const id = ctx.allocId();
|
|
1452
|
+
const result = await ctx.sendRequest(id, "session/resume", {
|
|
1453
|
+
sessionId,
|
|
1454
|
+
cwd: cwd ?? ctx.opts.cwd ?? ctx.opts.projectRoot,
|
|
1455
|
+
mcpServers: servers
|
|
1456
|
+
});
|
|
1457
|
+
if (isJsonRpcError(result)) {
|
|
1458
|
+
throw new ACPSessionError(
|
|
1459
|
+
"prompt_failed",
|
|
1460
|
+
`session/resume failed: ${result.message}`,
|
|
1461
|
+
result
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
ctx.setSessionId(sessionId);
|
|
1465
|
+
}
|
|
1466
|
+
async function executeListSessions(ctx, cursor, cwd) {
|
|
1467
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1468
|
+
if (!ctx.agentCapabilities.sessionCapabilities?.list) {
|
|
1469
|
+
throw new ACPSessionError(
|
|
1470
|
+
"unsupported_capability",
|
|
1471
|
+
"agent does not support session/list (sessionCapabilities.list not advertised)"
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
const id = ctx.allocId();
|
|
1475
|
+
const params = {};
|
|
1476
|
+
if (cursor !== void 0) params.cursor = cursor;
|
|
1477
|
+
if (cwd !== void 0) params.cwd = cwd;
|
|
1478
|
+
const result = await ctx.sendRequest(id, "session/list", params);
|
|
1479
|
+
if (isJsonRpcError(result)) {
|
|
1480
|
+
throw new ACPSessionError("prompt_failed", `session/list failed: ${result.message}`, result);
|
|
1481
|
+
}
|
|
1482
|
+
const r = result;
|
|
1483
|
+
return {
|
|
1484
|
+
sessions: r.sessions ?? [],
|
|
1485
|
+
nextCursor: r.nextCursor
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
async function executeDeleteSession(ctx, sessionId) {
|
|
1489
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1490
|
+
if (!ctx.agentCapabilities.sessionCapabilities?.delete) {
|
|
1491
|
+
throw new ACPSessionError(
|
|
1492
|
+
"unsupported_capability",
|
|
1493
|
+
"agent does not support session/delete (sessionCapabilities.delete not advertised)"
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
const id = ctx.allocId();
|
|
1497
|
+
const result = await ctx.sendRequest(id, "session/delete", { sessionId });
|
|
1498
|
+
if (isJsonRpcError(result)) {
|
|
1499
|
+
throw new ACPSessionError(
|
|
1500
|
+
"prompt_failed",
|
|
1501
|
+
`session/delete failed: ${result.message}`,
|
|
1502
|
+
result
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
if (ctx.sessionId === sessionId) {
|
|
1506
|
+
ctx.setSessionId(null);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
async function executeForkSession(ctx, sourceSessionId, cwd, mcpServers) {
|
|
1510
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1511
|
+
const servers = filterMcpServers(ctx.agentCapabilities, mcpServers ?? ctx.opts.mcpServers);
|
|
1512
|
+
const id = ctx.allocId();
|
|
1513
|
+
const result = await ctx.sendRequest(id, "session/fork", {
|
|
1514
|
+
sessionId: sourceSessionId,
|
|
1515
|
+
cwd: cwd ?? ctx.opts.cwd ?? ctx.opts.projectRoot,
|
|
1516
|
+
...servers.length > 0 ? { mcpServers: servers } : {}
|
|
1517
|
+
});
|
|
1518
|
+
if (isJsonRpcError(result)) {
|
|
1519
|
+
throw new ACPSessionError("prompt_failed", `session/fork failed: ${result.message}`, result);
|
|
1520
|
+
}
|
|
1521
|
+
const newId = result.sessionId;
|
|
1522
|
+
if (typeof newId !== "string" || !newId) {
|
|
1523
|
+
throw new ACPSessionError("protocol_error", "session/fork returned no sessionId", result);
|
|
1524
|
+
}
|
|
1525
|
+
return newId;
|
|
1526
|
+
}
|
|
1527
|
+
async function executeSetMode(ctx, sessionId, modeId) {
|
|
1528
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1529
|
+
const id = ctx.allocId();
|
|
1530
|
+
const result = await ctx.sendRequest(id, "session/set_mode", { sessionId, modeId });
|
|
1531
|
+
if (isJsonRpcError(result)) {
|
|
1532
|
+
throw new ACPSessionError(
|
|
1533
|
+
"prompt_failed",
|
|
1534
|
+
`session/set_mode failed: ${result.message}`,
|
|
1535
|
+
result
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
async function executeSetConfigOption(ctx, sessionId, configId, value) {
|
|
1540
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1541
|
+
const id = ctx.allocId();
|
|
1542
|
+
const result = await ctx.sendRequest(id, "session/set_config_option", {
|
|
1543
|
+
sessionId,
|
|
1544
|
+
configId,
|
|
1545
|
+
value
|
|
1546
|
+
});
|
|
1547
|
+
if (isJsonRpcError(result)) {
|
|
1548
|
+
throw new ACPSessionError(
|
|
1549
|
+
"prompt_failed",
|
|
1550
|
+
`session/set_config_option failed: ${result.message}`,
|
|
1551
|
+
result
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
async function executeListProviders(ctx) {
|
|
1556
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1557
|
+
const id = ctx.allocId();
|
|
1558
|
+
const result = await ctx.sendRequest(id, "providers/list", {});
|
|
1559
|
+
if (isJsonRpcError(result)) {
|
|
1560
|
+
throw new ACPSessionError(
|
|
1561
|
+
"prompt_failed",
|
|
1562
|
+
`providers/list failed: ${result.message}`,
|
|
1563
|
+
result
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
const r = result;
|
|
1567
|
+
return { providers: r.providers ?? [], currentProviderId: r.currentProviderId ?? null };
|
|
1568
|
+
}
|
|
1569
|
+
async function executeSetProvider(ctx, providerId, config) {
|
|
1570
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1571
|
+
const id = ctx.allocId();
|
|
1572
|
+
const result = await ctx.sendRequest(id, "providers/set", { providerId, ...config ?? {} });
|
|
1573
|
+
if (isJsonRpcError(result)) {
|
|
1574
|
+
throw new ACPSessionError("prompt_failed", `providers/set failed: ${result.message}`, result);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
async function executeDisableProvider(ctx) {
|
|
1578
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1579
|
+
const id = ctx.allocId();
|
|
1580
|
+
const result = await ctx.sendRequest(id, "providers/disable", {});
|
|
1581
|
+
if (isJsonRpcError(result)) {
|
|
1582
|
+
throw new ACPSessionError(
|
|
1583
|
+
"prompt_failed",
|
|
1584
|
+
`providers/disable failed: ${result.message}`,
|
|
1585
|
+
result
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
async function executeMcpMessage(ctx, connectionId, message) {
|
|
1590
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1591
|
+
const id = ctx.allocId();
|
|
1592
|
+
const result = await ctx.sendRequest(id, "mcp/message", { connectionId, message });
|
|
1593
|
+
if (isJsonRpcError(result)) {
|
|
1594
|
+
throw new ACPSessionError("prompt_failed", `mcp/message failed: ${result.message}`, result);
|
|
1595
|
+
}
|
|
1596
|
+
return result;
|
|
1597
|
+
}
|
|
1598
|
+
async function executeCreateSession(ctx) {
|
|
1599
|
+
const servers = filterMcpServers(ctx.agentCapabilities, ctx.opts.mcpServers);
|
|
1600
|
+
const id = ctx.allocId();
|
|
1601
|
+
const result = await ctx.sendRequest(id, "session/new", {
|
|
1602
|
+
cwd: ctx.opts.cwd ?? ctx.opts.projectRoot,
|
|
1603
|
+
mcpServers: servers
|
|
1604
|
+
});
|
|
1605
|
+
if (isJsonRpcError(result)) {
|
|
1606
|
+
throw new ACPSessionError(
|
|
1607
|
+
"session_create_failed",
|
|
1608
|
+
`session/new failed: ${result.message}`,
|
|
1609
|
+
result
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
const sessionId = result.sessionId;
|
|
1613
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
1614
|
+
throw new ACPSessionError("protocol_error", "session/new returned no sessionId", result);
|
|
1615
|
+
}
|
|
1616
|
+
return sessionId;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1405
1619
|
// src/client/acp-session.ts
|
|
1406
1620
|
var ACPSession = class _ACPSession {
|
|
1407
1621
|
transport;
|
|
@@ -1590,9 +1804,6 @@ var ACPSession = class _ACPSession {
|
|
|
1590
1804
|
/**
|
|
1591
1805
|
* Authenticate with the agent using one of the advertised auth methods.
|
|
1592
1806
|
* Call this AFTER start() and BEFORE any session/new call.
|
|
1593
|
-
*
|
|
1594
|
-
* Throws ACPSessionError('auth_failed') if the agent rejects the
|
|
1595
|
-
* authentication or if the methodId is not in the advertised list.
|
|
1596
1807
|
*/
|
|
1597
1808
|
async authenticate(methodId) {
|
|
1598
1809
|
if (this.state === "closed") {
|
|
@@ -1639,268 +1850,59 @@ var ACPSession = class _ACPSession {
|
|
|
1639
1850
|
this.state = "ready";
|
|
1640
1851
|
}
|
|
1641
1852
|
// ──────────────────────────────────────────────────────────────────────
|
|
1642
|
-
// Session management
|
|
1853
|
+
// Session management delegation
|
|
1643
1854
|
// ──────────────────────────────────────────────────────────────────────
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1855
|
+
opContext() {
|
|
1856
|
+
return {
|
|
1857
|
+
closed: this.closed,
|
|
1858
|
+
sessionId: this.sessionId,
|
|
1859
|
+
agentCapabilities: this.agentCapabilities,
|
|
1860
|
+
opts: this.opts,
|
|
1861
|
+
allocId: () => this.allocId(),
|
|
1862
|
+
sendRequest: (id, method, params, timeoutMs) => this.sendRequest(id, method, params, timeoutMs),
|
|
1863
|
+
setSessionId: (id) => {
|
|
1864
|
+
this.sessionId = id;
|
|
1865
|
+
},
|
|
1866
|
+
resetScratch: () => this.resetScratch(),
|
|
1867
|
+
closeSession: () => this.closeSession()
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1654
1870
|
async loadSession(sessionId, mcpServers, cwd) {
|
|
1655
|
-
|
|
1656
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
1657
|
-
}
|
|
1658
|
-
if (!this.agentCapabilities.loadSession) {
|
|
1659
|
-
throw new ACPSessionError(
|
|
1660
|
-
"unsupported_capability",
|
|
1661
|
-
"agent does not support session/load (loadSession capability not advertised)"
|
|
1662
|
-
);
|
|
1663
|
-
}
|
|
1664
|
-
if (this.sessionId) {
|
|
1665
|
-
await this.closeSession();
|
|
1666
|
-
}
|
|
1667
|
-
this.resetScratch();
|
|
1668
|
-
const servers = this.filterMcpServers(mcpServers ?? this.opts.mcpServers);
|
|
1669
|
-
const id = this.allocId();
|
|
1670
|
-
const result = await this.sendRequest(id, "session/load", {
|
|
1671
|
-
sessionId,
|
|
1672
|
-
cwd: cwd ?? this.opts.cwd ?? this.opts.projectRoot,
|
|
1673
|
-
mcpServers: servers
|
|
1674
|
-
});
|
|
1675
|
-
if (isJsonRpcError(result)) {
|
|
1676
|
-
throw new ACPSessionError("prompt_failed", `session/load failed: ${result.message}`, result);
|
|
1677
|
-
}
|
|
1678
|
-
this.sessionId = sessionId;
|
|
1871
|
+
return executeLoadSession(this.opContext(), sessionId, mcpServers, cwd);
|
|
1679
1872
|
}
|
|
1680
|
-
/**
|
|
1681
|
-
* Resume an existing session without replaying history.
|
|
1682
|
-
*
|
|
1683
|
-
* Only works if the agent advertises `sessionCapabilities.resume`.
|
|
1684
|
-
*
|
|
1685
|
-
* @param sessionId - The session to resume
|
|
1686
|
-
* @param mcpServers - Optional MCP servers (defaults to options.mcpServers)
|
|
1687
|
-
* @param cwd - Optional working directory (defaults to options.cwd or projectRoot)
|
|
1688
|
-
*/
|
|
1689
1873
|
async resumeSession(sessionId, mcpServers, cwd) {
|
|
1690
|
-
|
|
1691
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
1692
|
-
}
|
|
1693
|
-
if (!this.agentCapabilities.sessionCapabilities?.resume) {
|
|
1694
|
-
throw new ACPSessionError(
|
|
1695
|
-
"unsupported_capability",
|
|
1696
|
-
"agent does not support session/resume (sessionCapabilities.resume not advertised)"
|
|
1697
|
-
);
|
|
1698
|
-
}
|
|
1699
|
-
if (this.sessionId) {
|
|
1700
|
-
await this.closeSession();
|
|
1701
|
-
}
|
|
1702
|
-
const servers = this.filterMcpServers(mcpServers ?? this.opts.mcpServers);
|
|
1703
|
-
const id = this.allocId();
|
|
1704
|
-
const result = await this.sendRequest(id, "session/resume", {
|
|
1705
|
-
sessionId,
|
|
1706
|
-
cwd: cwd ?? this.opts.cwd ?? this.opts.projectRoot,
|
|
1707
|
-
mcpServers: servers
|
|
1708
|
-
});
|
|
1709
|
-
if (isJsonRpcError(result)) {
|
|
1710
|
-
throw new ACPSessionError(
|
|
1711
|
-
"prompt_failed",
|
|
1712
|
-
`session/resume failed: ${result.message}`,
|
|
1713
|
-
result
|
|
1714
|
-
);
|
|
1715
|
-
}
|
|
1716
|
-
this.sessionId = sessionId;
|
|
1874
|
+
return executeResumeSession(this.opContext(), sessionId, mcpServers, cwd);
|
|
1717
1875
|
}
|
|
1718
|
-
/**
|
|
1719
|
-
* List existing sessions known to the agent.
|
|
1720
|
-
*
|
|
1721
|
-
* Only works if the agent advertises `sessionCapabilities.list`.
|
|
1722
|
-
*/
|
|
1723
1876
|
async listSessions(cursor, cwd) {
|
|
1724
|
-
|
|
1725
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
1726
|
-
}
|
|
1727
|
-
if (!this.agentCapabilities.sessionCapabilities?.list) {
|
|
1728
|
-
throw new ACPSessionError(
|
|
1729
|
-
"unsupported_capability",
|
|
1730
|
-
"agent does not support session/list (sessionCapabilities.list not advertised)"
|
|
1731
|
-
);
|
|
1732
|
-
}
|
|
1733
|
-
const id = this.allocId();
|
|
1734
|
-
const params = {};
|
|
1735
|
-
if (cursor !== void 0) params.cursor = cursor;
|
|
1736
|
-
if (cwd !== void 0) params.cwd = cwd;
|
|
1737
|
-
const result = await this.sendRequest(id, "session/list", params);
|
|
1738
|
-
if (isJsonRpcError(result)) {
|
|
1739
|
-
throw new ACPSessionError("prompt_failed", `session/list failed: ${result.message}`, result);
|
|
1740
|
-
}
|
|
1741
|
-
const r = result;
|
|
1742
|
-
return {
|
|
1743
|
-
sessions: r.sessions ?? [],
|
|
1744
|
-
nextCursor: r.nextCursor
|
|
1745
|
-
};
|
|
1877
|
+
return executeListSessions(this.opContext(), cursor, cwd);
|
|
1746
1878
|
}
|
|
1747
|
-
/**
|
|
1748
|
-
* Delete a session from the agent's session list.
|
|
1749
|
-
*
|
|
1750
|
-
* Only works if the agent advertises `sessionCapabilities.delete`.
|
|
1751
|
-
*/
|
|
1752
1879
|
async deleteSession(sessionId) {
|
|
1753
|
-
|
|
1754
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
1755
|
-
}
|
|
1756
|
-
if (!this.agentCapabilities.sessionCapabilities?.delete) {
|
|
1757
|
-
throw new ACPSessionError(
|
|
1758
|
-
"unsupported_capability",
|
|
1759
|
-
"agent does not support session/delete (sessionCapabilities.delete not advertised)"
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
|
-
const id = this.allocId();
|
|
1763
|
-
const result = await this.sendRequest(id, "session/delete", { sessionId });
|
|
1764
|
-
if (isJsonRpcError(result)) {
|
|
1765
|
-
throw new ACPSessionError(
|
|
1766
|
-
"prompt_failed",
|
|
1767
|
-
`session/delete failed: ${result.message}`,
|
|
1768
|
-
result
|
|
1769
|
-
);
|
|
1770
|
-
}
|
|
1771
|
-
if (this.sessionId === sessionId) {
|
|
1772
|
-
this.sessionId = null;
|
|
1773
|
-
}
|
|
1880
|
+
return executeDeleteSession(this.opContext(), sessionId);
|
|
1774
1881
|
}
|
|
1775
|
-
/**
|
|
1776
|
-
* Fork a session — create a new session from an existing one.
|
|
1777
|
-
*/
|
|
1778
1882
|
async forkSession(sourceSessionId, cwd, mcpServers) {
|
|
1779
|
-
|
|
1780
|
-
const servers = this.filterMcpServers(mcpServers ?? this.opts.mcpServers);
|
|
1781
|
-
const id = this.allocId();
|
|
1782
|
-
const result = await this.sendRequest(id, "session/fork", {
|
|
1783
|
-
sessionId: sourceSessionId,
|
|
1784
|
-
cwd: cwd ?? this.opts.cwd ?? this.opts.projectRoot,
|
|
1785
|
-
...servers.length > 0 ? { mcpServers: servers } : {}
|
|
1786
|
-
});
|
|
1787
|
-
if (isJsonRpcError(result)) {
|
|
1788
|
-
throw new ACPSessionError("prompt_failed", `session/fork failed: ${result.message}`, result);
|
|
1789
|
-
}
|
|
1790
|
-
const newId = result.sessionId;
|
|
1791
|
-
if (typeof newId !== "string" || !newId) {
|
|
1792
|
-
throw new ACPSessionError("protocol_error", "session/fork returned no sessionId", result);
|
|
1793
|
-
}
|
|
1794
|
-
return newId;
|
|
1883
|
+
return executeForkSession(this.opContext(), sourceSessionId, cwd, mcpServers);
|
|
1795
1884
|
}
|
|
1796
|
-
/**
|
|
1797
|
-
* Set the active mode for a session.
|
|
1798
|
-
*/
|
|
1799
1885
|
async setMode(sessionId, modeId) {
|
|
1800
|
-
|
|
1801
|
-
const id = this.allocId();
|
|
1802
|
-
const result = await this.sendRequest(id, "session/set_mode", { sessionId, modeId });
|
|
1803
|
-
if (isJsonRpcError(result)) {
|
|
1804
|
-
throw new ACPSessionError(
|
|
1805
|
-
"prompt_failed",
|
|
1806
|
-
`session/set_mode failed: ${result.message}`,
|
|
1807
|
-
result
|
|
1808
|
-
);
|
|
1809
|
-
}
|
|
1886
|
+
return executeSetMode(this.opContext(), sessionId, modeId);
|
|
1810
1887
|
}
|
|
1811
|
-
/**
|
|
1812
|
-
* Set a configuration option for a session.
|
|
1813
|
-
*/
|
|
1814
1888
|
async setConfigOption(sessionId, configId, value) {
|
|
1815
|
-
|
|
1816
|
-
const id = this.allocId();
|
|
1817
|
-
const result = await this.sendRequest(id, "session/set_config_option", {
|
|
1818
|
-
sessionId,
|
|
1819
|
-
configId,
|
|
1820
|
-
value
|
|
1821
|
-
});
|
|
1822
|
-
if (isJsonRpcError(result)) {
|
|
1823
|
-
throw new ACPSessionError(
|
|
1824
|
-
"prompt_failed",
|
|
1825
|
-
`session/set_config_option failed: ${result.message}`,
|
|
1826
|
-
result
|
|
1827
|
-
);
|
|
1828
|
-
}
|
|
1889
|
+
return executeSetConfigOption(this.opContext(), sessionId, configId, value);
|
|
1829
1890
|
}
|
|
1830
|
-
/**
|
|
1831
|
-
* List available providers and the current provider.
|
|
1832
|
-
*/
|
|
1833
1891
|
async listProviders() {
|
|
1834
|
-
|
|
1835
|
-
const id = this.allocId();
|
|
1836
|
-
const result = await this.sendRequest(id, "providers/list", {});
|
|
1837
|
-
if (isJsonRpcError(result)) {
|
|
1838
|
-
throw new ACPSessionError(
|
|
1839
|
-
"prompt_failed",
|
|
1840
|
-
`providers/list failed: ${result.message}`,
|
|
1841
|
-
result
|
|
1842
|
-
);
|
|
1843
|
-
}
|
|
1844
|
-
const r = result;
|
|
1845
|
-
return { providers: r.providers ?? [], currentProviderId: r.currentProviderId ?? null };
|
|
1892
|
+
return executeListProviders(this.opContext());
|
|
1846
1893
|
}
|
|
1847
|
-
/**
|
|
1848
|
-
* Send an MCP message to the agent for routing.
|
|
1849
|
-
*/
|
|
1850
1894
|
async mcpMessage(connectionId, message) {
|
|
1851
|
-
|
|
1852
|
-
const id = this.allocId();
|
|
1853
|
-
const result = await this.sendRequest(id, "mcp/message", { connectionId, message });
|
|
1854
|
-
if (isJsonRpcError(result)) {
|
|
1855
|
-
throw new ACPSessionError("prompt_failed", `mcp/message failed: ${result.message}`, result);
|
|
1856
|
-
}
|
|
1857
|
-
return result;
|
|
1895
|
+
return executeMcpMessage(this.opContext(), connectionId, message);
|
|
1858
1896
|
}
|
|
1859
|
-
/**
|
|
1860
|
-
* Set the active provider for the agent.
|
|
1861
|
-
*/
|
|
1862
1897
|
async setProvider(providerId, config) {
|
|
1863
|
-
|
|
1864
|
-
const id = this.allocId();
|
|
1865
|
-
const result = await this.sendRequest(id, "providers/set", { providerId, ...config ?? {} });
|
|
1866
|
-
if (isJsonRpcError(result)) {
|
|
1867
|
-
throw new ACPSessionError("prompt_failed", `providers/set failed: ${result.message}`, result);
|
|
1868
|
-
}
|
|
1898
|
+
return executeSetProvider(this.opContext(), providerId, config);
|
|
1869
1899
|
}
|
|
1870
|
-
/**
|
|
1871
|
-
* Disable the current provider.
|
|
1872
|
-
*/
|
|
1873
1900
|
async disableProvider() {
|
|
1874
|
-
|
|
1875
|
-
const id = this.allocId();
|
|
1876
|
-
const result = await this.sendRequest(id, "providers/disable", {});
|
|
1877
|
-
if (isJsonRpcError(result)) {
|
|
1878
|
-
throw new ACPSessionError(
|
|
1879
|
-
"prompt_failed",
|
|
1880
|
-
`providers/disable failed: ${result.message}`,
|
|
1881
|
-
result
|
|
1882
|
-
);
|
|
1883
|
-
}
|
|
1901
|
+
return executeDisableProvider(this.opContext());
|
|
1884
1902
|
}
|
|
1885
1903
|
// ──────────────────────────────────────────────────────────────────────
|
|
1886
1904
|
// Prompt
|
|
1887
1905
|
// ──────────────────────────────────────────────────────────────────────
|
|
1888
|
-
/**
|
|
1889
|
-
* Run one prompt turn. Creates a session if needed, sends the
|
|
1890
|
-
* prompt, streams session/update notifications, and resolves with
|
|
1891
|
-
* the agent's response.
|
|
1892
|
-
*
|
|
1893
|
-
* @param blocks - Content blocks to send. Use `textContent()` for plain
|
|
1894
|
-
* text, or include ImageContent/AudioContent if the agent's
|
|
1895
|
-
* `promptCapabilities` allow it.
|
|
1896
|
-
* @param signal - AbortSignal for cancellation.
|
|
1897
|
-
*
|
|
1898
|
-
* Cancellation: if `signal` aborts mid-prompt, we send
|
|
1899
|
-
* `session/cancel` (a notification per spec) and keep accepting
|
|
1900
|
-
* updates until the agent returns with `stopReason: 'cancelled'`.
|
|
1901
|
-
* The result is the same shape as a normal turn, with
|
|
1902
|
-
* `stopReason === 'cancelled'`.
|
|
1903
|
-
*/
|
|
1904
1906
|
async prompt(blocks, signal, onProgress) {
|
|
1905
1907
|
if (this.closed) {
|
|
1906
1908
|
throw new ACPSessionError("closed", "session is closed");
|
|
@@ -1912,7 +1914,7 @@ var ACPSession = class _ACPSession {
|
|
|
1912
1914
|
return emptyRunResult("cancelled");
|
|
1913
1915
|
}
|
|
1914
1916
|
if (!this.sessionId) {
|
|
1915
|
-
await this.
|
|
1917
|
+
this.sessionId = await executeCreateSession(this.opContext());
|
|
1916
1918
|
}
|
|
1917
1919
|
this.resetScratch();
|
|
1918
1920
|
this.progressHandler = onProgress ?? null;
|
|
@@ -1974,33 +1976,6 @@ var ACPSession = class _ACPSession {
|
|
|
1974
1976
|
thoughts: this.scratch.thoughts
|
|
1975
1977
|
};
|
|
1976
1978
|
}
|
|
1977
|
-
async createSession() {
|
|
1978
|
-
const servers = this.filterMcpServers(this.opts.mcpServers);
|
|
1979
|
-
const id = this.allocId();
|
|
1980
|
-
const result = await this.sendRequest(id, "session/new", {
|
|
1981
|
-
cwd: this.opts.cwd ?? this.opts.projectRoot,
|
|
1982
|
-
mcpServers: servers
|
|
1983
|
-
});
|
|
1984
|
-
if (isJsonRpcError(result)) {
|
|
1985
|
-
throw new ACPSessionError(
|
|
1986
|
-
"session_create_failed",
|
|
1987
|
-
`session/new failed: ${result.message}`,
|
|
1988
|
-
result
|
|
1989
|
-
);
|
|
1990
|
-
}
|
|
1991
|
-
const sessionId = result.sessionId;
|
|
1992
|
-
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
1993
|
-
throw new ACPSessionError("protocol_error", "session/new returned no sessionId", result);
|
|
1994
|
-
}
|
|
1995
|
-
this.sessionId = sessionId;
|
|
1996
|
-
}
|
|
1997
|
-
/**
|
|
1998
|
-
* Close the current session gracefully (if the agent supports it).
|
|
1999
|
-
*
|
|
2000
|
-
* Sends `session/close` JSON-RPC request, then clears the local
|
|
2001
|
-
* session id. Best-effort — errors are swallowed so the caller can
|
|
2002
|
-
* always proceed to transport teardown.
|
|
2003
|
-
*/
|
|
2004
1979
|
async closeSession() {
|
|
2005
1980
|
if (!this.sessionId) return;
|
|
2006
1981
|
const sid = this.sessionId;
|
|
@@ -2016,7 +1991,6 @@ var ACPSession = class _ACPSession {
|
|
|
2016
1991
|
// ──────────────────────────────────────────────────────────────────────
|
|
2017
1992
|
// Lifecycle — close
|
|
2018
1993
|
// ──────────────────────────────────────────────────────────────────────
|
|
2019
|
-
/** Tear down the session and kill the child process. */
|
|
2020
1994
|
async close() {
|
|
2021
1995
|
if (this.closed) return;
|
|
2022
1996
|
this.closed = true;
|
|
@@ -2043,24 +2017,6 @@ var ACPSession = class _ACPSession {
|
|
|
2043
2017
|
} catch {
|
|
2044
2018
|
}
|
|
2045
2019
|
}
|
|
2046
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
2047
|
-
// Helpers
|
|
2048
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
2049
|
-
/**
|
|
2050
|
-
* Filter MCP servers according to agent capabilities.
|
|
2051
|
-
* - Stdio servers are always included.
|
|
2052
|
-
* - HTTP servers are only included if agent supports mcpCapabilities.http.
|
|
2053
|
-
* - SSE servers are only included if agent supports mcpCapabilities.sse.
|
|
2054
|
-
*/
|
|
2055
|
-
filterMcpServers(servers) {
|
|
2056
|
-
if (!servers || servers.length === 0) return [];
|
|
2057
|
-
const mcpCaps = this.agentCapabilities.mcpCapabilities ?? {};
|
|
2058
|
-
return servers.filter((s) => {
|
|
2059
|
-
if ("type" in s && s.type === "http") return mcpCaps.http === true;
|
|
2060
|
-
if ("type" in s && s.type === "sse") return mcpCaps.sse === true;
|
|
2061
|
-
return true;
|
|
2062
|
-
});
|
|
2063
|
-
}
|
|
2064
2020
|
// ────────────────────────────────────────────────────────────────────
|
|
2065
2021
|
// Wire layer
|
|
2066
2022
|
// ────────────────────────────────────────────────────────────────────
|
|
@@ -2091,21 +2047,9 @@ var ACPSession = class _ACPSession {
|
|
|
2091
2047
|
});
|
|
2092
2048
|
});
|
|
2093
2049
|
}
|
|
2094
|
-
/**
|
|
2095
|
-
* Send a JSON-RPC 2.0 success response to an agent-initiated request.
|
|
2096
|
-
*
|
|
2097
|
-
* Per JSON-RPC 2.0 (and the official ACP SDK's message router) a Response
|
|
2098
|
-
* object MUST carry `jsonrpc: "2.0"` and MUST NOT carry a `method` field —
|
|
2099
|
-
* the SDK classifies any object with a `method` key as a Request and drops
|
|
2100
|
-
* it as a response, so an agent's `fs/*`, `terminal/*`, or
|
|
2101
|
-
* `session/request_permission` callback would hang forever. The legacy
|
|
2102
|
-
* `ACPMessage` type predates v1 (requires `method`, lacks `jsonrpc`), so we
|
|
2103
|
-
* build the correct wire object and cast at the boundary.
|
|
2104
|
-
*/
|
|
2105
2050
|
sendResult(id, result) {
|
|
2106
2051
|
return this.transport.send({ jsonrpc: "2.0", id, result });
|
|
2107
2052
|
}
|
|
2108
|
-
/** Send a JSON-RPC 2.0 error response (no `method` field, per spec). */
|
|
2109
2053
|
sendErrorResponse(id, code, message) {
|
|
2110
2054
|
return this.transport.send({
|
|
2111
2055
|
jsonrpc: "2.0",
|
|
@@ -2201,9 +2145,7 @@ var ACPSession = class _ACPSession {
|
|
|
2201
2145
|
} catch {
|
|
2202
2146
|
}
|
|
2203
2147
|
}
|
|
2204
|
-
/** Live progress handler installed for the duration of a `prompt()` turn. */
|
|
2205
2148
|
progressHandler = null;
|
|
2206
|
-
// Per-prompt scratch state
|
|
2207
2149
|
scratch = createSessionScratch();
|
|
2208
2150
|
resetScratch() {
|
|
2209
2151
|
this.scratch = createSessionScratch();
|