mojulo 0.0.0 → 0.1.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 (121) hide show
  1. package/README.md +53 -4
  2. package/lib/audit-logger-new.js +11 -0
  3. package/lib/auth/gate.js +25 -0
  4. package/lib/auth/service.js +17 -0
  5. package/lib/auth/session.js +63 -0
  6. package/lib/builder/chat-processor.js +607 -0
  7. package/lib/builder/composer-bridge.js +82 -0
  8. package/lib/builder/evaluator.js +159 -0
  9. package/lib/builder/executor.js +252 -0
  10. package/lib/builder/index.js +48 -0
  11. package/lib/builder/session.js +248 -0
  12. package/lib/builder/system-prompt.js +422 -0
  13. package/lib/builder/tone-presets.js +75 -0
  14. package/lib/builder/tool-executors.js +1418 -0
  15. package/lib/builder/tools.js +338 -0
  16. package/lib/builder/validators.js +239 -0
  17. package/lib/composer/composer.js +225 -0
  18. package/lib/composer/index.js +40 -0
  19. package/lib/composer/protocols/00_base.txt +19 -0
  20. package/lib/composer/protocols/01_knowledge.txt +9 -0
  21. package/lib/composer/protocols/02_form-gathering.txt +32 -0
  22. package/lib/composer/protocols/03_appointments.txt +16 -0
  23. package/lib/composer/protocols/04_triage.txt +15 -0
  24. package/lib/composer/protocols/05_optical-read.txt +22 -0
  25. package/lib/composer/response-builder.js +98 -0
  26. package/lib/config-builder.js +650 -0
  27. package/lib/db/ids.js +10 -0
  28. package/lib/db/index.js +179 -0
  29. package/lib/db/repositories/apiKeys.js +72 -0
  30. package/lib/db/repositories/auditLogs.js +12 -0
  31. package/lib/db/repositories/botSpaces.js +12 -0
  32. package/lib/db/repositories/builderSessions.js +312 -0
  33. package/lib/db/repositories/deploymentEvents.js +12 -0
  34. package/lib/db/repositories/deployments.js +385 -0
  35. package/lib/db/repositories/documents.js +68 -0
  36. package/lib/db/repositories/mcpJobs.js +84 -0
  37. package/lib/deployers/bot-fleet.js +110 -0
  38. package/lib/deployers/bot-proxy.js +72 -0
  39. package/lib/deployers/build.js +89 -0
  40. package/lib/deployers/cloud-deploy.js +310 -0
  41. package/lib/deployers/docker.js +439 -0
  42. package/lib/deployers/fly.js +432 -0
  43. package/lib/deployers/index.js +38 -0
  44. package/lib/deployment-auth.js +36 -0
  45. package/lib/document-parser.js +171 -0
  46. package/lib/embedder/chunker.js +93 -0
  47. package/lib/embedder/local.js +101 -0
  48. package/lib/embedder/preview-rag.js +93 -0
  49. package/lib/envelope-schema.js +54 -0
  50. package/lib/fleet/scoped-sql.js +342 -0
  51. package/lib/form-schema-config/base.js +135 -0
  52. package/lib/form-schema-config/index.js +286 -0
  53. package/lib/form-schema-config/locales/af-ZA.js +153 -0
  54. package/lib/form-schema-config/locales/ar-AE.js +142 -0
  55. package/lib/form-schema-config/locales/ar-SA.js +164 -0
  56. package/lib/form-schema-config/locales/de-DE.js +152 -0
  57. package/lib/form-schema-config/locales/en-AU.js +161 -0
  58. package/lib/form-schema-config/locales/en-CA.js +115 -0
  59. package/lib/form-schema-config/locales/en-GB.js +132 -0
  60. package/lib/form-schema-config/locales/en-IN.js +219 -0
  61. package/lib/form-schema-config/locales/en-MY.js +171 -0
  62. package/lib/form-schema-config/locales/en-NG.js +198 -0
  63. package/lib/form-schema-config/locales/en-PH.js +186 -0
  64. package/lib/form-schema-config/locales/en-SG.js +153 -0
  65. package/lib/form-schema-config/locales/en-US.js +138 -0
  66. package/lib/form-schema-config/locales/es-ES.js +171 -0
  67. package/lib/form-schema-config/locales/es-MX.js +193 -0
  68. package/lib/form-schema-config/locales/fr-CA.js +138 -0
  69. package/lib/form-schema-config/locales/fr-FR.js +155 -0
  70. package/lib/form-schema-config/locales/hi-IN.js +219 -0
  71. package/lib/form-schema-config/locales/it-IT.js +157 -0
  72. package/lib/form-schema-config/locales/ja-JP.js +169 -0
  73. package/lib/form-schema-config/locales/ko-KR.js +140 -0
  74. package/lib/form-schema-config/locales/nl-NL.js +149 -0
  75. package/lib/form-schema-config/locales/pt-BR.js +168 -0
  76. package/lib/form-schema-config/locales/zh-CN.js +172 -0
  77. package/lib/form-schema-config/locales/zh-HK.js +142 -0
  78. package/lib/form-structure-schema.js +191 -0
  79. package/lib/llm-providers.js +828 -0
  80. package/lib/markdown.js +197 -0
  81. package/lib/mcp/catalysts/appointment-to-calendar.md +84 -0
  82. package/lib/mcp/catalysts/conversations-to-channel-digest.md +104 -0
  83. package/lib/mcp/catalysts/document-extract-to-store.md +92 -0
  84. package/lib/mcp/catalysts/knowledge-gap-miner.md +96 -0
  85. package/lib/mcp/catalysts/loader.js +144 -0
  86. package/lib/mcp/catalysts/qualify-lead-to-crm.md +83 -0
  87. package/lib/mcp/catalysts/scan-conversations-for-signal.md +92 -0
  88. package/lib/mcp/catalysts/submission-to-ticket.md +83 -0
  89. package/lib/mcp/catalysts/submissions-to-warehouse.md +103 -0
  90. package/lib/mcp/catalysts/weekly-submissions-digest.md +82 -0
  91. package/lib/mcp/jobs.js +64 -0
  92. package/lib/mcp/server.js +184 -0
  93. package/lib/mcp/session-binding.js +130 -0
  94. package/lib/mcp/tools/build.js +123 -0
  95. package/lib/mcp/tools/catalysts.js +477 -0
  96. package/lib/mcp/tools/context.js +325 -0
  97. package/lib/mcp/tools/fleet.js +391 -0
  98. package/lib/mcp/tools/jobs-tools.js +240 -0
  99. package/lib/mcp/tools/operate.js +314 -0
  100. package/lib/preview/build-preview-config.js +136 -0
  101. package/lib/rate-limiter.js +11 -0
  102. package/lib/resolve-api-key.js +142 -0
  103. package/lib/storage/index.js +40 -0
  104. package/messages/de.json +2136 -0
  105. package/messages/en.json +2136 -0
  106. package/messages/es.json +2136 -0
  107. package/messages/fr.json +2136 -0
  108. package/messages/it.json +2136 -0
  109. package/messages/ja.json +2136 -0
  110. package/messages/ko.json +2136 -0
  111. package/messages/nl.json +2136 -0
  112. package/messages/pl.json +2136 -0
  113. package/messages/pt.json +2136 -0
  114. package/messages/ru.json +2136 -0
  115. package/messages/uk.json +2136 -0
  116. package/messages/zh.json +2136 -0
  117. package/package.json +61 -5
  118. package/scripts/mcp-config.mjs +162 -0
  119. package/scripts/mcp-stdio-loader.mjs +42 -0
  120. package/scripts/mcp-stdio.mjs +108 -0
  121. package/scripts/mojulo-paths.mjs +48 -0
