@ema.co/mcp-toolkit 0.2.0
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.
- package/LICENSE +21 -0
- package/README.md +321 -0
- package/config.example.yaml +32 -0
- package/dist/cli/index.js +333 -0
- package/dist/config.js +136 -0
- package/dist/emaClient.js +398 -0
- package/dist/index.js +109 -0
- package/dist/mcp/handlers-consolidated.js +851 -0
- package/dist/mcp/index.js +15 -0
- package/dist/mcp/prompts.js +1753 -0
- package/dist/mcp/resources.js +624 -0
- package/dist/mcp/server.js +4723 -0
- package/dist/mcp/tools-consolidated.js +590 -0
- package/dist/mcp/tools-legacy.js +736 -0
- package/dist/models.js +8 -0
- package/dist/scheduler.js +21 -0
- package/dist/sdk/client.js +788 -0
- package/dist/sdk/config.js +136 -0
- package/dist/sdk/contracts.js +429 -0
- package/dist/sdk/generation-schema.js +189 -0
- package/dist/sdk/index.js +39 -0
- package/dist/sdk/knowledge.js +2780 -0
- package/dist/sdk/models.js +8 -0
- package/dist/sdk/state.js +88 -0
- package/dist/sdk/sync-options.js +216 -0
- package/dist/sdk/sync.js +220 -0
- package/dist/sdk/validation-rules.js +355 -0
- package/dist/sdk/workflow-generator.js +291 -0
- package/dist/sdk/workflow-intent.js +1585 -0
- package/dist/state.js +88 -0
- package/dist/sync.js +416 -0
- package/dist/syncOptions.js +216 -0
- package/dist/ui.js +334 -0
- package/docs/advisor-comms-assistant-fixes.md +175 -0
- package/docs/api-contracts.md +216 -0
- package/docs/auto-builder-analysis.md +271 -0
- package/docs/data-architecture.md +166 -0
- package/docs/ema-auto-builder-guide.html +394 -0
- package/docs/ema-user-guide.md +1121 -0
- package/docs/mcp-tools-guide.md +149 -0
- package/docs/naming-conventions.md +218 -0
- package/docs/tool-consolidation-proposal.md +427 -0
- package/package.json +98 -0
- package/resources/templates/chat-ai/README.md +119 -0
- package/resources/templates/chat-ai/persona-config.json +111 -0
- package/resources/templates/dashboard-ai/README.md +156 -0
- package/resources/templates/dashboard-ai/persona-config.json +180 -0
- package/resources/templates/voice-ai/README.md +123 -0
- package/resources/templates/voice-ai/persona-config.json +74 -0
- package/resources/templates/voice-ai/workflow-prompt.md +120 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Advisor Communications Assistant - Workflow Fixes
|
|
2
|
+
|
|
3
|
+
**Persona ID**: `d5aa0b7a-792d-4e3d-8a74-ac87457ffca2`
|
|
4
|
+
**Environment**: demo
|
|
5
|
+
**Analysis Date**: 2026-01-10
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
| Severity | Count | Status |
|
|
10
|
+
|----------|-------|--------|
|
|
11
|
+
| Critical | 3 | Needs fix |
|
|
12
|
+
| Warning | 0 | - |
|
|
13
|
+
| Info | 4 | Acceptable |
|
|
14
|
+
|
|
15
|
+
## Critical Issues & Fixes
|
|
16
|
+
|
|
17
|
+
### Issue 1: Document → Email Attachment Type Mismatch
|
|
18
|
+
|
|
19
|
+
**Location**: `generate_documentnr7ttm` → `send_email_agentq7zdvj`
|
|
20
|
+
|
|
21
|
+
**Problem**:
|
|
22
|
+
- `document_link` output is type `WELL_KNOWN_TYPE_DOCUMENT`
|
|
23
|
+
- `attachment_links` input expects `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES`
|
|
24
|
+
|
|
25
|
+
**Fix Options**:
|
|
26
|
+
|
|
27
|
+
**Option A (Recommended)**: Use `named_inputs` instead
|
|
28
|
+
```yaml
|
|
29
|
+
# Change from:
|
|
30
|
+
send_email_agentq7zdvj.inputs.attachment_links:
|
|
31
|
+
actionOutput:
|
|
32
|
+
actionName: generate_documentnr7ttm
|
|
33
|
+
output: document_link
|
|
34
|
+
|
|
35
|
+
# To:
|
|
36
|
+
send_email_agentq7zdvj.inputs.named_inputs:
|
|
37
|
+
multiBinding:
|
|
38
|
+
elements:
|
|
39
|
+
- namedBinding:
|
|
40
|
+
name: document_attachment
|
|
41
|
+
value:
|
|
42
|
+
actionOutput:
|
|
43
|
+
actionName: generate_documentnr7ttm
|
|
44
|
+
output: document_link
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Option B**: Use a fixed_response node to convert document_link to text
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### Issue 2: Combined Results → Content Generator Type Mismatch
|
|
52
|
+
|
|
53
|
+
**Location**: `combine_search_resultssmoo58` → `personalized_content_generatorfosf62`
|
|
54
|
+
|
|
55
|
+
**Problem**:
|
|
56
|
+
- `combined_results` output is type `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES`
|
|
57
|
+
- `search_results` input expects `WELL_KNOWN_TYPE_SEARCH_RESULT`
|
|
58
|
+
|
|
59
|
+
**Fix**:
|
|
60
|
+
Route original search results directly instead of combined:
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
# Change from:
|
|
64
|
+
personalized_content_generatorfosf62.inputs.search_results:
|
|
65
|
+
actionOutput:
|
|
66
|
+
actionName: combine_search_resultssmoo58
|
|
67
|
+
output: combined_results
|
|
68
|
+
|
|
69
|
+
# To:
|
|
70
|
+
personalized_content_generatorfosf62.inputs.search_results:
|
|
71
|
+
actionOutput:
|
|
72
|
+
actionName: searchfleqzf
|
|
73
|
+
output: search_results
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Alternative**: Use `named_inputs` for combined results:
|
|
77
|
+
```yaml
|
|
78
|
+
personalized_content_generatorfosf62.inputs.named_inputs:
|
|
79
|
+
multiBinding:
|
|
80
|
+
elements:
|
|
81
|
+
- namedBinding:
|
|
82
|
+
name: combined_context
|
|
83
|
+
value:
|
|
84
|
+
actionOutput:
|
|
85
|
+
actionName: combine_search_resultssmoo58
|
|
86
|
+
output: combined_results
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Issue 3: Summarized Conversation → Custom Agent Conversation Mismatch
|
|
92
|
+
|
|
93
|
+
**Location**: `conversation_summarizer` → `custom_agentrjrvw6`
|
|
94
|
+
|
|
95
|
+
**Problem**:
|
|
96
|
+
- `summarized_conversation` is type `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES`
|
|
97
|
+
- `conversation` input expects `WELL_KNOWN_TYPE_CHAT_CONVERSATION`
|
|
98
|
+
|
|
99
|
+
**Fix**:
|
|
100
|
+
Use the trigger's conversation output instead:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
# Change from:
|
|
104
|
+
custom_agentrjrvw6.inputs.conversation:
|
|
105
|
+
actionOutput:
|
|
106
|
+
actionName: conversation_summarizer
|
|
107
|
+
output: summarized_conversation
|
|
108
|
+
|
|
109
|
+
# To:
|
|
110
|
+
custom_agentrjrvw6.inputs.conversation:
|
|
111
|
+
actionOutput:
|
|
112
|
+
actionName: trigger
|
|
113
|
+
output: chat_conversation
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
And pass the summarized query via `named_inputs`:
|
|
117
|
+
```yaml
|
|
118
|
+
custom_agentrjrvw6.inputs.named_inputs:
|
|
119
|
+
multiBinding:
|
|
120
|
+
elements:
|
|
121
|
+
- namedBinding:
|
|
122
|
+
name: context
|
|
123
|
+
value:
|
|
124
|
+
actionOutput:
|
|
125
|
+
actionName: conversation_summarizer
|
|
126
|
+
output: summarized_conversation
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Info Issues (Acceptable)
|
|
132
|
+
|
|
133
|
+
### Sequential Searches
|
|
134
|
+
The workflow has sequential dependencies between searches:
|
|
135
|
+
- `conversation_summarizer` → `live_web_search7kmyak`
|
|
136
|
+
- `searchfleqzf` → `combine_search_resultssmoo58`
|
|
137
|
+
|
|
138
|
+
**Assessment**: Acceptable - the searches depend on each other's outputs.
|
|
139
|
+
|
|
140
|
+
### Multiple LLM Nodes
|
|
141
|
+
5 LLM nodes process results from `searchfleqzf`:
|
|
142
|
+
- `respond_client_update`
|
|
143
|
+
- `respond_market_impact`
|
|
144
|
+
- `respond_exposure`
|
|
145
|
+
- `respond_compliance`
|
|
146
|
+
- `respond_health`
|
|
147
|
+
|
|
148
|
+
**Assessment**: Expected behavior - these are conditional branches from the categorizer.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Application Instructions
|
|
153
|
+
|
|
154
|
+
### Via Ema UI (Recommended)
|
|
155
|
+
1. Open persona in Auto Builder
|
|
156
|
+
2. For each critical issue:
|
|
157
|
+
- Click on the target node
|
|
158
|
+
- Modify the input binding as described
|
|
159
|
+
3. Save and test
|
|
160
|
+
|
|
161
|
+
### Via API
|
|
162
|
+
Use the `/api/personas/update_persona` endpoint with the corrected `workflow` field.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Type Compatibility Quick Reference
|
|
167
|
+
|
|
168
|
+
| From Type | Can Connect To |
|
|
169
|
+
|-----------|---------------|
|
|
170
|
+
| CHAT_CONVERSATION | conversation inputs, named_inputs |
|
|
171
|
+
| TEXT_WITH_SOURCES | query, named_inputs, instructions |
|
|
172
|
+
| SEARCH_RESULT | search_results inputs, named_inputs |
|
|
173
|
+
| DOCUMENT | named_inputs (NOT text inputs) |
|
|
174
|
+
|
|
175
|
+
**Rule**: When in doubt, use `named_inputs` - it accepts ANY type.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# API Contracts
|
|
2
|
+
|
|
3
|
+
This document explains how API contracts are managed between the Ema backend and the MCP toolkit.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
9
|
+
│ Ema Backend (Python) │
|
|
10
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
11
|
+
│ Pydantic Models (schema.py) → FastAPI → OpenAPI JSON │
|
|
12
|
+
│ │
|
|
13
|
+
│ PersonaDTO(BaseModel) → @router → /api/openapi.json │
|
|
14
|
+
│ ConversationDTO(BaseModel) │
|
|
15
|
+
│ MessageDTO(BaseModel) │
|
|
16
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
17
|
+
│
|
|
18
|
+
│ Auto-generated
|
|
19
|
+
▼
|
|
20
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ OpenAPI 3.0 Specification │
|
|
22
|
+
│ │
|
|
23
|
+
│ /api/openapi.json │
|
|
24
|
+
│ • paths: All REST endpoints │
|
|
25
|
+
│ • components/schemas: All data types │
|
|
26
|
+
│ • securitySchemes: Authentication │
|
|
27
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
28
|
+
│
|
|
29
|
+
┌──────────────┴──────────────┐
|
|
30
|
+
│ │
|
|
31
|
+
▼ ▼
|
|
32
|
+
┌────────────────────────────┐ ┌────────────────────────────────┐
|
|
33
|
+
│ Generated Types │ │ Zod Runtime Validation │
|
|
34
|
+
│ │ │ │
|
|
35
|
+
│ src/sdk/generated/ │ │ src/sdk/contracts.ts │
|
|
36
|
+
│ • api-types.ts │ │ • PersonaDTOSchema │
|
|
37
|
+
│ • openapi.json │ │ • validateResponse() │
|
|
38
|
+
│ │ │ • safeValidateResponse() │
|
|
39
|
+
└────────────────────────────┘ └────────────────────────────────┘
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Source of Truth
|
|
43
|
+
|
|
44
|
+
| Layer | File | Generated? | Runtime Validated? |
|
|
45
|
+
|-------|------|------------|-------------------|
|
|
46
|
+
| Backend | `ema_backend/web/api/*/schema.py` | No | Yes (Pydantic) |
|
|
47
|
+
| OpenAPI | `/api/openapi.json` | Yes (from Pydantic) | N/A |
|
|
48
|
+
| TypeScript Types | `src/sdk/generated/api-types.ts` | Yes (from OpenAPI) | No |
|
|
49
|
+
| Zod Schemas | `src/sdk/contracts.ts` | No (manual) | Yes (Zod) |
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
|
|
53
|
+
### 1. Backend Changes (Python)
|
|
54
|
+
|
|
55
|
+
When you add/modify a Pydantic model:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# ema_backend/web/api/personas/schema.py
|
|
59
|
+
class PersonaDTO(BaseModel):
|
|
60
|
+
id: str
|
|
61
|
+
name: str = Field(..., description="Display name of the AI Employee")
|
|
62
|
+
status: PersonaStateEnum
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The OpenAPI spec updates automatically (FastAPI generates it).
|
|
66
|
+
|
|
67
|
+
### 2. Generate TypeScript Types
|
|
68
|
+
|
|
69
|
+
After backend changes, regenerate TypeScript types:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# From ema-mcp-toolkit directory
|
|
73
|
+
npm run generate:types
|
|
74
|
+
|
|
75
|
+
# Or with a specific URL
|
|
76
|
+
npm run generate:types -- --url http://localhost:8000/api/openapi.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This creates/updates:
|
|
80
|
+
- `src/sdk/generated/api-types.ts` - TypeScript interfaces
|
|
81
|
+
- `src/sdk/generated/openapi.json` - Cached spec for CI
|
|
82
|
+
|
|
83
|
+
### 3. Update Zod Schemas (if needed)
|
|
84
|
+
|
|
85
|
+
If you need runtime validation, update `src/sdk/contracts.ts`:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
export const PersonaDTOSchema = z.object({
|
|
89
|
+
id: z.string(),
|
|
90
|
+
name: z.string(),
|
|
91
|
+
status: PersonaStateSchema,
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4. CI Contract Check
|
|
96
|
+
|
|
97
|
+
CI runs `npm run check:contracts` to detect drift:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm run check:contracts
|
|
101
|
+
|
|
102
|
+
# Output on drift:
|
|
103
|
+
# ❌ API contracts have drifted!
|
|
104
|
+
# Added schemas: NewSchemaName
|
|
105
|
+
# Modified schemas: PersonaDTO
|
|
106
|
+
# Regenerate types: npm run generate:types
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Using Contracts
|
|
110
|
+
|
|
111
|
+
### TypeScript Types (Compile-time)
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import type { PersonaDTO } from "./generated/api-types";
|
|
115
|
+
|
|
116
|
+
function processPersona(persona: PersonaDTO) {
|
|
117
|
+
console.log(persona.name);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Zod Validation (Runtime)
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { PersonaDTOSchema, safeValidateResponse } from "./contracts";
|
|
125
|
+
|
|
126
|
+
const response = await fetch("/api/personas/123");
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
|
|
129
|
+
const result = safeValidateResponse(PersonaDTOSchema, data);
|
|
130
|
+
if (result.success) {
|
|
131
|
+
console.log("Valid persona:", result.data);
|
|
132
|
+
} else {
|
|
133
|
+
console.error("Invalid response:", result.error);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Validating Lists
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { PersonaDTOSchema, validateList } from "./contracts";
|
|
141
|
+
|
|
142
|
+
const personas = validateList(PersonaDTOSchema, apiResponse.personas, "personas");
|
|
143
|
+
// Invalid items are logged and filtered out
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Scripts
|
|
147
|
+
|
|
148
|
+
| Script | Description |
|
|
149
|
+
|--------|-------------|
|
|
150
|
+
| `npm run generate:types` | Generate TypeScript types from OpenAPI |
|
|
151
|
+
| `npm run check:contracts` | Check for drift between spec and types |
|
|
152
|
+
|
|
153
|
+
### Script Options
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Generate from specific URL
|
|
157
|
+
npm run generate:types -- --url http://localhost:8000/api/openapi.json
|
|
158
|
+
|
|
159
|
+
# Generate from local file
|
|
160
|
+
npm run generate:types -- --file ./openapi.json
|
|
161
|
+
|
|
162
|
+
# Check against specific URL
|
|
163
|
+
npm run check:contracts -- --url http://localhost:8000/api/openapi.json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Best Practices
|
|
167
|
+
|
|
168
|
+
1. **Always regenerate after backend changes**
|
|
169
|
+
```bash
|
|
170
|
+
# After modifying schema.py files
|
|
171
|
+
npm run generate:types
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
2. **Commit generated files**
|
|
175
|
+
- Generated types are checked into git
|
|
176
|
+
- This ensures CI can detect drift
|
|
177
|
+
- Other developers don't need backend running
|
|
178
|
+
|
|
179
|
+
3. **Use Zod for user-facing data**
|
|
180
|
+
- Validate API responses before displaying to users
|
|
181
|
+
- Log validation errors for debugging
|
|
182
|
+
|
|
183
|
+
4. **Don't modify generated files**
|
|
184
|
+
- Changes will be overwritten
|
|
185
|
+
- Update backend schemas instead
|
|
186
|
+
|
|
187
|
+
## Troubleshooting
|
|
188
|
+
|
|
189
|
+
### "API contracts have drifted"
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Regenerate types
|
|
193
|
+
npm run generate:types
|
|
194
|
+
|
|
195
|
+
# Commit the changes
|
|
196
|
+
git add src/sdk/generated/
|
|
197
|
+
git commit -m "Regenerate API types from OpenAPI spec"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### "Failed to fetch OpenAPI spec"
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Check if backend is running
|
|
204
|
+
curl http://localhost:8000/api/openapi.json
|
|
205
|
+
|
|
206
|
+
# Use staging instead
|
|
207
|
+
npm run generate:types -- --url https://staging.ema.co/api/openapi.json
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Type mismatch in Zod schema
|
|
211
|
+
|
|
212
|
+
The Zod schemas in `contracts.ts` are manually maintained. If they're out of sync:
|
|
213
|
+
|
|
214
|
+
1. Check the generated types in `api-types.ts`
|
|
215
|
+
2. Update the Zod schema to match
|
|
216
|
+
3. Add `.passthrough()` for objects with unknown additional fields
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Auto-Builder Prompt Analysis & MCP Toolkit Improvements
|
|
2
|
+
|
|
3
|
+
> Analysis of the Ema Auto-Builder prompt architecture and recommended improvements for the MCP Toolkit.
|
|
4
|
+
|
|
5
|
+
## Executive Summary
|
|
6
|
+
|
|
7
|
+
The Ema Auto-Builder (DeltaGrapher agent) uses a **~70K token system prompt** that includes full documentation for every available agent. This is wasteful and could be optimized significantly. Our MCP Toolkit has the right abstractions but doesn't fully utilize them during workflow generation.
|
|
8
|
+
|
|
9
|
+
**Key Findings:**
|
|
10
|
+
1. Auto-Builder sends full agent documentation (~70K tokens) when only ~5K of constraints are needed
|
|
11
|
+
2. Our `AGENT_CATALOG` is well-structured but not used during generation
|
|
12
|
+
3. Our `workflow-intent.ts` uses primitive regex parsing that can't handle complex requests
|
|
13
|
+
4. Validation rules are applied **after** generation instead of **during** generation
|
|
14
|
+
5. No support for incremental DSL operations (add/remove nodes)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Auto-Builder Prompt Analysis
|
|
19
|
+
|
|
20
|
+
### What the Prompt Contains
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
System Prompt (~70K tokens)
|
|
24
|
+
├── Role Definition (~500 tokens)
|
|
25
|
+
├── Language Instructions (~200 tokens)
|
|
26
|
+
├── Security Instructions (~300 tokens)
|
|
27
|
+
├── available_nodes (~65K tokens) ← PROBLEM
|
|
28
|
+
│ └── For each of ~35 agents:
|
|
29
|
+
│ ├── name, displayName, description
|
|
30
|
+
│ ├── inputs (with wellKnownType, displayName, isOptional)
|
|
31
|
+
│ ├── outputs (with wellKnownType, displayName)
|
|
32
|
+
│ └── builderDocumentation (~2K tokens each!) ← WASTE
|
|
33
|
+
├── Workflow Construction Rules (~3K tokens)
|
|
34
|
+
├── Output Node Instructions (~500 tokens)
|
|
35
|
+
└── DSL Operations (~500 tokens)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### The Problem: Token Waste
|
|
39
|
+
|
|
40
|
+
Each agent includes full `builderDocumentation` which is detailed user guides:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"builderDocumentation": "# Conversation Summarizer Agent\\n\\n
|
|
45
|
+
This agent converts a chat conversation into a search query...
|
|
46
|
+
[2000+ chars of examples, FAQs, use cases, etc.]"
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**For graph generation, you only need:**
|
|
51
|
+
- Action name
|
|
52
|
+
- Input types (wellKnownType)
|
|
53
|
+
- Output types (wellKnownType)
|
|
54
|
+
- Critical constraints (3-5 rules)
|
|
55
|
+
|
|
56
|
+
### Token Comparison
|
|
57
|
+
|
|
58
|
+
| Content | Current | Optimized |
|
|
59
|
+
|---------|---------|-----------|
|
|
60
|
+
| Agent definitions | ~65,000 | ~3,000 |
|
|
61
|
+
| Rules & constraints | ~3,000 | ~2,000 |
|
|
62
|
+
| Instructions | ~2,000 | ~2,000 |
|
|
63
|
+
| **Total** | **~70,000** | **~7,000** |
|
|
64
|
+
|
|
65
|
+
**90% token reduction is achievable.**
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 2. Our MCP Toolkit: Current State
|
|
70
|
+
|
|
71
|
+
### What We Have (Good)
|
|
72
|
+
|
|
73
|
+
1. **`AGENT_CATALOG`** - Well-structured agent definitions with types, inputs, outputs, constraints
|
|
74
|
+
2. **`INPUT_SOURCE_RULES`** - Type compatibility rules (e.g., "chat_categorizer needs chat_conversation")
|
|
75
|
+
3. **`ANTI_PATTERNS`** - Common mistakes to avoid
|
|
76
|
+
4. **`WORKFLOW_PATTERNS`** - Template patterns (kb-search, intent-routing, tool-calling)
|
|
77
|
+
5. **`compileWorkflow()`** - Spec-to-workflow compiler
|
|
78
|
+
|
|
79
|
+
### What's Missing (Problems)
|
|
80
|
+
|
|
81
|
+
#### Problem 1: AGENT_CATALOG Not Used During Generation
|
|
82
|
+
|
|
83
|
+
Our catalog is exposed as a **resource** but not used in `intentToSpec()` or `compileWorkflow()`:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// In resources.ts - exposed for reference
|
|
87
|
+
DYNAMIC_RESOURCES.push({
|
|
88
|
+
uri: "ema://catalog/agents",
|
|
89
|
+
generate: () => JSON.stringify(AGENT_CATALOG, null, 2),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// In workflow-intent.ts - NOT USING AGENT_CATALOG
|
|
93
|
+
const INTENT_PATTERNS = [
|
|
94
|
+
{ pattern: /password\s*reset/i, name: "Password Reset", handler: "llm" },
|
|
95
|
+
// Hardcoded patterns instead of using catalog!
|
|
96
|
+
];
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Problem 2: No Type Validation During Generation
|
|
100
|
+
|
|
101
|
+
Our compiler builds workflows but doesn't validate type compatibility:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// In workflow-generator.ts
|
|
105
|
+
function buildInputBinding(binding: InputBinding): Record<string, unknown> {
|
|
106
|
+
// Builds binding but doesn't validate types match!
|
|
107
|
+
switch (binding.type) {
|
|
108
|
+
case "action_output":
|
|
109
|
+
return { actionOutput: { ... } };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Compare to Auto-Builder which has explicit type rules:
|
|
115
|
+
```
|
|
116
|
+
INPUT AND OUTPUT `wellKnownType` MUST MATCH when creating edges
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Problem 3: Primitive NLP Parsing
|
|
120
|
+
|
|
121
|
+
Our `parseNaturalLanguage()` uses simple regex:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const INTENT_PATTERNS = [
|
|
125
|
+
{ pattern: /password\s*reset/i, name: "Password Reset", handler: "llm" },
|
|
126
|
+
{ pattern: /billing|payment|invoice/i, name: "Billing", handler: "search" },
|
|
127
|
+
];
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This can't handle complex requests like:
|
|
131
|
+
> "Banking Customer Onboarding with KYC/AML screening, identity verification, risk scoring, and manual review routing"
|
|
132
|
+
|
|
133
|
+
#### Problem 4: No DSL Operations
|
|
134
|
+
|
|
135
|
+
Auto-Builder supports incremental edits:
|
|
136
|
+
- `add_node(id, action_name, display_name)`
|
|
137
|
+
- `remove_node(id)`
|
|
138
|
+
- `add_edge(from_id, to_id, source_output, target_input)`
|
|
139
|
+
- `remove_edge(...)`
|
|
140
|
+
- `modify_node(id, display_name)`
|
|
141
|
+
|
|
142
|
+
Our toolkit only supports **full workflow generation**.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 3. Improvements Made
|
|
147
|
+
|
|
148
|
+
### New: `generation-schema.ts`
|
|
149
|
+
|
|
150
|
+
Created a compact schema generator that transforms `AGENT_CATALOG` into a generation-focused format:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
export function generateSchemaMarkdown(): string {
|
|
154
|
+
// Returns ~5K tokens of actionable constraints
|
|
155
|
+
// vs ~70K tokens of full documentation
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function isTypeCompatible(sourceType, targetType): boolean {
|
|
159
|
+
// Validates type compatibility during generation
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function getRecommendedInput(actionName): string {
|
|
163
|
+
// Uses INPUT_SOURCE_RULES to recommend correct inputs
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Usage
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { generateSchemaMarkdown, isTypeCompatible } from "./sdk/generation-schema.js";
|
|
171
|
+
|
|
172
|
+
// Get compact schema for LLM prompt
|
|
173
|
+
const schema = generateSchemaMarkdown(); // ~5K tokens
|
|
174
|
+
|
|
175
|
+
// Validate during generation
|
|
176
|
+
if (!isTypeCompatible("WELL_KNOWN_TYPE_CHAT_CONVERSATION", "WELL_KNOWN_TYPE_TEXT_WITH_SOURCES")) {
|
|
177
|
+
throw new Error("Type mismatch: use conversation_to_search_query first");
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 4. Recommended Next Steps
|
|
184
|
+
|
|
185
|
+
### Phase 1: Enhance Workflow Intent (Priority: High)
|
|
186
|
+
|
|
187
|
+
1. **Replace regex with LLM-based parsing**
|
|
188
|
+
- Use the compact schema as context
|
|
189
|
+
- Let LLM extract intents, tools, data sources
|
|
190
|
+
|
|
191
|
+
2. **Add type validation to `intentToSpec()`**
|
|
192
|
+
- Use `isTypeCompatible()` to validate connections
|
|
193
|
+
- Suggest fixes when mismatches found
|
|
194
|
+
|
|
195
|
+
### Phase 2: Add DSL Operations (Priority: Medium)
|
|
196
|
+
|
|
197
|
+
Create incremental workflow editing:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
interface DSLOperation {
|
|
201
|
+
operation: "add_node" | "remove_node" | "add_edge" | "remove_edge" | "modify_node";
|
|
202
|
+
// ... params
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function applyDSLOperations(workflow: WorkflowDef, operations: DSLOperation[]): WorkflowDef {
|
|
206
|
+
// Apply incremental changes
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Phase 3: Optimize Auto-Builder Integration (Priority: Low)
|
|
211
|
+
|
|
212
|
+
If we integrate with Auto-Builder:
|
|
213
|
+
- Send compact schema instead of full docs
|
|
214
|
+
- Use our validation rules to pre-validate prompts
|
|
215
|
+
- Apply fixes locally before sending to Auto-Builder
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 5. Code Locations
|
|
220
|
+
|
|
221
|
+
| Component | File | Status |
|
|
222
|
+
|-----------|------|--------|
|
|
223
|
+
| Agent Catalog | `src/sdk/knowledge.ts` | ✅ Good |
|
|
224
|
+
| Validation Rules | `src/sdk/validation-rules.ts` | ✅ Good |
|
|
225
|
+
| Compact Schema | `src/sdk/generation-schema.ts` | ✅ New |
|
|
226
|
+
| Intent Parsing | `src/sdk/workflow-intent.ts` | ⚠️ Needs LLM |
|
|
227
|
+
| Workflow Compiler | `src/sdk/workflow-generator.ts` | ⚠️ Needs validation |
|
|
228
|
+
| DSL Operations | N/A | ❌ Not implemented |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 6. Example: Optimized Prompt Structure
|
|
233
|
+
|
|
234
|
+
Instead of the current 70K token prompt, use this structure:
|
|
235
|
+
|
|
236
|
+
```markdown
|
|
237
|
+
# Workflow Generation Schema
|
|
238
|
+
|
|
239
|
+
## Available Agents (35)
|
|
240
|
+
|
|
241
|
+
| Action | Category | Inputs | Outputs |
|
|
242
|
+
|--------|----------|--------|---------|
|
|
243
|
+
| `chat_trigger` | trigger | - | chat_conversation*, user_query* |
|
|
244
|
+
| `chat_categorizer` | routing | conversation* | category |
|
|
245
|
+
| `search` | search | query* | search_results |
|
|
246
|
+
| `respond_with_sources` | generation | query*, search_results* | response_with_sources |
|
|
247
|
+
...
|
|
248
|
+
|
|
249
|
+
## Type Compatibility
|
|
250
|
+
|
|
251
|
+
- `WELL_KNOWN_TYPE_CHAT_CONVERSATION` → `WELL_KNOWN_TYPE_CHAT_CONVERSATION`, `WELL_KNOWN_TYPE_ANY`
|
|
252
|
+
- `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES` → `WELL_KNOWN_TYPE_TEXT_WITH_SOURCES`, `WELL_KNOWN_TYPE_ANY`
|
|
253
|
+
...
|
|
254
|
+
|
|
255
|
+
## Input Source Rules
|
|
256
|
+
|
|
257
|
+
| Action | Recommended | Avoid | Severity |
|
|
258
|
+
|--------|-------------|-------|----------|
|
|
259
|
+
| `chat_categorizer` | `chat_conversation` | user_query | critical |
|
|
260
|
+
| `search` | `user_query` | chat_conversation | critical |
|
|
261
|
+
...
|
|
262
|
+
|
|
263
|
+
## Structural Constraints
|
|
264
|
+
|
|
265
|
+
### Categorizers
|
|
266
|
+
- MUST have at least one outgoing edge for each category
|
|
267
|
+
- MUST include a Fallback category
|
|
268
|
+
...
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
This gives the LLM everything it needs in ~5K tokens instead of ~70K.
|