@band-ai/sdk 0.1.4 → 0.1.10

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 (73) hide show
  1. package/README.md +372 -0
  2. package/dist/{ClaudeSDKAdapter-CRq4R-WB.d.cts → ClaudeSDKAdapter-DfjaI5ke.d.cts} +9 -7
  3. package/dist/{ClaudeSDKAdapter-BHOkjN3X.d.ts → ClaudeSDKAdapter-DonPGJ43.d.ts} +9 -7
  4. package/dist/{acp-server-BdRz9_UN.d.cts → acp-server-CUBXIiG6.d.cts} +2 -2
  5. package/dist/{acp-server-B1Da7L6u.d.ts → acp-server-NZAeg-WO.d.ts} +2 -2
  6. package/dist/adapters.cjs +494 -106
  7. package/dist/adapters.d.cts +12 -12
  8. package/dist/adapters.d.ts +12 -12
  9. package/dist/adapters.js +7 -7
  10. package/dist/{backends-SVMT-7l4.d.cts → backends-DYtEhCZG.d.cts} +7 -2
  11. package/dist/{backends-CzDbiQar.d.ts → backends-oYAb7EU-.d.ts} +7 -2
  12. package/dist/{chunk-MSL6CWHY.js → chunk-2BHHR6YW.js} +17 -16
  13. package/dist/{chunk-EDPKUUJL.js → chunk-6RXWL6TC.js} +9 -1
  14. package/dist/{chunk-SFVKOEQH.js → chunk-DNPVCR3S.js} +92 -14
  15. package/dist/{chunk-I5EZG52P.js → chunk-FP237EAG.js} +424 -136
  16. package/dist/{chunk-RHVH2GZR.js → chunk-J3M3PFFY.js} +81 -31
  17. package/dist/{chunk-GVEQ3RAH.js → chunk-MLROFDKR.js} +132 -23
  18. package/dist/{chunk-INA6YZTZ.js → chunk-RDM4TE4B.js} +32 -30
  19. package/dist/chunk-US226AS4.js +130 -0
  20. package/dist/{chunk-W5NDZSYE.js → chunk-XA4N2JPH.js} +1 -1
  21. package/dist/converters.cjs +469 -13
  22. package/dist/converters.d.cts +5 -5
  23. package/dist/converters.d.ts +5 -5
  24. package/dist/converters.js +3 -2
  25. package/dist/core.cjs +45 -2
  26. package/dist/core.d.cts +4 -3
  27. package/dist/core.d.ts +4 -3
  28. package/dist/core.js +5 -1
  29. package/dist/disconnectReason-IuADl6TH.d.cts +34 -0
  30. package/dist/disconnectReason-IuADl6TH.d.ts +34 -0
  31. package/dist/{dtos-DUpbIu8k.d.cts → dtos-Dd_fTfLn.d.cts} +26 -6
  32. package/dist/{dtos-DUpbIu8k.d.ts → dtos-Dd_fTfLn.d.ts} +26 -6
  33. package/dist/index.cjs +1089 -269
  34. package/dist/index.d.cts +16 -15
  35. package/dist/index.d.ts +16 -15
  36. package/dist/index.js +14 -8
  37. package/dist/linear.cjs +985 -53
  38. package/dist/linear.d.cts +137 -7
  39. package/dist/linear.d.ts +137 -7
  40. package/dist/linear.js +974 -53
  41. package/dist/mcp-claude.cjs +303 -32
  42. package/dist/mcp-claude.d.cts +3 -3
  43. package/dist/mcp-claude.d.ts +3 -3
  44. package/dist/mcp-claude.js +210 -12
  45. package/dist/mcp.cjs +313 -45
  46. package/dist/mcp.d.cts +5 -5
  47. package/dist/mcp.d.ts +5 -5
  48. package/dist/mcp.js +3 -3
  49. package/dist/{opencode-BBcDchcN.d.cts → opencode--iA5-KYk.d.cts} +2 -2
  50. package/dist/{opencode-DthQQUsZ.d.ts → opencode-YNacv-eJ.d.ts} +2 -2
  51. package/dist/{pagination-CcDkVFxK.d.ts → pagination-BBLsYLhT.d.ts} +2 -2
  52. package/dist/{pagination-BPiys10t.d.cts → pagination-CqidD-L_.d.cts} +2 -2
  53. package/dist/{protocols-DrhzOH6K.d.ts → protocols-BF6jamIl.d.ts} +1 -1
  54. package/dist/{protocols-CInhtFpA.d.cts → protocols-D2bTrQ_t.d.cts} +1 -1
  55. package/dist/rest.d.cts +5 -5
  56. package/dist/rest.d.ts +5 -5
  57. package/dist/runtime.cjs +721 -172
  58. package/dist/runtime.d.cts +15 -10
  59. package/dist/runtime.d.ts +15 -10
  60. package/dist/runtime.js +11 -8
  61. package/dist/{schemas-vos1AaBc.d.ts → schemas-B1Fd3oUM.d.ts} +17 -8
  62. package/dist/{schemas-BpEBkq5V.d.cts → schemas-CI0qgcp_.d.cts} +17 -8
  63. package/dist/{sdk-CcnQ5OUC.d.ts → sdk-CyqN1W5g.d.ts} +32 -2
  64. package/dist/{sdk-CwTAxhwI.d.cts → sdk-D2rTDU_o.d.cts} +32 -2
  65. package/dist/{simpleAdapter-DqhvjsGr.d.cts → simpleAdapter-C_f-01Cu.d.cts} +1 -1
  66. package/dist/{simpleAdapter-9OE_p6QW.d.ts → simpleAdapter-qQt-tSz4.d.ts} +1 -1
  67. package/dist/testing.d.cts +3 -3
  68. package/dist/testing.d.ts +3 -3
  69. package/dist/{types-CovcHpYf.d.cts → types-CKqrhGB1.d.cts} +2 -2
  70. package/dist/{types-CxII3XkA.d.ts → types-D3AsUnd0.d.ts} +1 -1
  71. package/dist/{types-7jVzOeOP.d.ts → types-DNySTI_8.d.ts} +2 -2
  72. package/dist/{types-CSHFipIc.d.cts → types-DtMms5Fi.d.cts} +1 -1
  73. package/package.json +22 -21
