@ema.co/mcp-toolkit 2026.1.25 → 2026.1.26-3

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 (85) hide show
  1. package/README.md +10 -2
  2. package/dist/mcp/handlers/action/index.js +3 -18
  3. package/dist/mcp/handlers/data/index.js +385 -41
  4. package/dist/mcp/handlers/data/templates.js +107 -0
  5. package/dist/mcp/handlers/deprecation.js +50 -0
  6. package/dist/mcp/handlers/env/index.js +8 -4
  7. package/dist/mcp/handlers/knowledge/index.js +44 -237
  8. package/dist/mcp/handlers/persona/create.js +5 -11
  9. package/dist/mcp/handlers/persona/index.js +5 -1
  10. package/dist/mcp/handlers/persona/version.js +234 -0
  11. package/dist/mcp/handlers/sync/index.js +3 -18
  12. package/dist/mcp/handlers/template/index.js +75 -10
  13. package/dist/mcp/handlers/workflow/analyze.js +171 -0
  14. package/dist/mcp/handlers/workflow/compare.js +70 -0
  15. package/dist/mcp/handlers/workflow/compile.js +39 -0
  16. package/dist/mcp/handlers/workflow/deploy.js +73 -0
  17. package/dist/mcp/handlers/workflow/generate.js +350 -0
  18. package/dist/mcp/handlers/workflow/index.js +136 -0
  19. package/dist/mcp/handlers/workflow/modify.js +456 -0
  20. package/dist/mcp/handlers/workflow/optimize.js +136 -0
  21. package/dist/mcp/handlers/workflow/types.js +4 -0
  22. package/dist/mcp/handlers/workflow/utils.js +132 -0
  23. package/dist/mcp/handlers-consolidated.js +62 -2691
  24. package/dist/mcp/prompts.js +13 -14
  25. package/dist/mcp/resources.js +55 -54
  26. package/dist/mcp/server.js +93 -124
  27. package/dist/mcp/{tools-v2.js → tools.js} +1 -1
  28. package/dist/mcp/workflow-operations.js +2 -2
  29. package/dist/sdk/client-adapter.js +267 -32
  30. package/dist/sdk/client.js +31 -15
  31. package/dist/sdk/ema-client.js +183 -0
  32. package/dist/sdk/generated/template-fallbacks.js +123 -0
  33. package/dist/sdk/guidance.js +65 -11
  34. package/dist/sdk/index.js +3 -1
  35. package/dist/sdk/knowledge.js +16 -86
  36. package/dist/sdk/workflow-intent.js +27 -0
  37. package/dist/sdk/workflow-transformer.js +0 -342
  38. package/docs/DEBUG-ANALYSIS-unused-category-type-mismatch.md +481 -0
  39. package/docs/TODO-fix-analyzer-and-modify.md +182 -0
  40. package/package.json +9 -4
  41. package/dist/mcp/tools-consolidated.js +0 -875
  42. package/dist/mcp/tools-legacy.js +0 -736
  43. package/docs/CODEBASE-ANALYSIS-2026-01-23.md +0 -936
  44. package/docs/CODEBASE-ANALYSIS-PRIORITIZED.md +0 -774
  45. package/docs/api-contracts.md +0 -216
  46. package/docs/auto-builder-analysis.md +0 -271
  47. package/docs/blog/mcp-tool-design-lessons.md +0 -309
  48. package/docs/data-architecture.md +0 -166
  49. package/docs/demos/ap-invoice-generation.md +0 -347
  50. package/docs/demos/ap-invoice-processing.md +0 -271
  51. package/docs/ema-auto-builder-guide.html +0 -394
  52. package/docs/lessons-learned.md +0 -209
  53. package/docs/llm-native-workflow-design.md +0 -252
  54. package/docs/local-generation.md +0 -508
  55. package/docs/mcp-flow-diagram.md +0 -135
  56. package/docs/migration/action-composition-migration.md +0 -270
  57. package/docs/naming-conventions.md +0 -278
  58. package/docs/proposals/HANDOFF-tool-restructure.md +0 -526
  59. package/docs/proposals/action-composition.md +0 -490
  60. package/docs/proposals/explicit-method-restructure.md +0 -328
  61. package/docs/proposals/mcp-tool-restructure-2026-01.md +0 -366
  62. package/docs/proposals/self-contained-guidance.md +0 -427
  63. package/docs/proto-sdk-generation.md +0 -242
  64. package/docs/release-impact.md +0 -102
  65. package/docs/release-process.md +0 -157
  66. package/docs/staging.RULE.md +0 -142
  67. package/docs/test-persona-creation.md +0 -196
  68. package/docs/tool-consolidation-v2.md +0 -225
  69. package/docs/tool-response-standards.md +0 -256
  70. package/resources/demo-kits/README.md +0 -175
  71. package/resources/demo-kits/finance-ap/manifest.json +0 -150
  72. package/resources/demo-kits/tags.json +0 -91
  73. package/resources/docs/getting-started.md +0 -97
  74. package/resources/templates/auto-builder-rules.md +0 -224
  75. package/resources/templates/chat-ai/README.md +0 -119
  76. package/resources/templates/chat-ai/persona-config.json +0 -111
  77. package/resources/templates/dashboard-ai/README.md +0 -156
  78. package/resources/templates/dashboard-ai/persona-config.json +0 -180
  79. package/resources/templates/demo-scenarios/README.md +0 -63
  80. package/resources/templates/demo-scenarios/test-published-package.md +0 -116
  81. package/resources/templates/document-gen-ai/README.md +0 -132
  82. package/resources/templates/document-gen-ai/persona-config.json +0 -316
  83. package/resources/templates/voice-ai/README.md +0 -123
  84. package/resources/templates/voice-ai/persona-config.json +0 -74
  85. package/resources/templates/voice-ai/workflow-prompt.md +0 -121
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Auto-generated fallback templates from proto definitions.
3
+ *
4
+ * These are used ONLY when the API is unavailable.
5
+ * The API templates (getPersonaTemplates()) are the source of truth.
6
+ *
7
+ * Generated at: 2026-01-25T21:51:05.018Z
8
+ *
9
+ * DO NOT EDIT MANUALLY - regenerate with: npm run generate:templates
10
+ */
11
+ /* eslint-disable @typescript-eslint/no-explicit-any */
12
+ /**
13
+ * Voice AI persona config template (fallback).
14
+ *
15
+ * Fields derived from proto definitions:
16
+ * - VoicebotConversationSettingsWidget
17
+ * - VoicebotVoiceSettingsWidget
18
+ * - VoicebotCallSettingsWidget
19
+ * - VoicebotVADSettingsWidget
20
+ * - VoicebotDataStorageSettingsWidget
21
+ */
22
+ export const VOICE_TEMPLATE_FALLBACK = {
23
+ "conversationSettings": {
24
+ "name": "{AI Name}",
25
+ "welcomeMessage": "Hello, thank you for calling {Company}. This is {AI Name}. How can I help you today?",
26
+ "speechCharacteristics": "Keep tone friendly and concise. Use brief pauses between sentences.",
27
+ "identityAndPurpose": "You are {AI Name}, an AI assistant for {Company}. Your responsibilities: 1) {Task 1} 2) {Task 2}",
28
+ "hangupInstructions": "End the call when: The caller explicitly says goodbye, or confirms they have no more questions.",
29
+ "takeActionInstructions": "</Case 1>\\n{Action Name}\\n\\nTrigger When: {Condition}\\n\\nIntent for tool call: \"{Intent}\"\\n\\nRequired parameters: { \"{param}\": \"\" }\\n</Case 1>",
30
+ "systemPrompt": "Tool Calling Instructions: Always collect required parameters before calling tools. Confirm with caller before executing.",
31
+ "waitMessage": "One moment while I look that up for you...",
32
+ "formFillingInstructions": "When collecting information, ask one question at a time. Confirm values before proceeding.",
33
+ "transferCallInstructions": "Transfer when: The caller explicitly requests a human agent, or the issue is beyond AI capabilities."
34
+ },
35
+ "voiceSettings": {
36
+ "languageHints": [
37
+ "en-US"
38
+ ],
39
+ "voiceModel": "default"
40
+ },
41
+ "callSettings": {
42
+ "enableCallForwarding": false,
43
+ "callForwardingNumber": "",
44
+ "enableSpamCallPrevention": true,
45
+ "enableDisconnectCall": false
46
+ },
47
+ "vadSettings": {
48
+ "turnTimeout": 3,
49
+ "silenceEndCallTimeout": 30,
50
+ "maxConversationDuration": 600
51
+ },
52
+ "dataStorageSettings": {
53
+ "storeAudioRecording": true,
54
+ "storeTranscripts": true,
55
+ "storeAgentTranscript": true
56
+ }
57
+ };
58
+ /**
59
+ * Field documentation for LLM consumption.
60
+ * Use this when generating prompts about config structure.
61
+ */
62
+ export const VOICE_TEMPLATE_FIELD_DOCS = `
63
+ ## Voice AI Persona Configuration Fields
64
+
65
+ ### Conversation Settings
66
+ - name: Name for the Voicebot Agent that will be spoken
67
+ - welcomeMessage: Message spoken when call connects
68
+ - speechCharacteristics: Instructions on how voicebot should speak
69
+ - identityAndPurpose: What the voicebot is for and tools it has access to
70
+ - hangupInstructions: When to end the call
71
+ - takeActionInstructions: Instructions on what actions takeAction can perform
72
+ - systemPrompt: Instructions on how to respond to user, handle tools
73
+ - waitMessage: Message when tool is taking time to execute
74
+ - formFillingInstructions: How to collect form data conversationally
75
+ - transferCallInstructions: When to transfer to human agent
76
+
77
+ ### Voice Settings
78
+ - languageHints: BCP47 language codes for speech recognition
79
+ - voiceModel: Voice model ID
80
+
81
+ ### Call Settings
82
+ - enableCallForwarding: Enable call forwarding
83
+ - callForwardingNumber: Number to forward calls to
84
+ - enableSpamCallPrevention: Enable spam call prevention
85
+ - enableDisconnectCall: Enable disconnect call
86
+
87
+ ### VAD Settings
88
+ - turnTimeout: Seconds to wait for caller to finish speaking
89
+ - silenceEndCallTimeout: Seconds of silence before ending call
90
+ - maxConversationDuration: Maximum call length in seconds
91
+
92
+ ### Data Storage Settings
93
+ - storeAudioRecording: Store audio recordings
94
+ - storeTranscripts: Store call transcripts
95
+ - storeAgentTranscript: Store agent transcript
96
+ `;
97
+ /**
98
+ * Get template fallback by type.
99
+ * Returns undefined if type is not supported.
100
+ */
101
+ export function getTemplateFallback(type) {
102
+ switch (type) {
103
+ case "voice":
104
+ return { ...VOICE_TEMPLATE_FALLBACK };
105
+ case "chat":
106
+ // TODO: Generate from chat proto definitions
107
+ return undefined;
108
+ case "dashboard":
109
+ // TODO: Generate from dashboard proto definitions
110
+ return undefined;
111
+ }
112
+ }
113
+ /**
114
+ * Get field documentation by type.
115
+ */
116
+ export function getTemplateFieldDocs(type) {
117
+ switch (type) {
118
+ case "voice":
119
+ return VOICE_TEMPLATE_FIELD_DOCS;
120
+ default:
121
+ return undefined;
122
+ }
123
+ }
@@ -82,8 +82,10 @@ await persona({ id: "abc", update: { workflow_spec: spec } }); // Then deploy`,
82
82
  do: "For content changes: 1) Get workflow with persona(include_workflow=true), " +
