@ema.co/mcp-toolkit 2026.2.27 → 2026.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (58) hide show
  1. package/.context/public/guides/ema-user-guide.md +7 -6
  2. package/.context/public/guides/mcp-tools-guide.md +46 -23
  3. package/dist/config/index.js +11 -0
  4. package/dist/config/workflow-patterns.js +361 -0
  5. package/dist/mcp/autobuilder.js +2 -2
  6. package/dist/mcp/domain/generation-schema.js +15 -9
  7. package/dist/mcp/domain/structural-rules.js +3 -3
  8. package/dist/mcp/domain/validation-rules.js +20 -27
  9. package/dist/mcp/domain/workflow-generator.js +3 -3
  10. package/dist/mcp/domain/workflow-graph.js +1 -1
  11. package/dist/mcp/guidance.js +60 -1
  12. package/dist/mcp/handlers/conversation/adapter.js +13 -0
  13. package/dist/mcp/handlers/conversation/create.js +19 -0
  14. package/dist/mcp/handlers/conversation/delete.js +18 -0
  15. package/dist/mcp/handlers/conversation/formatters.js +62 -0
  16. package/dist/mcp/handlers/conversation/history.js +15 -0
  17. package/dist/mcp/handlers/conversation/index.js +43 -0
  18. package/dist/mcp/handlers/conversation/list.js +40 -0
  19. package/dist/mcp/handlers/conversation/messages.js +13 -0
  20. package/dist/mcp/handlers/conversation/rename.js +16 -0
  21. package/dist/mcp/handlers/conversation/send.js +90 -0
  22. package/dist/mcp/handlers/data/index.js +169 -3
  23. package/dist/mcp/handlers/feedback/client-id.js +49 -0
  24. package/dist/mcp/handlers/feedback/coalesce.js +167 -0
  25. package/dist/mcp/handlers/feedback/index.js +42 -1
  26. package/dist/mcp/handlers/feedback/outbox.js +301 -0
  27. package/dist/mcp/handlers/feedback/probes.js +127 -0
  28. package/dist/mcp/handlers/feedback/remote-store.js +59 -0
  29. package/dist/mcp/handlers/feedback/store.js +13 -1
  30. package/dist/mcp/handlers/persona/delete.js +7 -28
  31. package/dist/mcp/handlers/persona/update.js +7 -26
  32. package/dist/mcp/handlers/persona/version.js +30 -15
  33. package/dist/mcp/handlers/template/adapter.js +23 -0
  34. package/dist/mcp/handlers/template/crud.js +174 -0
  35. package/dist/mcp/handlers/template/index.js +6 -7
  36. package/dist/mcp/handlers/workflow/adapter.js +30 -46
  37. package/dist/mcp/handlers/workflow/index.js +2 -2
  38. package/dist/mcp/handlers/workflow/validation.js +2 -2
  39. package/dist/mcp/knowledge-guidance-topics.js +90 -53
  40. package/dist/mcp/knowledge.js +7 -357
  41. package/dist/mcp/prompts.js +5 -5
  42. package/dist/mcp/resources-dynamic.js +46 -38
  43. package/dist/mcp/resources-validation.js +5 -5
  44. package/dist/mcp/server.js +38 -5
  45. package/dist/mcp/tools.js +340 -8
  46. package/dist/sdk/client-adapter.js +90 -2
  47. package/dist/sdk/client.js +7 -0
  48. package/dist/sdk/ema-client.js +242 -27
  49. package/dist/sdk/generated/agent-catalog.js +96 -39
  50. package/dist/sdk/generated/deprecated-actions.js +1 -1
  51. package/dist/sdk/grpc-client.js +67 -5
  52. package/dist/sync/central-factory.js +86 -0
  53. package/dist/sync/central-version-storage.js +387 -0
  54. package/dist/sync/dis-port.js +75 -0
  55. package/dist/sync/version-policy.js +29 -31
  56. package/dist/sync/version-storage-interface.js +11 -0
  57. package/dist/sync/version-storage.js +22 -22
  58. package/package.json +2 -1
package/dist/mcp/tools.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * MCP Tools v2 - Minimal, LLM-optimized tool set with explicit methods
3
3
  *
4
- * 7 tools:
4
+ * 9 tools:
5
5
  * 1. persona - AI Employee entity + data + incremental modifications
