@ema.co/mcp-toolkit 2026.1.17 → 2026.1.24
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/README.md +52 -25
- package/dist/mcp/handlers/action/index.js +148 -0
- package/dist/mcp/handlers/action-executor.js +350 -0
- package/dist/mcp/handlers/data/dashboard-clone.js +352 -0
- package/dist/mcp/handlers/data/index.js +381 -0
- package/dist/mcp/handlers/env/index.js +44 -0
- package/dist/mcp/handlers/index.js +32 -0
- package/dist/mcp/handlers/knowledge/index.js +247 -0
- package/dist/mcp/handlers/persona/analyze.js +275 -0
- package/dist/mcp/handlers/persona/compare.js +32 -0
- package/dist/mcp/handlers/persona/create.js +450 -0
- package/dist/mcp/handlers/persona/delete.js +74 -0
- package/dist/mcp/handlers/persona/get.js +46 -0
- package/dist/mcp/handlers/persona/index.js +73 -0
- package/dist/mcp/handlers/persona/intent.js +141 -0
- package/dist/mcp/handlers/persona/list.js +50 -0
- package/dist/mcp/handlers/persona/sanitize.js +43 -0
- package/dist/mcp/handlers/persona/templates.js +28 -0
- package/dist/mcp/handlers/persona/update.js +345 -0
- package/dist/mcp/handlers/reference/index.js +291 -0
- package/dist/mcp/handlers/sync/index.js +129 -0
- package/dist/mcp/handlers/template/index.js +61 -0
- package/dist/mcp/handlers/types.js +26 -0
- package/dist/mcp/handlers/utils.js +222 -0
- package/dist/mcp/handlers-consolidated.js +902 -1651
- package/dist/mcp/prompts.js +6 -3
- package/dist/mcp/resources.js +79 -14
- package/dist/mcp/server.js +539 -890
- package/dist/mcp/tools-consolidated.js +230 -167
- package/dist/mcp/tools-v2.js +510 -0
- package/dist/mcp/workflow-operations.js +100 -0
- package/dist/sdk/autobuilder.js +300 -0
- package/dist/sdk/client-adapter.js +162 -0
- package/dist/sdk/client.js +721 -194
- package/dist/sdk/ema-client.js +292 -0
- package/dist/sdk/generated/api-client/client/client.gen.js +235 -0
- package/dist/sdk/generated/api-client/client/index.js +6 -0
- package/dist/sdk/generated/api-client/client/types.gen.js +2 -0
- package/dist/sdk/generated/api-client/client/utils.gen.js +231 -0
- package/dist/sdk/generated/api-client/client.gen.js +3 -0
- package/dist/sdk/generated/api-client/core/auth.gen.js +14 -0
- package/dist/sdk/generated/api-client/core/bodySerializer.gen.js +57 -0
- package/dist/sdk/generated/api-client/core/params.gen.js +100 -0
- package/dist/sdk/generated/api-client/core/pathSerializer.gen.js +114 -0
- package/dist/sdk/generated/api-client/core/queryKeySerializer.gen.js +99 -0
- package/dist/sdk/generated/api-client/core/serverSentEvents.gen.js +137 -0
- package/dist/sdk/generated/api-client/core/types.gen.js +2 -0
- package/dist/sdk/generated/api-client/core/utils.gen.js +87 -0
- package/dist/sdk/generated/api-client/index.js +2 -0
- package/dist/sdk/generated/api-client/sdk.gen.js +910 -0
- package/dist/sdk/generated/api-client/types.gen.js +2 -0
- package/dist/sdk/generated/api-types.js +23 -2
- package/dist/sdk/generated/proto-fields.js +159 -0
- package/dist/sdk/generated/protos/service/agent_qa/v1/agent_qa_pb.js +29 -0
- package/dist/sdk/generated/protos/service/audience/v1/audience_pb.js +670 -0
- package/dist/sdk/generated/protos/service/auth/v1/auth_pb.js +167 -0
- package/dist/sdk/generated/protos/service/commentservice/v1/comment_pb.js +139 -0
- package/dist/sdk/generated/protos/service/common/v1/common_pb.js +134 -0
- package/dist/sdk/generated/protos/service/conversation/v1/conversation_pb.js +93 -0
- package/dist/sdk/generated/protos/service/conversation_review/v1/conversation_review_pb.js +197 -0
- package/dist/sdk/generated/protos/service/dataingest/v1/crm_pb.js +153 -0
- package/dist/sdk/generated/protos/service/dataingest/v1/dataingest_pb.js +786 -0
- package/dist/sdk/generated/protos/service/debugger/service_pb.js +44 -0
- package/dist/sdk/generated/protos/service/document_store/v1/copyright_pb.js +22 -0
- package/dist/sdk/generated/protos/service/document_store/v1/document_store_pb.js +415 -0
- package/dist/sdk/generated/protos/service/document_store/v1/feedback_store_pb.js +84 -0
- package/dist/sdk/generated/protos/service/document_store/v1/rfp_response_pb.js +198 -0
- package/dist/sdk/generated/protos/service/document_store/v1/rfp_template_pb.js +135 -0
- package/dist/sdk/generated/protos/service/eval-tool/v1/evaluation_pb.js +413 -0
- package/dist/sdk/generated/protos/service/eval-tool/v1/prompts_pb.js +92 -0
- package/dist/sdk/generated/protos/service/eval-tool/v1/testbed_pb.js +96 -0
- package/dist/sdk/generated/protos/service/eval-tool/v1/workflow_metadata_pb.js +44 -0
- package/dist/sdk/generated/protos/service/evaluation/v1/evaluation_pb.js +121 -0
- package/dist/sdk/generated/protos/service/external_access_service/v1/external_bot_pb.js +111 -0
- package/dist/sdk/generated/protos/service/external_access_service/v1/phone_number_service_pb.js +114 -0
- package/dist/sdk/generated/protos/service/external_entity/v1/candidate_pb.js +90 -0
- package/dist/sdk/generated/protos/service/external_entity/v1/company_pb.js +33 -0
- package/dist/sdk/generated/protos/service/external_entity/v1/external_entity_pb.js +155 -0
- package/dist/sdk/generated/protos/service/external_entity/v1/people_pb.js +251 -0
- package/dist/sdk/generated/protos/service/external_tool_connection/v1/composio_connector_pb.js +46 -0
- package/dist/sdk/generated/protos/service/external_tool_connection/v1/connection_manager_pb.js +280 -0
- package/dist/sdk/generated/protos/service/feature_config/feature_config_pb.js +95 -0
- package/dist/sdk/generated/protos/service/feedback/v1/feedback_pb.js +152 -0
- package/dist/sdk/generated/protos/service/filestore/v1/filestore_pb.js +145 -0
- package/dist/sdk/generated/protos/service/jiraservice/v1/jiraservice_pb.js +163 -0
- package/dist/sdk/generated/protos/service/llmservice/v1/llmservice_pb.js +1009 -0
- package/dist/sdk/generated/protos/service/llmservice/v1/pii_pb.js +532 -0
- package/dist/sdk/generated/protos/service/llmserviceproxy/v1/llmserviceproxy_pb.js +17 -0
- package/dist/sdk/generated/protos/service/metricservice/v1/metricservice_pb.js +351 -0
- package/dist/sdk/generated/protos/service/ml/v1/categories_pb.js +13 -0
- package/dist/sdk/generated/protos/service/ml/v1/categorizer_pb.js +47 -0
- package/dist/sdk/generated/protos/service/permissions/permissions_pb.js +182 -0
- package/dist/sdk/generated/protos/service/persona/v1/answerticket_pb.js +86 -0
- package/dist/sdk/generated/protos/service/persona/v1/chatbot_pb.js +27 -0
- package/dist/sdk/generated/protos/service/persona/v1/debug_logs_pb.js +45 -0
- package/dist/sdk/generated/protos/service/persona/v1/persona_config_pb.js +2152 -0
- package/dist/sdk/generated/protos/service/persona/v1/persona_pb.js +1207 -0
- package/dist/sdk/generated/protos/service/persona/v1/shared_widgets/widget_types_pb.js +422 -0
- package/dist/sdk/generated/protos/service/persona/v1/voicebot_widgets/widget_types_pb.js +64 -0
- package/dist/sdk/generated/protos/service/proposal/v1/proposal_pb.js +196 -0
- package/dist/sdk/generated/protos/service/quota/v1/quota_pb.js +42 -0
- package/dist/sdk/generated/protos/service/search/v1/search_pb.js +465 -0
- package/dist/sdk/generated/protos/service/search/v2/search_pb.js +93 -0
- package/dist/sdk/generated/protos/service/serverless/v1/inference_pb.js +139 -0
- package/dist/sdk/generated/protos/service/tenant/v1/tenant_pb.js +137 -0
- package/dist/sdk/generated/protos/service/ticketing/v1/ticket_context_pb.js +266 -0
- package/dist/sdk/generated/protos/service/ticketing/v1/ticketing_pb.js +192 -0
- package/dist/sdk/generated/protos/service/ticketing/v1/unified_ticket_model_pb.js +70 -0
- package/dist/sdk/generated/protos/service/token/v1/token_pb.js +38 -0
- package/dist/sdk/generated/protos/service/tool_bench/v1/tool_bench_pb.js +17 -0
- package/dist/sdk/generated/protos/service/transform/v1/transform_pb.js +378 -0
- package/dist/sdk/generated/protos/service/user/v1/user_pb.js +100 -0
- package/dist/sdk/generated/protos/service/user_internal/v1/user_internal_pb.js +50 -0
- package/dist/sdk/generated/protos/service/utils/v1/utils_pb.js +139 -0
- package/dist/sdk/generated/protos/service/voice/v1/voice_pb.js +58 -0
- package/dist/sdk/generated/protos/service/webcrawl/v1/webcrawl_pb.js +23 -0
- package/dist/sdk/generated/protos/service/webcrawler/v1/webcrawler_pb.js +32 -0
- package/dist/sdk/generated/protos/service/workflows/v1/action_registry_pb.js +406 -0
- package/dist/sdk/generated/protos/service/workflows/v1/action_runner_pb.js +82 -0
- package/dist/sdk/generated/protos/service/workflows/v1/action_type_pb.js +330 -0
- package/dist/sdk/generated/protos/service/workflows/v1/chatbot_pb.js +194 -0
- package/dist/sdk/generated/protos/service/workflows/v1/common_forms_pb.js +29 -0
- package/dist/sdk/generated/protos/service/workflows/v1/common_pb.js +76 -0
- package/dist/sdk/generated/protos/service/workflows/v1/coordinator_pb.js +131 -0
- package/dist/sdk/generated/protos/service/workflows/v1/dashboards_pb.js +522 -0
- package/dist/sdk/generated/protos/service/workflows/v1/embedded_persona_runner_pb.js +37 -0
- package/dist/sdk/generated/protos/service/workflows/v1/external_actions_pb.js +164 -0
- package/dist/sdk/generated/protos/service/workflows/v1/human_in_the_loop_pb.js +47 -0
- package/dist/sdk/generated/protos/service/workflows/v1/human_interactions_pb.js +14 -0
- package/dist/sdk/generated/protos/service/workflows/v1/lifecycle_pb.js +103 -0
- package/dist/sdk/generated/protos/service/workflows/v1/log_type_pb.js +160 -0
- package/dist/sdk/generated/protos/service/workflows/v1/names_pb.js +33 -0
- package/dist/sdk/generated/protos/service/workflows/v1/rpc/workflow_rpc_pb.js +188 -0
- package/dist/sdk/generated/protos/service/workflows/v1/rules_pb.js +329 -0
- package/dist/sdk/generated/protos/service/workflows/v1/types_pb.js +14 -0
- package/dist/sdk/generated/protos/service/workflows/v1/values_pb.js +243 -0
- package/dist/sdk/generated/protos/service/workflows/v1/well_known_pb.js +559 -0
- package/dist/sdk/generated/protos/service/workflows/v1/workflow_pb.js +307 -0
- package/dist/sdk/generated/protos/service/workspace/v1/workspace_pb.js +57 -0
- package/dist/sdk/generated/protos/util/auth_annotations_pb.js +104 -0
- package/dist/sdk/generated/protos/util/test_service_pb.js +26 -0
- package/dist/sdk/generated/protos/util/tracking_metadata_pb.js +13 -0
- package/dist/sdk/generation-schema.js +5 -5
- package/dist/sdk/grpc-client.js +268 -0
- package/dist/sdk/guidance.js +560 -0
- package/dist/sdk/index.js +20 -0
- package/dist/sdk/intent-architect.js +52 -21
- package/dist/sdk/knowledge.js +190 -198
- package/dist/sdk/logging.js +98 -0
- package/dist/sdk/models.js +81 -4
- package/dist/sdk/paths.js +70 -0
- package/dist/sdk/proto-config.js +173 -0
- package/dist/sdk/sanitizer.js +174 -2
- package/dist/sdk/structural-rules.js +1 -1
- package/dist/sdk/sync-options.js +8 -3
- package/dist/sdk/validation-rules.js +5 -12
- package/dist/sdk/workflow-fixer.js +131 -24
- package/dist/sdk/workflow-generator.js +29 -3
- package/dist/sdk/workflow-merge.js +449 -0
- package/dist/sdk/workflow-transformer.js +389 -2
- package/dist/sdk/workflow-validator.js +10 -7
- package/docs/CODEBASE-ANALYSIS-2026-01-23.md +936 -0
- package/docs/CODEBASE-ANALYSIS-PRIORITIZED.md +774 -0
- package/docs/blog/mcp-tool-design-lessons.md +309 -0
- package/docs/dashboard-operations.md +246 -0
- package/docs/ema-user-guide.md +29 -14
- package/docs/email-patterns.md +120 -0
- package/docs/lessons-learned.md +209 -0
- package/docs/mcp-tools-guide.md +286 -61
- package/docs/migration/action-composition-migration.md +270 -0
- package/docs/naming-conventions.md +85 -25
- package/docs/proposals/HANDOFF-tool-restructure.md +526 -0
- package/docs/proposals/action-composition.md +490 -0
- package/docs/proposals/explicit-method-restructure.md +328 -0
- package/docs/proposals/mcp-tool-restructure-2026-01.md +366 -0
- package/docs/proposals/self-contained-guidance.md +427 -0
- package/docs/proto-sdk-generation.md +242 -0
- package/docs/release-impact.md +102 -0
- package/docs/release-process.md +25 -21
- package/docs/staging.RULE.md +142 -0
- package/docs/tool-consolidation-v2.md +19 -9
- package/docs/tool-response-standards.md +256 -0
- package/package.json +20 -5
- package/resources/config/gates.json +2 -1
- package/resources/docs/getting-started.md +97 -0
- package/resources/templates/auto-builder-rules.md +8 -6
- package/resources/templates/demo-scenarios/test-published-package.md +2 -2
- package/resources/templates/document-gen-ai/README.md +132 -0
- package/resources/templates/document-gen-ai/persona-config.json +316 -0
- package/resources/templates/voice-ai/workflow-prompt.md +11 -10
- package/dist/sdk/contracts.js +0 -430
- package/docs/tool-consolidation-proposal.md +0 -215
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ MCP (Model Context Protocol) server for managing Ema AI Employees. Works with Cu
|
|
|
7
7
|
### Option 1: npx (Recommended)
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @ema.co/mcp-toolkit
|
|
10
|
+
npx -y @ema.co/mcp-toolkit@latest
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
### Option 2: Global Install
|
|
@@ -63,7 +63,7 @@ Then reload: `source ~/.zshrc`
|
|
|
63
63
|
"mcpServers": {
|
|
64
64
|
"ema": {
|
|
65
65
|
"command": "npx",
|
|
66
|
-
"args": ["@ema.co/mcp-toolkit"],
|
|
66
|
+
"args": ["-y", "@ema.co/mcp-toolkit@latest"],
|
|
67
67
|
"env": {
|
|
68
68
|
"EMA_ENV_NAME": "demo",
|
|
69
69
|
"EMA_PROD_BEARER_TOKEN": "${env:EMA_PROD_BEARER_TOKEN}",
|
|
@@ -77,6 +77,8 @@ Then reload: `source ~/.zshrc`
|
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
> **Important**:
|
|
80
|
+
> - Use `@latest` to always get the newest version (npx caches aggressively without it)
|
|
81
|
+
> - The `-y` flag auto-confirms the npx install prompt
|
|
80
82
|
> - Use `${env:VAR_NAME}` syntax to reference shell environment variables
|
|
81
83
|
> - After changing mcp.json, restart the MCP server: `Cmd+Shift+P` → "MCP: Restart Server"
|
|
82
84
|
> - After changing ~/.zshrc, reload it AND restart Cursor for changes to take effect
|
|
@@ -88,7 +90,7 @@ Then reload: `source ~/.zshrc`
|
|
|
88
90
|
"mcpServers": {
|
|
89
91
|
"ema": {
|
|
90
92
|
"command": "npx",
|
|
91
|
-
"args": ["@ema.co/mcp-toolkit"],
|
|
93
|
+
"args": ["-y", "@ema.co/mcp-toolkit@latest"],
|
|
92
94
|
"env": {
|
|
93
95
|
"EMA_ENV_NAME": "demo",
|
|
94
96
|
"EMA_DEMO_BEARER_TOKEN": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
@@ -202,46 +204,71 @@ environments:
|
|
|
202
204
|
|
|
203
205
|
| Tool | Purpose |
|
|
204
206
|
|------|---------|
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `action` | Agent lookup, docs, and recommendations |
|
|
209
|
-
| `template` | Patterns, widgets, qualifying questions |
|
|
210
|
-
| `knowledge` | Data sources + embedding + dashboard data (upload/list/dashboard_rows/dashboard_clone) |
|
|
211
|
-
| `reference` | Concepts, guidance, validation, common mistakes |
|
|
207
|
+
| `persona` | **Primary**: AI Employee management (create/clone/modify/analyze/sanitize/optimize) |
|
|
208
|
+
| `data` | **v2**: Simplified data management (list/upload/delete/sanitize/embedding) |
|
|
209
|
+
| `reference` | **v2**: All reference info (envs, actions, templates, patterns, concepts, guidance) |
|
|
212
210
|
| `sync` | Sync across environments |
|
|
211
|
+
| `knowledge` | Data sources (legacy, use `data`) |
|
|
212
|
+
| `action` | Agent lookup (legacy, use `reference(type="actions")`) |
|
|
213
|
+
| `template` | Patterns (legacy, use `reference`) |
|
|
214
|
+
| `env` | Environments (legacy, use `reference(type="envs")`) |
|
|
213
215
|
| `demo` | Demo/RAG document utilities |
|
|
214
216
|
|
|
215
217
|
### Common Workflows
|
|
216
218
|
|
|
217
|
-
**Create new AI Employee
|
|
219
|
+
**Create new AI Employee:**
|
|
218
220
|
```typescript
|
|
219
|
-
|
|
220
|
-
// Preview by default, use preview=false to deploy
|
|
221
|
+
persona(input="IT helpdesk with KB search", type="chat", name="IT Support", preview=false)
|
|
221
222
|
```
|
|
222
223
|
|
|
223
|
-
**
|
|
224
|
+
**Modify existing AI Employee:**
|
|
224
225
|
```typescript
|
|
225
|
-
|
|
226
|
-
workflow(mode="extend", persona_id="abc-123", input="add caller_type categorizer, add HITL before email, add compliance intent")
|
|
227
|
-
// Preview by default, use preview=false to deploy
|
|
226
|
+
persona(id="abc-123", input="add HITL before email, add compliance intent", preview=false)
|
|
228
227
|
```
|
|
229
228
|
|
|
230
229
|
**Fix issues automatically:**
|
|
231
230
|
```typescript
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
persona(id="abc-123", optimize=true, preview=false)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Get reference info:**
|
|
235
|
+
```typescript
|
|
236
|
+
reference(type="envs") // List environments
|
|
237
|
+
reference(type="actions", id="send_email") // Get action details
|
|
238
|
+
reference(type="patterns", pattern="intent-routing") // Get pattern
|
|
234
239
|
```
|
|
235
240
|
|
|
236
241
|
## Dynamic Resources
|
|
237
242
|
|
|
238
|
-
| Resource |
|
|
239
|
-
|
|
240
|
-
| `ema://catalog/agents` | Live from API |
|
|
241
|
-
| `ema://catalog/templates` |
|
|
243
|
+
| Resource | Purpose |
|
|
244
|
+
|----------|---------|
|
|
245
|
+
| `ema://catalog/agents` | Live action catalog from API |
|
|
246
|
+
| `ema://catalog/templates` | Persona templates from API |
|
|
242
247
|
| `ema://catalog/patterns` | Workflow patterns |
|
|
243
|
-
| `ema://
|
|
244
|
-
| `ema://rules
|
|
248
|
+
| `ema://docs/usage-guide` | Complete usage guide (generated) |
|
|
249
|
+
| `ema://guidance/rules` | Structured rules as JSON |
|
|
250
|
+
| `ema://guidance/cursor-rule` | Export as Cursor .mdc rule |
|
|
251
|
+
| `ema://guidance/server-instructions` | Server instructions text |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Self-Contained Guidance
|
|
256
|
+
|
|
257
|
+
The MCP is fully self-contained—no external configuration files needed.
|
|
258
|
+
|
|
259
|
+
**How it works:**
|
|
260
|
+
- Server instructions are injected on MCP init (system prompt)
|
|
261
|
+
- Tools include usage tips in their descriptions
|
|
262
|
+
- Responses include `_tip` and `_next_step` fields with contextual guidance
|
|
263
|
+
- `env()` returns a getting_started guide with workflow patterns
|
|
264
|
+
- `persona(..., analyze=true)` includes workflow_guidance with state-specific tips
|
|
265
|
+
|
|
266
|
+
**For other services:**
|
|
267
|
+
- Read `ema://guidance/rules` (JSON) for programmatic consumption
|
|
268
|
+
- Read `ema://docs/usage-guide` (markdown) for documentation
|
|
269
|
+
- Read `ema://guidance/cursor-rule` (.mdc) for IDE integration
|
|
270
|
+
|
|
271
|
+
All guidance flows from a single source (`src/sdk/guidance.ts`).
|
|
245
272
|
|
|
246
273
|
---
|
|
247
274
|
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Handler
|
|
3
|
+
*
|
|
4
|
+
* Provides action/agent lookup, filtering, and documentation.
|
|
5
|
+
*/
|
|
6
|
+
import { AGENT_CATALOG, getAgentByName, suggestAgentsForUseCase, } from "../../../sdk/knowledge.js";
|
|
7
|
+
// Deprecated param mappings for backwards compatibility
|
|
8
|
+
const DEPRECATED_PARAMS = {
|
|
9
|
+
identifier: { newName: "id", message: "'identifier' is deprecated, use 'id' instead (will be removed in v2.0.0)" },
|
|
10
|
+
};
|
|
11
|
+
function checkDeprecatedParams(args) {
|
|
12
|
+
const warnings = [];
|
|
13
|
+
for (const [oldName, info] of Object.entries(DEPRECATED_PARAMS)) {
|
|
14
|
+
if (args[oldName] !== undefined) {
|
|
15
|
+
warnings.push(info.message);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return warnings;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Handle action tool requests - list, get, filter, and search actions
|
|
22
|
+
*/
|
|
23
|
+
export async function handleAction(args, client) {
|
|
24
|
+
// Check for deprecated params and log warnings
|
|
25
|
+
const deprecationWarnings = checkDeprecatedParams(args);
|
|
26
|
+
for (const warning of deprecationWarnings) {
|
|
27
|
+
console.warn(`[action] Deprecation: ${warning}`);
|
|
28
|
+
}
|
|
29
|
+
const id = args.id;
|
|
30
|
+
const identifier = args.identifier; // deprecated alias for 'id'
|
|
31
|
+
const idOrName = id ?? identifier;
|
|
32
|
+
// Categories list
|
|
33
|
+
if (args.categories) {
|
|
34
|
+
const categories = [...new Set(Object.values(AGENT_CATALOG).map(a => a.category))];
|
|
35
|
+
return { categories, count: categories.length };
|
|
36
|
+
}
|
|
37
|
+
// Suggest for use case
|
|
38
|
+
if (args.suggest) {
|
|
39
|
+
const suggestions = suggestAgentsForUseCase(args.suggest);
|
|
40
|
+
return { suggestions, use_case: args.suggest };
|
|
41
|
+
}
|
|
42
|
+
// Get single action
|
|
43
|
+
if (idOrName) {
|
|
44
|
+
// Try API first
|
|
45
|
+
try {
|
|
46
|
+
const actions = await client.listActions();
|
|
47
|
+
const action = actions.find(a => a.id === idOrName ||
|
|
48
|
+
a.name === idOrName ||
|
|
49
|
+
a.name?.toLowerCase() === idOrName.toLowerCase());
|
|
50
|
+
const result = action ? {
|
|
51
|
+
id: action.id,
|
|
52
|
+
name: action.name,
|
|
53
|
+
category: action.category,
|
|
54
|
+
enabled: action.enabled,
|
|
55
|
+
inputs: action.inputs,
|
|
56
|
+
outputs: action.outputs,
|
|
57
|
+
source: "api",
|
|
58
|
+
} : {};
|
|
59
|
+
// Include docs if requested or if not found in API
|
|
60
|
+
if (args.include_docs || !action) {
|
|
61
|
+
const doc = getAgentByName(idOrName);
|
|
62
|
+
if (doc) {
|
|
63
|
+
result.documentation = doc;
|
|
64
|
+
result.source = action ? "api+docs" : "docs";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (Object.keys(result).length === 0) {
|
|
68
|
+
return { error: `Action not found: ${idOrName}` };
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Fallback to docs only
|
|
74
|
+
const doc = getAgentByName(idOrName);
|
|
75
|
+
if (doc) {
|
|
76
|
+
return { ...doc, source: "docs" };
|
|
77
|
+
}
|
|
78
|
+
return { error: `Action not found: ${idOrName}` };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// List actions
|
|
82
|
+
try {
|
|
83
|
+
let actions = await client.listActions();
|
|
84
|
+
// Apply filters
|
|
85
|
+
if (args.query) {
|
|
86
|
+
const q = args.query.toLowerCase();
|
|
87
|
+
actions = actions.filter(a => a.name?.toLowerCase().includes(q));
|
|
88
|
+
}
|
|
89
|
+
if (args.category) {
|
|
90
|
+
actions = actions.filter(a => a.category === args.category);
|
|
91
|
+
}
|
|
92
|
+
if (args.enabled !== undefined) {
|
|
93
|
+
actions = actions.filter(a => a.enabled === args.enabled);
|
|
94
|
+
}
|
|
95
|
+
// Filter by persona workflow
|
|
96
|
+
if (args.persona_id) {
|
|
97
|
+
const persona = await client.getPersonaById(args.persona_id);
|
|
98
|
+
if (persona?.workflow_id) {
|
|
99
|
+
const workflowActionIds = await client.listActionsFromWorkflow(persona.workflow_id);
|
|
100
|
+
const actionIdSet = new Set(workflowActionIds);
|
|
101
|
+
actions = actions.filter(a => actionIdSet.has(a.id));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Apply limit
|
|
105
|
+
const limit = args.limit || 100;
|
|
106
|
+
actions = actions.slice(0, limit);
|
|
107
|
+
// Include docs if requested
|
|
108
|
+
if (args.include_docs) {
|
|
109
|
+
return {
|
|
110
|
+
count: actions.length,
|
|
111
|
+
actions: actions.map(a => ({
|
|
112
|
+
...a,
|
|
113
|
+
documentation: a.name ? getAgentByName(a.name) : undefined,
|
|
114
|
+
})),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
count: actions.length,
|
|
119
|
+
actions: actions.map(a => ({
|
|
120
|
+
id: a.id,
|
|
121
|
+
name: a.name,
|
|
122
|
+
category: a.category,
|
|
123
|
+
enabled: a.enabled,
|
|
124
|
+
})),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
// Fallback to catalog only
|
|
129
|
+
let agents = Object.entries(AGENT_CATALOG);
|
|
130
|
+
if (args.category) {
|
|
131
|
+
agents = agents.filter(([_, a]) => a.category === args.category);
|
|
132
|
+
}
|
|
133
|
+
if (args.query) {
|
|
134
|
+
const q = args.query.toLowerCase();
|
|
135
|
+
agents = agents.filter(([name]) => name.toLowerCase().includes(q));
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
count: agents.length,
|
|
139
|
+
actions: agents.map(([name, agent]) => ({
|
|
140
|
+
name,
|
|
141
|
+
category: agent.category,
|
|
142
|
+
description: agent.description,
|
|
143
|
+
source: "catalog",
|
|
144
|
+
})),
|
|
145
|
+
note: "Live API unavailable, showing catalog data",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Executor - Executes composable action sequences
|
|
3
|
+
*
|
|
4
|
+
* Replaces flag-based parameters with explicit action composition.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* ```
|
|
8
|
+
* persona(
|
|
9
|
+
* method="create",
|
|
10
|
+
* from="source-id",
|
|
11
|
+
* name="Clone",
|
|
12
|
+
* actions=[
|
|
13
|
+
* {tool:"data", args:{method:"copy", from:"$source"}},
|
|
14
|
+
* {tool:"data", args:{method:"sanitize", examples:["Acme"]}},
|
|
15
|
+
* {tool:"snapshot", args:{message:"Clone ready"}},
|
|
16
|
+
* ]
|
|
17
|
+
* )
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Context variables:
|
|
21
|
+
* - $source: The `from` parameter (template/persona ID being cloned)
|
|
22
|
+
* - $target: The ID of the created/modified persona
|
|
23
|
+
* - $env: Current environment name
|
|
24
|
+
*/
|
|
25
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
|
+
// Action Aliases
|
|
27
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Built-in action aliases for common patterns
|
|
30
|
+
*/
|
|
31
|
+
export const ACTION_ALIASES = {
|
|
32
|
+
// Copy data from source to target
|
|
33
|
+
"copy-data": [
|
|
34
|
+
{ tool: "data", args: { method: "copy", from: "$source" } },
|
|
35
|
+
],
|
|
36
|
+
// Copy and sanitize data
|
|
37
|
+
"copy-and-sanitize": [
|
|
38
|
+
{ tool: "data", args: { method: "copy", from: "$source" } },
|
|
39
|
+
{ tool: "data", args: { method: "sanitize" } },
|
|
40
|
+
],
|
|
41
|
+
// Standard demo setup: copy, sanitize, snapshot
|
|
42
|
+
"standard-demo-setup": [
|
|
43
|
+
{ tool: "data", args: { method: "copy", from: "$source" } },
|
|
44
|
+
{ tool: "data", args: { method: "sanitize" } },
|
|
45
|
+
{ tool: "snapshot", args: { message: "Demo setup complete" } },
|
|
46
|
+
],
|
|
47
|
+
// Snapshot only
|
|
48
|
+
"create-snapshot": [
|
|
49
|
+
{ tool: "snapshot", args: { message: "Checkpoint" } },
|
|
50
|
+
],
|
|
51
|
+
// Validate workflow
|
|
52
|
+
"validate-workflow": [
|
|
53
|
+
{ tool: "validate", args: { checks: ["workflow"] } },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
57
|
+
// Context Substitution
|
|
58
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
/**
|
|
60
|
+
* Substitute context variables in action args
|
|
61
|
+
*
|
|
62
|
+
* Variables:
|
|
63
|
+
* - $source → context.source
|
|
64
|
+
* - $target → context.target
|
|
65
|
+
* - $env → context.env
|
|
66
|
+
*/
|
|
67
|
+
function substituteContext(action, context) {
|
|
68
|
+
// Deep clone args to avoid mutation
|
|
69
|
+
const args = JSON.parse(JSON.stringify(action.args));
|
|
70
|
+
function substitute(obj) {
|
|
71
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
72
|
+
if (typeof value === "string") {
|
|
73
|
+
obj[key] = value
|
|
74
|
+
.replace(/\$source/g, context.source ?? "")
|
|
75
|
+
.replace(/\$target/g, context.target ?? "")
|
|
76
|
+
.replace(/\$env/g, context.env ?? "");
|
|
77
|
+
}
|
|
78
|
+
else if (Array.isArray(value)) {
|
|
79
|
+
for (let i = 0; i < value.length; i++) {
|
|
80
|
+
if (typeof value[i] === "string") {
|
|
81
|
+
value[i] = value[i]
|
|
82
|
+
.replace(/\$source/g, context.source ?? "")
|
|
83
|
+
.replace(/\$target/g, context.target ?? "")
|
|
84
|
+
.replace(/\$env/g, context.env ?? "");
|
|
85
|
+
}
|
|
86
|
+
else if (typeof value[i] === "object" && value[i] !== null) {
|
|
87
|
+
substitute(value[i]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (typeof value === "object" && value !== null) {
|
|
92
|
+
substitute(value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
substitute(args);
|
|
97
|
+
return { tool: action.tool, args };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Expand aliases into action specs
|
|
101
|
+
*/
|
|
102
|
+
function expandAliases(actions) {
|
|
103
|
+
const expanded = [];
|
|
104
|
+
for (const action of actions) {
|
|
105
|
+
if (typeof action === "string") {
|
|
106
|
+
// It's an alias
|
|
107
|
+
const aliasActions = ACTION_ALIASES[action];
|
|
108
|
+
if (aliasActions) {
|
|
109
|
+
expanded.push(...aliasActions);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Unknown alias - will be reported as error during execution
|
|
113
|
+
console.warn(`[action-executor] Unknown alias: ${action}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// It's an action spec
|
|
118
|
+
expanded.push(action);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return expanded;
|
|
122
|
+
}
|
|
123
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
124
|
+
// Action Handlers
|
|
125
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
126
|
+
/**
|
|
127
|
+
* Execute a data action using the real data handler
|
|
128
|
+
*/
|
|
129
|
+
async function executeDataAction(args, context, client) {
|
|
130
|
+
const method = args.method;
|
|
131
|
+
const targetId = context.target;
|
|
132
|
+
if (!targetId) {
|
|
133
|
+
throw new Error("No target persona ID available for data action");
|
|
134
|
+
}
|
|
135
|
+
// Substitute context variables in args
|
|
136
|
+
const resolvedArgs = { ...args };
|
|
137
|
+
if (typeof resolvedArgs.from === "string") {
|
|
138
|
+
resolvedArgs.from = resolvedArgs.from
|
|
139
|
+
.replace(/\$source/g, context.source ?? "")
|
|
140
|
+
.replace(/\$target/g, context.target ?? "");
|
|
141
|
+
}
|
|
142
|
+
// Import and use the unified data handler
|
|
143
|
+
const { handleData } = await import("./data/index.js");
|
|
144
|
+
const result = await handleData({
|
|
145
|
+
persona_id: targetId,
|
|
146
|
+
data: { method, ...resolvedArgs },
|
|
147
|
+
mode: "data", // Legacy mode marker
|
|
148
|
+
}, client);
|
|
149
|
+
// Check for errors in result
|
|
150
|
+
if (result.error) {
|
|
151
|
+
throw new Error(result.error);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Execute a snapshot action
|
|
157
|
+
*/
|
|
158
|
+
async function executeSnapshotAction(args, context, client) {
|
|
159
|
+
const message = args.message ?? "Action-created snapshot";
|
|
160
|
+
const targetId = context.target;
|
|
161
|
+
if (!targetId) {
|
|
162
|
+
throw new Error("No target persona ID available for snapshot action");
|
|
163
|
+
}
|
|
164
|
+
// For now, return a placeholder
|
|
165
|
+
// Full implementation would call the version storage API
|
|
166
|
+
return {
|
|
167
|
+
status: "snapshot_created",
|
|
168
|
+
persona_id: targetId,
|
|
169
|
+
message,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
note: "Full snapshot integration pending version storage implementation",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Execute a validate action
|
|
176
|
+
*/
|
|
177
|
+
async function executeValidateAction(args, context, client) {
|
|
178
|
+
const checks = args.checks ?? ["workflow", "config"];
|
|
179
|
+
const targetId = context.target;
|
|
180
|
+
if (!targetId) {
|
|
181
|
+
throw new Error("No target persona ID available for validate action");
|
|
182
|
+
}
|
|
183
|
+
// Fetch persona and run validation
|
|
184
|
+
const persona = await client.getPersonaById(targetId);
|
|
185
|
+
if (!persona) {
|
|
186
|
+
throw new Error(`Persona not found: ${targetId}`);
|
|
187
|
+
}
|
|
188
|
+
const results = {};
|
|
189
|
+
if (checks.includes("workflow")) {
|
|
190
|
+
const workflowDef = persona.workflow_def;
|
|
191
|
+
results.workflow = {
|
|
192
|
+
has_workflow: !!persona.workflow_def,
|
|
193
|
+
node_count: workflowDef?.nodes?.length ?? 0,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (checks.includes("config")) {
|
|
197
|
+
const protoConfig = persona.proto_config;
|
|
198
|
+
results.config = {
|
|
199
|
+
has_proto_config: !!persona.proto_config,
|
|
200
|
+
widget_count: protoConfig?.widgets?.length ?? 0,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
status: "validated",
|
|
205
|
+
persona_id: targetId,
|
|
206
|
+
checks,
|
|
207
|
+
results,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Execute a single action
|
|
212
|
+
*/
|
|
213
|
+
async function executeAction(action, context, client) {
|
|
214
|
+
switch (action.tool) {
|
|
215
|
+
case "data":
|
|
216
|
+
return executeDataAction(action.args, context, client);
|
|
217
|
+
case "snapshot":
|
|
218
|
+
return executeSnapshotAction(action.args, context, client);
|
|
219
|
+
case "validate":
|
|
220
|
+
return executeValidateAction(action.args, context, client);
|
|
221
|
+
default:
|
|
222
|
+
throw new Error(`Unknown action tool: ${action.tool}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
226
|
+
// Main Executor
|
|
227
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
228
|
+
/**
|
|
229
|
+
* Execute a sequence of actions with context substitution
|
|
230
|
+
*
|
|
231
|
+
* @param actions - Array of action specs or alias strings
|
|
232
|
+
* @param context - Execution context with source/target IDs
|
|
233
|
+
* @param client - EmaClient for API calls
|
|
234
|
+
* @returns Results of all action executions
|
|
235
|
+
*/
|
|
236
|
+
export async function executeActions(actions, context, client) {
|
|
237
|
+
const results = [];
|
|
238
|
+
let succeeded = 0;
|
|
239
|
+
let failed = 0;
|
|
240
|
+
let stoppedOnError = false;
|
|
241
|
+
// Expand aliases
|
|
242
|
+
const expanded = expandAliases(actions);
|
|
243
|
+
// Execute in sequence
|
|
244
|
+
for (const action of expanded) {
|
|
245
|
+
const startTime = Date.now();
|
|
246
|
+
// Substitute context variables
|
|
247
|
+
const substituted = substituteContext(action, context);
|
|
248
|
+
try {
|
|
249
|
+
const result = await executeAction(substituted, context, client);
|
|
250
|
+
results.push({
|
|
251
|
+
tool: action.tool,
|
|
252
|
+
status: "success",
|
|
253
|
+
result,
|
|
254
|
+
duration_ms: Date.now() - startTime,
|
|
255
|
+
});
|
|
256
|
+
succeeded++;
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
results.push({
|
|
260
|
+
tool: action.tool,
|
|
261
|
+
status: "error",
|
|
262
|
+
error: error instanceof Error ? error.message : String(error),
|
|
263
|
+
duration_ms: Date.now() - startTime,
|
|
264
|
+
});
|
|
265
|
+
failed++;
|
|
266
|
+
stoppedOnError = true;
|
|
267
|
+
break; // Stop on first error
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
executed: results.length,
|
|
272
|
+
succeeded,
|
|
273
|
+
failed,
|
|
274
|
+
results,
|
|
275
|
+
stopped_on_error: stoppedOnError ? true : undefined,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Check if actions array contains any valid actions
|
|
280
|
+
*/
|
|
281
|
+
export function hasActions(actions) {
|
|
282
|
+
return Array.isArray(actions) && actions.length > 0;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Validate actions array structure
|
|
286
|
+
*/
|
|
287
|
+
export function validateActions(actions) {
|
|
288
|
+
const errors = [];
|
|
289
|
+
if (!Array.isArray(actions)) {
|
|
290
|
+
return { valid: false, errors: ["actions must be an array"] };
|
|
291
|
+
}
|
|
292
|
+
for (let i = 0; i < actions.length; i++) {
|
|
293
|
+
const action = actions[i];
|
|
294
|
+
if (typeof action === "string") {
|
|
295
|
+
// Alias - check if known
|
|
296
|
+
if (!ACTION_ALIASES[action]) {
|
|
297
|
+
errors.push(`actions[${i}]: unknown alias "${action}". Valid: ${Object.keys(ACTION_ALIASES).join(", ")}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (typeof action === "object" && action !== null) {
|
|
301
|
+
// Action spec - check required fields
|
|
302
|
+
const spec = action;
|
|
303
|
+
if (!spec.tool) {
|
|
304
|
+
errors.push(`actions[${i}]: missing required field "tool"`);
|
|
305
|
+
}
|
|
306
|
+
else if (!["data", "snapshot", "validate"].includes(spec.tool)) {
|
|
307
|
+
errors.push(`actions[${i}]: invalid tool "${spec.tool}". Valid: data, snapshot, validate`);
|
|
308
|
+
}
|
|
309
|
+
if (!spec.args || typeof spec.args !== "object") {
|
|
310
|
+
errors.push(`actions[${i}]: missing or invalid "args" object`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
errors.push(`actions[${i}]: must be object or string, got ${typeof action}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return { valid: errors.length === 0, errors };
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get list of available aliases with descriptions
|
|
321
|
+
*/
|
|
322
|
+
export function getAvailableAliases() {
|
|
323
|
+
return [
|
|
324
|
+
{
|
|
325
|
+
name: "copy-data",
|
|
326
|
+
description: "Copy data from source to target persona",
|
|
327
|
+
actions: ACTION_ALIASES["copy-data"],
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "copy-and-sanitize",
|
|
331
|
+
description: "Copy data then sanitize PII",
|
|
332
|
+
actions: ACTION_ALIASES["copy-and-sanitize"],
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
name: "standard-demo-setup",
|
|
336
|
+
description: "Copy, sanitize, and create snapshot",
|
|
337
|
+
actions: ACTION_ALIASES["standard-demo-setup"],
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "create-snapshot",
|
|
341
|
+
description: "Create a checkpoint snapshot",
|
|
342
|
+
actions: ACTION_ALIASES["create-snapshot"],
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: "validate-workflow",
|
|
346
|
+
description: "Run workflow validation checks",
|
|
347
|
+
actions: ACTION_ALIASES["validate-workflow"],
|
|
348
|
+
},
|
|
349
|
+
];
|
|
350
|
+
}
|