83
83
  "2) Edit the node's stringValue in the JSON, 3) Deploy with workflow(mode='deploy', workflow_def={...})",
84
84
  dont: "Use workflow(mode='modify') for content changes - it will silently return 0 changes.",
85
- example: `// STRUCTURAL change (supported)
86
- workflow({ mode: "modify", persona_id: "abc", input: "Add HITL before email" })
85
+ example: `// STRUCTURAL change (supported via structured operations)
86
+ persona({ mode: "modify", id: "abc", operations: [
87
+ { type: "insert", insert: { action_type: "hitl", insert_before: "send_email" }}
88
+ ]})
87
89
 
88
90
  // CONTENT change (requires manual edit)
89
91
  const p = await persona({ id: "abc", include_workflow: true });
@@ -92,8 +94,42 @@ const wf = p.workflow_def;
92
94
  wf.actions[2].inputs.data.stringValue = JSON.stringify(newData);
93
95
  await workflow({ mode: "deploy", persona_id: "abc", workflow_def: wf });`,
94
96
  antiExample: `// This will silently fail - content change via modify
95
- workflow({ mode: "modify", persona_id: "abc", input: "Change customer data to commission data" })`,
96
- related: ["workflow-spec-not-def"],
97
+ persona({ mode: "modify", id: "abc", operations: [...] }) // for content changes`,
98
+ related: ["workflow-spec-not-def", "llm-driven-modifications"],
99
+ },
100
+ {
101
+ id: "llm-driven-modifications",
102
+ level: "critical",
103
+ category: "workflow",
104
+ title: "LLM-Driven Workflow Modifications",
105
+ applies: "When modifying workflows structurally",
106
+ description: "The MCP does NOT parse natural language for modifications. YOU (the Agent/LLM) must build structured operations. " +
107
+ "Call persona(mode='modify') first to get workflow context, then build operations array.",
108
+ do: "1) Get context: persona(mode='modify', id='...') returns current_nodes, available_actions, example_operations. " +
109
+ "2) Build structured operations array. 3) Execute: persona(mode='modify', id='...', operations=[...])",
110
+ dont: "Pass natural language strings expecting MCP to parse them into operations.",
111
+ example: `// Step 1: Get context (returns current_nodes, available_actions, examples)
112
+ const ctx = await persona({ mode: "modify", id: "abc" });
113
+
114
+ // Step 2: YOU build structured operations based on user intent
115
+ const operations = [
116
+ {
117
+ type: "insert",
118
+ insert: {
119
+ action_type: "hitl",
120
+ display_name: "Email Approval",
121
+ insert_before: "send_email_node",
122
+ add_runif_to_downstream: true
123
+ }
124
+ }
125
+ ];
126
+
127
+ // Step 3: Execute
128
+ await persona({ mode: "modify", id: "abc", operations });`,
129
+ antiExample: `// DON'T: Pass natural language expecting MCP to understand it
130
+ await persona({ mode: "modify", id: "abc", input: "add approval before email" })
131
+ // The MCP will NOT parse this - it returns context instead`,
132
+ related: ["workflow-modification-scope", "analyze-before-modify"],
97
133
  },
