@molroo-io/sdk 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +102 -210
  2. package/dist/cjs/api-client.d.ts +2 -12
  3. package/dist/cjs/api-client.d.ts.map +1 -1
  4. package/dist/cjs/api-client.js +4 -42
  5. package/dist/cjs/errors.d.ts +1 -16
  6. package/dist/cjs/errors.d.ts.map +1 -1
  7. package/dist/cjs/errors.js +2 -18
  8. package/dist/cjs/events/types.d.ts +14 -21
  9. package/dist/cjs/events/types.d.ts.map +1 -1
  10. package/dist/cjs/events/types.js +0 -11
  11. package/dist/cjs/index.d.ts +28 -48
  12. package/dist/cjs/index.d.ts.map +1 -1
  13. package/dist/cjs/index.js +31 -52
  14. package/dist/cjs/llm/resolve.d.ts +4 -22
  15. package/dist/cjs/llm/resolve.d.ts.map +1 -1
  16. package/dist/cjs/llm/resolve.js +19 -7
  17. package/dist/cjs/llm/vercel-ai/adapter.d.ts +4 -10
  18. package/dist/cjs/llm/vercel-ai/adapter.d.ts.map +1 -1
  19. package/dist/cjs/llm/vercel-ai/adapter.js +6 -152
  20. package/dist/cjs/llm/vercel-ai/config.d.ts +8 -5
  21. package/dist/cjs/llm/vercel-ai/config.d.ts.map +1 -1
  22. package/dist/cjs/memory/in-memory.d.ts +14 -37
  23. package/dist/cjs/memory/in-memory.d.ts.map +1 -1
  24. package/dist/cjs/memory/in-memory.js +22 -85
  25. package/dist/cjs/memory/recall.d.ts +10 -21
  26. package/dist/cjs/memory/recall.d.ts.map +1 -1
  27. package/dist/cjs/memory/recall.js +12 -91
  28. package/dist/cjs/memory/types.d.ts +46 -186
  29. package/dist/cjs/memory/types.d.ts.map +1 -1
  30. package/dist/cjs/memory/types.js +0 -10
  31. package/dist/cjs/persona/chat-orchestrator.d.ts +46 -0
  32. package/dist/cjs/persona/chat-orchestrator.d.ts.map +1 -0
  33. package/dist/cjs/persona/chat-orchestrator.js +240 -0
  34. package/dist/cjs/persona/event-emitter.d.ts +7 -0
  35. package/dist/cjs/persona/event-emitter.d.ts.map +1 -0
  36. package/dist/cjs/persona/event-emitter.js +53 -0
  37. package/dist/cjs/persona/memory-pipeline.d.ts +26 -0
  38. package/dist/cjs/persona/memory-pipeline.d.ts.map +1 -0
  39. package/dist/cjs/persona/memory-pipeline.js +69 -0
  40. package/dist/cjs/persona.d.ts +66 -171
  41. package/dist/cjs/persona.d.ts.map +1 -1
  42. package/dist/cjs/persona.js +64 -617
  43. package/dist/cjs/shared/appraisal.d.ts +26 -0
  44. package/dist/cjs/shared/appraisal.d.ts.map +1 -0
  45. package/dist/cjs/shared/appraisal.js +45 -0
  46. package/dist/cjs/shared/client-factory.d.ts +23 -0
  47. package/dist/cjs/shared/client-factory.d.ts.map +1 -0
  48. package/dist/cjs/shared/client-factory.js +48 -0
  49. package/dist/cjs/shared/errors.d.ts +21 -0
  50. package/dist/cjs/shared/errors.d.ts.map +1 -0
  51. package/dist/cjs/shared/errors.js +29 -0
  52. package/dist/cjs/world/client.d.ts +5 -12
  53. package/dist/cjs/world/client.d.ts.map +1 -1
  54. package/dist/cjs/world/client.js +10 -37
  55. package/dist/cjs/world/errors.d.ts +1 -8
  56. package/dist/cjs/world/errors.d.ts.map +1 -1
  57. package/dist/cjs/world/errors.js +2 -12
  58. package/dist/cjs/world/index.d.ts +5 -5
  59. package/dist/cjs/world/index.d.ts.map +1 -1
  60. package/dist/cjs/world/index.js +4 -4
  61. package/dist/cjs/world/types.d.ts +10 -8
  62. package/dist/cjs/world/types.d.ts.map +1 -1
  63. package/dist/{esm/world/village.d.ts → cjs/world/world-domain.d.ts} +25 -25
  64. package/dist/cjs/world/world-domain.d.ts.map +1 -0
  65. package/dist/cjs/world/{village.js → world-domain.js} +40 -68
  66. package/dist/cjs/world/world-persona.d.ts +12 -10
  67. package/dist/cjs/world/world-persona.d.ts.map +1 -1
  68. package/dist/cjs/world/world-persona.js +16 -31
  69. package/dist/cjs/world/world.d.ts +84 -17
  70. package/dist/cjs/world/world.d.ts.map +1 -1
  71. package/dist/cjs/world/world.js +72 -27
  72. package/dist/esm/api-client.d.ts +2 -12
  73. package/dist/esm/api-client.d.ts.map +1 -1
  74. package/dist/esm/api-client.js +3 -38
  75. package/dist/esm/errors.d.ts +1 -16
  76. package/dist/esm/errors.d.ts.map +1 -1
  77. package/dist/esm/errors.js +1 -17
  78. package/dist/esm/events/types.d.ts +14 -21
  79. package/dist/esm/events/types.d.ts.map +1 -1
  80. package/dist/esm/events/types.js +0 -11
  81. package/dist/esm/index.d.ts +28 -48
  82. package/dist/esm/index.d.ts.map +1 -1
  83. package/dist/esm/index.js +26 -38
  84. package/dist/esm/llm/resolve.d.ts +4 -22
  85. package/dist/esm/llm/resolve.d.ts.map +1 -1
  86. package/dist/esm/llm/resolve.js +20 -8
  87. package/dist/esm/llm/vercel-ai/adapter.d.ts +4 -10
  88. package/dist/esm/llm/vercel-ai/adapter.d.ts.map +1 -1
  89. package/dist/esm/llm/vercel-ai/adapter.js +6 -119
  90. package/dist/esm/llm/vercel-ai/config.d.ts +8 -5
  91. package/dist/esm/llm/vercel-ai/config.d.ts.map +1 -1
  92. package/dist/esm/memory/in-memory.d.ts +14 -37
  93. package/dist/esm/memory/in-memory.d.ts.map +1 -1
  94. package/dist/esm/memory/in-memory.js +20 -83
  95. package/dist/esm/memory/recall.d.ts +10 -21
  96. package/dist/esm/memory/recall.d.ts.map +1 -1
  97. package/dist/esm/memory/recall.js +12 -91
  98. package/dist/esm/memory/types.d.ts +46 -186
  99. package/dist/esm/memory/types.d.ts.map +1 -1
  100. package/dist/esm/memory/types.js +1 -9
  101. package/dist/esm/persona/chat-orchestrator.d.ts +46 -0
  102. package/dist/esm/persona/chat-orchestrator.d.ts.map +1 -0
  103. package/dist/esm/persona/chat-orchestrator.js +204 -0
  104. package/dist/esm/persona/event-emitter.d.ts +7 -0
  105. package/dist/esm/persona/event-emitter.d.ts.map +1 -0
  106. package/dist/esm/persona/event-emitter.js +50 -0
  107. package/dist/esm/persona/memory-pipeline.d.ts +26 -0
  108. package/dist/esm/persona/memory-pipeline.d.ts.map +1 -0
  109. package/dist/esm/persona/memory-pipeline.js +65 -0
  110. package/dist/esm/persona.d.ts +66 -171
  111. package/dist/esm/persona.d.ts.map +1 -1
  112. package/dist/esm/persona.js +64 -617
  113. package/dist/esm/shared/appraisal.d.ts +26 -0
  114. package/dist/esm/shared/appraisal.d.ts.map +1 -0
  115. package/dist/esm/shared/appraisal.js +40 -0
  116. package/dist/esm/shared/client-factory.d.ts +23 -0
  117. package/dist/esm/shared/client-factory.d.ts.map +1 -0
  118. package/dist/esm/shared/client-factory.js +41 -0
  119. package/dist/esm/shared/errors.d.ts +21 -0
  120. package/dist/esm/shared/errors.d.ts.map +1 -0
  121. package/dist/esm/shared/errors.js +24 -0
  122. package/dist/esm/world/client.d.ts +5 -12
  123. package/dist/esm/world/client.d.ts.map +1 -1
  124. package/dist/esm/world/client.js +9 -33
  125. package/dist/esm/world/errors.d.ts +1 -8
  126. package/dist/esm/world/errors.d.ts.map +1 -1
  127. package/dist/esm/world/errors.js +1 -11
  128. package/dist/esm/world/index.d.ts +5 -5
  129. package/dist/esm/world/index.d.ts.map +1 -1
  130. package/dist/esm/world/index.js +2 -2
  131. package/dist/esm/world/types.d.ts +10 -8
  132. package/dist/esm/world/types.d.ts.map +1 -1
  133. package/dist/{cjs/world/village.d.ts → esm/world/world-domain.d.ts} +25 -25
  134. package/dist/esm/world/world-domain.d.ts.map +1 -0
  135. package/dist/esm/world/{village.js → world-domain.js} +38 -66
  136. package/dist/esm/world/world-persona.d.ts +12 -10
  137. package/dist/esm/world/world-persona.d.ts.map +1 -1
  138. package/dist/esm/world/world-persona.js +16 -31
  139. package/dist/esm/world/world.d.ts +84 -17
  140. package/dist/esm/world/world.d.ts.map +1 -1
  141. package/dist/esm/world/world.js +70 -25
  142. package/package.json +4 -101
  143. package/dist/cjs/embedding/cloudflare.d.ts +0 -15
  144. package/dist/cjs/embedding/cloudflare.d.ts.map +0 -1
  145. package/dist/cjs/embedding/cloudflare.js +0 -16
  146. package/dist/cjs/embedding/cohere.d.ts +0 -8
  147. package/dist/cjs/embedding/cohere.d.ts.map +0 -1
  148. package/dist/cjs/embedding/cohere.js +0 -31
  149. package/dist/cjs/embedding/index.d.ts +0 -9
  150. package/dist/cjs/embedding/index.d.ts.map +0 -1
  151. package/dist/cjs/embedding/index.js +0 -11
  152. package/dist/cjs/embedding/local.d.ts +0 -6
  153. package/dist/cjs/embedding/local.d.ts.map +0 -1
  154. package/dist/cjs/embedding/local.js +0 -28
  155. package/dist/cjs/embedding/openai.d.ts +0 -9
  156. package/dist/cjs/embedding/openai.d.ts.map +0 -1
  157. package/dist/cjs/embedding/openai.js +0 -26
  158. package/dist/cjs/events/console.d.ts +0 -25
  159. package/dist/cjs/events/console.d.ts.map +0 -1
  160. package/dist/cjs/events/console.js +0 -41
  161. package/dist/cjs/events/webhook.d.ts +0 -30
  162. package/dist/cjs/events/webhook.d.ts.map +0 -1
  163. package/dist/cjs/events/webhook.js +0 -79
  164. package/dist/cjs/memory/cloudflare/index.d.ts +0 -3
  165. package/dist/cjs/memory/cloudflare/index.d.ts.map +0 -1
  166. package/dist/cjs/memory/cloudflare/index.js +0 -5
  167. package/dist/cjs/memory/cloudflare/vectorize.d.ts +0 -62
  168. package/dist/cjs/memory/cloudflare/vectorize.d.ts.map +0 -1
  169. package/dist/cjs/memory/cloudflare/vectorize.js +0 -55
  170. package/dist/cjs/memory/in-memory-semantic.d.ts +0 -16
  171. package/dist/cjs/memory/in-memory-semantic.d.ts.map +0 -1
  172. package/dist/cjs/memory/in-memory-semantic.js +0 -57
  173. package/dist/cjs/memory/pinecone/index.d.ts +0 -7
  174. package/dist/cjs/memory/pinecone/index.d.ts.map +0 -1
  175. package/dist/cjs/memory/pinecone/index.js +0 -8
  176. package/dist/cjs/memory/pinecone/memory-adapter.d.ts +0 -62
  177. package/dist/cjs/memory/pinecone/memory-adapter.d.ts.map +0 -1
  178. package/dist/cjs/memory/pinecone/memory-adapter.js +0 -220
  179. package/dist/cjs/memory/pinecone/semantic.d.ts +0 -44
  180. package/dist/cjs/memory/pinecone/semantic.d.ts.map +0 -1
  181. package/dist/cjs/memory/pinecone/semantic.js +0 -90
  182. package/dist/cjs/memory/sqlite/index.d.ts +0 -3
  183. package/dist/cjs/memory/sqlite/index.d.ts.map +0 -1
  184. package/dist/cjs/memory/sqlite/index.js +0 -5
  185. package/dist/cjs/memory/sqlite/memory-adapter.d.ts +0 -58
  186. package/dist/cjs/memory/sqlite/memory-adapter.d.ts.map +0 -1
  187. package/dist/cjs/memory/sqlite/memory-adapter.js +0 -336
  188. package/dist/cjs/memory/sqlite/schema.d.ts +0 -4
  189. package/dist/cjs/memory/sqlite/schema.d.ts.map +0 -1
  190. package/dist/cjs/memory/sqlite/schema.js +0 -91
  191. package/dist/cjs/memory/supabase/index.d.ts +0 -7
  192. package/dist/cjs/memory/supabase/index.d.ts.map +0 -1
  193. package/dist/cjs/memory/supabase/index.js +0 -8
  194. package/dist/cjs/memory/supabase/memory-adapter.d.ts +0 -67
  195. package/dist/cjs/memory/supabase/memory-adapter.d.ts.map +0 -1
  196. package/dist/cjs/memory/supabase/memory-adapter.js +0 -335
  197. package/dist/cjs/memory/supabase/semantic.d.ts +0 -44
  198. package/dist/cjs/memory/supabase/semantic.d.ts.map +0 -1
  199. package/dist/cjs/memory/supabase/semantic.js +0 -72
  200. package/dist/cjs/world/village.d.ts.map +0 -1
  201. package/dist/esm/embedding/cloudflare.d.ts +0 -15
  202. package/dist/esm/embedding/cloudflare.d.ts.map +0 -1
  203. package/dist/esm/embedding/cloudflare.js +0 -13
  204. package/dist/esm/embedding/cohere.d.ts +0 -8
  205. package/dist/esm/embedding/cohere.d.ts.map +0 -1
  206. package/dist/esm/embedding/cohere.js +0 -28
  207. package/dist/esm/embedding/index.d.ts +0 -9
  208. package/dist/esm/embedding/index.d.ts.map +0 -1
  209. package/dist/esm/embedding/index.js +0 -4
  210. package/dist/esm/embedding/local.d.ts +0 -6
  211. package/dist/esm/embedding/local.d.ts.map +0 -1
  212. package/dist/esm/embedding/local.js +0 -25
  213. package/dist/esm/embedding/openai.d.ts +0 -9
  214. package/dist/esm/embedding/openai.d.ts.map +0 -1
  215. package/dist/esm/embedding/openai.js +0 -23
  216. package/dist/esm/events/console.d.ts +0 -25
  217. package/dist/esm/events/console.d.ts.map +0 -1
  218. package/dist/esm/events/console.js +0 -37
  219. package/dist/esm/events/webhook.d.ts +0 -30
  220. package/dist/esm/events/webhook.d.ts.map +0 -1
  221. package/dist/esm/events/webhook.js +0 -75
  222. package/dist/esm/memory/cloudflare/index.d.ts +0 -3
  223. package/dist/esm/memory/cloudflare/index.d.ts.map +0 -1
  224. package/dist/esm/memory/cloudflare/index.js +0 -1
  225. package/dist/esm/memory/cloudflare/vectorize.d.ts +0 -62
  226. package/dist/esm/memory/cloudflare/vectorize.d.ts.map +0 -1
  227. package/dist/esm/memory/cloudflare/vectorize.js +0 -51
  228. package/dist/esm/memory/in-memory-semantic.d.ts +0 -16
  229. package/dist/esm/memory/in-memory-semantic.d.ts.map +0 -1
  230. package/dist/esm/memory/in-memory-semantic.js +0 -53
  231. package/dist/esm/memory/pinecone/index.d.ts +0 -7
  232. package/dist/esm/memory/pinecone/index.d.ts.map +0 -1
  233. package/dist/esm/memory/pinecone/index.js +0 -3
  234. package/dist/esm/memory/pinecone/memory-adapter.d.ts +0 -62
  235. package/dist/esm/memory/pinecone/memory-adapter.d.ts.map +0 -1
  236. package/dist/esm/memory/pinecone/memory-adapter.js +0 -216
  237. package/dist/esm/memory/pinecone/semantic.d.ts +0 -44
  238. package/dist/esm/memory/pinecone/semantic.d.ts.map +0 -1
  239. package/dist/esm/memory/pinecone/semantic.js +0 -86
  240. package/dist/esm/memory/sqlite/index.d.ts +0 -3
  241. package/dist/esm/memory/sqlite/index.d.ts.map +0 -1
  242. package/dist/esm/memory/sqlite/index.js +0 -1
  243. package/dist/esm/memory/sqlite/memory-adapter.d.ts +0 -58
  244. package/dist/esm/memory/sqlite/memory-adapter.d.ts.map +0 -1
  245. package/dist/esm/memory/sqlite/memory-adapter.js +0 -296
  246. package/dist/esm/memory/sqlite/schema.d.ts +0 -4
  247. package/dist/esm/memory/sqlite/schema.d.ts.map +0 -1
  248. package/dist/esm/memory/sqlite/schema.js +0 -86
  249. package/dist/esm/memory/supabase/index.d.ts +0 -7
  250. package/dist/esm/memory/supabase/index.d.ts.map +0 -1
  251. package/dist/esm/memory/supabase/index.js +0 -3
  252. package/dist/esm/memory/supabase/memory-adapter.d.ts +0 -67
  253. package/dist/esm/memory/supabase/memory-adapter.d.ts.map +0 -1
  254. package/dist/esm/memory/supabase/memory-adapter.js +0 -331
  255. package/dist/esm/memory/supabase/semantic.d.ts +0 -44
  256. package/dist/esm/memory/supabase/semantic.d.ts.map +0 -1
  257. package/dist/esm/memory/supabase/semantic.js +0 -68
  258. package/dist/esm/world/village.d.ts.map +0 -1
