@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
package/dist/index.cjs CHANGED
@@ -133,6 +133,114 @@ var init_chatEvents = __esm({
133
133
  }
134
134
  });
135
135
 
136
+ // src/contracts/memory.ts
137
+ function namedValues(values) {
138
+ return Object.fromEntries(values.map((value) => [value, value]));
139
+ }
140
+ function isMemorySystem(value) {
141
+ return MEMORY_SYSTEMS.includes(value);
142
+ }
143
+ function isMemoryType(value) {
144
+ return MEMORY_TYPES.includes(value);
145
+ }
146
+ function isMemoryTypeForSystem(system, type) {
147
+ return MEMORY_SYSTEM_TYPES[system].includes(type);
148
+ }
149
+ function isMemorySegment(value) {
150
+ return MEMORY_SEGMENTS.includes(value);
151
+ }
152
+ function isMemoryStoreScope(value) {
153
+ return MEMORY_STORE_SCOPES.includes(value);
154
+ }
155
+ function isMemoryListScope(value) {
156
+ return MEMORY_LIST_SCOPES.includes(value);
157
+ }
158
+ function isMemoryStatus(value) {
159
+ return MEMORY_STATUSES.includes(value);
160
+ }
161
+ function expectedList(values) {
162
+ return values.join(", ");
163
+ }
164
+ function expectedMemoryTypesForSystem(system) {
165
+ return expectedList(MEMORY_SYSTEM_TYPES[system]);
166
+ }
167
+ function memoryTypeForSystemError(system) {
168
+ return `type must be one of: ${expectedMemoryTypesForSystem(system)} for system "${system}"`;
169
+ }
170
+ var SENSORY_MEMORY_TYPES, COGNITIVE_MEMORY_TYPES, MEMORY_SYSTEM_TYPES, MEMORY_SYSTEMS, MEMORY_TYPES, MEMORY_SEGMENTS, MEMORY_STORE_SCOPES, MEMORY_LIST_SCOPES, MEMORY_STATUSES, MEMORY_SYSTEM, MEMORY_TYPE, MEMORY_SEGMENT, MEMORY_STORE_SCOPE;
171
+ var init_memory = __esm({
172
+ "src/contracts/memory.ts"() {
173
+ "use strict";
174
+ SENSORY_MEMORY_TYPES = [
175
+ "iconic",
176
+ // Visual input
177
+ "echoic",
178
+ // Auditory input
179
+ "haptic"
180
+ // Tactile input
181
+ ];
182
+ COGNITIVE_MEMORY_TYPES = [
183
+ "episodic",
184
+ // Events that occurred
185
+ "semantic",
186
+ // Facts, preferences, learned knowledge
187
+ "procedural"
188
+ // How to perform tasks
189
+ ];
190
+ MEMORY_SYSTEM_TYPES = {
191
+ sensory: SENSORY_MEMORY_TYPES,
192
+ // Brief sensory inputs
193
+ working: COGNITIVE_MEMORY_TYPES,
194
+ // Short-term session context
195
+ long_term: COGNITIVE_MEMORY_TYPES
196
+ // Persistent cross-conversation memory
197
+ };
198
+ MEMORY_SYSTEMS = Object.keys(MEMORY_SYSTEM_TYPES);
199
+ MEMORY_TYPES = [
200
+ ...SENSORY_MEMORY_TYPES,
201
+ ...COGNITIVE_MEMORY_TYPES
202
+ ];
203
+ MEMORY_SEGMENTS = [
204
+ "user",
205
+ // User preferences or profile info
206
+ "agent",
207
+ // Facts or events about agents/entities
208
+ "tool",
209
+ // Tool usage or task procedures
210
+ "guideline"
211
+ // Behavioral rules or policies
212
+ ];
213
+ MEMORY_STORE_SCOPES = [
214
+ "subject",
215
+ // About one person/agent; requires subject_id
216
+ "organization"
217
+ // Shared org-wide
218
+ ];
219
+ MEMORY_LIST_SCOPES = [
220
+ "subject",
221
+ // Subject-scoped memories only
222
+ "organization",
223
+ // Organization-scoped memories only
224
+ "all"
225
+ // Both scopes (no scope filter)
226
+ ];
227
+ MEMORY_STATUSES = [
228
+ "active",
229
+ // Normal, visible memories
230
+ "superseded",
231
+ // Outdated; soft-deleted via thenvoi_supersede_memory
232
+ "archived",
233
+ // Hidden but preserved via thenvoi_archive_memory
234
+ "all"
235
+ // Any status (no filter)
236
+ ];
237
+ MEMORY_SYSTEM = namedValues(MEMORY_SYSTEMS);
238
+ MEMORY_TYPE = namedValues(MEMORY_TYPES);
239
+ MEMORY_SEGMENT = namedValues(MEMORY_SEGMENTS);
240
+ MEMORY_STORE_SCOPE = namedValues(MEMORY_STORE_SCOPES);
241
+ }
242
+ });
243
+
136
244
  // src/runtime/tools/schemas.ts
