@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.
Files changed (37) hide show
  1. package/dist/{ClaudeSDKAdapter-Cna5P1dR.d.ts → ClaudeSDKAdapter-CXud2DBE.d.ts} +2 -1
  2. package/dist/{ClaudeSDKAdapter-BY4zEbCl.d.cts → ClaudeSDKAdapter-Cx6zhSaG.d.cts} +2 -1
  3. package/dist/adapters.cjs +347 -172
  4. package/dist/adapters.d.cts +22 -5
  5. package/dist/adapters.d.ts +22 -5
  6. package/dist/adapters.js +204 -60
  7. package/dist/chunk-F63TPOI3.js +29 -0
  8. package/dist/{chunk-3BKAC4OZ.js → chunk-JADCAMZY.js} +8 -0
  9. package/dist/{chunk-N2QTUMGO.js → chunk-JJF44XWA.js} +365 -249
  10. package/dist/{chunk-TLBCKDQO.js → chunk-K5KAEYPF.js} +2 -2
  11. package/dist/{chunk-ZZJRRBPQ.js → chunk-KXJ74J73.js} +1 -1
  12. package/dist/{chunk-NMZLX7TP.js → chunk-MQBBWYRP.js} +52 -45
  13. package/dist/{chunk-RV76SKFT.js → chunk-MQY74R7D.js} +2 -20
  14. package/dist/{chunk-LBWKISBS.js → chunk-OH6VVVKT.js} +21 -0
  15. package/dist/{chunk-EAI2M3WM.js → chunk-W5IAI6Z4.js} +1 -1
  16. package/dist/{chunk-4IAXZBXX.js → chunk-WA7CHXUS.js} +2 -2
  17. package/dist/{chunk-NT7TBFX2.js → chunk-XWHWJP4I.js} +2 -2
  18. package/dist/{chunk-WLCM2OXG.js → chunk-YJ42AZO4.js} +1 -1
  19. package/dist/converters.js +6 -5
  20. package/dist/index.cjs +405 -277
  21. package/dist/index.d.cts +5 -5
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.js +12 -11
  24. package/dist/mcp-claude.js +4 -3
  25. package/dist/mcp.js +5 -4
  26. package/dist/rest.js +3 -3
  27. package/dist/runtime.cjs +387 -362
  28. package/dist/runtime.d.cts +10 -39
  29. package/dist/runtime.d.ts +10 -39
  30. package/dist/runtime.js +20 -142
  31. package/dist/{schemas-BotL3ZLH.d.cts → schemas-BgJhlqqO.d.cts} +57 -13
  32. package/dist/{schemas-DBsC4J1g.d.ts → schemas-C4mK1WSs.d.ts} +57 -13
  33. package/dist/testing.cjs +11 -0
  34. package/dist/testing.js +8 -1
  35. package/dist/{types-D958TC71.d.cts → types-BNNtOXu3.d.cts} +1 -1
  36. package/dist/{types-BTN_ZETM.d.ts → types-DFUtpxah.d.ts} +1 -1
  37. 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
- var CHAT_EVENT_TYPES, CHAT_MESSAGE_TYPES;
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, _participantsMessage, _contactsMessage, context) {
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 promptText = this.bootstrappedSessions.has(sessionId) ? message.content : `${this.buildSystemContext(context.roomId, message)}
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
- ${message.content}`;
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
- if (this.connectionState?.agentCapabilities?.loadSession) {
2231
- await connection.loadSession({
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
- await tools.sendEvent(`Permission requested: ${toolName}`, "tool_call", {
2362
- permission_request: true,
2363
- tool_name: toolName,
2364
- tool_call_id: params.toolCall.toolCallId,
2365
- acp_session_id: params.sessionId,
2366
- auto_allowed: selected !== null
2367
- });
2368
- if (!selected) {
2369
- return {
2370
- outcome: {
2371
- outcome: "cancelled"
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
- if (chunk.content.length > 0) {
2390
- await input.tools.sendMessage(chunk.content, [{
2391
- id: input.senderId,
2392
- handle: input.senderHandle
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
- if (input.participantsMessage) {
10548
- items.push({ type: "text", text: `[System]: ${input.participantsMessage}` });
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
  }