98
134
  // ─────────────────────────────────────────────────────────────────────────
99
135
  // Important: Should Follow
@@ -162,7 +198,7 @@ const details = await persona({ id: list.personas[0].id });`,
162
198
  example: `// Useful resources:
163
199
  // ema://catalog/agents-summary - Action catalog
164
200
  // ema://rules/anti-patterns - Common mistakes
165
- // ema://templates/voice-ai/config - Voice AI template
201
+ // ema://catalog/persona-templates - Live API templates
166
202
  // ema://docs/usage-guide - Comprehensive guide`,
167
203
  },
168
204
  // ─────────────────────────────────────────────────────────────────────────
@@ -186,7 +222,7 @@ persona({ id: "abc", env: "prod" }) // production`,
186
222
  export const TOOL_GUIDANCE = {
187
223
  persona: {
188
224
  toolName: "persona",
189
- quickTip: "Use analyze=true before modifying. Use preview=true before deploying.",
225
+ quickTip: "Use analyze=true before modifying. Use preview=true before deploying. Build structured operations for modify.",
190
226
  operations: [
191
227
  {
192
228
  name: "List all",
@@ -204,9 +240,14 @@ export const TOOL_GUIDANCE = {
204
240
  example: 'persona(id="abc", analyze=true)',
205
241
  },
206
242
  {
207
- name: "Update",
208
- description: "Modify workflow using workflow_spec",
209
- example: 'persona(id="abc", update={workflow_spec: {...}})',
243
+ name: "Get modify context",
244
+ description: "Get current_nodes, available_actions for building operations",
245
+ example: 'persona(mode="modify", id="abc")',
246
+ },
247
+ {
248
+ name: "Execute modify",
249
+ description: "Apply structured operations (insert/remove/rewire)",
250
+ example: 'persona(mode="modify", id="abc", operations=[...])',
210
251
  },
211
252
  {
212
253
  name: "Create",
@@ -218,11 +259,13 @@ export const TOOL_GUIDANCE = {
218
259
  list: "Get details: persona(id='<id>')",
219
260
  get: "Analyze: persona(id='...', analyze=true)",
220
261
  analyze: "Review issues, build workflow_spec, then update",
221
- update: "Verify: persona(id='...') to confirm changes",
262
+ modify_context: "Build operations array, then execute with operations=[...]",
263
+ modify_execute: "Verify: persona(id='...') to confirm changes",
222
264
  create: "Configure: persona(id='<new_id>', update={...})",
223
265
  },
224
266
  commonMistakes: [
225
- "Modifying without analyzing first",
267
+ "Passing natural language to modify mode (MCP doesn't parse NL)",
268
+ "Modifying without getting context first",
226
269
  "Deploying without preview",
227
270
  "Using raw workflow_def instead of workflow_spec",
228
271
  "Forgetting Fallback in categorizers",
@@ -231,6 +274,7 @@ export const TOOL_GUIDANCE = {
231
274
  "analyze-before-modify",
232
275
  "preview-before-deploy",
233
276
  "workflow-spec-not-def",
277
+ "llm-driven-modifications",
234
278
  ],
235
279
  },
236
280
  catalog: {
@@ -361,6 +405,16 @@ ${critical.map((r) => `- **${r.title}**: ${r.do}`).join("\n")}
361
405
  ## Important
362
406
  ${important.map((r) => `- **${r.title}**: ${r.do}`).join("\n")}
363
407
 
408
+ ## LLM-Driven Architecture (CRITICAL)
409
+ The MCP does NOT parse natural language for workflow modifications.
410
+ **YOU (the Agent) must build structured operations:**
411
+
412
+ 1. Get context: \`persona(mode="modify", id="...")\` → returns current_nodes, available_actions
413
+ 2. Build operations array based on user intent
414
+ 3. Execute: \`persona(mode="modify", id="...", operations=[...])\`
415
+
416
+ Example operations: insert, remove, rewire, update_config
417
+
364
418
  ## Resources
365
419
  - \`ema://docs/usage-guide\` - Complete guide
366
420
  - \`ema://catalog/agents-summary\` - Action catalog
package/dist/sdk/index.js CHANGED
@@ -22,7 +22,9 @@ export { StateStore } from "./state.js";
22
22
  // Auto Builder Knowledge Base
23
23
  export {
24
24
  // Catalogs & References
25
- AGENT_CATALOG, WIDGET_CATALOG, WORKFLOW_PATTERNS, QUALIFYING_QUESTIONS, PLATFORM_CONCEPTS, WORKFLOW_EXECUTION_MODEL, COMMON_MISTAKES, DEBUG_CHECKLIST, GUIDANCE_TOPICS, VOICE_PERSONA_TEMPLATE, PROJECT_TYPES,
25
+ AGENT_CATALOG, WIDGET_CATALOG, WORKFLOW_PATTERNS, QUALIFYING_QUESTIONS, PLATFORM_CONCEPTS, WORKFLOW_EXECUTION_MODEL, COMMON_MISTAKES, DEBUG_CHECKLIST, GUIDANCE_TOPICS,
26
+ // VOICE_PERSONA_TEMPLATE removed - use getTemplateFallback("voice") from generated/template-fallbacks.ts
27
+ PROJECT_TYPES,
26
28
  // Helper Functions
27
29
  getAgentsByCategory, getAgentByName, getWidgetsForPersonaType, checkTypeCompatibility, getQualifyingQuestionsByCategory, getRequiredQualifyingQuestions, getConceptByTerm, suggestAgentsForUseCase, validateWorkflowPrompt,
28
30
  // Workflow Analysis Functions
@@ -920,90 +920,15 @@ export const QUALIFYING_QUESTIONS = [
920
920
  { category: "Guardrails", question: "Are there compliance requirements? (regulations, policies)", whyItMatters: "May need response_validator or compliance_document_analyzer", required: false },
921
921
  ];
922
922
  // ─────────────────────────────────────────────────────────────────────────────
923
- // Voice AI Templates
923
+ // Voice AI Templates - REMOVED
924
+ // ─────────────────────────────────────────────────────────────────────────────
925
+ // VOICE_PERSONA_TEMPLATE has been removed.
926
+ // Use the API-first approach instead:
927
+ // 1. client.getPersonaTemplates() - source of truth from API
928
+ // 2. getTemplateFallback("voice") from src/sdk/generated/template-fallbacks.ts
929
+ //
930
+ // See: scripts/generate-templates.ts for how fallbacks are generated from protos.
924
931
  // ─────────────────────────────────────────────────────────────────────────────
925
- export const VOICE_PERSONA_TEMPLATE = {
926
- welcomeMessage: "Hello, thank you for calling {Company}. This is {AI Name}. How can I help you today?",
927
- identityAndPurpose: `You are {AI Name}, a Voice AI assistant for {Company}.
928
-
929
- Primary responsibility: {Main purpose}
930
-
931
- Your responsibilities:
932
- 1. {Responsibility 1}
933
- 2. {Responsibility 2}
934
- 3. {Responsibility 3}
935
-
936
- Rules:
937
- - {Rule 1}
938
- - {Rule 2}
939
- - Always be professional and helpful
940
- - Never provide information you're not certain about`,
941
- takeActionInstructions: `</Case 1>
942
- {Action 1 Name}
943
-
944
- Trigger When:
945
- {Condition that triggers this action}
946
-
947
- Intent for tool call: "{Tool Intent Name}"
948
-
949
- Required parameters:
950
- { "{param1}": "", "{param2}": "" }
951
- </Case 1>
952
-
953
- </Case 2>
954
- {Action 2 Name}
955
-
956
- Trigger When:
957
- {Condition that triggers this action}
958
-
959
- Intent for tool call: "{Tool Intent Name}"
960
-
961
- Required parameters:
962
- { "{param1}": "" }
963
- </Case 2>`,
964
- hangupInstructions: `End the call when:
965
- - The caller explicitly says goodbye or asks to hang up
966
- - The caller confirms they have no more questions
967
- - {Additional hangup conditions}
968
-
969
- Before ending:
970
- - Confirm all issues are resolved
971
- - Offer any follow-up information
972
- - Thank the caller`,
973
- transferCallInstructions: `Transfer the call when:
974
- - The caller explicitly requests a human agent
975
- - The issue is beyond AI capabilities
976
- - {Complex scenario requiring human}
977
-
978
- Before transferring:
979
- - Inform the caller you're transferring them
980
- - Summarize the issue for the human agent`,
981
- speechCharacteristics: `**Conversational Style:**
982
- - Keep responses brief (2-3 sentences per turn)
983
- - Use warm, professional tone
984
- - Speak clearly at moderate pace
985
-
986
- **Natural Speech:**
987
- - Use brief pauses between sentences
988
- - Acknowledge with 'I understand', 'Of course', 'Certainly'
989
- - Avoid robotic language
990
-
991
- **TTS Pronunciation Rules:**
992
- - Spell out IDs: 'A-B-C-1-2-3'
993
- - Pause between numbers: 'Your code is... 1... 2... 3... 4'
994
- - {Domain-specific pronunciation rules}`,
995
- systemPrompt: `Tool Calling Instructions:
996
-
997
- 1. Always collect ALL required parameters before calling a tool
998
- 2. Confirm parameter values with the caller before executing
999
- 3. Wait for tool response before calling another tool
1000
- 4. NEVER mention tool names to the user
1001
- 5. NEVER guess parameter values - always ask
1002
- 6. Use plain language: "Let me look that up" not "Calling the API"
1003
- 7. Handle delays with wait message: "One moment while I check..."
1004
- 8. Handle errors gracefully, offer alternatives`,
1005
- waitMessage: "One moment while I look that up for you...",
1006
- };
1007
932
  // ─────────────────────────────────────────────────────────────────────────────
1008
933
  // Common Mistakes & Debugging
1009
934
  // ─────────────────────────────────────────────────────────────────────────────
@@ -2592,13 +2517,18 @@ function detectUnusedCategories(nodes, workflowDef) {
2592
2517
  const categorizers = nodes.filter(n => n.action_name === "chat_categorizer" ||
2593
2518
  n.action_name === "intent_classifier");
2594
2519
  for (const categorizer of categorizers) {
2595
- // Find the enumType for this categorizer
2596
- const enumTypeName = categorizer.id + "_enumType";
2520
+ // Find the enumType for this categorizer using typeArguments reference (robust)
2521
+ // The action's typeArguments.categories.enumType points to the correct enumType
2522
+ const categorizerAction = actions.find(a => a.name === categorizer.id);
2523
+ const typeArgs = categorizerAction?.typeArguments;
2524
+ const enumTypeRefName = typeArgs?.categories?.enumType?.name?.name;
2597
2525
  const enumType = enumTypes.find(e => {
2598
2526
  const name = e.name;
2599
2527
  const innerName = name?.name;
2600
2528
  const nameStr = String(innerName?.name ?? name?.name ?? "");
2601
- return nameStr.includes(categorizer.id) || nameStr.includes("enumType");
2529
+ // Match by typeArguments reference (preferred) or by categorizer ID (fallback)
2530
+ // DO NOT use generic "enumType" fallback - that causes cross-categorizer pollution
2531
+ return (enumTypeRefName && nameStr === enumTypeRefName) || nameStr.includes(categorizer.id);
2602
2532
  });
2603
2533
  if (!enumType)
2604
2534
  continue;
@@ -528,7 +528,25 @@ const PERSONA_TYPE_PATTERNS = [
528
528
  { pattern: /voice|call|phone/i, type: "voice" },
529
529
  { pattern: /document|batch|upload/i, type: "dashboard" },
530
530
  ];
531
+ /**
532
+ * @deprecated Use LLM-based intent extraction instead of regex parsing.
533
+ *
534
+ * This function uses regex patterns to parse natural language, which is an
535
+ * anti-pattern. The LLM (Agent) should understand user intent naturally
536
+ * and provide structured data directly.
537
+ *
538
+ * For greenfield workflow generation, consider using:
539
+ * - Intent Architect for complex requirements analysis
540
+ * - Direct structured input (WorkflowSpec) from the Agent
541
+ *
542
+ * This function is retained for backward compatibility but should not be
543
+ * used in new code paths.
544
+ *
545
+ * @see src/mcp/AGENTS.md for the LLM-driven architecture guidelines
546
+ */
531
547
  export function parseNaturalLanguage(text) {
548
+ console.warn("[DEPRECATED] parseNaturalLanguage() uses regex parsing which is an anti-pattern. " +
549
+ "Consider using LLM-based intent extraction or structured input instead.");
532
550
  // Detect persona type (default: chat)
533
551
  let personaType = "chat";
534
552
  for (const { pattern, type } of PERSONA_TYPE_PATTERNS) {
@@ -1457,11 +1475,20 @@ export function intentToSpec(intent) {
1457
1475
  ...(intent.persona_type === "chat" && { chatConfig: { name: intent.name } }),
1458
1476
  };
1459
1477
  }
1478
+ /**
1479
+ * Parse input and extract workflow intent.
1480
+ *
1481
+ * Note: The "natural_language" path uses deprecated regex-based parsing.
1482
+ * For new code, prefer providing structured input (partial_spec or full_spec)
1483
+ * directly from the Agent, which understands user intent naturally.
1484
+ */
1460
1485
  export function parseInput(input) {
1461
1486
  const inputType = detectInputType(input);
1462
1487
  let intent;
1463
1488
  switch (inputType) {
1464
1489
  case "natural_language":
1490
+ // DEPRECATED: This path uses regex-based parsing.
1491
+ // Prefer structured input from the Agent instead.
1465
1492
  intent = parseNaturalLanguage(String(input));
1466
1493
  break;
1467
1494
  case "partial_spec":