@band-ai/sdk 0.4.1 → 0.4.3
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/README.md +1 -1
- package/dist/{CopilotACPAdapter-B_AVyAl6.d.ts → CursorACPAdapter-7-Jtl1LV.d.ts} +167 -3
- package/dist/{CopilotACPAdapter-Clid9xGR.d.cts → CursorACPAdapter-_YhrXRWq.d.cts} +167 -3
- package/dist/adapters.cjs +733 -205
- package/dist/adapters.d.cts +1 -1
- package/dist/adapters.d.ts +1 -1
- package/dist/adapters.js +13 -1
- package/dist/{chunk-UFO6XMCV.js → chunk-VHYPQAQ5.js} +710 -188
- package/dist/index.cjs +671 -141
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -2
- package/package.json +8 -2
package/dist/adapters.cjs
CHANGED
|
@@ -978,6 +978,7 @@ __export(adapters_exports, {
|
|
|
978
978
|
A2AHistoryConverter: () => A2AHistoryConverter,
|
|
979
979
|
ACPClientAdapter: () => ACPClientAdapter,
|
|
980
980
|
ACPServer: () => ACPServer,
|
|
981
|
+
AcpSessionConfigError: () => AcpSessionConfigError,
|
|
981
982
|
AnthropicAdapter: () => AnthropicAdapter,
|
|
982
983
|
AnthropicToolCallingModel: () => AnthropicToolCallingModel,
|
|
983
984
|
BandACPServerAdapter: () => BandACPServerAdapter,
|
|
@@ -989,8 +990,11 @@ __export(adapters_exports, {
|
|
|
989
990
|
CodexAppServerStdioClient: () => CodexAppServerStdioClient,
|
|
990
991
|
CodexJsonRpcError: () => CodexJsonRpcError,
|
|
991
992
|
CopilotACPAdapter: () => CopilotACPAdapter,
|
|
993
|
+
CursorACPAdapter: () => CursorACPAdapter,
|
|
992
994
|
DEFAULT_COPILOT_ACP_COMMAND: () => DEFAULT_COPILOT_ACP_COMMAND,
|
|
995
|
+
DEFAULT_CURSOR_ACP_COMMAND: () => DEFAULT_CURSOR_ACP_COMMAND,
|
|
993
996
|
DEFAULT_OMP_ACP_COMMAND: () => DEFAULT_OMP_ACP_COMMAND,
|
|
997
|
+
FAILURE_CODE_SESSION_CONFIG: () => FAILURE_CODE_SESSION_CONFIG,
|
|
994
998
|
GatewayHistoryConverter: () => GatewayHistoryConverter,
|
|
995
999
|
GatewayServer: () => GatewayServer,
|
|
996
1000
|
GeminiAdapter: () => GeminiAdapter,
|
|
@@ -1002,6 +1006,7 @@ __export(adapters_exports, {
|
|
|
1002
1006
|
LangGraphAdapter: () => LangGraphAdapter,
|
|
1003
1007
|
LettaAdapter: () => LettaAdapter,
|
|
1004
1008
|
LettaHistoryConverter: () => LettaHistoryConverter,
|
|
1009
|
+
MISSING_CONFIG_OPTIONS_REASON: () => MISSING_CONFIG_OPTIONS_REASON,
|
|
1005
1010
|
OmpACPAdapter: () => OmpACPAdapter,
|
|
1006
1011
|
OpenAIAdapter: () => OpenAIAdapter,
|
|
1007
1012
|
OpenAIToolCallingModel: () => OpenAIToolCallingModel,
|
|
@@ -1011,6 +1016,7 @@ __export(adapters_exports, {
|
|
|
1011
1016
|
ToolCallingAdapter: () => ToolCallingAdapter,
|
|
1012
1017
|
VercelAISDKAdapter: () => VercelAISDKAdapter,
|
|
1013
1018
|
VercelAISDKToolCallingModel: () => VercelAISDKToolCallingModel,
|
|
1019
|
+
applySessionConfigSelections: () => applySessionConfigSelections,
|
|
1014
1020
|
buildA2AAuthHeaders: () => buildA2AAuthHeaders,
|
|
1015
1021
|
createGatewayServer: () => createGatewayServer,
|
|
1016
1022
|
runSingleToolRound: () => runSingleToolRound
|
|
@@ -1730,6 +1736,149 @@ function abandon(operation, onError = () => void 0) {
|
|
|
1730
1736
|
void Promise.resolve().then(operation).catch(onError);
|
|
1731
1737
|
}
|
|
1732
1738
|
|
|
1739
|
+
// src/adapters/acp/sessionConfigReconciliation.ts
|
|
1740
|
+
var FAILURE_CODE_SESSION_CONFIG = "session_config";
|
|
1741
|
+
var MISSING_CONFIG_OPTIONS_REASON = "missing_config_options";
|
|
1742
|
+
var AcpSessionConfigTimeoutError = class extends Error {
|
|
1743
|
+
};
|
|
1744
|
+
var AcpSessionConfigError = class extends Error {
|
|
1745
|
+
provider;
|
|
1746
|
+
sessionId;
|
|
1747
|
+
optionId;
|
|
1748
|
+
selectedValue;
|
|
1749
|
+
acpCode;
|
|
1750
|
+
detail;
|
|
1751
|
+
timedOut;
|
|
1752
|
+
constructor(input) {
|
|
1753
|
+
super(input.message, input.cause !== void 0 ? { cause: input.cause } : void 0);
|
|
1754
|
+
this.name = "AcpSessionConfigError";
|
|
1755
|
+
this.provider = input.provider;
|
|
1756
|
+
this.sessionId = input.sessionId;
|
|
1757
|
+
this.optionId = input.optionId;
|
|
1758
|
+
this.selectedValue = input.selectedValue;
|
|
1759
|
+
this.acpCode = input.acpCode;
|
|
1760
|
+
this.detail = input.detail;
|
|
1761
|
+
this.timedOut = input.timedOut ?? false;
|
|
1762
|
+
}
|
|
1763
|
+
toAgentFailure() {
|
|
1764
|
+
return agentFailure(
|
|
1765
|
+
this.provider,
|
|
1766
|
+
this.message,
|
|
1767
|
+
this.acpCode !== void 0 ? String(this.acpCode) : FAILURE_CODE_SESSION_CONFIG,
|
|
1768
|
+
{
|
|
1769
|
+
sessionId: this.sessionId,
|
|
1770
|
+
optionId: this.optionId,
|
|
1771
|
+
selectedValue: this.selectedValue,
|
|
1772
|
+
detail: this.detail
|
|
1773
|
+
}
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
async function applySessionConfigSelections(input) {
|
|
1778
|
+
let catalog = input.catalog;
|
|
1779
|
+
for (const { configId, value: selectedValue } of sessionConfigSelectionEntries(input.selections)) {
|
|
1780
|
+
if (selectedValue === void 0) {
|
|
1781
|
+
continue;
|
|
1782
|
+
}
|
|
1783
|
+
const option = catalog.find((entry) => entry?.id === configId);
|
|
1784
|
+
if (!option || !isSessionConfigSelect(option)) {
|
|
1785
|
+
throw new AcpSessionConfigError({
|
|
1786
|
+
provider: input.provider,
|
|
1787
|
+
sessionId: input.sessionId,
|
|
1788
|
+
optionId: configId,
|
|
1789
|
+
selectedValue,
|
|
1790
|
+
message: `Session config option "${configId}" is not available after prior selections.`
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
if (selectedValue === option.currentValue) {
|
|
1794
|
+
continue;
|
|
1795
|
+
}
|
|
1796
|
+
const availableValues = flattenConfigSelectOptions(option.options).map((entry) => entry.value);
|
|
1797
|
+
if (!availableValues.includes(selectedValue)) {
|
|
1798
|
+
throw new AcpSessionConfigError({
|
|
1799
|
+
provider: input.provider,
|
|
1800
|
+
sessionId: input.sessionId,
|
|
1801
|
+
optionId: configId,
|
|
1802
|
+
selectedValue,
|
|
1803
|
+
message: `Session config value "${selectedValue}" is not advertised for option "${configId}".`,
|
|
1804
|
+
detail: { availableValues }
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
const timeoutMessage = `setSessionConfigOption did not respond within ${input.timeoutMs}ms`;
|
|
1808
|
+
try {
|
|
1809
|
+
const response = await withTimeout(
|
|
1810
|
+
input.setOption({ sessionId: input.sessionId, configId, value: selectedValue }),
|
|
1811
|
+
input.timeoutMs,
|
|
1812
|
+
() => new AcpSessionConfigTimeoutError(timeoutMessage)
|
|
1813
|
+
);
|
|
1814
|
+
if (!Array.isArray(response?.configOptions)) {
|
|
1815
|
+
throw new AcpSessionConfigError({
|
|
1816
|
+
provider: input.provider,
|
|
1817
|
+
sessionId: input.sessionId,
|
|
1818
|
+
optionId: configId,
|
|
1819
|
+
selectedValue,
|
|
1820
|
+
message: `Session config option "${configId}" response did not include a refreshed catalog.`,
|
|
1821
|
+
detail: { reason: MISSING_CONFIG_OPTIONS_REASON }
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
catalog = response.configOptions;
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
if (error instanceof AcpSessionConfigError) {
|
|
1827
|
+
throw error;
|
|
1828
|
+
}
|
|
1829
|
+
const acpError = asAcpJsonRpcError(error);
|
|
1830
|
+
throw new AcpSessionConfigError({
|
|
1831
|
+
provider: input.provider,
|
|
1832
|
+
sessionId: input.sessionId,
|
|
1833
|
+
optionId: configId,
|
|
1834
|
+
selectedValue,
|
|
1835
|
+
acpCode: acpError?.code,
|
|
1836
|
+
detail: acpError?.data,
|
|
1837
|
+
message: acpError?.message ?? asErrorMessage(error),
|
|
1838
|
+
cause: error,
|
|
1839
|
+
timedOut: error instanceof AcpSessionConfigTimeoutError
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
return { catalog };
|
|
1844
|
+
}
|
|
1845
|
+
function sessionConfigSelectionEntries(selections) {
|
|
1846
|
+
if (isOrderedSessionConfigSelections(selections)) {
|
|
1847
|
+
return selections;
|
|
1848
|
+
}
|
|
1849
|
+
return Object.keys(selections).map((configId) => ({ configId, value: selections[configId] }));
|
|
1850
|
+
}
|
|
1851
|
+
function isOrderedSessionConfigSelections(selections) {
|
|
1852
|
+
return Array.isArray(selections);
|
|
1853
|
+
}
|
|
1854
|
+
function isSessionConfigSelect(option) {
|
|
1855
|
+
return option?.type === "select";
|
|
1856
|
+
}
|
|
1857
|
+
function flattenConfigSelectOptions(options) {
|
|
1858
|
+
if (!Array.isArray(options)) {
|
|
1859
|
+
return [];
|
|
1860
|
+
}
|
|
1861
|
+
return options.flatMap((entry) => {
|
|
1862
|
+
if (!asOptionalRecord2(entry)) {
|
|
1863
|
+
return [];
|
|
1864
|
+
}
|
|
1865
|
+
if ("group" in entry) {
|
|
1866
|
+
return Array.isArray(entry.options) ? entry.options : [];
|
|
1867
|
+
}
|
|
1868
|
+
return [entry];
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
function isAcpErrorResponse(error) {
|
|
1872
|
+
return typeof error === "object" && error !== null && typeof error.code === "number" && typeof error.message === "string";
|
|
1873
|
+
}
|
|
1874
|
+
function asAcpJsonRpcError(error) {
|
|
1875
|
+
if (isAcpErrorResponse(error)) {
|
|
1876
|
+
return error;
|
|
1877
|
+
}
|
|
1878
|
+
const nested = asOptionalRecord2(error)?.error;
|
|
1879
|
+
return isAcpErrorResponse(nested) ? nested : void 0;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1733
1882
|
// src/adapters/acp/ACPClientAdapter.ts
|
|
1734
1883
|
init_chatEvents();
|
|
1735
1884
|
init_schemas();
|
|
@@ -2191,74 +2340,17 @@ function checkPort2(http, port) {
|
|
|
2191
2340
|
});
|
|
2192
2341
|
}
|
|
2193
2342
|
|
|
2194
|
-
// src/adapters/acp/types.ts
|
|
2195
|
-
var DEFAULT_ACP_SERVER_MODES = [
|
|
2196
|
-
{
|
|
2197
|
-
id: "default",
|
|
2198
|
-
name: "Default",
|
|
2199
|
-
description: "General-purpose chat mode"
|
|
2200
|
-
},
|
|
2201
|
-
{
|
|
2202
|
-
id: "code",
|
|
2203
|
-
name: "Code",
|
|
2204
|
-
description: "Route prompts toward coding peers when available"
|
|
2205
|
-
}
|
|
2206
|
-
];
|
|
2207
|
-
function createPendingPrompt(sessionId) {
|
|
2208
|
-
let markDone = () => void 0;
|
|
2209
|
-
const done = new Promise((resolve) => {
|
|
2210
|
-
markDone = resolve;
|
|
2211
|
-
});
|
|
2212
|
-
return {
|
|
2213
|
-
sessionId,
|
|
2214
|
-
done,
|
|
2215
|
-
markDone,
|
|
2216
|
-
terminalMessageSeen: false,
|
|
2217
|
-
completionTimer: null
|
|
2218
|
-
};
|
|
2219
|
-
}
|
|
2220
|
-
function choosePermissionOption(options) {
|
|
2221
|
-
if (options.length === 0) {
|
|
2222
|
-
return null;
|
|
2223
|
-
}
|
|
2224
|
-
return options.find((option) => option.kind === "allow_once") ?? options.find((option) => option.kind === "allow_always") ?? options[0];
|
|
2225
|
-
}
|
|
2226
|
-
function asJsonSafe(value) {
|
|
2227
|
-
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2228
|
-
return value;
|
|
2229
|
-
}
|
|
2230
|
-
if (Array.isArray(value)) {
|
|
2231
|
-
return value.map((item) => asJsonSafe(item));
|
|
2232
|
-
}
|
|
2233
|
-
if (typeof value === "object") {
|
|
2234
|
-
if ("model_dump" in value && typeof value.model_dump === "function") {
|
|
2235
|
-
return asJsonSafe(value.model_dump());
|
|
2236
|
-
}
|
|
2237
|
-
if ("toJSON" in value && typeof value.toJSON === "function") {
|
|
2238
|
-
return asJsonSafe(value.toJSON());
|
|
2239
|
-
}
|
|
2240
|
-
return Object.fromEntries(
|
|
2241
|
-
Object.entries(value).map(([key, item]) => [key, asJsonSafe(item)])
|
|
2242
|
-
);
|
|
2243
|
-
}
|
|
2244
|
-
return String(value);
|
|
2245
|
-
}
|
|
2246
|
-
function normalizeMcpServers(mcpServers) {
|
|
2247
|
-
if (!mcpServers) {
|
|
2248
|
-
return [];
|
|
2249
|
-
}
|
|
2250
|
-
return mcpServers.map((server) => asJsonSafe(server)).filter((server) => !!server && typeof server === "object" && !Array.isArray(server));
|
|
2251
|
-
}
|
|
2252
|
-
|
|
2253
2343
|
// src/adapters/acp/client.ts
|
|
2254
2344
|
var BandACPClient = class {
|
|
2255
2345
|
sessionChunks = /* @__PURE__ */ new Map();
|
|
2256
2346
|
permissionHandler;
|
|
2347
|
+
extensionHandler;
|
|
2257
2348
|
// The handler is connection-scoped and required at construction, so it is
|
|
2258
2349
|
// already in place before the agent process is spawned: there is no window
|
|
2259
2350
|
// in which a `session/request_permission` has nowhere to go.
|
|
2260
|
-
constructor(permissionHandler) {
|
|
2351
|
+
constructor(permissionHandler, extensionHandler) {
|
|
2261
2352
|
this.permissionHandler = permissionHandler;
|
|
2353
|
+
this.extensionHandler = extensionHandler;
|
|
2262
2354
|
}
|
|
2263
2355
|
beginSession(sessionId) {
|
|
2264
2356
|
this.sessionChunks.set(sessionId, []);
|
|
@@ -2303,62 +2395,26 @@ var BandACPClient = class {
|
|
|
2303
2395
|
return chunks;
|
|
2304
2396
|
}
|
|
2305
2397
|
async extMethod(method, params) {
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
return {
|
|
2313
|
-
outcome: {
|
|
2314
|
-
type: "cancelled"
|
|
2315
|
-
}
|
|
2316
|
-
};
|
|
2317
|
-
}
|
|
2318
|
-
return {
|
|
2319
|
-
outcome: {
|
|
2320
|
-
type: "selected",
|
|
2321
|
-
optionId: selected.optionId
|
|
2322
|
-
}
|
|
2323
|
-
};
|
|
2324
|
-
}
|
|
2325
|
-
if (method === "cursor/create_plan") {
|
|
2326
|
-
return {
|
|
2327
|
-
outcome: {
|
|
2328
|
-
type: "approved"
|
|
2329
|
-
}
|
|
2330
|
-
};
|
|
2331
|
-
}
|
|
2332
|
-
return {};
|
|
2398
|
+
const result = await this.extensionHandler?.extMethod?.(
|
|
2399
|
+
method,
|
|
2400
|
+
params,
|
|
2401
|
+
{ sessionId: sessionIdFrom(params) }
|
|
2402
|
+
);
|
|
2403
|
+
return result ?? {};
|
|
2333
2404
|
}
|
|
2334
2405
|
async extNotification(method, params) {
|
|
2335
|
-
const sessionId =
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
this.appendChunk(sessionId, {
|
|
2344
|
-
chunkType: "plan",
|
|
2345
|
-
content: lines.join("\n"),
|
|
2346
|
-
metadata: {},
|
|
2347
|
-
streamed: false
|
|
2348
|
-
});
|
|
2349
|
-
}
|
|
2406
|
+
const sessionId = sessionIdFrom(params);
|
|
2407
|
+
const chunks = await this.extensionHandler?.extNotification?.(
|
|
2408
|
+
method,
|
|
2409
|
+
params,
|
|
2410
|
+
{ sessionId }
|
|
2411
|
+
);
|
|
2412
|
+
const targetSessionId = sessionId ?? this.extensionHandler?.extensionSessionId?.() ?? null;
|
|
2413
|
+
if (!targetSessionId || !chunks) {
|
|
2350
2414
|
return;
|
|
2351
2415
|
}
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
if (result) {
|
|
2355
|
-
this.appendChunk(sessionId, {
|
|
2356
|
-
chunkType: "text",
|
|
2357
|
-
content: `[Task completed] ${result}`,
|
|
2358
|
-
metadata: {},
|
|
2359
|
-
streamed: false
|
|
2360
|
-
});
|
|
2361
|
-
}
|
|
2416
|
+
for (const chunk of chunks) {
|
|
2417
|
+
this.appendChunk(targetSessionId, chunk);
|
|
2362
2418
|
}
|
|
2363
2419
|
}
|
|
2364
2420
|
appendChunk(sessionId, chunk) {
|
|
@@ -2483,6 +2539,68 @@ function extractTextFromContent(content) {
|
|
|
2483
2539
|
function toOptionalString(value) {
|
|
2484
2540
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
2485
2541
|
}
|
|
2542
|
+
function sessionIdFrom(params) {
|
|
2543
|
+
return toOptionalString(params.sessionId) ?? toOptionalString(params.session_id);
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
// src/adapters/acp/types.ts
|
|
2547
|
+
var DEFAULT_ACP_SERVER_MODES = [
|
|
2548
|
+
{
|
|
2549
|
+
id: "default",
|
|
2550
|
+
name: "Default",
|
|
2551
|
+
description: "General-purpose chat mode"
|
|
2552
|
+
},
|
|
2553
|
+
{
|
|
2554
|
+
id: "code",
|
|
2555
|
+
name: "Code",
|
|
2556
|
+
description: "Route prompts toward coding peers when available"
|
|
2557
|
+
}
|
|
2558
|
+
];
|
|
2559
|
+
function createPendingPrompt(sessionId) {
|
|
2560
|
+
let markDone = () => void 0;
|
|
2561
|
+
const done = new Promise((resolve) => {
|
|
2562
|
+
markDone = resolve;
|
|
2563
|
+
});
|
|
2564
|
+
return {
|
|
2565
|
+
sessionId,
|
|
2566
|
+
done,
|
|
2567
|
+
markDone,
|
|
2568
|
+
terminalMessageSeen: false,
|
|
2569
|
+
completionTimer: null
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
function choosePermissionOption(options) {
|
|
2573
|
+
if (options.length === 0) {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
return options.find((option) => option.kind === "allow_once") ?? options.find((option) => option.kind === "allow_always") ?? options[0];
|
|
2577
|
+
}
|
|
2578
|
+
function asJsonSafe(value) {
|
|
2579
|
+
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2580
|
+
return value;
|
|
2581
|
+
}
|
|
2582
|
+
if (Array.isArray(value)) {
|
|
2583
|
+
return value.map((item) => asJsonSafe(item));
|
|
2584
|
+
}
|
|
2585
|
+
if (typeof value === "object") {
|
|
2586
|
+
if ("model_dump" in value && typeof value.model_dump === "function") {
|
|
2587
|
+
return asJsonSafe(value.model_dump());
|
|
2588
|
+
}
|
|
2589
|
+
if ("toJSON" in value && typeof value.toJSON === "function") {
|
|
2590
|
+
return asJsonSafe(value.toJSON());
|
|
2591
|
+
}
|
|
2592
|
+
return Object.fromEntries(
|
|
2593
|
+
Object.entries(value).map(([key, item]) => [key, asJsonSafe(item)])
|
|
2594
|
+
);
|
|
2595
|
+
}
|
|
2596
|
+
return String(value);
|
|
2597
|
+
}
|
|
2598
|
+
function normalizeMcpServers(mcpServers) {
|
|
2599
|
+
if (!mcpServers) {
|
|
2600
|
+
return [];
|
|
2601
|
+
}
|
|
2602
|
+
return mcpServers.map((server) => asJsonSafe(server)).filter((server) => !!server && typeof server === "object" && !Array.isArray(server));
|
|
2603
|
+
}
|
|
2486
2604
|
|
|
2487
2605
|
// src/adapters/acp/loader.ts
|
|
2488
2606
|
init_errors();
|
|
@@ -2546,6 +2664,13 @@ var acpModule = new LazyAsyncValue({
|
|
|
2546
2664
|
});
|
|
2547
2665
|
|
|
2548
2666
|
// src/adapters/acp/ACPClientAdapter.ts
|
|
2667
|
+
function createConnectionRetirement() {
|
|
2668
|
+
let reject = () => void 0;
|
|
2669
|
+
const promise = new Promise((_resolve, rejectPromise) => {
|
|
2670
|
+
reject = rejectPromise;
|
|
2671
|
+
});
|
|
2672
|
+
return { promise, reject };
|
|
2673
|
+
}
|
|
2549
2674
|
var DEFAULT_PERMISSION_TIMEOUT_MS = 5 * 6e4;
|
|
2550
2675
|
var DEFAULT_TURN_TIMEOUT_MS = 60 * 6e4;
|
|
2551
2676
|
var SET_SESSION_CONFIG_TIMEOUT_MS = 1e4;
|
|
@@ -2571,6 +2696,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2571
2696
|
additionalMcpTools;
|
|
2572
2697
|
clientCapabilities;
|
|
2573
2698
|
connectionFactory;
|
|
2699
|
+
extensionHandler;
|
|
2574
2700
|
tcpEndpoint;
|
|
2575
2701
|
// The value's `generation` is the connection generation the session was
|
|
2576
2702
|
// last established/restored against. `client` is the exact BandACPClient
|
|
@@ -2603,6 +2729,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2603
2729
|
permissionTimeoutMs;
|
|
2604
2730
|
turnTimeoutMs;
|
|
2605
2731
|
logger;
|
|
2732
|
+
customSection;
|
|
2606
2733
|
backend = null;
|
|
2607
2734
|
backendPromise = null;
|
|
2608
2735
|
client = null;
|
|
@@ -2613,6 +2740,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2613
2740
|
started = false;
|
|
2614
2741
|
systemPrompt = "";
|
|
2615
2742
|
spawnPromise = null;
|
|
2743
|
+
connectionRetirements = /* @__PURE__ */ new WeakMap();
|
|
2616
2744
|
// Bumped by `stop()` and on every successful spawn install. Cleanup/timeout
|
|
2617
2745
|
// and permission maps key by this plus session id so a stale generation
|
|
2618
2746
|
// cannot alias a same-id session on a newer connection.
|
|
@@ -2633,12 +2761,14 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2633
2761
|
this.additionalMcpTools = [...options.additionalMcpTools ?? []];
|
|
2634
2762
|
this.clientCapabilities = options.clientCapabilities;
|
|
2635
2763
|
this.connectionFactory = options.connectionFactory;
|
|
2764
|
+
this.extensionHandler = options.extensionHandler;
|
|
2636
2765
|
this.tcpEndpoint = tcpEndpoint;
|
|
2637
2766
|
this.resolvePermission = options.resolvePermission;
|
|
2638
2767
|
this.resolveSessionMode = options.resolveSessionMode;
|
|
2639
2768
|
this.resolveSessionModel = options.resolveSessionModel;
|
|
2640
2769
|
this.resolveSessionConfig = options.resolveSessionConfig;
|
|
2641
2770
|
this.logger = resolveLogger(options.logger);
|
|
2771
|
+
this.customSection = options.customSection;
|
|
2642
2772
|
this.permissionTimeoutMs = options.permissionTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
2643
2773
|
if ((this.resolvePermission || this.resolveSessionMode || this.resolveSessionModel || this.resolveSessionConfig) && (!Number.isFinite(this.permissionTimeoutMs) || this.permissionTimeoutMs <= 0)) {
|
|
2644
2774
|
throw new ValidationError(`permissionTimeoutMs must be a positive finite number, got ${options.permissionTimeoutMs}`);
|
|
@@ -2670,7 +2800,8 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2670
2800
|
this.systemPrompt = renderSystemPrompt({
|
|
2671
2801
|
agentName,
|
|
2672
2802
|
agentDescription,
|
|
2673
|
-
includeBaseInstructions: false
|
|
2803
|
+
includeBaseInstructions: false,
|
|
2804
|
+
customSection: this.customSection
|
|
2674
2805
|
});
|
|
2675
2806
|
await this.ensureConnection();
|
|
2676
2807
|
}
|
|
@@ -2686,6 +2817,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2686
2817
|
let client = null;
|
|
2687
2818
|
let sessionId;
|
|
2688
2819
|
let generation = 0;
|
|
2820
|
+
await this.onAcpTurnStarted(message, tools, context);
|
|
2689
2821
|
try {
|
|
2690
2822
|
const ensured = await this.ensureConnection();
|
|
2691
2823
|
connection = ensured.connection;
|
|
@@ -2696,6 +2828,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2696
2828
|
}
|
|
2697
2829
|
sessionId = await this.getOrCreateSession(context.roomId, connection, generation, client);
|
|
2698
2830
|
const sessionKey = this.sessionKey(generation, sessionId);
|
|
2831
|
+
await this.onAcpSessionReady(message, tools, context, sessionId);
|
|
2699
2832
|
client.beginSession(sessionId);
|
|
2700
2833
|
const content = replaceUuidMentions(message.content, mentionSubjectsFromMetadata(message.metadata));
|
|
2701
2834
|
const messageWithContext = [...systemUpdateParts(participantsMessage, contactsMessage), content].join("\n\n");
|
|
@@ -2703,13 +2836,17 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2703
2836
|
|
|
2704
2837
|
${messageWithContext}`;
|
|
2705
2838
|
this.bootstrappedSessions.add(sessionKey);
|
|
2706
|
-
const response = await withTimeout(
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2839
|
+
const response = await withTimeout(
|
|
2840
|
+
this.raceAgainstConnectionRetirement(connection, connection.prompt({
|
|
2841
|
+
sessionId,
|
|
2842
|
+
prompt: [{
|
|
2843
|
+
type: "text",
|
|
2844
|
+
text: promptText
|
|
2845
|
+
}]
|
|
2846
|
+
})),
|
|
2847
|
+
this.turnTimeoutMs,
|
|
2848
|
+
() => new AcpTurnTimeoutError()
|
|
2849
|
+
);
|
|
2713
2850
|
await this.flushChunks({
|
|
2714
2851
|
client,
|
|
2715
2852
|
tools,
|
|
@@ -2750,15 +2887,28 @@ ${messageWithContext}`;
|
|
|
2750
2887
|
}
|
|
2751
2888
|
}
|
|
2752
2889
|
}
|
|
2753
|
-
const
|
|
2890
|
+
const configError = error instanceof AcpSessionConfigError ? error : void 0;
|
|
2891
|
+
const acpError = configError ? void 0 : asAcpJsonRpcError(error);
|
|
2754
2892
|
await reportTurnFailure(
|
|
2755
2893
|
tools,
|
|
2756
|
-
isTimeout ? agentFailure(this.provider, "ACP turn timed out.", FAILURE_CODE_TIMEOUT) : acpError ? agentFailure(this.provider, acpError.message, String(acpError.code), acpError.data) : agentFailure(this.provider, asErrorMessage(error)),
|
|
2894
|
+
isTimeout ? agentFailure(this.provider, "ACP turn timed out.", FAILURE_CODE_TIMEOUT) : configError ? configError.toAgentFailure() : acpError ? agentFailure(this.provider, acpError.message, String(acpError.code), acpError.data) : agentFailure(this.provider, asErrorMessage(error)),
|
|
2757
2895
|
this.logger,
|
|
2758
|
-
{
|
|
2896
|
+
{
|
|
2897
|
+
roomId: context.roomId,
|
|
2898
|
+
sessionId: configError?.sessionId ?? sessionId,
|
|
2899
|
+
...configError ? { optionId: configError.optionId, selectedValue: configError.selectedValue } : {}
|
|
2900
|
+
}
|
|
2759
2901
|
);
|
|
2902
|
+
} finally {
|
|
2903
|
+
await this.onAcpTurnFinished(message, tools, context);
|
|
2760
2904
|
}
|
|
2761
2905
|
}
|
|
2906
|
+
async onAcpTurnStarted(_message, _tools, _context) {
|
|
2907
|
+
}
|
|
2908
|
+
async onAcpTurnFinished(_message, _tools, _context) {
|
|
2909
|
+
}
|
|
2910
|
+
async onAcpSessionReady(_message, _tools, _context, _sessionId) {
|
|
2911
|
+
}
|
|
2762
2912
|
// Best-effort: tells the agent to stop working on a turn Band has already
|
|
2763
2913
|
// given up waiting for (the ACP client has no way to force it), evicts the
|
|
2764
2914
|
// session so the room's next turn re-establishes rather than reuses it
|
|
@@ -2774,17 +2924,12 @@ ${messageWithContext}`;
|
|
|
2774
2924
|
// would risk blocking this room's turn lock forever on the very process
|
|
2775
2925
|
// that just proved it can hang.
|
|
2776
2926
|
async abandonTimedOutTurn(connection, sessionId, generation) {
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
}
|
|
2784
|
-
abandon(
|
|
2785
|
-
() => connection.cancel({ sessionId }),
|
|
2786
|
-
(error) => this.safeWarn("acp_client.cancel_failed", { sessionId, error: asErrorMessage(error) })
|
|
2787
|
-
);
|
|
2927
|
+
this.evictAbandonedSession(sessionId, generation, connection, () => {
|
|
2928
|
+
const owner = [...this.roomToSession.entries()].find(([, value]) => value.sessionId === sessionId && value.generation === generation);
|
|
2929
|
+
if (owner) {
|
|
2930
|
+
this.unlinkOwner(owner[0], owner[1]);
|
|
2931
|
+
}
|
|
2932
|
+
});
|
|
2788
2933
|
}
|
|
2789
2934
|
// A per-room async mutex: `fn` for a given `roomId` never overlaps another
|
|
2790
2935
|
// call for that same room, while different rooms stay fully concurrent.
|
|
@@ -2910,6 +3055,11 @@ ${messageWithContext}`;
|
|
|
2910
3055
|
void connection.closed.then(() => reject(new Error("ACP connection closed while a session operation was still in flight")));
|
|
2911
3056
|
return Promise.race([operation, closedRejection]);
|
|
2912
3057
|
}
|
|
3058
|
+
raceAgainstConnectionRetirement(connection, operation) {
|
|
3059
|
+
const retirement = this.connectionRetirements.get(connection) ?? createConnectionRetirement();
|
|
3060
|
+
this.connectionRetirements.set(connection, retirement);
|
|
3061
|
+
return Promise.race([operation, retirement.promise]);
|
|
3062
|
+
}
|
|
2913
3063
|
unlinkRoom(roomId) {
|
|
2914
3064
|
const owner = this.roomToSession.get(roomId);
|
|
2915
3065
|
if (owner) {
|
|
@@ -2928,6 +3078,9 @@ ${messageWithContext}`;
|
|
|
2928
3078
|
sessionKey(generation, sessionId) {
|
|
2929
3079
|
return `${generation}:${sessionId}`;
|
|
2930
3080
|
}
|
|
3081
|
+
roomIdForSession(sessionId) {
|
|
3082
|
+
return [...this.roomToSession.entries()].find(([, owner]) => owner.sessionId === sessionId)?.[0];
|
|
3083
|
+
}
|
|
2931
3084
|
async ensureConnection() {
|
|
2932
3085
|
if (this.connection && !this.connection.signal.aborted) {
|
|
2933
3086
|
return { connection: this.connection, generation: this.connectionGeneration };
|
|
@@ -2964,7 +3117,10 @@ ${messageWithContext}`;
|
|
|
2964
3117
|
throw new Error(CONNECTION_ATTEMPT_SUPERSEDED_ERROR);
|
|
2965
3118
|
}
|
|
2966
3119
|
const owner = { generation: -1 };
|
|
2967
|
-
const client = new BandACPClient(
|
|
3120
|
+
const client = new BandACPClient(
|
|
3121
|
+
(params) => this.routePermissionRequest(params, owner.generation),
|
|
3122
|
+
this.extensionHandler
|
|
3123
|
+
);
|
|
2968
3124
|
handle = await (this.connectionFactory ? this.connectionFactory(client, {
|
|
2969
3125
|
command: this.command,
|
|
2970
3126
|
cwd: this.cwd,
|
|
@@ -3054,7 +3210,7 @@ ${messageWithContext}`;
|
|
|
3054
3210
|
this.activeSessions.add(restoredKey);
|
|
3055
3211
|
this.bootstrappedSessions.add(restoredKey);
|
|
3056
3212
|
await this.configureSessionMode(roomId, existingSessionId, restored.modes, connection);
|
|
3057
|
-
await this.configureSessionConfig(roomId, existingSessionId, restored.configOptions, connection);
|
|
3213
|
+
await this.configureSessionConfig(roomId, existingSessionId, restored.configOptions, connection, connectionGeneration, client);
|
|
3058
3214
|
if (!this.resolveSessionConfig) {
|
|
3059
3215
|
await this.configureSessionModel(roomId, existingSessionId, restored.configOptions, connection);
|
|
3060
3216
|
}
|
|
@@ -3068,13 +3224,13 @@ ${messageWithContext}`;
|
|
|
3068
3224
|
this.linkOrAbandon(roomId, created.sessionId, generation, connectionGeneration, client);
|
|
3069
3225
|
this.activeSessions.add(this.sessionKey(connectionGeneration, created.sessionId));
|
|
3070
3226
|
await this.configureSessionMode(roomId, created.sessionId, created.modes, connection);
|
|
3071
|
-
await this.configureSessionConfig(roomId, created.sessionId, created.configOptions, connection);
|
|
3227
|
+
await this.configureSessionConfig(roomId, created.sessionId, created.configOptions, connection, connectionGeneration, client);
|
|
3072
3228
|
if (!this.resolveSessionConfig) {
|
|
3073
3229
|
await this.configureSessionModel(roomId, created.sessionId, created.configOptions, connection);
|
|
3074
3230
|
}
|
|
3075
3231
|
return created.sessionId;
|
|
3076
3232
|
}
|
|
3077
|
-
async configureSessionConfig(roomId, sessionId, configOptions, connection) {
|
|
3233
|
+
async configureSessionConfig(roomId, sessionId, configOptions, connection, connectionGeneration, client) {
|
|
3078
3234
|
if (!this.resolveSessionConfig || !Array.isArray(configOptions) || configOptions.length === 0) {
|
|
3079
3235
|
return;
|
|
3080
3236
|
}
|
|
@@ -3087,35 +3243,76 @@ ${messageWithContext}`;
|
|
|
3087
3243
|
if (!selections) {
|
|
3088
3244
|
return;
|
|
3089
3245
|
}
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3246
|
+
try {
|
|
3247
|
+
await applySessionConfigSelections({
|
|
3248
|
+
provider: this.provider,
|
|
3249
|
+
sessionId,
|
|
3250
|
+
catalog: advertisedOptions,
|
|
3251
|
+
selections,
|
|
3252
|
+
setOption: (params) => connection.setSessionConfigOption(params),
|
|
3253
|
+
timeoutMs: SET_SESSION_CONFIG_TIMEOUT_MS
|
|
3254
|
+
});
|
|
3255
|
+
} catch (error) {
|
|
3256
|
+
this.abandonFailedConfigSession(
|
|
3257
|
+
roomId,
|
|
3258
|
+
sessionId,
|
|
3259
|
+
connectionGeneration,
|
|
3260
|
+
client,
|
|
3261
|
+
connection,
|
|
3262
|
+
error instanceof AcpSessionConfigError && error.timedOut
|
|
3263
|
+
);
|
|
3264
|
+
throw error;
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
// A config failure mid-establish must not leave a half-applied session
|
|
3268
|
+
// active for the room: the next turn needs a fresh `newSession` catalog.
|
|
3269
|
+
abandonFailedConfigSession(roomId, sessionId, connectionGeneration, client, connection, retireConnection) {
|
|
3270
|
+
const key = this.sessionKey(connectionGeneration, sessionId);
|
|
3271
|
+
this.bootstrappedSessions.delete(key);
|
|
3272
|
+
client.resetChunks(sessionId);
|
|
3273
|
+
this.evictAbandonedSession(sessionId, connectionGeneration, connection, () => {
|
|
3274
|
+
const owner = this.roomToSession.get(roomId);
|
|
3275
|
+
if (owner && owner.sessionId === sessionId && owner.generation === connectionGeneration) {
|
|
3276
|
+
this.unlinkOwner(roomId, owner);
|
|
3118
3277
|
}
|
|
3278
|
+
});
|
|
3279
|
+
if (retireConnection) {
|
|
3280
|
+
this.retireConnection(connection, connectionGeneration);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
// Common half of timeout and config-failure abandon: mark the session
|
|
3284
|
+
// unusable for restore, unlink ownership, and best-effort cancel.
|
|
3285
|
+
evictAbandonedSession(sessionId, connectionGeneration, connection, unlink) {
|
|
3286
|
+
const key = this.sessionKey(connectionGeneration, sessionId);
|
|
3287
|
+
const wasActive = this.activeSessions.delete(key);
|
|
3288
|
+
if (wasActive) {
|
|
3289
|
+
this.abandonedSessions.add(key);
|
|
3290
|
+
}
|
|
3291
|
+
unlink();
|
|
3292
|
+
abandon(
|
|
3293
|
+
() => connection.cancel({ sessionId }),
|
|
3294
|
+
(error) => this.safeWarn("acp_client.cancel_failed", { sessionId, error: asErrorMessage(error) })
|
|
3295
|
+
);
|
|
3296
|
+
}
|
|
3297
|
+
// A timed-out config RPC means this transport has already failed to answer
|
|
3298
|
+
// one request. Retire it so the next turn cannot wait forever on another.
|
|
3299
|
+
retireConnection(connection, generation) {
|
|
3300
|
+
if (this.connection !== connection || this.connectionGeneration !== generation) {
|
|
3301
|
+
return;
|
|
3302
|
+
}
|
|
3303
|
+
const handle = this.connectionHandle;
|
|
3304
|
+
this.connectionGeneration++;
|
|
3305
|
+
this.connection = null;
|
|
3306
|
+
this.connectionHandle = null;
|
|
3307
|
+
this.connectionState = null;
|
|
3308
|
+
this.client = null;
|
|
3309
|
+
this.pruneConnectionGeneration(generation);
|
|
3310
|
+
this.connectionRetirements.get(connection)?.reject(new Error("ACP connection retired after a config timeout"));
|
|
3311
|
+
if (handle) {
|
|
3312
|
+
abandon(
|
|
3313
|
+
() => handle.stop(),
|
|
3314
|
+
(error) => this.safeWarn("acp_client.handle_stop_after_config_timeout", { error: asErrorMessage(error) })
|
|
3315
|
+
);
|
|
3119
3316
|
}
|
|
3120
3317
|
}
|
|
3121
3318
|
// The single gate an establishment must pass before it's allowed to claim
|
|
@@ -3729,39 +3926,12 @@ async function createTcpConnection(client, endpoint, signal) {
|
|
|
3729
3926
|
};
|
|
3730
3927
|
}
|
|
3731
3928
|
var MODEL_CONFIG_OPTION_KEY = "model";
|
|
3732
|
-
function isSessionConfigSelect(option) {
|
|
3733
|
-
return option?.type === "select";
|
|
3734
|
-
}
|
|
3735
3929
|
function isModelConfigOption(option) {
|
|
3736
3930
|
return isSessionConfigSelect(option) && option.category === MODEL_CONFIG_OPTION_KEY;
|
|
3737
3931
|
}
|
|
3738
3932
|
function isModelConfigOptionById(option) {
|
|
3739
3933
|
return isSessionConfigSelect(option) && option.id === MODEL_CONFIG_OPTION_KEY;
|
|
3740
3934
|
}
|
|
3741
|
-
function flattenConfigSelectOptions(options) {
|
|
3742
|
-
if (!Array.isArray(options)) {
|
|
3743
|
-
return [];
|
|
3744
|
-
}
|
|
3745
|
-
return options.flatMap((entry) => {
|
|
3746
|
-
if (!asOptionalRecord2(entry)) {
|
|
3747
|
-
return [];
|
|
3748
|
-
}
|
|
3749
|
-
if ("group" in entry) {
|
|
3750
|
-
return Array.isArray(entry.options) ? entry.options : [];
|
|
3751
|
-
}
|
|
3752
|
-
return [entry];
|
|
3753
|
-
});
|
|
3754
|
-
}
|
|
3755
|
-
function isAcpErrorResponse(error) {
|
|
3756
|
-
return typeof error === "object" && error !== null && typeof error.code === "number" && typeof error.message === "string";
|
|
3757
|
-
}
|
|
3758
|
-
function asAcpJsonRpcError(error) {
|
|
3759
|
-
if (isAcpErrorResponse(error)) {
|
|
3760
|
-
return error;
|
|
3761
|
-
}
|
|
3762
|
-
const nested = asOptionalRecord2(error)?.error;
|
|
3763
|
-
return isAcpErrorResponse(nested) ? nested : void 0;
|
|
3764
|
-
}
|
|
3765
3935
|
|
|
3766
3936
|
// src/adapters/acp/ACPServer.ts
|
|
3767
3937
|
var import_node_stream2 = require("stream");
|
|
@@ -4675,6 +4845,358 @@ var CopilotACPAdapter = class extends ACPClientAdapter {
|
|
|
4675
4845
|
}
|
|
4676
4846
|
};
|
|
4677
4847
|
|
|
4848
|
+
// src/adapters/cursor-acp/CursorACPAdapter.ts
|
|
4849
|
+
var DEFAULT_CURSOR_ACP_COMMAND = ["agent", "acp"];
|
|
4850
|
+
var DEFAULT_CURSOR_DECISION_TIMEOUT_MS = 3e5;
|
|
4851
|
+
var DEFAULT_CURSOR_MAX_PENDING_DECISIONS = 10;
|
|
4852
|
+
var CursorExtensions = class {
|
|
4853
|
+
adapter = null;
|
|
4854
|
+
todosBySession = /* @__PURE__ */ new Map();
|
|
4855
|
+
bind(adapter) {
|
|
4856
|
+
this.adapter = adapter;
|
|
4857
|
+
}
|
|
4858
|
+
async resolvePermission(request, signal) {
|
|
4859
|
+
return this.adapter?.resolveCursorPermission(request, signal);
|
|
4860
|
+
}
|
|
4861
|
+
extensionSessionId() {
|
|
4862
|
+
return this.adapter?.extensionSessionId() ?? null;
|
|
4863
|
+
}
|
|
4864
|
+
async extMethod(method, params, context) {
|
|
4865
|
+
return this.adapter?.resolveExtension(method, params, context.sessionId) ?? null;
|
|
4866
|
+
}
|
|
4867
|
+
async extNotification(method, params, context) {
|
|
4868
|
+
const sessionId = context.sessionId ?? this.extensionSessionId();
|
|
4869
|
+
if (!sessionId) {
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
if (method === "cursor/update_todos") {
|
|
4873
|
+
const content = this.updateTodos(sessionId, params);
|
|
4874
|
+
if (!content) {
|
|
4875
|
+
return;
|
|
4876
|
+
}
|
|
4877
|
+
return [{ chunkType: "plan", content, metadata: { cursor_todos: true }, streamed: false }];
|
|
4878
|
+
}
|
|
4879
|
+
if (method === "cursor/task") {
|
|
4880
|
+
const description = stringValue(params.description);
|
|
4881
|
+
if (!description) {
|
|
4882
|
+
return [];
|
|
4883
|
+
}
|
|
4884
|
+
const subagentType = stringValue(params.subagentType) ?? "unspecified";
|
|
4885
|
+
const model = stringValue(params.model);
|
|
4886
|
+
const suffix = model ? ` (${model})` : "";
|
|
4887
|
+
return [{ chunkType: "plan", content: `[Cursor ${subagentType} task] ${description}${suffix}`, metadata: {}, streamed: false }];
|
|
4888
|
+
}
|
|
4889
|
+
if (method === "cursor/generate_image") {
|
|
4890
|
+
const description = stringValue(params.description);
|
|
4891
|
+
if (!description) {
|
|
4892
|
+
return [];
|
|
4893
|
+
}
|
|
4894
|
+
const filePath = stringValue(params.filePath);
|
|
4895
|
+
return [{ chunkType: "plan", content: `[Cursor generated image] ${description}${filePath ? ` \u2192 ${filePath}` : ""}`, metadata: {}, streamed: false }];
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
forgetSession(sessionId) {
|
|
4899
|
+
this.todosBySession.delete(sessionId);
|
|
4900
|
+
}
|
|
4901
|
+
clearSessions() {
|
|
4902
|
+
this.todosBySession.clear();
|
|
4903
|
+
}
|
|
4904
|
+
updateTodos(sessionId, params) {
|
|
4905
|
+
const todos = parseTodos(params.todos);
|
|
4906
|
+
if (params.merge === true) {
|
|
4907
|
+
const current2 = this.todosBySession.get(sessionId) ?? /* @__PURE__ */ new Map();
|
|
4908
|
+
for (const todo of todos) {
|
|
4909
|
+
current2.set(todo.id, todo);
|
|
4910
|
+
}
|
|
4911
|
+
this.todosBySession.set(sessionId, current2);
|
|
4912
|
+
} else {
|
|
4913
|
+
this.todosBySession.set(sessionId, new Map(todos.map((todo) => [todo.id, todo])));
|
|
4914
|
+
}
|
|
4915
|
+
const current = this.todosBySession.get(sessionId);
|
|
4916
|
+
return current && current.size > 0 ? [...current.values()].map((todo) => `- [${todoMark(todo.status)}] ${todo.content}`).join("\n") : void 0;
|
|
4917
|
+
}
|
|
4918
|
+
};
|
|
4919
|
+
var CursorACPAdapter = class extends ACPClientAdapter {
|
|
4920
|
+
provider = "cursor-acp";
|
|
4921
|
+
approvalMode;
|
|
4922
|
+
questionMode;
|
|
4923
|
+
planMode;
|
|
4924
|
+
decisionTimeoutMs;
|
|
4925
|
+
maxPendingDecisions;
|
|
4926
|
+
authorizedSenders;
|
|
4927
|
+
decisionLogger;
|
|
4928
|
+
extensions;
|
|
4929
|
+
turns = /* @__PURE__ */ new Map();
|
|
4930
|
+
pending = /* @__PURE__ */ new Map();
|
|
4931
|
+
activeTurn = null;
|
|
4932
|
+
turnTail = Promise.resolve();
|
|
4933
|
+
constructor(options = {}) {
|
|
4934
|
+
const extensions = new CursorExtensions();
|
|
4935
|
+
validateOptions(options);
|
|
4936
|
+
const env = cursorEnv(options);
|
|
4937
|
+
super({
|
|
4938
|
+
...options,
|
|
4939
|
+
env,
|
|
4940
|
+
command: options.command ?? [...DEFAULT_CURSOR_ACP_COMMAND],
|
|
4941
|
+
authMethod: "cursor_login",
|
|
4942
|
+
extensionHandler: extensions,
|
|
4943
|
+
resolvePermission: (request, signal) => extensions.resolvePermission(request, signal)
|
|
4944
|
+
});
|
|
4945
|
+
extensions.bind(this);
|
|
4946
|
+
this.extensions = extensions;
|
|
4947
|
+
this.approvalMode = options.approvalMode ?? "manual";
|
|
4948
|
+
this.questionMode = options.questionMode ?? "manual";
|
|
4949
|
+
this.planMode = options.planMode ?? "manual";
|
|
4950
|
+
this.decisionTimeoutMs = options.decisionTimeoutMs ?? DEFAULT_CURSOR_DECISION_TIMEOUT_MS;
|
|
4951
|
+
this.maxPendingDecisions = options.maxPendingDecisions ?? DEFAULT_CURSOR_MAX_PENDING_DECISIONS;
|
|
4952
|
+
this.authorizedSenders = options.decisionAuthorizedSenders ? new Set(options.decisionAuthorizedSenders) : null;
|
|
4953
|
+
this.decisionLogger = resolveLogger(options.logger);
|
|
4954
|
+
}
|
|
4955
|
+
async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
|
|
4956
|
+
if (await this.handleControl(message, tools, context.roomId)) {
|
|
4957
|
+
return;
|
|
4958
|
+
}
|
|
4959
|
+
await this.withCursorTurnLock(() => super.onMessage(message, tools, history, participantsMessage, contactsMessage, context));
|
|
4960
|
+
}
|
|
4961
|
+
async onAcpTurnStarted(message, tools, context) {
|
|
4962
|
+
const turn = { messageId: message.id, roomId: context.roomId, tools, requesterId: message.senderId };
|
|
4963
|
+
this.turns.set(context.roomId, turn);
|
|
4964
|
+
this.activeTurn = turn;
|
|
4965
|
+
}
|
|
4966
|
+
async onAcpSessionReady(message, _tools, context, sessionId) {
|
|
4967
|
+
const turn = this.turns.get(context.roomId);
|
|
4968
|
+
if (turn?.messageId === message.id) {
|
|
4969
|
+
turn.sessionId = sessionId;
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
async onAcpTurnFinished(message, _tools, context) {
|
|
4973
|
+
const turn = this.turns.get(context.roomId);
|
|
4974
|
+
if (turn?.messageId === message.id) {
|
|
4975
|
+
this.turns.delete(context.roomId);
|
|
4976
|
+
this.cancelRoom(context.roomId);
|
|
4977
|
+
}
|
|
4978
|
+
if (this.activeTurn?.messageId === message.id) {
|
|
4979
|
+
this.activeTurn = null;
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
async onCleanup(roomId) {
|
|
4983
|
+
const sessionId = this.turns.get(roomId)?.sessionId;
|
|
4984
|
+
this.cancelRoom(roomId);
|
|
4985
|
+
this.turns.delete(roomId);
|
|
4986
|
+
if (this.activeTurn?.roomId === roomId) {
|
|
4987
|
+
this.activeTurn = null;
|
|
4988
|
+
}
|
|
4989
|
+
await super.onCleanup(roomId);
|
|
4990
|
+
if (sessionId) {
|
|
4991
|
+
this.extensions.forgetSession(sessionId);
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
async stop() {
|
|
4995
|
+
for (const decision of this.pending.values()) {
|
|
4996
|
+
decision.resolve(void 0);
|
|
4997
|
+
}
|
|
4998
|
+
this.pending.clear();
|
|
4999
|
+
this.turns.clear();
|
|
5000
|
+
this.activeTurn = null;
|
|
5001
|
+
this.extensions.clearSessions();
|
|
5002
|
+
await super.stop();
|
|
5003
|
+
}
|
|
5004
|
+
async resolveExtension(method, params, sessionId) {
|
|
5005
|
+
const roomId = sessionId ? this.roomIdForSession(sessionId) : this.activeTurn?.roomId;
|
|
5006
|
+
const turn = roomId ? this.turns.get(roomId) : void 0;
|
|
5007
|
+
if (!turn || sessionId && turn.sessionId !== sessionId) {
|
|
5008
|
+
return { outcome: { outcome: "cancelled" } };
|
|
5009
|
+
}
|
|
5010
|
+
if (method === "cursor/ask_question") {
|
|
5011
|
+
return this.resolveQuestion(turn.roomId, turn, params);
|
|
5012
|
+
}
|
|
5013
|
+
if (method === "cursor/create_plan") {
|
|
5014
|
+
return this.resolvePlan(turn.roomId, turn, params);
|
|
5015
|
+
}
|
|
5016
|
+
return {};
|
|
5017
|
+
}
|
|
5018
|
+
async resolveCursorPermission(request, signal) {
|
|
5019
|
+
if (this.approvalMode === "autoAccept") {
|
|
5020
|
+
return allowOption(request.options)?.optionId;
|
|
5021
|
+
}
|
|
5022
|
+
if (this.approvalMode === "autoDecline") {
|
|
5023
|
+
return void 0;
|
|
5024
|
+
}
|
|
5025
|
+
const turn = this.turns.get(request.roomId);
|
|
5026
|
+
if (!turn) {
|
|
5027
|
+
return void 0;
|
|
5028
|
+
}
|
|
5029
|
+
const options = request.options.map((option) => option.optionId);
|
|
5030
|
+
const token = await this.waitForDecision("permission", request.roomId, turn, /* @__PURE__ */ new Map([["permission", options]]), /* @__PURE__ */ new Set(), `Cursor needs permission. Reply \`/cursor select {token} option-id\` or \`/cursor deny {token}\`.`, signal);
|
|
5031
|
+
return typeof token === "string" && options.includes(token) ? token : void 0;
|
|
5032
|
+
}
|
|
5033
|
+
extensionSessionId() {
|
|
5034
|
+
return this.activeTurn?.sessionId ?? null;
|
|
5035
|
+
}
|
|
5036
|
+
async resolveQuestion(roomId, turn, params) {
|
|
5037
|
+
const questions = questionChoices(params.questions);
|
|
5038
|
+
if (questions.choices.size === 0) {
|
|
5039
|
+
return { outcome: { outcome: "cancelled" } };
|
|
5040
|
+
}
|
|
5041
|
+
if (this.questionMode === "autoCancel") {
|
|
5042
|
+
return { outcome: { outcome: "cancelled" } };
|
|
5043
|
+
}
|
|
5044
|
+
if (this.questionMode === "autoFirst") {
|
|
5045
|
+
return answered(Object.fromEntries([...questions.choices].map(([id, options]) => [id, [options[0]]])));
|
|
5046
|
+
}
|
|
5047
|
+
const result = await this.waitForDecision("question", roomId, turn, questions.choices, questions.multiSelect, "Cursor needs input. Reply `/cursor answer {token} question-id=option-id[,option-id] ...`.");
|
|
5048
|
+
return isRecord(result) ? result : { outcome: { outcome: "cancelled" } };
|
|
5049
|
+
}
|
|
5050
|
+
async resolvePlan(roomId, turn, params) {
|
|
5051
|
+
if (this.planMode === "autoAccept") {
|
|
5052
|
+
return { outcome: { outcome: "accepted" } };
|
|
5053
|
+
}
|
|
5054
|
+
if (this.planMode === "autoDecline") {
|
|
5055
|
+
return { outcome: { outcome: "rejected" } };
|
|
5056
|
+
}
|
|
5057
|
+
const title = stringValue(params.title) ?? "Cursor plan";
|
|
5058
|
+
const result = await this.waitForDecision("plan", roomId, turn, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Set(), `${title} needs approval. Reply \`/cursor accept {token}\` or \`/cursor reject {token}\`.`);
|
|
5059
|
+
return isRecord(result) ? result : { outcome: { outcome: "cancelled" } };
|
|
5060
|
+
}
|
|
5061
|
+
async waitForDecision(kind, roomId, turn, choices, multiSelect, prompt, signal) {
|
|
5062
|
+
if (this.pending.size >= this.maxPendingDecisions) {
|
|
5063
|
+
this.pending.values().next().value?.resolve(void 0);
|
|
5064
|
+
}
|
|
5065
|
+
const token = crypto.randomUUID().slice(0, 8);
|
|
5066
|
+
return new Promise((resolve) => {
|
|
5067
|
+
const timer = setTimeout(() => settle(void 0), this.decisionTimeoutMs);
|
|
5068
|
+
const abort = () => settle(void 0);
|
|
5069
|
+
const settle = (value) => {
|
|
5070
|
+
clearTimeout(timer);
|
|
5071
|
+
signal?.removeEventListener("abort", abort);
|
|
5072
|
+
this.pending.delete(token);
|
|
5073
|
+
resolve(value);
|
|
5074
|
+
};
|
|
5075
|
+
this.pending.set(token, { kind, roomId, choices, multiSelect, resolve: settle });
|
|
5076
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
5077
|
+
void turn.tools.sendMessage(prompt.replaceAll("{token}", token), [turn.requesterId]).catch((error) => {
|
|
5078
|
+
this.decisionLogger.warn("cursor_acp.decision_prompt_delivery_failed", { roomId, kind, error: String(error) });
|
|
5079
|
+
settle(void 0);
|
|
5080
|
+
});
|
|
5081
|
+
});
|
|
5082
|
+
}
|
|
5083
|
+
async handleControl(message, tools, roomId) {
|
|
5084
|
+
const words = message.content.trim().split(/\s+/);
|
|
5085
|
+
if (words[0]?.toLowerCase() !== "/cursor") {
|
|
5086
|
+
return false;
|
|
5087
|
+
}
|
|
5088
|
+
if (words.length === 1 || words[1]?.toLowerCase() === "decisions") {
|
|
5089
|
+
const entries = [...this.pending.entries()].filter(([, decision2]) => decision2.roomId === roomId).map(([token2, decision2]) => `\`${token2}\` (${decision2.kind})`);
|
|
5090
|
+
await tools.sendMessage(`Pending Cursor decisions: ${entries.join(", ") || "none"}`);
|
|
5091
|
+
return true;
|
|
5092
|
+
}
|
|
5093
|
+
const [_, action, token, ...args] = words;
|
|
5094
|
+
const decision = token ? this.pending.get(token) : void 0;
|
|
5095
|
+
if (!decision || decision.roomId !== roomId) {
|
|
5096
|
+
await tools.sendMessage(`Cursor decision \`${token ?? ""}\` is not pending.`);
|
|
5097
|
+
return true;
|
|
5098
|
+
}
|
|
5099
|
+
if (this.authorizedSenders && !this.authorizedSenders.has(message.senderId)) {
|
|
5100
|
+
await tools.sendMessage("You are not authorized to resolve Cursor decisions.");
|
|
5101
|
+
return true;
|
|
5102
|
+
}
|
|
5103
|
+
const result = commandResult(action ?? "", args, decision);
|
|
5104
|
+
if (result === null) {
|
|
5105
|
+
await tools.sendMessage(`That command is not valid for Cursor ${decision.kind} decision \`${token}\`.`);
|
|
5106
|
+
return true;
|
|
5107
|
+
}
|
|
5108
|
+
decision.resolve(result);
|
|
5109
|
+
await tools.sendMessage(`Cursor ${decision.kind} decision \`${token}\` resolved.`);
|
|
5110
|
+
return true;
|
|
5111
|
+
}
|
|
5112
|
+
cancelRoom(roomId) {
|
|
5113
|
+
for (const [token, decision] of this.pending) {
|
|
5114
|
+
if (decision.roomId === roomId) {
|
|
5115
|
+
decision.resolve(void 0);
|
|
5116
|
+
this.pending.delete(token);
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
async withCursorTurnLock(run) {
|
|
5121
|
+
const queued = this.turnTail.then(run, run);
|
|
5122
|
+
this.turnTail = queued.then(() => void 0, () => void 0);
|
|
5123
|
+
return queued;
|
|
5124
|
+
}
|
|
5125
|
+
};
|
|
5126
|
+
function cursorEnv(options) {
|
|
5127
|
+
const env = { ...options.env };
|
|
5128
|
+
if (options.apiKey) env.CURSOR_API_KEY ??= options.apiKey;
|
|
5129
|
+
if (options.authToken) env.CURSOR_AUTH_TOKEN ??= options.authToken;
|
|
5130
|
+
return Object.keys(env).length > 0 ? env : void 0;
|
|
5131
|
+
}
|
|
5132
|
+
function validateOptions(options) {
|
|
5133
|
+
if (options.apiKey && options.authToken) throw new Error("set either apiKey or authToken, not both");
|
|
5134
|
+
if (Array.isArray(options.command) && options.command.length === 0) throw new Error("Cursor ACP command must not be empty");
|
|
5135
|
+
if (options.decisionTimeoutMs !== void 0 && (!Number.isFinite(options.decisionTimeoutMs) || options.decisionTimeoutMs <= 0)) throw new Error("decisionTimeoutMs must be a positive finite number");
|
|
5136
|
+
if (options.maxPendingDecisions !== void 0 && (!Number.isInteger(options.maxPendingDecisions) || options.maxPendingDecisions <= 0)) throw new Error("maxPendingDecisions must be a positive integer");
|
|
5137
|
+
}
|
|
5138
|
+
function allowOption(options) {
|
|
5139
|
+
return options.find((option) => option.kind === "allow_once") ?? options.find((option) => option.kind === "allow_always");
|
|
5140
|
+
}
|
|
5141
|
+
function questionChoices(value) {
|
|
5142
|
+
const choices = /* @__PURE__ */ new Map();
|
|
5143
|
+
const multiSelect = /* @__PURE__ */ new Set();
|
|
5144
|
+
if (!Array.isArray(value)) return { choices, multiSelect };
|
|
5145
|
+
for (const question of value) {
|
|
5146
|
+
if (!isRecord(question) || typeof question.id !== "string" || !Array.isArray(question.options)) continue;
|
|
5147
|
+
const options = question.options.filter(isRecord).map((option) => stringValue(option.id)).filter((id) => !!id);
|
|
5148
|
+
if (options.length === 0) continue;
|
|
5149
|
+
choices.set(question.id, options);
|
|
5150
|
+
if (question.allowMultiple === true) multiSelect.add(question.id);
|
|
5151
|
+
}
|
|
5152
|
+
return { choices, multiSelect };
|
|
5153
|
+
}
|
|
5154
|
+
function commandResult(action, args, decision) {
|
|
5155
|
+
if (decision.kind === "permission") return action === "deny" ? void 0 : action === "select" && args.length === 1 && decision.choices.get("permission")?.includes(args[0] ?? "") ? args[0] : null;
|
|
5156
|
+
if (decision.kind === "plan") return action === "accept" ? { outcome: { outcome: "accepted" } } : action === "reject" ? { outcome: { outcome: "rejected" } } : null;
|
|
5157
|
+
if (action !== "answer") return null;
|
|
5158
|
+
const selected = {};
|
|
5159
|
+
for (const argument of args) {
|
|
5160
|
+
const [id, raw] = argument.split("=", 2);
|
|
5161
|
+
const values = raw?.split(",") ?? [];
|
|
5162
|
+
const offered = id ? decision.choices.get(id) : void 0;
|
|
5163
|
+
if (!id || !offered || selected[id] || values.length === 0 || values.length > 1 && !decision.multiSelect.has(id) || values.some((value) => !offered.includes(value))) return null;
|
|
5164
|
+
selected[id] = values;
|
|
5165
|
+
}
|
|
5166
|
+
return Object.keys(selected).length === decision.choices.size ? answered(selected) : null;
|
|
5167
|
+
}
|
|
5168
|
+
function answered(selected) {
|
|
5169
|
+
return { outcome: { outcome: "answered", answers: Object.entries(selected).map(([questionId, selectedOptionIds]) => ({ questionId, selectedOptionIds })) } };
|
|
5170
|
+
}
|
|
5171
|
+
function parseTodos(value) {
|
|
5172
|
+
if (!Array.isArray(value)) return [];
|
|
5173
|
+
return value.flatMap((todo) => {
|
|
5174
|
+
if (!isRecord(todo)) return [];
|
|
5175
|
+
const id = stringValue(todo.id);
|
|
5176
|
+
const content = stringValue(todo.content);
|
|
5177
|
+
const status = stringValue(todo.status);
|
|
5178
|
+
return id && content && status ? [{ id, content, status }] : [];
|
|
5179
|
+
});
|
|
5180
|
+
}
|
|
5181
|
+
function todoMark(status) {
|
|
5182
|
+
switch (status) {
|
|
5183
|
+
case "completed":
|
|
5184
|
+
return "x";
|
|
5185
|
+
case "in_progress":
|
|
5186
|
+
return "~";
|
|
5187
|
+
case "cancelled":
|
|
5188
|
+
return "-";
|
|
5189
|
+
default:
|
|
5190
|
+
return " ";
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
function isRecord(value) {
|
|
5194
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5195
|
+
}
|
|
5196
|
+
function stringValue(value) {
|
|
5197
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
5198
|
+
}
|
|
5199
|
+
|
|
4678
5200
|
// src/adapters/tool-calling/ToolCallingAdapter.ts
|
|
4679
5201
|
init_protocols();
|
|
4680
5202
|
|
|
@@ -7102,20 +7624,20 @@ function unwrapResult(value, depth = 0) {
|
|
|
7102
7624
|
}
|
|
7103
7625
|
return event;
|
|
7104
7626
|
}
|
|
7105
|
-
function
|
|
7627
|
+
function isRecord2(value) {
|
|
7106
7628
|
return typeof value === "object" && value !== null;
|
|
7107
7629
|
}
|
|
7108
7630
|
function isOptionalString(value) {
|
|
7109
7631
|
return value === void 0 || typeof value === "string";
|
|
7110
7632
|
}
|
|
7111
7633
|
function isMessagePart(value) {
|
|
7112
|
-
if (!
|
|
7634
|
+
if (!isRecord2(value)) {
|
|
7113
7635
|
return false;
|
|
7114
7636
|
}
|
|
7115
7637
|
return isOptionalString(value.kind) && isOptionalString(value.type) && isOptionalString(value.text) && (value.root === void 0 || isMessagePart(value.root));
|
|
7116
7638
|
}
|
|
7117
7639
|
function isMessageLike(value) {
|
|
7118
|
-
if (!
|
|
7640
|
+
if (!isRecord2(value)) {
|
|
7119
7641
|
return false;
|
|
7120
7642
|
}
|
|
7121
7643
|
if (!isOptionalString(value.kind) || !isOptionalString(value.role)) {
|
|
@@ -7130,7 +7652,7 @@ function isMessageLike(value) {
|
|
|
7130
7652
|
return Array.isArray(value.parts) && value.parts.every((part) => isMessagePart(part));
|
|
7131
7653
|
}
|
|
7132
7654
|
function isStatusLike(value) {
|
|
7133
|
-
if (!
|
|
7655
|
+
if (!isRecord2(value)) {
|
|
7134
7656
|
return false;
|
|
7135
7657
|
}
|
|
7136
7658
|
if (!isOptionalString(value.state)) {
|
|
@@ -7139,7 +7661,7 @@ function isStatusLike(value) {
|
|
|
7139
7661
|
return value.message === void 0 || isMessageLike(value.message);
|
|
7140
7662
|
}
|
|
7141
7663
|
function isArtifactLike(value) {
|
|
7142
|
-
if (!
|
|
7664
|
+
if (!isRecord2(value)) {
|
|
7143
7665
|
return false;
|
|
7144
7666
|
}
|
|
7145
7667
|
if (value.parts === void 0) {
|
|
@@ -7148,19 +7670,19 @@ function isArtifactLike(value) {
|
|
|
7148
7670
|
return Array.isArray(value.parts) && value.parts.every((part) => isMessagePart(part));
|
|
7149
7671
|
}
|
|
7150
7672
|
function isMessageEvent(event) {
|
|
7151
|
-
return
|
|
7673
|
+
return isRecord2(event) && event.kind === "message" && isMessageLike(event) && Array.isArray(event.parts);
|
|
7152
7674
|
}
|
|
7153
7675
|
function isTaskEvent(event) {
|
|
7154
|
-
if (!
|
|
7676
|
+
if (!isRecord2(event) || event.kind !== "task") {
|
|
7155
7677
|
return false;
|
|
7156
7678
|
}
|
|
7157
7679
|
return typeof event.id === "string" && isOptionalString(event.contextId) && isStatusLike(event.status) && (event.artifacts === void 0 || Array.isArray(event.artifacts) && event.artifacts.every((item) => isArtifactLike(item))) && (event.history === void 0 || Array.isArray(event.history) && event.history.every((item) => isMessageLike(item)));
|
|
7158
7680
|
}
|
|
7159
7681
|
function isStatusUpdateEvent(event) {
|
|
7160
|
-
return
|
|
7682
|
+
return isRecord2(event) && event.kind === "status-update" && typeof event.taskId === "string" && typeof event.contextId === "string" && isStatusLike(event.status);
|
|
7161
7683
|
}
|
|
7162
7684
|
function isArtifactUpdateEvent(event) {
|
|
7163
|
-
return
|
|
7685
|
+
return isRecord2(event) && event.kind === "artifact-update" && typeof event.taskId === "string" && typeof event.contextId === "string" && isArtifactLike(event.artifact);
|
|
7164
7686
|
}
|
|
7165
7687
|
async function loadDefaultA2AClientFactory() {
|
|
7166
7688
|
let module2;
|
|
@@ -9800,7 +10322,7 @@ var SdkOpencodeClientBase = class {
|
|
|
9800
10322
|
{ signal: this.eventsAbortController.signal }
|
|
9801
10323
|
);
|
|
9802
10324
|
for await (const event of events.stream) {
|
|
9803
|
-
if (
|
|
10325
|
+
if (isRecord3(event)) {
|
|
9804
10326
|
yield event;
|
|
9805
10327
|
}
|
|
9806
10328
|
}
|
|
@@ -9918,7 +10440,7 @@ function optionalString(value) {
|
|
|
9918
10440
|
const trimmed = value.trim();
|
|
9919
10441
|
return trimmed.length > 0 ? trimmed : null;
|
|
9920
10442
|
}
|
|
9921
|
-
function
|
|
10443
|
+
function isRecord3(value) {
|
|
9922
10444
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
9923
10445
|
}
|
|
9924
10446
|
function getResultBody(result) {
|
|
@@ -9928,7 +10450,7 @@ function expectRecord(result) {
|
|
|
9928
10450
|
if (!result.response.ok) {
|
|
9929
10451
|
throw new HttpStatusError(result.response.status, getResultBody(result));
|
|
9930
10452
|
}
|
|
9931
|
-
return
|
|
10453
|
+
return isRecord3(result.data) ? result.data : {};
|
|
9932
10454
|
}
|
|
9933
10455
|
async function expectVoid(resultPromise) {
|
|
9934
10456
|
const result = await resultPromise;
|
|
@@ -12864,6 +13386,7 @@ function parseModelListResponse(value) {
|
|
|
12864
13386
|
A2AHistoryConverter,
|
|
12865
13387
|
ACPClientAdapter,
|
|
12866
13388
|
ACPServer,
|
|
13389
|
+
AcpSessionConfigError,
|
|
12867
13390
|
AnthropicAdapter,
|
|
12868
13391
|
AnthropicToolCallingModel,
|
|
12869
13392
|
BandACPServerAdapter,
|
|
@@ -12875,8 +13398,11 @@ function parseModelListResponse(value) {
|
|
|
12875
13398
|
CodexAppServerStdioClient,
|
|
12876
13399
|
CodexJsonRpcError,
|
|
12877
13400
|
CopilotACPAdapter,
|
|
13401
|
+
CursorACPAdapter,
|
|
12878
13402
|
DEFAULT_COPILOT_ACP_COMMAND,
|
|
13403
|
+
DEFAULT_CURSOR_ACP_COMMAND,
|
|
12879
13404
|
DEFAULT_OMP_ACP_COMMAND,
|
|
13405
|
+
FAILURE_CODE_SESSION_CONFIG,
|
|
12880
13406
|
GatewayHistoryConverter,
|
|
12881
13407
|
GatewayServer,
|
|
12882
13408
|
GeminiAdapter,
|
|
@@ -12888,6 +13414,7 @@ function parseModelListResponse(value) {
|
|
|
12888
13414
|
LangGraphAdapter,
|
|
12889
13415
|
LettaAdapter,
|
|
12890
13416
|
LettaHistoryConverter,
|
|
13417
|
+
MISSING_CONFIG_OPTIONS_REASON,
|
|
12891
13418
|
OmpACPAdapter,
|
|
12892
13419
|
OpenAIAdapter,
|
|
12893
13420
|
OpenAIToolCallingModel,
|
|
@@ -12897,6 +13424,7 @@ function parseModelListResponse(value) {
|
|
|
12897
13424
|
ToolCallingAdapter,
|
|
12898
13425
|
VercelAISDKAdapter,
|
|
12899
13426
|
VercelAISDKToolCallingModel,
|
|
13427
|
+
applySessionConfigSelections,
|
|
12900
13428
|
buildA2AAuthHeaders,
|
|
12901
13429
|
createGatewayServer,
|
|
12902
13430
|
runSingleToolRound
|