@@ -30,6 +30,78 @@ var import_zod = require("zod");
30
30
  var CHAT_EVENT_TYPES = ["tool_call", "tool_result", "thought", "error", "task"];
31
31
  var CHAT_MESSAGE_TYPES = ["text", ...CHAT_EVENT_TYPES];
32
32
 
33
+ // src/contracts/memory.ts
34
+ var SENSORY_MEMORY_TYPES = [
35
+ "iconic",
36
+ // Visual input
37
+ "echoic",
38
+ // Auditory input
39
+ "haptic"
40
+ // Tactile input
41
+ ];
42
+ var COGNITIVE_MEMORY_TYPES = [
43
+ "episodic",
44
+ // Events that occurred
45
+ "semantic",
46
+ // Facts, preferences, learned knowledge
47
+ "procedural"
48
+ // How to perform tasks
49
+ ];
50
+ function namedValues(values) {
51
+ return Object.fromEntries(values.map((value) => [value, value]));
52
+ }
53
+ var MEMORY_SYSTEM_TYPES = {
54
+ sensory: SENSORY_MEMORY_TYPES,
55
+ // Brief sensory inputs
56
+ working: COGNITIVE_MEMORY_TYPES,
57
+ // Short-term session context
58
+ long_term: COGNITIVE_MEMORY_TYPES
59
+ // Persistent cross-conversation memory
60
+ };
61
+ var MEMORY_SYSTEMS = Object.keys(MEMORY_SYSTEM_TYPES);
62
+ var MEMORY_TYPES = [
63
+ ...SENSORY_MEMORY_TYPES,
64
+ ...COGNITIVE_MEMORY_TYPES
65
+ ];
66
+ var MEMORY_SEGMENTS = [
67
+ "user",
68
+ // User preferences or profile info
69
+ "agent",
70
+ // Facts or events about agents/entities
71
+ "tool",
72
+ // Tool usage or task procedures
73
+ "guideline"
74
+ // Behavioral rules or policies
75
+ ];
76
+ var MEMORY_STORE_SCOPES = [
77
+ "subject",
78
+ // About one person/agent; requires subject_id
79
+ "organization"
80
+ // Shared org-wide
81
+ ];
82
+ var MEMORY_LIST_SCOPES = [
83
+ "subject",
84
+ // Subject-scoped memories only
85
+ "organization",
86
+ // Organization-scoped memories only
87
+ "all"
88
+ // Both scopes (no scope filter)
89
+ ];
90
+ var MEMORY_STATUSES = [
91
+ "active",
92
+ // Normal, visible memories
93
+ "superseded",
94
+ // Outdated; soft-deleted via thenvoi_supersede_memory
95
+ "archived",
96
+ // Hidden but preserved via thenvoi_archive_memory
97
+ "all"
98
+ // Any status (no filter)
99
+ ];
100
+ var MEMORY_SYSTEM = namedValues(MEMORY_SYSTEMS);
101
+ var MEMORY_TYPE = namedValues(MEMORY_TYPES);
102
+ var MEMORY_SEGMENT = namedValues(MEMORY_SEGMENTS);
103
+ var MEMORY_STORE_SCOPE = namedValues(MEMORY_STORE_SCOPES);
104
+
33
105
  // src/runtime/tools/schemas.ts
