@ema.co/mcp-toolkit 2026.2.27 → 2026.2.28

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.

Potentially problematic release.


This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.

Files changed (58) hide show
  1. package/.context/public/guides/ema-user-guide.md +7 -6
  2. package/.context/public/guides/mcp-tools-guide.md +46 -23
  3. package/dist/config/index.js +11 -0
  4. package/dist/config/workflow-patterns.js +361 -0
  5. package/dist/mcp/autobuilder.js +2 -2
  6. package/dist/mcp/domain/generation-schema.js +15 -9
  7. package/dist/mcp/domain/structural-rules.js +3 -3
  8. package/dist/mcp/domain/validation-rules.js +20 -27
  9. package/dist/mcp/domain/workflow-generator.js +3 -3
  10. package/dist/mcp/domain/workflow-graph.js +1 -1
  11. package/dist/mcp/guidance.js +60 -1
  12. package/dist/mcp/handlers/conversation/adapter.js +13 -0
  13. package/dist/mcp/handlers/conversation/create.js +19 -0
  14. package/dist/mcp/handlers/conversation/delete.js +18 -0
  15. package/dist/mcp/handlers/conversation/formatters.js +62 -0
  16. package/dist/mcp/handlers/conversation/history.js +15 -0
  17. package/dist/mcp/handlers/conversation/index.js +43 -0
  18. package/dist/mcp/handlers/conversation/list.js +40 -0
  19. package/dist/mcp/handlers/conversation/messages.js +13 -0
  20. package/dist/mcp/handlers/conversation/rename.js +16 -0
  21. package/dist/mcp/handlers/conversation/send.js +90 -0
  22. package/dist/mcp/handlers/data/index.js +169 -3
  23. package/dist/mcp/handlers/feedback/client-id.js +49 -0
  24. package/dist/mcp/handlers/feedback/coalesce.js +167 -0
  25. package/dist/mcp/handlers/feedback/index.js +42 -1
  26. package/dist/mcp/handlers/feedback/outbox.js +301 -0
  27. package/dist/mcp/handlers/feedback/probes.js +127 -0
  28. package/dist/mcp/handlers/feedback/remote-store.js +59 -0
  29. package/dist/mcp/handlers/feedback/store.js +13 -1
  30. package/dist/mcp/handlers/persona/delete.js +7 -28
  31. package/dist/mcp/handlers/persona/update.js +7 -26
  32. package/dist/mcp/handlers/persona/version.js +30 -15
  33. package/dist/mcp/handlers/template/adapter.js +23 -0
  34. package/dist/mcp/handlers/template/crud.js +174 -0
  35. package/dist/mcp/handlers/template/index.js +6 -7
  36. package/dist/mcp/handlers/workflow/adapter.js +30 -46
  37. package/dist/mcp/handlers/workflow/index.js +2 -2
  38. package/dist/mcp/handlers/workflow/validation.js +2 -2
  39. package/dist/mcp/knowledge-guidance-topics.js +90 -53
  40. package/dist/mcp/knowledge.js +7 -357
  41. package/dist/mcp/prompts.js +5 -5
  42. package/dist/mcp/resources-dynamic.js +46 -38
  43. package/dist/mcp/resources-validation.js +5 -5
  44. package/dist/mcp/server.js +38 -5
  45. package/dist/mcp/tools.js +340 -8
  46. package/dist/sdk/client-adapter.js +90 -2
  47. package/dist/sdk/client.js +7 -0
  48. package/dist/sdk/ema-client.js +242 -27
  49. package/dist/sdk/generated/agent-catalog.js +96 -39
  50. package/dist/sdk/generated/deprecated-actions.js +1 -1
  51. package/dist/sdk/grpc-client.js +67 -5
  52. package/dist/sync/central-factory.js +86 -0
  53. package/dist/sync/central-version-storage.js +387 -0
  54. package/dist/sync/dis-port.js +75 -0
  55. package/dist/sync/version-policy.js +29 -31
  56. package/dist/sync/version-storage-interface.js +11 -0
  57. package/dist/sync/version-storage.js +22 -22
  58. package/package.json +2 -1
@@ -69,7 +69,7 @@ export const PLATFORM_CONCEPTS = [
69
69
  definition: "Human-in-the-Loop. An approval/verification step where a human reviews before the workflow continues.",
70
70
  aliases: ["Human Collaboration", "Approval Step", "Review Step"],
71
71
  relatedTerms: ["entity_extraction_with_documents", "send_email_agent"],
72
- commonConfusions: "HITL is ONLY supported on entity_extraction_with_documents and send_email_agent. general_hitl is NOT deployable. external_action_caller does NOT support HITL.",
72
+ commonConfusions: "Two HITL mechanisms: 1) general_hitl (Human Collaboration Agent) — standalone node with Conversational, Standard Form, and Custom Form modes. 2) Agent-level flags on entity_extraction_with_documents and send_email_agent (disable_human_interaction: false). external_action_caller does NOT support HITL.",
73
73
  },