@@ -35,116 +35,58 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.MolrooPersona = void 0;
37
37
  const resolve_1 = require("./llm/resolve");
38
- const types_1 = require("./memory/types");
39
- const recall_1 = require("./memory/recall");
40
38
  const errors_1 = require("./errors");
41
39
  const api_client_1 = require("./api-client");
42
- /** Clamp appraisal values to engine-valid ranges after LLM generation. */
43
- function clampAppraisal(a) {
44
- const c = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
45
- return {
46
- goal_relevance: c(a.goal_relevance, -1, 1),
47
- goal_congruence: c(a.goal_congruence, -1, 1),
48
- expectedness: c(a.expectedness, 0, 1),
49
- controllability: c(a.controllability, 0, 1),
50
- agency: c(a.agency, -1, 1),
51
- norm_compatibility: c(a.norm_compatibility, -1, 1),
52
- internal_standards: c(a.internal_standards ?? 0, -1, 1),
53
- adjustment_potential: c(a.adjustment_potential ?? 0.5, 0, 1),
54
- urgency: c(a.urgency ?? 0.5, 0, 1),
55
- };
56
- }
57
- /** Build a system prompt section describing the interlocutor. */
58
- function buildInterlocutorBlock(ctx) {
59
- const parts = [`## About ${ctx.name}`];
60
- if (ctx.description)
61
- parts.push(ctx.description);
62
- if (ctx.extensions) {
63
- for (const [title, content] of Object.entries(ctx.extensions)) {
64
- parts.push(`### ${title}`);
65
- parts.push(content);
66
- }
67
- }
68
- return parts.join('\n');
69
- }
40
+ const memory_pipeline_1 = require("./persona/memory-pipeline");
41
+ const chat_orchestrator_1 = require("./persona/chat-orchestrator");
42
+ // ── SDK Persona Types ──
43
+ const DEFAULT_BASE_URL = 'https://api.molroo.io';
70
44
  // ── MolrooPersona ──