137
245
  function mcpToolNames(names) {
138
246
  return [...names].sort((a, b) => a.localeCompare(b)).map((name) => `${MCP_TOOL_PREFIX}${name}`);
@@ -146,6 +254,7 @@ var init_schemas = __esm({
146
254
  "src/runtime/tools/schemas.ts"() {
147
255
  "use strict";
148
256
  init_chatEvents();
257
+ init_memory();
149
258
  TOOL_MODELS = {
150
259
  thenvoi_send_message: {
151
260
  description: "Send a message to the chat room. Use this to respond to users or other agents. Messages require at least one @mention in the mentions array. You MUST use this tool to communicate \u2014 plain text responses won't reach users. When delegating, send the full task context in this message instead of assuming hidden state.",
@@ -332,29 +441,22 @@ var init_schemas = __esm({
332
441
  },
333
442
  scope: {
334
443
  type: "string",
335
- enum: ["subject", "organization", "all"],
444
+ enum: [...MEMORY_LIST_SCOPES],
336
445
  description: "Filter by scope."
337
446
  },
338
447
  system: {
339
448
  type: "string",
340
- enum: ["sensory", "working", "long_term"],
449
+ enum: [...MEMORY_SYSTEMS],
341
450
  description: "Filter by memory system."
342
451
  },
343
452
  type: {
344
453
  type: "string",
345
- enum: [
346
- "iconic",
347
- "echoic",
348
- "haptic",
349
- "episodic",
350
- "semantic",
351
- "procedural"
352
- ],
454
+ enum: [...MEMORY_TYPES],
353
455
  description: "Filter by memory type."
354
456
  },
355
457
  segment: {
356
458
  type: "string",
357
- enum: ["user", "agent", "tool", "guideline"],
459
+ enum: [...MEMORY_SEGMENTS],
358
460
  description: "Filter by segment."
359
461
  },
360
462
  content_query: {
@@ -369,7 +471,7 @@ var init_schemas = __esm({
369
471
  },
370
472
  status: {
371
473
  type: "string",
372
- enum: ["active", "superseded", "archived", "all"],
474
+ enum: [...MEMORY_STATUSES],
373
475
  description: "Filter by status."
374
476
  }
375
477
  },
@@ -384,24 +486,17 @@ var init_schemas = __esm({
384
486
  },
385
487
  system: {
386
488
  type: "string",
387
- enum: ["sensory", "working", "long_term"],
489
+ enum: [...MEMORY_SYSTEMS],
388
490
  description: "Memory system tier."
389
491
  },
390
492
  type: {
391
493
  type: "string",
392
- enum: [
393
- "iconic",
394
- "echoic",
395
- "haptic",
396
- "episodic",
397
- "semantic",
398
- "procedural"
399
- ],
494
+ enum: [...MEMORY_TYPES],
400
495
  description: "Memory type (must be valid for selected system)."
401
496
  },
402
497
  segment: {
403
498
  type: "string",
404
- enum: ["user", "agent", "tool", "guideline"],
499
+ enum: [...MEMORY_SEGMENTS],
405
500
  description: "Logical segment."
406
501
  },
407
502
  thought: {
@@ -410,7 +505,7 @@ var init_schemas = __esm({
410
505
  },
411
506
  scope: {
412
507
  type: "string",
413
- enum: ["subject", "organization"],
508
+ enum: [...MEMORY_STORE_SCOPES],
414
509
  description: "Visibility scope."
415
510
  },
416
511
  subject_id: {
@@ -598,6 +693,13 @@ function serializeValue(value) {
598
693
  return String(value);
599
694
  }
600
695
  }
696
+ function resolveSingleRoomTools(getToolsForRoom) {
697
+ const tools = getToolsForRoom("");
698
+ if (!tools) {
699
+ throw new Error('Single-room mode requires getToolsForRoom("") to return a tools instance');
700
+ }
701
+ return tools;
702
+ }
601
703
  var init_registrations = __esm({
602
704
  "src/mcp/registrations.ts"() {
603
705
  "use strict";
@@ -607,42 +709,42 @@ var init_registrations = __esm({
607
709
  });
608
710
 
609
711
  // src/mcp/zod.ts
610
- function buildZodShape(z5, properties, required) {
712
+ function buildZodShape(z6, properties, required) {
611
713
  const shape = {};
612
714
  for (const [name, schema] of Object.entries(properties)) {
613
- const validator = jsonSchemaToZod(z5, schema);
715
+ const validator = jsonSchemaToZod(z6, schema);
614
716
  shape[name] = required.has(name) ? validator : validator.optional();
615
717
  }
616
718
  return shape;
617
719
  }
618
- function jsonSchemaToZod(z5, schema) {
720
+ function jsonSchemaToZod(z6, schema) {
619
721
  const type = schema.type;
620
722
  if (type === "string") {
621
723
  if (Array.isArray(schema.enum) && schema.enum.every((v) => typeof v === "string")) {
622
724
  const values = schema.enum;
623
725
  if (values.length > 0) {
624
- return z5.enum(values);
726
+ return z6.enum(values);
625
727
  }
626
728
  }
627
- return z5.string();
729
+ return z6.string();
628
730
  }
629
731
  if (type === "integer" || type === "number") {
630
- return z5.number();
732
+ return z6.number();
631
733
  }
632
734
  if (type === "boolean") {
633
- return z5.boolean();
735
+ return z6.boolean();
634
736
  }
635
737
  if (type === "array") {
636
738
  const itemSchema = schema.items;
637
739
  if (itemSchema && typeof itemSchema === "object") {
638
- return z5.array(jsonSchemaToZod(z5, itemSchema));
740
+ return z6.array(jsonSchemaToZod(z6, itemSchema));
639
741
  }
640
- return z5.array(z5.unknown());
742
+ return z6.array(z6.unknown());
641
743
  }
642
744
  if (type === "object") {
643
- return z5.record(z5.string(), z5.unknown());
745
+ return z6.record(z6.string(), z6.unknown());
644
746
  }
645
- return z5.unknown();
747
+ return z6.unknown();
646
748
  }
647
749
  var init_zod = __esm({
648
750
  "src/mcp/zod.ts"() {
@@ -656,16 +758,16 @@ __export(sdk_exports, {
656
758
  createThenvoiSdkMcpServer: () => createThenvoiSdkMcpServer
657
759
  });
658
760
  function createThenvoiSdkMcpServer(options) {
659
- const registrations = buildRoomScopedRegistrations(
660
- options.getToolsForRoom,
661
- {
662
- enableMemoryTools: options.enableMemoryTools,
663
- enableContactTools: true,
664
- additionalTools: options.additionalTools
665
- }
666
- );
761
+ const registrationOptions = {
762
+ enableMemoryTools: options.enableMemoryTools,
763
+ enableContactTools: true,
764
+ additionalTools: options.additionalTools
765
+ };
766
+ const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolveSingleRoomTools(options.getToolsForRoom), registrationOptions) : buildRoomScopedRegistrations(options.getToolsForRoom, registrationOptions);
667
767
  const toolDefinitions = registrations.map(toSdkToolDefinition);
668
768
  const toolNames = new Set(registrations.map((r) => r.name));
769
+ const contextCache = /* @__PURE__ */ new Map();
770
+ const MAX_CONTEXT_CACHE_ENTRIES = 100;
669
771
  const serverConfig = (0, import_claude_agent_sdk.createSdkMcpServer)({
670
772
  name: "thenvoi",
671
773
  tools: toolDefinitions
@@ -673,12 +775,208 @@ function createThenvoiSdkMcpServer(options) {
673
775
  return {
674
776
  serverConfig,
675
777
  allowedTools: mcpToolNames(toolNames),
676
- toolDefinitions
778
+ toolDefinitions,
779
+ getSystemPromptContext: async (roomId, contextOptions) => {
780
+ const context = await getOrBuildSystemPromptContext(
781
+ roomId,
782
+ contextOptions,
783
+ options.getToolsForRoom,
784
+ contextCache,
785
+ MAX_CONTEXT_CACHE_ENTRIES
786
+ );
787
+ return context.markdown;
788
+ },
789
+ getSystemPromptContextData: (roomId, contextOptions) => {
790
+ return getOrBuildSystemPromptContext(
791
+ roomId,
792
+ contextOptions,
793
+ options.getToolsForRoom,
794
+ contextCache,
795
+ MAX_CONTEXT_CACHE_ENTRIES
796
+ );
797
+ }
798
+ };
799
+ }
800
+ async function getOrBuildSystemPromptContext(roomId, contextOptions, getToolsForRoom, contextCache, maxEntries) {
801
+ const ttlMs = contextOptions?.ttlMs ?? 3e4;
802
+ const now = Date.now();
803
+ const cached = contextCache.get(roomId);
804
+ if (cached && cached.expiresAt > now) {
805
+ cached.lastAccessedAt = now;
806
+ return cached.value;
807
+ }
808
+ if (cached) {
809
+ contextCache.delete(roomId);
810
+ }
811
+ const tools = getToolsForRoom(roomId);
812
+ if (!tools) {
813
+ return buildUnavailableSystemPromptContext(roomId);
814
+ }
815
+ const context = await buildSystemPromptContext(roomId, tools);
816
+ contextCache.set(roomId, {
817
+ value: context,
818
+ expiresAt: now + ttlMs,
819
+ lastAccessedAt: now
820
+ });
821
+ evictLeastRecentlyUsedContext(contextCache, maxEntries);
822
+ return context;
823
+ }
824
+ async function buildSystemPromptContext(roomId, tools) {
825
+ const participants = await tools.getParticipants();
826
+ const warnings = [];
827
+ const agentResolution = await resolveAgentIdentity(tools);
828
+ if (agentResolution.warning) {
829
+ warnings.push(agentResolution.warning);
830
+ }
831
+ const roomResolution = await resolveRoomTitle(tools, roomId);
832
+ if (roomResolution.warning) {
833
+ warnings.push(roomResolution.warning);
834
+ }
835
+ const agentIdentity = agentResolution.value;
836
+ const roomTitle = roomResolution.value;
837
+ const normalizedParticipants = participants.map((participant) => ({
838
+ id: String(participant.id),
839
+ name: String(participant.name ?? "Unknown"),
840
+ type: String(participant.type ?? "Unknown"),
841
+ handle: normalizeHandle2(participant.handle),
842
+ isSelf: participant.id === agentIdentity?.id
843
+ }));
844
+ const selfHandle = normalizeHandle2(agentIdentity?.handle);
845
+ const selfName = agentIdentity?.name ?? "Agent";
846
+ const mentionHandles = normalizedParticipants.filter((participant) => !participant.isSelf).map((participant) => participant.handle).filter((handle) => Boolean(handle));
847
+ const mentionFormat = mentionHandles.length > 0 ? mentionHandles.join(", ") : "No participant handles available";
848
+ const roomLabel = roomTitle ? `"${roomTitle}"` : "this room";
849
+ const agentLabel = selfHandle ? `${selfName} (${selfHandle})` : selfName;
850
+ const participantLines = normalizedParticipants.length > 0 ? normalizedParticipants.map((participant) => {
851
+ const suffix = participant.isSelf ? " (you)" : "";
852
+ const handle = participant.handle ? ` (${participant.handle})` : "";
853
+ return `- **${participant.name}**${handle} -- ${participant.type}${suffix}`;
854
+ }).join("\n") : "- No participants found";
855
+ const markdown = [
856
+ "## Room Context",
857
+ "",
858
+ `You are **${agentLabel}** in room ${roomLabel} (id: ${roomId}).`,
859
+ "",
860
+ "### Participants",
861
+ participantLines,
862
+ "",
863
+ "### Mention Format",
864
+ `To address someone, use their exact handle: ${mentionFormat}`,
865
+ ...warnings.length > 0 ? ["", "### Warnings", ...warnings.map((warning) => `- ${warning}`)] : []
866
+ ].join("\n");
867
+ return {
868
+ roomId,
869
+ roomTitle,
870
+ agent: {
871
+ id: agentIdentity?.id ?? "unknown-agent",
872
+ name: selfName,
873
+ handle: selfHandle,
874
+ description: agentIdentity?.description ?? null
875
+ },
876
+ participants: normalizedParticipants,
877
+ mentionFormat,
878
+ warnings,
879
+ markdown
880
+ };
881
+ }
882
+ async function resolveAgentIdentity(tools) {
883
+ const maybeTools = tools;
884
+ try {
885
+ if (maybeTools.getAgentIdentity) {
886
+ return { value: await maybeTools.getAgentIdentity(), warning: null };
887
+ }
888
+ if (maybeTools.rest?.getAgentMe) {
889
+ return { value: await maybeTools.rest.getAgentMe(), warning: null };
890
+ }
891
+ } catch (error) {
892
+ return {
893
+ value: null,
894
+ warning: `Unable to resolve agent identity: ${error instanceof Error ? error.message : String(error)}`
895
+ };
896
+ }
897
+ return { value: null, warning: null };
898
+ }
899
+ async function resolveRoomTitle(tools, roomId) {
900
+ const maybeTools = tools;
901
+ const rest = maybeTools.rest;
902
+ if (!rest?.listChats) {
903
+ return { value: null, warning: null };
904
+ }
905
+ try {
906
+ let page = 1;
907
+ const pageSize = 100;
908
+ while (true) {
909
+ const response = await rest.listChats({ page, pageSize });
910
+ const room = response?.data?.find((entry) => entry.id === roomId);
911
+ if (typeof room?.title === "string" && room.title.length > 0) {
912
+ return { value: room.title, warning: null };
913
+ }
914
+ const totalPages = response?.metadata?.totalPages ?? page;
915
+ if (page >= totalPages) {
916
+ return { value: null, warning: null };
917
+ }
918
+ page += 1;
919
+ }
920
+ } catch (error) {
921
+ return {
922
+ value: null,
923
+ warning: `Unable to resolve room title: ${error instanceof Error ? error.message : String(error)}`
924
+ };
925
+ }
926
+ }
927
+ function buildUnavailableSystemPromptContext(roomId) {
928
+ const warnings = [`No tool context found for room_id ${roomId}`];
929
+ const markdown = [
930
+ "## Room Context",
931
+ "",
932
+ `You are **Agent** in this room (id: ${roomId}).`,
933
+ "",
934
+ "### Participants",
935
+ "- No participants found",
936
+ "",
937
+ "### Mention Format",
938
+ "No participant handles available",
939
+ "",
940
+ "### Warnings",
941
+ ...warnings.map((warning) => `- ${warning}`)
942
+ ].join("\n");
943
+ return {
944
+ roomId,
945
+ roomTitle: null,
946
+ agent: {
947
+ id: "unknown-agent",
948
+ name: "Agent",
949
+ handle: null,
950
+ description: null
951
+ },
952
+ participants: [],
953
+ mentionFormat: "No participant handles available",
954
+ warnings,
955
+ markdown
677
956
  };
678
957
  }
958
+ function evictLeastRecentlyUsedContext(contextCache, maxEntries) {
959
+ if (contextCache.size <= maxEntries) {
960
+ return;
961
+ }
962
+ let oldestKey = null;
963
+ let oldestAccessedAt = Number.POSITIVE_INFINITY;
964
+ for (const [key, entry] of contextCache.entries()) {
965
+ if (entry.lastAccessedAt < oldestAccessedAt) {
966
+ oldestAccessedAt = entry.lastAccessedAt;
967
+ oldestKey = key;
968
+ }
969
+ }
970
+ if (oldestKey) {
971
+ contextCache.delete(oldestKey);
972
+ }
973
+ }
974
+ function normalizeHandle2(handle) {
975
+ return typeof handle === "string" && handle.trim().length > 0 ? handle.trim() : null;
976
+ }
679
977
  function toSdkToolDefinition(registration) {
680
978
  const shape = buildZodShape(
681
- import_zod6.z,
979
+ import_zod7.z,
682
980
  registration.inputSchema.properties,
683
981
  new Set(registration.inputSchema.required)
684
982
  );
@@ -689,12 +987,12 @@ function toSdkToolDefinition(registration) {
689
987
  async (args) => registration.execute(args)
690
988
  );
691
989
  }
692
- var import_claude_agent_sdk, import_zod6;
990
+ var import_claude_agent_sdk, import_zod7;
693
991
  var init_sdk = __esm({
694
992
  "src/mcp/sdk.ts"() {
695
993
  "use strict";
696
994
  import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
697
- import_zod6 = require("zod");
995
+ import_zod7 = require("zod");
698
996
  init_schemas();
699
997
  init_registrations();
700
998
  init_zod();
@@ -729,6 +1027,8 @@ __export(src_exports, {
729
1027
  TOOL_MODELS: () => TOOL_MODELS,
730
1028
  ThenvoiLink: () => ThenvoiLink,
731
1029
  VercelAISDKAdapter: () => VercelAISDKAdapter,
1030
+ WebSocketDisconnectError: () => WebSocketDisconnectError,
1031
+ deriveDefaultRestUrl: () => deriveDefaultRestUrl,
732
1032
  isDirectExecution: () => isDirectExecution,
733
1033
  loadAgentConfig: () => loadAgentConfig,
734
1034
  loadAgentConfigFromEnv: () => loadAgentConfigFromEnv
@@ -1758,56 +2058,242 @@ var payloadSchemas = {
1758
2058
 
1759
2059
  // src/platform/streaming/PhoenixChannelsTransport.ts
1760
2060
  var import_phoenix = require("phoenix");
1761
- var import_ws = require("ws");
1762
2061
  init_errors();
2062
+
2063
+ // src/platform/streaming/disconnectReason.ts
2064
+ var import_zod2 = require("zod");
2065
+ var UPGRADE_CODES = [
2066
+ "invalid_on_conflict",
2067
+ "connection_conflict",
2068
+ "too_many_requests",
2069
+ "tracking_failed"
2070
+ ];
2071
+ var UPGRADE_REASONS = {
2072
+ invalid_on_conflict: {
2073
+ status: 400,
2074
+ message: "Invalid websocket conflict policy.",
2075
+ retryable: false
2076
+ },
2077
+ connection_conflict: {
2078
+ status: 409,
2079
+ message: "Websocket connection conflict.",
2080
+ retryable: false
2081
+ },
2082
+ too_many_requests: {
2083
+ status: 429,
2084
+ message: "Too many websocket connection attempts.",
2085
+ retryable: true
2086
+ },
2087
+ tracking_failed: {
2088
+ status: 503,
2089
+ message: "Websocket connection tracking failed.",
2090
+ retryable: true
2091
+ }
2092
+ };
2093
+ var upgradeErrorSchema = import_zod2.z.object({
2094
+ status: import_zod2.z.number(),
2095
+ body: import_zod2.z.preprocess(
2096
+ (body) => {
2097
+ if (typeof body !== "string") {
2098
+ return body;
2099
+ }
2100
+ try {
2101
+ return JSON.parse(body);
2102
+ } catch {
2103
+ return null;
2104
+ }
2105
+ },
2106
+ import_zod2.z.object({
2107
+ error: import_zod2.z.object({
2108
+ code: import_zod2.z.enum(UPGRADE_CODES),
2109
+ message: import_zod2.z.string().optional(),
2110
+ retry_after: import_zod2.z.number().nullable().optional(),
2111
+ request_id: import_zod2.z.string().nullable().optional()
2112
+ })
2113
+ })
2114
+ ),
2115
+ headers: import_zod2.z.record(import_zod2.z.unknown()).optional()
2116
+ });
2117
+ var WebSocketDisconnectError = class extends Error {
2118
+ reason;
2119
+ constructor(reason) {
2120
+ super(reason.message);
2121
+ this.name = "WebSocketDisconnectError";
2122
+ this.reason = reason;
2123
+ }
2124
+ };
2125
+ function parseSupersedeDisconnectReason(payload) {
2126
+ if (typeof payload.reason !== "string" || typeof payload.message !== "string") {
2127
+ return null;
2128
+ }
2129
+ return {
2130
+ source: "agent_control",
2131
+ code: payload.reason,
2132
+ message: payload.message,
2133
+ retryable: false,
2134
+ retryAfter: typeof payload.retry_after === "number" ? payload.retry_after : null,
2135
+ targetSocketId: typeof payload.target_socket_id === "string" ? payload.target_socket_id : null,
2136
+ correlationId: typeof payload.correlation_id === "string" ? payload.correlation_id : null
2137
+ };
2138
+ }
2139
+ function parseUpgradeDisconnectReason(event) {
2140
+ const parsed = upgradeErrorSchema.safeParse(event);
2141
+ if (!parsed.success) {
2142
+ return null;
2143
+ }
2144
+ const { status, body, headers } = parsed.data;
2145
+ const {
2146
+ code,
2147
+ message,
2148
+ retry_after: retryAfter,
2149
+ request_id: requestId
2150
+ } = body.error;
2151
+ const reason = UPGRADE_REASONS[code];
2152
+ if (status !== reason.status) {
2153
+ return null;
2154
+ }
2155
+ return {
2156
+ source: "upgrade",
2157
+ status: reason.status,
2158
+ code,
2159
+ message: message ?? reason.message,
2160
+ retryable: reason.retryable,
2161
+ retryAfter: retryAfter ?? retryAfterFromHeaders(headers),
2162
+ requestId: requestId ?? null
2163
+ };
2164
+ }
2165
+ function genericCloseReason(event) {
2166
+ return {
2167
+ source: "websocket_close",
2168
+ code: "websocket.closed",
2169
+ message: "Phoenix socket closed without a platform disconnect reason.",
2170
+ retryable: true,
2171
+ closeCode: typeof event?.code === "number" ? event.code : null,
2172
+ closeReason: typeof event?.reason === "string" && event.reason.length > 0 ? event.reason : null
2173
+ };
2174
+ }
2175
+ function retryAfterFromHeaders(headers) {
2176
+ const value = headers?.["retry-after"] ?? headers?.["Retry-After"];
2177
+ if (typeof value === "number") {
2178
+ return value;
2179
+ }
2180
+ if (typeof value === "string" && value.trim() !== "") {
2181
+ const seconds = Number(value);
2182
+ return Number.isFinite(seconds) ? seconds : null;
2183
+ }
2184
+ return null;
2185
+ }
2186
+
2187
+ // src/platform/streaming/nodeWebSocketFactory.ts
2188
+ var import_ws = require("ws");
2189
+ function createNodeWebSocketFactory(headers) {
2190
+ const Constructor = import_ws.WebSocket;
2191
+ class ThenvoiNodeWebSocket {
2192
+ constructor(address, protocols) {
2193
+ const socket = new Constructor(address, protocols, headers ? { headers } : void 0);
2194
+ socket.once("unexpected-response", (request, response) => {
2195
+ void emitUpgradeError(socket, request, response);
2196
+ });
2197
+ return socket;
2198
+ }
2199
+ }
2200
+ return ThenvoiNodeWebSocket;
2201
+ }
2202
+ async function emitUpgradeError(websocket, request, response) {
2203
+ const body = await readResponseBody(response);
2204
+ const error = new Error(
2205
+ `Unexpected server response: ${response.statusCode ?? "unknown"}`
2206
+ );
2207
+ error.status = response.statusCode;
2208
+ error.body = body;
2209
+ error.headers = response.headers;
2210
+ request.destroy();
2211
+ websocket.emit("error", error);
2212
+ websocket.emit("close", 1006, Buffer.alloc(0));
2213
+ }
2214
+ async function readResponseBody(response) {
2215
+ const chunks = [];
2216
+ for await (const chunk of response) {
2217
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
2218
+ }
2219
+ return Buffer.concat(chunks).toString("utf8");
2220
+ }
2221
+
2222
+ // src/platform/streaming/PhoenixChannelsTransport.ts
1763
2223
  var PhoenixChannelsTransport = class {
1764
2224
  socket;
2225
+ agentId;
1765
2226
  channels = /* @__PURE__ */ new Map();
1766
2227
  channelRefs = /* @__PURE__ */ new Map();
1767
2228
  pendingJoins = /* @__PURE__ */ new Map();
1768
2229
  logger;
2230
+ onTerminalDisconnect;
1769
2231
  onHandlerError;
1770
2232
  connected = false;
1771
2233
  connectPromise = null;
1772
2234
  connectResolve = null;
2235
+ connectReject = null;
2236
+ lastDisconnectReason = null;
2237
+ terminalDisconnectError = null;
2238
+ runForeverWaiters = /* @__PURE__ */ new Set();
2239
+ stoppingReconnect = false;
2240
+ suppressNextCloseReason = false;
1773
2241
  constructor(options) {
1774
2242
  this.logger = options.logger ?? new NoopLogger();
2243
+ this.agentId = options.agentId;
2244
+ this.onTerminalDisconnect = options.onTerminalDisconnect;
1775
2245
  let wsUrl = options.wsUrl;
1776
2246
  if (wsUrl.endsWith("/websocket")) {
1777
2247
  wsUrl = wsUrl.slice(0, -"/websocket".length);
1778
2248
  }
2249
+ const reconnectAfterMs = options.reconnectAfterMs ?? ((tries) => [1e3, 2e3, 5e3, 1e4, 3e4][tries - 1] ?? 3e4);
1779
2250
  this.socket = new import_phoenix.Socket(wsUrl, {
1780
2251
  params: {
1781
- api_key: options.apiKey,
1782
- agent_id: options.agentId
2252
+ agent_id: options.agentId,
2253
+ ...options.conflictPolicy ? { on_conflict: options.conflictPolicy } : {}
1783
2254
  },
1784
2255
  heartbeatIntervalMs: options.heartbeatIntervalMs,
1785
- reconnectAfterMs: options.reconnectAfterMs ?? ((tries) => [1e3, 2e3, 5e3, 1e4, 3e4][tries - 1] ?? 3e4),
1786
- transport: options.websocketFactory ?? resolveWebSocketFactory()
2256
+ reconnectAfterMs: (tries) => {
2257
+ if (this.terminalDisconnectError) {
2258
+ return Number.POSITIVE_INFINITY;
2259
+ }
2260
+ return reconnectAfterMs(tries);
2261
+ },
2262
+ transport: options.websocketFactory ?? resolveWebSocketFactory(options.apiKey)
1787
2263
  });
1788
2264
  this.socket.onOpen(() => {
1789
- this.connected = true;
1790
- this.connectResolve?.();
1791
- this.connectResolve = null;
1792
- this.logger.info("Phoenix socket opened", {
1793
- channels: getSocketChannelCount(this.socket)
1794
- });
2265
+ void this.handleOpen();
1795
2266
  });
1796
2267
  this.socket.onClose((event) => {
1797
- this.connected = false;
1798
- if (getSocketChannelCount(this.socket) === 0) {
1799
- this.socket.disconnect();
1800
- }
1801
- this.logger.info("Phoenix socket closed", {
1802
- code: event?.code ?? null,
1803
- reason: event?.reason ?? null
1804
- });
2268
+ this.recordSocketClose(event);
1805
2269
  });
1806
2270
  this.socket.onError((event) => {
2271
+ const errorEvent = unwrapErrorEvent(event);
2272
+ const upgradeReason = parseUpgradeDisconnectReason(errorEvent);
2273
+ if (upgradeReason) {
2274
+ if (upgradeReason.retryable) {
2275
+ this.lastDisconnectReason = upgradeReason;
2276
+ this.connectReject?.(new WebSocketDisconnectError(upgradeReason));
2277
+ this.stopReconnectIfNoChannels({ suppressCloseReason: true });
2278
+ } else {
2279
+ this.recordTerminalDisconnect(upgradeReason);
2280
+ }
2281
+ this.logger.warn("Phoenix socket upgrade failed", {
2282
+ reason: upgradeReason
2283
+ });
2284
+ return;
2285
+ }
2286
+ this.connectReject?.(
2287
+ new TransportError("Phoenix socket connection failed", errorEvent)
2288
+ );
2289
+ this.stopReconnectIfNoChannels({ suppressCloseReason: true });
1807
2290
  this.logger.warn("Phoenix socket error", { event });
1808
2291
  });
1809
2292
  }
1810
2293
  async connect() {
2294
+ if (this.terminalDisconnectError) {
2295
+ throw this.terminalDisconnectError;
2296
+ }
1811
2297
  if (this.connected) {
1812
2298
  return;
1813
2299
  }
@@ -1831,15 +2317,30 @@ var PhoenixChannelsTransport = class {
1831
2317
  await this.connectPromise;
1832
2318
  }
1833
2319
  async disconnect() {
1834
- for (const topic of this.channels.keys()) {
1835
- await this.leave(topic);
1836
- }
2320
+ const results = await Promise.allSettled(
2321
+ [...this.channels.keys()].map((topic) => this.leave(topic))
2322
+ );
1837
2323
  this.socket.disconnect();
1838
2324
  this.connected = false;
2325
+ const failures = [];
2326
+ for (const result of results) {
2327
+ if (result.status === "rejected") {
2328
+ failures.push(result.reason);
2329
+ }
2330
+ }
2331
+ if (failures.length > 0) {
2332
+ throw new AggregateError(
2333
+ failures,
2334
+ "Failed to leave one or more Phoenix topics during disconnect"
2335
+ );
2336
+ }
1839
2337
  }
1840
2338
  isConnected() {
1841
2339
  return this.connected;
1842
2340
  }
2341
+ getDisconnectReason() {
2342
+ return this.lastDisconnectReason;
2343
+ }
1843
2344
  async join(topic, handlers) {
1844
2345
  if (this.channels.has(topic)) {
1845
2346
  return;
@@ -1875,7 +2376,10 @@ var PhoenixChannelsTransport = class {
1875
2376
  channel.join().receive("ok", () => resolve()).receive(
1876
2377
  "error",
1877
2378
  (error) => reject(new TransportError(`Failed to join topic ${topic}`, error))
1878
- ).receive("timeout", () => reject(new TransportError(`Timeout joining topic ${topic}`)));
2379
+ ).receive(
2380
+ "timeout",
2381
+ () => reject(new TransportError(`Timeout joining topic ${topic}`))
2382
+ );
1879
2383
  });
1880
2384
  } catch (error) {
1881
2385
  for (const [event, ref] of refs) {
@@ -1903,19 +2407,127 @@ var PhoenixChannelsTransport = class {
1903
2407
  channel.leave().receive("ok", () => resolve()).receive(
1904
2408
  "error",
1905
2409
  (error) => reject(new TransportError(`Failed to leave topic ${topic}`, error))
1906
- ).receive("timeout", () => reject(new TransportError(`Timeout leaving topic ${topic}`)));
2410
+ ).receive(
2411
+ "timeout",
2412
+ () => reject(new TransportError(`Timeout leaving topic ${topic}`))
2413
+ );
1907
2414
  });
1908
2415
  this.channels.delete(topic);
1909
2416
  this.logger.debug("Left topic", { topic });
1910
2417
  }
1911
2418
  async runForever(signal) {
2419
+ if (this.terminalDisconnectError) {
2420
+ throw this.terminalDisconnectError;
2421
+ }
1912
2422
  if (signal.aborted) {
1913
2423
  return;
1914
2424
  }
1915
- await new Promise((resolve) => {
1916
- signal.addEventListener("abort", () => resolve(), { once: true });
2425
+ await new Promise((resolve, reject) => {
2426
+ let settled = false;
2427
+ const abortController = new AbortController();
2428
+ const waiter = {
2429
+ reject: (error) => {
2430
+ if (settled) {
2431
+ return;
2432
+ }
2433
+ settled = true;
2434
+ this.runForeverWaiters.delete(waiter);
2435
+ abortController.abort();
2436
+ reject(error);
2437
+ }
2438
+ };
2439
+ this.runForeverWaiters.add(waiter);
2440
+ signal.addEventListener(
2441
+ "abort",
2442
+ () => {
2443
+ if (settled) {
2444
+ return;
2445
+ }
2446
+ settled = true;
2447
+ this.runForeverWaiters.delete(waiter);
2448
+ resolve();
2449
+ },
2450
+ { once: true, signal: abortController.signal }
2451
+ );
2452
+ });
2453
+ }
2454
+ async handleOpen() {
2455
+ try {
2456
+ await this.subscribeAgentControl();
2457
+ } catch (error) {
2458
+ this.connected = false;
2459
+ this.socket.disconnect();
2460
+ this.connectReject?.(
2461
+ error instanceof Error ? error : new TransportError(String(error))
2462
+ );
2463
+ this.logger.warn("Failed to join mandatory agent_control channel", {
2464
+ error
2465
+ });
2466
+ return;
2467
+ }
2468
+ this.connected = true;
2469
+ this.connectResolve?.();
2470
+ this.connectResolve = null;
2471
+ this.connectReject = null;
2472
+ this.logger.info("Phoenix socket opened", {
2473
+ channels: getSocketChannelCount(this.socket)
2474
+ });
2475
+ }
2476
+ stopReconnectIfNoChannels(options = {}) {
2477
+ if (this.stoppingReconnect || getSocketChannelCount(this.socket) !== 0) {
2478
+ return;
2479
+ }
2480
+ this.suppressNextCloseReason = options.suppressCloseReason ?? false;
2481
+ this.stoppingReconnect = true;
2482
+ this.socket.disconnect();
2483
+ this.stoppingReconnect = false;
2484
+ }
2485
+ async subscribeAgentControl() {
2486
+ if (!this.agentId) {
2487
+ return;
2488
+ }
2489
+ await this.join(`agent_control:${this.agentId}`, {
2490
+ supersede: (payload) => {
2491
+ const reason = parseSupersedeDisconnectReason(payload);
2492
+ if (!reason) {
2493
+ this.logger.warn("Invalid agent_control supersede payload", {
2494
+ payload
2495
+ });
2496
+ return;
2497
+ }
2498
+ this.recordTerminalDisconnect(reason);
2499
+ }
1917
2500
  });
1918
2501
  }
2502
+ recordSocketClose(event) {
2503
+ this.connected = false;
2504
+ const suppressCloseReason = this.suppressNextCloseReason;
2505
+ this.suppressNextCloseReason = false;
2506
+ this.stopReconnectIfNoChannels();
2507
+ if (!suppressCloseReason && !this.terminalDisconnectError && !this.lastDisconnectReason) {
2508
+ this.lastDisconnectReason = genericCloseReason(event);
2509
+ }
2510
+ this.logger.info("Phoenix socket closed", {
2511
+ code: event?.code ?? null,
2512
+ reason: event?.reason ?? null,
2513
+ platformReason: this.lastDisconnectReason
2514
+ });
2515
+ }
2516
+ recordTerminalDisconnect(reason) {
2517
+ if (this.terminalDisconnectError) {
2518
+ return;
2519
+ }
2520
+ const error = new WebSocketDisconnectError(reason);
2521
+ this.lastDisconnectReason = reason;
2522
+ this.terminalDisconnectError = error;
2523
+ this.onTerminalDisconnect?.(reason);
2524
+ this.connectReject?.(error);
2525
+ for (const waiter of this.runForeverWaiters) {
2526
+ waiter.reject(error);
2527
+ }
2528
+ this.runForeverWaiters.clear();
2529
+ this.socket.disconnect();
2530
+ }
1919
2531
  async waitForConnection(timeoutMs = 1e4) {
1920
2532
  if (this.connected) {
1921
2533
  return;
@@ -1923,20 +2535,43 @@ var PhoenixChannelsTransport = class {
1923
2535
  await new Promise((resolve, reject) => {
1924
2536
  const timeout = setTimeout(() => {
1925
2537
  this.connectResolve = null;
1926
- reject(new TransportError("Timed out waiting for Phoenix socket connection"));
2538
+ this.connectReject = null;
2539
+ reject(
2540
+ new TransportError("Timed out waiting for Phoenix socket connection")
2541
+ );
1927
2542
  }, timeoutMs);
1928
2543
  this.connectResolve = () => {
1929
2544
  clearTimeout(timeout);
2545
+ this.connectReject = null;
1930
2546
  resolve();
1931
2547
  };
2548
+ this.connectReject = (error) => {
2549
+ clearTimeout(timeout);
2550
+ this.connectResolve = null;
2551
+ this.connectReject = null;
2552
+ reject(
2553
+ error instanceof Error ? error : new TransportError(String(error))
2554
+ );
2555
+ };
1932
2556
  });
1933
2557
  }
1934
2558
  };
1935
- function resolveWebSocketFactory() {
2559
+ function resolveWebSocketFactory(apiKey) {
1936
2560
  if (typeof process !== "undefined" && process.versions?.node) {
1937
- return import_ws.WebSocket;
2561
+ return createNodeWebSocketFactory({ "x-api-key": apiKey });
2562
+ }
2563
+ throw new TransportError(
2564
+ "Phoenix WebSocket API-key auth requires a WebSocket transport that can set handshake headers."
2565
+ );
2566
+ }
2567
+ function unwrapErrorEvent(event) {
2568
+ if (!isErrorEvent(event)) {
2569
+ return event;
1938
2570
  }
1939
- return WebSocket;
2571
+ return event.error;
2572
+ }
2573
+ function isErrorEvent(event) {
2574
+ return typeof event === "object" && event !== null && "error" in event;
1940
2575
  }
1941
2576
  function removeSocketChannel(socket, channel) {
1942
2577
  const candidate = socket;
@@ -1959,6 +2594,12 @@ function deriveDefaultRestUrl(wsUrl) {
1959
2594
  const protocol = parsed.protocol === "ws:" ? "http:" : "https:";
1960
2595
  return `${protocol}//${parsed.host}`;
1961
2596
  }
2597
+ function roomTopics(roomId) {
2598
+ return {
2599
+ chat: `chat_room:${roomId}`,
2600
+ participants: `room_participants:${roomId}`
2601
+ };
2602
+ }
1962
2603
  function toPlatformMessage(roomId, message) {
1963
2604
  return {
1964
2605
  id: message.id,
@@ -1985,6 +2626,8 @@ var ThenvoiLink = class {
1985
2626
  eventQueue = [];
1986
2627
  waiters = [];
1987
2628
  connected = false;
2629
+ lastDisconnectReason = null;
2630
+ terminalDisconnectError = null;
1988
2631
  constructor(options) {
1989
2632
  this.agentId = options.agentId;
1990
2633
  this.apiKey = options.apiKey;
@@ -2006,17 +2649,35 @@ var ThenvoiLink = class {
2006
2649
  wsUrl: this.wsUrl,
2007
2650
  apiKey: this.apiKey,
2008
2651
  agentId: this.agentId,
2009
- logger: this.logger
2652
+ logger: this.logger,
2653
+ conflictPolicy: options.conflictPolicy,
2654
+ onTerminalDisconnect: (reason) => {
2655
+ this.recordDisconnectReason(reason);
2656
+ }
2010
2657
  });
2011
2658
  }
2012
2659
  isConnected() {
2013
2660
  return this.connected;
2014
2661
  }
2662
+ getDisconnectReason() {
2663
+ return this.lastDisconnectReason;
2664
+ }
2015
2665
  async connect() {
2016
2666
  if (this.connected) {
2017
2667
  return;
2018
2668
  }
2019
- await this.transport.connect();
2669
+ try {
2670
+ await this.transport.connect();
2671
+ } catch (error) {
2672
+ if (error instanceof WebSocketDisconnectError) {
2673
+ if (error.reason.retryable) {
2674
+ this.lastDisconnectReason = error.reason;
2675
+ } else {
2676
+ this.recordDisconnectError(error);
2677
+ }
2678
+ }
2679
+ throw error;
2680
+ }
2020
2681
  this.connected = true;
2021
2682
  }
2022
2683
  async disconnect() {
@@ -2030,8 +2691,23 @@ var ThenvoiLink = class {
2030
2691
  this.connected = false;
2031
2692
  }
2032
2693
  async runForever(signal) {
2694
+ if (this.terminalDisconnectError) {
2695
+ throw this.terminalDisconnectError;
2696
+ }
2033
2697
  await this.transport.runForever(signal);
2034
2698
  }
2699
+ recordDisconnectReason(reason) {
2700
+ this.recordDisconnectError(new WebSocketDisconnectError(reason));
2701
+ }
2702
+ recordDisconnectError(error) {
2703
+ this.connected = false;
2704
+ this.lastDisconnectReason = error.reason;
2705
+ this.terminalDisconnectError = error;
2706
+ while (this.waiters.length > 0) {
2707
+ const waiter = this.waiters.shift();
2708
+ waiter?.reject(error);
2709
+ }
2710
+ }
2035
2711
  queueEvent(event) {
2036
2712
  const waiter = this.waiters.shift();
2037
2713
  if (waiter) {
@@ -2056,32 +2732,42 @@ var ThenvoiLink = class {
2056
2732
  if (this.subscribedRooms.has(roomId)) {
2057
2733
  return;
2058
2734
  }
2059
- await this.transport.join(`chat_room:${roomId}`, {
2060
- message_created: (payload) => {
2061
- this.emit("message_created", payload, roomId);
2062
- }
2063
- });
2064
- await this.transport.join(`room_participants:${roomId}`, {
2065
- participant_added: (payload) => {
2066
- this.emit("participant_added", payload, roomId);
2067
- },
2068
- participant_removed: (payload) => {
2069
- this.emit("participant_removed", payload, roomId);
2070
- },
2071
- room_deleted: (payload) => {
2072
- this.emit("room_deleted", payload, roomId);
2073
- }
2074
- });
2735
+ await this.joinRoomTopics(roomId);
2075
2736
  this.subscribedRooms.add(roomId);
2076
2737
  }
2077
2738
  async unsubscribeRoom(roomId) {
2078
2739
  if (!this.subscribedRooms.has(roomId)) {
2079
2740
  return;
2080
2741
  }
2081
- await this.transport.leave(`chat_room:${roomId}`);
2082
- await this.transport.leave(`room_participants:${roomId}`);
2742
+ const topics = roomTopics(roomId);
2743
+ await this.transport.leave(topics.chat);
2744
+ await this.transport.leave(topics.participants);
2083
2745
  this.subscribedRooms.delete(roomId);
2084
2746
  }
2747
+ async joinRoomTopics(roomId) {
2748
+ const topics = roomTopics(roomId);
2749
+ await this.transport.join(topics.chat, {
2750
+ message_created: (payload) => {
2751
+ this.emit("message_created", payload, roomId);
2752
+ }
2753
+ });
2754
+ try {
2755
+ await this.transport.join(topics.participants, {
2756
+ participant_added: (payload) => {
2757
+ this.emit("participant_added", payload, roomId);
2758
+ },
2759
+ participant_removed: (payload) => {
2760
+ this.emit("participant_removed", payload, roomId);
2761
+ },
2762
+ room_deleted: (payload) => {
2763
+ this.emit("room_deleted", payload, roomId);
2764
+ }
2765
+ });
2766
+ } catch (error) {
2767
+ await this.transport.leave(topics.chat);
2768
+ throw error;
2769
+ }
2770
+ }
2085
2771
  async subscribeAgentContacts() {
2086
2772
  assertCapability(this.capabilities, "contacts", "Contacts streaming");
2087
2773
  await this.transport.join(`agent_contacts:${this.agentId}`, {
@@ -2103,6 +2789,9 @@ var ThenvoiLink = class {
2103
2789
  await this.transport.leave(`agent_contacts:${this.agentId}`);
2104
2790
  }
2105
2791
  async nextEvent(signal) {
2792
+ if (this.terminalDisconnectError) {
2793
+ throw this.terminalDisconnectError;
2794
+ }
2106
2795
  if (signal?.aborted) {
2107
2796
  return null;
2108
2797
  }
@@ -2110,19 +2799,19 @@ var ThenvoiLink = class {
2110
2799
  if (queued) {
2111
2800
  return queued;
2112
2801
  }
2113
- return new Promise((resolve) => {
2802
+ return new Promise((resolve, reject) => {
2114
2803
  let settled = false;
2115
2804
  const onAbort = () => {
2116
2805
  const index = this.waiters.indexOf(waiter);
2117
2806
  if (index >= 0) {
2118
2807
  this.waiters.splice(index, 1);
2119
2808
  }
2120
- finalize(null);
2809
+ finalizeResolve(null);
2121
2810
  };
2122
2811
  const cleanup = () => {
2123
2812
  signal?.removeEventListener("abort", onAbort);
2124
2813
  };
2125
- const finalize = (event) => {
2814
+ const finalizeResolve = (event) => {
2126
2815
  if (settled) {
2127
2816
  return;
2128
2817
  }
@@ -2130,8 +2819,17 @@ var ThenvoiLink = class {
2130
2819
  cleanup();
2131
2820
  resolve(event);
2132
2821
  };
2822
+ const finalizeReject = (error) => {
2823
+ if (settled) {
2824
+ return;
2825
+ }
2826
+ settled = true;
2827
+ cleanup();
2828
+ reject(error);
2829
+ };
2133
2830
  const waiter = {
2134
- resolve: finalize,
2831
+ resolve: finalizeResolve,
2832
+ reject: finalizeReject,
2135
2833
  cleanup
2136
2834
  };
2137
2835
  this.waiters.push(waiter);
@@ -2143,7 +2841,10 @@ var ThenvoiLink = class {
2143
2841
  next: async () => {
2144
2842
  const value = await this.nextEvent();
2145
2843
  if (value === null) {
2146
- return { done: true, value: void 0 };
2844
+ return {
2845
+ done: true,
2846
+ value: void 0
2847
+ };
2147
2848
  }
2148
2849
  return { done: false, value };
2149
2850
  }
@@ -2225,7 +2926,9 @@ var ThenvoiLink = class {
2225
2926
  }
2226
2927
  async listChats(request, requestOptions) {
2227
2928
  if (!this.rest.listChats) {
2228
- throw new UnsupportedFeatureError("Chat listing is not available in current REST adapter");
2929
+ throw new UnsupportedFeatureError(
2930
+ "Chat listing is not available in current REST adapter"
2931
+ );
2229
2932
  }
2230
2933
  return this.rest.listChats(request, requestOptions);
2231
2934
  }
@@ -2558,6 +3261,7 @@ init_errors();
2558
3261
  init_chatEvents();
2559
3262
  init_protocols();
2560
3263
  init_schemas();
3264
+ init_memory();
2561
3265
  var REQUIRED_ADAPTER_TOOL_METHODS = [
2562
3266
  "sendMessage",
2563
3267
  "sendEvent",
@@ -2592,40 +3296,6 @@ var CONTACT_REQUEST_ACTIONS = /* @__PURE__ */ new Set([
2592
3296
  "reject",
2593
3297
  "cancel"
2594
3298
  ]);
2595
- var MEMORY_SYSTEMS = /* @__PURE__ */ new Set([
2596
- "sensory",
2597
- "working",
2598
- "long_term"
2599
- ]);
2600
- var MEMORY_TYPES = /* @__PURE__ */ new Set([
2601
- "iconic",
2602
- "echoic",
2603
- "haptic",
2604
- "episodic",
2605
- "semantic",
2606
- "procedural"
2607
- ]);
2608
- var MEMORY_SEGMENTS = /* @__PURE__ */ new Set([
2609
- "user",
2610
- "agent",
2611
- "tool",
2612
- "guideline"
2613
- ]);
2614
- var LIST_MEMORY_SCOPES = /* @__PURE__ */ new Set([
2615
- "subject",
2616
- "organization",
2617
- "all"
2618
- ]);
2619
- var LIST_MEMORY_STATUSES = /* @__PURE__ */ new Set([
2620
- "active",
2621
- "superseded",
2622
- "archived",
2623
- "all"
2624
- ]);
2625
- var MEMORY_SCOPES = /* @__PURE__ */ new Set([
2626
- "subject",
2627
- "organization"
2628
- ]);
2629
3299
  var AgentTools = class {
2630
3300
  roomId;
2631
3301
  capabilities;
@@ -3203,6 +3873,9 @@ var AgentTools = class {
3203
3873
  const status = this.normalizeOptionalMemoryStatus(arguments_.status);
3204
3874
  const subjectId = this.normalizeOptionalString(arguments_.subject_id);
3205
3875
  const contentQuery = this.normalizeOptionalString(arguments_.content_query);
3876
+ if (system && type && !isMemoryTypeForSystem(system, type)) {
3877
+ throw new ValidationError(memoryTypeForSystemError(system));
3878
+ }
3206
3879
  return {
3207
3880
  ...subjectId ? { subject_id: subjectId } : {},
3208
3881
  ...scope ? { scope } : {},
@@ -3224,13 +3897,21 @@ var AgentTools = class {
3224
3897
  const subjectId = this.normalizeOptionalString(arguments_.subject_id);
3225
3898
  const metadata = this.normalizeOptionalMetadata(arguments_.metadata);
3226
3899
  if (!system) {
3227
- throw new ValidationError("system must be one of: sensory, working, long_term");
3900
+ throw new ValidationError(`system must be one of: ${expectedList(MEMORY_SYSTEMS)}`);
3228
3901
  }
3229
3902
  if (!type) {
3230
- throw new ValidationError("type must be one of: iconic, echoic, haptic, episodic, semantic, procedural");
3903
+ throw new ValidationError(`type must be one of: ${expectedList(MEMORY_TYPES)}`);
3904
+ }
3905
+ if (!isMemoryTypeForSystem(system, type)) {
3906
+ throw new ValidationError(memoryTypeForSystemError(system));
3231
3907
  }
3232
3908
  if (!segment) {
3233
- throw new ValidationError("segment must be one of: user, agent, tool, guideline");
3909
+ throw new ValidationError(`segment must be one of: ${expectedList(MEMORY_SEGMENTS)}`);
3910
+ }
3911
+ if (scope === "subject" && !subjectId) {
3912
+ throw new ValidationError(
3913
+ 'scope="subject" requires a subject_id (the UUID of the person or agent the memory is about). If you do not have a concrete subject UUID, retry with scope="organization" and omit subject_id. Do not invent a UUID.'
3914
+ );
3234
3915
  }
3235
3916
  return {
3236
3917
  content,
@@ -3310,8 +3991,8 @@ var AgentTools = class {
3310
3991
  if (!normalized) {
3311
3992
  return void 0;
3312
3993
  }
3313
- if (!isListMemoryScope(normalized)) {
3314
- throw new ValidationError("scope must be one of: subject, organization, all");
3994
+ if (!isMemoryListScope(normalized)) {
3995
+ throw new ValidationError(`scope must be one of: ${expectedList(MEMORY_LIST_SCOPES)}`);
3315
3996
  }
3316
3997
  return normalized;
3317
3998
  }
@@ -3321,7 +4002,7 @@ var AgentTools = class {
3321
4002
  return void 0;
3322
4003
  }
3323
4004
  if (!isMemorySystem(normalized)) {
3324
- throw new ValidationError("system must be one of: sensory, working, long_term");
4005
+ throw new ValidationError(`system must be one of: ${expectedList(MEMORY_SYSTEMS)}`);
3325
4006
  }
3326
4007
  return normalized;
3327
4008
  }
@@ -3331,7 +4012,7 @@ var AgentTools = class {
3331
4012
  return void 0;
3332
4013
  }
3333
4014
  if (!isMemoryType(normalized)) {
3334
- throw new ValidationError("type must be one of: iconic, echoic, haptic, episodic, semantic, procedural");
4015
+ throw new ValidationError(`type must be one of: ${expectedList(MEMORY_TYPES)}`);
3335
4016
  }
3336
4017
  return normalized;
3337
4018
  }
@@ -3341,7 +4022,7 @@ var AgentTools = class {
3341
4022
  return void 0;
3342
4023
  }
3343
4024
  if (!isMemorySegment(normalized)) {
3344
- throw new ValidationError("segment must be one of: user, agent, tool, guideline");
4025
+ throw new ValidationError(`segment must be one of: ${expectedList(MEMORY_SEGMENTS)}`);
3345
4026
  }
3346
4027
  return normalized;
3347
4028
  }
@@ -3351,7 +4032,7 @@ var AgentTools = class {
3351
4032
  return void 0;
3352
4033
  }
3353
4034
  if (!isMemoryStatus(normalized)) {
3354
- throw new ValidationError("status must be one of: active, superseded, archived, all");
4035
+ throw new ValidationError(`status must be one of: ${expectedList(MEMORY_STATUSES)}`);
3355
4036
  }
3356
4037
  return normalized;
3357
4038
  }
@@ -3360,8 +4041,8 @@ var AgentTools = class {
3360
4041
  if (!normalized) {
3361
4042
  return void 0;
3362
4043
  }
3363
- if (!isStoreMemoryScope(normalized)) {
3364
- throw new ValidationError("scope must be one of: subject, organization");
4044
+ if (!isMemoryStoreScope(normalized)) {
4045
+ throw new ValidationError(`scope must be one of: ${expectedList(MEMORY_STORE_SCOPES)}`);
3365
4046
  }
3366
4047
  return normalized;
3367
4048
  }
@@ -3369,24 +4050,6 @@ var AgentTools = class {
3369
4050
  function isContactRequestAction(value) {
3370
4051
  return CONTACT_REQUEST_ACTIONS.has(value);
3371
4052
  }
3372
- function isMemorySystem(value) {
3373
- return MEMORY_SYSTEMS.has(value);
3374
- }
3375
- function isMemoryType(value) {
3376
- return MEMORY_TYPES.has(value);
3377
- }
3378
- function isMemorySegment(value) {
3379
- return MEMORY_SEGMENTS.has(value);
3380
- }
3381
- function isStoreMemoryScope(value) {
3382
- return MEMORY_SCOPES.has(value);
3383
- }
3384
- function isListMemoryScope(value) {
3385
- return LIST_MEMORY_SCOPES.has(value);
3386
- }
3387
- function isMemoryStatus(value) {
3388
- return LIST_MEMORY_STATUSES.has(value);
3389
- }
3390
4053
  function coercePositiveInt(value, fallback) {
3391
4054
  const num = Number(value ?? fallback);
3392
4055
  return Number.isFinite(num) && num >= 1 ? Math.floor(num) : fallback;
@@ -3426,17 +4089,19 @@ function validateToolArgs(toolName, args) {
3426
4089
  }
3427
4090
  }
3428
4091
  if (toolName === "thenvoi_store_memory") {
3429
- const validSystems = ["sensory", "working", "long_term"];
3430
- const validTypes = ["iconic", "echoic", "haptic", "episodic", "semantic", "procedural"];
3431
- const validSegments = ["user", "agent", "tool", "guideline"];
3432
- if (typeof args.system === "string" && !validSystems.includes(args.system)) {
3433
- errors.push(`system: Invalid value '${args.system}'. Expected one of: ${validSystems.join(", ")}`);
4092
+ if (typeof args.system === "string" && !isMemorySystem(args.system)) {
4093
+ errors.push(`system: Invalid value '${args.system}'. Expected one of: ${expectedList(MEMORY_SYSTEMS)}`);
4094
+ }
4095
+ if (typeof args.type === "string" && !isMemoryType(args.type)) {
4096
+ errors.push(`type: Invalid value '${args.type}'. Expected one of: ${expectedList(MEMORY_TYPES)}`);
3434
4097
  }
3435
- if (typeof args.type === "string" && !validTypes.includes(args.type)) {
3436
- errors.push(`type: Invalid value '${args.type}'. Expected one of: ${validTypes.join(", ")}`);
4098
+ if (typeof args.system === "string" && isMemorySystem(args.system) && typeof args.type === "string" && isMemoryType(args.type) && !isMemoryTypeForSystem(args.system, args.type)) {
4099
+ errors.push(
4100
+ `type: Invalid value '${args.type}' for system '${args.system}'. Expected one of: ${expectedMemoryTypesForSystem(args.system)}`
4101
+ );
3437
4102
  }
3438
- if (typeof args.segment === "string" && !validSegments.includes(args.segment)) {
3439
- errors.push(`segment: Invalid value '${args.segment}'. Expected one of: ${validSegments.join(", ")}`);
4103
+ if (typeof args.segment === "string" && !isMemorySegment(args.segment)) {
4104
+ errors.push(`segment: Invalid value '${args.segment}'. Expected one of: ${expectedList(MEMORY_SEGMENTS)}`);
3440
4105
  }
3441
4106
  }
3442
4107
  if (errors.length > 0) {
@@ -3503,6 +4168,29 @@ var MessageRetryTracker = class {
3503
4168
  }
3504
4169
  };
3505
4170
 
4171
+ // src/runtime/types.ts
4172
+ var HistoryProvider = class {
4173
+ raw;
4174
+ constructor(raw) {
4175
+ this.raw = raw;
4176
+ }
4177
+ convert(converter) {
4178
+ return converter.convert(this.raw);
4179
+ }
4180
+ get length() {
4181
+ return this.raw.length;
4182
+ }
4183
+ };
4184
+ var SYNTHETIC_SENDER_TYPE = "System";
4185
+ var SYNTHETIC_CONTACT_EVENTS_SENDER_ID = "contact-events";
4186
+ var SYNTHETIC_CONTACT_EVENTS_SENDER_NAME = "Contact Events";
4187
+ function ensureHandlePrefix(handle) {
4188
+ if (!handle) {
4189
+ return null;
4190
+ }
4191
+ return handle.startsWith("@") ? handle : `@${handle}`;
4192
+ }
4193
+
3506
4194
  // src/runtime/formatters.ts
3507
4195
  function isMetadataMap(value) {
3508
4196
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -3516,7 +4204,7 @@ function replaceUuidMentions(content, participants) {
3516
4204
  const participantId = participant.id;
3517
4205
  const handle = participant.handle;
3518
4206
  if (typeof participantId === "string" && typeof handle === "string") {
3519
- next = next.replaceAll(`@[[${participantId}]]`, `@${handle}`);
4207
+ next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
3520
4208
  }
3521
4209
  }
3522
4210
  return next;
@@ -3548,7 +4236,9 @@ function buildParticipantsMessage(participants) {
3548
4236
  const participantType = String(participant.type ?? "Unknown");
3549
4237
  const participantName = String(participant.name ?? "Unknown");
3550
4238
  const participantHandle = String(participant.handle ?? "Unknown");
3551
- lines.push(`- @${participantHandle} \u2014 ${participantName} (${participantType})`);
4239
+ lines.push(
4240
+ `- ${ensureHandlePrefix(participantHandle) ?? ""} \u2014 ${participantName} (${participantType})`
4241
+ );
3552
4242
  }
3553
4243
  lines.push("");
3554
4244
  lines.push(
@@ -4028,7 +4718,7 @@ var AgentRuntime = class {
4028
4718
  await this.link.disconnect();
4029
4719
  }
4030
4720
  async stop(timeoutMs) {
4031
- if (!this.running || this.stopping) {
4721
+ if (this.stopping || !this.running && !this.fatalError) {
4032
4722
  return true;
4033
4723
  }
4034
4724
  this.stopping = true;
@@ -4048,7 +4738,8 @@ var AgentRuntime = class {
4048
4738
  }
4049
4739
  }
4050
4740
  for (const roomId of [...this.subscribedRooms]) {
4051
- await this.leaveTrackedRoom(roomId);
4741
+ const remaining = deadline === void 0 ? void 0 : Math.max(0, deadline - Date.now());
4742
+ await this.leaveTrackedRoom(roomId, remaining);
4052
4743
  }
4053
4744
  for (const roomId of [...this.contexts.keys()]) {
4054
4745
  await this.onSessionCleanup(roomId);
@@ -4084,7 +4775,13 @@ var AgentRuntime = class {
4084
4775
  }
4085
4776
  async consumeLoop(signal) {
4086
4777
  while (!signal.aborted) {
4087
- const event = await this.link.nextEvent(signal);
4778
+ let event;
4779
+ try {
4780
+ event = await this.link.nextEvent(signal);
4781
+ } catch (error) {
4782
+ await this.failRuntime(error, syntheticRuntimeFailureEvent(this.agentId));
4783
+ return;
4784
+ }
4088
4785
  if (!event) {
4089
4786
  return;
4090
4787
  }
@@ -4247,13 +4944,13 @@ var AgentRuntime = class {
4247
4944
  }
4248
4945
  });
4249
4946
  }
4250
- async leaveTrackedRoom(roomId) {
4947
+ async leaveTrackedRoom(roomId, timeoutMs) {
4251
4948
  await trackRoomLeave({
4252
4949
  link: this.link,
4253
4950
  roomId,
4254
4951
  trackedRooms: this.subscribedRooms,
4255
4952
  onLeft: async (leftRoomId) => {
4256
- await this.executions.get(leftRoomId)?.stop();
4953
+ await this.executions.get(leftRoomId)?.stop(timeoutMs);
4257
4954
  this.contexts.delete(leftRoomId);
4258
4955
  this.executions.delete(leftRoomId);
4259
4956
  await this.onSessionCleanup(leftRoomId);
@@ -4290,27 +4987,27 @@ var AgentRuntime = class {
4290
4987
  }
4291
4988
  }
4292
4989
  };
4990
+ function syntheticRuntimeFailureEvent(agentId) {
4991
+ return {
4992
+ type: "message_created",
4993
+ roomId: null,
4994
+ payload: {
4995
+ id: "runtime-failed",
4996
+ content: "",
4997
+ sender_id: agentId,
4998
+ sender_type: "Agent",
4999
+ sender_name: null,
5000
+ message_type: "text",
5001
+ metadata: {},
5002
+ inserted_at: (/* @__PURE__ */ new Date(0)).toISOString(),
5003
+ updated_at: (/* @__PURE__ */ new Date(0)).toISOString()
5004
+ }
5005
+ };
5006
+ }
4293
5007
  function assertNever(value) {
4294
5008
  throw new Error(`Unhandled platform event: ${JSON.stringify(value)}`);
4295
5009
  }
4296
5010
 
4297
- // src/runtime/types.ts
4298
- var HistoryProvider = class {
4299
- raw;
4300
- constructor(raw) {
4301
- this.raw = raw;
4302
- }
4303
- convert(converter) {
4304
- return converter.convert(this.raw);
4305
- }
4306
- get length() {
4307
- return this.raw.length;
4308
- }
4309
- };
4310
- var SYNTHETIC_SENDER_TYPE = "System";
4311
- var SYNTHETIC_CONTACT_EVENTS_SENDER_ID = "contact-events";
4312
- var SYNTHETIC_CONTACT_EVENTS_SENDER_NAME = "Contact Events";
4313
-
4314
5011
  // src/runtime/PlatformRuntime.ts
4315
5012
  init_errors();
4316
5013
 
@@ -5156,7 +5853,8 @@ var PlatformRuntime = class {
5156
5853
  agentId: this._agentId,
5157
5854
  apiKey: this._apiKey,
5158
5855
  wsUrl: this._wsUrl,
5159
- restUrl: this._restUrl
5856
+ restUrl: this._restUrl,
5857
+ logger: this.logger
5160
5858
  });
5161
5859
  }
5162
5860
  if (this.configuredIdentity) {
@@ -5659,16 +6357,15 @@ var GenericAdapter = class extends SimpleAdapter {
5659
6357
  // src/adapters/codex/CodexAdapter.ts
5660
6358
  init_protocols();
5661
6359
 
5662
- // src/runtime/prompts.ts
5663
- var BASE_INSTRUCTIONS = `
6360
+ // src/runtime/prompts/base.ts
6361
+ var ENVIRONMENT_SECTION = `
5664
6362
  ## Environment
5665
6363
 
5666
6364
  Multi-participant chat. Messages show sender: [Name]: content.
5667
6365
  Messages prefixed with [System]: are platform updates (participant changes, contact updates, etc.) \u2014 not messages from users.
5668
6366
  Use \`thenvoi_send_message(content, mentions)\` to respond. Plain text output is not delivered.
5669
- Mentions use handles: @<username> for users, @<username>/<agent-name> for agents.
5670
-
5671
- ## CRITICAL: Delegate When You Cannot Help Directly
6367
+ Mentions use handles: @<username> for users, @<username>/<agent-name> for agents.`;
6368
+ var MULTI_AGENT_RULES_SECTION = `## CRITICAL: Delegate When You Cannot Help Directly
5672
6369
 
5673
6370
  You have NO internet access and NO real-time data. When asked about weather, news, stock prices,
5674
6371
  or any current information you cannot answer directly:
@@ -5694,14 +6391,12 @@ Only remove agents if the user explicitly requests it.
5694
6391
  When someone asks you to get information from another agent:
5695
6392
  1. Ask the other agent for the information
5696
6393
  2. When you receive the response, IMMEDIATELY relay it back to the ORIGINAL REQUESTER
5697
- 3. Do NOT just thank the helper agent - the requester is waiting for their answer!
5698
-
5699
- ## IMPORTANT: Always Share Your Thinking
6394
+ 3. Do NOT just thank the helper agent - the requester is waiting for their answer!`;
6395
+ var THINKING_SECTION = `## IMPORTANT: Always Share Your Thinking
5700
6396
 
5701
6397
  You MUST call \`thenvoi_send_event(content, message_type="thought")\` BEFORE every action.
5702
- This is required so users can see your reasoning process.
5703
-
5704
- ## Examples
6398
+ This is required so users can see your reasoning process.`;
6399
+ var EXAMPLES_SECTION = `## Examples
5705
6400
 
5706
6401
  ### Simple question - answer directly
5707
6402
  [John Doe]: What's 2+2?
@@ -5734,8 +6429,75 @@ This is required so users can see your reasoning process.
5734
6429
 
5735
6430
  [Weather Agent]: London is 8\xB0C and rainy.
5736
6431
  -> thenvoi_send_event("Got London weather. Relaying to John Doe.", message_type="thought")
5737
- -> thenvoi_send_message("London is 8\xB0C and rainy.", mentions=["@john"])
5738
- `;
6432
+ -> thenvoi_send_message("London is 8\xB0C and rainy.", mentions=["@john"])`;
6433
+ var BASE_INSTRUCTIONS = [
6434
+ ENVIRONMENT_SECTION,
6435
+ MULTI_AGENT_RULES_SECTION,
6436
+ THINKING_SECTION,
6437
+ EXAMPLES_SECTION
6438
+ ].join("\n\n") + "\n";
6439
+
6440
+ // src/runtime/prompts/memory.ts
6441
+ init_memory();
6442
+ init_schemas();
6443
+ var MEMORY_INTRO = `## Memory Tools
6444
+
6445
+ You have access to memory tools for storing and retrieving information
6446
+ across conversations. Use \`thenvoi_store_memory\` to persist important
6447
+ information and \`thenvoi_list_memories\` / \`thenvoi_get_memory\` to recall it.
6448
+ Use \`thenvoi_supersede_memory\` to mark outdated memories and
6449
+ \`thenvoi_archive_memory\` to hide memories that should be preserved.`;
6450
+ function longTermPattern(label, type, segment, scope) {
6451
+ return {
6452
+ label,
6453
+ system: MEMORY_SYSTEM.long_term,
6454
+ type,
6455
+ segment,
6456
+ scope
6457
+ };
6458
+ }
6459
+ var COMMON_MEMORY_PATTERNS = [
6460
+ longTermPattern("Facts learned about a specific agent/entity", MEMORY_TYPE.semantic, MEMORY_SEGMENT.agent, MEMORY_STORE_SCOPE.subject),
6461
+ longTermPattern("Events involving a specific person/agent", MEMORY_TYPE.episodic, MEMORY_SEGMENT.agent, MEMORY_STORE_SCOPE.subject),
6462
+ longTermPattern("A user's preferences or profile info", MEMORY_TYPE.semantic, MEMORY_SEGMENT.user, MEMORY_STORE_SCOPE.subject),
6463
+ longTermPattern("Org-wide knowledge or how to perform a task", MEMORY_TYPE.procedural, MEMORY_SEGMENT.tool, MEMORY_STORE_SCOPE.organization)
6464
+ ];
6465
+ function renderMemoryPattern(pattern) {
6466
+ return `- ${pattern.label}: \`system="${pattern.system}"\`, \`type="${pattern.type}"\`, \`segment="${pattern.segment}"\`, \`scope="${pattern.scope}"\``;
6467
+ }
6468
+ var MEMORY_COMMON_PATTERNS = [
6469
+ "Common patterns:",
6470
+ ...COMMON_MEMORY_PATTERNS.map(renderMemoryPattern)
6471
+ ].join("\n");
6472
+ var MEMORY_SCOPE_GUIDANCE = `Prefer \`scope="${MEMORY_STORE_SCOPE.subject}"\` whenever the memory is about a specific person or agent, so it
6473
+ stays attached to that subject rather than leaking org-wide. Storing with \`scope="${MEMORY_STORE_SCOPE.subject}"\` requires a
6474
+ real \`subject_id\` UUID, so resolve it first via \`thenvoi_lookup_peers\` or the participant list.
6475
+ Reserve \`scope="${MEMORY_STORE_SCOPE.organization}"\` for knowledge that is genuinely shared across the whole organization and
6476
+ is not about any one subject.`;
6477
+ function quoteChoices(values) {
6478
+ return values.map((value) => `\`"${value}"\``).join(" | ");
6479
+ }
6480
+ function memoryTypeLines() {
6481
+ return Object.entries(MEMORY_SYSTEM_TYPES).map(([system, types]) => ` - ${system}: ${quoteChoices(types)}`).join("\n");
6482
+ }
6483
+ function buildMemorySection() {
6484
+ const storeMemoryProps = TOOL_MODELS.thenvoi_store_memory.properties;
6485
+ const systems = storeMemoryProps.system.enum;
6486
+ const segments = storeMemoryProps.segment.enum;
6487
+ const scopes = storeMemoryProps.scope.enum;
6488
+ const fieldRules = `When calling \`thenvoi_store_memory\`, the \`system\`, \`type\`, \`segment\`, and \`scope\` fields
6489
+ must use these exact values (case-sensitive):
6490
+
6491
+ - **system**: ${quoteChoices(systems)}
6492
+ - **type** (must match the chosen system):
6493
+ ${memoryTypeLines()}
6494
+ - **segment**: ${quoteChoices(segments)}
6495
+ - **scope**: ${quoteChoices(scopes)}`;
6496
+ return [MEMORY_INTRO, fieldRules, MEMORY_COMMON_PATTERNS, MEMORY_SCOPE_GUIDANCE].join("\n\n");
6497
+ }
6498
+ var MEMORY_SECTION = buildMemorySection();
6499
+
6500
+ // src/runtime/prompts/templates.ts
5739
6501
  var TEMPLATES = {
5740
6502
  default: `You are {agent_name}, {agent_description}.
5741
6503
 
@@ -5754,11 +6516,17 @@ ${customSection}`.trim();
5754
6516
  }
5755
6517
  const template = options?.template ?? "default";
5756
6518
  const templateString = TEMPLATES[template] ?? TEMPLATES.default;
5757
- return templateString.replaceAll("{agent_name}", agentName).replaceAll("{agent_description}", agentDescription).replaceAll("{custom_section}", customSection);
6519
+ const parts = [
6520
+ templateString.replaceAll("{agent_name}", agentName).replaceAll("{agent_description}", agentDescription).replaceAll("{custom_section}", customSection)
6521
+ ];
6522
+ if (options?.capabilities?.memory) {
6523
+ parts.push(MEMORY_SECTION);
6524
+ }
6525
+ return parts.join("\n\n");
5758
6526
  }
5759
6527
 
5760
6528
  // src/runtime/tools/customTools.ts
5761
- var import_zod2 = require("zod");
6529
+ var import_zod3 = require("zod");
5762
6530
  var import_zod_to_json_schema = require("zod-to-json-schema");
5763
6531
  var CustomToolDefinitionError = class extends Error {
5764
6532
  constructor(message) {
@@ -6453,7 +7221,8 @@ var CodexAdapter = class extends SimpleAdapter {
6453
7221
  agentName: this.agentName,
6454
7222
  agentDescription: this.agentDescription,
6455
7223
  customSection,
6456
- includeBaseInstructions: this.baseConfig.includeBaseInstructions ?? true
7224
+ includeBaseInstructions: this.baseConfig.includeBaseInstructions ?? true,
7225
+ capabilities: { memory: this.includeMemoryTools }
6457
7226
  }).trim();
6458
7227
  this.systemPrompt = prompt.length > 0 ? prompt : null;
6459
7228
  }
@@ -8576,7 +9345,8 @@ var GoogleADKAdapter = class extends SimpleAdapter {
8576
9345
  this.systemPrompt = this.systemPromptOverride ?? renderSystemPrompt({
8577
9346
  agentName,
8578
9347
  agentDescription,
8579
- customSection: this.customSection
9348
+ customSection: this.customSection,
9349
+ capabilities: { memory: this.enableMemoryTools }
8580
9350
  });
8581
9351
  }
8582
9352
  async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
@@ -8816,7 +9586,8 @@ var LangGraphAdapter = class extends SimpleAdapter {
8816
9586
  this.renderedSystemPrompt = this.systemPromptOverride ?? renderSystemPrompt({
8817
9587
  agentName,
8818
9588
  agentDescription,
8819
- customSection: this.customSection
9589
+ customSection: this.customSection,
9590
+ capabilities: { memory: this.includeMemoryTools }
8820
9591
  });
8821
9592
  }
8822
9593
  async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
@@ -8835,14 +9606,17 @@ var LangGraphAdapter = class extends SimpleAdapter {
8835
9606
  ];
8836
9607
  }
8837
9608
  const graph = await this.resolveGraph(sdk, langGraphTools);
8838
- const messages = this.buildMessages(
8839
- history,
8840
- message,
8841
- participantsMessage,
8842
- contactsMessage,
8843
- context.isSessionBootstrap,
8844
- context.roomId
8845
- );
9609
+ const usesCheckpointer = Boolean(this.checkpointer);
9610
+ const isFirstBootstrap = context.isSessionBootstrap && !this.bootstrappedRooms.has(context.roomId);
9611
+ const replayHistory = !usesCheckpointer || isFirstBootstrap;
9612
+ const includeSystemPrompt = this.usesCustomGraph && (!usesCheckpointer || isFirstBootstrap);
9613
+ if (context.isSessionBootstrap) {
9614
+ this.bootstrappedRooms.add(context.roomId);
9615
+ }
9616
+ const messages = this.buildMessages(history, message, participantsMessage, contactsMessage, {
9617
+ replayHistory,
9618
+ includeSystemPrompt
9619
+ });
8846
9620
  const input = { messages };
8847
9621
  const graphConfig = {
8848
9622
  configurable: {
@@ -8869,6 +9643,10 @@ var LangGraphAdapter = class extends SimpleAdapter {
8869
9643
  async onCleanup(roomId) {
8870
9644
  this.bootstrappedRooms.delete(roomId);
8871
9645
  }
9646
+ /** A caller-supplied graph rather than the built-in createReactAgent. */
9647
+ get usesCustomGraph() {
9648
+ return Boolean(this.graph || this.graphFactory);
9649
+ }
8872
9650
  resolveGraph(sdk, langGraphTools) {
8873
9651
  if (this.graphFactory) {
8874
9652
  return Promise.resolve(this.graphFactory(langGraphTools));
@@ -8889,14 +9667,13 @@ var LangGraphAdapter = class extends SimpleAdapter {
8889
9667
  prompt: this.renderedSystemPrompt
8890
9668
  }));
8891
9669
  }
8892
- buildMessages(history, message, participantsMessage, contactsMessage, isSessionBootstrap, roomId) {
9670
+ buildMessages(history, message, participantsMessage, contactsMessage, options) {
8893
9671
  const messages = [];
8894
- if (isSessionBootstrap && !this.bootstrappedRooms.has(roomId)) {
9672
+ if (options.includeSystemPrompt) {
8895
9673
  messages.push(["system", this.renderedSystemPrompt]);
8896
- this.bootstrappedRooms.add(roomId);
8897
9674
  }
8898
- if (isSessionBootstrap && history.length > 0) {
8899
- const historical = history.raw.slice(-this.maxHistoryMessages);
9675
+ if (options.replayHistory && history.length > 0) {
9676
+ const historical = history.raw.filter((item) => item.id !== message.id).slice(-this.maxHistoryMessages);
8900
9677
  for (const item of historical) {
8901
9678
  const role = String(item.sender_type ?? "") === "Agent" ? "assistant" : "user";
8902
9679
  const content = String(item.content ?? "");
@@ -8915,7 +9692,7 @@ var LangGraphAdapter = class extends SimpleAdapter {
8915
9692
  return messages;
8916
9693
  }
8917
9694
  async forwardStreamEvents(graph, input, config, tools) {
8918
- const stream = graph.streamEvents?.(input, config, { version: "v2" });
9695
+ const stream = graph.streamEvents?.(input, { ...config, version: "v2" });
8919
9696
  if (!stream) {
8920
9697
  return null;
8921
9698
  }
@@ -8942,6 +9719,10 @@ var LangGraphAdapter = class extends SimpleAdapter {
8942
9719
  );
8943
9720
  }
8944
9721
  if (eventType === "on_chain_end") {
9722
+ const chainName = String(data.name ?? "");
9723
+ if (!this.usesCustomGraph && chainName !== "LangGraph" && chainName !== "agent") {
9724
+ continue;
9725
+ }
8945
9726
  const output = asOptionalRecord(data.data) ?? {};
8946
9727
  const text = extractAssistantText(output.output);
8947
9728
  if (text) {
@@ -9003,18 +9784,25 @@ function stringifyToolResult2(value, logger, toolName) {
9003
9784
  });
9004
9785
  }
9005
9786
  function extractAssistantText(result) {
9006
- if (typeof result === "string" && result.trim().length > 0) {
9007
- return result.trim();
9787
+ if (typeof result === "string") {
9788
+ const trimmed = result.trim();
9789
+ return trimmed.length > 0 && !isInternalLangGraphMarker(trimmed) ? trimmed : null;
9008
9790
  }
9009
9791
  const record = asOptionalRecord(result) ?? {};
9792
+ if (isLangChainAssistantMessage(record)) {
9793
+ const text = asLangChainMessageContent(record);
9794
+ if (text && !isInternalLangGraphMarker(text)) {
9795
+ return text;
9796
+ }
9797
+ }
9010
9798
  const directContent = asMessageContent(record.content);
9011
- if (directContent) {
9799
+ if (directContent && !isInternalLangGraphMarker(directContent)) {
9012
9800
  return directContent;
9013
9801
  }
9014
9802
  const messages = Array.isArray(record.messages) ? record.messages : [];
9015
9803
  for (let index = messages.length - 1; index >= 0; index -= 1) {
9016
9804
  const text = asMessageText(messages[index]);
9017
- if (text) {
9805
+ if (text && !isInternalLangGraphMarker(text)) {
9018
9806
  return text;
9019
9807
  }
9020
9808
  }
@@ -9031,12 +9819,40 @@ function asMessageText(value) {
9031
9819
  if (!record) {
9032
9820
  return null;
9033
9821
  }
9822
+ if (isLangChainAssistantMessage(record)) {
9823
+ return asLangChainMessageContent(record);
9824
+ }
9034
9825
  const role = String(record.role ?? "");
9035
9826
  if (role !== "assistant") {
9036
9827
  return null;
9037
9828
  }
9038
9829
  return asMessageContent(record.content);
9039
9830
  }
9831
+ function isLangChainAssistantMessage(record) {
9832
+ const id = record.id;
9833
+ if (Array.isArray(id)) {
9834
+ const typeName = String(id[id.length - 1] ?? "");
9835
+ if (typeName === "AIMessage" || typeName === "AIMessageChunk") {
9836
+ return true;
9837
+ }
9838
+ }
9839
+ const getType = record.getType;
9840
+ if (typeof getType === "function") {
9841
+ try {
9842
+ return getType.call(record) === "ai";
9843
+ } catch {
9844
+ return false;
9845
+ }
9846
+ }
9847
+ return false;
9848
+ }
9849
+ function asLangChainMessageContent(record) {
9850
+ const kwargs = asOptionalRecord(record.kwargs);
9851
+ return asMessageContent(kwargs?.content ?? record.content);
9852
+ }
9853
+ function isInternalLangGraphMarker(text) {
9854
+ return text === "__end__" || text === "__start__";
9855
+ }
9040
9856
  function asMessageContent(value) {
9041
9857
  if (typeof value === "string" && value.trim().length > 0) {
9042
9858
  return value.trim();
@@ -11956,12 +12772,12 @@ var ThenvoiMcpStdioServer = class {
11956
12772
  }
11957
12773
  const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
11958
12774
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
11959
- const { z: z5 } = await import("zod");
12775
+ const { z: z6 } = await import("zod");
11960
12776
  const mcpServer = new McpServer({
11961
12777
  name: this.options.name ?? "thenvoi",
11962
12778
  version: "1.0.0"
11963
12779
  });
11964
- registerTools(mcpServer, z5, this.registrations);
12780
+ registerTools(mcpServer, z6, this.registrations);
11965
12781
  const transport = new StdioServerTransport(this.options.stdin, this.options.stdout);
11966
12782
  await mcpServer.connect(transport);
11967
12783
  this.mcpServer = mcpServer;
@@ -11973,14 +12789,14 @@ var ThenvoiMcpStdioServer = class {
11973
12789
  this.mcpServer = null;
11974
12790
  }
11975
12791
  };
11976
- function registerTools(mcpServer, z5, registrations) {
12792
+ function registerTools(mcpServer, z6, registrations) {
11977
12793
  for (const reg of registrations) {
11978
- const zodShape = buildZodShape(z5, reg.inputSchema.properties, new Set(reg.inputSchema.required));
12794
+ const zodShape = buildZodShape(z6, reg.inputSchema.properties, new Set(reg.inputSchema.required));
11979
12795
  mcpServer.registerTool(
11980
12796
  reg.name,
11981
12797
  {
11982
12798
  description: reg.description,
11983
- inputSchema: z5.object(zodShape)
12799
+ inputSchema: z6.object(zodShape)
11984
12800
  },
11985
12801
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
11986
12802
  async (args) => reg.execute(args)
@@ -12039,7 +12855,7 @@ var ThenvoiMcpServer = class {
12039
12855
  const express = expressModule.default ?? expressModule;
12040
12856
  const http = await import("http");
12041
12857
  const { randomUUID: randomUUID6 } = await import("crypto");
12042
- const { z: z5 } = await import("zod");
12858
+ const { z: z6 } = await import("zod");
12043
12859
  const serverName = this.options.name ?? "thenvoi";
12044
12860
  const app = express();
12045
12861
  app.use(express.json());
@@ -12060,7 +12876,7 @@ var ThenvoiMcpServer = class {
12060
12876
  StreamableHTTPServerTransport,
12061
12877
  serverName,
12062
12878
  sessionIdGenerator: randomUUID6,
12063
- z: z5
12879
+ z: z6
12064
12880
  });
12065
12881
  }
12066
12882
  session.lastSeenAt = Date.now();
@@ -12186,14 +13002,14 @@ function sendMcpError(res, status, message) {
12186
13002
  id: null
12187
13003
  });
12188
13004
  }
12189
- function registerTools2(mcpServer, z5, registrations) {
13005
+ function registerTools2(mcpServer, z6, registrations) {
12190
13006
  for (const reg of registrations) {
12191
- const zodShape = buildZodShape(z5, reg.inputSchema.properties, new Set(reg.inputSchema.required));
13007
+ const zodShape = buildZodShape(z6, reg.inputSchema.properties, new Set(reg.inputSchema.required));
12192
13008
  mcpServer.registerTool(
12193
13009
  reg.name,
12194
13010
  {
12195
13011
  description: reg.description,
12196
- inputSchema: z5.object(zodShape)
13012
+ inputSchema: z6.object(zodShape)
12197
13013
  },
12198
13014
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
12199
13015
  async (args) => reg.execute(args)
@@ -12268,7 +13084,7 @@ var ThenvoiMcpSseServer = class {
12268
13084
  const expressModule = await import("express");
12269
13085
  const express = expressModule.default ?? expressModule;
12270
13086
  const http = await import("http");
12271
- const { z: z5 } = await import("zod");
13087
+ const { z: z6 } = await import("zod");
12272
13088
  const app = express();
12273
13089
  app.use(express.json());
12274
13090
  app.get("/healthz", (_req, res) => {
@@ -12280,7 +13096,7 @@ var ThenvoiMcpSseServer = class {
12280
13096
  name: this.options.name ?? "thenvoi",
12281
13097
  version: "1.0.0"
12282
13098
  });
12283
- registerTools3(mcpServer, z5, this.registrations);
13099
+ registerTools3(mcpServer, z6, this.registrations);
12284
13100
  await mcpServer.connect(transport);
12285
13101
  const sessionId = transport.sessionId;
12286
13102
  this.sessions.set(sessionId, {
@@ -12372,10 +13188,10 @@ var ThenvoiMcpSseServer = class {
12372
13188
  }
12373
13189
  }
12374
13190
  };
12375
- function registerTools3(mcpServer, z5, registrations) {
13191
+ function registerTools3(mcpServer, z6, registrations) {
12376
13192
  for (const registration of registrations) {
12377
13193
  const zodShape = buildZodShape(
12378
- z5,
13194
+ z6,
12379
13195
  registration.inputSchema.properties,
12380
13196
  new Set(registration.inputSchema.required)
12381
13197
  );
@@ -12383,7 +13199,7 @@ function registerTools3(mcpServer, z5, registrations) {
12383
13199
  registration.name,
12384
13200
  {
12385
13201
  description: registration.description,
12386
- inputSchema: z5.object(zodShape)
13202
+ inputSchema: z6.object(zodShape)
12387
13203
  },
12388
13204
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
12389
13205
  async (args) => registration.execute(args)
@@ -12413,20 +13229,17 @@ function checkPort2(http, port) {
12413
13229
 
12414
13230
  // src/mcp/backends.ts
12415
13231
  async function createThenvoiMcpBackend(options) {
12416
- const registrations = buildRoomScopedRegistrations(
12417
- options.getToolsForRoom,
12418
- {
12419
- enableMemoryTools: options.enableMemoryTools,
12420
- enableContactTools: true,
12421
- additionalTools: options.additionalTools
12422
- }
12423
- );
12424
- const allowedTools = mcpToolNames(new Set(registrations.map((registration) => registration.name)));
13232
+ const registrationOptions = {
13233
+ enableMemoryTools: options.enableMemoryTools,
13234
+ enableContactTools: true,
13235
+ additionalTools: options.additionalTools
13236
+ };
12425
13237
  if (options.kind === "sdk") {
12426
13238
  const { createThenvoiSdkMcpServer: createThenvoiSdkMcpServer2 } = await Promise.resolve().then(() => (init_sdk(), sdk_exports));
12427
13239
  const server2 = createThenvoiSdkMcpServer2({
12428
- enableMemoryTools: options.enableMemoryTools,
12429
13240
  getToolsForRoom: options.getToolsForRoom,
13241
+ multiRoom: options.multiRoom,
13242
+ enableMemoryTools: options.enableMemoryTools,
12430
13243
  additionalTools: options.additionalTools
12431
13244
  });
12432
13245
  return {
@@ -12436,9 +13249,12 @@ async function createThenvoiMcpBackend(options) {
12436
13249
  stop: async () => void 0
12437
13250
  };
12438
13251
  }
13252
+ const resolvedTools = options.multiRoom === false ? resolveSingleRoomTools(options.getToolsForRoom) : options.getToolsForRoom;
13253
+ const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolvedTools, registrationOptions) : buildRoomScopedRegistrations(resolvedTools, registrationOptions);
13254
+ const allowedTools = mcpToolNames(new Set(registrations.map((registration) => registration.name)));
12439
13255
  if (options.kind === "stdio") {
12440
13256
  const server2 = new ThenvoiMcpStdioServer({
12441
- tools: options.getToolsForRoom,
13257
+ tools: resolvedTools,
12442
13258
  enableMemoryTools: options.enableMemoryTools,
12443
13259
  enableContactTools: true,
12444
13260
  additionalTools: options.additionalTools
@@ -12455,7 +13271,7 @@ async function createThenvoiMcpBackend(options) {
12455
13271
  }
12456
13272
  if (options.kind === "sse") {
12457
13273
  const server2 = new ThenvoiMcpSseServer({
12458
- tools: options.getToolsForRoom,
13274
+ tools: resolvedTools,
12459
13275
  enableMemoryTools: options.enableMemoryTools,
12460
13276
  enableContactTools: true,
12461
13277
  additionalTools: options.additionalTools
@@ -12471,7 +13287,7 @@ async function createThenvoiMcpBackend(options) {
12471
13287
  };
12472
13288
  }
12473
13289
  const server = new ThenvoiMcpServer({
12474
- tools: options.getToolsForRoom,
13290
+ tools: resolvedTools,
12475
13291
  enableMemoryTools: options.enableMemoryTools,
12476
13292
  enableContactTools: true,
12477
13293
  additionalTools: options.additionalTools
@@ -12710,7 +13526,7 @@ var SdkOpencodeClientBase = class {
12710
13526
  }
12711
13527
  const response = await fetch(url, { method: "DELETE" });
12712
13528
  if (!response.ok && response.status !== 404) {
12713
- throw new HttpStatusError(response.status, await readResponseBody(response));
13529
+ throw new HttpStatusError(response.status, await readResponseBody2(response));
12714
13530
  }
12715
13531
  }
12716
13532
  };
@@ -12799,7 +13615,7 @@ async function findAvailablePort3() {
12799
13615
  });
12800
13616
  });
12801
13617
  }
12802
- async function readResponseBody(response) {
13618
+ async function readResponseBody2(response) {
12803
13619
  const contentType = response.headers.get("content-type") ?? "";
12804
13620
  if (contentType.includes("application/json")) {
12805
13621
  try {
@@ -12911,7 +13727,8 @@ var OpencodeAdapter = class extends SimpleAdapter {
12911
13727
  agentName,
12912
13728
  agentDescription,
12913
13729
  customSection: this.config.customSection,
12914
- includeBaseInstructions: this.config.includeBaseInstructions
13730
+ includeBaseInstructions: this.config.includeBaseInstructions,
13731
+ capabilities: { memory: this.config.enableMemoryTools }
12915
13732
  }).trim();
12916
13733
  this.systemPrompt = `${systemPrompt}
12917
13734
 
@@ -13691,7 +14508,7 @@ function extractClaudeSessionId(raw) {
13691
14508
  // src/adapters/claude-sdk/ClaudeSDKAdapter.ts
13692
14509
  init_registrations();
13693
14510
  init_zod();
13694
- var import_zod9 = require("zod");
14511
+ var import_zod10 = require("zod");
13695
14512
  var DEFAULT_MODEL2 = "claude-sonnet-4-6";
13696
14513
  var thenvoiMcpBridgeFactory = new LazyAsyncValue({
13697
14514
  load: async () => {
@@ -13718,7 +14535,7 @@ var thenvoiMcpBridgeFactory = new LazyAsyncValue({
13718
14535
  );
13719
14536
  const toolDefinitions = registrations.map((registration) => {
13720
14537
  const shape = buildZodShape(
13721
- import_zod9.z,
14538
+ import_zod10.z,
13722
14539
  registration.inputSchema.properties,
13723
14540
  new Set(registration.inputSchema.required)
13724
14541
  );
@@ -13778,7 +14595,8 @@ var ClaudeSDKAdapter = class extends SimpleAdapter {
13778
14595
  agentName,
13779
14596
  agentDescription,
13780
14597
  customSection: this.customSection,
13781
- includeBaseInstructions: this.includeBaseInstructions
14598
+ includeBaseInstructions: this.includeBaseInstructions,
14599
+ capabilities: { memory: this.enableMemoryTools }
13782
14600
  });
13783
14601
  if (this.enableMcpTools) {
13784
14602
  const createThenvoiMcpBridge = await thenvoiMcpBridgeFactory.get();
@@ -13953,6 +14771,8 @@ init_schemas();
13953
14771
  TOOL_MODELS,
13954
14772
  ThenvoiLink,
13955
14773
  VercelAISDKAdapter,
14774
+ WebSocketDisconnectError,
14775
+ deriveDefaultRestUrl,
13956
14776
  isDirectExecution,
13957
14777
  loadAgentConfig,
13958
14778
  loadAgentConfigFromEnv