6
6
  * 2. catalog - Reference data (actions, templates, widgets, voices, patterns)
7
7
  * 3. workflow - Complex workflow generation/compilation
@@ -9,6 +9,8 @@
9
9
  * 5. env - Environment info
10
10
  * 6. toolkit_feedback - Agent feedback collection
11
11
  * 7. debug - Audit conversations + workflow execution traces
12
+ * 8. conversation - Chat conversation management + HITL continuations
13
+ * 9. template - Persona template CRUD (create, list, get, update, delete)
12
14
  *
13
15
  * Design principles:
14
16
  * - ALL operations require explicit `method` or `mode` parameter
@@ -51,7 +53,7 @@ export function generateTools(envNames, defaultEnv) {
51
53
  **IMPORTANT (strict)**:
52
54
  - Always fetch latest state immediately before changing: \`persona(method="get", id="abc", include_fingerprint=true)\`
53
55
  - Pass \`base_fingerprint\` to update to prevent overwriting out-of-band changes
54
- - The toolkit snapshots the persona locally before applying updates
56
+ - The toolkit automatically snapshots the persona before applying updates
55
57
 
56
58
  **For workflow changes**: Use the workflow tool:
57
59
  1. \`workflow(mode="get", persona_id="abc")\` - get current workflow_def
@@ -85,6 +87,12 @@ export function generateTools(envNames, defaultEnv) {
85
87
  - \`persona(id="abc", data={method:"replicate", from:"src", widget_mappings:[...]})\` - with widget mapping
86
88
  - \`persona(id="abc", data={method:"delete", file_id:"file-123"})\` - delete file
87
89
  - \`persona(id="abc", data={method:"search", query:"pricing"})\` - search knowledge base
90
+ - \`persona(id="abc", data={method:"result", row_id:"row-123"})\` - get row output/status
91
+ - \`persona(id="abc", data={method:"result", row_id:"row-123", include_file_contents:true})\` - with generated files
92
+ - \`persona(id="abc", data={method:"continue", row_id:"row-123", text:"approved"})\` - text HITL response
93
+ - \`persona(id="abc", data={method:"continue", row_id:"row-123", buttons:{selected_button:{label:"Approve"}}})\` - button selection
94
+ - \`persona(id="abc", data={method:"continue", row_id:"row-123", form:{is_cancelled:true}})\` - cancel form
95
+ - \`persona(id="abc", data={method:"continue", row_id:"row-123", raw_continuation:{formMessage:{...full form with values...}}})\` - form submission (echo back full formMessage)
88
96
  - \`persona(id="abc", data={method:"refresh", row_id:"row-123"})\` - rerun workflow for existing row
89
97
  - \`persona(id="abc", data={method:"regenerate", document_id:"doc-123", project_id:"proj-456", selection:"intro", query:"make it shorter"})\` - modify document section
90
98
  - \`persona(id="abc", data={method:"replace", document_id:"doc-123", project_id:"proj-456", content:"new content"})\` - replace entire document content
@@ -107,6 +115,40 @@ Item values support: strings, numbers, booleans, file attachments ({ file: "path
107
115
  - Chat personas → use \`path\` (uploads to KB, enables search)
108
116
  Using \`path\` for dashboards is WRONG - data won't be processed.
109
117
 
118
+ ### Dashboard Row Polling Flow
119
+ After upload, poll for completion:
120
+ 1. \`persona(id="abc", data={method:"upload", items:[...]})\` → returns \`row_ids\`
121
+ 2. \`persona(id="abc", data={method:"result", row_id:"<from_step_1>"})\` → check status
122
+ 3. If \`is_complete=false\` and state is RUNNING/QUEUED, wait 5-10 seconds and repeat step 2
123
+ 4. If \`requires_human_input=true\` (HITL), review \`continuation_message\` and \`continuation_type\`, and ask the user:
124
+ - **text**: Ask user for free-text response → \`data={method:"continue", text:"user's answer"}\`
125
+ - **buttons**: Show options to user → \`data={method:"continue", buttons:{selected_button:{label:"chosen"}}}\`
126
+ - **form**: Ask user to fill fields → echo back full formMessage via \`data={method:"continue", raw_continuation:{formMessage:{...with values...}}}\`
127
+ - **form cancel**: \`data={method:"continue", form:{is_cancelled:true}}\`
128
+ 5. After continue, poll result again (repeat step 2) — workflow resumes processing
129
+ 6. If \`continuation_type=form\` and response has \`isIntermediate:true\`, more form fields follow — repeat from step 4
130
+ 7. When \`is_complete=true\`, the row output is in the \`row\` field
131
+ 8. Add \`include_file_contents=true\` to get generated file contents
132
+
133
+ ### Form HITL (CRITICAL — use raw_continuation)
134
+ Form submissions require echoing back the **entire formMessage** from \`continuation_message\` with values filled in:
135
+ \`\`\`
136
+ persona(id="abc", data={method:"continue", row_id:"...", raw_continuation:{
137
+ formMessage: { ...entire formMessage from continuation_message with field values filled in... }
138
+ }})
139
+ \`\`\`
140
+ **Field value patterns by wellKnown type:**
141
+ - **String**: \`value: {wellKnown: {stringValue: "text"}}\`
142
+ - **Int**: \`value: {wellKnown: {int64Value: "42"}}\` (string-encoded)
143
+ - **Float**: \`value: {wellKnown: {doubleValue: 3.14}}\`
144
+ - **Boolean**: \`value: {wellKnown: {boolValue: true}}\`
145
+ - **Date**: \`value: {wellKnown: {dateValue: {year: 2026, month: 3, day: 2}}}\`
146
+ - **DateTime**: \`value: {wellKnown: {datetimeValue: {utcTime: "2026-03-02T09:00:00Z"}}}\`
147
+
148
+ **Dropdown fields:** Check \`inputValidation.validValues\`:
149
+ - Struct options → use the **Id** as stringValue
150
+ - Enum options → use the enumValue as stringValue
151
+
110
152
  ## Action Composition (post-operation actions)
111
153
  Use \`actions\` array for multi-step operations instead of flag parameters.
112
154
 
@@ -254,7 +296,7 @@ persona(
254
296
  properties: {
255
297
  method: {
256
298
  type: "string",
257
- enum: ["list", "stats", "schema", "upload", "copy", "replicate", "delete", "embed", "search", "refresh", "regenerate", "replace"],
299
+ enum: ["list", "stats", "schema", "upload", "copy", "replicate", "delete", "embed", "search", "refresh", "result", "continue", "regenerate", "replace"],
258
300
  description: "Data operation to perform (required)"
259
301
  },
260
302
  // copy/replicate params
@@ -292,6 +334,38 @@ persona(
292
334
  enabled: { type: "boolean", description: "Enable/disable embeddings (for method=embed)" },
293
335
  // search params
294
336
  query: { type: "string", description: "Search query (for method=search)" },
337
+ // result params (dashboard row output)
338
+ row_id: { type: "string", description: "Row ID (for method=result, method=refresh)" },
339
+ include_file_contents: { type: "boolean", description: "Include generated file contents in result (for method=result, default: false)" },
340
+ // continue params (HITL response) — mirrors conversation tool's HITL params
341
+ text: { type: "string", description: "Free-text response to HITL pause (for method=continue)" },
342
+ buttons: {
343
+ type: "object",
344
+ description: "Button selection for HITL continuation (for method=continue). Same format as conversation tool.",
345
+ properties: {
346
+ selected_button: {
347
+ type: "object",
348
+ properties: {
349
+ label: { type: "string", description: "Button label to select" },
350
+ description: { type: "string", description: "Button description" },
351
+ },
352
+ required: ["label"],
353
+ },
354
+ },
355
+ required: ["selected_button"],
356
+ },
357
+ form: {
358
+ type: "object",
359
+ description: "Form HITL cancellation only (for method=continue). Set is_cancelled=true to cancel a form. For form SUBMISSIONS, use raw_continuation instead — the backend requires the full formMessage echoed back.",
360
+ properties: {
361
+ is_cancelled: { type: "boolean", description: "Set to true to cancel the form" },
362
+ },
363
+ },
364
+ // raw pass-through for form HITL submissions
365
+ raw_continuation: {
366
+ type: "object",
367
+ description: "Pre-built ContinuationMessage dict (for method=continue). REQUIRED for form HITL submissions — echo back the full formMessage from continuation_message with values filled in. Use correct wellKnown value types: {wellKnown:{stringValue:'text'}} for strings, {wellKnown:{int64Value:'42'}} for ints, {wellKnown:{doubleValue:3.14}} for floats, {wellKnown:{boolValue:true}} for bools, {wellKnown:{dateValue:{year,month,day}}} for dates, {wellKnown:{datetimeValue:{utcTime:'ISO'}}} for datetimes. For struct dropdowns use Id as stringValue; for enum dropdowns use enumValue as stringValue.",
368
+ },
295
369
  },
296
370
  required: ["method"],
297
371
  },
@@ -353,7 +427,7 @@ persona(
353
427
 
354
428
  ## List
355
429
  - \`catalog(method="list", type="actions")\` - list all actions/agents
356
- - \`catalog(method="list", type="templates")\` - list persona templates
430
+ - \`catalog(method="list", type="templates")\` - list persona templates (read-only; for CRUD use the \`template\` tool)
357
431
  - \`catalog(method="list", type="widgets")\` - list config widgets
358
432
  - \`catalog(method="list", type="voices")\` - list voice models
359
433
  - \`catalog(method="list", type="patterns")\` - list workflow patterns
@@ -592,12 +666,16 @@ persona(
592
666
  - \`toolkit_feedback(method="submit", category="success", message="...")\` - report what worked well
593
667
  - \`toolkit_feedback(method="submit", category="error_unclear", message="...", tool="persona")\` - report unhelpful errors
594
668
  - \`toolkit_feedback(method="submit", category="suggestion", message="...")\` - suggest improvements
669
+ - \`toolkit_feedback(method="submit", category="probe_response", message="<answer>", context="<probe.id>")\` - respond to a _probe question
595
670
 
596
671
  ## Review Feedback
597
672
  - \`toolkit_feedback(method="list")\` - view recent feedback
598
673
  - \`toolkit_feedback(method="list", category="gap")\` - filter by category
599
674
  - \`toolkit_feedback(method="analyze")\` - aggregate insights and actionable items
600
675
 
676
+ ## Maintenance
677
+ - \`toolkit_feedback(method="flush")\` - force immediate upload of pending outbox entries to remote storage
678
+
601
679
  ## When to Submit Feedback
602
680
  - You encountered an error message that didn't help you fix the issue
603
681
  - Documentation was missing for something you needed to do
@@ -609,13 +687,13 @@ persona(
609
687
  properties: {
610
688
  method: {
611
689
  type: "string",
612
- enum: ["submit", "list", "analyze"],
690
+ enum: ["submit", "list", "analyze", "flush"],
613
691
  description: "Operation to perform (required)",
614
692
  },
615
693
  category: {
616
694
  type: "string",
617
- enum: ["gap", "confusion", "success", "error_unclear", "suggestion"],
618
- description: "Feedback category (required for submit): gap=missing docs, confusion=unclear guidance, success=worked well, error_unclear=unhelpful error, suggestion=improvement idea",
695
+ enum: ["gap", "confusion", "success", "error_unclear", "suggestion", "probe_response"],
696
+ description: "Feedback category (required for submit): gap=missing docs, confusion=unclear guidance, success=worked well, error_unclear=unhelpful error, suggestion=improvement idea, probe_response=answer to a _probe question",
619
697
  },
620
698
  message: {
621
699
  type: "string",
@@ -734,6 +812,261 @@ persona(
734
812
  required: ["method"],
735
813
  },
736
814
  },
815
+ // ═══════════════════════════════════════════════════════════════════════════
816
+ // 8. CONVERSATION - Chat conversation management + HITL continuations
817
+ // ═══════════════════════════════════════════════════════════════════════════
818
+ {
819
+ name: "conversation",
820
+ description: `Live chat session management. Create chat sessions with personas, send messages, handle HITL (human-in-the-loop) continuations, and view history.
821
+
822
+ **IMPORTANT**: All operations require explicit \`method\` parameter.
823
+
824
+ **NOTE**: This tool manages **live chat sessions** (interactive conversations with AI Employees). For audit/review conversation logs, use \`debug(method="conversations")\` instead.
825
+
826
+ ## Create
827
+ - \`conversation(method="create", persona_id="abc")\` - start a new conversation (returns conversation_id + welcome message)
828
+
829
+ ## Send Message
830
+ - \`conversation(method="send", conversation_id="...", text="hello")\` - send a text message
831
+
832
+ ## HITL Continuations
833
+ When the bot responds with a continuation (form, buttons, or text prompt), respond with the matching type:
834
+
835
+ - **Text**: \`conversation(method="send", conversation_id="...", text="user reply")\`
836
+ - **Buttons**: \`conversation(method="send", conversation_id="...", buttons={selected_button:{label:"Yes", description:"Confirm"}})\`
837
+ - **Form cancel**: \`conversation(method="send", conversation_id="...", form={is_cancelled:true})\`
838
+ - **Form submit**: Use \`raw_message\` — the simplified \`form\` param does NOT work for form submissions because the backend expects the full form structure echoed back.
839
+
840
+ ### Form HITL (CRITICAL — use raw_message)
841
+ Forms require echoing back the **entire formMessage** from the bot's response with your values filled in:
842
+
843
+ \`\`\`
844
+ conversation(method="send", conversation_id="...", original_message_id="<id from bot message>", raw_message={
845
+ type: "MESSAGE_TYPE_FORM",
846
+ formMessage: { ...entire formMessage from bot response with field values filled in... },
847
+ isUserMessage: true
848
+ })
849
+ \`\`\`
850
+
851
+ **Field value patterns by wellKnown type (from WellKnownValue proto):**
852
+ - **String** (\`WELL_KNOWN_TYPE_STRING\`): \`value: {wellKnown: {stringValue: "text"}}\`
853
+ - **Int** (\`WELL_KNOWN_TYPE_INT\`): \`value: {wellKnown: {int64Value: "42"}}\` (string-encoded integer)
854
+ - **Float** (\`WELL_KNOWN_TYPE_FLOAT\`): \`value: {wellKnown: {doubleValue: 3.14}}\`
855
+ - **Boolean** (\`WELL_KNOWN_TYPE_BOOL\`): \`value: {wellKnown: {boolValue: true}}\`
856
+ - **Date** (\`WELL_KNOWN_TYPE_DATE\`): \`value: {wellKnown: {dateValue: {year: 2026, month: 3, day: 2}}}\`
857
+ - **DateTime** (\`WELL_KNOWN_TYPE_DATETIME\`): \`value: {wellKnown: {datetimeValue: {utcTime: "2026-03-02T09:00:00Z"}}}\`
858
+
859
+ **Dropdown fields:** Check \`inputValidation.validValues\` to determine format:
860
+ - Struct options \`{wellKnown: {structValue: {Name:"Engineering", Id:"E"}}}\` → use the **Id** as stringValue: \`value: {wellKnown: {stringValue: "E"}}\`
861
+ - Enum options \`{enumValue: "Sick Leave"}\` → use the enum value as stringValue: \`value: {wellKnown: {stringValue: "Sick Leave"}}\`
862
+
863
+ **Intermediate forms**: If the response has \`isIntermediate: true\`, the bot will return another form with more fields after you submit. Previously filled fields will have \`editDisabled: true\`. The final form (no \`isIntermediate\`) submits all fields at once.
864
+
865
+ **Async responses**: Some workflows (e.g. agentic search) run long tasks after HITL exits. If \`send\` times out, poll with \`conversation(method="history")\` until the response appears with \`processing_status: "completed"\`.
866
+
867
+ ## History
868
+ - \`conversation(method="history", conversation_id="...")\` - get all messages in the conversation
869
+
870
+ ## List Conversations
871
+ - \`conversation(method="list")\` - list all conversations for the current user
872
+ - \`conversation(method="list", persona_id="abc")\` - list conversations for a specific persona
873
+
874
+ ## Messages
875
+ - \`conversation(method="messages", conversation_id="...")\` - get all messages (webapp endpoint, richer metadata than history)
876
+
877
+ ## Rename
878
+ - \`conversation(method="rename", conversation_id="...", display_name="New Name")\` - update display name
879
+
880
+ ## Delete
881
+ - \`conversation(method="delete", conversation_id="...", confirm=true)\` - delete a conversation
882
+
883
+ ## Raw Message
884
+ - \`conversation(method="send", conversation_id="...", raw_message={...})\` - send a pre-built ChatbotMessage dict. **Required for form HITL submissions.**`,
885
+ inputSchema: {
886
+ type: "object",
887
+ properties: {
888
+ method: {
889
+ type: "string",
890
+ enum: ["create", "send", "history", "list", "messages", "rename", "delete"],
891
+ description: "Operation to perform (required)",
892
+ },
893
+ persona_id: {
894
+ type: "string",
895
+ description: "Persona ID (for method=create to start a conversation, or method=list to filter by persona)",
896
+ },
897
+ conversation_id: {
898
+ type: "string",
899
+ description: "Conversation ID (required for method=send, history, messages, rename, delete)",
900
+ },
901
+ text: {
902
+ type: "string",
903
+ description: "Text message content (for method=send). Used for regular queries and text HITL continuations.",
904
+ },
905
+ buttons: {
906
+ type: "object",
907
+ description: "Button selection for HITL continuation (for method=send). Must include selected_button with label and description.",
908
+ properties: {
909
+ selected_button: {
910
+ type: "object",
911
+ properties: {
912
+ label: { type: "string", description: "Button label" },
913
+ description: { type: "string", description: "Button description (sent as response text)" },
914
+ },
915
+ required: ["label"],
916
+ },
917
+ },
918
+ required: ["selected_button"],
919
+ },
920
+ form: {
921
+ type: "object",
922
+ description: "Form HITL cancellation only (for method=send). Set is_cancelled=true to cancel a form. For form SUBMISSIONS, use raw_message instead — the backend requires the full formMessage echoed back.",
923
+ properties: {
924
+ fields: {
925
+ type: "array",
926
+ items: {
927
+ type: "object",
928
+ properties: {
929
+ name: { type: "string", description: "Field name" },
930
+ displayName: { type: "string", description: "Display label" },
931
+ value: {
932
+ type: "object",
933
+ description: "Field value. Use stringValue for strings, e.g. {stringValue: \"hello\"}",
934
+ },
935
+ },
936
+ required: ["name"],
937
+ },
938
+ description: "Form fields with values",
939
+ },
940
+ is_cancelled: {
941
+ type: "boolean",
942
+ description: "Set to true to cancel the form instead of submitting",
943
+ },
944
+ },
945
+ },
946
+ raw_message: {
947
+ type: "object",
948
+ description: "Pre-built ChatbotMessage dict (for method=send). REQUIRED for form HITL submissions — echo back the full formMessage from the bot's response with values filled in. Use correct wellKnown value types: stringValue (strings), int64Value (ints, string-encoded), doubleValue (floats), boolValue (bools), dateValue {year,month,day} (dates), datetimeValue {utcTime} (datetimes). For struct dropdowns use the Id as stringValue; for enum dropdowns use the enumValue as stringValue.",
949
+ },
950
+ original_message_id: {
951
+ type: "string",
952
+ description: "ID of the bot message being responded to (for HITL continuations with method=send)",
953
+ },
954
+ user_context: {
955
+ type: "object",
956
+ description: "Optional user context dict passed to the workflow",
957
+ },
958
+ display_name: {
959
+ type: "string",
960
+ description: "New display name (for method=rename)",
961
+ },
962
+ confirm: {
963
+ type: "boolean",
964
+ description: "Confirm deletion - required (for method=delete)",
965
+ },
966
+ limit: {
967
+ type: "number",
968
+ description: "Max conversations to return (for method=list)",
969
+ },
970
+ pagination_token: {
971
+ type: "string",
972
+ description: "Pagination token from previous response (for method=list)",
973
+ },
974
+ env: {
975
+ type: "string",
976
+ description: envDescription,
977
+ },
978
+ },
979
+ required: ["method"],
980
+ },
981
+ },
982
+ // ═══════════════════════════════════════════════════════════════════════════
983
+ // 9. TEMPLATE - Persona template CRUD
984
+ // ═══════════════════════════════════════════════════════════════════════════
985
+ {
986
+ name: "template",
987
+ description: `Manage persona templates (blueprints for creating AI Employees). Create, browse, update, and delete templates.
988
+
989
+ **IMPORTANT**: All operations require explicit \`method\` parameter.
990
+
991
+ ## List
992
+ - \`template(method="list")\` - list all templates
993
+ - \`template(method="list", type="voice")\` - filter by type (voice/chat/dashboard)
994
+ - \`template(method="list", query="support")\` - search by name/description
995
+ - \`template(method="list", category="customer_service")\` - filter by category
996
+
997
+ ## Get
998
+ - \`template(method="get", id="template-uuid")\` - get full template details
999
+
1000
+ ## Create
1001
+ - \`template(method="create", name="My Template")\` - create minimal template
1002
+ - \`template(method="create", name="My Template", type="voice", proto_config={...})\` - with config
1003
+
1004
+ ## Update
1005
+ - \`template(method="update", id="template-uuid", name="New Name")\` - update fields
1006
+
1007
+ ## Delete
1008
+ - \`template(method="delete", id="template-uuid", confirm=true)\` - delete template`,
1009
+ inputSchema: {
1010
+ type: "object",
1011
+ properties: {
1012
+ method: {
1013
+ type: "string",
1014
+ enum: ["list", "get", "create", "update", "delete"],
1015
+ description: "Operation to perform (required)",
1016
+ },
1017
+ id: {
1018
+ type: "string",
1019
+ description: "Template ID (for method=get/update/delete)",
1020
+ },
1021
+ name: {
1022
+ type: "string",
1023
+ description: "Template name (required for create, optional for update)",
1024
+ },
1025
+ description: {
1026
+ type: "string",
1027
+ description: "Template description",
1028
+ },
1029
+ type: {
1030
+ type: "string",
1031
+ enum: ["voice", "chat", "dashboard"],
1032
+ description: "Template type / trigger type (for filtering or create)",
1033
+ },
1034
+ category: {
1035
+ type: "string",
1036
+ description: "Template category (for filtering or create/update)",
1037
+ },
1038
+ query: {
1039
+ type: "string",
1040
+ description: "Search query for filtering templates by name/description (for method=list)",
1041
+ },
1042
+ from: {
1043
+ type: "string",
1044
+ description: "Source template ID to clone from (for method=create)",
1045
+ },
1046
+ proto_config: {
1047
+ type: "object",
1048
+ description: "Proto config for the template (for method=create/update)",
1049
+ },
1050
+ workflow_def: {
1051
+ type: "object",
1052
+ description: "Workflow definition for the template (for method=create/update)",
1053
+ },
1054
+ about_template: {
1055
+ type: "string",
1056
+ description: "About/description text for the template (for method=create/update)",
1057
+ },
1058
+ confirm: {
1059
+ type: "boolean",
1060
+ description: "Confirm deletion - required (for method=delete)",
1061
+ },
1062
+ env: {
1063
+ type: "string",
1064
+ description: envDescription,
1065
+ },
1066
+ },
1067
+ required: ["method"],
1068
+ },
1069
+ },
737
1070
  ];