@@ -0,0 +1,607 @@
1
+ /**
2
+ * Chat Processor for Modular Bot Creation
3
+ *
4
+ * Processes user messages and generates contextual responses.
5
+ * Uses rule-based intent detection with optional LLM enhancement.
6
+ */
7
+
8
+ import {
9
+ toggleProtocol,
10
+ saveCoreConfig,
11
+ saveIdentityConfig,
12
+ saveProtocolConfig,
13
+ } from './index.js';
14
+
15
+ // Message types
16
+ const MESSAGE_TYPES = {
17
+ BOT_TEXT: 'bot_text',
18
+ BOT_QUESTION: 'bot_question',
19
+ BOT_STEP_CARD: 'bot_step_card',
20
+ BOT_CONFIRMATION: 'bot_confirmation',
21
+ BOT_SUCCESS: 'bot_success',
22
+ BOT_ERROR: 'bot_error',
23
+ };
24
+
25
+ // Intent patterns
26
+ const INTENT_PATTERNS = {
27
+ // Protocol mentions
28
+ knowledge: [/knowledge/i, /rag/i, /document/i, /faq/i, /answer.*question/i, /search/i],
29
+ formGathering: [/form/i, /collect/i, /gather/i, /information/i, /lead/i, /contact/i],
30
+ appointments: [/appointment/i, /book/i, /schedule/i, /calendar/i, /meeting/i],
31
+
32
+ // Action intents
33
+ deploy: [/deploy/i, /launch/i, /publish/i, /go live/i, /start/i, /create bot/i],
34
+ confirm: [/^yes$/i, /confirm/i, /correct/i, /right/i, /looks? good/i, /^ok$/i, /^yep$/i],
35
+ deny: [/^no$/i, /cancel/i, /wrong/i, /change/i, /redo/i, /different/i],
36
+
37
+ // Setup intents
38
+ setup_core: [/provider/i, /model/i, /name.*bot/i, /bot.*name/i, /core.*config/i],
39
+ setup_identity: [/identity/i, /personality/i, /objective/i, /first message/i, /greeting/i],
40
+ setup_protocols: [/capabilities/i, /protocols/i, /what.*can.*do/i, /choose.*features/i],
41
+ setup_knowledge: [/configure.*knowledge/i, /setup.*knowledge/i, /knowledge.*config/i, /rag.*config/i],
42
+ setup_forms: [/configure.*form/i, /setup.*form/i, /form.*config/i, /form.*collection/i],
43
+ setup_appointments: [/configure.*appointment/i, /setup.*appointment/i, /appointment.*config/i, /calendar.*config/i],
44
+ };
45
+
46
+ // Protocol descriptions
47
+ const PROTOCOL_INFO = {
48
+ knowledge: {
49
+ name: 'Knowledge Base',
50
+ description: 'Answer questions from your documents using RAG',
51
+ },
52
+ formGathering: {
53
+ name: 'Form Collection',
54
+ description: 'Gather information through conversational forms',
55
+ },
56
+ appointments: {
57
+ name: 'Appointments',
58
+ description: 'Allow users to book calendar appointments',
59
+ },
60
+ };
61
+
62
+ /**
63
+ * Process a chat message and generate response
64
+ * @param {Object} params - Processing parameters
65
+ * @param {Object} params.session - Current session
66
+ * @param {string} params.userId - User ID
67
+ * @param {string} params.message - User message
68
+ * @param {string} params.messageType - Message type (text, selection, confirmation)
69
+ * @param {Object} params.context - Additional context
70
+ * @returns {Promise<{ messages: Array, sessionUpdate?: Object }>}
71
+ */
72
+ export async function processChatMessage({
73
+ session,
74
+ userId,
75
+ message,
76
+ messageType,
77
+ context,
78
+ }) {
79
+ const messages = [];
80
+ let sessionUpdate = null;
81
+
82
+ // Detect intent
83
+ const intent = detectIntent(message);
84
+ const protocols = detectProtocols(message);
85
+
86
+ // Handle based on message type and intent
87
+ if (messageType === 'confirmation') {
88
+ return handleConfirmation(message, session, userId, context);
89
+ }
90
+
91
+ if (messageType === 'selection') {
92
+ return handleSelection(message, session, userId, context);
93
+ }
94
+
95
+ // Handle protocol detection
96
+ if (protocols.length > 0) {
97
+ return handleProtocolDetection(protocols, session, userId, message);
98
+ }
99
+
100
+ // Handle specific intents
101
+ if (intent === 'deploy') {
102
+ return handleDeployIntent(session, userId);
103
+ }
104
+
105
+ if (intent === 'setup_core') {
106
+ return handleCoreSetupIntent(session);
107
+ }
108
+
109
+ if (intent === 'setup_identity') {
110
+ return handleIdentitySetupIntent(session);
111
+ }
112
+
113
+ if (intent === 'setup_protocols') {
114
+ return handleProtocolsSetupIntent(session);
115
+ }
116
+
117
+ if (intent === 'setup_knowledge') {
118
+ return handleKnowledgeSetupIntent(session);
119
+ }
120
+
121
+ if (intent === 'setup_forms') {
122
+ return handleFormsSetupIntent(session);
123
+ }
124
+
125
+ if (intent === 'setup_appointments') {
126
+ return handleAppointmentsSetupIntent(session);
127
+ }
128
+
129
+ // Default: Analyze message and suggest next step
130
+ return suggestNextStep(session, message);
131
+ }
132
+
133
+ /**
134
+ * Detect protocols mentioned in message
135
+ */
136
+ function detectProtocols(message) {
137
+ const detected = [];
138
+
139
+ for (const [protocol, patterns] of Object.entries(INTENT_PATTERNS)) {
140
+ if (['knowledge', 'formGathering', 'appointments'].includes(protocol)) {
141
+ for (const pattern of patterns) {
142
+ if (pattern.test(message)) {
143
+ detected.push(protocol);
144
+ break;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ return [...new Set(detected)];
151
+ }
152
+
153
+ /**
154
+ * Detect user intent
155
+ */
156
+ function detectIntent(message) {
157
+ for (const [intent, patterns] of Object.entries(INTENT_PATTERNS)) {
158
+ if (!['knowledge', 'formGathering', 'appointments'].includes(intent)) {
159
+ for (const pattern of patterns) {
160
+ if (pattern.test(message)) {
161
+ return intent;
162
+ }
163
+ }
164
+ }
165
+ }
166
+ return null;
167
+ }
168
+
169
+ /**
170
+ * Handle protocol detection
171
+ */
172
+ async function handleProtocolDetection(protocols, session, userId, message) {
173
+ const messages = [];
174
+ const enabledProtocols = session.enabledProtocols || {};
175
+
176
+ // Build protocol description
177
+ const protocolList = protocols
178
+ .map((p) => `**${PROTOCOL_INFO[p]?.name || p}**: ${PROTOCOL_INFO[p]?.description || ''}`)
179
+ .join('\n');
180
+
181
+ messages.push({
182
+ type: MESSAGE_TYPES.BOT_TEXT,
183
+ content: `I'll set up your bot with these capabilities:\n\n${protocolList}`,
184
+ });
185
+
186
+ // Show protocol selection card for confirmation
187
+ messages.push({
188
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
189
+ content: null,
190
+ data: {
191
+ step: 'protocols',
192
+ knowledge: protocols.includes('knowledge'),
193
+ formGathering: protocols.includes('formGathering'),
194
+ appointments: protocols.includes('appointments'),
195
+ },
196
+ });
197
+
198
+ return { messages };
199
+ }
200
+
201
+ /**
202
+ * Handle confirmation responses
203
+ */
204
+ async function handleConfirmation(message, session, userId, context) {
205
+ const isConfirmed = /^(yes|confirm|correct|right|ok|yep)/i.test(message);
206
+
207
+ if (isConfirmed) {
208
+ // Move to next step based on current state
209
+ return suggestNextStep(session, 'Confirmed! Let\'s continue.');
210
+ }
211
+
212
+ return {
213
+ messages: [
214
+ {
215
+ type: MESSAGE_TYPES.BOT_TEXT,
216
+ content: "No problem! What would you like to change?",
217
+ },
218
+ ],
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Handle selection responses
224
+ */
225
+ async function handleSelection(selection, session, userId, context) {
226
+ // Just acknowledge and continue
227
+ return suggestNextStep(session, selection);
228
+ }
229
+
230
+ /**
231
+ * Handle deploy intent
232
+ */
233
+ async function handleDeployIntent(session, userId) {
234
+ const messages = [];
235
+ const enabledProtocols = session.enabledProtocols || {};
236
+ const protocolConfigs = session.protocolConfigs || {};
237
+
238
+ // Check if ready to deploy
239
+ if (!session.coreConfig?.botName) {
240
+ messages.push({
241
+ type: MESSAGE_TYPES.BOT_TEXT,
242
+ content: "Before deploying, we need to set up some basics. Let's start with the core configuration.",
243
+ });
244
+ messages.push({
245
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
246
+ content: null,
247
+ data: { step: 'core' },
248
+ });
249
+ return { messages };
250
+ }
251
+
252
+ // Check if any protocols are enabled
253
+ const hasProtocols = Object.values(enabledProtocols).some((v) => v);
254
+ if (!hasProtocols) {
255
+ messages.push({
256
+ type: MESSAGE_TYPES.BOT_TEXT,
257
+ content: "Before deploying, we need to choose what your bot can do.",
258
+ });
259
+ messages.push({
260
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
261
+ content: null,
262
+ data: { step: 'protocols' },
263
+ });
264
+ return { messages };
265
+ }
266
+
267
+ if (!session.identityConfig?.objective) {
268
+ messages.push({
269
+ type: MESSAGE_TYPES.BOT_TEXT,
270
+ content: "We need to define your bot's identity before deploying.",
271
+ });
272
+ messages.push({
273
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
274
+ content: null,
275
+ data: { step: 'identity' },
276
+ });
277
+ return { messages };
278
+ }
279
+
280
+ // Check if any enabled protocols need configuration
281
+ if (enabledProtocols.knowledge && !protocolConfigs.knowledge) {
282
+ messages.push({
283
+ type: MESSAGE_TYPES.BOT_TEXT,
284
+ content: "Before deploying, let's configure the Knowledge Base.",
285
+ });
286
+ messages.push({
287
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
288
+ content: null,
289
+ data: { step: 'knowledge' },
290
+ });
291
+ return { messages };
292
+ }
293
+
294
+ if (enabledProtocols.formGathering && !protocolConfigs.formGathering) {
295
+ messages.push({
296
+ type: MESSAGE_TYPES.BOT_TEXT,
297
+ content: "Before deploying, let's set up Form Collection.",
298
+ });
299
+ messages.push({
300
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
301
+ content: null,
302
+ data: { step: 'formGathering' },
303
+ });
304
+ return { messages };
305
+ }
306
+
307
+ if (enabledProtocols.appointments && !protocolConfigs.appointments) {
308
+ messages.push({
309
+ type: MESSAGE_TYPES.BOT_TEXT,
310
+ content: "Before deploying, let's configure Appointments.",
311
+ });
312
+ messages.push({
313
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
314
+ content: null,
315
+ data: { step: 'appointments' },
316
+ });
317
+ return { messages };
318
+ }
319
+
320
+ // Ready to deploy
321
+ const protocolNames = Object.entries(enabledProtocols)
322
+ .filter(([_, enabled]) => enabled)
323
+ .map(([name]) => PROTOCOL_INFO[name]?.name || name);
324
+
325
+ messages.push({
326
+ type: MESSAGE_TYPES.BOT_TEXT,
327
+ content: "Everything looks ready! Here's a summary of your bot:",
328
+ });
329
+
330
+ messages.push({
331
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
332
+ content: null,
333
+ data: {
334
+ step: 'deploy',
335
+ botName: session.coreConfig.botName,
336
+ protocols: protocolNames,
337
+ provider: session.coreConfig.provider || 'Anthropic',
338
+ model: session.coreConfig.model,
339
+ },
340
+ });
341
+
342
+ return { messages };
343
+ }
344
+
345
+ /**
346
+ * Handle core setup intent
347
+ */
348
+ async function handleCoreSetupIntent(session) {
349
+ return {
350
+ messages: [
351
+ {
352
+ type: MESSAGE_TYPES.BOT_TEXT,
353
+ content: "Let's configure the core settings for your bot.",
354
+ },
355
+ {
356
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
357
+ content: null,
358
+ data: {
359
+ step: 'core',
360
+ provider: session.coreConfig?.provider,
361
+ model: session.coreConfig?.model,
362
+ botName: session.coreConfig?.botName,
363
+ },
364
+ },
365
+ ],
366
+ };
367
+ }
368
+
369
+ /**
370
+ * Handle identity setup intent
371
+ */
372
+ async function handleIdentitySetupIntent(session) {
373
+ return {
374
+ messages: [
375
+ {
376
+ type: MESSAGE_TYPES.BOT_TEXT,
377
+ content: "Let's define your bot's personality and behavior.",
378
+ },
379
+ {
380
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
381
+ content: null,
382
+ data: {
383
+ step: 'identity',
384
+ objective: session.identityConfig?.objective,
385
+ firstMessage: session.identityConfig?.firstMessage,
386
+ displayName: session.identityConfig?.displayName,
387
+ },
388
+ },
389
+ ],
390
+ };
391
+ }
392
+
393
+ /**
394
+ * Handle protocols setup intent
395
+ */
396
+ async function handleProtocolsSetupIntent(session) {
397
+ const enabledProtocols = session.enabledProtocols || {};
398
+ return {
399
+ messages: [
400
+ {
401
+ type: MESSAGE_TYPES.BOT_TEXT,
402
+ content: "Let's choose what capabilities your bot should have.",
403
+ },
404
+ {
405
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
406
+ content: null,
407
+ data: {
408
+ step: 'protocols',
409
+ knowledge: enabledProtocols.knowledge || false,
410
+ formGathering: enabledProtocols.formGathering || false,
411
+ appointments: enabledProtocols.appointments || false,
412
+ },
413
+ },
414
+ ],
415
+ };
416
+ }
417
+
418
+ /**
419
+ * Handle knowledge base setup intent
420
+ */
421
+ async function handleKnowledgeSetupIntent(session) {
422
+ const config = session.protocolConfigs?.knowledge || {};
423
+ return {
424
+ messages: [
425
+ {
426
+ type: MESSAGE_TYPES.BOT_TEXT,
427
+ content: "Let's configure the Knowledge Base for your bot.",
428
+ },
429
+ {
430
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
431
+ content: null,
432
+ data: {
433
+ step: 'knowledge',
434
+ ...config,
435
+ },
436
+ },
437
+ ],
438
+ };
439
+ }
440
+
441
+ /**
442
+ * Handle form collection setup intent
443
+ */
444
+ async function handleFormsSetupIntent(session) {
445
+ const config = session.protocolConfigs?.formGathering || {};
446
+ return {
447
+ messages: [
448
+ {
449
+ type: MESSAGE_TYPES.BOT_TEXT,
450
+ content: "Let's set up Form Collection for your bot.",
451
+ },
452
+ {
453
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
454
+ content: null,
455
+ data: {
456
+ step: 'formGathering',
457
+ ...config,
458
+ },
459
+ },
460
+ ],
461
+ };
462
+ }
463
+
464
+ /**
465
+ * Handle appointments setup intent
466
+ */
467
+ async function handleAppointmentsSetupIntent(session) {
468
+ const config = session.protocolConfigs?.appointments || {};
469
+ return {
470
+ messages: [
471
+ {
472
+ type: MESSAGE_TYPES.BOT_TEXT,
473
+ content: "Let's configure Appointments for your bot.",
474
+ },
475
+ {
476
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
477
+ content: null,
478
+ data: {
479
+ step: 'appointments',
480
+ ...config,
481
+ },
482
+ },
483
+ ],
484
+ };
485
+ }
486
+
487
+ /**
488
+ * Suggest next step based on session state
489
+ */
490
+ function suggestNextStep(session, userMessage = '') {
491
+ const messages = [];
492
+
493
+ // Check what's missing and suggest
494
+ if (!session.coreConfig?.botName) {
495
+ messages.push({
496
+ type: MESSAGE_TYPES.BOT_TEXT,
497
+ content: "Great! Let's start by setting up the basics for your bot. Choose a provider, model, and give your bot a name.",
498
+ });
499
+ messages.push({
500
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
501
+ content: null,
502
+ data: { step: 'core' },
503
+ });
504
+ return { messages };
505
+ }
506
+
507
+ // Check if any protocols are enabled
508
+ const enabledProtocols = session.enabledProtocols || {};
509
+ const protocolConfigs = session.protocolConfigs || {};
510
+ const hasProtocols = Object.values(enabledProtocols).some((v) => v);
511
+
512
+ if (!hasProtocols) {
513
+ messages.push({
514
+ type: MESSAGE_TYPES.BOT_TEXT,
515
+ content: "Now let's choose what your bot can do. What capabilities would you like to enable?",
516
+ });
517
+ messages.push({
518
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
519
+ content: null,
520
+ data: { step: 'protocols' },
521
+ });
522
+ return { messages };
523
+ }
524
+
525
+ if (!session.identityConfig?.objective) {
526
+ messages.push({
527
+ type: MESSAGE_TYPES.BOT_TEXT,
528
+ content: "Now let's define your bot's personality. What's its main objective and how should it greet users?",
529
+ });
530
+ messages.push({
531
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
532
+ content: null,
533
+ data: {
534
+ step: 'identity',
535
+ displayName: session.coreConfig?.botName,
536
+ },
537
+ });
538
+ return { messages };
539
+ }
540
+
541
+ // Check if any enabled protocols need configuration
542
+ // Knowledge base config
543
+ if (enabledProtocols.knowledge && !protocolConfigs.knowledge) {
544
+ messages.push({
545
+ type: MESSAGE_TYPES.BOT_TEXT,
546
+ content: "Let's configure the Knowledge Base. This allows your bot to answer questions from your documents.",
547
+ });
548
+ messages.push({
549
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
550
+ content: null,
551
+ data: { step: 'knowledge' },
552
+ });
553
+ return { messages };
554
+ }
555
+
556
+ // Form gathering config
557
+ if (enabledProtocols.formGathering && !protocolConfigs.formGathering) {
558
+ messages.push({
559
+ type: MESSAGE_TYPES.BOT_TEXT,
560
+ content: "Let's set up Form Collection. This allows your bot to gather information from users.",
561
+ });
562
+ messages.push({
563
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
564
+ content: null,
565
+ data: { step: 'formGathering' },
566
+ });
567
+ return { messages };
568
+ }
569
+
570
+ // Appointments config
571
+ if (enabledProtocols.appointments && !protocolConfigs.appointments) {
572
+ messages.push({
573
+ type: MESSAGE_TYPES.BOT_TEXT,
574
+ content: "Let's configure Appointments. This allows your bot to help users book appointments.",
575
+ });
576
+ messages.push({
577
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
578
+ content: null,
579
+ data: { step: 'appointments' },
580
+ });
581
+ return { messages };
582
+ }
583
+
584
+ // All basics and protocol configs done - suggest deploy
585
+ const protocolNames = Object.entries(enabledProtocols)
586
+ .filter(([_, enabled]) => enabled)
587
+ .map(([name]) => PROTOCOL_INFO[name]?.name || name);
588
+
589
+ messages.push({
590
+ type: MESSAGE_TYPES.BOT_TEXT,
591
+ content: `Your bot "${session.coreConfig.botName}" is ready to deploy! It has ${protocolNames.join(', ')} capabilities.`,
592
+ });
593
+
594
+ messages.push({
595
+ type: MESSAGE_TYPES.BOT_STEP_CARD,
596
+ content: null,
597
+ data: {
598
+ step: 'deploy',
599
+ botName: session.coreConfig.botName,
600
+ protocols: protocolNames,
601
+ provider: session.coreConfig.provider || 'Anthropic',
602
+ model: session.coreConfig.model,
603
+ },
604
+ });
605
+
606
+ return { messages };
607
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Composer Bridge for Builder Flow
3
+ *
4
+ * Bridges builder session data to the lib/composer system for instruction composition.
5
+ */
6
+
7
+ import { composeInstructions, getEnabledProtocolNames } from '../composer/composer.js';
8
+ import { buildResponseFormatSection } from '../composer/response-builder.js';
9
+
10
+ /**
11
+ * Compose instructions from a builder session
12
+ *
13
+ * @param {Object} session - The builder session object
14
+ * @returns {Promise<{ instructions: string, responseFormat: string, protocolsIncluded: string[] }>}
15
+ */
16
+ export async function composeFromSession(session) {
17
+ const { enabledProtocols, identityConfig, protocolData } = session;
18
+
19
+ // Build protocol data object for composer
20
+ const composerProtocolData = {};
21
+
22
+ if (enabledProtocols.formGathering && protocolData.formGathering) {
23
+ composerProtocolData.formStructure = protocolData.formGathering.generatedFormJson;
24
+ }
25
+
26
+ if (enabledProtocols.appointments && protocolData.appointments) {
27
+ composerProtocolData.appointments = protocolData.appointments.destinations;
28
+ }
29
+
30
+ if (enabledProtocols.triage && protocolData.triage) {
31
+ composerProtocolData.triage = protocolData.triage.routes;
32
+ }
33
+
34
+ // Optical Read: tool executor stores fields under generatedConfigs.opticalRead.
35
+ // Honor protocolData first for symmetry with the wizard-side path, then fall
36
+ // back to generatedConfigs for the chat-builder path.
37
+ if (enabledProtocols.opticalRead) {
38
+ const fields =
39
+ protocolData.opticalRead?.fields ||
40
+ session.generatedConfigs?.opticalRead?.fields ||
41
+ [];
42
+ if (fields.length > 0) {
43
+ composerProtocolData.opticalRead = { fields };
44
+ }
45
+ }
46
+
47
+ // Call composer
48
+ const instructions = await composeInstructions({
49
+ objective: identityConfig?.objective || '',
50
+ enabledProtocols,
51
+ protocolData: composerProtocolData,
52
+ });
53
+
54
+ // Build response format (already included in instructions, but provide separately for reference)
55
+ const responseFormat = await buildResponseFormatSection(enabledProtocols);
56
+
57
+ // Get list of included protocols
58
+ const protocolsIncluded = getEnabledProtocolNames(enabledProtocols);
59
+
60
+ return {
61
+ instructions,
62
+ responseFormat,
63
+ protocolsIncluded,
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Preview composition without caching
69
+ *
70
+ * @param {Object} session - The modular session object
71
+ * @returns {Promise<Object>} - Composition preview with instructions and metadata
72
+ */
73
+ export async function previewComposition(session) {
74
+ const result = await composeFromSession(session);
75
+
76
+ return {
77
+ ...result,
78
+ isCached: false,
79
+ previewedAt: new Date().toISOString(),
80
+ sessionId: session.id,
81
+ };
82
+ }