74
74
  {
75
75
  term: "Connector",
@@ -155,7 +155,7 @@ const CURATED_OVERRIDES = [
155
155
  { sourceType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", targetType: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", compatible: false, note: "Cannot convert text to conversation" },
156
156
  { sourceType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", targetType: "WELL_KNOWN_TYPE_SEARCH_RESULT", compatible: false, note: "Text is not a search result" },
157
157
  // Search result → other types
158
- { sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", compatible: false, note: "Use respond_for_external_actions or call_llm.named_inputs" },
158
+ { sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", compatible: false, note: "Use call_llm.named_inputs, respond_with_sources.search_results, or any node accepting ANY" },
159
159
  { sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", compatible: false, note: "Search result is not a conversation" },
160
160
  // Document → other types
161
161
  { sourceType: "WELL_KNOWN_TYPE_DOCUMENT", targetType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", compatible: false, note: "Use entity_extraction or document-specific agents" },
@@ -166,359 +166,9 @@ export const TYPE_COMPATIBILITY = [
166
166
  ...CURATED_OVERRIDES,
167
167
  ];
168
168
  // ─────────────────────────────────────────────────────────────────────────────
169
- // Workflow Patterns
169
+ // Workflow Patterns — SINGLE SOURCE OF TRUTH in src/config/workflow-patterns.ts
170
170
  // ─────────────────────────────────────────────────────────────────────────────
171
- export const WORKFLOW_PATTERNS = [
172
- {
173
- name: "simple-kb-search",
174
- personaType: "chat",
175
- description: "Basic knowledge base Q&A with search and response",
176
- nodes: ["chat_trigger", "conversation_to_search_query", "search", "respond_for_external_actions"],
177
- connections: [
178
- "chat_trigger.chat_conversation → conversation_to_search_query.conversation",
179
- "conversation_to_search_query.summarized_conversation → search.query",
180
- "search.search_results → respond_for_external_actions.external_action_result",
181
- "chat_trigger.user_query → respond_for_external_actions.query",
182
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
183
- "respond_for_external_actions.response → WORKFLOW_OUTPUT",
184
- ],
185
- useCase: "FAQ bot, documentation assistant, policy lookup",
186
- antiPatterns: [
187
- "Using call_llm instead of respond_for_external_actions (loses citation and conversation awareness)",
188
- "Connecting chat_conversation directly to search.query (type mismatch — use conversation_to_search_query)",
189
- "Forgetting to upload data sources to the persona (search returns empty results)",
190
- ],
191
- },
192
- {
193
- name: "intent-routing",
194
- personaType: "chat",
195
- description: "Route conversations to different handlers based on intent classification",
196
- nodes: ["chat_trigger", "chat_categorizer", "handler_per_category", "fallback_response"],
197
- connections: [
198
- "chat_trigger.chat_conversation → chat_categorizer.conversation",
199
- "handler_1 (runIf: categorizer.category == Category1)",
200
- "handler_2 (runIf: categorizer.category == Category2)",
201
- "fallback_response (runIf: categorizer.category == Fallback)",
202
- "handler_*.response → WORKFLOW_OUTPUT",
203
- "fallback_response.response → WORKFLOW_OUTPUT",
204
- ],
205
- useCase: "Multi-purpose assistant with distinct capabilities (HR + IT + General)",
206
- antiPatterns: [
207
- "Missing Fallback category",
208
- "Categories without outgoing edges",
209
- "Not all paths leading to WORKFLOW_OUTPUT",
210
- "Only one gated respond node wired to WORKFLOW_OUTPUT while others are silently lost",
211
- "Duplicate identical call_llm nodes differing only by trigger_when — consolidate into one with category as named_input",
212
- ],
213
- },
214
- {
215
- name: "multi-source-search",
216
- personaType: "chat",
217
- description: "Combine local and web search for comprehensive answers",
218
- nodes: ["chat_trigger", "conversation_to_search_query", "search", "live_web_search", "combine_search_results", "respond_for_external_actions"],
219
- connections: [
220
- "chat_trigger.chat_conversation → conversation_to_search_query.conversation",
221
- "conversation_to_search_query.summarized_conversation → search.query",
222
- "conversation_to_search_query.summarized_conversation → live_web_search.query",
223
- "search.search_results → combine_search_results.search_results_1",
224
- "live_web_search.web_search_results → combine_search_results.search_results_2",
225
- "combine_search_results.combined_results → respond_for_external_actions.external_action_result",
226
- "chat_trigger.user_query → respond_for_external_actions.query",
227
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
228
- "respond_for_external_actions.response → WORKFLOW_OUTPUT",
229
- ],
230
- useCase: "Research assistant needing both internal docs and current web info",
231
- antiPatterns: [
232
- "Using web search as the primary/only data source (slower, less reliable, uncontrolled content)",
233
- "Not wiring combine_search_results.combined_results to response node (combined results go unused)",
234
- "Forgetting to upload internal KB documents (search returns empty, only web results used)",
235
- ],
236
- },
237
- {
238
- name: "tool-calling",
239
- personaType: "voice",
240
- description: "Voice AI that calls external tools (ServiceNow, Salesforce, CRM)",
241
- nodes: ["chat_trigger", "chat_categorizer", "external_action_caller", "call_llm"],
242
- connections: [
243
- "chat_trigger.chat_conversation → chat_categorizer.conversation",
244
- "external_action_caller (runIf: categorizer.category == <Action>)",
245
- "chat_trigger.chat_conversation → external_action_caller.conversation",
246
- "external_action_caller.tool_execution_result → call_llm.named_inputs_Tool_Result",
247
- "chat_trigger.user_query → call_llm.query",
248
- "call_llm.response_with_sources → WORKFLOW_OUTPUT",
249
- ],
250
- useCase: "IT helpdesk, customer service with ticketing, CRM operations",
251
- antiPatterns: [
252
- "Creating duplicate records on follow-up questions",
253
- "Not checking conversation history before actions",
254
- "Forgetting voice-specific widgets (conversationSettings, voiceSettings, callSettings, vadSettings)",
255
- "external_action_caller does NOT support HITL — cannot gate tool calls with human approval",
256
- ],
257
- },
258
- {
259
- name: "hitl-approval",
260
- personaType: "chat",
261
- description: "Human-in-the-loop approval — enable HITL flag on send_email_agent or entity_extraction_with_documents (only nodes that support HITL)",
262
- nodes: ["chat_trigger", "entity_extraction_with_documents", "send_email_agent", "respond_for_external_actions"],
263
- connections: [
264
- "chat_trigger.user_query → entity_extraction_with_documents.query",
265
- "chat_trigger.chat_conversation → entity_extraction_with_documents.conversation",
266
- "entity_extraction_with_documents.extraction_columns → send_email_agent (HITL flag enabled: disable_human_interaction: false)",
267
- "send_email_agent.confirmation → respond_for_external_actions.external_action_result",
268
- "chat_trigger.user_query → respond_for_external_actions.query",
269
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
270
- "respond_for_external_actions.response → WORKFLOW_OUTPUT",
271
- ],
272
- useCase: "High-value transactions, sensitive operations — enable HITL flag on send_email_agent or entity_extraction_with_documents",
273
- antiPatterns: [
274
- "Adding general_hitl as a standalone node (it is NOT deployable)",
275
- "Not wiring conversation context to response node",
276
- "Using external_action_caller for HITL — it does NOT support the HITL flag",
277
- "Only send_email_agent and entity_extraction_with_documents support HITL (disable_human_interaction: false)",
278
- ],
279
- },
280
- {
281
- name: "document-processing",
282
- personaType: "dashboard",
283
- description: "Document upload → extraction → validation → analysis (results as dashboard columns)",
284
- nodes: ["document_trigger", "entity_extraction_with_documents", "rule_validation_with_documents", "call_llm"],
285
- connections: [
286
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
287
- "entity_extraction_with_documents.extraction_columns → rule_validation_with_documents.map_of_extracted_columns",
288
- "workflowInput.document-mmf2 → rule_validation_with_documents.primary_docs",
289
- "rule_validation_with_documents.ruleset_output → call_llm.named_inputs_Validation_Results",
290
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
291
- "rule_validation_with_documents.ruleset_output → results (dot-notation: '<nodeId>.ruleset_output')",
292
- "call_llm.llm_output → results (dot-notation: '<nodeId>.llm_output')",
293
- ],
294
- useCase: "Invoice processing, contract analysis, compliance checking",
295
- antiPatterns: [
296
- "Not mapping extraction/validation outputs to results (dashboard columns won't appear)",
297
- "Missing primary_docs on rule_validation_with_documents (validator needs original documents for context)",
298
- "Using a single call_llm without passing validation results (analysis lacks validation context)",
299
- ],
300
- },
301
- {
302
- name: "dashboard-email-notification",
303
- personaType: "dashboard",
304
- description: "Document upload → extraction → email notification (with intermediary for type conversion). Production workflows often add a body generator (call_llm/custom_agent) and dual send paths (auto + HITL) with CC config.",
305
- nodes: ["document_trigger", "entity_extraction_with_documents", "json_mapper", "fixed_response", "call_llm (body generator)", "send_email_agent"],
306
- connections: [
307
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
308
- "entity_extraction_with_documents.extraction_columns → json_mapper.input_json",
309
- "json_mapper.output_json → fixed_response.named_inputs_Extracted_Data (template: '{{to}}', '{{subject}}', etc.)",
310
- "fixed_response.response → send_email_agent.email_to (one fixed_response per email field)",
311
- "entity_extraction_with_documents.extraction_columns → call_llm.named_inputs_Extracted_Data (for body generation)",
312
- "call_llm.llm_output → send_email_agent.email_body (LLM-generated body)",
313
- "send_email_agent.confirmation → results (dot-notation: '<nodeId>.confirmation')",
314
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
315
- ],
316
- useCase: "Invoice receipt notification, contract alerts, document-triggered emails, payment confirmations",
317
- antiPatterns: [
318
- "DO NOT wire entity_extraction directly to send_email — type mismatch (ANY vs TEXT_WITH_SOURCES)",
319
- "Use json_mapper + fixed_response as intermediary for type conversion",
320
- "Enable HITL flag on send_email_agent (disable_human_interaction: false) if approval needed",
321
- "For CC/BCC: extract additional recipients via entity_extraction columns, route through separate fixed_response nodes",
322
- ],
323
- },
324
- {
325
- name: "guardrails-pattern",
326
- personaType: "chat",
327
- description: "Response generation with validation guardrails",
328
- nodes: ["chat_trigger", "search", "respond_for_external_actions", "response_validator", "abstain_action"],
329
- connections: [
330
- "chat_trigger.user_query → search.query",
331
- "search.search_results → respond_for_external_actions.external_action_result",
332
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
333
- "respond_for_external_actions.response → response_validator.response_to_validate",
334
- "chat_trigger.user_query → response_validator.reference_query",
335
- "response_validator.abstain_reason → [conditional: if valid] → WORKFLOW_OUTPUT",
336
- "response_validator.abstain_reason → [conditional: if invalid] → abstain_action → WORKFLOW_OUTPUT",
337
- ],
338
- useCase: "Regulated industries, compliance-sensitive responses",
339
- antiPatterns: [
340
- "Not connecting both response and abstain paths to WORKFLOW_OUTPUT",
341
- "Using guardrails without search results (validator has nothing to check against)",
342
- "Skipping the abstain_action fallback (invalid responses return nothing to user)",
343
- ],
344
- },
345
- {
346
- name: "externalized-instructions",
347
- personaType: "chat",
348
- description: "Dynamic instructions fetched from knowledge base instead of hardcoded in node prompts. Upload instruction documents (policies, tone guides, procedures) to KB and let search retrieve them at runtime.",
349
- nodes: ["chat_trigger", "conversation_to_search_query", "search", "respond_for_external_actions"],
350
- connections: [
351
- "chat_trigger.chat_conversation → conversation_to_search_query.conversation",
352
- "conversation_to_search_query.summarized_conversation → search.query",
353
- "search.search_results → respond_for_external_actions.external_action_result (instructions + knowledge combined)",
354
- "chat_trigger.user_query → respond_for_external_actions.query",
355
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
356
- "respond_for_external_actions.response → WORKFLOW_OUTPUT",
357
- ],
358
- useCase: "When instructions change frequently, when multiple teams maintain different policies, when A/B testing response styles",
359
- antiPatterns: [
360
- "Hardcoding all instructions in node prompt (requires workflow redeploy to change behavior)",
361
- "Not connecting search results to extraction nodes that also need instructions",
362
- "Mixing instruction documents with knowledge documents without clear separation",
363
- ],
364
- },
365
- {
366
- name: "consolidated-intent-routing",
367
- personaType: "chat",
368
- description: "Single respond node handles all intents by receiving the category as a named_input. Reduces duplication vs. having separate respond nodes per intent.",
369
- nodes: ["chat_trigger", "chat_categorizer", "search", "call_llm", "fixed_response"],
370
- connections: [
371
- "chat_trigger.chat_conversation → chat_categorizer.conversation",
372
- "chat_trigger.user_query → search.query (always runs, not gated)",
373
- "chat_categorizer.category → call_llm.named_inputs_Intent",
374
- "search.search_results → call_llm.named_inputs_Search_Results",
375
- "chat_trigger.chat_conversation → call_llm.named_inputs_Conversation",
376
- "chat_trigger.user_query → call_llm.query",
377
- "call_llm.response_with_sources → WORKFLOW_OUTPUT (runIf: category != Fallback)",
378
- "fixed_response.response → WORKFLOW_OUTPUT (runIf: category == Fallback)",
379
- ],
380
- useCase: "Multi-intent assistant where all intents share similar response style, search sources, and safety constraints",
381
- antiPatterns: [
382
- "Using this when intents need different tools or actions (use separate nodes instead)",
383
- "Forgetting to pass the category as named_input (LLM won't know which intent to address)",
384
- "Not gating fallback separately (fixed_response should handle fallback, not the LLM)",
385
- ],
386
- },
387
- // ─── Composite Dashboard Patterns (from FX2 production analysis) ──────────
388
- {
389
- name: "multi-phase-validation",
390
- personaType: "dashboard",
391
- description: "Document upload → extraction → N sequential rule_validation_with_documents phases. Each phase checks a different concern (format → compliance → cross-reference) and feeds its output to the next. All phase outputs mapped to dashboard columns for per-phase visibility.",
392
- nodes: ["document_trigger", "entity_extraction_with_documents", "rule_validation_phase_1", "rule_validation_phase_2", "rule_validation_phase_3", "call_llm"],
393
- connections: [
394
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
395
- "entity_extraction_with_documents.extraction_columns → rule_validation_phase_1.map_of_extracted_columns",
396
- "workflowInput.document-mmf2 → rule_validation_phase_1.primary_docs",
397
- "rule_validation_phase_1.ruleset_output → rule_validation_phase_2.map_of_extracted_columns",
398
- "workflowInput.document-mmf2 → rule_validation_phase_2.primary_docs",
399
- "rule_validation_phase_2.ruleset_output → rule_validation_phase_3.map_of_extracted_columns",
400
- "workflowInput.document-mmf2 → rule_validation_phase_3.primary_docs",
401
- "rule_validation_phase_3.ruleset_output → call_llm.named_inputs_Final_Validation",
402
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
403
- "rule_validation_phase_1.ruleset_output → results (dot-notation: '<nodeId>.ruleset_output')",
404
- "rule_validation_phase_2.ruleset_output → results (dot-notation: '<nodeId>.ruleset_output')",
405
- "rule_validation_phase_3.ruleset_output → results (dot-notation: '<nodeId>.ruleset_output')",
406
- "call_llm.llm_output → results (dot-notation: '<nodeId>.llm_output')",
407
- ],
408
- useCase: "Invoice processing with multi-step validation (format → compliance → PO matching), regulatory document review, dunning letter compliance checks",
409
- antiPatterns: [
410
- "Running all validation rules in a single phase (loses granularity, hard to debug which phase failed)",
411
- "Not passing primary_docs to each validation phase (validator needs original documents for context)",
412
- "Forgetting to map intermediate phase outputs to results (dashboard won't show per-phase status)",
413
- ],
414
- },
415
- {
416
- name: "confidence-dual-path",
417
- personaType: "dashboard",
418
- description: "Dashboard: after extraction and validation, fork into AUTO path (send_email_agent without HITL) and ESCALATE path (send_email_agent with HITL enabled). A confidence/risk score from validation determines which path fires via runIf conditions.",
419
- nodes: ["document_trigger", "entity_extraction_with_documents", "rule_validation_with_documents", "call_llm (confidence scorer)", "send_email_auto (no HITL)", "send_email_escalate (HITL enabled)"],
420
- connections: [
421
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
422
- "entity_extraction_with_documents.extraction_columns → rule_validation_with_documents.map_of_extracted_columns",
423
- "workflowInput.document-mmf2 → rule_validation_with_documents.primary_docs",
424
- "rule_validation_with_documents.ruleset_output → call_llm.named_inputs_Validation_Results",
425
- "call_llm.llm_output → send_email_auto (runIf: validation_status == PASS)",
426
- "call_llm.llm_output → send_email_escalate (runIf: validation_status != PASS)",
427
- "send_email_auto.confirmation → results (dot-notation: '<nodeId>.confirmation')",
428
- "send_email_escalate.confirmation → results (dot-notation: '<nodeId>.confirmation')",
429
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
430
- "rule_validation_with_documents.ruleset_output → results (dot-notation: '<nodeId>.ruleset_output')",
431
- ],
432
- useCase: "AP invoice processing (clean invoices auto-process, exceptions need human review), dunning workflows (high-confidence auto-send, ambiguous escalate), contract approvals",
433
- antiPatterns: [
434
- "Using a single send_email_agent for both paths (loses ability to gate high-risk sends separately)",
435
- "Not having the ESCALATE path (all documents auto-process with no human oversight for edge cases)",
436
- "Hardcoding threshold in node config — use validation rules output to drive the routing decision",
437
- "Forgetting to use intermediary (json_mapper + fixed_response) between extraction and send_email inputs",
438
- ],
439
- },
440
- {
441
- name: "document-intake-resolution",
442
- personaType: "dashboard",
443
- description: "Dashboard: full document intake pipeline — extract entities → convert/normalize → search knowledge base for matching records → LLM resolves/reconciles against master data. The resolution chain ensures extracted entities are validated against existing records before downstream processing.",
444
- nodes: ["document_trigger", "entity_extraction_with_documents", "json_mapper", "search", "call_llm (resolver)"],
445
- connections: [
446
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
447
- "entity_extraction_with_documents.extraction_columns → json_mapper.input_json",
448
- "json_mapper.output_json → search.query (lookup extracted entity in KB)",
449
- "search.search_results → call_llm.named_inputs_Matching_Records",
450
- "entity_extraction_with_documents.extraction_columns → call_llm.named_inputs_Extracted_Data",
451
- "call_llm.llm_output → results (dot-notation: '<nodeId>.llm_output' — resolution status + matched record)",
452
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
453
- ],
454
- useCase: "Invoice vendor matching against vendor master, contract party resolution, employee onboarding verification against HR records, PO line-item matching",
455
- antiPatterns: [
456
- "Skipping the search/resolution step (extracted data goes unvalidated against master data)",
457
- "Using entity_extraction output directly as the resolved entity (extraction ≠ resolution)",
458
- "Not handling 'no match found' case in the resolver LLM (must surface unresolved items)",
459
- ],
460
- },
461
- {
462
- name: "hitl-decision-form",
463
- personaType: "dashboard",
464
- description: "Dashboard: use entity_extraction_with_documents with HITL flag as a human review/decision form — presenting processed data for human verification or correction before downstream actions. The extraction columns define the form fields the reviewer sees and can modify.",
465
- nodes: ["document_trigger", "entity_extraction_with_documents (processing)", "call_llm (prepare review)", "entity_extraction_with_documents (HITL review form)", "send_email_agent"],
466
- connections: [
467
- "workflowInput.document-mmf2 → entity_extraction_processing.documents",
468
- "entity_extraction_processing.extraction_columns → call_llm.named_inputs_Extracted_Data",
469
- "call_llm.llm_output → entity_extraction_review.named_inputs_Summary (HITL enabled)",
470
- "entity_extraction_review.extraction_columns → send_email_agent (human-verified data)",
471
- "entity_extraction_review.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
472
- ],
473
- useCase: "Invoice approval where reviewer corrects extracted amounts before payment, contract review where legal team verifies extracted terms, compliance review with sign-off",
474
- antiPatterns: [
475
- "Using general_hitl (NOT deployable) — use HITL flag on entity_extraction_with_documents",
476
- "Confusing extraction-for-processing with extraction-as-review-form (different roles, different column configs)",
477
- "Not passing processed data to the review form's named_inputs (reviewer sees empty form)",
478
- ],
479
- },
480
- {
481
- name: "document-generation-pipeline",
482
- personaType: "dashboard",
483
- description: "Dashboard: generate formatted documents from processed data — extraction → LLM drafts content → generate_document creates formatted output (PDF) → send_email_agent delivers as attachment.",
484
- nodes: ["document_trigger", "entity_extraction_with_documents", "call_llm (content drafter)", "generate_document", "send_email_agent"],
485
- connections: [
486
- "workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
487
- "entity_extraction_with_documents.extraction_columns → call_llm.named_inputs_Extracted_Data",
488
- "call_llm.llm_output → generate_document.markdown_file_contents",
489
- "generate_document.document_link → send_email_agent.named_inputs_Attachment",
490
- "send_email_agent.confirmation → results (dot-notation: '<nodeId>.confirmation')",
491
- "entity_extraction_with_documents.extraction_columns → results (dot-notation: '<nodeId>.extraction_columns')",
492
- ],
493
- useCase: "Dunning letter generation, invoice creation from PO data, compliance report generation, customer correspondence, welcome packets",
494
- antiPatterns: [
495
- "Putting the full template in call_llm instructions (use data source templates for strict regulatory formats)",
496
- "Skipping generate_document and sending raw LLM text as attachment (no formatting, no PDF)",
497
- "Not including extracted entity data in the LLM's named_inputs (generated document lacks specifics)",
498
- ],
499
- },
500
- // ─── Voice Patterns ──────────────────────────────────────────────────────
501
- {
502
- name: "voice-kb-search",
503
- personaType: "voice",
504
- description: "Voice AI with knowledge base search only — no external actions or side effects. Clean 4-node pattern for informational help desks. Requires voice-specific widgets.",
505
- nodes: ["chat_trigger", "conversation_to_search_query", "search", "respond_for_external_actions"],
506
- connections: [
507
- "chat_trigger.chat_conversation → conversation_to_search_query.conversation",
508
- "conversation_to_search_query.summarized_conversation → search.query",
509
- "search.search_results → respond_for_external_actions.external_action_result",
510
- "chat_trigger.user_query → respond_for_external_actions.query",
511
- "chat_trigger.chat_conversation → respond_for_external_actions.conversation",
512
- "respond_for_external_actions.response → WORKFLOW_OUTPUT",
513
- ],
514
- useCase: "FX rate inquiries, policy Q&A hotline, product information line, internal help desk for common questions",
515
- antiPatterns: [
516
- "Adding external_action_caller when no side effects are needed (over-engineering)",
517
- "Using call_llm instead of respond_for_external_actions (loses citation and conversation awareness)",
518
- "Forgetting voice-specific widgets (conversationSettings, voiceSettings, callSettings, vadSettings)",
519
- ],
520
- },
521
- ];
171
+ export { WORKFLOW_PATTERNS } from "../config/workflow-patterns.js";
522
172
  // ─────────────────────────────────────────────────────────────────────────────
523
173
  // Qualifying Questions
524
174
  // ─────────────────────────────────────────────────────────────────────────────
@@ -532,7 +182,7 @@ export const QUALIFYING_QUESTIONS = [
532
182
  // Round 2: Workflow Details
533
183
  { category: "Data", question: "Are the data sources static files or live APIs?", whyItMatters: "Static = search agent, Live = external_action_caller", required: false },
534
184
  { category: "Data", question: "What specific fields/entities need to be extracted from queries?", whyItMatters: "May need entity_extraction or conversation_to_search_query", required: false },
535
- { category: "Data", question: "Are there multiple data sources that need to be correlated?", whyItMatters: "Requires cross-document linking strategy and combine_search_results", required: false },
185
+ { category: "Data", question: "Are there multiple data sources that need to be correlated?", whyItMatters: "Requires cross-document linking strategy use combine_and_rerank_search_results or call_llm with multiple named_inputs", required: false },
536
186
  { category: "Actions", question: "What external tools/APIs should the AI call? (ServiceNow, Salesforce, Workday, etc.)", whyItMatters: "Configures external_action_caller tools and connectors", required: false },
537
187
  { category: "Actions", question: "What actions can the AI perform? (create ticket, send email, update record)", whyItMatters: "Lists available tools and determines action scope", required: false },
538
188
  { category: "Actions", question: "Which actions require human approval?", whyItMatters: "Enable HITL flag on the relevant agent (only entity_extraction_with_documents and send_email_agent support HITL)", required: false },
@@ -578,9 +228,9 @@ export const COMMON_MISTAKES = [
578
228
  { mistake: "Type mismatches in connections", problem: "Validation errors, runtime failures", solution: "Check type compatibility: use conversation_to_search_query when needed" },
579
229
  { mistake: "Not mapping to WORKFLOW_OUTPUT", problem: "Responses don't reach user", solution: "Ensure ALL paths terminate at WORKFLOW_OUTPUT" },
580
230
  { mistake: "Using workflow_def instead of workflow in updates", problem: "API accepts request but changes silently don't persist", solution: "Use 'workflow' field (not 'workflow_def') in updateAiEmployee(). GET returns workflow_def, UPDATE expects workflow." },
581
- { mistake: "Chat workflow without chat-aware response node", problem: "Duplicate/repetitive responses — LLM re-asks questions already answered, loses multi-turn context", solution: "Use respond_for_external_actions (for search results or tool results) instead of generic call_llm. If using call_llm, wire chat_conversation into named_inputs." },
231
+ { mistake: "Chat workflow without chat-aware response node", problem: "Duplicate/repetitive responses — LLM re-asks questions already answered, loses multi-turn context", solution: "Wire chat_conversation into the response node's named_inputs (e.g., call_llm.named_inputs_Conversation) so the LLM has multi-turn context. respond_for_external_actions is only for external_action_caller results." },
582
232
  { mistake: "Wiring entity_extraction directly to send_email inputs", problem: "Type mismatch — entity_extraction outputs ANY type, email inputs need TEXT_WITH_SOURCES. Results in corrupted email addresses or deploy errors.", solution: "Use intermediary: entity_extraction → json_mapper → fixed_response({{field}}) → send_email. Or use custom_agent with output_fields=[To,Subject,Body]." },
583
- { mistake: "Adding general_hitl as a standalone workflow node", problem: "general_hitl is NOT deployable it appears in catalogs but cannot be deployed. Deploying it will fail.", solution: "Enable the HITL flag on the agent that performs the action. Only entity_extraction_with_documents and send_email_agent support HITL (disable_human_interaction: false). external_action_caller does NOT support HITL." },
233
+ { mistake: "Adding general_hitl without understanding its modes", problem: "general_hitl (Human Collaboration Agent) is a full standalone agent with Conversational, Standard Form, and Custom Form modes not just an approval gate.", solution: "For rich human-in-the-loop: use general_hitl with appropriate mode. For simple yes/no approval on specific actions: enable the HITL flag on send_email_agent or entity_extraction_with_documents (disable_human_interaction: false)." },
584
234
  ];
585
235
  export const DEBUG_CHECKLIST = [
586
236
  { step: 1, action: "Check Status", description: "Is the AI Employee active/ready?", apiField: "status" },
@@ -1035,7 +1035,7 @@ Fetch \`ema://rules/deprecated-actions-summary\` to know which actions to AVOID.
1035
1035
 
1036
1036
  **Key deprecated actions to avoid:**
1037
1037
  - search/v0 → use search/v2 (requires datastore_configs)
1038
- - respond_with_sources → use respond_for_external_actions
1038
+ - respond_with_sources/v0 → use call_llm with named_inputs (for KB Q&A) or respond_with_sources current version
1039
1039
  - call_llm/v0 → use call_llm/v2
1040
1040
  - web_search/v0 → use live_web_search or ai_web_search
1041
1041
 
@@ -1126,7 +1126,7 @@ Fetch \`ema://rules/deprecated-actions-summary\` to know which actions to AVOID.
1126
1126
 
1127
1127
  **Key deprecated actions to avoid:**
1128
1128
  - search/v0 → use search/v2 (requires datastore_configs)
1129
- - respond_with_sources → use respond_for_external_actions
1129
+ - respond_with_sources/v0 → use call_llm with named_inputs (for KB Q&A) or respond_with_sources current version
1130
1130
  - call_llm/v0 → use call_llm/v2
1131
1131
  - web_search/v0 → use live_web_search or ai_web_search
1132
1132
 
@@ -1493,7 +1493,7 @@ document_trigger → entity_extraction/call_llm → WORKFLOW_OUTPUT
1493
1493
  **Trigger**: Use \`chat_trigger\`
1494
1494
  **Common Pattern**:
1495
1495
  \`\`\`
1496
- chat_trigger → search/v2 → respond_for_external_actions → WORKFLOW_OUTPUT
1496
+ chat_trigger → search/v2 → call_llm (via named_inputs_Search_Results) → WORKFLOW_OUTPUT
1497
1497
  \`\`\`
1498
1498
 
1499
1499
  **Key inputs from trigger**:
@@ -1873,7 +1873,7 @@ Common agents for extensions:
1873
1873
  - **entity_extraction_with_documents**: Extract structured data
1874
1874
  - **json_mapper**: Transform data structures
1875
1875
  - **live_web_search**: Real-time data
1876
- - **combine_search_results**: Merge multiple sources
1876
+ - **combine_and_rerank_search_results**: Merge and rerank multiple sources
1877
1877
  - **personalized_content_generator**: Rich content generation
1878
1878
  - **custom_agent**: Complex logic with custom prompts
1879
1879
  - **send_email_agent**: Email notifications
@@ -1968,7 +1968,7 @@ trigger → entity_extraction_with_documents → json_mapper → downstream_node
1968
1968
  trigger → [parallel]
1969
1969
  ├→ search(kb)
1970
1970
  └→ live_web_search
1971
- combine_search_resultsrespond
1971
+ combine_and_rerank_search_resultscall_llm
1972
1972
  \`\`\`
1973
1973
 
1974
1974
  ### Pattern: Add Email Notification