@ema.co/mcp-toolkit 2026.1.26 → 2026.1.27-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.
- package/dist/mcp/handlers/action/index.js +17 -20
- package/dist/mcp/handlers/data/index.js +75 -6
- package/dist/mcp/handlers/deprecation.js +50 -0
- package/dist/mcp/handlers/env/index.js +3 -3
- package/dist/mcp/handlers/knowledge/index.js +44 -237
- package/dist/mcp/handlers/persona/create.js +63 -18
- package/dist/mcp/handlers/persona/index.js +9 -10
- package/dist/mcp/handlers/persona/update.js +6 -3
- package/dist/mcp/handlers/reference/index.js +15 -2
- package/dist/mcp/handlers/sync/index.js +3 -18
- package/dist/mcp/handlers/workflow/analyze.js +53 -105
- package/dist/mcp/handlers/workflow/deploy.js +160 -1
- package/dist/mcp/handlers/workflow/generate.js +8 -28
- package/dist/mcp/handlers/workflow/index.js +258 -85
- package/dist/mcp/handlers/workflow/modify.js +69 -26
- package/dist/mcp/handlers/workflow/optimize.js +22 -108
- package/dist/mcp/handlers/workflow/utils.js +0 -102
- package/dist/mcp/handlers-consolidated.js +15 -38
- package/dist/mcp/prompts.js +82 -44
- package/dist/mcp/resources.js +335 -3
- package/dist/mcp/server.js +242 -457
- package/dist/mcp/tools.js +44 -61
- package/dist/sdk/action-schema-parser.js +11 -5
- package/dist/sdk/client.js +81 -25
- package/dist/sdk/ema-client.js +11 -0
- package/dist/sdk/generated/deprecated-actions.js +171 -0
- package/dist/sdk/guidance.js +58 -35
- package/dist/sdk/index.js +8 -7
- package/dist/sdk/knowledge.js +216 -1932
- package/dist/sdk/quality-gates.js +60 -336
- package/dist/sdk/validation-rules.js +33 -0
- package/dist/sdk/workflow-fixer.js +29 -360
- package/dist/sdk/workflow-generator.js +2 -1
- package/dist/sdk/workflow-intent.js +43 -3
- package/dist/sdk/workflow-transformer.js +0 -342
- package/docs/dashboard-operations.md +35 -0
- package/docs/ema-user-guide.md +66 -0
- package/docs/mcp-tools-guide.md +74 -45
- package/package.json +2 -2
- package/dist/mcp/handlers/persona/analyze.js +0 -275
- package/dist/mcp/handlers/persona/compare.js +0 -32
- package/dist/mcp/handlers/workflow/compile.js +0 -39
- package/docs/DEBUG-ANALYSIS-unused-category-type-mismatch.md +0 -481
- package/docs/TODO-fix-analyzer-and-modify.md +0 -182
- package/resources/action-schema.json +0 -5678
package/dist/mcp/prompts.js
CHANGED
|
@@ -28,12 +28,12 @@ const PROMPTS = {
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
name: "context",
|
|
31
|
-
description: "Context type: 'greenfield' (new workflow), 'brownfield' (extend existing)
|
|
31
|
+
description: "Context type: 'greenfield' (new workflow), 'brownfield' (extend existing)",
|
|
32
32
|
required: false,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
name: "persona_id",
|
|
36
|
-
description: "Existing persona ID if brownfield
|
|
36
|
+
description: "Existing persona ID if brownfield context",
|
|
37
37
|
required: false,
|
|
38
38
|
},
|
|
39
39
|
],
|
|
@@ -53,10 +53,12 @@ ${args.persona_id ? `**Existing Persona**: ${args.persona_id}` : ""}
|
|
|
53
53
|
|
|
54
54
|
### Step 1: Parse the Request
|
|
55
55
|
Identify what the user is asking for:
|
|
56
|
-
- **Action Type**: Create new / Extend existing
|
|
56
|
+
- **Action Type**: Create new / Extend existing
|
|
57
57
|
- **Scope**: Single intent / Multi-intent / Full workflow
|
|
58
58
|
- **Specificity**: Vague / Partially specified / Detailed
|
|
59
59
|
|
|
60
|
+
Note: For analysis/optimization, use \`workflow(mode="get")\` then analyze with \`ema://rules/*\` resources.
|
|
61
|
+
|
|
60
62
|
### Step 2: Check for Required Information
|
|
61
63
|
|
|
62
64
|
#### For ALL requests, verify:
|
|
@@ -92,13 +94,6 @@ For external side-effect actions (send_email, create_ticket, update_record):
|
|
|
92
94
|
| **Data Dependencies** | ✓/✗ | What existing data to use? |
|
|
93
95
|
| **Impact Assessment** | ✓/✗ | What might break? |
|
|
94
96
|
|
|
95
|
-
#### For OPTIMIZE:
|
|
96
|
-
| Dimension | Status | Missing Info |
|
|
97
|
-
|-----------|--------|--------------|
|
|
98
|
-
| **Problem Areas** | ✓/✗ | What's not working? |
|
|
99
|
-
| **Performance Goals** | ✓/✗ | Speed, accuracy, cost? |
|
|
100
|
-
| **Constraints** | ✓/✗ | What can't change? |
|
|
101
|
-
|
|
102
97
|
### Step 3: Identify Ambiguities
|
|
103
98
|
|
|
104
99
|
Look for:
|
|
@@ -159,7 +154,7 @@ Based on analysis, output ONE of:
|
|
|
159
154
|
"confidence": "high|medium",
|
|
160
155
|
"summary": "Brief summary of understood requirements",
|
|
161
156
|
"inferred_defaults": ["List any assumptions made"],
|
|
162
|
-
"next_action": "workflow(mode='
|
|
157
|
+
"next_action": "workflow(mode='get'|'deploy', ...)"
|
|
163
158
|
}
|
|
164
159
|
\`\`\`
|
|
165
160
|
|
|
@@ -338,15 +333,19 @@ Environment: ${args.env || "demo"}
|
|
|
338
333
|
|
|
339
334
|
Follow this review workflow using the consolidated tools:
|
|
340
335
|
|
|
341
|
-
### Step 1: Fetch
|
|
342
|
-
Call \`
|
|
336
|
+
### Step 1: Fetch Workflow Data
|
|
337
|
+
Call \`workflow(mode="get", persona_id="${args.persona_id}", env="${args.env || "demo"}")\` to get the workflow_def, schema, and examples.
|
|
343
338
|
|
|
344
|
-
### Step 2: Analyze (
|
|
345
|
-
|
|
339
|
+
### Step 2: Analyze (YOU do this)
|
|
340
|
+
Review the workflow_def for:
|
|
341
|
+
- Missing WORKFLOW_OUTPUT (required for activation)
|
|
342
|
+
- Missing Fallback category in categorizers
|
|
343
|
+
- Type mismatches between connected nodes
|
|
344
|
+
- Orphan nodes not connected to output
|
|
346
345
|
|
|
347
|
-
### Step 3:
|
|
348
|
-
If issues are found
|
|
349
|
-
Call \`workflow(mode="
|
|
346
|
+
### Step 3: Propose Fixes
|
|
347
|
+
If issues are found, generate a corrected workflow_def and deploy:
|
|
348
|
+
Call \`workflow(mode="deploy", persona_id="${args.persona_id}", workflow_def={...}, env="${args.env || "demo"}")\`.
|
|
350
349
|
|
|
351
350
|
## Output Format
|
|
352
351
|
|
|
@@ -456,9 +455,9 @@ ${args.symptoms.toLowerCase().includes("hitl") || args.symptoms.toLowerCase().in
|
|
|
456
455
|
` : ""}
|
|
457
456
|
${args.symptoms.toLowerCase().includes("type") || args.symptoms.toLowerCase().includes("mismatch") ? `
|
|
458
457
|
**Type Compatibility Issues:**
|
|
459
|
-
- Call \`workflow(mode="
|
|
458
|
+
- Call \`workflow(mode="get", persona_id="${args.persona_id}", env="${args.env || "demo"}")\` and analyze the workflow_def
|
|
459
|
+
- Check wellKnownType compatibility between connected nodes
|
|
460
460
|
- Common issues: chat_conversation → search (should be user_query)
|
|
461
|
-
- Check wellKnownType compatibility
|
|
462
461
|
` : ""}
|
|
463
462
|
${args.symptoms.toLowerCase().includes("loop") || args.symptoms.toLowerCase().includes("infinite") || args.symptoms.toLowerCase().includes("hang") ? `
|
|
464
463
|
**Loop/Hang Issues:**
|
|
@@ -467,8 +466,8 @@ ${args.symptoms.toLowerCase().includes("loop") || args.symptoms.toLowerCase().in
|
|
|
467
466
|
- Verify workflow has proper termination paths
|
|
468
467
|
` : ""}
|
|
469
468
|
|
|
470
|
-
### Step 4:
|
|
471
|
-
Call \`workflow(mode="
|
|
469
|
+
### Step 4: Review Workflow
|
|
470
|
+
Call \`workflow(mode="get", persona_id="${args.persona_id}", env="${args.env || "demo"}")\` and analyze the workflow_def for issues.
|
|
472
471
|
|
|
473
472
|
### Step 5: Propose Fix
|
|
474
473
|
Based on findings, provide specific fix with before/after configuration.
|
|
@@ -642,13 +641,15 @@ Call in parallel:
|
|
|
642
641
|
- \`persona(id="${args.persona_id_1}", include_workflow=true, env="${args.env_1 || "demo"}")\`
|
|
643
642
|
- \`persona(id="${args.persona_id_2}", include_workflow=true, env="${args.env_2 || args.env_1 || "demo"}")\`
|
|
644
643
|
|
|
645
|
-
### Step 2:
|
|
646
|
-
Call \`persona(
|
|
644
|
+
### Step 2: Get Both Personas
|
|
645
|
+
Call \`persona(method="get", id="${args.persona_id_1}", include_workflow=true, env="${args.env_1 || "demo"}")\`
|
|
646
|
+
Call \`persona(method="get", id="${args.persona_id_2}", include_workflow=true, env="${args.env_2 || args.env_1 || "demo"}")\`
|
|
647
647
|
|
|
648
|
-
### Step 3: Compare
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
648
|
+
### Step 3: Compare (YOU do this)
|
|
649
|
+
Compare the two workflow_def structures:
|
|
650
|
+
- Node differences (added/removed/renamed)
|
|
651
|
+
- Connection differences
|
|
652
|
+
- Configuration differences
|
|
652
653
|
|
|
653
654
|
## Output Format
|
|
654
655
|
|
|
@@ -754,8 +755,9 @@ ${args.action === "snapshot" ? `
|
|
|
754
755
|
1. List versions first to see available:
|
|
755
756
|
\`persona(id="${args.persona_id}", mode="version_list", env="${args.env || "demo"}")\`
|
|
756
757
|
|
|
757
|
-
2.
|
|
758
|
-
\`persona(id="${args.persona_id}", mode="
|
|
758
|
+
2. Get two versions and compare (YOU compare the results):
|
|
759
|
+
\`persona(id="${args.persona_id}", mode="version_get", version="${args.version || "v1"}", env="${args.env || "demo"}")\`
|
|
760
|
+
\`persona(id="${args.persona_id}", mode="version_get", version="latest", env="${args.env || "demo"}")\`
|
|
759
761
|
|
|
760
762
|
3. Present changes:
|
|
761
763
|
- Fields that changed
|
|
@@ -937,7 +939,7 @@ Provide examples of common tasks:
|
|
|
937
939
|
2. **Search for specific persona**: \`persona(query="support", status="active", env="demo")\`
|
|
938
940
|
3. **Get full persona details**: \`persona(id="xxx", include_workflow=true, env="demo")\`
|
|
939
941
|
4. **Sync a persona**: \`sync(id="my-bot", source="demo", target="dev")\`
|
|
940
|
-
5. **
|
|
942
|
+
5. **Get workflow data**: \`workflow(mode="get", persona_id="xxx", env="demo")\` (you analyze the result)
|
|
941
943
|
|
|
942
944
|
## Output Format
|
|
943
945
|
|
|
@@ -1027,6 +1029,15 @@ ${args.intents ? `**Intents**: ${args.intents}` : ""}
|
|
|
1027
1029
|
|
|
1028
1030
|
## Instructions
|
|
1029
1031
|
|
|
1032
|
+
### Step 0: Check Deprecated Actions (DO THIS FIRST)
|
|
1033
|
+
Fetch \`ema://rules/deprecated-actions-summary\` to know which actions to AVOID.
|
|
1034
|
+
|
|
1035
|
+
**Key deprecated actions to avoid:**
|
|
1036
|
+
- search/v0 → use search/v2 (requires datastore_configs)
|
|
1037
|
+
- respond_with_sources → use respond_for_external_actions
|
|
1038
|
+
- call_llm/v0 → use call_llm/v2
|
|
1039
|
+
- web_search/v0 → use live_web_search or ai_web_search
|
|
1040
|
+
|
|
1030
1041
|
### Step 1: Get Templates
|
|
1031
1042
|
Get templates from API or use generated fallbacks:
|
|
1032
1043
|
- \`template(config="voice")\` - Voice AI persona configuration (API-first with fallback)
|
|
@@ -1061,10 +1072,12 @@ ${args.name.toLowerCase().replace(/\s+/g, "-")}/
|
|
|
1061
1072
|
└── proto-config.json # Full API config
|
|
1062
1073
|
\`\`\`
|
|
1063
1074
|
|
|
1075
|
+
**IMPORTANT**: Only use non-deprecated actions from Step 0.
|
|
1076
|
+
|
|
1064
1077
|
### Step 6: Validate
|
|
1065
1078
|
Call \`reference(validate_prompt=<generated_prompt>)\` to verify the prompt.
|
|
1066
1079
|
|
|
1067
|
-
Now begin by reading the
|
|
1080
|
+
Now begin by reading the deprecated actions, then proceed with generation.`,
|
|
1068
1081
|
},
|
|
1069
1082
|
},
|
|
1070
1083
|
],
|
|
@@ -1107,6 +1120,15 @@ ${args.data_sources ? `**Data Sources**: ${args.data_sources}` : ""}
|
|
|
1107
1120
|
|
|
1108
1121
|
## Instructions
|
|
1109
1122
|
|
|
1123
|
+
### Step 0: Check Deprecated Actions (DO THIS FIRST)
|
|
1124
|
+
Fetch \`ema://rules/deprecated-actions-summary\` to know which actions to AVOID.
|
|
1125
|
+
|
|
1126
|
+
**Key deprecated actions to avoid:**
|
|
1127
|
+
- search/v0 → use search/v2 (requires datastore_configs)
|
|
1128
|
+
- respond_with_sources → use respond_for_external_actions
|
|
1129
|
+
- call_llm/v0 → use call_llm/v2
|
|
1130
|
+
- web_search/v0 → use live_web_search or ai_web_search
|
|
1131
|
+
|
|
1110
1132
|
### Step 1: Get Templates
|
|
1111
1133
|
Get templates from API or use generated fallbacks:
|
|
1112
1134
|
- \`template(config="chat")\` - Chat AI persona configuration (API-first with fallback)
|
|
@@ -1130,6 +1152,8 @@ Call \`reference(guidance="conversation-vs-query")\` to understand:
|
|
|
1130
1152
|
### Step 5: Generate Output
|
|
1131
1153
|
Using the templates from Step 1 and guidance from Steps 3-4, generate:
|
|
1132
1154
|
|
|
1155
|
+
**IMPORTANT**: Only use non-deprecated actions from Step 0.
|
|
1156
|
+
|
|
1133
1157
|
**Folder structure:**
|
|
1134
1158
|
\`\`\`
|
|
1135
1159
|
${args.name.toLowerCase().replace(/\s+/g, "-")}/
|
|
@@ -1183,6 +1207,16 @@ Now begin by reading the resources, then proceed with generation.`,
|
|
|
1183
1207
|
**Type**: ${args.type}
|
|
1184
1208
|
**Description**: ${args.description}
|
|
1185
1209
|
|
|
1210
|
+
## Step 0: Check Deprecated Actions (DO THIS FIRST)
|
|
1211
|
+
|
|
1212
|
+
Fetch \`ema://rules/deprecated-actions-summary\` to see which actions to AVOID.
|
|
1213
|
+
|
|
1214
|
+
Common deprecated actions:
|
|
1215
|
+
- search/v0 → use search/v2 (requires datastore_configs)
|
|
1216
|
+
- respond_with_sources → use respond_for_external_actions
|
|
1217
|
+
- call_llm/v0 → use call_llm/v2
|
|
1218
|
+
- web_search/v0 → use live_web_search or ai_web_search
|
|
1219
|
+
|
|
1186
1220
|
## Step 1: Preview the workflow
|
|
1187
1221
|
|
|
1188
1222
|
\`\`\`
|
|
@@ -1193,6 +1227,7 @@ workflow(
|
|
|
1193
1227
|
\`\`\`
|
|
1194
1228
|
|
|
1195
1229
|
This returns workflow_def and proto_config. Review them before deploying.
|
|
1230
|
+
**Check for any deprecated actions in the generated workflow.**
|
|
1196
1231
|
|
|
1197
1232
|
## Step 2: Deploy when ready
|
|
1198
1233
|
|
|
@@ -1213,7 +1248,8 @@ ${args.type === "voice" ? `
|
|
|
1213
1248
|
The generated proto_config includes voice settings:
|
|
1214
1249
|
- welcomeMessage: Generated greeting
|
|
1215
1250
|
- identityAndPurpose: Generated from description
|
|
1216
|
-
- takeActionInstructions
|
|
1251
|
+
- takeActionInstructions: Auto-generated from workflow tools (if tools specified)
|
|
1252
|
+
- hangupInstructions: Sensible defaults
|
|
1217
1253
|
|
|
1218
1254
|
These are set automatically but can be customized via proto_config override.
|
|
1219
1255
|
` : ""}`,
|
|
@@ -1349,8 +1385,7 @@ ${args.workflow_def ? `**Workflow Definition**: Provided inline` : ""}
|
|
|
1349
1385
|
${args.persona_id ? `First, fetch the workflow:
|
|
1350
1386
|
\`persona(id="${args.persona_id}", include_workflow=true, env="${args.env || "demo"}")\`
|
|
1351
1387
|
|
|
1352
|
-
Then
|
|
1353
|
-
\`workflow(persona_id="${args.persona_id}", mode="analyze", env="${args.env || "demo"}")\`
|
|
1388
|
+
Then review the workflow_def for issues (missing WORKFLOW_OUTPUT, type mismatches, etc.).
|
|
1354
1389
|
` : ""}
|
|
1355
1390
|
|
|
1356
1391
|
## Required Analysis Sections
|
|
@@ -1506,10 +1541,11 @@ Proceed to Phase 1.
|
|
|
1506
1541
|
|
|
1507
1542
|
### Step 1.1: Fetch and Analyze
|
|
1508
1543
|
\`\`\`
|
|
1509
|
-
|
|
1510
|
-
workflow(persona_id="${args.persona_id}", mode="analyze", env="${args.env || "demo"}")
|
|
1544
|
+
workflow(mode="get", persona_id="${args.persona_id}", env="${args.env || "demo"}")
|
|
1511
1545
|
\`\`\`
|
|
1512
1546
|
|
|
1547
|
+
Review the workflow_def for issues (missing WORKFLOW_OUTPUT, type mismatches, orphan nodes).
|
|
1548
|
+
|
|
1513
1549
|
### Step 1.2: Document Existing Logic
|
|
1514
1550
|
Before making changes, document:
|
|
1515
1551
|
- **Current intents**: List all categories and their handlers
|
|
@@ -1611,8 +1647,8 @@ workflow(
|
|
|
1611
1647
|
|
|
1612
1648
|
## Phase 4: Validate & Deploy
|
|
1613
1649
|
|
|
1614
|
-
### Step 4.1:
|
|
1615
|
-
\`workflow(persona_id="${args.persona_id}"
|
|
1650
|
+
### Step 4.1: Review Changes
|
|
1651
|
+
\`workflow(mode="get", persona_id="${args.persona_id}")\` and verify the workflow_def is correct.
|
|
1616
1652
|
|
|
1617
1653
|
Verify:
|
|
1618
1654
|
- [ ] No type mismatches
|
|
@@ -1620,11 +1656,12 @@ Verify:
|
|
|
1620
1656
|
- [ ] All new nodes properly linked
|
|
1621
1657
|
- [ ] Existing functionality preserved
|
|
1622
1658
|
|
|
1623
|
-
### Step 4.2:
|
|
1624
|
-
\`
|
|
1659
|
+
### Step 4.2: Validate with Rules
|
|
1660
|
+
Fetch \`ema://rules/anti-patterns\` and verify no issues.
|
|
1625
1661
|
|
|
1626
1662
|
### Step 4.3: Deploy
|
|
1627
|
-
\`workflow(persona_id="${args.persona_id}", mode="deploy", workflow_def=<extended_workflow
|
|
1663
|
+
\`workflow(persona_id="${args.persona_id}", mode="deploy", workflow_def=<extended_workflow>, preview=true)\`
|
|
1664
|
+
Then without preview to commit.
|
|
1628
1665
|
|
|
1629
1666
|
## Extension Patterns
|
|
1630
1667
|
|
|
@@ -1709,10 +1746,11 @@ Provide:
|
|
|
1709
1746
|
## Step 1: Fetch Workflow Data
|
|
1710
1747
|
|
|
1711
1748
|
\`\`\`
|
|
1712
|
-
|
|
1713
|
-
workflow(persona_id="${args.persona_id}", mode="analyze", env="${args.env || "demo"}")
|
|
1749
|
+
workflow(mode="get", persona_id="${args.persona_id}", env="${args.env || "demo"}")
|
|
1714
1750
|
\`\`\`
|
|
1715
1751
|
|
|
1752
|
+
Review the workflow_def for issues (missing WORKFLOW_OUTPUT, type mismatches, orphan nodes).
|
|
1753
|
+
|
|
1716
1754
|
## Step 2: Intent Analysis Framework
|
|
1717
1755
|
|
|
1718
1756
|
### Business Intent Layer
|
package/dist/mcp/resources.js
CHANGED
|
@@ -30,11 +30,13 @@ import { dirname } from "node:path";
|
|
|
30
30
|
const __filename = fileURLToPath(import.meta.url);
|
|
31
31
|
const __dirname = dirname(__filename);
|
|
32
32
|
// Import knowledge catalogs for dynamic resources
|
|
33
|
-
import { AGENT_CATALOG, WORKFLOW_PATTERNS, WIDGET_CATALOG } from "../sdk/knowledge.js";
|
|
33
|
+
import { AGENT_CATALOG, WORKFLOW_PATTERNS, WIDGET_CATALOG, ALL_DEPRECATED_ACTIONS, DEPRECATED_ACTIONS_WITH_REPLACEMENT, DEPRECATED_ACTIONS_NO_REPLACEMENT, WORKFLOW_ENABLING_CONSTRAINTS, MINIMUM_VIABLE_WORKFLOWS, } from "../sdk/knowledge.js";
|
|
34
34
|
import { INPUT_SOURCE_RULES, ANTI_PATTERNS, OPTIMIZATION_RULES } from "../sdk/validation-rules.js";
|
|
35
|
+
import { STRUCTURAL_INVARIANTS } from "../sdk/structural-rules.js";
|
|
35
36
|
import { EmaClient } from "../sdk/client.js";
|
|
36
37
|
import { APISchemaRegistry } from "../sdk/workflow-validator.js";
|
|
37
38
|
import { loadConfigFromJsonEnv, loadConfigOptional, resolveBearerToken, getEnvByName, getMasterEnv, } from "../sdk/config.js";
|
|
39
|
+
import { VOICE_TEMPLATE_FALLBACK, VOICE_TEMPLATE_FIELD_DOCS, } from "../sdk/generated/template-fallbacks.js";
|
|
38
40
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
39
41
|
// Security Utilities
|
|
40
42
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -207,6 +209,336 @@ const DYNAMIC_RESOURCES = [
|
|
|
207
209
|
mimeType: "application/json",
|
|
208
210
|
generate: async () => JSON.stringify(OPTIMIZATION_RULES, null, 2),
|
|
209
211
|
},
|
|
212
|
+
{
|
|
213
|
+
uri: "ema://rules/structural-invariants",
|
|
214
|
+
name: "rules/structural-invariants",
|
|
215
|
+
description: "Structural invariants: hard constraints that workflows must satisfy (no cycles, reachability, etc.)",
|
|
216
|
+
mimeType: "application/json",
|
|
217
|
+
generate: async () => JSON.stringify(STRUCTURAL_INVARIANTS, null, 2),
|
|
218
|
+
},
|
|
219
|
+
// Deprecated Actions - API-first with fallback
|
|
220
|
+
{
|
|
221
|
+
uri: "ema://rules/deprecated-actions",
|
|
222
|
+
name: "rules/deprecated-actions",
|
|
223
|
+
description: "Deprecated actions list: actions to avoid in new workflows, with their replacements and migration notes",
|
|
224
|
+
mimeType: "application/json",
|
|
225
|
+
generate: async (ctx) => {
|
|
226
|
+
// Try API first using existing client infrastructure
|
|
227
|
+
let apiDeprecated = [];
|
|
228
|
+
let source = "fallback";
|
|
229
|
+
try {
|
|
230
|
+
const client = getClientForEnvName(ctx.env);
|
|
231
|
+
if (client) {
|
|
232
|
+
const actions = await client.listActions();
|
|
233
|
+
apiDeprecated = actions.filter(a => a.deprecated).map(a => a.id);
|
|
234
|
+
source = "api";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// API unavailable, use fallback
|
|
239
|
+
}
|
|
240
|
+
// Merge API deprecated with fallback replacement info
|
|
241
|
+
const result = {
|
|
242
|
+
_note: "Actions marked deprecated should not be used in new workflows. Use replacements where available.",
|
|
243
|
+
_source: source,
|
|
244
|
+
_api_deprecated_count: apiDeprecated.length,
|
|
245
|
+
// From API (current deprecated status)
|
|
246
|
+
api_deprecated: apiDeprecated.length > 0 ? apiDeprecated : undefined,
|
|
247
|
+
// From fallback (includes replacement info)
|
|
248
|
+
with_replacement: DEPRECATED_ACTIONS_WITH_REPLACEMENT.map(d => ({
|
|
249
|
+
action: d.action,
|
|
250
|
+
version: d.version,
|
|
251
|
+
replacement: d.replacement,
|
|
252
|
+
replacement_version: d.replacementVersion,
|
|
253
|
+
migration_notes: d.migrationNotes,
|
|
254
|
+
})),
|
|
255
|
+
no_replacement: DEPRECATED_ACTIONS_NO_REPLACEMENT.map(d => ({
|
|
256
|
+
action: d.action,
|
|
257
|
+
version: d.version,
|
|
258
|
+
environment: d.environment,
|
|
259
|
+
notes: d.migrationNotes,
|
|
260
|
+
})),
|
|
261
|
+
_tip: "Check workflow(mode='get') for deprecation_warnings on specific workflows",
|
|
262
|
+
};
|
|
263
|
+
return JSON.stringify(result, null, 2);
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
uri: "ema://rules/deprecated-actions-summary",
|
|
268
|
+
name: "rules/deprecated-actions-summary",
|
|
269
|
+
description: "Deprecated actions summary: quick reference table of deprecated actions and replacements",
|
|
270
|
+
mimeType: "text/markdown",
|
|
271
|
+
generate: async (ctx) => {
|
|
272
|
+
// Try API first using existing client infrastructure
|
|
273
|
+
let apiDeprecated = [];
|
|
274
|
+
let source = "fallback";
|
|
275
|
+
try {
|
|
276
|
+
const client = getClientForEnvName(ctx.env);
|
|
277
|
+
if (client) {
|
|
278
|
+
const actions = await client.listActions();
|
|
279
|
+
apiDeprecated = actions.filter(a => a.deprecated).map(a => a.id);
|
|
280
|
+
source = "api";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
// API unavailable, use fallback
|
|
285
|
+
}
|
|
286
|
+
let md = "# Deprecated Actions\n\n";
|
|
287
|
+
md += "> Do NOT use these actions in new workflows. Use replacements where available.\n\n";
|
|
288
|
+
md += `> Source: ${source} (${source === "api" ? "live" : "synced 2026-01-26"})\n\n`;
|
|
289
|
+
if (apiDeprecated.length > 0) {
|
|
290
|
+
md += "## From API (Current)\n\n";
|
|
291
|
+
md += "| Action ID | Status |\n";
|
|
292
|
+
md += "|-----------|--------|\n";
|
|
293
|
+
for (const id of apiDeprecated) {
|
|
294
|
+
md += `| \`${id}\` | DEPRECATED |\n`;
|
|
295
|
+
}
|
|
296
|
+
md += "\n";
|
|
297
|
+
}
|
|
298
|
+
md += "## Actions with Known Replacements\n\n";
|
|
299
|
+
md += "| Deprecated Action | Version | Replacement | Notes |\n";
|
|
300
|
+
md += "|-------------------|---------|-------------|-------|\n";
|
|
301
|
+
for (const d of DEPRECATED_ACTIONS_WITH_REPLACEMENT) {
|
|
302
|
+
const repl = Array.isArray(d.replacement) ? d.replacement.join(" or ") : d.replacement;
|
|
303
|
+
const replVer = d.replacementVersion ? ` ${d.replacementVersion}` : "";
|
|
304
|
+
md += `| \`${d.action}\` | ${d.version} | \`${repl}\`${replVer} | ${d.migrationNotes || "-"} |\n`;
|
|
305
|
+
}
|
|
306
|
+
md += "\n## Actions with No Known Replacement\n\n";
|
|
307
|
+
md += "| Action | Environment | Notes |\n";
|
|
308
|
+
md += "|--------|-------------|-------|\n";
|
|
309
|
+
for (const d of DEPRECATED_ACTIONS_NO_REPLACEMENT) {
|
|
310
|
+
md += `| \`${d.action}\` | ${d.environment || "all"} | ${d.migrationNotes || "-"} |\n`;
|
|
311
|
+
}
|
|
312
|
+
md += `\n**Total Known Deprecated**: ${ALL_DEPRECATED_ACTIONS.length} actions\n`;
|
|
313
|
+
md += `\n> **Best Practice**: Use \`workflow(mode="get")\` to check for deprecation warnings in specific workflows.\n`;
|
|
314
|
+
return md;
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
// Workflow Enabling Constraints - Requirements for persona activation
|
|
318
|
+
{
|
|
319
|
+
uri: "ema://rules/workflow-constraints",
|
|
320
|
+
name: "rules/workflow-constraints",
|
|
321
|
+
description: "Workflow enabling constraints: requirements that must be met before a persona can be activated",
|
|
322
|
+
mimeType: "application/json",
|
|
323
|
+
generate: async () => JSON.stringify({
|
|
324
|
+
_note: "These constraints are checked by the Ema backend when enabling a persona.",
|
|
325
|
+
_source: "ema/ema_backend/db/models/personas_model.py:672-756",
|
|
326
|
+
_last_synced: "2026-01-26",
|
|
327
|
+
enabling_constraints: WORKFLOW_ENABLING_CONSTRAINTS,
|
|
328
|
+
minimum_viable_workflows: MINIMUM_VIABLE_WORKFLOWS,
|
|
329
|
+
}, null, 2),
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
uri: "ema://rules/workflow-constraints-summary",
|
|
333
|
+
name: "rules/workflow-constraints-summary",
|
|
334
|
+
description: "Workflow constraints summary: checklist of requirements for enabling a persona",
|
|
335
|
+
mimeType: "text/markdown",
|
|
336
|
+
generate: async () => {
|
|
337
|
+
let md = "# Workflow Enabling Constraints\n\n";
|
|
338
|
+
md += "> These constraints must be satisfied for a persona to be activated.\n\n";
|
|
339
|
+
md += "> Source: ema_backend/db/models/personas_model.py (synced 2026-01-26)\n\n";
|
|
340
|
+
md += "## Required Checks\n\n";
|
|
341
|
+
md += "| # | Constraint | Error State | Fix |\n";
|
|
342
|
+
md += "|---|------------|-------------|-----|\n";
|
|
343
|
+
for (const c of WORKFLOW_ENABLING_CONSTRAINTS) {
|
|
344
|
+
const critical = c.critical ? "**" : "";
|
|
345
|
+
md += `| ${c.id} | ${critical}${c.name}${critical} | \`${c.errorState}\` | ${c.fix} |\n`;
|
|
346
|
+
}
|
|
347
|
+
md += "\n## Minimum Viable Workflows by Type\n\n";
|
|
348
|
+
for (const [type, mvw] of Object.entries(MINIMUM_VIABLE_WORKFLOWS)) {
|
|
349
|
+
md += `### ${type}\n\n`;
|
|
350
|
+
md += `**Structure**: \`${mvw.exampleStructure}\`\n\n`;
|
|
351
|
+
md += `- Required nodes: ${mvw.requiredNodes.map(n => `\`${n}\``).join(", ")}\n`;
|
|
352
|
+
md += `- Required outputs: ${mvw.requiredOutputs.map(o => `\`${o}\``).join(", ")}\n`;
|
|
353
|
+
if (mvw.requiredWidgets) {
|
|
354
|
+
md += `- Required widgets: ${mvw.requiredWidgets.map(w => `\`${w}\``).join(", ")}\n`;
|
|
355
|
+
}
|
|
356
|
+
if (mvw.notes) {
|
|
357
|
+
md += `- Notes: ${mvw.notes}\n`;
|
|
358
|
+
}
|
|
359
|
+
md += "\n";
|
|
360
|
+
}
|
|
361
|
+
md += "## Critical Rule: WORKFLOW_OUTPUT\n\n";
|
|
362
|
+
md += "**Every workflow must have a `results.WORKFLOW_OUTPUT` that maps to an action output.**\n\n";
|
|
363
|
+
md += "```json\n";
|
|
364
|
+
md += '{\n "results": {\n "WORKFLOW_OUTPUT": {\n "actionName": "respond_node",\n "outputName": "response_with_sources"\n }\n }\n}\n';
|
|
365
|
+
md += "```\n";
|
|
366
|
+
return md;
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
370
|
+
// Workflow Requirements & Guidance
|
|
371
|
+
// NOT hardcoded templates - provide requirements and let LLM generate
|
|
372
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
373
|
+
{
|
|
374
|
+
uri: "ema://templates/voice-ai/requirements",
|
|
375
|
+
name: "templates/voice-ai/requirements",
|
|
376
|
+
description: "Voice AI workflow requirements and guidance. Use workflow(mode='get') for schema, then generate workflow_def.",
|
|
377
|
+
mimeType: "application/json",
|
|
378
|
+
generate: async () => {
|
|
379
|
+
return JSON.stringify({
|
|
380
|
+
_note: "Requirements and guidance for Voice AI workflows. LLM generates workflow_def based on these.",
|
|
381
|
+
_usage: "1) workflow(mode='get', persona_id='...') for schema, 2) Generate workflow_def, 3) workflow(mode='deploy', ...)",
|
|
382
|
+
hard_requirements: {
|
|
383
|
+
workflow_output: {
|
|
384
|
+
rule: "MUST have results.WORKFLOW_OUTPUT mapped to final action output",
|
|
385
|
+
example: '{ "results": { "WORKFLOW_OUTPUT": { "actionName": "respond", "outputName": "response" } } }',
|
|
386
|
+
},
|
|
387
|
+
workflow_name: {
|
|
388
|
+
rule: "workflowName MUST be ['ema', 'personas', '<actual_persona_id>']",
|
|
389
|
+
},
|
|
390
|
+
trigger: {
|
|
391
|
+
rule: "Voice AI uses chat_trigger (type CHAT)",
|
|
392
|
+
namespace: ["triggers", "emainternal"],
|
|
393
|
+
},
|
|
394
|
+
response: {
|
|
395
|
+
rule: "Must produce a response output that wires to WORKFLOW_OUTPUT",
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
required_widgets: [
|
|
399
|
+
{ name: "conversationSettings", type: 39, purpose: "Voice identity, welcome message, instructions" },
|
|
400
|
+
{ name: "voiceSettings", type: 40, purpose: "Language, voice model" },
|
|
401
|
+
{ name: "callSettings", type: 41, purpose: "Call forwarding, spam prevention" },
|
|
402
|
+
{ name: "vadSettings", type: 42, purpose: "Voice activity detection, timeouts" },
|
|
403
|
+
],
|
|
404
|
+
common_patterns: {
|
|
405
|
+
simple_qa: "chat_trigger → search → respond_for_external_actions → WORKFLOW_OUTPUT",
|
|
406
|
+
with_routing: "chat_trigger → chat_categorizer → [branch per intent] → respond → WORKFLOW_OUTPUT",
|
|
407
|
+
with_tools: "chat_trigger → categorizer → external_action_caller → respond_for_external_actions → WORKFLOW_OUTPUT",
|
|
408
|
+
},
|
|
409
|
+
best_practices: [
|
|
410
|
+
"Use search/v2 (NOT v0) with datastore_configs",
|
|
411
|
+
"Include Fallback category in every categorizer",
|
|
412
|
+
"Use respond_for_external_actions (NOT deprecated respond_with_sources)",
|
|
413
|
+
"Consider general_hitl before actions with side effects",
|
|
414
|
+
],
|
|
415
|
+
_next_step: "Call workflow(mode='get', persona_id='...') to get full schema, then generate workflow_def",
|
|
416
|
+
}, null, 2);
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
uri: "ema://templates/voice-ai/config",
|
|
421
|
+
name: "templates/voice-ai/config",
|
|
422
|
+
description: "Voice AI configuration template (proto_config widgets). Customize values for your use case.",
|
|
423
|
+
mimeType: "application/json",
|
|
424
|
+
generate: async () => {
|
|
425
|
+
const config = {
|
|
426
|
+
_note: "Voice AI configuration template. Customize values for your use case.",
|
|
427
|
+
_usage: "persona(method='update', id='<ID>', config={widgets: [<these widgets with your values>]})",
|
|
428
|
+
widgets: [
|
|
429
|
+
{
|
|
430
|
+
name: "conversationSettings",
|
|
431
|
+
type: 39,
|
|
432
|
+
conversationSettings: {
|
|
433
|
+
...VOICE_TEMPLATE_FALLBACK.conversationSettings,
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
name: "voiceSettings",
|
|
438
|
+
type: 40,
|
|
439
|
+
voiceSettings: {
|
|
440
|
+
...VOICE_TEMPLATE_FALLBACK.voiceSettings,
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: "callSettings",
|
|
445
|
+
type: 41,
|
|
446
|
+
callSettings: {
|
|
447
|
+
...VOICE_TEMPLATE_FALLBACK.callSettings,
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
name: "vadSettings",
|
|
452
|
+
type: 42,
|
|
453
|
+
vadSettings: {
|
|
454
|
+
...VOICE_TEMPLATE_FALLBACK.vadSettings,
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
field_docs: VOICE_TEMPLATE_FIELD_DOCS,
|
|
459
|
+
};
|
|
460
|
+
return JSON.stringify(config, null, 2);
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
uri: "ema://templates/voice-ai/guide",
|
|
465
|
+
name: "templates/voice-ai/guide",
|
|
466
|
+
description: "Voice AI creation guide with requirements and step-by-step process",
|
|
467
|
+
mimeType: "text/markdown",
|
|
468
|
+
generate: async () => {
|
|
469
|
+
return `# Voice AI Creation Guide
|
|
470
|
+
|
|
471
|
+
## Process (Follow This Order)
|
|
472
|
+
|
|
473
|
+
### 1. Create Persona
|
|
474
|
+
\`\`\`
|
|
475
|
+
persona(method="create", name="Your Voice AI", type="voice")
|
|
476
|
+
\`\`\`
|
|
477
|
+
|
|
478
|
+
### 2. Get Workflow Schema
|
|
479
|
+
\`\`\`
|
|
480
|
+
workflow(mode="get", persona_id="<ID>")
|
|
481
|
+
\`\`\`
|
|
482
|
+
This returns:
|
|
483
|
+
- Current workflow (if any)
|
|
484
|
+
- Deprecation warnings (fix these first!)
|
|
485
|
+
- Generation schema (agents, constraints)
|
|
486
|
+
- Requirements and guidance
|
|
487
|
+
|
|
488
|
+
### 3. Generate Workflow
|
|
489
|
+
Using the schema, generate a workflow_def that:
|
|
490
|
+
- Has WORKFLOW_OUTPUT in results
|
|
491
|
+
- Uses non-deprecated actions
|
|
492
|
+
- Follows the flow pattern: trigger → processing → response → OUTPUT
|
|
493
|
+
|
|
494
|
+
### 4. Deploy Workflow
|
|
495
|
+
\`\`\`
|
|
496
|
+
workflow(mode="deploy", persona_id="<ID>", workflow_def={...}, preview=true)
|
|
497
|
+
\`\`\`
|
|
498
|
+
Always preview first!
|
|
499
|
+
|
|
500
|
+
### 5. Configure Settings
|
|
501
|
+
\`\`\`
|
|
502
|
+
persona(method="update", id="<ID>", config={widgets: [...]})
|
|
503
|
+
\`\`\`
|
|
504
|
+
|
|
505
|
+
### 6. Upload Knowledge
|
|
506
|
+
\`\`\`
|
|
507
|
+
persona(id="<ID>", data={method:"upload", path:"your-data.txt"})
|
|
508
|
+
\`\`\`
|
|
509
|
+
|
|
510
|
+
## Hard Requirements
|
|
511
|
+
|
|
512
|
+
| Requirement | Why |
|
|
513
|
+
|-------------|-----|
|
|
514
|
+
| WORKFLOW_OUTPUT | Persona cannot be activated without it |
|
|
515
|
+
| workflowName format | API rejects invalid namespaces |
|
|
516
|
+
| Non-deprecated actions | Deprecated actions may fail |
|
|
517
|
+
|
|
518
|
+
## Check for Deprecated Actions
|
|
519
|
+
|
|
520
|
+
\`workflow(mode="get")\` returns \`deprecation_warnings\` if any actions are deprecated.
|
|
521
|
+
**Fix these BEFORE deploying.**
|
|
522
|
+
|
|
523
|
+
## Common Deprecated Actions
|
|
524
|
+
|
|
525
|
+
| Deprecated | Use Instead |
|
|
526
|
+
|------------|-------------|
|
|
527
|
+
| search/v0 | search/v2 (requires datastore_configs) |
|
|
528
|
+
| respond_with_sources | respond_for_external_actions |
|
|
529
|
+
| call_llm/v0 | call_llm/v2 |
|
|
530
|
+
|
|
531
|
+
## Anti-Patterns
|
|
532
|
+
|
|
533
|
+
❌ Cloning random existing persona
|
|
534
|
+
❌ Skipping workflow_def
|
|
535
|
+
❌ Using deprecated actions
|
|
536
|
+
❌ Deploying without preview
|
|
537
|
+
|
|
538
|
+
${VOICE_TEMPLATE_FIELD_DOCS}
|
|
539
|
+
`;
|
|
540
|
+
},
|
|
541
|
+
},
|
|
210
542
|
// Persona Templates - Dynamic from API with fallback
|
|
211
543
|
{
|
|
212
544
|
uri: "ema://catalog/templates",
|
|
@@ -798,8 +1130,8 @@ To read a resource, use the \`resources/read\` endpoint:
|
|
|
798
1130
|
| Get input/output compatibility rules | Resource: \`ema://rules/input-sources\` |
|
|
799
1131
|
| Get persona templates | Resource: \`ema://catalog/persona-templates\` (API) or Tool: \`template(config="voice")\` |
|
|
800
1132
|
| Query live persona data | Tool: \`persona\` |
|
|
801
|
-
|
|
|
802
|
-
|
|
|
1133
|
+
| Get workflow data | Tool: \`workflow(mode="get")\` |
|
|
1134
|
+
| Deploy workflow | Tool: \`workflow(mode="deploy")\` |
|
|
803
1135
|
`;
|
|
804
1136
|
return {
|
|
805
1137
|
uri: "ema://index/all-resources",
|