@band-ai/sdk 0.2.0 → 0.3.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/{ClaudeSDKAdapter-Cna5P1dR.d.ts → ClaudeSDKAdapter-CXud2DBE.d.ts} +2 -1
- package/dist/{ClaudeSDKAdapter-BY4zEbCl.d.cts → ClaudeSDKAdapter-Cx6zhSaG.d.cts} +2 -1
- package/dist/adapters.cjs +347 -172
- package/dist/adapters.d.cts +22 -5
- package/dist/adapters.d.ts +22 -5
- package/dist/adapters.js +204 -60
- package/dist/chunk-F63TPOI3.js +29 -0
- package/dist/{chunk-3BKAC4OZ.js → chunk-JADCAMZY.js} +8 -0
- package/dist/{chunk-N2QTUMGO.js → chunk-JJF44XWA.js} +365 -249
- package/dist/{chunk-TLBCKDQO.js → chunk-K5KAEYPF.js} +2 -2
- package/dist/{chunk-ZZJRRBPQ.js → chunk-KXJ74J73.js} +1 -1
- package/dist/{chunk-NMZLX7TP.js → chunk-MQBBWYRP.js} +52 -45
- package/dist/{chunk-RV76SKFT.js → chunk-MQY74R7D.js} +2 -20
- package/dist/{chunk-LBWKISBS.js → chunk-OH6VVVKT.js} +21 -0
- package/dist/{chunk-EAI2M3WM.js → chunk-W5IAI6Z4.js} +1 -1
- package/dist/{chunk-4IAXZBXX.js → chunk-WA7CHXUS.js} +2 -2
- package/dist/{chunk-NT7TBFX2.js → chunk-XWHWJP4I.js} +2 -2
- package/dist/{chunk-WLCM2OXG.js → chunk-YJ42AZO4.js} +1 -1
- package/dist/converters.js +6 -5
- package/dist/index.cjs +405 -277
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +12 -11
- package/dist/mcp-claude.js +4 -3
- package/dist/mcp.js +5 -4
- package/dist/rest.js +3 -3
- package/dist/runtime.cjs +387 -362
- package/dist/runtime.d.cts +10 -39
- package/dist/runtime.d.ts +10 -39
- package/dist/runtime.js +20 -142
- package/dist/{schemas-BotL3ZLH.d.cts → schemas-BgJhlqqO.d.cts} +57 -13
- package/dist/{schemas-DBsC4J1g.d.ts → schemas-C4mK1WSs.d.ts} +57 -13
- package/dist/testing.cjs +11 -0
- package/dist/testing.js +8 -1
- package/dist/{types-D958TC71.d.cts → types-BNNtOXu3.d.cts} +1 -1
- package/dist/{types-BTN_ZETM.d.ts → types-DFUtpxah.d.ts} +1 -1
- package/package.json +2 -2
package/dist/adapters.cjs
CHANGED
|
@@ -30,6 +30,38 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
+
// src/core/errors.ts
|
|
34
|
+
var BandSdkError, UnsupportedFeatureError, ValidationError, RuntimeStateError;
|
|
35
|
+
var init_errors = __esm({
|
|
36
|
+
"src/core/errors.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
BandSdkError = class extends Error {
|
|
39
|
+
constructor(message, cause) {
|
|
40
|
+
super(message, cause !== void 0 ? { cause } : void 0);
|
|
41
|
+
this.name = "BandSdkError";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
UnsupportedFeatureError = class extends BandSdkError {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "UnsupportedFeatureError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
ValidationError = class extends BandSdkError {
|
|
51
|
+
constructor(message, cause) {
|
|
52
|
+
super(message, cause);
|
|
53
|
+
this.name = "ValidationError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
RuntimeStateError = class extends BandSdkError {
|
|
57
|
+
constructor(message) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "RuntimeStateError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
33
65
|
// src/contracts/memory.ts
|
|
34
66
|
function namedValues(values) {
|
|
35
67
|
return Object.fromEntries(values.map((value) => [value, value]));
|
|
@@ -108,46 +140,18 @@ var init_memory = __esm({
|
|
|
108
140
|
}
|
|
109
141
|
});
|
|
110
142
|
|
|
111
|
-
// src/core/errors.ts
|
|
112
|
-
var BandSdkError, UnsupportedFeatureError, ValidationError, RuntimeStateError;
|
|
113
|
-
var init_errors = __esm({
|
|
114
|
-
"src/core/errors.ts"() {
|
|
115
|
-
"use strict";
|
|
116
|
-
BandSdkError = class extends Error {
|
|
117
|
-
constructor(message, cause) {
|
|
118
|
-
super(message, cause !== void 0 ? { cause } : void 0);
|
|
119
|
-
this.name = "BandSdkError";
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
UnsupportedFeatureError = class extends BandSdkError {
|
|
123
|
-
constructor(message) {
|
|
124
|
-
super(message);
|
|
125
|
-
this.name = "UnsupportedFeatureError";
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
ValidationError = class extends BandSdkError {
|
|
129
|
-
constructor(message, cause) {
|
|
130
|
-
super(message, cause);
|
|
131
|
-
this.name = "ValidationError";
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
RuntimeStateError = class extends BandSdkError {
|
|
135
|
-
constructor(message) {
|
|
136
|
-
super(message);
|
|
137
|
-
this.name = "RuntimeStateError";
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
143
|
// src/contracts/chatEvents.ts
|
|
144
|
-
|
|
144
|
+
function isBlankEventContent(content) {
|
|
145
|
+
return !VISIBLE_CONTENT_PATTERN.test(content);
|
|
146
|
+
}
|
|
147
|
+
var CHAT_EVENT_TYPES, CHAT_MESSAGE_TYPES, VISIBLE_CONTENT_PATTERN;
|
|
145
148
|
var init_chatEvents = __esm({
|
|
146
149
|
"src/contracts/chatEvents.ts"() {
|
|
147
150
|
"use strict";
|
|
148
151
|
init_errors();
|
|
149
152
|
CHAT_EVENT_TYPES = ["tool_call", "tool_result", "thought", "error", "task"];
|
|
150
153
|
CHAT_MESSAGE_TYPES = ["text", ...CHAT_EVENT_TYPES];
|
|
154
|
+
VISIBLE_CONTENT_PATTERN = /[\p{L}\p{N}\p{P}\p{S}]/u;
|
|
151
155
|
}
|
|
152
156
|
});
|
|
153
157
|
|
|
@@ -496,6 +500,13 @@ function isToolExecutorError(value) {
|
|
|
496
500
|
const candidate = value;
|
|
497
501
|
return candidate.ok === false && typeof candidate.errorType === "string" && TOOL_EXECUTOR_ERROR_TYPES.includes(candidate.errorType) && typeof candidate.toolName === "string" && typeof candidate.message === "string" && typeof candidate.legacyMessage === "string";
|
|
498
502
|
}
|
|
503
|
+
function isStructuredToolFailure(value) {
|
|
504
|
+
if (!value || typeof value !== "object") {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
const payload = value;
|
|
508
|
+
return payload.ok === false && typeof payload.message === "string";
|
|
509
|
+
}
|
|
499
510
|
function toLegacyToolExecutorErrorMessage(value) {
|
|
500
511
|
if (typeof value === "string") {
|
|
501
512
|
return value;
|
|
@@ -1066,6 +1077,18 @@ var ACPClientHistoryConverter = class {
|
|
|
1066
1077
|
}
|
|
1067
1078
|
};
|
|
1068
1079
|
|
|
1080
|
+
// src/core/logger.ts
|
|
1081
|
+
var noop = () => void 0;
|
|
1082
|
+
var NoopLogger = class {
|
|
1083
|
+
debug = noop;
|
|
1084
|
+
info = noop;
|
|
1085
|
+
warn = noop;
|
|
1086
|
+
error = noop;
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
// src/adapters/acp/ACPClientAdapter.ts
|
|
1090
|
+
init_errors();
|
|
1091
|
+
|
|
1069
1092
|
// src/runtime/prompts/base.ts
|
|
1070
1093
|
var ENVIRONMENT_SECTION = `
|
|
1071
1094
|
## Environment
|
|
@@ -1234,7 +1257,116 @@ ${customSection}`.trim();
|
|
|
1234
1257
|
return parts.join("\n\n");
|
|
1235
1258
|
}
|
|
1236
1259
|
|
|
1260
|
+
// src/runtime/types.ts
|
|
1261
|
+
function ensureHandlePrefix(handle) {
|
|
1262
|
+
if (!handle) {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
return handle.startsWith("@") ? handle : `@${handle}`;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// src/runtime/formatters.ts
|
|
1269
|
+
function isMetadataMap(value) {
|
|
1270
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1271
|
+
}
|
|
1272
|
+
function mentionSubjectsFromMetadata(metadata) {
|
|
1273
|
+
const mentions = metadata?.mentions;
|
|
1274
|
+
if (!Array.isArray(mentions)) {
|
|
1275
|
+
return [];
|
|
1276
|
+
}
|
|
1277
|
+
const subjects = [];
|
|
1278
|
+
for (const mention of mentions) {
|
|
1279
|
+
if (!isMetadataMap(mention) || typeof mention.id !== "string") {
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
const label = [mention.handle, mention.username, mention.name].find(
|
|
1283
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
1284
|
+
);
|
|
1285
|
+
if (label === void 0) {
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
subjects.push({ id: mention.id, handle: label });
|
|
1289
|
+
}
|
|
1290
|
+
return subjects;
|
|
1291
|
+
}
|
|
1292
|
+
function replaceUuidMentions(content, participants) {
|
|
1293
|
+
if (!content || participants.length === 0) {
|
|
1294
|
+
return content;
|
|
1295
|
+
}
|
|
1296
|
+
let next = content;
|
|
1297
|
+
for (const participant of participants) {
|
|
1298
|
+
const participantId = participant.id;
|
|
1299
|
+
const handle = participant.handle;
|
|
1300
|
+
if (typeof participantId === "string" && typeof handle === "string") {
|
|
1301
|
+
next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return next;
|
|
1305
|
+
}
|
|
1306
|
+
function formatMessageForLlm(message, participants) {
|
|
1307
|
+
const senderType = String(message.sender_type ?? "");
|
|
1308
|
+
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
1309
|
+
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
1310
|
+
return {
|
|
1311
|
+
role: senderType === "Agent" ? "assistant" : "user",
|
|
1312
|
+
content,
|
|
1313
|
+
sender_name: senderName,
|
|
1314
|
+
sender_type: senderType,
|
|
1315
|
+
message_type: String(message.message_type ?? "text"),
|
|
1316
|
+
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
function formatHistoryForLlm(messages, options) {
|
|
1320
|
+
const excludeId = options?.excludeId;
|
|
1321
|
+
const participants = options?.participants;
|
|
1322
|
+
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// src/adapters/shared/conversationPrompt.ts
|
|
1326
|
+
function systemUpdateParts(participantsMessage, contactsMessage) {
|
|
1327
|
+
const parts = [];
|
|
1328
|
+
if (participantsMessage) {
|
|
1329
|
+
parts.push(`[System]: ${participantsMessage}`);
|
|
1330
|
+
}
|
|
1331
|
+
if (contactsMessage) {
|
|
1332
|
+
parts.push(`[System]: ${contactsMessage}`);
|
|
1333
|
+
}
|
|
1334
|
+
return parts;
|
|
1335
|
+
}
|
|
1336
|
+
function buildConversationPrompt(options) {
|
|
1337
|
+
const parts = [];
|
|
1338
|
+
if (options.isSessionBootstrap && options.history.length > 0) {
|
|
1339
|
+
const historyText = options.history.raw.slice(-(options.maxHistoryMessages ?? 50)).map(formatHistoryLine).join("\n");
|
|
1340
|
+
parts.push(`${options.historyHeader}
|
|
1341
|
+
${historyText}`);
|
|
1342
|
+
}
|
|
1343
|
+
parts.push(...systemUpdateParts(options.participantsMessage, options.contactsMessage));
|
|
1344
|
+
parts.push(options.currentMessage);
|
|
1345
|
+
return parts.join("\n\n");
|
|
1346
|
+
}
|
|
1347
|
+
function formatHistoryLine(entry) {
|
|
1348
|
+
const sender = String(entry.sender_name ?? entry.sender_type ?? "Unknown");
|
|
1349
|
+
const content = String(entry.content ?? "");
|
|
1350
|
+
return `[${sender}]: ${content}`;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// src/adapters/shared/withTimeout.ts
|
|
1354
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
1355
|
+
let timer;
|
|
1356
|
+
try {
|
|
1357
|
+
return await Promise.race([
|
|
1358
|
+
promise,
|
|
1359
|
+
new Promise((_, reject) => {
|
|
1360
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
1361
|
+
})
|
|
1362
|
+
]);
|
|
1363
|
+
} finally {
|
|
1364
|
+
clearTimeout(timer);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1237
1368
|
// src/adapters/acp/ACPClientAdapter.ts
|
|
1369
|
+
init_chatEvents();
|
|
1238
1370
|
init_schemas();
|
|
1239
1371
|
|
|
1240
1372
|
// src/mcp/auth.ts
|
|
@@ -2016,6 +2148,8 @@ var acpModule = new LazyAsyncValue({
|
|
|
2016
2148
|
});
|
|
2017
2149
|
|
|
2018
2150
|
// src/adapters/acp/ACPClientAdapter.ts
|
|
2151
|
+
var DEFAULT_PERMISSION_TIMEOUT_MS = 5 * 6e4;
|
|
2152
|
+
var SET_SESSION_MODE_TIMEOUT_MS = 1e4;
|
|
2019
2153
|
var ACPClientAdapter = class extends SimpleAdapter {
|
|
2020
2154
|
command;
|
|
2021
2155
|
cwd;
|
|
@@ -2031,6 +2165,11 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2031
2165
|
roomTools = /* @__PURE__ */ new Map();
|
|
2032
2166
|
activeSessions = /* @__PURE__ */ new Set();
|
|
2033
2167
|
bootstrappedSessions = /* @__PURE__ */ new Set();
|
|
2168
|
+
pendingPermissions = /* @__PURE__ */ new Map();
|
|
2169
|
+
resolvePermission;
|
|
2170
|
+
permissionTimeoutMs;
|
|
2171
|
+
requestedPermissionMode;
|
|
2172
|
+
logger;
|
|
2034
2173
|
backend = null;
|
|
2035
2174
|
backendPromise = null;
|
|
2036
2175
|
client = null;
|
|
@@ -2057,6 +2196,16 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2057
2196
|
this.additionalMcpTools = [...options.additionalMcpTools ?? []];
|
|
2058
2197
|
this.clientCapabilities = options.clientCapabilities;
|
|
2059
2198
|
this.connectionFactory = options.connectionFactory ?? createSubprocessConnection;
|
|
2199
|
+
this.resolvePermission = options.resolvePermission;
|
|
2200
|
+
this.logger = options.logger ?? new NoopLogger();
|
|
2201
|
+
this.permissionTimeoutMs = options.permissionTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
2202
|
+
this.requestedPermissionMode = options.requestedPermissionMode;
|
|
2203
|
+
if (this.requestedPermissionMode !== void 0 && this.requestedPermissionMode.length === 0) {
|
|
2204
|
+
throw new ValidationError("requestedPermissionMode must be a non-empty mode id, got an empty string");
|
|
2205
|
+
}
|
|
2206
|
+
if (this.resolvePermission && (!Number.isFinite(this.permissionTimeoutMs) || this.permissionTimeoutMs <= 0)) {
|
|
2207
|
+
throw new ValidationError(`permissionTimeoutMs must be a positive finite number, got ${options.permissionTimeoutMs}`);
|
|
2208
|
+
}
|
|
2060
2209
|
}
|
|
2061
2210
|
async onStarted(agentName, agentDescription) {
|
|
2062
2211
|
await super.onStarted(agentName, agentDescription);
|
|
@@ -2068,7 +2217,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2068
2217
|
});
|
|
2069
2218
|
await this.ensureConnection();
|
|
2070
2219
|
}
|
|
2071
|
-
async onMessage(message, tools, history,
|
|
2220
|
+
async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
|
|
2072
2221
|
if (context.isSessionBootstrap) {
|
|
2073
2222
|
this.rehydrate(history);
|
|
2074
2223
|
}
|
|
@@ -2084,9 +2233,11 @@ var ACPClientAdapter = class extends SimpleAdapter {
|
|
|
2084
2233
|
sessionId,
|
|
2085
2234
|
(params) => this.handlePermissionRequest(tools, context.roomId, params)
|
|
2086
2235
|
);
|
|
2087
|
-
const
|
|
2236
|
+
const content = replaceUuidMentions(message.content, mentionSubjectsFromMetadata(message.metadata));
|
|
2237
|
+
const messageWithContext = [...systemUpdateParts(participantsMessage, contactsMessage), content].join("\n\n");
|
|
2238
|
+
const promptText = this.bootstrappedSessions.has(sessionId) ? messageWithContext : `${this.buildSystemContext(context.roomId, message)}
|
|
2088
2239
|
|
|
2089
|
-
${
|
|
2240
|
+
${messageWithContext}`;
|
|
2090
2241
|
this.bootstrappedSessions.add(sessionId);
|
|
2091
2242
|
try {
|
|
2092
2243
|
await connection.prompt({
|
|
@@ -2122,6 +2273,7 @@ ${message.content}`;
|
|
|
2122
2273
|
this.activeSessions.delete(sessionId);
|
|
2123
2274
|
this.bootstrappedSessions.delete(sessionId);
|
|
2124
2275
|
this.client?.setPermissionHandler(sessionId, void 0);
|
|
2276
|
+
this.cancelPendingPermissions(sessionId);
|
|
2125
2277
|
}
|
|
2126
2278
|
}
|
|
2127
2279
|
async onRuntimeStop() {
|
|
@@ -2134,6 +2286,7 @@ ${message.content}`;
|
|
|
2134
2286
|
this.bootstrappedSessions.clear();
|
|
2135
2287
|
this.roomToSession.clear();
|
|
2136
2288
|
this.roomTools.clear();
|
|
2289
|
+
this.cancelAllPendingPermissions();
|
|
2137
2290
|
this.client = null;
|
|
2138
2291
|
this.connection = null;
|
|
2139
2292
|
if (this.backend) {
|
|
@@ -2211,9 +2364,10 @@ ${message.content}`;
|
|
|
2211
2364
|
const mcpServers = await this.buildSessionMcpServers();
|
|
2212
2365
|
if (existingSessionId) {
|
|
2213
2366
|
const restored = await this.tryRestoreSession(connection, existingSessionId, mcpServers);
|
|
2214
|
-
if (restored) {
|
|
2367
|
+
if (restored.ok) {
|
|
2215
2368
|
this.activeSessions.add(existingSessionId);
|
|
2216
2369
|
this.bootstrappedSessions.add(existingSessionId);
|
|
2370
|
+
await this.applyRequestedPermissionMode(connection, existingSessionId, restored.modes);
|
|
2217
2371
|
return existingSessionId;
|
|
2218
2372
|
}
|
|
2219
2373
|
}
|
|
@@ -2223,30 +2377,52 @@ ${message.content}`;
|
|
|
2223
2377
|
});
|
|
2224
2378
|
this.roomToSession.set(roomId, created.sessionId);
|
|
2225
2379
|
this.activeSessions.add(created.sessionId);
|
|
2380
|
+
await this.applyRequestedPermissionMode(connection, created.sessionId, created.modes);
|
|
2226
2381
|
return created.sessionId;
|
|
2227
2382
|
}
|
|
2228
2383
|
async tryRestoreSession(connection, sessionId, mcpServers) {
|
|
2384
|
+
const capabilities = this.connectionState?.agentCapabilities;
|
|
2385
|
+
const params = { cwd: this.cwd, mcpServers, sessionId };
|
|
2386
|
+
const restore = capabilities?.loadSession ? () => connection.loadSession(params) : capabilities?.sessionCapabilities?.resume ? () => connection.unstable_resumeSession(params) : null;
|
|
2387
|
+
if (!restore) {
|
|
2388
|
+
return { ok: false };
|
|
2389
|
+
}
|
|
2229
2390
|
try {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
cwd: this.cwd,
|
|
2233
|
-
mcpServers,
|
|
2234
|
-
sessionId
|
|
2235
|
-
});
|
|
2236
|
-
return true;
|
|
2237
|
-
}
|
|
2238
|
-
if (this.connectionState?.agentCapabilities?.sessionCapabilities?.resume) {
|
|
2239
|
-
await connection.unstable_resumeSession({
|
|
2240
|
-
cwd: this.cwd,
|
|
2241
|
-
mcpServers,
|
|
2242
|
-
sessionId
|
|
2243
|
-
});
|
|
2244
|
-
return true;
|
|
2245
|
-
}
|
|
2391
|
+
const restored = await restore();
|
|
2392
|
+
return { ok: true, modes: restored?.modes };
|
|
2246
2393
|
} catch {
|
|
2247
|
-
return false;
|
|
2394
|
+
return { ok: false };
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
// Best-effort: never throws, so a mode switch going wrong can't take a
|
|
2398
|
+
// session establishment down with it.
|
|
2399
|
+
async applyRequestedPermissionMode(connection, sessionId, modes) {
|
|
2400
|
+
const requestedModeId = this.requestedPermissionMode;
|
|
2401
|
+
if (!requestedModeId || !modes || modes.currentModeId === requestedModeId) {
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
const availableModes = Array.isArray(modes.availableModes) ? modes.availableModes : [];
|
|
2405
|
+
if (!availableModes.some((mode) => mode?.id === requestedModeId)) {
|
|
2406
|
+
this.safeWarn("requested permission mode is not advertised by this session", {
|
|
2407
|
+
sessionId,
|
|
2408
|
+
requestedModeId,
|
|
2409
|
+
availableModeIds: availableModes.map((mode) => mode?.id)
|
|
2410
|
+
});
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
try {
|
|
2414
|
+
await withTimeout(
|
|
2415
|
+
connection.setSessionMode({ sessionId, modeId: requestedModeId }),
|
|
2416
|
+
SET_SESSION_MODE_TIMEOUT_MS,
|
|
2417
|
+
`setSessionMode did not respond within ${SET_SESSION_MODE_TIMEOUT_MS}ms`
|
|
2418
|
+
);
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
this.safeWarn("failed to switch session into the requested permission mode", {
|
|
2421
|
+
sessionId,
|
|
2422
|
+
requestedModeId,
|
|
2423
|
+
error: String(error)
|
|
2424
|
+
});
|
|
2248
2425
|
}
|
|
2249
|
-
return false;
|
|
2250
2426
|
}
|
|
2251
2427
|
async buildSessionMcpServers() {
|
|
2252
2428
|
const mcpServers = [...this.mcpServers];
|
|
@@ -2356,28 +2532,103 @@ ${message.content}`;
|
|
|
2356
2532
|
].join("\n");
|
|
2357
2533
|
}
|
|
2358
2534
|
async handlePermissionRequest(tools, roomId, params) {
|
|
2359
|
-
const selected = choosePermissionOption(params.options);
|
|
2360
2535
|
const toolName = params.toolCall.title ?? "unknown";
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2536
|
+
const autoSelection = this.resolvePermission ? void 0 : choosePermissionOption(params.options);
|
|
2537
|
+
const controller = this.resolvePermission ? new AbortController() : void 0;
|
|
2538
|
+
if (controller) {
|
|
2539
|
+
this.trackPending(params.sessionId, controller);
|
|
2540
|
+
}
|
|
2541
|
+
const [, chosenId] = await Promise.all([
|
|
2542
|
+
// This is the room's only "a permission request is pending" signal,
|
|
2543
|
+
// and the only one other room participants ever see — started
|
|
2544
|
+
// immediately rather than serialized in front of a manual wait that
|
|
2545
|
+
// can take up to `permissionTimeoutMs`.
|
|
2546
|
+
tools.sendEvent(`Permission requested: ${toolName}`, "tool_call", {
|
|
2547
|
+
permission_request: true,
|
|
2548
|
+
tool_name: toolName,
|
|
2549
|
+
tool_call_id: params.toolCall.toolCallId,
|
|
2550
|
+
acp_session_id: params.sessionId,
|
|
2551
|
+
auto_allowed: autoSelection !== void 0 && autoSelection !== null
|
|
2552
|
+
}),
|
|
2553
|
+
controller ? this.resolveManually(params.sessionId, params, controller) : Promise.resolve(autoSelection?.optionId)
|
|
2554
|
+
]);
|
|
2555
|
+
return this.toResponse(chosenId, params.options);
|
|
2556
|
+
}
|
|
2557
|
+
// `undefined`, or an id absent from this request's own `options` (a buggy
|
|
2558
|
+
// or stale caller), both map to `cancelled` — never silently treated as a
|
|
2559
|
+
// deny. A real match, reject-kind options included, maps to `selected`.
|
|
2560
|
+
toResponse(chosenId, options) {
|
|
2561
|
+
const matched = chosenId !== void 0 && options.some((option) => option.optionId === chosenId);
|
|
2562
|
+
return matched ? { outcome: { outcome: "selected", optionId: chosenId } } : { outcome: { outcome: "cancelled" } };
|
|
2563
|
+
}
|
|
2564
|
+
// A caller-supplied `Logger` isn't guaranteed to be synchronous or
|
|
2565
|
+
// non-throwing. Every best-effort warning in this file routes through here
|
|
2566
|
+
// so one failing sink — a synchronous throw, or an `async` implementation
|
|
2567
|
+
// rejecting (the `Logger` interface's `void` return type permits either;
|
|
2568
|
+
// a bare try/catch only ever catches the former) — can't turn a warning
|
|
2569
|
+
// into an unhandled rejection in its place.
|
|
2570
|
+
safeWarn(message, context) {
|
|
2571
|
+
try {
|
|
2572
|
+
Promise.resolve(this.logger.warn(message, context)).catch(() => void 0);
|
|
2573
|
+
} catch {
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
// Races the caller-supplied resolver against a timeout and against
|
|
2577
|
+
// `controller`'s own abort signal — aborted externally by
|
|
2578
|
+
// `cancelPendingPermissions`/`cancelAllPendingPermissions` (fired from
|
|
2579
|
+
// `onCleanup`/`stop()` below) when a room or the whole adapter tears down
|
|
2580
|
+
// while this is still pending. `controller` is the same object tracked in
|
|
2581
|
+
// `pendingPermissions` by the caller, so there is exactly one cancellation
|
|
2582
|
+
// channel here, not a second hand-rolled one alongside it.
|
|
2583
|
+
async resolveManually(sessionId, params, controller) {
|
|
2584
|
+
let timer;
|
|
2585
|
+
const cancelled = new Promise((resolve) => {
|
|
2586
|
+
controller.signal.addEventListener("abort", () => resolve(void 0));
|
|
2587
|
+
});
|
|
2588
|
+
try {
|
|
2589
|
+
const timeout = new Promise((resolve) => {
|
|
2590
|
+
timer = setTimeout(() => resolve(void 0), this.permissionTimeoutMs);
|
|
2591
|
+
});
|
|
2592
|
+
return await Promise.race([
|
|
2593
|
+
// `resolvePermission` is caller-supplied; nothing guarantees it's
|
|
2594
|
+
// `async` or otherwise well-behaved. `Promise.resolve().then(...)`
|
|
2595
|
+
// normalizes a synchronous throw the same way it normalizes a
|
|
2596
|
+
// rejected promise, so both land in the `.catch` below rather than
|
|
2597
|
+
// escaping this race uncaught.
|
|
2598
|
+
Promise.resolve().then(() => this.resolvePermission(params, controller.signal)).catch((error) => {
|
|
2599
|
+
this.safeWarn("resolvePermission threw; treating as no answer", { error: String(error) });
|
|
2600
|
+
return void 0;
|
|
2601
|
+
}),
|
|
2602
|
+
timeout,
|
|
2603
|
+
cancelled
|
|
2604
|
+
]);
|
|
2605
|
+
} finally {
|
|
2606
|
+
clearTimeout(timer);
|
|
2607
|
+
this.untrackPending(sessionId, controller);
|
|
2608
|
+
controller.abort();
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
trackPending(sessionId, controller) {
|
|
2612
|
+
const pending = this.pendingPermissions.get(sessionId) ?? /* @__PURE__ */ new Set();
|
|
2613
|
+
pending.add(controller);
|
|
2614
|
+
this.pendingPermissions.set(sessionId, pending);
|
|
2615
|
+
}
|
|
2616
|
+
untrackPending(sessionId, controller) {
|
|
2617
|
+
const pending = this.pendingPermissions.get(sessionId);
|
|
2618
|
+
pending?.delete(controller);
|
|
2619
|
+
if (pending?.size === 0) {
|
|
2620
|
+
this.pendingPermissions.delete(sessionId);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
cancelPendingPermissions(sessionId) {
|
|
2624
|
+
for (const controller of this.pendingPermissions.get(sessionId) ?? []) {
|
|
2625
|
+
controller.abort();
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
cancelAllPendingPermissions() {
|
|
2629
|
+
for (const sessionId of this.pendingPermissions.keys()) {
|
|
2630
|
+
this.cancelPendingPermissions(sessionId);
|
|
2374
2631
|
}
|
|
2375
|
-
return {
|
|
2376
|
-
outcome: {
|
|
2377
|
-
outcome: "selected",
|
|
2378
|
-
optionId: selected.optionId
|
|
2379
|
-
}
|
|
2380
|
-
};
|
|
2381
2632
|
}
|
|
2382
2633
|
async flushChunks(input) {
|
|
2383
2634
|
const client = this.client;
|
|
@@ -2385,13 +2636,14 @@ ${message.content}`;
|
|
|
2385
2636
|
return;
|
|
2386
2637
|
}
|
|
2387
2638
|
for (const chunk of client.getCollectedChunks(input.sessionId)) {
|
|
2639
|
+
if (isBlankEventContent(chunk.content)) {
|
|
2640
|
+
continue;
|
|
2641
|
+
}
|
|
2388
2642
|
if (chunk.chunkType === "text") {
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
}]);
|
|
2394
|
-
}
|
|
2643
|
+
await input.tools.sendMessage(chunk.content, [{
|
|
2644
|
+
id: input.senderId,
|
|
2645
|
+
handle: input.senderHandle
|
|
2646
|
+
}]);
|
|
2395
2647
|
continue;
|
|
2396
2648
|
}
|
|
2397
2649
|
const messageType = chunk.chunkType === "plan" ? "task" : chunk.chunkType;
|
|
@@ -2499,14 +2751,6 @@ var ACPServerHistoryConverter = class {
|
|
|
2499
2751
|
}
|
|
2500
2752
|
};
|
|
2501
2753
|
|
|
2502
|
-
// src/runtime/types.ts
|
|
2503
|
-
function ensureHandlePrefix(handle) {
|
|
2504
|
-
if (!handle) {
|
|
2505
|
-
return null;
|
|
2506
|
-
}
|
|
2507
|
-
return handle.startsWith("@") ? handle : `@${handle}`;
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
2754
|
// src/converters/shared.ts
|
|
2511
2755
|
function asOptionalString(value) {
|
|
2512
2756
|
if (typeof value !== "string") {
|
|
@@ -3345,52 +3589,6 @@ function extractPromptText(prompt) {
|
|
|
3345
3589
|
// src/adapters/tool-calling/ToolCallingAdapter.ts
|
|
3346
3590
|
init_protocols();
|
|
3347
3591
|
|
|
3348
|
-
// src/core/logger.ts
|
|
3349
|
-
var noop = () => void 0;
|
|
3350
|
-
var NoopLogger = class {
|
|
3351
|
-
debug = noop;
|
|
3352
|
-
info = noop;
|
|
3353
|
-
warn = noop;
|
|
3354
|
-
error = noop;
|
|
3355
|
-
};
|
|
3356
|
-
|
|
3357
|
-
// src/runtime/formatters.ts
|
|
3358
|
-
function isMetadataMap(value) {
|
|
3359
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3360
|
-
}
|
|
3361
|
-
function replaceUuidMentions(content, participants) {
|
|
3362
|
-
if (!content || participants.length === 0) {
|
|
3363
|
-
return content;
|
|
3364
|
-
}
|
|
3365
|
-
let next = content;
|
|
3366
|
-
for (const participant of participants) {
|
|
3367
|
-
const participantId = participant.id;
|
|
3368
|
-
const handle = participant.handle;
|
|
3369
|
-
if (typeof participantId === "string" && typeof handle === "string") {
|
|
3370
|
-
next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
|
|
3371
|
-
}
|
|
3372
|
-
}
|
|
3373
|
-
return next;
|
|
3374
|
-
}
|
|
3375
|
-
function formatMessageForLlm(message, participants) {
|
|
3376
|
-
const senderType = String(message.sender_type ?? "");
|
|
3377
|
-
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
3378
|
-
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
3379
|
-
return {
|
|
3380
|
-
role: senderType === "Agent" ? "assistant" : "user",
|
|
3381
|
-
content,
|
|
3382
|
-
sender_name: senderName,
|
|
3383
|
-
sender_type: senderType,
|
|
3384
|
-
message_type: String(message.message_type ?? "text"),
|
|
3385
|
-
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
3386
|
-
};
|
|
3387
|
-
}
|
|
3388
|
-
function formatHistoryForLlm(messages, options) {
|
|
3389
|
-
const excludeId = options?.excludeId;
|
|
3390
|
-
const participants = options?.participants;
|
|
3391
|
-
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
3392
|
-
}
|
|
3393
|
-
|
|
3394
3592
|
// src/runtime/tools/customTools.ts
|
|
3395
3593
|
var import_zod3 = require("zod");
|
|
3396
3594
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
@@ -4929,18 +5127,28 @@ var GoogleADKAdapter = class extends SimpleAdapter {
|
|
|
4929
5127
|
}
|
|
4930
5128
|
async reportExecutionEvent(sdk, event, tools) {
|
|
4931
5129
|
for (const functionCall of sdk.getFunctionCalls(event)) {
|
|
4932
|
-
await tools.sendEvent(JSON.stringify({
|
|
5130
|
+
const result = await tools.sendEvent(JSON.stringify({
|
|
4933
5131
|
name: functionCall.name ?? "unknown",
|
|
4934
5132
|
args: asToolArgs(functionCall.args),
|
|
4935
5133
|
tool_call_id: functionCall.id ?? ""
|
|
4936
5134
|
}), "tool_call");
|
|
5135
|
+
this.warnOnFailedSend(result, "Google ADK tool_call event send failed", { toolCallId: functionCall.id ?? "" });
|
|
4937
5136
|
}
|
|
4938
5137
|
for (const functionResponse of sdk.getFunctionResponses(event)) {
|
|
4939
|
-
await tools.sendEvent(JSON.stringify({
|
|
5138
|
+
const result = await tools.sendEvent(JSON.stringify({
|
|
4940
5139
|
name: functionResponse.name ?? "unknown",
|
|
4941
5140
|
output: String(functionResponse.response ?? ""),
|
|
4942
5141
|
tool_call_id: functionResponse.id ?? ""
|
|
4943
5142
|
}), "tool_result");
|
|
5143
|
+
this.warnOnFailedSend(result, "Google ADK tool_result event send failed", { toolCallId: functionResponse.id ?? "" });
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
warnOnFailedSend(result, message, meta) {
|
|
5147
|
+
if (result.ok === false) {
|
|
5148
|
+
try {
|
|
5149
|
+
this.logger.warn(message, meta);
|
|
5150
|
+
} catch {
|
|
5151
|
+
}
|
|
4944
5152
|
}
|
|
4945
5153
|
}
|
|
4946
5154
|
};
|
|
@@ -9498,29 +9706,6 @@ function delay(ms) {
|
|
|
9498
9706
|
init_errors();
|
|
9499
9707
|
init_schemas();
|
|
9500
9708
|
|
|
9501
|
-
// src/adapters/shared/conversationPrompt.ts
|
|
9502
|
-
function buildConversationPrompt(options) {
|
|
9503
|
-
const parts = [];
|
|
9504
|
-
if (options.isSessionBootstrap && options.history.length > 0) {
|
|
9505
|
-
const historyText = options.history.raw.slice(-(options.maxHistoryMessages ?? 50)).map(formatHistoryLine).join("\n");
|
|
9506
|
-
parts.push(`${options.historyHeader}
|
|
9507
|
-
${historyText}`);
|
|
9508
|
-
}
|
|
9509
|
-
if (options.participantsMessage) {
|
|
9510
|
-
parts.push(`[System]: ${options.participantsMessage}`);
|
|
9511
|
-
}
|
|
9512
|
-
if (options.contactsMessage) {
|
|
9513
|
-
parts.push(`[System]: ${options.contactsMessage}`);
|
|
9514
|
-
}
|
|
9515
|
-
parts.push(options.currentMessage);
|
|
9516
|
-
return parts.join("\n\n");
|
|
9517
|
-
}
|
|
9518
|
-
function formatHistoryLine(entry) {
|
|
9519
|
-
const sender = String(entry.sender_name ?? entry.sender_type ?? "Unknown");
|
|
9520
|
-
const content = String(entry.content ?? "");
|
|
9521
|
-
return `[${sender}]: ${content}`;
|
|
9522
|
-
}
|
|
9523
|
-
|
|
9524
9709
|
// src/converters/claude-sdk.ts
|
|
9525
9710
|
function extractClaudeSessionId(raw) {
|
|
9526
9711
|
const metadata = findLatestTaskMetadata(
|
|
@@ -10544,11 +10729,8 @@ var CodexAdapter = class extends SimpleAdapter {
|
|
|
10544
10729
|
items.push({ type: "text", text: context });
|
|
10545
10730
|
}
|
|
10546
10731
|
}
|
|
10547
|
-
|
|
10548
|
-
items.push({ type: "text", text:
|
|
10549
|
-
}
|
|
10550
|
-
if (input.contactsMessage) {
|
|
10551
|
-
items.push({ type: "text", text: `[System]: ${input.contactsMessage}` });
|
|
10732
|
+
for (const part of systemUpdateParts(input.participantsMessage, input.contactsMessage)) {
|
|
10733
|
+
items.push({ type: "text", text: part });
|
|
10552
10734
|
}
|
|
10553
10735
|
items.push({
|
|
10554
10736
|
type: "text",
|
|
@@ -10976,13 +11158,6 @@ var TURN_STATUS_VALUES = /* @__PURE__ */ new Set([
|
|
|
10976
11158
|
"failed",
|
|
10977
11159
|
"inProgress"
|
|
10978
11160
|
]);
|
|
10979
|
-
function isStructuredToolFailure(value) {
|
|
10980
|
-
if (!value || typeof value !== "object") {
|
|
10981
|
-
return false;
|
|
10982
|
-
}
|
|
10983
|
-
const payload = value;
|
|
10984
|
-
return payload.ok === false && typeof payload.message === "string";
|
|
10985
|
-
}
|
|
10986
11161
|
function isCodexToolOutputError(value) {
|
|
10987
11162
|
return isToolExecutorError(value) || isStructuredToolFailure(value);
|
|
10988
11163
|
}
|