@band-ai/sdk 0.2.1 → 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 +208 -115
  4. package/dist/adapters.d.cts +8 -4
  5. package/dist/adapters.d.ts +8 -4
  6. package/dist/adapters.js +105 -43
  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.js CHANGED
@@ -23,14 +23,15 @@ import {
23
23
  ToolCallingAdapter,
24
24
  VercelAISDKAdapter,
25
25
  VercelAISDKToolCallingModel,
26
- runSingleToolRound
27
- } from "./chunk-NMZLX7TP.js";
26
+ runSingleToolRound,
27
+ systemUpdateParts
28
+ } from "./chunk-MQBBWYRP.js";
28
29
  import {
29
30
  BandMcpServer,
30
31
  BandMcpSseServer,
31
32
  generateAuthToken
32
- } from "./chunk-4IAXZBXX.js";
33
- import "./chunk-NT7TBFX2.js";
33
+ } from "./chunk-WA7CHXUS.js";
34
+ import "./chunk-XWHWJP4I.js";
34
35
  import {
35
36
  ACPClientHistoryConverter,
36
37
  ACPServerHistoryConverter
@@ -48,21 +49,26 @@ import {
48
49
  createGatewayServer,
49
50
  parseToolCall,
50
51
  parseToolResult
51
- } from "./chunk-TLBCKDQO.js";
52
+ } from "./chunk-K5KAEYPF.js";
52
53
  import {
53
54
  SimpleAdapter
54
55
  } from "./chunk-AVVDPXP4.js";
55
56
  import {
56
- ensureHandlePrefix
57
- } from "./chunk-LBWKISBS.js";
57
+ ensureHandlePrefix,
58
+ mentionSubjectsFromMetadata,
59
+ replaceUuidMentions
60
+ } from "./chunk-OH6VVVKT.js";
58
61
  import {
59
62
  renderSystemPrompt
60
- } from "./chunk-WLCM2OXG.js";
63
+ } from "./chunk-YJ42AZO4.js";
61
64
  import {
62
65
  MCP_SERVER_NAME
63
- } from "./chunk-RV76SKFT.js";
64
- import "./chunk-ZZJRRBPQ.js";
65
- import "./chunk-3BKAC4OZ.js";
66
+ } from "./chunk-MQY74R7D.js";
67
+ import {
68
+ isBlankEventContent
69
+ } from "./chunk-F63TPOI3.js";
70
+ import "./chunk-KXJ74J73.js";
71
+ import "./chunk-JADCAMZY.js";
66
72
  import {
67
73
  NoopLogger
68
74
  } from "./chunk-OD2G5LFQ.js";