34
106
  var TOOL_MODELS = {
35
107
  thenvoi_send_message: {
@@ -217,29 +289,22 @@ var TOOL_MODELS = {
217
289
  },
218
290
  scope: {
219
291
  type: "string",
220
- enum: ["subject", "organization", "all"],
292
+ enum: [...MEMORY_LIST_SCOPES],
221
293
  description: "Filter by scope."
222
294
  },
223
295
  system: {
224
296
  type: "string",
225
- enum: ["sensory", "working", "long_term"],
297
+ enum: [...MEMORY_SYSTEMS],
226
298
  description: "Filter by memory system."
227
299
  },
228
300
  type: {
229
301
  type: "string",
230
- enum: [
231
- "iconic",
232
- "echoic",
233
- "haptic",
234
- "episodic",
235
- "semantic",
236
- "procedural"
237
- ],
302
+ enum: [...MEMORY_TYPES],
238
303
  description: "Filter by memory type."
239
304
  },
240
305
  segment: {
241
306
  type: "string",
242
- enum: ["user", "agent", "tool", "guideline"],
307
+ enum: [...MEMORY_SEGMENTS],
243
308
  description: "Filter by segment."
244
309
  },
245
310
  content_query: {
@@ -254,7 +319,7 @@ var TOOL_MODELS = {
254
319
  },
255
320
  status: {
256
321
  type: "string",
257
- enum: ["active", "superseded", "archived", "all"],
322
+ enum: [...MEMORY_STATUSES],
258
323
  description: "Filter by status."
259
324
  }
260
325
  },
@@ -269,24 +334,17 @@ var TOOL_MODELS = {
269
334
  },
270
335
  system: {
271
336
  type: "string",
272
- enum: ["sensory", "working", "long_term"],
337
+ enum: [...MEMORY_SYSTEMS],
273
338
  description: "Memory system tier."
274
339
  },
275
340
  type: {
276
341
  type: "string",
277
- enum: [
278
- "iconic",
279
- "echoic",
280
- "haptic",
281
- "episodic",
282
- "semantic",
283
- "procedural"
284
- ],
342
+ enum: [...MEMORY_TYPES],
285
343
  description: "Memory type (must be valid for selected system)."
286
344
  },
287
345
  segment: {
288
346
  type: "string",
289
- enum: ["user", "agent", "tool", "guideline"],
347
+ enum: [...MEMORY_SEGMENTS],
290
348
  description: "Logical segment."
291
349
  },
292
350
  thought: {
@@ -295,7 +353,7 @@ var TOOL_MODELS = {
295
353
  },
296
354
  scope: {
297
355
  type: "string",
298
- enum: ["subject", "organization"],
356
+ enum: [...MEMORY_STORE_SCOPES],
299
357
  description: "Visibility scope."
300
358
  },
301
359
  subject_id: {
@@ -414,6 +472,16 @@ function buildRoomScopedRegistrations(resolver, options = {}) {
414
472
  }
415
473
  return registrations;
416
474
  }
475
+ function buildSingleContextRegistrations(tools, options = {}) {
476
+ const toolNames = resolveToolNames(options);
477
+ const registrations = buildRegistrations(toolNames, (_toolName, args) => {
478
+ return executeToolCall(tools, _toolName, args);
479
+ }, { injectRoomId: false });
480
+ if (options.additionalTools) {
481
+ registrations.push(...options.additionalTools);
482
+ }
483
+ return registrations;
484
+ }
417
485
  function resolveToolNames(options) {
418
486
  const names = /* @__PURE__ */ new Set();
419
487
  for (const name of BASE_TOOL_NAMES) {
@@ -501,6 +569,13 @@ function serializeValue(value) {
501
569
  return String(value);
502
570
  }
503
571
  }
572
+ function resolveSingleRoomTools(getToolsForRoom) {
573
+ const tools = getToolsForRoom("");
574
+ if (!tools) {
575
+ throw new Error('Single-room mode requires getToolsForRoom("") to return a tools instance');
576
+ }
577
+ return tools;
578
+ }
504
579
 
505
580
  // src/mcp/zod.ts
506
581
  function buildZodShape(z2, properties, required) {
@@ -543,16 +618,16 @@ function jsonSchemaToZod(z2, schema) {
543
618
 
544
619
  // src/mcp/sdk.ts
545
620
  function createThenvoiSdkMcpServer(options) {
546
- const registrations = buildRoomScopedRegistrations(
547
- options.getToolsForRoom,
548
- {
549
- enableMemoryTools: options.enableMemoryTools,
550
- enableContactTools: true,
551
- additionalTools: options.additionalTools
552
- }
553
- );
621
+ const registrationOptions = {
622
+ enableMemoryTools: options.enableMemoryTools,
623
+ enableContactTools: true,
624
+ additionalTools: options.additionalTools
625
+ };
626
+ const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolveSingleRoomTools(options.getToolsForRoom), registrationOptions) : buildRoomScopedRegistrations(options.getToolsForRoom, registrationOptions);
554
627
  const toolDefinitions = registrations.map(toSdkToolDefinition);
555
628
  const toolNames = new Set(registrations.map((r) => r.name));
629
+ const contextCache = /* @__PURE__ */ new Map();
630
+ const MAX_CONTEXT_CACHE_ENTRIES = 100;
556
631
  const serverConfig = (0, import_claude_agent_sdk.createSdkMcpServer)({
557
632
  name: "thenvoi",
558
633
  tools: toolDefinitions
@@ -560,9 +635,205 @@ function createThenvoiSdkMcpServer(options) {
560
635
  return {
561
636
  serverConfig,
562
637
  allowedTools: mcpToolNames(toolNames),
563
- toolDefinitions
638
+ toolDefinitions,
639
+ getSystemPromptContext: async (roomId, contextOptions) => {
640
+ const context = await getOrBuildSystemPromptContext(
641
+ roomId,
642
+ contextOptions,
643
+ options.getToolsForRoom,
644
+ contextCache,
645
+ MAX_CONTEXT_CACHE_ENTRIES
646
+ );
647
+ return context.markdown;
648
+ },
649
+ getSystemPromptContextData: (roomId, contextOptions) => {
650
+ return getOrBuildSystemPromptContext(
651
+ roomId,
652
+ contextOptions,
653
+ options.getToolsForRoom,
654
+ contextCache,
655
+ MAX_CONTEXT_CACHE_ENTRIES
656
+ );
657
+ }
658
+ };
659
+ }
660
+ async function getOrBuildSystemPromptContext(roomId, contextOptions, getToolsForRoom, contextCache, maxEntries) {
661
+ const ttlMs = contextOptions?.ttlMs ?? 3e4;
662
+ const now = Date.now();
663
+ const cached = contextCache.get(roomId);
664
+ if (cached && cached.expiresAt > now) {
665
+ cached.lastAccessedAt = now;
666
+ return cached.value;
667
+ }
668
+ if (cached) {
669
+ contextCache.delete(roomId);
670
+ }
671
+ const tools = getToolsForRoom(roomId);
672
+ if (!tools) {
673
+ return buildUnavailableSystemPromptContext(roomId);
674
+ }
675
+ const context = await buildSystemPromptContext(roomId, tools);
676
+ contextCache.set(roomId, {
677
+ value: context,
678
+ expiresAt: now + ttlMs,
679
+ lastAccessedAt: now
680
+ });
681
+ evictLeastRecentlyUsedContext(contextCache, maxEntries);
682
+ return context;
683
+ }
684
+ async function buildSystemPromptContext(roomId, tools) {
685
+ const participants = await tools.getParticipants();
686
+ const warnings = [];
687
+ const agentResolution = await resolveAgentIdentity(tools);
688
+ if (agentResolution.warning) {
689
+ warnings.push(agentResolution.warning);
690
+ }
691
+ const roomResolution = await resolveRoomTitle(tools, roomId);
692
+ if (roomResolution.warning) {
693
+ warnings.push(roomResolution.warning);
694
+ }
695
+ const agentIdentity = agentResolution.value;
696
+ const roomTitle = roomResolution.value;
697
+ const normalizedParticipants = participants.map((participant) => ({
698
+ id: String(participant.id),
699
+ name: String(participant.name ?? "Unknown"),
700
+ type: String(participant.type ?? "Unknown"),
701
+ handle: normalizeHandle(participant.handle),
702
+ isSelf: participant.id === agentIdentity?.id
703
+ }));
704
+ const selfHandle = normalizeHandle(agentIdentity?.handle);
705
+ const selfName = agentIdentity?.name ?? "Agent";
706
+ const mentionHandles = normalizedParticipants.filter((participant) => !participant.isSelf).map((participant) => participant.handle).filter((handle) => Boolean(handle));
707
+ const mentionFormat = mentionHandles.length > 0 ? mentionHandles.join(", ") : "No participant handles available";
708
+ const roomLabel = roomTitle ? `"${roomTitle}"` : "this room";
709
+ const agentLabel = selfHandle ? `${selfName} (${selfHandle})` : selfName;
710
+ const participantLines = normalizedParticipants.length > 0 ? normalizedParticipants.map((participant) => {
711
+ const suffix = participant.isSelf ? " (you)" : "";
712
+ const handle = participant.handle ? ` (${participant.handle})` : "";
713
+ return `- **${participant.name}**${handle} -- ${participant.type}${suffix}`;
714
+ }).join("\n") : "- No participants found";
715
+ const markdown = [
716
+ "## Room Context",
717
+ "",
718
+ `You are **${agentLabel}** in room ${roomLabel} (id: ${roomId}).`,
719
+ "",
720
+ "### Participants",
721
+ participantLines,
722
+ "",
723
+ "### Mention Format",
724
+ `To address someone, use their exact handle: ${mentionFormat}`,
725
+ ...warnings.length > 0 ? ["", "### Warnings", ...warnings.map((warning) => `- ${warning}`)] : []
726
+ ].join("\n");
727
+ return {
728
+ roomId,
729
+ roomTitle,
730
+ agent: {
731
+ id: agentIdentity?.id ?? "unknown-agent",
732
+ name: selfName,
733
+ handle: selfHandle,
734
+ description: agentIdentity?.description ?? null
735
+ },
736
+ participants: normalizedParticipants,
737
+ mentionFormat,
738
+ warnings,
739
+ markdown
564
740
  };
565
741
  }
742
+ async function resolveAgentIdentity(tools) {
743
+ const maybeTools = tools;
744
+ try {
745
+ if (maybeTools.getAgentIdentity) {
746
+ return { value: await maybeTools.getAgentIdentity(), warning: null };
747
+ }
748
+ if (maybeTools.rest?.getAgentMe) {
749
+ return { value: await maybeTools.rest.getAgentMe(), warning: null };
750
+ }
751
+ } catch (error) {
752
+ return {
753
+ value: null,
754
+ warning: `Unable to resolve agent identity: ${error instanceof Error ? error.message : String(error)}`
755
+ };
756
+ }
757
+ return { value: null, warning: null };
758
+ }
759
+ async function resolveRoomTitle(tools, roomId) {
760
+ const maybeTools = tools;
761
+ const rest = maybeTools.rest;
762
+ if (!rest?.listChats) {
763
+ return { value: null, warning: null };
764
+ }
765
+ try {
766
+ let page = 1;
767
+ const pageSize = 100;
768
+ while (true) {
769
+ const response = await rest.listChats({ page, pageSize });
770
+ const room = response?.data?.find((entry) => entry.id === roomId);
771
+ if (typeof room?.title === "string" && room.title.length > 0) {
772
+ return { value: room.title, warning: null };
773
+ }
774
+ const totalPages = response?.metadata?.totalPages ?? page;
775
+ if (page >= totalPages) {
776
+ return { value: null, warning: null };
777
+ }
778
+ page += 1;
779
+ }
780
+ } catch (error) {
781
+ return {
782
+ value: null,
783
+ warning: `Unable to resolve room title: ${error instanceof Error ? error.message : String(error)}`
784
+ };
785
+ }
786
+ }
787
+ function buildUnavailableSystemPromptContext(roomId) {
788
+ const warnings = [`No tool context found for room_id ${roomId}`];
789
+ const markdown = [
790
+ "## Room Context",
791
+ "",
792
+ `You are **Agent** in this room (id: ${roomId}).`,
793
+ "",
794
+ "### Participants",
795
+ "- No participants found",
796
+ "",
797
+ "### Mention Format",
798
+ "No participant handles available",
799
+ "",
800
+ "### Warnings",
801
+ ...warnings.map((warning) => `- ${warning}`)
802
+ ].join("\n");
803
+ return {
804
+ roomId,
805
+ roomTitle: null,
806
+ agent: {
807
+ id: "unknown-agent",
808
+ name: "Agent",
809
+ handle: null,
810
+ description: null
811
+ },
812
+ participants: [],
813
+ mentionFormat: "No participant handles available",
814
+ warnings,
815
+ markdown
816
+ };
817
+ }
818
+ function evictLeastRecentlyUsedContext(contextCache, maxEntries) {
819
+ if (contextCache.size <= maxEntries) {
820
+ return;
821
+ }
822
+ let oldestKey = null;
823
+ let oldestAccessedAt = Number.POSITIVE_INFINITY;
824
+ for (const [key, entry] of contextCache.entries()) {
825
+ if (entry.lastAccessedAt < oldestAccessedAt) {
826
+ oldestAccessedAt = entry.lastAccessedAt;
827
+ oldestKey = key;
828
+ }
829
+ }
830
+ if (oldestKey) {
831
+ contextCache.delete(oldestKey);
832
+ }
833
+ }
834
+ function normalizeHandle(handle) {
835
+ return typeof handle === "string" && handle.trim().length > 0 ? handle.trim() : null;
836
+ }
566
837
  function toSdkToolDefinition(registration) {
567
838
  const shape = buildZodShape(
568
839
  import_zod.z,
@@ -1,4 +1,4 @@
1
1
  import '@anthropic-ai/claude-agent-sdk';
2
- import './protocols-CInhtFpA.cjs';
3
- export { C as CreateThenvoiSdkMcpServerOptions, T as ThenvoiSdkMcpServer, f as createThenvoiSdkMcpServer } from './sdk-CwTAxhwI.cjs';
4
- import './dtos-DUpbIu8k.cjs';
2
+ import './protocols-D2bTrQ_t.cjs';
3
+ export { C as CreateThenvoiSdkMcpServerOptions, G as GetSystemPromptContextOptions, f as GetSystemPromptContextResult, T as ThenvoiSdkMcpServer, g as createThenvoiSdkMcpServer } from './sdk-D2rTDU_o.cjs';
4
+ import './dtos-Dd_fTfLn.cjs';
@@ -1,4 +1,4 @@
1
1
  import '@anthropic-ai/claude-agent-sdk';
2
- import './protocols-DrhzOH6K.js';
3
- export { C as CreateThenvoiSdkMcpServerOptions, T as ThenvoiSdkMcpServer, f as createThenvoiSdkMcpServer } from './sdk-CcnQ5OUC.js';
4
- import './dtos-DUpbIu8k.js';
2
+ import './protocols-BF6jamIl.js';
3
+ export { C as CreateThenvoiSdkMcpServerOptions, G as GetSystemPromptContextOptions, f as GetSystemPromptContextResult, T as ThenvoiSdkMcpServer, g as createThenvoiSdkMcpServer } from './sdk-CyqN1W5g.js';
4
+ import './dtos-Dd_fTfLn.js';
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  buildRoomScopedRegistrations,
3
- buildZodShape
4
- } from "./chunk-EDPKUUJL.js";
3
+ buildSingleContextRegistrations,
4
+ buildZodShape,
5
+ resolveSingleRoomTools
6
+ } from "./chunk-6RXWL6TC.js";
5
7
  import {
6
8
  mcpToolNames
7
- } from "./chunk-GVEQ3RAH.js";
9
+ } from "./chunk-MLROFDKR.js";
8
10
  import "./chunk-3BKAC4OZ.js";
9
11
  import "./chunk-YR3BOQNW.js";
10
12
 
@@ -15,16 +17,16 @@ import {
15
17
  } from "@anthropic-ai/claude-agent-sdk";
16
18
  import { z } from "zod";
17
19
  function createThenvoiSdkMcpServer(options) {
18
- const registrations = buildRoomScopedRegistrations(
19
- options.getToolsForRoom,
20
- {
21
- enableMemoryTools: options.enableMemoryTools,
22
- enableContactTools: true,
23
- additionalTools: options.additionalTools
24
- }
25
- );
20
+ const registrationOptions = {
21
+ enableMemoryTools: options.enableMemoryTools,
22
+ enableContactTools: true,
23
+ additionalTools: options.additionalTools
24
+ };
25
+ const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolveSingleRoomTools(options.getToolsForRoom), registrationOptions) : buildRoomScopedRegistrations(options.getToolsForRoom, registrationOptions);
26
26
  const toolDefinitions = registrations.map(toSdkToolDefinition);
27
27
  const toolNames = new Set(registrations.map((r) => r.name));
28
+ const contextCache = /* @__PURE__ */ new Map();
29
+ const MAX_CONTEXT_CACHE_ENTRIES = 100;
28
30
  const serverConfig = createSdkMcpServer({
29
31
  name: "thenvoi",
30
32
  tools: toolDefinitions
@@ -32,9 +34,205 @@ function createThenvoiSdkMcpServer(options) {
32
34
  return {
33
35
  serverConfig,
34
36
  allowedTools: mcpToolNames(toolNames),
35
- toolDefinitions
37
+ toolDefinitions,
38
+ getSystemPromptContext: async (roomId, contextOptions) => {
39
+ const context = await getOrBuildSystemPromptContext(
40
+ roomId,
41
+ contextOptions,
42
+ options.getToolsForRoom,
43
+ contextCache,
44
+ MAX_CONTEXT_CACHE_ENTRIES
45
+ );
46
+ return context.markdown;
47
+ },
48
+ getSystemPromptContextData: (roomId, contextOptions) => {
49
+ return getOrBuildSystemPromptContext(
50
+ roomId,
51
+ contextOptions,
52
+ options.getToolsForRoom,
53
+ contextCache,
54
+ MAX_CONTEXT_CACHE_ENTRIES
55
+ );
56
+ }
57
+ };
58
+ }
59
+ async function getOrBuildSystemPromptContext(roomId, contextOptions, getToolsForRoom, contextCache, maxEntries) {
60
+ const ttlMs = contextOptions?.ttlMs ?? 3e4;
61
+ const now = Date.now();
62
+ const cached = contextCache.get(roomId);
63
+ if (cached && cached.expiresAt > now) {
64
+ cached.lastAccessedAt = now;
65
+ return cached.value;
66
+ }
67
+ if (cached) {
68
+ contextCache.delete(roomId);
69
+ }
70
+ const tools = getToolsForRoom(roomId);
71
+ if (!tools) {
72
+ return buildUnavailableSystemPromptContext(roomId);
73
+ }
74
+ const context = await buildSystemPromptContext(roomId, tools);
75
+ contextCache.set(roomId, {
76
+ value: context,
77
+ expiresAt: now + ttlMs,
78
+ lastAccessedAt: now
79
+ });
80
+ evictLeastRecentlyUsedContext(contextCache, maxEntries);
81
+ return context;
82
+ }
83
+ async function buildSystemPromptContext(roomId, tools) {
84
+ const participants = await tools.getParticipants();
85
+ const warnings = [];
86
+ const agentResolution = await resolveAgentIdentity(tools);
87
+ if (agentResolution.warning) {
88
+ warnings.push(agentResolution.warning);
89
+ }
90
+ const roomResolution = await resolveRoomTitle(tools, roomId);
91
+ if (roomResolution.warning) {
92
+ warnings.push(roomResolution.warning);
93
+ }
94
+ const agentIdentity = agentResolution.value;
95
+ const roomTitle = roomResolution.value;
96
+ const normalizedParticipants = participants.map((participant) => ({
97
+ id: String(participant.id),
98
+ name: String(participant.name ?? "Unknown"),
99
+ type: String(participant.type ?? "Unknown"),
100
+ handle: normalizeHandle(participant.handle),
101
+ isSelf: participant.id === agentIdentity?.id
102
+ }));
103
+ const selfHandle = normalizeHandle(agentIdentity?.handle);
104
+ const selfName = agentIdentity?.name ?? "Agent";
105
+ const mentionHandles = normalizedParticipants.filter((participant) => !participant.isSelf).map((participant) => participant.handle).filter((handle) => Boolean(handle));
106
+ const mentionFormat = mentionHandles.length > 0 ? mentionHandles.join(", ") : "No participant handles available";
107
+ const roomLabel = roomTitle ? `"${roomTitle}"` : "this room";
108
+ const agentLabel = selfHandle ? `${selfName} (${selfHandle})` : selfName;
109
+ const participantLines = normalizedParticipants.length > 0 ? normalizedParticipants.map((participant) => {
110
+ const suffix = participant.isSelf ? " (you)" : "";
111
+ const handle = participant.handle ? ` (${participant.handle})` : "";
112
+ return `- **${participant.name}**${handle} -- ${participant.type}${suffix}`;
113
+ }).join("\n") : "- No participants found";
114
+ const markdown = [
115
+ "## Room Context",
116
+ "",
117
+ `You are **${agentLabel}** in room ${roomLabel} (id: ${roomId}).`,
118
+ "",
119
+ "### Participants",
120
+ participantLines,
121
+ "",
122
+ "### Mention Format",
123
+ `To address someone, use their exact handle: ${mentionFormat}`,
124
+ ...warnings.length > 0 ? ["", "### Warnings", ...warnings.map((warning) => `- ${warning}`)] : []
125
+ ].join("\n");
126
+ return {
127
+ roomId,
128
+ roomTitle,
129
+ agent: {
130
+ id: agentIdentity?.id ?? "unknown-agent",
131
+ name: selfName,
132
+ handle: selfHandle,
133
+ description: agentIdentity?.description ?? null
134
+ },
135
+ participants: normalizedParticipants,
136
+ mentionFormat,
137
+ warnings,
138
+ markdown
139
+ };
140
+ }
141
+ async function resolveAgentIdentity(tools) {
142
+ const maybeTools = tools;
143
+ try {
144
+ if (maybeTools.getAgentIdentity) {
145
+ return { value: await maybeTools.getAgentIdentity(), warning: null };
146
+ }
147
+ if (maybeTools.rest?.getAgentMe) {
148
+ return { value: await maybeTools.rest.getAgentMe(), warning: null };
149
+ }
150
+ } catch (error) {
151
+ return {
152
+ value: null,
153
+ warning: `Unable to resolve agent identity: ${error instanceof Error ? error.message : String(error)}`
154
+ };
155
+ }
156
+ return { value: null, warning: null };
157
+ }
158
+ async function resolveRoomTitle(tools, roomId) {
159
+ const maybeTools = tools;
160
+ const rest = maybeTools.rest;
161
+ if (!rest?.listChats) {
162
+ return { value: null, warning: null };
163
+ }
164
+ try {
165
+ let page = 1;
166
+ const pageSize = 100;
167
+ while (true) {
168
+ const response = await rest.listChats({ page, pageSize });
169
+ const room = response?.data?.find((entry) => entry.id === roomId);
170
+ if (typeof room?.title === "string" && room.title.length > 0) {
171
+ return { value: room.title, warning: null };
172
+ }
173
+ const totalPages = response?.metadata?.totalPages ?? page;
174
+ if (page >= totalPages) {
175
+ return { value: null, warning: null };
176
+ }
177
+ page += 1;
178
+ }
179
+ } catch (error) {
180
+ return {
181
+ value: null,
182
+ warning: `Unable to resolve room title: ${error instanceof Error ? error.message : String(error)}`
183
+ };
184
+ }
185
+ }
186
+ function buildUnavailableSystemPromptContext(roomId) {
187
+ const warnings = [`No tool context found for room_id ${roomId}`];
188
+ const markdown = [
189
+ "## Room Context",
190
+ "",
191
+ `You are **Agent** in this room (id: ${roomId}).`,
192
+ "",
193
+ "### Participants",
194
+ "- No participants found",
195
+ "",
196
+ "### Mention Format",
197
+ "No participant handles available",
198
+ "",
199
+ "### Warnings",
200
+ ...warnings.map((warning) => `- ${warning}`)
201
+ ].join("\n");
202
+ return {
203
+ roomId,
204
+ roomTitle: null,
205
+ agent: {
206
+ id: "unknown-agent",
207
+ name: "Agent",
208
+ handle: null,
209
+ description: null
210
+ },
211
+ participants: [],
212
+ mentionFormat: "No participant handles available",
213
+ warnings,
214
+ markdown
36
215
  };
37
216
  }
217
+ function evictLeastRecentlyUsedContext(contextCache, maxEntries) {
218
+ if (contextCache.size <= maxEntries) {
219
+ return;
220
+ }
221
+ let oldestKey = null;
222
+ let oldestAccessedAt = Number.POSITIVE_INFINITY;
223
+ for (const [key, entry] of contextCache.entries()) {
224
+ if (entry.lastAccessedAt < oldestAccessedAt) {
225
+ oldestAccessedAt = entry.lastAccessedAt;
226
+ oldestKey = key;
227
+ }
228
+ }
229
+ if (oldestKey) {
230
+ contextCache.delete(oldestKey);
231
+ }
232
+ }
233
+ function normalizeHandle(handle) {
234
+ return typeof handle === "string" && handle.trim().length > 0 ? handle.trim() : null;
235
+ }
38
236
  function toSdkToolDefinition(registration) {
39
237
  const shape = buildZodShape(
40
238
  z,