@ema.co/mcp-toolkit 2026.2.5 → 2026.2.19
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/.context/public/guides/ema-user-guide.md +12 -16
- package/.context/public/guides/mcp-tools-guide.md +203 -334
- package/LICENSE +29 -21
- package/README.md +58 -35
- package/dist/mcp/domain/loop-detection.js +97 -0
- package/dist/mcp/domain/proto-constraints.js +284 -0
- package/dist/mcp/domain/structural-rules.js +12 -5
- package/dist/mcp/domain/validation-rules.js +107 -20
- package/dist/mcp/domain/workflow-graph-optimizer.js +235 -0
- package/dist/mcp/domain/workflow-graph-transforms.js +808 -0
- package/dist/mcp/domain/workflow-graph.js +374 -0
- package/dist/mcp/domain/workflow-optimizer.js +10 -4
- package/dist/mcp/guidance.js +54 -31
- package/dist/mcp/handlers/feedback/index.js +139 -0
- package/dist/mcp/handlers/feedback/store.js +262 -0
- package/dist/mcp/handlers/persona/index.js +237 -8
- package/dist/mcp/handlers/persona/schema.js +27 -0
- package/dist/mcp/handlers/reference/index.js +6 -4
- package/dist/mcp/handlers/workflow/index.js +25 -28
- package/dist/mcp/handlers/workflow/optimize.js +73 -33
- package/dist/mcp/handlers/workflow/validation.js +1 -1
- package/dist/mcp/knowledge-types.js +7 -0
- package/dist/mcp/knowledge.js +146 -834
- package/dist/mcp/resources.js +610 -18
- package/dist/mcp/server.js +233 -2156
- package/dist/mcp/tools.js +91 -5
- package/dist/sdk/generated/agent-catalog.js +615 -0
- package/dist/sdk/generated/deprecated-actions.js +182 -96
- package/dist/sdk/generated/proto-fields.js +2 -1
- package/dist/sdk/generated/protos/service/agent_qa/v1/agent_qa_pb.js +460 -21
- package/dist/sdk/generated/protos/service/auth/v1/auth_pb.js +11 -1
- package/dist/sdk/generated/protos/service/dataingest/v1/dataingest_pb.js +173 -66
- package/dist/sdk/generated/protos/service/feedback/v1/feedback_pb.js +43 -1
- package/dist/sdk/generated/protos/service/llmservice/v1/llmservice_pb.js +26 -21
- package/dist/sdk/generated/protos/service/persona/v1/persona_config_pb.js +100 -89
- package/dist/sdk/generated/protos/service/persona/v1/persona_pb.js +126 -116
- package/dist/sdk/generated/protos/service/persona/v1/shared_widgets/widget_types_pb.js +33 -1
- package/dist/sdk/generated/protos/service/persona/v1/voicebot_widgets/widget_types_pb.js +60 -11
- package/dist/sdk/generated/protos/service/tenant/v1/tenant_pb.js +1 -1
- package/dist/sdk/generated/protos/service/user/v1/user_pb.js +1 -1
- package/dist/sdk/generated/protos/service/utils/v1/agent_qa_pb.js +35 -0
- package/dist/sdk/generated/protos/service/workflows/v1/action_registry_pb.js +1 -1
- package/dist/sdk/generated/protos/service/workflows/v1/action_type_pb.js +6 -1
- package/dist/sdk/generated/protos/service/workflows/v1/chatbot_pb.js +106 -11
- package/dist/sdk/generated/protos/service/workflows/v1/common_forms_pb.js +1 -1
- package/dist/sdk/generated/protos/service/workflows/v1/coordinator_pb.js +1 -1
- package/dist/sdk/generated/protos/service/workflows/v1/external_actions_pb.js +31 -1
- package/dist/sdk/generated/protos/service/workflows/v1/well_known_pb.js +5 -1
- package/dist/sdk/generated/protos/service/workflows/v1/workflow_pb.js +1 -1
- package/dist/sdk/generated/protos/util/tracking_metadata_pb.js +1 -1
- package/dist/sdk/generated/widget-catalog.js +60 -0
- package/docs/README.md +17 -9
- package/package.json +2 -2
- package/.context/public/guides/dashboard-operations.md +0 -286
- package/.context/public/guides/email-patterns.md +0 -125
- package/dist/mcp/domain/intent-architect.js +0 -914
- package/dist/mcp/domain/quality-gates.js +0 -110
- package/dist/mcp/domain/workflow-execution-analyzer.js +0 -412
- package/dist/mcp/domain/workflow-intent.js +0 -1806
- package/dist/mcp/domain/workflow-merge.js +0 -449
- package/dist/mcp/domain/workflow-tracer.js +0 -648
- package/dist/mcp/domain/workflow-transformer.js +0 -742
- package/dist/mcp/handlers/persona/intent.js +0 -141
- package/dist/mcp/handlers/workflow/analyze.js +0 -119
- package/dist/mcp/handlers/workflow/compare.js +0 -70
- package/dist/mcp/handlers/workflow/generate.js +0 -384
- package/dist/mcp/handlers-consolidated.js +0 -333
package/dist/mcp/knowledge.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ema Platform Knowledge Base
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Curated knowledge constants, patterns, and helper functions.
|
|
5
|
+
* Types are in ./knowledge-types.ts
|
|
6
|
+
* Auto-generated catalogs are in ../sdk/generated/
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - TODO: Move to src/sdk/generated/ and import here
|
|
11
|
-
*
|
|
12
|
-
* 2. CURATED KNOWLEDGE (Human-Maintained)
|
|
13
|
-
* - PLATFORM_CONCEPTS, WORKFLOW_PATTERNS, GUIDANCE_TOPICS, etc.
|
|
14
|
-
* - Source repos are INPUT, not law
|
|
15
|
-
* - Optimized for customer-facing MCP users
|
|
16
|
-
* - Updated via knowledge scanning workflow + human review
|
|
8
|
+
* Content:
|
|
9
|
+
* - PLATFORM_CONCEPTS, WORKFLOW_PATTERNS, GUIDANCE_TOPICS, etc. (human-maintained)
|
|
10
|
+
* - Helper functions (getAgentsByCategory, suggestAgentsForUseCase, etc.)
|
|
11
|
+
* - Workflow analysis functions (parseWorkflowDef, validateWorkflowConnections)
|
|
17
12
|
*
|
|
18
13
|
* Input Sources (for curated content):
|
|
19
14
|
* - ema-repos/ema/docs/ - Platform documentation
|
|
@@ -24,6 +19,13 @@
|
|
|
24
19
|
* See: .context/core/guides/source-repos.md for full architecture
|
|
25
20
|
*/
|
|
26
21
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
// Re-exports: Auto-Generated Catalogs (from sdk/generated/)
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
export { AGENT_CATALOG } from "../sdk/generated/agent-catalog.js";
|
|
25
|
+
import { AGENT_CATALOG } from "../sdk/generated/agent-catalog.js";
|
|
26
|
+
export { WIDGET_CATALOG } from "../sdk/generated/widget-catalog.js";
|
|
27
|
+
import { WIDGET_CATALOG } from "../sdk/generated/widget-catalog.js";
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
29
|
// Platform Concepts (from Ema User Guide)
|
|
28
30
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
31
|
export const PLATFORM_CONCEPTS = [
|
|
@@ -66,8 +68,8 @@ export const PLATFORM_CONCEPTS = [
|
|
|
66
68
|
term: "HITL",
|
|
67
69
|
definition: "Human-in-the-Loop. An approval/verification step where a human reviews before the workflow continues.",
|
|
68
70
|
aliases: ["Human Collaboration", "Approval Step", "Review Step"],
|
|
69
|
-
relatedTerms: ["
|
|
70
|
-
commonConfusions: "HITL
|
|
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.",
|
|
71
73
|
},
|
|
72
74
|
{
|
|
73
75
|
term: "Connector",
|
|
@@ -125,678 +127,6 @@ then route to "update ticket" instead of "create ticket"`,
|
|
|
125
127
|
},
|
|
126
128
|
},
|
|
127
129
|
};
|
|
128
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
129
|
-
// Agent Catalog
|
|
130
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
131
|
-
export const AGENT_CATALOG = [
|
|
132
|
-
// Triggers
|
|
133
|
-
{
|
|
134
|
-
actionName: "chat_trigger",
|
|
135
|
-
displayName: "Chat Trigger",
|
|
136
|
-
category: "trigger",
|
|
137
|
-
description: "Entry point for chat-based interactions. Outputs both conversation history and current query.",
|
|
138
|
-
inputs: [],
|
|
139
|
-
outputs: [
|
|
140
|
-
{ name: "chat_conversation", type: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", description: "Full conversation history from start" },
|
|
141
|
-
{ name: "user_query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Current user message only" },
|
|
142
|
-
],
|
|
143
|
-
whenToUse: "Starting point for any chat or voice AI workflow",
|
|
144
|
-
criticalRules: [
|
|
145
|
-
"Each user message triggers a NEW workflow execution",
|
|
146
|
-
"chat_conversation accumulates; user_query is current message only",
|
|
147
|
-
],
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
actionName: "document_trigger",
|
|
151
|
-
displayName: "Document Trigger",
|
|
152
|
-
category: "trigger",
|
|
153
|
-
description: "Entry point for document processing workflows triggered by file upload.",
|
|
154
|
-
inputs: [],
|
|
155
|
-
outputs: [
|
|
156
|
-
{ name: "user_query", type: "WELL_KNOWN_TYPE_DOCUMENT", description: "Uploaded document(s)" },
|
|
157
|
-
],
|
|
158
|
-
whenToUse: "When workflow is triggered by document upload for processing/extraction",
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
actionName: "voice_trigger",
|
|
162
|
-
displayName: "Voice Trigger",
|
|
163
|
-
category: "trigger",
|
|
164
|
-
description: "Entry point for voice/phone call interactions.",
|
|
165
|
-
inputs: [],
|
|
166
|
-
outputs: [
|
|
167
|
-
{ name: "chat_conversation", type: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", description: "Voice conversation history" },
|
|
168
|
-
{ name: "user_query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Current utterance" },
|
|
169
|
-
],
|
|
170
|
-
whenToUse: "Voice AI employees handling phone calls",
|
|
171
|
-
},
|
|
172
|
-
// Routing / Classification
|
|
173
|
-
{
|
|
174
|
-
actionName: "chat_categorizer",
|
|
175
|
-
displayName: "Intent Classifier",
|
|
176
|
-
category: "routing",
|
|
177
|
-
description: "Classifies user intent into predefined categories for routing. First routing node after trigger.",
|
|
178
|
-
inputs: [
|
|
179
|
-
{ name: "conversation", type: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", required: true, description: "Chat conversation to classify" },
|
|
180
|
-
],
|
|
181
|
-
outputs: [
|
|
182
|
-
{ name: "category", type: "WELL_KNOWN_TYPE_ENUM", description: "Outputs the matched category enum value (e.g., 'Client_Update', 'Fallback')" },
|
|
183
|
-
],
|
|
184
|
-
criticalRules: [
|
|
185
|
-
"MUST have at least one outgoing edge",
|
|
186
|
-
"runIf condition: compare 'output: category' to 'enumValue: <CategoryName>' (NOT category_<name> format)",
|
|
187
|
-
"Handler nodes use runIf conditions to route by category",
|
|
188
|
-
"ALWAYS include a Fallback category",
|
|
189
|
-
"Create a runIf condition for EACH category or routing fails",
|
|
190
|
-
"You MUST create a handler for EACH category",
|
|
191
|
-
],
|
|
192
|
-
whenToUse: "When you need to route chat conversations to different processing paths based on intent",
|
|
193
|
-
whenNotToUse: "Simple single-path workflows that don't need routing",
|
|
194
|
-
example: "Categories: [Market_Impact, Client_Lookup, Compliance_Check, Fallback]",
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
actionName: "text_categorizer",
|
|
198
|
-
displayName: "Text Categorizer",
|
|
199
|
-
category: "routing",
|
|
200
|
-
description: "Classifies text content (not conversation) into categories.",
|
|
201
|
-
inputs: [
|
|
202
|
-
{ name: "text", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Text to classify" },
|
|
203
|
-
],
|
|
204
|
-
outputs: [
|
|
205
|
-
{ name: "category", type: "WELL_KNOWN_TYPE_ENUM", description: "Classification result" },
|
|
206
|
-
],
|
|
207
|
-
criticalRules: [
|
|
208
|
-
"Same rules as chat_categorizer: must have Fallback, edges for each category",
|
|
209
|
-
],
|
|
210
|
-
whenToUse: "When routing based on text content rather than full conversation history",
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
actionName: "document_categorizer",
|
|
214
|
-
displayName: "Document Categorizer",
|
|
215
|
-
category: "routing",
|
|
216
|
-
description: "Classifies documents into categories for routing.",
|
|
217
|
-
inputs: [
|
|
218
|
-
{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Documents to classify" },
|
|
219
|
-
],
|
|
220
|
-
outputs: [
|
|
221
|
-
{ name: "category", type: "WELL_KNOWN_TYPE_ENUM", description: "Document classification" },
|
|
222
|
-
],
|
|
223
|
-
whenToUse: "When routing based on document type or content",
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
actionName: "conversation_to_search_query",
|
|
227
|
-
displayName: "Conversation Summarizer",
|
|
228
|
-
category: "routing",
|
|
229
|
-
description: "Converts conversation history to a search query. Configurable turn count.",
|
|
230
|
-
inputs: [
|
|
231
|
-
{ name: "conversation", type: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", required: true, description: "Conversation to summarize" },
|
|
232
|
-
],
|
|
233
|
-
outputs: [
|
|
234
|
-
{ name: "summarized_conversation", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Distilled search query" },
|
|
235
|
-
],
|
|
236
|
-
whenToUse: "Before search nodes when you have chat_conversation but need TEXT_WITH_SOURCES. Also for managing long conversation context windows.",
|
|
237
|
-
whenNotToUse: "When trigger.user_query is sufficient for simple queries",
|
|
238
|
-
criticalRules: [
|
|
239
|
-
"May still be needed WITH chat_conversation for downstream agents requiring specific format",
|
|
240
|
-
"Use to reduce conversation size due to LLM context window limits",
|
|
241
|
-
],
|
|
242
|
-
},
|
|
243
|
-
// Search & Retrieval
|
|
244
|
-
{
|
|
245
|
-
actionName: "search",
|
|
246
|
-
displayName: "File Search / Knowledge Search",
|
|
247
|
-
category: "search",
|
|
248
|
-
description: "Searches uploaded documents/knowledge base using hybrid search (keyword + vector). Use version v2 (search/v2) which requires datastore_configs input. search/v0 is deprecated.",
|
|
249
|
-
inputs: [
|
|
250
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Search query" },
|
|
251
|
-
{ name: "datastore_configs", type: "WELL_KNOWN_TYPE_ANY", required: false, description: "Datastore configuration (v2). Wired from persona widget config." },
|
|
252
|
-
],
|
|
253
|
-
outputs: [
|
|
254
|
-
{ name: "search_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", description: "Matching passages with sources and citations" },
|
|
255
|
-
],
|
|
256
|
-
whenToUse: "When searching static uploaded documents or internal knowledge base. Always use search/v2 (not deprecated search/v0).",
|
|
257
|
-
whenNotToUse: "For real-time web content — use live_web_search or ai_web_search instead",
|
|
258
|
-
example: "FAQ lookup, policy search, documentation assistant",
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
actionName: "live_web_search",
|
|
262
|
-
displayName: "Live Web Search / Deep Web Search",
|
|
263
|
-
category: "search",
|
|
264
|
-
description: "Real-time web search for external information not in knowledge base.",
|
|
265
|
-
inputs: [
|
|
266
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Search query" },
|
|
267
|
-
],
|
|
268
|
-
outputs: [
|
|
269
|
-
{ name: "web_search_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", description: "Web search results" },
|
|
270
|
-
],
|
|
271
|
-
whenToUse: "When you need real-time external information not in the knowledge base",
|
|
272
|
-
example: "Current events, live data, external research",
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
actionName: "combine_search_results",
|
|
276
|
-
displayName: "Combine Search Results",
|
|
277
|
-
category: "search",
|
|
278
|
-
description: "Merges results from multiple search sources with deduplication.",
|
|
279
|
-
inputs: [
|
|
280
|
-
{ name: "search_results_1", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", required: true, description: "First result set" },
|
|
281
|
-
{ name: "search_results_2", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", required: true, description: "Second result set" },
|
|
282
|
-
],
|
|
283
|
-
outputs: [
|
|
284
|
-
{ name: "combined_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", description: "Merged, deduplicated results" },
|
|
285
|
-
],
|
|
286
|
-
criticalRules: [
|
|
287
|
-
"AVOID using unless necessary - prefer combine_and_rerank_search_results or call_llm with named_inputs",
|
|
288
|
-
"combine_and_rerank_search_results provides intelligent relevance ranking",
|
|
289
|
-
"call_llm with named_inputs allows prompt-based ranking control",
|
|
290
|
-
],
|
|
291
|
-
whenToUse: "When combining local + web search, or multiple knowledge bases",
|
|
292
|
-
whenNotToUse: "When you need intelligent ranking - use combine_and_rerank_search_results instead",
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
actionName: "combine_and_rerank_search_results",
|
|
296
|
-
displayName: "Rerank Search Results",
|
|
297
|
-
category: "search",
|
|
298
|
-
description: "Combines and reranks search results by relevance.",
|
|
299
|
-
inputs: [
|
|
300
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Original query for relevance scoring" },
|
|
301
|
-
{ name: "search_results_lists", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", required: true, description: "Results to rerank" },
|
|
302
|
-
],
|
|
303
|
-
outputs: [
|
|
304
|
-
{ name: "reranked_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", description: "Reranked results" },
|
|
305
|
-
],
|
|
306
|
-
whenToUse: "When you need to prioritize results by relevance after combining multiple sources",
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
actionName: "document_metasearch",
|
|
310
|
-
displayName: "Document Metasearch",
|
|
311
|
-
category: "search",
|
|
312
|
-
description: "Searches across document metadata.",
|
|
313
|
-
inputs: [
|
|
314
|
-
{ name: "template", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Search template" },
|
|
315
|
-
],
|
|
316
|
-
outputs: [
|
|
317
|
-
{ name: "document_metasearch_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", description: "Metadata search results" },
|
|
318
|
-
],
|
|
319
|
-
whenToUse: "When searching by document metadata rather than content",
|
|
320
|
-
},
|
|
321
|
-
// Generation & Response
|
|
322
|
-
{
|
|
323
|
-
actionName: "call_llm",
|
|
324
|
-
displayName: "Respond",
|
|
325
|
-
category: "generation",
|
|
326
|
-
description: "Generates response using LLM with custom instructions. Accepts ANY type via named_inputs. Also used for LLM templating.",
|
|
327
|
-
inputs: [
|
|
328
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "User query" },
|
|
329
|
-
{ name: "named_inputs", type: "WELL_KNOWN_TYPE_ANY", required: false, description: "Additional context (use named_inputs_<Name> suffix)" },
|
|
330
|
-
],
|
|
331
|
-
outputs: [
|
|
332
|
-
{ name: "response_with_sources", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Generated response" },
|
|
333
|
-
],
|
|
334
|
-
whenToUse: "When you need custom response generation, content synthesis, or LLM templating for documents",
|
|
335
|
-
whenNotToUse: "For strict regulatory formats requiring pixel-perfect layouts - use template engine instead",
|
|
336
|
-
criticalRules: [
|
|
337
|
-
"named_inputs accepts ANY type - use for tool results, search results, etc.",
|
|
338
|
-
"Use suffix pattern: named_inputs_<Descriptive_Name>",
|
|
339
|
-
"LLM TEMPLATING: Include structured section headers (## Section) in prompt - let LLM determine appropriate sections based on content",
|
|
340
|
-
"For document generation: Set temperature 0.3-0.5 for consistent formatting",
|
|
341
|
-
"Use structured prompts with clear formatting rules and examples",
|
|
342
|
-
],
|
|
343
|
-
example: "named_inputs_Market_Context, named_inputs_Client_Data | " +
|
|
344
|
-
"LLM Template prompt: 'Generate structured content with clear ## section headers, organized by themes'",
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
actionName: "generate_document",
|
|
348
|
-
displayName: "Generate Document",
|
|
349
|
-
category: "generation",
|
|
350
|
-
description: "Converts markdown content to formatted document (.docx). Use after call_llm for document generation workflows.",
|
|
351
|
-
inputs: [
|
|
352
|
-
{ name: "markdown_file_contents", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Well-structured markdown to convert" },
|
|
353
|
-
{ name: "template", type: "WELL_KNOWN_TYPE_DOCUMENT", required: false, description: "Optional template from data source for styling" },
|
|
354
|
-
],
|
|
355
|
-
outputs: [
|
|
356
|
-
{ name: "document_link", type: "WELL_KNOWN_TYPE_DOCUMENT", description: "Link to generated document" },
|
|
357
|
-
],
|
|
358
|
-
whenToUse: "When converting LLM-generated markdown to professional document format",
|
|
359
|
-
criticalRules: [
|
|
360
|
-
"Ensure input markdown has clear headers (## Section) and structure",
|
|
361
|
-
"For email attachment: use named_inputs (not attachment_links) due to DOCUMENT type",
|
|
362
|
-
"Chain pattern: call_llm (content generation) → generate_document → send_email (via named_inputs)",
|
|
363
|
-
"Optional: Add CSS/styling in markdown for professional formatting",
|
|
364
|
-
],
|
|
365
|
-
example: "detailed_content (call_llm) → generate_doc → send_email.named_inputs_Attachment",
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
actionName: "respond_with_sources",
|
|
369
|
-
displayName: "Respond using Search Results",
|
|
370
|
-
category: "generation",
|
|
371
|
-
description: "Generates response grounded in search results with citations.",
|
|
372
|
-
inputs: [
|
|
373
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "User query" },
|
|
374
|
-
{ name: "search_results", type: "WELL_KNOWN_TYPE_SEARCH_RESULT", required: true, description: "Search results to ground response" },
|
|
375
|
-
],
|
|
376
|
-
outputs: [
|
|
377
|
-
{ name: "response_with_sources", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Response with citations" },
|
|
378
|
-
],
|
|
379
|
-
whenToUse: "When you want responses grounded in specific search results with source citations",
|
|
380
|
-
criticalRules: [
|
|
381
|
-
"Enable use_citation_based_filtering for trust",
|
|
382
|
-
"Implement confidence thresholds for quality control",
|
|
383
|
-
],
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
actionName: "respond_for_external_actions",
|
|
387
|
-
displayName: "Respond using Tool Result",
|
|
388
|
-
category: "generation",
|
|
389
|
-
description: "Generates response explaining external tool/action results.",
|
|
390
|
-
inputs: [
|
|
391
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Original query" },
|
|
392
|
-
{ name: "external_action_result", type: "WELL_KNOWN_TYPE_ANY", required: true, description: "Tool execution result" },
|
|
393
|
-
],
|
|
394
|
-
outputs: [
|
|
395
|
-
{ name: "response", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Human-friendly explanation" },
|
|
396
|
-
],
|
|
397
|
-
whenToUse: "After external_action_caller to explain results to user",
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
actionName: "fixed_response",
|
|
401
|
-
displayName: "Fixed Response",
|
|
402
|
-
category: "generation",
|
|
403
|
-
description: "Returns a static/template response with {{variable}} substitution. No LLM call.",
|
|
404
|
-
inputs: [
|
|
405
|
-
{ name: "named_inputs", type: "WELL_KNOWN_TYPE_ANY", required: false, description: "Variables to substitute into template (use named_inputs_<Variable_Name>)" },
|
|
406
|
-
{ name: "extracted_variables", type: "WELL_KNOWN_TYPE_ANY", required: false, description: "JSON key-value pairs for variable substitution" },
|
|
407
|
-
{ name: "fixed_response", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Template with {{variable_name}} placeholders" },
|
|
408
|
-
],
|
|
409
|
-
outputs: [
|
|
410
|
-
{ name: "fixed_response_with_sources", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Response with variables substituted" },
|
|
411
|
-
],
|
|
412
|
-
whenToUse: "For short, structured messages with variables: confirmations, acknowledgments, simple notifications",
|
|
413
|
-
whenNotToUse: "For complex templates - use data source templates with generate_document or fill_document_template instead",
|
|
414
|
-
criticalRules: [
|
|
415
|
-
"Use {{variable_name}} syntax for dynamic content (case-sensitive)",
|
|
416
|
-
"named_inputs takes precedence over extracted_variables when same variable name exists",
|
|
417
|
-
"Keep templates SHORT - for long emails/documents use data source templates",
|
|
418
|
-
"Variables must match exactly including case",
|
|
419
|
-
],
|
|
420
|
-
example: "Template: 'Dear {{Customer_Name}}, your order {{Order_ID}} has been {{Status}}.' " +
|
|
421
|
-
"→ Connect entity_extraction.customer_name to named_inputs_Customer_Name",
|
|
422
|
-
},
|
|
423
|
-
{
|
|
424
|
-
actionName: "send_email_agent",
|
|
425
|
-
displayName: "Send Email",
|
|
426
|
-
category: "external",
|
|
427
|
-
description: "Sends email via configured email provider.",
|
|
428
|
-
inputs: [
|
|
429
|
-
{ name: "email_to", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Recipient email address - use fixed_response with {{email}} template" },
|
|
430
|
-
{ name: "email_subject", type: "WELL_KNOWN_TYPE_ANY", required: false, description: "Email subject line" },
|
|
431
|
-
{ name: "email_body", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Email body content" },
|
|
432
|
-
{ name: "attachment_links", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: false, description: "Document links to attach (use named_inputs for DOCUMENT type)" },
|
|
433
|
-
],
|
|
434
|
-
outputs: [
|
|
435
|
-
{ name: "send_status", type: "WELL_KNOWN_TYPE_ANY", description: "Send confirmation" },
|
|
436
|
-
],
|
|
437
|
-
whenToUse: "When you need to send email after user confirmation",
|
|
438
|
-
criticalRules: [
|
|
439
|
-
"email_to requires TEXT_WITH_SOURCES type - use fixed_response with {{email}} template populated from entity_extraction",
|
|
440
|
-
"ALWAYS use HITL confirmation before sending (runIf: 'HITL Success')",
|
|
441
|
-
"For attachments with DOCUMENT type, use named_inputs instead of attachment_links",
|
|
442
|
-
"Never connect summarized_conversation or search_results directly to email_to",
|
|
443
|
-
],
|
|
444
|
-
example: "entity_extraction → fixed_response('{{email}}') → send_email.email_to (CORRECT pattern)",
|
|
445
|
-
},
|
|
446
|
-
// External Actions
|
|
447
|
-
{
|
|
448
|
-
actionName: "external_action_caller",
|
|
449
|
-
displayName: "External Tool Caller / Intelligent Actions",
|
|
450
|
-
category: "external",
|
|
451
|
-
description: "Calls external APIs/tools (ServiceNow, Salesforce, Workday, etc.).",
|
|
452
|
-
inputs: [
|
|
453
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Context for tool call" },
|
|
454
|
-
{ name: "conversation", type: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", required: false, description: "Conversation history" },
|
|
455
|
-
],
|
|
456
|
-
outputs: [
|
|
457
|
-
{ name: "tool_execution_result", type: "WELL_KNOWN_TYPE_ANY", description: "Tool execution result" },
|
|
458
|
-
],
|
|
459
|
-
whenToUse: "When you need to call external systems (create ticket, send email, lookup CRM, update records)",
|
|
460
|
-
criticalRules: [
|
|
461
|
-
"Check conversation history before creating records to avoid duplicates",
|
|
462
|
-
"Use HITL for actions with external side effects",
|
|
463
|
-
],
|
|
464
|
-
example: "ServiceNow ticket creation, Salesforce record update, Email sending",
|
|
465
|
-
},
|
|
466
|
-
// Entity & Rule Processing
|
|
467
|
-
{
|
|
468
|
-
actionName: "entity_extraction_with_documents",
|
|
469
|
-
displayName: "Entity Extraction",
|
|
470
|
-
category: "entity",
|
|
471
|
-
description: "Extracts structured entities from documents for cross-document linking or API calls.",
|
|
472
|
-
inputs: [
|
|
473
|
-
{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Documents to extract from" },
|
|
474
|
-
{ name: "extraction_columns", type: "WELL_KNOWN_TYPE_ANY", required: true, description: "Schema defining what to extract" },
|
|
475
|
-
],
|
|
476
|
-
outputs: [
|
|
477
|
-
{ name: "extraction_columns", type: "WELL_KNOWN_TYPE_ANY", description: "Extracted structured data" },
|
|
478
|
-
],
|
|
479
|
-
criticalRules: [
|
|
480
|
-
"Works on DOCUMENTS, not text",
|
|
481
|
-
"Requires schema definition for extraction columns",
|
|
482
|
-
],
|
|
483
|
-
whenToUse: "When you need structured data extraction for cross-document linking, API calls, or audit trails with citations",
|
|
484
|
-
whenNotToUse: "For simple conversational queries—use LLM resolution instead",
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
actionName: "rule_validation_with_documents",
|
|
488
|
-
displayName: "Rule Validation",
|
|
489
|
-
category: "validation",
|
|
490
|
-
description: "Validates extracted data against business rules. Rules are configured through the node's settings panel (UI), not via workflow_def inputs. Each rule has a name and description. Output mode is Pass/Fail per rule.",
|
|
491
|
-
inputs: [
|
|
492
|
-
{ name: "primary_docs", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Primary documents to validate against" },
|
|
493
|
-
{ name: "map_of_extracted_columns", type: "WELL_KNOWN_TYPE_ANY", required: true, description: "Extracted data from entity_extraction to validate" },
|
|
494
|
-
],
|
|
495
|
-
outputs: [
|
|
496
|
-
{ name: "ruleset_output", type: "WELL_KNOWN_TYPE_ANY", description: "Pass/Fail results per rule with explanations" },
|
|
497
|
-
],
|
|
498
|
-
whenToUse: "For compliance checks, business rule validation, threshold checking. Rules (e.g., 'Required Fields', 'Data Variance') are defined in the node's UI settings — the LLM only needs to wire inputs/outputs correctly.",
|
|
499
|
-
},
|
|
500
|
-
// Human Collaboration
|
|
501
|
-
// NOTE: general_hitl as a standalone workflow node is NOT currently recommended.
|
|
502
|
-
// HITL is implemented as a FLAG on specific agents (e.g., send_email_agent, external_action_caller).
|
|
503
|
-
// Kept here for reference when analyzing existing workflows that may use it.
|
|
504
|
-
{
|
|
505
|
-
actionName: "general_hitl",
|
|
506
|
-
displayName: "Human Collaboration (NOT RECOMMENDED — use agent flags instead)",
|
|
507
|
-
category: "collaboration",
|
|
508
|
-
description: "DEPRECATED for new workflows. HITL approval is now a flag on specific agents (send_email_agent, external_action_caller), not a separate workflow node. Do NOT add general_hitl nodes to new workflows.",
|
|
509
|
-
inputs: [
|
|
510
|
-
{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Context for review" },
|
|
511
|
-
],
|
|
512
|
-
outputs: [
|
|
513
|
-
{ name: "hitl_status_HITL Success", type: "WELL_KNOWN_TYPE_ANY", description: "Human approved path" },
|
|
514
|
-
{ name: "hitl_status_HITL Failure", type: "WELL_KNOWN_TYPE_ANY", description: "Human rejected path" },
|
|
515
|
-
],
|
|
516
|
-
criticalRules: [
|
|
517
|
-
"DO NOT use general_hitl in new workflows — use HITL flags on the agent that needs approval instead",
|
|
518
|
-
"If user asks for approval: enable the HITL flag on the relevant agent (e.g., send_email_agent, external_action_caller)",
|
|
519
|
-
"Existing workflows with general_hitl nodes will still function — no migration required",
|
|
520
|
-
"If you encounter general_hitl in an existing workflow: leave it, but don't add new ones",
|
|
521
|
-
],
|
|
522
|
-
whenToUse: "DO NOT USE for new workflows. HITL is a flag on agents, not a standalone node.",
|
|
523
|
-
example: "For approval: enable HITL flag on send_email_agent or external_action_caller",
|
|
524
|
-
},
|
|
525
|
-
// Validation & Guardrails
|
|
526
|
-
{
|
|
527
|
-
actionName: "response_validator",
|
|
528
|
-
displayName: "Response Validator",
|
|
529
|
-
category: "validation",
|
|
530
|
-
description: "Validates LLM output against criteria. Guardrail for response quality.",
|
|
531
|
-
inputs: [
|
|
532
|
-
{ name: "reference_query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Original query" },
|
|
533
|
-
{ name: "response_to_validate", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Response to check" },
|
|
534
|
-
],
|
|
535
|
-
outputs: [
|
|
536
|
-
{ name: "abstain_reason", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Reason if validation fails" },
|
|
537
|
-
],
|
|
538
|
-
whenToUse: "For guardrails, compliance checking on generated responses, quality control",
|
|
539
|
-
},
|
|
540
|
-
{
|
|
541
|
-
actionName: "abstain_action",
|
|
542
|
-
displayName: "Abstain from Answering",
|
|
543
|
-
category: "validation",
|
|
544
|
-
description: "Declines to answer when appropriate. Graceful handling of out-of-scope queries.",
|
|
545
|
-
inputs: [
|
|
546
|
-
{ name: "abstain_reason", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Why abstaining" },
|
|
547
|
-
],
|
|
548
|
-
outputs: [
|
|
549
|
-
{ name: "abstain_reason", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Abstention message" },
|
|
550
|
-
],
|
|
551
|
-
whenToUse: "When the AI should explicitly decline to answer or redirect",
|
|
552
|
-
},
|
|
553
|
-
// Sentiment & Analysis
|
|
554
|
-
{
|
|
555
|
-
actionName: "sentiment_analyzer",
|
|
556
|
-
displayName: "Sentiment Analyzer",
|
|
557
|
-
category: "analytics",
|
|
558
|
-
description: "Analyzes sentiment/emotion in user input.",
|
|
559
|
-
inputs: [
|
|
560
|
-
{ name: "text", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Text to analyze" },
|
|
561
|
-
],
|
|
562
|
-
outputs: [
|
|
563
|
-
{ name: "sentiment", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Sentiment analysis" },
|
|
564
|
-
],
|
|
565
|
-
whenToUse: "When you need to gauge user emotion for routing or response tone adjustment",
|
|
566
|
-
},
|
|
567
|
-
// Domain Agents - Finance
|
|
568
|
-
{
|
|
569
|
-
actionName: "financial_risk_assessor",
|
|
570
|
-
displayName: "Financial Risk Assessor",
|
|
571
|
-
category: "finance",
|
|
572
|
-
description: "Analyzes financial risk factors for investment/credit decisions.",
|
|
573
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Risk query" }],
|
|
574
|
-
outputs: [{ name: "risk_assessment", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Risk analysis" }],
|
|
575
|
-
whenToUse: "Financial services: portfolio risk, credit assessment, exposure analysis",
|
|
576
|
-
},
|
|
577
|
-
{
|
|
578
|
-
actionName: "financial_statement_analyzer",
|
|
579
|
-
displayName: "Financial Statement Analyzer",
|
|
580
|
-
category: "finance",
|
|
581
|
-
description: "Analyzes financial statements and reports.",
|
|
582
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Financial documents" }],
|
|
583
|
-
outputs: [{ name: "analysis", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Financial analysis" }],
|
|
584
|
-
whenToUse: "Analyzing P&L, balance sheets, annual reports",
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
actionName: "tax_advisor",
|
|
588
|
-
displayName: "Tax Advisor",
|
|
589
|
-
category: "finance",
|
|
590
|
-
description: "Provides tax-related guidance and analysis.",
|
|
591
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Tax question" }],
|
|
592
|
-
outputs: [{ name: "tax_advice", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Tax guidance" }],
|
|
593
|
-
whenToUse: "Tax planning, compliance questions, deduction analysis",
|
|
594
|
-
},
|
|
595
|
-
{
|
|
596
|
-
actionName: "audit_evidence_verifier",
|
|
597
|
-
displayName: "Audit Evidence Verifier",
|
|
598
|
-
category: "finance",
|
|
599
|
-
description: "Verifies audit evidence and documentation.",
|
|
600
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Audit documents" }],
|
|
601
|
-
outputs: [{ name: "verification", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Verification results" }],
|
|
602
|
-
whenToUse: "Audit support, evidence verification, compliance documentation",
|
|
603
|
-
},
|
|
604
|
-
// Domain Agents - Healthcare
|
|
605
|
-
{
|
|
606
|
-
actionName: "medical_record_summarizer",
|
|
607
|
-
displayName: "Medical Record Summarizer",
|
|
608
|
-
category: "healthcare",
|
|
609
|
-
description: "Summarizes medical records and patient history.",
|
|
610
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Medical records" }],
|
|
611
|
-
outputs: [{ name: "summary", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Record summary" }],
|
|
612
|
-
whenToUse: "Healthcare: summarizing patient records, medical history, clinical notes",
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
actionName: "medical_research_assistant",
|
|
616
|
-
displayName: "Medical Research Assistant",
|
|
617
|
-
category: "healthcare",
|
|
618
|
-
description: "Assists with medical research queries.",
|
|
619
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Research query" }],
|
|
620
|
-
outputs: [{ name: "research", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Research findings" }],
|
|
621
|
-
whenToUse: "Medical research, literature review, clinical guidance",
|
|
622
|
-
},
|
|
623
|
-
{
|
|
624
|
-
actionName: "insurance_claim_summarizer",
|
|
625
|
-
displayName: "Insurance Claim Summarizer",
|
|
626
|
-
category: "healthcare",
|
|
627
|
-
description: "Summarizes insurance claims and documentation.",
|
|
628
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Claim documents" }],
|
|
629
|
-
outputs: [{ name: "summary", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Claim summary" }],
|
|
630
|
-
whenToUse: "Insurance processing, claim analysis",
|
|
631
|
-
},
|
|
632
|
-
// Domain Agents - Legal
|
|
633
|
-
{
|
|
634
|
-
actionName: "compliance_document_analyzer",
|
|
635
|
-
displayName: "Compliance Document Analyzer",
|
|
636
|
-
category: "legal",
|
|
637
|
-
description: "Analyzes documents for compliance issues.",
|
|
638
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Documents to analyze" }],
|
|
639
|
-
outputs: [{ name: "compliance_findings", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Compliance analysis" }],
|
|
640
|
-
whenToUse: "Regulatory compliance, contract review, policy compliance",
|
|
641
|
-
},
|
|
642
|
-
{
|
|
643
|
-
actionName: "legal_expert",
|
|
644
|
-
displayName: "Legal Expert",
|
|
645
|
-
category: "legal",
|
|
646
|
-
description: "Provides legal analysis and guidance.",
|
|
647
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Legal question" }],
|
|
648
|
-
outputs: [{ name: "legal_analysis", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Legal guidance" }],
|
|
649
|
-
whenToUse: "Legal research, contract analysis, regulatory questions",
|
|
650
|
-
},
|
|
651
|
-
{
|
|
652
|
-
actionName: "information_redacter",
|
|
653
|
-
displayName: "Information Redacter",
|
|
654
|
-
category: "legal",
|
|
655
|
-
description: "Redacts sensitive information from documents.",
|
|
656
|
-
inputs: [{ name: "documents", type: "WELL_KNOWN_TYPE_DOCUMENT", required: true, description: "Documents to redact" }],
|
|
657
|
-
outputs: [{ name: "redacted", type: "WELL_KNOWN_TYPE_DOCUMENT", description: "Redacted documents" }],
|
|
658
|
-
whenToUse: "Privacy compliance, document sanitization",
|
|
659
|
-
},
|
|
660
|
-
// Domain Agents - IT/Security
|
|
661
|
-
{
|
|
662
|
-
actionName: "phishing_email_detector",
|
|
663
|
-
displayName: "Phishing Email Detector",
|
|
664
|
-
category: "it_security",
|
|
665
|
-
description: "Detects phishing attempts in emails.",
|
|
666
|
-
inputs: [{ name: "email_content", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Email to analyze" }],
|
|
667
|
-
outputs: [{ name: "detection_result", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Phishing analysis" }],
|
|
668
|
-
whenToUse: "Email security, security operations",
|
|
669
|
-
},
|
|
670
|
-
{
|
|
671
|
-
actionName: "cybersecurity_expert",
|
|
672
|
-
displayName: "Cybersecurity Expert",
|
|
673
|
-
category: "it_security",
|
|
674
|
-
description: "Provides cybersecurity analysis and guidance.",
|
|
675
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Security query" }],
|
|
676
|
-
outputs: [{ name: "security_analysis", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Security guidance" }],
|
|
677
|
-
whenToUse: "Security incident analysis, vulnerability assessment",
|
|
678
|
-
},
|
|
679
|
-
{
|
|
680
|
-
actionName: "technical_support",
|
|
681
|
-
displayName: "Technical Support",
|
|
682
|
-
category: "it_security",
|
|
683
|
-
description: "Provides IT technical support guidance.",
|
|
684
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Support query" }],
|
|
685
|
-
outputs: [{ name: "support_response", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Technical guidance" }],
|
|
686
|
-
whenToUse: "IT helpdesk, troubleshooting, technical guidance",
|
|
687
|
-
},
|
|
688
|
-
// Domain Agents - Sales
|
|
689
|
-
{
|
|
690
|
-
actionName: "sales_intelligence",
|
|
691
|
-
displayName: "Sales Intelligence",
|
|
692
|
-
category: "sales",
|
|
693
|
-
description: "Provides sales insights and account intelligence.",
|
|
694
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Sales query" }],
|
|
695
|
-
outputs: [{ name: "intelligence", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Sales insights" }],
|
|
696
|
-
whenToUse: "Account research, competitive analysis, opportunity assessment",
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
actionName: "email_writer",
|
|
700
|
-
displayName: "Email Writer",
|
|
701
|
-
category: "sales",
|
|
702
|
-
description: "Generates professional email content.",
|
|
703
|
-
inputs: [{ name: "query", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Email context" }],
|
|
704
|
-
outputs: [{ name: "email", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Generated email" }],
|
|
705
|
-
whenToUse: "Sales outreach, customer communication, follow-ups",
|
|
706
|
-
},
|
|
707
|
-
// Formatting Agents
|
|
708
|
-
{
|
|
709
|
-
actionName: "json_formatter",
|
|
710
|
-
displayName: "JSON Formatter",
|
|
711
|
-
category: "formatting",
|
|
712
|
-
description: "Formats output as JSON.",
|
|
713
|
-
inputs: [{ name: "content", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Content to format" }],
|
|
714
|
-
outputs: [{ name: "json", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "JSON formatted output" }],
|
|
715
|
-
whenToUse: "When structured JSON output is required",
|
|
716
|
-
},
|
|
717
|
-
{
|
|
718
|
-
actionName: "json_extractor",
|
|
719
|
-
displayName: "JSON Extractor",
|
|
720
|
-
category: "formatting",
|
|
721
|
-
description: "Extracts JSON from LLM output.",
|
|
722
|
-
inputs: [{ name: "content", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Content containing JSON" }],
|
|
723
|
-
outputs: [{ name: "extracted_json", type: "WELL_KNOWN_TYPE_ANY", description: "Extracted JSON object" }],
|
|
724
|
-
whenToUse: "When you need to parse JSON from LLM responses",
|
|
725
|
-
},
|
|
726
|
-
{
|
|
727
|
-
actionName: "markdown_formatter",
|
|
728
|
-
displayName: "Markdown Formatter",
|
|
729
|
-
category: "formatting",
|
|
730
|
-
description: "Formats output as Markdown.",
|
|
731
|
-
inputs: [{ name: "content", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", required: true, description: "Content to format" }],
|
|
732
|
-
outputs: [{ name: "markdown", type: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", description: "Markdown formatted output" }],
|
|
733
|
-
whenToUse: "When rich text formatting is needed",
|
|
734
|
-
},
|
|
735
|
-
];
|
|
736
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
737
|
-
// Widget Reference
|
|
738
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
739
|
-
// ═══════════════════════════════════════════════════════════════════════════════════
|
|
740
|
-
// WIDGET_CATALOG (NO API ALTERNATIVE - Intentionally Static)
|
|
741
|
-
// ═══════════════════════════════════════════════════════════════════════════════════
|
|
742
|
-
//
|
|
743
|
-
// WHY STATIC: There is no API endpoint to list widget definitions. Widget metadata
|
|
744
|
-
// lives in persona template YAML files and is not exposed via the API.
|
|
745
|
-
//
|
|
746
|
-
// RUNTIME ALTERNATIVE: For a specific persona, fetch widgets dynamically via:
|
|
747
|
-
// persona(id="...", include_workflow=true) → proto_config.widgets[].name
|
|
748
|
-
//
|
|
749
|
-
// SOURCE: ema-repos/ema/ema_backend/db/system_values/persona_templates/prod/*.yaml
|
|
750
|
-
// SYNC: Manual - run knowledge scan workflow to detect template changes
|
|
751
|
-
//
|
|
752
|
-
// TECHNICAL NOTES:
|
|
753
|
-
// - Widget 'id' is the WidgetType enum value from protos
|
|
754
|
-
// - Widget 'name' is assigned per-template (e.g., "upload", "upload1", "upload2")
|
|
755
|
-
// - Proto 'case' values represent TYPE discriminators, not widget names
|
|
756
|
-
//
|
|
757
|
-
// See .context/core/guides/source-repos.md for full sync instructions
|
|
758
|
-
// ═══════════════════════════════════════════════════════════════════════════════════
|
|
759
|
-
export const WIDGET_CATALOG = [
|
|
760
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
761
|
-
// Voice AI Widgets
|
|
762
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
763
|
-
// SOURCE: voicebot_ai_employee.yaml
|
|
764
|
-
// LAST VERIFIED: 2026-01-27
|
|
765
|
-
{ id: 38, name: "voiceSettings", description: "Language hints, voice model selection (title: 'Voice and language')", requiredFor: ["voice"], fields: ["languageHints", "voiceModel"] },
|
|
766
|
-
{ id: 39, name: "conversationSettings", description: "Identity, purpose, action instructions, hangup rules (title: 'Conversational behavior')", requiredFor: ["voice"], fields: ["welcomeMessage", "identityAndPurpose", "takeActionInstructions", "hangupInstructions", "transferCallInstructions", "speechCharacteristics", "systemPrompt", "formFillingInstructions", "waitMessage"] },
|
|
767
|
-
{ id: 43, name: "vadSettings", description: "Voice activity detection settings", requiredFor: ["voice"], fields: ["turnTimeout", "silenceEndCallTimeout", "maxConversationDuration"] },
|
|
768
|
-
{ id: 42, name: "dataStorageSettings", description: "Audio/transcript recording settings", requiredFor: ["voice"], fields: ["storeAudioRecording", "storeTranscripts", "storeAgentTranscript"] },
|
|
769
|
-
{ id: 41, name: "callSettings", description: "Call forwarding, spam prevention settings", requiredFor: ["voice"], fields: ["enableCallForwarding", "callForwardingNumber", "enableSpamCallPrevention"] },
|
|
770
|
-
{ id: 44, name: "voicebotPhoneNumber", description: "Phone number configuration (title: 'Phone numbers')", requiredFor: ["voice"], fields: ["phoneNumber"] },
|
|
771
|
-
{ id: 40, name: "voicebotFeedbackCollection", description: "Post-call feedback collection (title: 'Feedback collection')", requiredFor: ["voice"], fields: [] },
|
|
772
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
773
|
-
// Chat AI Widgets
|
|
774
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
775
|
-
// SOURCE: TBD - need to verify from chat template
|
|
776
|
-
{ id: 28, name: "chatbotSdkConfig", description: "Chat widget configuration and theming", requiredFor: ["chat"], fields: ["theme", "position", "initialMessage"] },
|
|
777
|
-
{ id: 33, name: "feedbackMessage", description: "Feedback collection settings", requiredFor: ["chat"], fields: ["enabled", "prompt"] },
|
|
778
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
779
|
-
// Document Generation Widgets
|
|
780
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
781
|
-
// SOURCE: ema-repos/ema/ema_backend/db/system_values/persona_templates/prod/document_proposal_manager.yaml
|
|
782
|
-
// NOTE: Widget names are defined per-template. These are from Document Proposal Manager.
|
|
783
|
-
// To sync: see .context/core/guides/source-repos.md
|
|
784
|
-
// LAST VERIFIED: 2026-01-27 from document_proposal_manager.yaml
|
|
785
|
-
{ id: 3, name: "upload", description: "Content Repository - gold standard company docs (title: 'Content Repository')", requiredFor: ["document"], fields: ["tags"], uploadTarget: true },
|
|
786
|
-
{ id: 3, name: "upload1", description: "Service Line Documents - business unit specific content (title: 'Service Line Documents')", requiredFor: ["document"], fields: ["tags"], uploadTarget: true },
|
|
787
|
-
{ id: 3, name: "upload2", description: "Style Guide - formatting and tone guide (title: 'Style Guide')", requiredFor: ["document"], fields: ["tags"], uploadTarget: true },
|
|
788
|
-
{ id: 29, name: "fileTagging0", description: "File tagging configuration (title: 'Set Tags')", requiredFor: ["document"], fields: ["tagTypes", "fileTagMappings"] },
|
|
789
|
-
{ id: 5, name: "answerFormat0", description: "Proposal instructions - format, tone, language (title: 'Proposal Instructions')", requiredFor: ["document"], fields: ["textValue"] },
|
|
790
|
-
{ id: 16, name: "sectionConfigWidget", description: "Section categories with instructions (title: 'Section Categories')", requiredFor: ["document"], fields: ["sections"] },
|
|
791
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
792
|
-
// Common Widgets (all types)
|
|
793
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
794
|
-
// These appear across multiple template types
|
|
795
|
-
{ id: 3, name: "fileUpload", description: "Default document upload (KB files, title: 'Data sources')", requiredFor: ["voice", "chat", "dashboard"], fields: ["allowedTypes", "maxSize"], uploadTarget: true },
|
|
796
|
-
{ id: 6, name: "fusionModel", description: "EmaFusion model selection (GPT-4, Claude, etc., title: 'EmaFusion™ model')", requiredFor: ["voice", "chat", "dashboard", "document"], fields: ["allModels", "selectedModels"] },
|
|
797
|
-
{ id: 8, name: "dataProtection", description: "PII redaction settings", requiredFor: ["voice", "chat", "dashboard", "document"], fields: ["protectedClasses"] },
|
|
798
|
-
{ id: 9, name: "copyrightCheck", description: "Copyright infringement checker (title: 'Copyright Checker')", requiredFor: ["document"], fields: [] },
|
|
799
|
-
];
|
|
800
130
|
// Project type mapping
|
|
801
131
|
export const PROJECT_TYPES = {
|
|
802
132
|
voice: 5,
|
|
@@ -813,7 +143,6 @@ export const PROJECT_TYPES = {
|
|
|
813
143
|
// SYNC: TODO - Add to catalog-sync.yml workflow for automatic updates
|
|
814
144
|
//
|
|
815
145
|
// Other type compatibility definitions serve different purposes:
|
|
816
|
-
// - INTENT_TYPE_ROUTING (workflow-intent.ts) - routing logic during intent processing
|
|
817
146
|
// - SCHEMA_TYPE_COMPATIBILITY (action-schema-parser.ts) - input name matching for validation
|
|
818
147
|
//
|
|
819
148
|
// See .context/core/guides/source-repos.md for full architecture
|
|
@@ -829,7 +158,7 @@ export const TYPE_COMPATIBILITY = [
|
|
|
829
158
|
{ sourceType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", targetType: "WELL_KNOWN_TYPE_CHAT_CONVERSATION", compatible: false, note: "Cannot convert text to conversation" },
|
|
830
159
|
// Search result compatibility
|
|
831
160
|
{ sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_SEARCH_RESULT", compatible: true },
|
|
832
|
-
{ sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES", compatible: false, note: "Use
|
|
161
|
+
{ 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) for search results" },
|
|
833
162
|
{ sourceType: "WELL_KNOWN_TYPE_SEARCH_RESULT", targetType: "WELL_KNOWN_TYPE_ANY", compatible: true, note: "call_llm.named_inputs accepts ANY" },
|
|
834
163
|
// Document compatibility
|
|
835
164
|
{ sourceType: "WELL_KNOWN_TYPE_DOCUMENT", targetType: "WELL_KNOWN_TYPE_DOCUMENT", compatible: true },
|
|
@@ -846,13 +175,14 @@ export const WORKFLOW_PATTERNS = [
|
|
|
846
175
|
name: "simple-kb-search",
|
|
847
176
|
personaType: "chat",
|
|
848
177
|
description: "Basic knowledge base Q&A with search and response",
|
|
849
|
-
nodes: ["chat_trigger", "conversation_to_search_query", "search", "
|
|
178
|
+
nodes: ["chat_trigger", "conversation_to_search_query", "search", "respond_for_external_actions"],
|
|
850
179
|
connections: [
|
|
851
180
|
"chat_trigger.chat_conversation → conversation_to_search_query.conversation",
|
|
852
181
|
"conversation_to_search_query.summarized_conversation → search.query",
|
|
853
|
-
"search.search_results →
|
|
854
|
-
"chat_trigger.user_query →
|
|
855
|
-
"
|
|
182
|
+
"search.search_results → respond_for_external_actions.external_action_result",
|
|
183
|
+
"chat_trigger.user_query → respond_for_external_actions.query",
|
|
184
|
+
"chat_trigger.chat_conversation → respond_for_external_actions.conversation",
|
|
185
|
+
"respond_for_external_actions.response → WORKFLOW_OUTPUT",
|
|
856
186
|
],
|
|
857
187
|
useCase: "FAQ bot, documentation assistant, policy lookup",
|
|
858
188
|
},
|
|
@@ -874,22 +204,25 @@ export const WORKFLOW_PATTERNS = [
|
|
|
874
204
|
"Missing Fallback category",
|
|
875
205
|
"Categories without outgoing edges",
|
|
876
206
|
"Not all paths leading to WORKFLOW_OUTPUT",
|
|
207
|
+
"Only one gated respond node wired to WORKFLOW_OUTPUT while others are silently lost",
|
|
208
|
+
"Duplicate identical call_llm nodes differing only by trigger_when — consolidate into one with category as named_input",
|
|
877
209
|
],
|
|
878
210
|
},
|
|
879
211
|
{
|
|
880
212
|
name: "multi-source-search",
|
|
881
213
|
personaType: "chat",
|
|
882
214
|
description: "Combine local and web search for comprehensive answers",
|
|
883
|
-
nodes: ["chat_trigger", "conversation_to_search_query", "search", "live_web_search", "combine_search_results", "
|
|
215
|
+
nodes: ["chat_trigger", "conversation_to_search_query", "search", "live_web_search", "combine_search_results", "respond_for_external_actions"],
|
|
884
216
|
connections: [
|
|
885
217
|
"chat_trigger.chat_conversation → conversation_to_search_query.conversation",
|
|
886
218
|
"conversation_to_search_query.summarized_conversation → search.query",
|
|
887
219
|
"conversation_to_search_query.summarized_conversation → live_web_search.query",
|
|
888
220
|
"search.search_results → combine_search_results.search_results_1",
|
|
889
221
|
"live_web_search.web_search_results → combine_search_results.search_results_2",
|
|
890
|
-
"combine_search_results.combined_results →
|
|
891
|
-
"chat_trigger.user_query →
|
|
892
|
-
"
|
|
222
|
+
"combine_search_results.combined_results → respond_for_external_actions.external_action_result",
|
|
223
|
+
"chat_trigger.user_query → respond_for_external_actions.query",
|
|
224
|
+
"chat_trigger.chat_conversation → respond_for_external_actions.conversation",
|
|
225
|
+
"respond_for_external_actions.response → WORKFLOW_OUTPUT",
|
|
893
226
|
],
|
|
894
227
|
useCase: "Research assistant needing both internal docs and current web info",
|
|
895
228
|
},
|
|
@@ -915,32 +248,35 @@ export const WORKFLOW_PATTERNS = [
|
|
|
915
248
|
{
|
|
916
249
|
name: "hitl-approval",
|
|
917
250
|
personaType: "chat",
|
|
918
|
-
description: "Human-in-the-loop approval —
|
|
919
|
-
nodes: ["chat_trigger", "
|
|
251
|
+
description: "Human-in-the-loop approval — enable HITL flag on send_email_agent or entity_extraction_with_documents (only nodes that support HITL)",
|
|
252
|
+
nodes: ["chat_trigger", "send_email_agent (with HITL flag)", "respond_for_external_actions"],
|
|
920
253
|
connections: [
|
|
921
254
|
"chat_trigger.user_query → external_action_caller.query",
|
|
922
255
|
"chat_trigger.chat_conversation → external_action_caller.conversation",
|
|
923
256
|
"external_action_caller.tool_execution_result → respond_for_external_actions.external_action_result",
|
|
924
257
|
"chat_trigger.user_query → respond_for_external_actions.query",
|
|
258
|
+
"chat_trigger.chat_conversation → respond_for_external_actions.conversation",
|
|
925
259
|
"respond_for_external_actions.response → WORKFLOW_OUTPUT",
|
|
926
260
|
],
|
|
927
|
-
useCase: "High-value transactions, sensitive operations — enable HITL flag on
|
|
261
|
+
useCase: "High-value transactions, sensitive operations — enable HITL flag on send_email_agent or entity_extraction_with_documents",
|
|
928
262
|
antiPatterns: [
|
|
929
|
-
"Adding general_hitl as a standalone node (
|
|
263
|
+
"Adding general_hitl as a standalone node (it is NOT deployable)",
|
|
930
264
|
"Not wiring conversation context to response node",
|
|
931
265
|
],
|
|
932
266
|
},
|
|
933
267
|
{
|
|
934
268
|
name: "document-processing",
|
|
935
269
|
personaType: "dashboard",
|
|
936
|
-
description: "Document upload → extraction → validation →
|
|
270
|
+
description: "Document upload → extraction → validation → analysis (results as dashboard columns)",
|
|
937
271
|
nodes: ["document_trigger", "entity_extraction_with_documents", "rule_validation_with_documents", "call_llm"],
|
|
938
272
|
connections: [
|
|
939
|
-
"
|
|
273
|
+
"workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
|
|
940
274
|
"entity_extraction_with_documents.extraction_columns → rule_validation_with_documents.map_of_extracted_columns",
|
|
941
|
-
"
|
|
275
|
+
"workflowInput.document-mmf2 → rule_validation_with_documents.primary_docs",
|
|
942
276
|
"rule_validation_with_documents.ruleset_output → call_llm.named_inputs_Validation_Results",
|
|
943
|
-
"
|
|
277
|
+
"entity_extraction_node.extraction_columns → results (dot-notation key)",
|
|
278
|
+
"rule_validation_node.ruleset_output → results (dot-notation key)",
|
|
279
|
+
"call_llm.llm_output → results (dot-notation key)",
|
|
944
280
|
],
|
|
945
281
|
useCase: "Invoice processing, contract analysis, compliance checking",
|
|
946
282
|
},
|
|
@@ -950,12 +286,13 @@ export const WORKFLOW_PATTERNS = [
|
|
|
950
286
|
description: "Document upload → extraction → email notification (with intermediary for type conversion)",
|
|
951
287
|
nodes: ["document_trigger", "entity_extraction_with_documents", "json_mapper", "fixed_response", "send_email_agent", "call_llm"],
|
|
952
288
|
connections: [
|
|
953
|
-
"
|
|
289
|
+
"workflowInput.document-mmf2 → entity_extraction_with_documents.documents",
|
|
954
290
|
"entity_extraction_with_documents.extraction_columns → json_mapper.input_json",
|
|
955
291
|
"json_mapper.output_json → fixed_response.named_inputs_Extracted_Data (template: '{{to}}', '{{subject}}', etc.)",
|
|
956
292
|
"fixed_response.response → send_email_agent.email_to (one fixed_response per email field)",
|
|
957
293
|
"send_email_agent.confirmation → call_llm.named_inputs_Email_Result",
|
|
958
|
-
"
|
|
294
|
+
"entity_extraction_node.extraction_columns → results (dot-notation key)",
|
|
295
|
+
"call_llm.llm_output → results (dot-notation key)",
|
|
959
296
|
],
|
|
960
297
|
useCase: "Invoice receipt notification, contract alerts, document-triggered emails",
|
|
961
298
|
antiPatterns: [
|
|
@@ -968,17 +305,60 @@ export const WORKFLOW_PATTERNS = [
|
|
|
968
305
|
name: "guardrails-pattern",
|
|
969
306
|
personaType: "chat",
|
|
970
307
|
description: "Response generation with validation guardrails",
|
|
971
|
-
nodes: ["chat_trigger", "search", "
|
|
308
|
+
nodes: ["chat_trigger", "search", "respond_for_external_actions", "response_validator", "abstain_action"],
|
|
972
309
|
connections: [
|
|
973
310
|
"chat_trigger.user_query → search.query",
|
|
974
|
-
"search.search_results →
|
|
975
|
-
"
|
|
311
|
+
"search.search_results → respond_for_external_actions.external_action_result",
|
|
312
|
+
"chat_trigger.chat_conversation → respond_for_external_actions.conversation",
|
|
313
|
+
"respond_for_external_actions.response → response_validator.response_to_validate",
|
|
976
314
|
"chat_trigger.user_query → response_validator.reference_query",
|
|
977
315
|
"response_validator.abstain_reason → [conditional: if valid] → WORKFLOW_OUTPUT",
|
|
978
316
|
"response_validator.abstain_reason → [conditional: if invalid] → abstain_action → WORKFLOW_OUTPUT",
|
|
979
317
|
],
|
|
980
318
|
useCase: "Regulated industries, compliance-sensitive responses",
|
|
981
319
|
},
|
|
320
|
+
{
|
|
321
|
+
name: "externalized-instructions",
|
|
322
|
+
personaType: "chat",
|
|
323
|
+
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.",
|
|
324
|
+
nodes: ["chat_trigger", "conversation_to_search_query", "search", "respond_for_external_actions"],
|
|
325
|
+
connections: [
|
|
326
|
+
"chat_trigger.chat_conversation → conversation_to_search_query.conversation",
|
|
327
|
+
"conversation_to_search_query.summarized_conversation → search.query",
|
|
328
|
+
"search.search_results → respond_for_external_actions.external_action_result (instructions + knowledge combined)",
|
|
329
|
+
"chat_trigger.user_query → respond_for_external_actions.query",
|
|
330
|
+
"chat_trigger.chat_conversation → respond_for_external_actions.conversation",
|
|
331
|
+
"respond_for_external_actions.response → WORKFLOW_OUTPUT",
|
|
332
|
+
],
|
|
333
|
+
useCase: "When instructions change frequently, when multiple teams maintain different policies, when A/B testing response styles",
|
|
334
|
+
antiPatterns: [
|
|
335
|
+
"Hardcoding all instructions in node prompt (requires workflow redeploy to change behavior)",
|
|
336
|
+
"Not connecting search results to extraction nodes that also need instructions",
|
|
337
|
+
"Mixing instruction documents with knowledge documents without clear separation",
|
|
338
|
+
],
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: "consolidated-intent-routing",
|
|
342
|
+
personaType: "chat",
|
|
343
|
+
description: "Single respond node handles all intents by receiving the category as a named_input. Reduces duplication vs. having separate respond nodes per intent.",
|
|
344
|
+
nodes: ["chat_trigger", "chat_categorizer", "search", "call_llm", "fixed_response"],
|
|
345
|
+
connections: [
|
|
346
|
+
"chat_trigger.chat_conversation → chat_categorizer.conversation",
|
|
347
|
+
"chat_trigger.user_query → search.query (always runs, not gated)",
|
|
348
|
+
"chat_categorizer.category → call_llm.named_inputs_Intent",
|
|
349
|
+
"search.search_results → call_llm.named_inputs_Search_Results",
|
|
350
|
+
"chat_trigger.chat_conversation → call_llm.named_inputs_Conversation",
|
|
351
|
+
"chat_trigger.user_query → call_llm.query",
|
|
352
|
+
"call_llm.response_with_sources → WORKFLOW_OUTPUT (runIf: category != Fallback)",
|
|
353
|
+
"fixed_response.response → WORKFLOW_OUTPUT (runIf: category == Fallback)",
|
|
354
|
+
],
|
|
355
|
+
useCase: "Multi-intent assistant where all intents share similar response style, search sources, and safety constraints",
|
|
356
|
+
antiPatterns: [
|
|
357
|
+
"Using this when intents need different tools or actions (use separate nodes instead)",
|
|
358
|
+
"Forgetting to pass the category as named_input (LLM won't know which intent to address)",
|
|
359
|
+
"Not gating fallback separately (fixed_response should handle fallback, not the LLM)",
|
|
360
|
+
],
|
|
361
|
+
},
|
|
982
362
|
];
|
|
983
363
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
984
364
|
// Qualifying Questions
|
|
@@ -996,7 +376,7 @@ export const QUALIFYING_QUESTIONS = [
|
|
|
996
376
|
{ 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 },
|
|
997
377
|
{ 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 },
|
|
998
378
|
{ 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 },
|
|
999
|
-
{ category: "Actions", question: "Which actions require human approval?", whyItMatters: "Enable HITL flag on the relevant agent (send_email_agent
|
|
379
|
+
{ 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 },
|
|
1000
380
|
{ category: "Validation", question: "What validations must be performed? (compliance, rules, thresholds)", whyItMatters: "May need rule_validation_with_documents or response_validator", required: false },
|
|
1001
381
|
{ category: "Output", question: "What should the success response look like?", whyItMatters: "Determines call_llm output formatting and response structure", required: true },
|
|
1002
382
|
{ category: "Output", question: "What should the error/exception response look like?", whyItMatters: "Needs explicit error handling paths and fallback responses", required: false },
|
|
@@ -1039,9 +419,9 @@ export const COMMON_MISTAKES = [
|
|
|
1039
419
|
{ mistake: "Type mismatches in connections", problem: "Validation errors, runtime failures", solution: "Check type compatibility: use conversation_to_search_query when needed" },
|
|
1040
420
|
{ mistake: "Not mapping to WORKFLOW_OUTPUT", problem: "Responses don't reach user", solution: "Ensure ALL paths terminate at WORKFLOW_OUTPUT" },
|
|
1041
421
|
{ 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." },
|
|
1042
|
-
{ mistake: "Chat workflow without chat-aware response node", problem: "Duplicate/repetitive responses — LLM re-asks questions already answered, loses multi-turn context", solution: "Use
|
|
422
|
+
{ 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." },
|
|
1043
423
|
{ 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]." },
|
|
1044
|
-
{ mistake: "Adding general_hitl as a standalone workflow node", problem: "general_hitl
|
|
424
|
+
{ 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." },
|
|
1045
425
|
];
|
|
1046
426
|
export const DEBUG_CHECKLIST = [
|
|
1047
427
|
{ step: 1, action: "Check Status", description: "Is the AI Employee active/ready?", apiField: "status" },
|
|
@@ -1092,13 +472,13 @@ export const GUIDANCE_TOPICS = {
|
|
|
1092
472
|
examples: [
|
|
1093
473
|
"✅ trigger.user_query → search.query (TEXT_WITH_SOURCES → TEXT_WITH_SOURCES)",
|
|
1094
474
|
"❌ trigger.chat_conversation → search.query (CHAT_CONVERSATION ≠ TEXT_WITH_SOURCES)",
|
|
1095
|
-
"✅ search.search_results →
|
|
475
|
+
"✅ search.search_results → respond_for_external_actions.external_action_result (SEARCH_RESULT → ANY)",
|
|
1096
476
|
"❌ search.search_results → call_llm.query (SEARCH_RESULT ≠ TEXT_WITH_SOURCES)",
|
|
1097
477
|
"✅ search.search_results → call_llm.named_inputs_* (SEARCH_RESULT → ANY)",
|
|
1098
478
|
],
|
|
1099
479
|
criticalRules: [
|
|
1100
480
|
"CHAT_CONVERSATION only compatible with chat_categorizer.conversation",
|
|
1101
|
-
"SEARCH_RESULT
|
|
481
|
+
"SEARCH_RESULT compatible with respond_for_external_actions.external_action_result or named_inputs (respond_with_sources/v0 is deprecated)",
|
|
1102
482
|
"call_llm.named_inputs accepts ANY type",
|
|
1103
483
|
"Use conversation_to_search_query to convert CHAT_CONVERSATION → TEXT_WITH_SOURCES",
|
|
1104
484
|
],
|
|
@@ -1117,27 +497,26 @@ export const GUIDANCE_TOPICS = {
|
|
|
1117
497
|
},
|
|
1118
498
|
"hitl-patterns": {
|
|
1119
499
|
title: "Human-in-the-Loop Patterns",
|
|
1120
|
-
content: "HITL is implemented as a FLAG on specific agents
|
|
1121
|
-
"
|
|
1122
|
-
"
|
|
1123
|
-
"
|
|
500
|
+
content: "HITL is implemented as a FLAG on specific agents — ONLY entity_extraction_with_documents and send_email_agent support it. " +
|
|
501
|
+
"external_action_caller does NOT support HITL. general_hitl is NOT deployable (appears in catalogs but cannot be deployed). " +
|
|
502
|
+
"When the user requests approval, enable the HITL flag on send_email_agent or entity_extraction_with_documents. " +
|
|
503
|
+
"The platform handles the approval UI and routing automatically.\n\n" +
|
|
1124
504
|
"JSON format: Set `disable_human_interaction: false` (or omit — default is false = HITL enabled) on the action node " +
|
|
1125
505
|
"in workflow_def.actions[]. To DISABLE HITL, set `disable_human_interaction: true`. " +
|
|
1126
506
|
"Note the counter-intuitive naming: false = HITL ON, true = HITL OFF.",
|
|
1127
507
|
status: "verified",
|
|
1128
508
|
examples: [
|
|
1129
509
|
"User wants email approval → enable HITL flag on send_email_agent",
|
|
1130
|
-
"User wants
|
|
1131
|
-
"Existing workflow has general_hitl → leave it (still functions), but don't add new ones",
|
|
510
|
+
"User wants extraction review → enable HITL flag on entity_extraction_with_documents",
|
|
1132
511
|
"JSON: { name: 'send_email', action: { name: 'send_email_agent' }, disable_human_interaction: false, ... } → HITL ENABLED",
|
|
1133
512
|
"JSON: { name: 'respond', action: { name: 'call_llm' }, disable_human_interaction: true, ... } → HITL DISABLED (auto-proceed)",
|
|
1134
513
|
],
|
|
1135
514
|
criticalRules: [
|
|
1136
|
-
"
|
|
1137
|
-
"HITL
|
|
515
|
+
"general_hitl is NOT deployable — do NOT add it to any workflow",
|
|
516
|
+
"HITL is ONLY supported on: entity_extraction_with_documents and send_email_agent",
|
|
517
|
+
"external_action_caller does NOT support HITL despite appearing in older guidance",
|
|
1138
518
|
"JSON field: `disable_human_interaction` (boolean) on the action node — false=HITL on, true=HITL off",
|
|
1139
|
-
"
|
|
1140
|
-
"When user says 'with approval': set disable_human_interaction: false on the relevant action node",
|
|
519
|
+
"When user says 'with approval': set disable_human_interaction: false on send_email_agent or entity_extraction_with_documents",
|
|
1141
520
|
],
|
|
1142
521
|
},
|
|
1143
522
|
"hitl-policy": {
|
|
@@ -1163,7 +542,7 @@ export const GUIDANCE_TOPICS = {
|
|
|
1163
542
|
content: "For comprehensive answers, combine local search with web search. Use combine_search_results to merge and deduplicate.",
|
|
1164
543
|
status: "verified",
|
|
1165
544
|
examples: [
|
|
1166
|
-
"search (local) + live_web_search → combine_search_results →
|
|
545
|
+
"search (local) + live_web_search → combine_search_results → respond_for_external_actions",
|
|
1167
546
|
"For cross-document linking: entity_extraction → knowledge_graph_generator → document_synthesis",
|
|
1168
547
|
],
|
|
1169
548
|
criticalRules: [
|
|
@@ -1438,7 +817,7 @@ export const GUIDANCE_TOPICS = {
|
|
|
1438
817
|
- NO → Use transform node (json_mapper, fixed_response)
|
|
1439
818
|
|
|
1440
819
|
### Q3: What KIND of generation?
|
|
1441
|
-
- Simple Q&A with citations →
|
|
820
|
+
- Simple Q&A with citations → respond_for_external_actions
|
|
1442
821
|
- Custom generation → call_llm
|
|
1443
822
|
- Complex multi-step reasoning → custom_agent
|
|
1444
823
|
- Search + synthesize in one → document_synthesis
|
|
@@ -1454,23 +833,23 @@ export const GUIDANCE_TOPICS = {
|
|
|
1454
833
|
| fixed_response | 0 | <50ms | Static content, config, templates |
|
|
1455
834
|
| json_mapper | 0 | <100ms | Transform JSON without reasoning |
|
|
1456
835
|
| entity_extraction | 1 | 1-2s | Extract structured data |
|
|
1457
|
-
|
|
|
836
|
+
| respond_for_external_actions | 1 | 2-4s | Search + response (conversation-aware) |
|
|
1458
837
|
| call_llm | 1 | 2-4s | Custom generation |
|
|
1459
838
|
| custom_agent | 1-3 | 3-8s | Complex reasoning |
|
|
1460
839
|
| document_synthesis | 2-5 | 5-15s | Multi-search + synthesis |`,
|
|
1461
840
|
examples: [
|
|
1462
841
|
"✅ Static template → fixed_response (0 LLM calls)",
|
|
1463
842
|
"✅ Extract client_name, email → entity_extraction (1 LLM call, typed output)",
|
|
1464
|
-
"✅ Simple KB Q&A →
|
|
843
|
+
"✅ Simple KB Q&A → respond_for_external_actions (1 LLM call, conversation-aware)",
|
|
1465
844
|
"✅ Custom email generation → call_llm with search results in named_inputs",
|
|
1466
845
|
"❌ Using call_llm to extract JSON → Use entity_extraction instead",
|
|
1467
|
-
"❌ Using document_synthesis for simple Q&A → Use
|
|
846
|
+
"❌ Using document_synthesis for simple Q&A → Use respond_for_external_actions",
|
|
1468
847
|
"❌ Using custom_agent for static response → Use fixed_response",
|
|
1469
848
|
],
|
|
1470
849
|
criticalRules: [
|
|
1471
850
|
"NEVER use LLM for transforms that json_mapper can do",
|
|
1472
851
|
"NEVER use call_llm for structured extraction - use entity_extraction",
|
|
1473
|
-
"NEVER use document_synthesis when
|
|
852
|
+
"NEVER use document_synthesis when respond_for_external_actions suffices",
|
|
1474
853
|
"ALWAYS use fixed_response for static content (templates, config, help text)",
|
|
1475
854
|
"Use entity_extraction for typed, reliable structured data",
|
|
1476
855
|
"Use call_llm when you need custom instructions or reasoning",
|
|
@@ -1483,9 +862,9 @@ export const GUIDANCE_TOPICS = {
|
|
|
1483
862
|
status: "verified",
|
|
1484
863
|
content: `Different LLM nodes serve different purposes. Choose based on your needs:
|
|
1485
864
|
|
|
1486
|
-
## respond_with_sources
|
|
1487
|
-
- **Best for**: Simple Q&A with KB citations
|
|
1488
|
-
- **Input**: Search results
|
|
865
|
+
## respond_for_external_actions (replaces deprecated respond_with_sources)
|
|
866
|
+
- **Best for**: Simple Q&A with KB citations, tool result explanation
|
|
867
|
+
- **Input**: Search results or tool results via external_action_result
|
|
1489
868
|
- **Output**: Response with source citations
|
|
1490
869
|
- **When**: User asks question, you search KB, return answer
|
|
1491
870
|
- **NOT for**: Custom generation, complex reasoning
|
|
@@ -1495,7 +874,7 @@ export const GUIDANCE_TOPICS = {
|
|
|
1495
874
|
- **Input**: Query + optional search/context via named_inputs
|
|
1496
875
|
- **Output**: Generated text
|
|
1497
876
|
- **When**: Need custom prompts, specific format, controlled generation
|
|
1498
|
-
- **NOT for**: Simple Q&A (use
|
|
877
|
+
- **NOT for**: Simple Q&A (use respond_for_external_actions)
|
|
1499
878
|
|
|
1500
879
|
## custom_agent
|
|
1501
880
|
- **Best for**: Complex tasks requiring role + instructions
|
|
@@ -1512,17 +891,17 @@ export const GUIDANCE_TOPICS = {
|
|
|
1512
891
|
- **When**: Need to search → plan → search again → synthesize
|
|
1513
892
|
- **NOT for**: Simple KB lookup (too heavy)`,
|
|
1514
893
|
examples: [
|
|
1515
|
-
"User asks 'What is our refund policy?' →
|
|
894
|
+
"User asks 'What is our refund policy?' → respond_for_external_actions",
|
|
1516
895
|
"Need to generate email with specific template → call_llm",
|
|
1517
896
|
"Need to analyze portfolio and recommend actions → custom_agent",
|
|
1518
897
|
"Need to research topic across multiple sources → document_synthesis",
|
|
1519
898
|
],
|
|
1520
899
|
criticalRules: [
|
|
1521
|
-
"
|
|
900
|
+
"respond_for_external_actions: 1 LLM call, simple Q&A or tool results, conversation-aware",
|
|
1522
901
|
"call_llm: 1 LLM call, custom generation, accepts named_inputs",
|
|
1523
902
|
"custom_agent: 1-3 LLM calls, complex reasoning, has role context",
|
|
1524
903
|
"document_synthesis: 2-5 LLM calls, heavy, only for research tasks",
|
|
1525
|
-
"Default to
|
|
904
|
+
"Default to respond_for_external_actions for KB Q&A",
|
|
1526
905
|
"Upgrade to call_llm when you need custom instructions",
|
|
1527
906
|
"Upgrade to custom_agent for complex reasoning",
|
|
1528
907
|
"Use document_synthesis sparingly (latency expensive)",
|
|
@@ -1680,105 +1059,38 @@ export function getConceptByTerm(term) {
|
|
|
1680
1059
|
c.aliases?.some(a => a.toLowerCase() === term.toLowerCase()));
|
|
1681
1060
|
}
|
|
1682
1061
|
export function suggestAgentsForUseCase(useCase) {
|
|
1683
|
-
const
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1062
|
+
const queryTokens = useCase
|
|
1063
|
+
.toLowerCase()
|
|
1064
|
+
.split(/[\s,;:.\-/|]+/)
|
|
1065
|
+
.filter(t => t.length > 1);
|
|
1066
|
+
if (queryTokens.length === 0)
|
|
1067
|
+
return [];
|
|
1068
|
+
const scored = AGENT_CATALOG.map(agent => {
|
|
1069
|
+
let score = 0;
|
|
1070
|
+
const searchableFields = [
|
|
1071
|
+
agent.actionName,
|
|
1072
|
+
agent.displayName,
|
|
1073
|
+
agent.category,
|
|
1074
|
+
agent.description,
|
|
1075
|
+
agent.whenToUse,
|
|
1076
|
+
agent.whenNotToUse ?? "",
|
|
1077
|
+
...agent.inputs.map(i => `${i.name} ${i.type}`),
|
|
1078
|
+
...agent.outputs.map(o => `${o.name} ${o.type}`),
|
|
1079
|
+
].map(f => f.toLowerCase());
|
|
1080
|
+
for (const token of queryTokens) {
|
|
1081
|
+
for (const field of searchableFields) {
|
|
1082
|
+
if (field.includes(token)) {
|
|
1083
|
+
score++;
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1692
1086
|
}
|
|
1693
1087
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
}
|
|
1701
|
-
// Search
|
|
1702
|
-
if (keywords.includes("search") || keywords.includes("document") || keywords.includes("knowledge") || keywords.includes("faq") || keywords.includes("lookup") || keywords.includes("find")) {
|
|
1703
|
-
addIfNotPresent("conversation_to_search_query");
|
|
1704
|
-
addIfNotPresent("search");
|
|
1705
|
-
addIfNotPresent("respond_with_sources");
|
|
1706
|
-
}
|
|
1707
|
-
// Web search
|
|
1708
|
-
if (keywords.includes("web") || keywords.includes("real-time") || keywords.includes("current") || keywords.includes("live")) {
|
|
1709
|
-
addIfNotPresent("live_web_search");
|
|
1710
|
-
if (added.has("search")) {
|
|
1711
|
-
addIfNotPresent("combine_search_results");
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
// External tools
|
|
1715
|
-
if (keywords.includes("ticket") || keywords.includes("servicenow") || keywords.includes("salesforce") || keywords.includes("api") || keywords.includes("create") || keywords.includes("update") || keywords.includes("crm") || keywords.includes("email")) {
|
|
1716
|
-
addIfNotPresent("external_action_caller");
|
|
1717
|
-
}
|
|
1718
|
-
// HITL — general_hitl is NOT recommended as a standalone node.
|
|
1719
|
-
// HITL is a flag on agents. Don't suggest adding general_hitl nodes.
|
|
1720
|
-
// If user wants approval, the agent should enable HITL flags on relevant agents.
|
|
1721
|
-
// Compliance/Validation
|
|
1722
|
-
if (keywords.includes("compliance") || keywords.includes("validate") || keywords.includes("rule") || keywords.includes("guardrail")) {
|
|
1723
|
-
addIfNotPresent("response_validator");
|
|
1724
|
-
}
|
|
1725
|
-
// Entity extraction
|
|
1726
|
-
if (keywords.includes("extract") || keywords.includes("entity") || keywords.includes("structure")) {
|
|
1727
|
-
addIfNotPresent("entity_extraction_with_documents");
|
|
1728
|
-
}
|
|
1729
|
-
// Voice specific
|
|
1730
|
-
if (keywords.includes("voice") || keywords.includes("phone") || keywords.includes("call")) {
|
|
1731
|
-
suggestions[0] = getAgentByName("voice_trigger") || suggestions[0];
|
|
1732
|
-
}
|
|
1733
|
-
// Document processing
|
|
1734
|
-
if (keywords.includes("document") || keywords.includes("upload") || keywords.includes("process") || keywords.includes("invoice") || keywords.includes("contract")) {
|
|
1735
|
-
if (!added.has("chat_trigger")) {
|
|
1736
|
-
suggestions[0] = getAgentByName("document_trigger") || suggestions[0];
|
|
1737
|
-
}
|
|
1738
|
-
addIfNotPresent("entity_extraction_with_documents");
|
|
1739
|
-
}
|
|
1740
|
-
// Default response if no response agent added
|
|
1741
|
-
if (!added.has("respond_with_sources") && !added.has("call_llm")) {
|
|
1742
|
-
addIfNotPresent("call_llm");
|
|
1743
|
-
}
|
|
1744
|
-
return suggestions;
|
|
1745
|
-
}
|
|
1746
|
-
export function validateWorkflowPrompt(prompt) {
|
|
1747
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
1748
|
-
const issues = [];
|
|
1749
|
-
const warnings = [];
|
|
1750
|
-
// Check for categorizer without fallback
|
|
1751
|
-
if ((lowerPrompt.includes("categoriz") || lowerPrompt.includes("classif") || lowerPrompt.includes("route")) &&
|
|
1752
|
-
!lowerPrompt.includes("fallback")) {
|
|
1753
|
-
issues.push("Missing Fallback category - every categorizer MUST have a Fallback");
|
|
1754
|
-
}
|
|
1755
|
-
// Check for HITL without both paths
|
|
1756
|
-
if (lowerPrompt.includes("hitl") || lowerPrompt.includes("human collaboration") || lowerPrompt.includes("approval")) {
|
|
1757
|
-
if (!lowerPrompt.includes("success") || !lowerPrompt.includes("fail")) {
|
|
1758
|
-
issues.push("HITL node requires both success AND failure paths");
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
// Check for output mapping
|
|
1762
|
-
if (!lowerPrompt.includes("workflow_output") && !lowerPrompt.includes("output")) {
|
|
1763
|
-
warnings.push("No explicit WORKFLOW_OUTPUT mapping found - ensure all paths lead to output");
|
|
1764
|
-
}
|
|
1765
|
-
// Check for trigger
|
|
1766
|
-
if (!lowerPrompt.includes("trigger") && !lowerPrompt.includes("chat") && !lowerPrompt.includes("voice") && !lowerPrompt.includes("document")) {
|
|
1767
|
-
issues.push("No trigger type specified - include chat_trigger, voice_trigger, or document_trigger");
|
|
1768
|
-
}
|
|
1769
|
-
// Check for common type issues
|
|
1770
|
-
if (lowerPrompt.includes("chat_conversation") && lowerPrompt.includes("search.query")) {
|
|
1771
|
-
warnings.push("Potential type mismatch: chat_conversation → search.query. Use conversation_to_search_query first.");
|
|
1772
|
-
}
|
|
1773
|
-
// Check for persona type
|
|
1774
|
-
if (!lowerPrompt.includes("voice ai") && !lowerPrompt.includes("chat ai") && !lowerPrompt.includes("dashboard ai") && !lowerPrompt.includes("persona type")) {
|
|
1775
|
-
warnings.push("No persona type specified - should specify Voice AI, Chat AI, or Dashboard AI");
|
|
1776
|
-
}
|
|
1777
|
-
return {
|
|
1778
|
-
valid: issues.length === 0,
|
|
1779
|
-
issues,
|
|
1780
|
-
warnings,
|
|
1781
|
-
};
|
|
1088
|
+
return { agent, score };
|
|
1089
|
+
});
|
|
1090
|
+
return scored
|
|
1091
|
+
.filter(s => s.score > 0)
|
|
1092
|
+
.sort((a, b) => b.score - a.score)
|
|
1093
|
+
.map(s => s.agent);
|
|
1782
1094
|
}
|
|
1783
1095
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1784
1096
|
// Workflow Analysis Functions
|