738
1071
  }
739
1072
  /**
@@ -743,7 +1076,6 @@ persona(
743
1076
  export const INTERNAL_TOOLS = [
744
1077
  "demo", // → persona(id=..., data={method:"upload", content:...})
745
1078
  "action", // → catalog(method="list", type="actions")
746
- "template", // → catalog(method="list", type="templates")
747
1079
  "reference", // → catalog(method="list", type="concepts")
748
1080
  "data", // → persona(id=..., data={method:...})
749
1081
  ];
@@ -198,6 +198,54 @@ export class EmaClientAdapter {
198
198
  const templates = await this.client.listPersonaTemplates();
199
199
  return templates.map(t => this.mapToLegacyTemplate(t));
200
200
  }
201
+ /**
202
+ * Get a single persona template by ID
203
+ * Returns null for non-existent templates.
204
+ */
205
+ async getPersonaTemplateById(templateId) {
206
+ const template = await this.client.getPersonaTemplateById(templateId);
207
+ if (!template)
208
+ return null;
209
+ return this.mapToLegacyTemplate(template);
210
+ }
211
+ /**
212
+ * Create a new persona template
213
+ */
214
+ async createPersonaTemplate(data) {
215
+ const result = await this.client.createPersonaTemplate({
216
+ name: data.name,
217
+ description: data.description,
218
+ proto_config: data.proto_config,
219
+ trigger_type: data.trigger_type,
220
+ category: data.category,
221
+ about_template: data.about_template,
222
+ workflow_def: data.workflow_def,
223
+ source_template_id: data.source_template_id,
224
+ });
225
+ return { template_id: result.template_id };
226
+ }
227
+ /**
228
+ * Update an existing persona template
229
+ */
230
+ async updatePersonaTemplate(data) {
231
+ const result = await this.client.updatePersonaTemplate({
232
+ template_id: data.template_id,
233
+ name: data.name,
234
+ description: data.description,
235
+ proto_config: data.proto_config,
236
+ category: data.category,
237
+ about_template: data.about_template,
238
+ workflow_def: data.workflow_def,
239
+ });
240
+ return result;
241
+ }
242
+ /**
243
+ * Delete a persona template by ID
244
+ */
245
+ async deletePersonaTemplate(templateId) {
246
+ const result = await this.client.deletePersonaTemplate(templateId);
247
+ return result;
248
+ }
201
249
  // ═══════════════════════════════════════════════════════════════════════════