71
45
  /**
72
46
  * SDK client for interacting with a standalone molroo persona instance.
73
47
  *
74
- * @example
75
- * ```typescript
76
- * // Single adapter (recommended)
77
- * const persona = await MolrooPersona.create(
78
- * { baseUrl: 'https://api.molroo.io', apiKey: 'key', llm,
79
- * memory: new SqliteMemoryAdapter({ dbPath: './memory.db' }) },
80
- * { identity: { name: 'Sera' }, personality: { O: 0.8, C: 0.6, E: 0.7 } },
81
- * );
82
- *
83
- * // Split adapters (advanced)
84
- * const persona = await MolrooPersona.create(
85
- * { baseUrl: 'https://api.molroo.io', apiKey: 'key', llm,
86
- * memory: { episodes: episodeStore, semantic: vectorStore, embedding: embedProvider } },
87
- * { identity: { name: 'Sera' }, personality: { O: 0.8, C: 0.6, E: 0.7 } },
88
- * );
89
- * ```
48
+ * @deprecated Use {@link Molroo} from './world/world' instead.
90
49
  */
91
50
  class MolrooPersona {
92
51
  constructor(config) {
93
- this.client = (0, api_client_1.createApiClient)(config.baseUrl, config.apiKey);
52
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
53
+ this.client = (0, api_client_1.createApiClient)(baseUrl, config.apiKey);
94
54
  this._personaId = config.personaId || '';
95
55
  this.llm = config.llm ?? null;
96
56
  this.engineLlm = config.engineLlm ?? null;
97
57
  this.events = config.events ?? null;
98
- // Memory infrastructure
99
- if (config.memory) {
100
- if ((0, types_1.isMemoryConfig)(config.memory)) {
101
- // Split adapter path (MemoryConfig)
102
- this.memoryAdapter = null;
103
- this.episodeStore = config.memory.episodes;
104
- this.semanticStore = config.memory.semantic ?? null;
105
- this.embeddingProvider = config.memory.embedding ?? null;
106
- this.memoryRecallConfig = config.memory.recall;
107
- }
108
- else {
109
- // Single adapter path (MemoryAdapter)
110
- this.memoryAdapter = config.memory;
111
- this.episodeStore = null;
112
- this.semanticStore = null;
113
- this.embeddingProvider = null;
114
- this.memoryRecallConfig = config.recall;
115
- }
116
- }
117
- else {
118
- this.memoryAdapter = null;
119
- this.episodeStore = null;
120
- this.semanticStore = null;
121
- this.embeddingProvider = null;
122
- this.memoryRecallConfig = undefined;
123
- }
58
+ this.memoryAdapter = config.memory ?? null;
59
+ this.memoryRecallConfig = config.recall;
124
60
  }
125
61
  // ── Properties ──
126
- /** Unique identifier for this persona instance. */
127
62
  get id() {
128
63
  return this._personaId;
129
64
  }
130
- /** Unique identifier for this persona instance (alias for {@link id}). */
131
65
  get personaId() {
132
66
  return this._personaId;
133
67
  }
134
- // ── Static Factory Methods ──
68
+ static async create(config, input) {
69
+ // Handle description string (auto-generate via LLM)
70
+ if (typeof input === 'string') {
71
+ if (!config.llm) {
72
+ throw new errors_1.MolrooApiError('LLM adapter is required when using description string. ' +
73
+ 'Provide llm option or use explicit PersonaConfigData.', 'LLM_REQUIRED', 400);
74
+ }
75
+ const { generatePersona } = await Promise.resolve().then(() => __importStar(require('./generate/persona')));
76
+ const llm = await (0, resolve_1.resolveLLM)(config.llm);
77
+ const personaConfig = await generatePersona(llm, input);
78
+ return MolrooPersona.createWithConfig(config, personaConfig);
79
+ }
80
+ // Handle explicit PersonaConfigData
81
+ return MolrooPersona.createWithConfig(config, input);
82
+ }
135
83
  /**
136
- * Create a new persona on the molroo API and return a connected instance.
137
- *
138
- * @param config - API connection config and optional LLM adapter.
139
- * Accepts a full {@link LLMAdapter} or a shorthand config object:
140
- * ```typescript
141
- * llm: { provider: 'openai', apiKey: '...' }
142
- * ```
143
- * @param personaConfig - Persona identity, personality, and goals.
144
- * @returns A connected MolrooPersona instance.
84
+ * Internal implementation for creating persona with resolved config.
85
+ * @internal
145
86
  */
146
- static async create(config, personaConfig) {
147
- const client = (0, api_client_1.createApiClient)(config.baseUrl, config.apiKey);
87
+ static async createWithConfig(config, personaConfig) {
88
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
89
+ const client = (0, api_client_1.createApiClient)(baseUrl, config.apiKey);
148
90
  const { data } = await client.POST('/personas', {
149
91
  body: { config: personaConfig },
150
92
  headers: { 'Idempotency-Key': crypto.randomUUID() },
@@ -154,52 +96,34 @@ class MolrooPersona {
154
96
  config.engineLlm ? (0, resolve_1.resolveLLM)(config.engineLlm) : undefined,
155
97
  ]);
156
98
  const result = (0, api_client_1.unwrap)(data);
157
- const persona = new MolrooPersona({ ...config, llm, engineLlm, personaId: result.personaId });
158
- return persona;
99
+ return new MolrooPersona({ ...config, llm, engineLlm, personaId: result.personaId });
159
100
  }
160
101
  /**
161
- * Connect to an existing persona by ID.
162
- *
163
- * Verifies the persona exists and fetches its configuration.
164
- *
165
- * @param config - API connection config and optional LLM adapter.
166
- * Accepts a full {@link LLMAdapter} or a shorthand config object:
167
- * ```typescript
168
- * llm: { provider: 'openai', apiKey: '...' }
169
- * ```
170
- * @param personaId - The ID of the persona to connect to.
171
- * @returns A connected MolrooPersona instance.
102
+ * Generate a persona from description and create it.
103
+ * @deprecated Use `create(config, description)` instead.
172
104
  */
105
+ static async generate(config, description) {
106
+ return MolrooPersona.create(config, description);
107
+ }
173
108
  static async connect(config, personaId) {
174
109
  const [llm, engineLlm] = await Promise.all([
175
110
  config.llm ? (0, resolve_1.resolveLLM)(config.llm) : undefined,
176
111
  config.engineLlm ? (0, resolve_1.resolveLLM)(config.engineLlm) : undefined,
177
112
  ]);
113
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
178
114
  const persona = new MolrooPersona({ ...config, llm, engineLlm, personaId });
179
- // Verify persona exists
180
115
  await persona.client.GET('/personas/{id}', {
181
116
  params: { path: { id: personaId } },
182
117
  });
183
118
  return persona;
184
119
  }
185
- /**
186
- * List all personas for the authenticated tenant.
187
- *
188
- * @param config - API connection config (baseUrl + apiKey).
189
- * @returns List of persona summaries with optional pagination cursor.
190
- */
191
120
  static async listPersonas(config) {
192
- const client = (0, api_client_1.createApiClient)(config.baseUrl, config.apiKey);
121
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
122
+ const client = (0, api_client_1.createApiClient)(baseUrl, config.apiKey);
193
123
  const { data } = await client.GET('/personas');
194
124
  return (0, api_client_1.unwrap)(data);
195
125
  }
196
126
  // ── Runtime ──
197
- /**
198
- * Send a message to the persona and get an emotion-processed response.
199
- *
200
- * Internally converts the SDK-friendly options into the API wire format
201
- * (`{ event: PerceiveEvent, context?: PerceiveContext }`).
202
- */
203
127
  async perceive(message, options) {
204
128
  const eventType = options?.type ?? 'chat_message';
205
129
  const sourceName = typeof options?.from === 'string'
@@ -224,196 +148,32 @@ class MolrooPersona {
224
148
  body: { event, context },
225
149
  });
226
150
  const response = (0, api_client_1.unwrap)(data);
227
- // Save episode to memory (unless caller opts out)
228
- if (!options?.skipMemory && response.memoryEpisode) {
229
- // Tag episode with event type so recall can distinguish chat vs events
151
+ if (!options?.skipMemory && response.memoryEpisode && this.memoryAdapter) {
230
152
  if (!response.memoryEpisode.type) {
231
153
  response.memoryEpisode.type = eventType;
232
154
  }
233
- this.postPerceivePipeline(response);
155
+ (0, memory_pipeline_1.postPerceive)(this.memoryPipelineDeps, response);
234
156
  }
235
157
  return response;
236
158
  }
237
- /**
238
- * Fire a non-chat event and process through the emotion engine.
239
- *
240
- * Unlike chat(), this does not involve LLM generation — it directly
241
- * sends an event to the perceive endpoint with a required appraisal vector.
242
- * The resulting episode is saved to memory and can be recalled during chat().
243
- *
244
- * @param type - Event type identifier (e.g. 'attack', 'gift', 'rest').
245
- * @param description - Human-readable event description (used as message context).
246
- * @param options - Must include `appraisal`. Optionally `from`, `stimulus`, `payload`.
247
- * @returns Emotion engine response.
248
- *
249
- * @example
250
- * ```typescript
251
- * await persona.event('attack', 'goblin attacks with sword', {
252
- * from: 'goblin',
253
- * appraisal: {
254
- * goal_relevance: 0.8,
255
- * goal_congruence: -0.9,
256
- * expectedness: 0.3,
257
- * controllability: 0.4,
258
- * agency: -0.6,
259
- * norm_compatibility: -0.5,
260
- * },
261
- * });
262
- * ```
263
- */
264
159
  async event(type, description, options) {
265
160
  return this.perceive(description, { ...options, type });
266
161
  }
267
- /**
268
- * High-level chat: getState → LLM generate → perceive with appraisal.
269
- *
270
- * 1. Calls `getPromptContext()` for the server-assembled system prompt
271
- * 2. Recalls episodic + semantic memories from client-side stores
272
- * 3. Sends to LLM adapter for text generation + appraisal
273
- * 4. Sends the appraisal to the API via `perceive()` for emotion computation
274
- * 5. Runs post-chat pipeline (episode save, reflection, events)
275
- *
276
- * Requires {@link LLMAdapter}. Without one, use {@link perceive} directly
277
- * for emotion-only interaction.
278
- */
279
162
  async chat(message, options) {
280
- const fromOption = options?.from ?? 'user';
281
- const from = typeof fromOption === 'string' ? fromOption : fromOption.name;
282
- const interlocutor = typeof fromOption === 'object' ? fromOption : null;
283
163
  const llm = this.requireLLM();
284
- // 1. Fetch server-assembled system prompt
285
- const ctx = await this.getPromptContext(options?.consumerSuffix, from);
286
- let systemPrompt = ctx.systemPrompt;
287
- const hasTools = (ctx.tools?.length ?? 0) > 0;
288
- // 2. Recall memories (episodic + semantic + reflections)
289
- const recalled = await (0, recall_1.recallMemories)(message, {
164
+ const deps = {
165
+ personaId: this._personaId,
166
+ llm,
167
+ engineLlm: this.engineLlm,
290
168
  memoryAdapter: this.memoryAdapter,
291
- episodeStore: this.episodeStore,
292
- semanticStore: this.semanticStore,
293
- embeddingProvider: this.embeddingProvider,
294
- config: this.memoryRecallConfig,
295
- sourceEntity: from,
296
- reflectionEntity: this._personaId,
297
- });
298
- if (interlocutor) {
299
- systemPrompt += '\n\n' + buildInterlocutorBlock(interlocutor);
300
- }
301
- const memoryBlock = (0, recall_1.buildMemoryBlock)(recalled.episodic, recalled.semantic, recalled.reflections);
302
- if (memoryBlock) {
303
- systemPrompt += '\n\n' + memoryBlock;
304
- }
305
- // 3. LLM Generate (SDK side, user's API key)
306
- const messages = [];
307
- if (options?.history) {
308
- messages.push(...options.history.map(h => ({ role: h.role, content: h.content })));
309
- }
310
- messages.push({ role: 'user', content: message });
311
- let responseText;
312
- let appraisal;
313
- let earlyPerceiveResponse;
314
- // Split mode: engineLlm handles appraisal, primary llm handles response text
315
- if (this.engineLlm && this.engineLlm !== llm) {
316
- const { AppraisalVectorSchema } = await Promise.resolve().then(() => __importStar(require('./llm/schema')));
317
- const appraisalInstruction = [
318
- '',
319
- '## Appraisal Task',
320
- "Evaluate how RECEIVING the user's message affects this persona emotionally.",
321
- 'The event you are appraising is the message itself arriving — not the described situation.',
322
- "When the user shares their own experience (e.g. loss, success), appraise through the persona's relational goals: caring about the speaker makes their suffering relevant and incongruent.",
323
- "Rate each dimension from the persona's subjective perspective.",
324
- 'An insult should produce negative goal_congruence and norm_compatibility.',
325
- 'A compliment should produce positive values. Neutral small talk should be near zero.',
326
- ].join('\n');
327
- // 3a. engineLlm → appraisal (based on prior emotional state)
328
- // Only send last few messages for appraisal context (full history is wasteful)
329
- const appraisalMessages = messages.length <= 5 ? messages : messages.slice(-5);
330
- const { object: appraisalResult } = await this.engineLlm.generateObject({
331
- system: systemPrompt + appraisalInstruction,
332
- messages: appraisalMessages,
333
- schema: AppraisalVectorSchema,
334
- });
335
- appraisal = clampAppraisal(appraisalResult);
336
- // 3b. perceive with user message → engine updates emotion before response generation
337
- earlyPerceiveResponse = await this.perceive(message, {
338
- from,
339
- appraisal,
340
- priorEpisodes: recalled.episodic.length > 0 ? recalled.episodic : undefined,
341
- skipMemory: true, // chat() runs its own postChatPipeline
342
- });
343
- // 3c. Fetch updated prompt reflecting new emotional state
344
- let updatedPrompt = systemPrompt;
345
- try {
346
- const updatedCtx = await this.getPromptContext(options?.consumerSuffix, from);
347
- updatedPrompt = updatedCtx.systemPrompt;
348
- if (interlocutor) {
349
- updatedPrompt += '\n\n' + buildInterlocutorBlock(interlocutor);
350
- }
351
- if (memoryBlock) {
352
- updatedPrompt += '\n\n' + memoryBlock;
353
- }
354
- }
355
- catch {
356
- // Use original prompt if updated fetch fails
357
- }
358
- // 3d. primary llm → response (with updated emotional state in prompt)
359
- const { text } = await llm.generateText({
360
- system: updatedPrompt,
361
- messages,
362
- });
363
- responseText = text;
364
- }
365
- else if (hasTools) {
366
- // Combined mode with tool-use: LLM can request memory searches
367
- const result = await this.generateWithToolLoop(llm, systemPrompt, messages, options?.onToolCall);
368
- responseText = result.text;
369
- appraisal = clampAppraisal(result.appraisal);
370
- }
371
- else {
372
- // Combined mode (default): single LLM call for response + appraisal
373
- const { LLMResponseSchema } = await Promise.resolve().then(() => __importStar(require('./llm/schema')));
374
- const { object: llmResult } = await llm.generateObject({
375
- system: systemPrompt,
376
- messages,
377
- schema: LLMResponseSchema,
378
- });
379
- responseText = llmResult.response;
380
- appraisal = clampAppraisal(llmResult.appraisal ?? {
381
- goal_relevance: 0,
382
- goal_congruence: 0,
383
- expectedness: 0.5,
384
- controllability: 0.5,
385
- agency: 0,
386
- norm_compatibility: 0,
387
- internal_standards: 0,
388
- adjustment_potential: 0.5,
389
- urgency: 0.5,
390
- });
391
- }
392
- // 4. Send to API for emotion processing (skip if already done in split mode)
393
- let response;
394
- if (earlyPerceiveResponse) {
395
- response = earlyPerceiveResponse;
396
- }
397
- else {
398
- response = await this.perceive(responseText, {
399
- from,
400
- appraisal,
401
- priorEpisodes: recalled.episodic.length > 0 ? recalled.episodic : undefined,
402
- skipMemory: true, // chat() runs its own postChatPipeline
403
- });
404
- }
405
- // Inject LLM-generated text
406
- response.text = responseText;
407
- // 5. Post-chat pipeline (fire-and-forget: episode save, reflection, events)
408
- this.postChatPipeline(response);
409
- return { text: responseText, response };
169
+ memoryRecallConfig: this.memoryRecallConfig,
170
+ events: this.events,
171
+ getPromptContext: (suffix, source) => this.getPromptContext(suffix, source),
172
+ perceive: (msg, opts) => this.perceive(msg, opts),
173
+ searchMemory: (query) => this.searchMemory(query),
174
+ };
175
+ return (0, chat_orchestrator_1.chat)(deps, message, options);
410
176
  }
411
- /**
412
- * Advance persona time by the specified number of seconds.
413
- *
414
- * @param seconds - Number of seconds to advance.
415
- * @returns Any pending events that were processed.
416
- */
417
177
  async tick(seconds) {
418
178
  const { data } = await this.client.POST('/personas/{id}/tick', {
419
179
  params: { path: { id: this._personaId } },
@@ -421,11 +181,6 @@ class MolrooPersona {
421
181
  });
422
182
  return (0, api_client_1.unwrap)(data);
423
183
  }
424
- /**
425
- * Directly set the persona's emotion state in VAD space.
426
- *
427
- * @param vad - Partial VAD values to set (V: -1..1, A: 0..1, D: -1..1).
428
- */
429
184
  async setEmotion(vad) {
430
185
  await this.client.POST('/personas/{id}/emotion', {
431
186
  params: { path: { id: this._personaId } },
@@ -433,33 +188,18 @@ class MolrooPersona {
433
188
  });
434
189
  }
435
190
  // ── State ──
436
- /**
437
- * Get the current emotional and psychological state of the persona.
438
- *
439
- * @returns Current emotion, mood, somatic, and narrative state.
440
- */
441
191
  async getState() {
442
192
  const { data } = await this.client.GET('/personas/{id}/state', {
443
193
  params: { path: { id: this._personaId } },
444
194
  });
445
195
  return (0, api_client_1.unwrap)(data);
446
196
  }
447
- /**
448
- * Get a full snapshot of the persona's internal state.
449
- *
450
- * @returns Complete persona snapshot for backup/restore.
451
- */
452
197
  async getSnapshot() {
453
198
  const { data } = await this.client.GET('/personas/{id}/snapshot', {
454
199
  params: { path: { id: this._personaId } },
455
200
  });
456
201
  return (0, api_client_1.unwrap)(data);
457
202
  }
458
- /**
459
- * Restore the persona's internal state from a snapshot.
460
- *
461
- * @param snapshot - The snapshot to restore.
462
- */
463
203
  async putSnapshot(snapshot) {
464
204
  await this.client.PUT('/personas/{id}/snapshot', {
465
205
  params: { path: { id: this._personaId } },
@@ -467,11 +207,6 @@ class MolrooPersona {
467
207
  });
468
208
  }
469
209
  // ── Config ──
470
- /**
471
- * Patch the persona's configuration (identity, personality, goals).
472
- *
473
- * @param updates - Configuration updates to apply.
474
- */
475
210
  async patch(updates) {
476
211
  await this.client.PATCH('/personas/{id}', {
477
212
  params: { path: { id: this._personaId } },
@@ -479,7 +214,6 @@ class MolrooPersona {
479
214
  });
480
215
  }
481
216
  // ── Lifecycle ──
482
- /** Soft-delete this persona. Can be restored with {@link restore}. */
483
217
  async destroy() {
484
218
  if (this._personaId) {
485
219
  await this.client.DELETE('/personas/{id}', {
@@ -487,7 +221,6 @@ class MolrooPersona {
487
221
  });
488
222
  }
489
223
  }
490
- /** Restore a previously soft-deleted persona. */
491
224
  async restore() {
492
225
  if (this._personaId) {
493
226
  await this.client.POST('/personas/{id}/restore', {
@@ -495,216 +228,7 @@ class MolrooPersona {
495
228
  });
496
229
  }
497
230
  }
498
- // ── Private Helpers ──
499
- /** Whether memory is available (either single adapter or split stores). */
500
- get hasMemory() {
501
- return this.memoryAdapter !== null || this.episodeStore !== null;
502
- }
503
- // ── Post-Chat Pipeline (fire-and-forget) ──
504
- /**
505
- * Lightweight pipeline for perceive()-only interactions (non-chat events).
506
- * Saves the episode and emits events, but skips LLM reflection.
507
- */
508
- postPerceivePipeline(response) {
509
- if (!response.memoryEpisode)
510
- return;
511
- if (this.memoryAdapter) {
512
- // Single adapter path — adapter handles semantic indexing internally
513
- this.memoryAdapter.saveEpisode(response.memoryEpisode).catch(() => { });
514
- }
515
- else if (this.episodeStore) {
516
- // Split adapter path
517
- this.episodeStore.saveEpisode(response.memoryEpisode).catch(() => { });
518
- if (this.semanticStore && this.embeddingProvider && response.memoryEpisode.context) {
519
- const ep = response.memoryEpisode;
520
- this.embeddingProvider
521
- .embed((0, recall_1.stripMetaTags)(ep.context))
522
- .then((embedding) => {
523
- this.semanticStore.index({
524
- id: ep.id,
525
- embedding,
526
- metadata: {
527
- type: 'episode',
528
- sourceEntity: ep.sourceEntity,
529
- timestamp: ep.timestamp,
530
- importance: ep.importance,
531
- episodeType: ep.type,
532
- },
533
- });
534
- })
535
- .catch(() => { });
536
- }
537
- }
538
- // Event emission
539
- if (this.events) {
540
- this.emitResponseEvents(response, Date.now()).catch(() => { });
541
- }
542
- }
543
- postChatPipeline(response) {
544
- const now = Date.now();
545
- if (this.memoryAdapter) {
546
- // Single adapter path — adapter handles semantic indexing internally
547
- if (response.memoryEpisode) {
548
- this.memoryAdapter.saveEpisode(response.memoryEpisode).catch(() => { });
549
- }
550
- // Reflection generation
551
- if ((this.engineLlm || this.llm) && response.reflectionPrompt) {
552
- this.handleReflection(response.reflectionPrompt, response.emotion.vad).catch(() => { });
553
- }
554
- }
555
- else {
556
- // Split adapter path
557
- // 1. Episode storage + semantic indexing
558
- if (this.episodeStore && response.memoryEpisode) {
559
- this.episodeStore.saveEpisode(response.memoryEpisode).catch(() => { });
560
- if (this.semanticStore && this.embeddingProvider && response.memoryEpisode.context) {
561
- const ep = response.memoryEpisode;
562
- this.embeddingProvider
563
- .embed((0, recall_1.stripMetaTags)(ep.context))
564
- .then((embedding) => {
565
- this.semanticStore.index({
566
- id: ep.id,
567
- embedding,
568
- metadata: {
569
- type: 'episode',
570
- sourceEntity: ep.sourceEntity,
571
- timestamp: ep.timestamp,
572
- importance: ep.importance,
573
- episodeType: ep.type,
574
- },
575
- });
576
- })
577
- .catch(() => { });
578
- }
579
- }
580
- // 2. Reflection generation (requires LLM + episodeStore)
581
- if (this.episodeStore && (this.engineLlm || this.llm) && response.reflectionPrompt) {
582
- this.handleReflection(response.reflectionPrompt, response.emotion.vad).catch(() => { });
583
- }
584
- }
585
- // 3. Event emission
586
- if (this.events) {
587
- this.emitResponseEvents(response, now).catch(() => { });
588
- }
589
- }
590
- async handleReflection(prompt, emotionVad) {
591
- const reflectionLlm = this.engineLlm ?? this.llm;
592
- if (!reflectionLlm)
593
- return;
594
- if (!this.memoryAdapter && !this.episodeStore)
595
- return;
596
- const { text } = await reflectionLlm.generateText({
597
- system: prompt.system,
598
- messages: [{ role: 'user', content: prompt.user }],
599
- });
600
- const reflection = {
601
- id: `ref-${Date.now()}`,
602
- timestamp: Date.now(),
603
- sourceEntity: this._personaId,
604
- content: text,
605
- trigger: 'interaction',
606
- emotionSnapshot: emotionVad ?? { V: 0, A: 0, D: 0 },
607
- };
608
- if (this.memoryAdapter) {
609
- // Single adapter path — save reflection if supported
610
- if (this.memoryAdapter.saveReflection) {
611
- await this.memoryAdapter.saveReflection(reflection);
612
- }
613
- }
614
- else if (this.episodeStore) {
615
- // Split adapter path
616
- await this.episodeStore.saveReflection(reflection);
617
- if (this.semanticStore && this.embeddingProvider) {
618
- try {
619
- const embedding = await this.embeddingProvider.embed(text);
620
- await this.semanticStore.index({
621
- id: reflection.id,
622
- embedding,
623
- metadata: {
624
- type: 'reflection',
625
- sourceEntity: this._personaId,
626
- timestamp: reflection.timestamp,
627
- },
628
- });
629
- }
630
- catch {
631
- // semantic indexing is optional
632
- }
633
- }
634
- }
635
- await this.events?.emit({
636
- type: 'reflection_generated',
637
- personaId: this._personaId,
638
- timestamp: Date.now(),
639
- payload: { trigger: 'interaction' },
640
- });
641
- }
642
- async emitResponseEvents(response, now) {
643
- if (!this.events)
644
- return;
645
- const batch = [];
646
- if (response.emotion) {
647
- batch.push({
648
- type: 'emotion_changed',
649
- personaId: this._personaId,
650
- timestamp: now,
651
- payload: {
652
- vad: response.emotion.vad,
653
- primary: response.emotion.discrete.primary,
654
- intensity: response.emotion.discrete.intensity,
655
- },
656
- });
657
- }
658
- if (response.socialUpdates?.length) {
659
- batch.push({
660
- type: 'relationship_changed',
661
- personaId: this._personaId,
662
- timestamp: now,
663
- payload: { updates: response.socialUpdates },
664
- });
665
- }
666
- if (response.memoryEpisode) {
667
- batch.push({
668
- type: 'memory_consolidated',
669
- personaId: this._personaId,
670
- timestamp: now,
671
- payload: { episodeId: response.memoryEpisode.id },
672
- });
673
- }
674
- if (response.stageTransition) {
675
- batch.push({ type: 'stage_transition', personaId: this._personaId, timestamp: now, payload: {} });
676
- }
677
- if (response.maskExposure) {
678
- batch.push({ type: 'mask_exposure', personaId: this._personaId, timestamp: now, payload: response.maskExposure });
679
- }
680
- if (response.goalChanges) {
681
- batch.push({ type: 'goal_changed', personaId: this._personaId, timestamp: now, payload: response.goalChanges });
682
- }
683
- if (batch.length === 0)
684
- return;
685
- if (this.events.emitBatch) {
686
- await this.events.emitBatch(batch);
687
- }
688
- else {
689
- for (const event of batch) {
690
- await this.events.emit(event);
691
- }
692
- }
693
- }
694
- buildAppraisalHint(appraisal) {
695
- return [
696
- '## Emotional Evaluation (already computed — embody this, do not describe it)',
697
- `Goal relevance: ${appraisal.goal_relevance.toFixed(2)}, congruence: ${appraisal.goal_congruence.toFixed(2)}`,
698
- `Expectedness: ${appraisal.expectedness.toFixed(2)}, controllability: ${appraisal.controllability.toFixed(2)}`,
699
- `Agency: ${appraisal.agency.toFixed(2)}, norm compatibility: ${appraisal.norm_compatibility.toFixed(2)}`,
700
- ].join('\n');
701
- }
702
- requireLLM() {
703
- if (!this.llm) {
704
- throw new errors_1.MolrooApiError('LLM adapter is required for chat(). Provide llm option, or use perceive() directly.', 'LLM_NOT_CONFIGURED', 400);
705
- }
706
- return this.llm;
707
- }
231
+ // ── Prompt / Memory ──
708
232
  async getPromptContext(consumerSuffix, sourceEntity) {
709
233
  const { data } = await this.client.POST('/personas/{id}/prompt-context', {
710
234
  params: { path: { id: this._personaId } },
@@ -715,10 +239,6 @@ class MolrooPersona {
715
239
  });
716
240
  return (0, api_client_1.unwrap)(data);
717
241
  }
718
- /**
719
- * Search persona's episodic memory via the API.
720
- * Used internally by the tool-use loop.
721
- */
722
242
  async searchMemory(query, options) {
723
243
  const { data } = await this.client.POST('/personas/{id}/memory/search', {
724
244
  params: { path: { id: this._personaId } },
@@ -731,94 +251,21 @@ class MolrooPersona {
731
251
  const result = (0, api_client_1.unwrap)(data);
732
252
  return result.episodes;
733
253
  }
734
- /**
735
- * LLM generation loop with tool-use support for standalone persona.
736
- * Uses LLMResponseWithToolsSchema which allows the LLM to request
737
- * memory searches via the search_memory field. Capped at 3 iterations.
738
- */
739
- async generateWithToolLoop(llm, system, messages, onToolCall) {
740
- const MAX_TOOL_ITERATIONS = 3;
741
- const { LLMResponseWithToolsSchema, LLMResponseSchema } = await Promise.resolve().then(() => __importStar(require('./llm/schema')));
742
- let currentSystem = system;
743
- for (let iteration = 0; iteration < MAX_TOOL_ITERATIONS; iteration++) {
744
- const { object: llmResult } = await llm.generateObject({
745
- system: currentSystem,
746
- messages,
747
- schema: LLMResponseWithToolsSchema,
748
- });
749
- // If no tool call requested, return the response
750
- if (!llmResult.search_memory) {
751
- const text = llmResult.response;
752
- const appraisal = llmResult.appraisal ?? {
753
- goal_relevance: 0,
754
- goal_congruence: 0,
755
- expectedness: 0.5,
756
- controllability: 0.5,
757
- agency: 0,
758
- norm_compatibility: 0,
759
- internal_standards: 0,
760
- adjustment_potential: 0.5,
761
- urgency: 0.5,
762
- };
763
- return { text, appraisal };
764
- }
765
- // Execute memory search tool call
766
- const query = llmResult.search_memory;
767
- let episodes = [];
768
- try {
769
- episodes = await this.searchMemory(query);
770
- }
771
- catch {
772
- // Memory search failed — continue without results
773
- }
774
- // Notify callback if provided
775
- if (onToolCall) {
776
- onToolCall({
777
- name: 'search_memory',
778
- args: { query },
779
- result: episodes,
780
- });
781
- }
782
- // Inject memory search results into system prompt for next iteration
783
- const resultBlock = episodes.length > 0
784
- ? `\n\n## Memory Search Results (query: "${query}")\n${episodes.map(ep => {
785
- const ts = ep.timestamp ? new Date(ep.timestamp).toISOString() : 'unknown';
786
- const source = ep.sourceEntity ?? 'unknown';
787
- const context = ep.context ?? 'no context';
788
- return `- [${ts}] ${source}: ${context}`;
789
- }).join('\n')}`
790
- : `\n\n## Memory Search Results (query: "${query}")\nNo matching memories found.`;
791
- currentSystem = currentSystem + resultBlock;
792
- }
793
- // Exhausted tool iterations — make a final call without tool schema
794
- const { object: finalResult } = await llm.generateObject({
795
- system: currentSystem,
796
- messages,
797
- schema: LLMResponseSchema,
798
- });
799
- const text = finalResult.response;
800
- const appraisal = finalResult.appraisal ?? {
801
- goal_relevance: 0,
802
- goal_congruence: 0,
803
- expectedness: 0.5,
804
- controllability: 0.5,
805
- agency: 0,
806
- norm_compatibility: 0,
807
- internal_standards: 0,
808
- adjustment_potential: 0.5,
809
- urgency: 0.5,
254
+ // ── Private ──
255
+ get memoryPipelineDeps() {
256
+ return {
257
+ personaId: this._personaId,
258
+ memoryAdapter: this.memoryAdapter,
259
+ events: this.events,
260
+ llm: this.llm,
261
+ engineLlm: this.engineLlm,
810
262
  };
811
- return { text, appraisal };
812
263
  }
813
- buildContextBlock(state, from) {
814
- const parts = [];
815
- if (from) {
816
- parts.push(`Speaking with: ${from}.`);
817
- }
818
- if (state.narrative) {
819
- parts.push(`Narrative tone: ${state.narrative.tone.toFixed(2)}, agency: ${state.narrative.agency.toFixed(2)}`);
264
+ requireLLM() {
265
+ if (!this.llm) {
266
+ throw new errors_1.MolrooApiError('LLM adapter is required for chat(). Provide llm option, or use perceive() directly.', 'LLM_NOT_CONFIGURED', 400);
820
267
  }
821
- return parts.join('\n');
268
+ return this.llm;
822
269
  }
823
270
  }
824
271
  exports.MolrooPersona = MolrooPersona;