@@ -75,6 +81,21 @@ import {
75
81
  import { spawn } from "child_process";
76
82
  import { Readable, Writable } from "stream";
77
83
 
84
+ // src/adapters/shared/withTimeout.ts
85
+ async function withTimeout(promise, timeoutMs, message) {
86
+ let timer;
87
+ try {
88
+ return await Promise.race([
89
+ promise,
90
+ new Promise((_, reject) => {
91
+ timer = setTimeout(() => reject(new Error(message)), timeoutMs);
92
+ })
93
+ ]);
94
+ } finally {
95
+ clearTimeout(timer);
96
+ }
97
+ }
98
+
78
99
  // src/adapters/acp/types.ts
79
100
  var DEFAULT_ACP_SERVER_MODES = [
80
101
  {
@@ -348,6 +369,7 @@ var acpModule = new LazyAsyncValue({
348
369
 
349
370
  // src/adapters/acp/ACPClientAdapter.ts
350
371
  var DEFAULT_PERMISSION_TIMEOUT_MS = 5 * 6e4;
372
+ var SET_SESSION_MODE_TIMEOUT_MS = 1e4;
351
373
  var ACPClientAdapter = class extends SimpleAdapter {
352
374
  command;
353
375
  cwd;
@@ -366,6 +388,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
366
388
  pendingPermissions = /* @__PURE__ */ new Map();
367
389
  resolvePermission;
368
390
  permissionTimeoutMs;
391
+ requestedPermissionMode;
369
392
  logger;
370
393
  backend = null;
371
394
  backendPromise = null;
@@ -396,6 +419,10 @@ var ACPClientAdapter = class extends SimpleAdapter {
396
419
  this.resolvePermission = options.resolvePermission;
397
420
  this.logger = options.logger ?? new NoopLogger();
398
421
  this.permissionTimeoutMs = options.permissionTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
422
+ this.requestedPermissionMode = options.requestedPermissionMode;
423
+ if (this.requestedPermissionMode !== void 0 && this.requestedPermissionMode.length === 0) {
424
+ throw new ValidationError("requestedPermissionMode must be a non-empty mode id, got an empty string");
425
+ }
399
426
  if (this.resolvePermission && (!Number.isFinite(this.permissionTimeoutMs) || this.permissionTimeoutMs <= 0)) {
400
427
  throw new ValidationError(`permissionTimeoutMs must be a positive finite number, got ${options.permissionTimeoutMs}`);
401
428
  }
@@ -410,7 +437,7 @@ var ACPClientAdapter = class extends SimpleAdapter {
410
437
  });
411
438
  await this.ensureConnection();
412
439
  }
413
- async onMessage(message, tools, history, _participantsMessage, _contactsMessage, context) {
440
+ async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
414
441
  if (context.isSessionBootstrap) {
415
442
  this.rehydrate(history);
416
443
  }
@@ -426,9 +453,11 @@ var ACPClientAdapter = class extends SimpleAdapter {
426
453
  sessionId,
427
454
  (params) => this.handlePermissionRequest(tools, context.roomId, params)
428
455
  );
429
- const promptText = this.bootstrappedSessions.has(sessionId) ? message.content : `${this.buildSystemContext(context.roomId, message)}
456
+ const content = replaceUuidMentions(message.content, mentionSubjectsFromMetadata(message.metadata));
457
+ const messageWithContext = [...systemUpdateParts(participantsMessage, contactsMessage), content].join("\n\n");
458
+ const promptText = this.bootstrappedSessions.has(sessionId) ? messageWithContext : `${this.buildSystemContext(context.roomId, message)}
430
459
 
431
- ${message.content}`;
460
+ ${messageWithContext}`;
432
461
  this.bootstrappedSessions.add(sessionId);
433
462
  try {
434
463
  await connection.prompt({
@@ -555,9 +584,10 @@ ${message.content}`;
555
584
  const mcpServers = await this.buildSessionMcpServers();
556
585
  if (existingSessionId) {
557
586
  const restored = await this.tryRestoreSession(connection, existingSessionId, mcpServers);
558
- if (restored) {
587
+ if (restored.ok) {
559
588
  this.activeSessions.add(existingSessionId);
560
589
  this.bootstrappedSessions.add(existingSessionId);
590
+ await this.applyRequestedPermissionMode(connection, existingSessionId, restored.modes);
561
591
  return existingSessionId;
562
592
  }
563
593
  }
@@ -567,30 +597,52 @@ ${message.content}`;
567
597
  });
568
598
  this.roomToSession.set(roomId, created.sessionId);
569
599
  this.activeSessions.add(created.sessionId);
600
+ await this.applyRequestedPermissionMode(connection, created.sessionId, created.modes);
570
601
  return created.sessionId;
571
602
  }
572
603
  async tryRestoreSession(connection, sessionId, mcpServers) {
604
+ const capabilities = this.connectionState?.agentCapabilities;
605
+ const params = { cwd: this.cwd, mcpServers, sessionId };
606
+ const restore = capabilities?.loadSession ? () => connection.loadSession(params) : capabilities?.sessionCapabilities?.resume ? () => connection.unstable_resumeSession(params) : null;
607
+ if (!restore) {
608
+ return { ok: false };
609
+ }
573
610
  try {
574
- if (this.connectionState?.agentCapabilities?.loadSession) {
575
- await connection.loadSession({
576
- cwd: this.cwd,
577
- mcpServers,
578
- sessionId
579
- });
580
- return true;
581
- }
582
- if (this.connectionState?.agentCapabilities?.sessionCapabilities?.resume) {
583
- await connection.unstable_resumeSession({
584
- cwd: this.cwd,
585
- mcpServers,
586
- sessionId
587
- });
588
- return true;
589
- }
611
+ const restored = await restore();
612
+ return { ok: true, modes: restored?.modes };
590
613
  } catch {
591
- return false;
614
+ return { ok: false };
615
+ }
616
+ }
617
+ // Best-effort: never throws, so a mode switch going wrong can't take a
618
+ // session establishment down with it.
619
+ async applyRequestedPermissionMode(connection, sessionId, modes) {
620
+ const requestedModeId = this.requestedPermissionMode;
621
+ if (!requestedModeId || !modes || modes.currentModeId === requestedModeId) {
622
+ return;
623
+ }
624
+ const availableModes = Array.isArray(modes.availableModes) ? modes.availableModes : [];
625
+ if (!availableModes.some((mode) => mode?.id === requestedModeId)) {
626
+ this.safeWarn("requested permission mode is not advertised by this session", {
627
+ sessionId,
628
+ requestedModeId,
629
+ availableModeIds: availableModes.map((mode) => mode?.id)
630
+ });
631
+ return;
632
+ }
633
+ try {
634
+ await withTimeout(
635
+ connection.setSessionMode({ sessionId, modeId: requestedModeId }),
636
+ SET_SESSION_MODE_TIMEOUT_MS,
637
+ `setSessionMode did not respond within ${SET_SESSION_MODE_TIMEOUT_MS}ms`
638
+ );
639
+ } catch (error) {
640
+ this.safeWarn("failed to switch session into the requested permission mode", {
641
+ sessionId,
642
+ requestedModeId,
643
+ error: String(error)
644
+ });
592
645
  }
593
- return false;
594
646
  }
595
647
  async buildSessionMcpServers() {
596
648
  const mcpServers = [...this.mcpServers];
@@ -729,6 +781,18 @@ ${message.content}`;
729
781
  const matched = chosenId !== void 0 && options.some((option) => option.optionId === chosenId);
730
782
  return matched ? { outcome: { outcome: "selected", optionId: chosenId } } : { outcome: { outcome: "cancelled" } };
731
783
  }
784
+ // A caller-supplied `Logger` isn't guaranteed to be synchronous or
785
+ // non-throwing. Every best-effort warning in this file routes through here
786
+ // so one failing sink — a synchronous throw, or an `async` implementation
787
+ // rejecting (the `Logger` interface's `void` return type permits either;
788
+ // a bare try/catch only ever catches the former) — can't turn a warning
789
+ // into an unhandled rejection in its place.
790
+ safeWarn(message, context) {
791
+ try {
792
+ Promise.resolve(this.logger.warn(message, context)).catch(() => void 0);
793
+ } catch {
794
+ }
795
+ }
732
796
  // Races the caller-supplied resolver against a timeout and against
733
797
  // `controller`'s own abort signal — aborted externally by
734
798
  // `cancelPendingPermissions`/`cancelAllPendingPermissions` (fired from
@@ -752,10 +816,7 @@ ${message.content}`;
752
816
  // rejected promise, so both land in the `.catch` below rather than
753
817
  // escaping this race uncaught.
754
818
  Promise.resolve().then(() => this.resolvePermission(params, controller.signal)).catch((error) => {
755
- try {
756
- this.logger.warn("resolvePermission threw; treating as no answer", { error: String(error) });
757
- } catch {
758
- }
819
+ this.safeWarn("resolvePermission threw; treating as no answer", { error: String(error) });
759
820
  return void 0;
760
821
  }),
761
822
  timeout,
@@ -795,13 +856,14 @@ ${message.content}`;
795
856
  return;
796
857
  }
797
858
  for (const chunk of client.getCollectedChunks(input.sessionId)) {
859
+ if (isBlankEventContent(chunk.content)) {
860
+ continue;
861
+ }
798
862
  if (chunk.chunkType === "text") {
799
- if (chunk.content.length > 0) {
800
- await input.tools.sendMessage(chunk.content, [{
801
- id: input.senderId,
802
- handle: input.senderHandle
803
- }]);
804
- }
863
+ await input.tools.sendMessage(chunk.content, [{
864
+ id: input.senderId,
865
+ handle: input.senderHandle
866
+ }]);
805
867
  continue;
806
868
  }
807
869
  const messageType = chunk.chunkType === "plan" ? "task" : chunk.chunkType;
@@ -0,0 +1,29 @@
1
+ import {
2
+ ValidationError
3
+ } from "./chunk-JY75VSQK.js";
4
+
5
+ // src/contracts/chatEvents.ts
6
+ var CHAT_EVENT_TYPES = ["tool_call", "tool_result", "thought", "error", "task"];
7
+ var CHAT_MESSAGE_TYPES = ["text", ...CHAT_EVENT_TYPES];
8
+ function isChatEventType(value) {
9
+ return CHAT_EVENT_TYPES.includes(value);
10
+ }
11
+ function assertChatEventType(value) {
12
+ if (!isChatEventType(value)) {
13
+ throw new ValidationError(
14
+ `Invalid event message_type '${value}'. Expected one of: ${CHAT_EVENT_TYPES.join(", ")}`
15
+ );
16
+ }
17
+ }
18
+ var VISIBLE_CONTENT_PATTERN = /[\p{L}\p{N}\p{P}\p{S}]/u;
19
+ function isBlankEventContent(content) {
20
+ return !VISIBLE_CONTENT_PATTERN.test(content);
21
+ }
22
+
23
+ export {
24
+ CHAT_EVENT_TYPES,
25
+ CHAT_MESSAGE_TYPES,
26
+ isChatEventType,
27
+ assertChatEventType,
28
+ isBlankEventContent
29
+ };
@@ -21,6 +21,13 @@ function isToolExecutorError(value) {
21
21
  const candidate = value;
22
22
  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";
23
23
  }
24
+ function isStructuredToolFailure(value) {
25
+ if (!value || typeof value !== "object") {
26
+ return false;
27
+ }
28
+ const payload = value;
29
+ return payload.ok === false && typeof payload.message === "string";
30
+ }
24
31
  function toLegacyToolExecutorErrorMessage(value) {
25
32
  if (typeof value === "string") {
26
33
  return value;
@@ -39,6 +46,7 @@ var DEFAULT_AGENT_TOOLS_CAPABILITIES = {
39
46
  export {
40
47
  createToolExecutorError,
41
48
  isToolExecutorError,
49
+ isStructuredToolFailure,
42
50
  toLegacyToolExecutorErrorMessage,
43
51
  DEFAULT_AGENT_TOOLS_CAPABILITIES
44
52
  };