202
250
  // Action Operations
203
251
  // ═══════════════════════════════════════════════════════════════════════════
@@ -271,6 +319,12 @@ export class EmaClientAdapter {
271
319
  async rerunDashboardRow(personaId, rowId) {
272
320
  return this.client.rerunDashboardRow(personaId, rowId);
273
321
  }
322
+ /**
323
+ * Continue a paused (HITL) workflow for a dashboard row.
324
+ */
325
+ async continueDashboardRow(rowId, continuation) {
326
+ return this.client.continueDashboardRow(rowId, continuation);
327
+ }
274
328
  /**
275
329
  * Get dashboard schema (columns).
276
330
  * Legacy signature takes (dashboardId, personaId).
@@ -291,8 +345,15 @@ export class EmaClientAdapter {
291
345
  /**
292
346
  * Delete a data source file
293
347
  */
294
- async deleteDataSource(personaId, fileId) {
295
- return this.client.deleteDataSource(personaId, fileId);
348
+ async deleteDataSource(personaId, fileId, opts) {
349
+ return this.client.deleteDataSource(personaId, fileId, opts);
350
+ }
351
+ /**
352
+ * Download a file's content by UploadedFile.Id.
353
+ * Uses GetSignedUrl gRPC → HTTP fetch.
354
+ */
355
+ async downloadFile(fileId, personaId) {
356
+ return this.client.downloadFile(fileId, personaId);
296
357
  }
297
358
  /**
298
359
  * List data source files
@@ -637,4 +698,31 @@ export class EmaClientAdapter {
637
698
  nullToUndefined(value) {
638
699
  return value === null ? undefined : value;
639
700
  }
701
+ // ═══════════════════════════════════════════════════════════════════════════
702
+ // Chat / Conversation Operations
703
+ // ═══════════════════════════════════════════════════════════════════════════
704
+ async createConversation(personaId, opts) {
705
+ return this.client.createConversation(personaId, opts);
706
+ }
707
+ async sendMessage(conversationId, message, opts) {
708
+ return this.client.sendMessage(conversationId, message, opts);
709
+ }
710
+ async getConversationHistory(conversationId) {
711
+ return this.client.getConversationHistory(conversationId);
712
+ }
713
+ async listConversations() {
714
+ return this.client.listConversations();
715
+ }
716
+ async listConversationsForPersona(personaId, opts) {
717
+ return this.client.listConversationsForPersona(personaId, opts);
718
+ }
719
+ async getConversationMessages(conversationId) {
720
+ return this.client.getConversationMessages(conversationId);
721
+ }
722
+ async deleteConversation(conversationId) {
723
+ return this.client.deleteConversation(conversationId);
724
+ }
725
+ async updateConversationDisplayName(conversationId, displayName) {
726
+ return this.client.updateConversationDisplayName(conversationId, displayName);
727
+ }
640
728
  }
@@ -2065,6 +2065,13 @@ export class EmaClient {
2065
2065
  }
2066
2066
  return (await resp.json());
2067
2067
  }
2068
+ /**
2069
+ * Continue a paused (HITL) workflow for a dashboard row.
2070
+ * Stub — actual implementation is in EmaClientAdapter/EmaClientV2.
2071
+ */
2072
+ async continueDashboardRow(_rowId, _continuation) {
2073
+ throw new Error("continueDashboardRow requires EmaClientV2/EmaClientAdapter (gRPC). Legacy EmaClient does not support this.");
2074
+ }
2068
2075
  // ─────────────────────────────────────────────────────────────────────────────
2069
2076
  // Autobuilder Chat API
2070
2077
  // ─────────────────────────────────────────────────────────────────────────────