@ema.co/mcp-toolkit 1.7.0 → 1.7.1
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/dist/mcp/handlers-consolidated.js +93 -11
- package/dist/sdk/client.js +73 -37
- package/docs/tool-consolidation-v2.md +215 -0
- package/package.json +1 -1
|
@@ -194,10 +194,18 @@ export async function handlePersona(args, client, getTemplateId, createClientFor
|
|
|
194
194
|
try {
|
|
195
195
|
sourcePersona = await resolvePersona(client, cloneFrom);
|
|
196
196
|
if (sourcePersona) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
197
|
+
// Use trigger_type (root level) for reliable persona type detection
|
|
198
|
+
// trigger_type: 0=chat, 1=voice, 2=dashboard
|
|
199
|
+
const triggerType = sourcePersona.trigger_type;
|
|
200
|
+
if (triggerType === 1) {
|
|
201
|
+
sourcePersonaType = "voice";
|
|
202
|
+
}
|
|
203
|
+
else if (triggerType === 2) {
|
|
204
|
+
sourcePersonaType = "dashboard";
|
|
205
|
+
}
|
|
206
|
+
else if (triggerType === 0) {
|
|
207
|
+
sourcePersonaType = "chat";
|
|
208
|
+
}
|
|
201
209
|
sourceDashboardId = sourcePersona.workflow_dashboard_id;
|
|
202
210
|
}
|
|
203
211
|
}
|
|
@@ -241,17 +249,35 @@ export async function handlePersona(args, client, getTemplateId, createClientFor
|
|
|
241
249
|
if (shouldSanitize) {
|
|
242
250
|
sanitizationSession = new SanitizationSession();
|
|
243
251
|
}
|
|
252
|
+
// Track document inputs that couldn't be cloned (require manual re-upload)
|
|
253
|
+
const allSkippedDocuments = [];
|
|
244
254
|
for (const row of sourceRows.rows) {
|
|
245
255
|
try {
|
|
246
256
|
// Build inputs from row's input column values
|
|
247
257
|
const inputs = [];
|
|
258
|
+
const rowSkippedDocs = [];
|
|
248
259
|
for (const inputCol of inputColumns) {
|
|
249
260
|
const colValue = row.columnValues.find(cv => cv.columnId === inputCol.columnId);
|
|
250
261
|
if (!colValue)
|
|
251
262
|
continue;
|
|
252
263
|
// Handle different column types
|
|
253
264
|
if (inputCol.columnType === "COLUMN_TYPE_DOCUMENT") {
|
|
254
|
-
//
|
|
265
|
+
// Document inputs can't be auto-cloned (no download API for original files)
|
|
266
|
+
// Track them for manual re-upload notification
|
|
267
|
+
const docValues = colValue.value.documentCellValue?.documentValues ?? [];
|
|
268
|
+
for (const doc of docValues) {
|
|
269
|
+
if (!doc.deleted) {
|
|
270
|
+
rowSkippedDocs.push({
|
|
271
|
+
name: inputCol.name,
|
|
272
|
+
original_filename: doc.name
|
|
273
|
+
});
|
|
274
|
+
allSkippedDocuments.push({
|
|
275
|
+
column: inputCol.name,
|
|
276
|
+
filename: doc.name,
|
|
277
|
+
contentNodeId: doc.contentNodeId,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
255
281
|
continue;
|
|
256
282
|
}
|
|
257
283
|
else if (inputCol.columnType === "COLUMN_TYPE_STRING") {
|
|
@@ -288,27 +314,74 @@ export async function handlePersona(args, client, getTemplateId, createClientFor
|
|
|
288
314
|
inputs.push({ name: inputCol.name, string_value: value });
|
|
289
315
|
}
|
|
290
316
|
}
|
|
317
|
+
// Note: COLUMN_TYPE_NUMBER and COLUMN_TYPE_BOOLEAN are not currently
|
|
318
|
+
// parsed from the dashboard rows protobuf response, so they're skipped
|
|
291
319
|
}
|
|
320
|
+
// If we have inputs (even if some docs were skipped), try to clone
|
|
292
321
|
if (inputs.length === 0) {
|
|
293
|
-
|
|
322
|
+
// Check if we had document-only inputs
|
|
323
|
+
if (rowSkippedDocs.length > 0) {
|
|
324
|
+
results.push({
|
|
325
|
+
source_row_id: row.id,
|
|
326
|
+
status: "skipped",
|
|
327
|
+
error: "Document-only inputs require manual re-upload",
|
|
328
|
+
skipped_documents: rowSkippedDocs,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
results.push({ source_row_id: row.id, status: "skipped", error: "No clonable input values" });
|
|
333
|
+
}
|
|
294
334
|
continue;
|
|
295
335
|
}
|
|
296
336
|
// Upload the row to target dashboard
|
|
297
337
|
const uploadResult = await client.uploadAndRunDashboardRow(newPersonaId, inputs);
|
|
298
|
-
|
|
338
|
+
const rowResult = {
|
|
339
|
+
source_row_id: row.id,
|
|
340
|
+
target_row_id: uploadResult.row_id,
|
|
341
|
+
status: rowSkippedDocs.length > 0 ? "partial" : "cloned",
|
|
342
|
+
};
|
|
343
|
+
if (rowSkippedDocs.length > 0) {
|
|
344
|
+
rowResult.skipped_documents = rowSkippedDocs;
|
|
345
|
+
}
|
|
346
|
+
results.push(rowResult);
|
|
299
347
|
}
|
|
300
348
|
catch (err) {
|
|
301
349
|
results.push({ source_row_id: row.id, status: "error", error: err instanceof Error ? err.message : String(err) });
|
|
302
350
|
}
|
|
303
351
|
}
|
|
304
|
-
const clonedCount = results.filter(r => r.status === "cloned").length;
|
|
352
|
+
const clonedCount = results.filter(r => r.status === "cloned" || r.status === "partial").length;
|
|
305
353
|
dashboardCloneResult = {
|
|
306
354
|
source_rows: sourceRows.rows.length,
|
|
307
355
|
cloned_rows: clonedCount,
|
|
356
|
+
partial_rows: results.filter(r => r.status === "partial").length,
|
|
308
357
|
skipped_rows: results.filter(r => r.status === "skipped").length,
|
|
309
358
|
error_rows: results.filter(r => r.status === "error").length,
|
|
310
359
|
sanitization_applied: !!shouldSanitize,
|
|
360
|
+
// Debug info for troubleshooting
|
|
361
|
+
_debug: {
|
|
362
|
+
total_count_from_api: sourceRows.totalCount,
|
|
363
|
+
schema_columns_count: sourceRows.schema.columns.length,
|
|
364
|
+
input_columns_count: inputColumns.length,
|
|
365
|
+
schema_columns: sourceRows.schema.columns.map(c => ({
|
|
366
|
+
id: c.columnId,
|
|
367
|
+
name: c.name,
|
|
368
|
+
type: c.columnType,
|
|
369
|
+
isInput: c.isInput,
|
|
370
|
+
})),
|
|
371
|
+
first_row_id: sourceRows.rows[0]?.id?.substring(0, 100),
|
|
372
|
+
first_row_state: sourceRows.rows[0]?.state,
|
|
373
|
+
first_row_column_values_count: sourceRows.rows[0]?.columnValues?.length,
|
|
374
|
+
results_detail: results,
|
|
375
|
+
},
|
|
311
376
|
};
|
|
377
|
+
// Include document upload notice if any documents were skipped
|
|
378
|
+
if (allSkippedDocuments.length > 0) {
|
|
379
|
+
dashboardCloneResult.documents_require_manual_upload = {
|
|
380
|
+
count: allSkippedDocuments.length,
|
|
381
|
+
files: allSkippedDocuments.slice(0, 10), // Limit to first 10 for readability
|
|
382
|
+
note: "Document inputs cannot be auto-cloned. Re-upload original files to the cloned dashboard.",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
312
385
|
}
|
|
313
386
|
else {
|
|
314
387
|
dashboardCloneResult = { source_rows: 0, cloned_rows: 0, message: "Source dashboard was empty" };
|
|
@@ -318,18 +391,27 @@ export async function handlePersona(args, client, getTemplateId, createClientFor
|
|
|
318
391
|
dashboardCloneResult = { error: `Dashboard clone failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
319
392
|
}
|
|
320
393
|
}
|
|
321
|
-
// Handle sanitization for
|
|
394
|
+
// Handle workflow sanitization for ALL persona types (including dashboard)
|
|
395
|
+
// Dashboard rows are sanitized during clone loop above, but workflow still needs sanitization
|
|
322
396
|
const shouldSanitize = args.sanitize;
|
|
323
|
-
if (shouldSanitize && newPersonaId
|
|
397
|
+
if (shouldSanitize && newPersonaId) {
|
|
324
398
|
const sanitizeResult = await sanitizePersonaById(client, newPersonaId, {
|
|
325
399
|
examples: args.sanitize_examples,
|
|
400
|
+
preview: args.preview ?? false, // Use preview arg, default to false (apply)
|
|
326
401
|
});
|
|
327
|
-
|
|
402
|
+
const createResult = {
|
|
328
403
|
success: true,
|
|
329
404
|
persona_id: newPersonaId,
|
|
330
405
|
name,
|
|
331
406
|
sanitization: sanitizeResult,
|
|
332
407
|
};
|
|
408
|
+
if (sourcePersonaType) {
|
|
409
|
+
createResult.source_persona_type = sourcePersonaType;
|
|
410
|
+
}
|
|
411
|
+
if (dashboardCloneResult) {
|
|
412
|
+
createResult.dashboard_data_clone = dashboardCloneResult;
|
|
413
|
+
}
|
|
414
|
+
return createResult;
|
|
333
415
|
}
|
|
334
416
|
const createResult = {
|
|
335
417
|
success: true,
|
package/dist/sdk/client.js
CHANGED
|
@@ -883,10 +883,6 @@ export class EmaClient {
|
|
|
883
883
|
*/
|
|
884
884
|
async getDashboardRows(dashboardId, personaId, opts) {
|
|
885
885
|
// Build protobuf request manually (GetDashboardRowsRequest)
|
|
886
|
-
// Field 1: dashboard_id (string)
|
|
887
|
-
// Field 2: limit (int32)
|
|
888
|
-
// Field 3: offset (int32)
|
|
889
|
-
// Field 9: get_minimal_row_values (bool)
|
|
890
886
|
const limit = opts?.limit ?? 100;
|
|
891
887
|
const offset = opts?.offset ?? 0;
|
|
892
888
|
const getMinimal = false;
|
|
@@ -1003,6 +999,9 @@ export class EmaClient {
|
|
|
1003
999
|
}
|
|
1004
1000
|
/**
|
|
1005
1001
|
* Parse the protobuf GetDashboardRowsResponse message.
|
|
1002
|
+
*
|
|
1003
|
+
* Note: The response format varies - sometimes columns are in field 1 (as repeated Column),
|
|
1004
|
+
* sometimes in field 2 as Schema { columns }. We detect and handle both cases.
|
|
1006
1005
|
*/
|
|
1007
1006
|
parseGetDashboardRowsResponse(data) {
|
|
1008
1007
|
const result = {
|
|
@@ -1011,6 +1010,11 @@ export class EmaClient {
|
|
|
1011
1010
|
schema: { columns: [] },
|
|
1012
1011
|
rows: [],
|
|
1013
1012
|
};
|
|
1013
|
+
// Field mapping (from protobuf analysis):
|
|
1014
|
+
// Field 1 = Schema message (contains nested Column messages at subfield 1)
|
|
1015
|
+
// Field 2 = Row messages (repeated)
|
|
1016
|
+
// Field 3 = totalCount (varint)
|
|
1017
|
+
// Field 4 = dashboardName (string)
|
|
1014
1018
|
let pos = 0;
|
|
1015
1019
|
const dec = new TextDecoder();
|
|
1016
1020
|
while (pos < data.length) {
|
|
@@ -1024,14 +1028,15 @@ export class EmaClient {
|
|
|
1024
1028
|
const fieldData = data.slice(pos, pos + length);
|
|
1025
1029
|
pos += length;
|
|
1026
1030
|
if (fieldNumber === 1) {
|
|
1027
|
-
//
|
|
1028
|
-
|
|
1029
|
-
if (row)
|
|
1030
|
-
result.rows.push(row);
|
|
1031
|
+
// Schema message - parse columns from it
|
|
1032
|
+
result.schema = this.parseProtoSchemaFromField1(fieldData, dec);
|
|
1031
1033
|
}
|
|
1032
1034
|
else if (fieldNumber === 2) {
|
|
1033
|
-
//
|
|
1034
|
-
|
|
1035
|
+
// Row message
|
|
1036
|
+
const row = this.parseProtoRow(fieldData, dec);
|
|
1037
|
+
if (row && row.id) {
|
|
1038
|
+
result.rows.push(row);
|
|
1039
|
+
}
|
|
1035
1040
|
}
|
|
1036
1041
|
else if (fieldNumber === 4) {
|
|
1037
1042
|
// dashboard_name (string)
|
|
@@ -1116,9 +1121,18 @@ export class EmaClient {
|
|
|
1116
1121
|
return row.id ? row : null;
|
|
1117
1122
|
}
|
|
1118
1123
|
/**
|
|
1119
|
-
* Parse Schema message from protobuf.
|
|
1124
|
+
* Parse Schema message from protobuf field 1.
|
|
1125
|
+
* Schema contains repeated Column messages at subfield 1.
|
|
1126
|
+
*
|
|
1127
|
+
* Column fields (from protobuf analysis):
|
|
1128
|
+
* - Field 1 (0x0a): name (string) e.g. "Document"
|
|
1129
|
+
* - Field 2 (0x10): columnType (varint) e.g. 6 = DOCUMENT
|
|
1130
|
+
* - Field 4 (0x20): isInput (bool)
|
|
1131
|
+
* - Field 5 (0x28): isRequired (bool)
|
|
1132
|
+
* - Field 11 (0x5a): actionId (string) e.g. "workflow_input"
|
|
1133
|
+
* - Field 13 (0x6a): columnId (string) e.g. "document-jghm"
|
|
1120
1134
|
*/
|
|
1121
|
-
|
|
1135
|
+
parseProtoSchemaFromField1(data, dec) {
|
|
1122
1136
|
const schema = { columns: [] };
|
|
1123
1137
|
let pos = 0;
|
|
1124
1138
|
while (pos < data.length) {
|
|
@@ -1131,10 +1145,11 @@ export class EmaClient {
|
|
|
1131
1145
|
const fieldData = data.slice(pos, pos + length);
|
|
1132
1146
|
pos += length;
|
|
1133
1147
|
if (fieldNumber === 1) {
|
|
1134
|
-
//
|
|
1135
|
-
const col = this.
|
|
1136
|
-
if (col)
|
|
1148
|
+
// Column message
|
|
1149
|
+
const col = this.parseProtoColumnV2(fieldData, dec);
|
|
1150
|
+
if (col) {
|
|
1137
1151
|
schema.columns.push(col);
|
|
1152
|
+
}
|
|
1138
1153
|
}
|
|
1139
1154
|
}
|
|
1140
1155
|
else if (wireType === 0) {
|
|
@@ -1148,24 +1163,35 @@ export class EmaClient {
|
|
|
1148
1163
|
return schema;
|
|
1149
1164
|
}
|
|
1150
1165
|
/**
|
|
1151
|
-
* Parse Column message from protobuf.
|
|
1166
|
+
* Parse Column message from protobuf (v2 - correct field mapping).
|
|
1167
|
+
* Based on actual protobuf analysis:
|
|
1168
|
+
* - Field 1: name (string)
|
|
1169
|
+
* - Field 2: columnType (varint)
|
|
1170
|
+
* - Field 4: isInput (bool)
|
|
1171
|
+
* - Field 5: isRequired (bool)
|
|
1172
|
+
* - Field 11: actionId (string)
|
|
1173
|
+
* - Field 12: actionName (string)
|
|
1174
|
+
* - Field 13: columnId (string)
|
|
1152
1175
|
*/
|
|
1153
|
-
|
|
1154
|
-
|
|
1176
|
+
parseProtoColumnV2(data, dec) {
|
|
1177
|
+
const col = {
|
|
1178
|
+
columnId: "",
|
|
1179
|
+
name: "",
|
|
1180
|
+
columnType: "COLUMN_TYPE_UNSPECIFIED",
|
|
1181
|
+
isInput: false,
|
|
1182
|
+
actionId: "",
|
|
1183
|
+
actionName: "",
|
|
1184
|
+
outputFieldName: "",
|
|
1185
|
+
};
|
|
1155
1186
|
const columnTypeMap = {
|
|
1156
1187
|
0: "COLUMN_TYPE_UNSPECIFIED",
|
|
1157
1188
|
1: "COLUMN_TYPE_STRING",
|
|
1158
1189
|
2: "COLUMN_TYPE_NUMBER",
|
|
1159
1190
|
3: "COLUMN_TYPE_BOOLEAN",
|
|
1160
1191
|
4: "COLUMN_TYPE_ARRAY",
|
|
1161
|
-
5: "
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
columnId: "",
|
|
1165
|
-
columnType: "COLUMN_TYPE_UNSPECIFIED",
|
|
1166
|
-
name: "",
|
|
1167
|
-
actionId: "",
|
|
1168
|
-
isInput: false,
|
|
1192
|
+
5: "COLUMN_TYPE_OBJECT",
|
|
1193
|
+
6: "COLUMN_TYPE_DOCUMENT",
|
|
1194
|
+
7: "COLUMN_TYPE_ENUM",
|
|
1169
1195
|
};
|
|
1170
1196
|
let pos = 0;
|
|
1171
1197
|
while (pos < data.length) {
|
|
@@ -1177,34 +1203,44 @@ export class EmaClient {
|
|
|
1177
1203
|
pos += bytesRead;
|
|
1178
1204
|
const fieldData = data.slice(pos, pos + length);
|
|
1179
1205
|
pos += length;
|
|
1206
|
+
const strValue = dec.decode(fieldData);
|
|
1180
1207
|
if (fieldNumber === 1) {
|
|
1181
|
-
col.
|
|
1208
|
+
col.name = strValue;
|
|
1182
1209
|
}
|
|
1183
|
-
else if (fieldNumber ===
|
|
1184
|
-
col.
|
|
1210
|
+
else if (fieldNumber === 11) {
|
|
1211
|
+
col.actionId = strValue;
|
|
1185
1212
|
}
|
|
1186
|
-
else if (fieldNumber ===
|
|
1187
|
-
col.
|
|
1213
|
+
else if (fieldNumber === 12) {
|
|
1214
|
+
col.actionName = strValue;
|
|
1188
1215
|
}
|
|
1189
|
-
else if (fieldNumber ===
|
|
1190
|
-
col.
|
|
1216
|
+
else if (fieldNumber === 13) {
|
|
1217
|
+
col.columnId = strValue;
|
|
1218
|
+
}
|
|
1219
|
+
else if (fieldNumber === 14) {
|
|
1220
|
+
col.outputFieldName = strValue;
|
|
1191
1221
|
}
|
|
1192
1222
|
}
|
|
1193
1223
|
else if (wireType === 0) {
|
|
1194
1224
|
const { value, bytesRead } = this.decodeVarintAt(data, pos);
|
|
1195
1225
|
pos += bytesRead;
|
|
1196
|
-
if (fieldNumber ===
|
|
1197
|
-
col.columnType = columnTypeMap[value] ??
|
|
1226
|
+
if (fieldNumber === 2) {
|
|
1227
|
+
col.columnType = columnTypeMap[value] ?? "COLUMN_TYPE_UNSPECIFIED";
|
|
1198
1228
|
}
|
|
1199
1229
|
else if (fieldNumber === 4) {
|
|
1200
1230
|
col.isInput = value === 1;
|
|
1201
1231
|
}
|
|
1202
1232
|
}
|
|
1203
1233
|
else {
|
|
1204
|
-
|
|
1234
|
+
// Skip unknown wire types (like fixed32/64)
|
|
1235
|
+
if (wireType === 5)
|
|
1236
|
+
pos += 4;
|
|
1237
|
+
else if (wireType === 1)
|
|
1238
|
+
pos += 8;
|
|
1239
|
+
else
|
|
1240
|
+
break;
|
|
1205
1241
|
}
|
|
1206
1242
|
}
|
|
1207
|
-
return col.columnId ? col : null;
|
|
1243
|
+
return (col.name || col.columnId) ? col : null;
|
|
1208
1244
|
}
|
|
1209
1245
|
/**
|
|
1210
1246
|
* Parse ColumnValue message from protobuf.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# MCP Tool Consolidation v2
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Consolidate from 9 tools to **5 core tools** with cleaner separation of concerns.
|
|
6
|
+
|
|
7
|
+
## Final Tool Design
|
|
8
|
+
|
|
9
|
+
### 1. `persona` - Manage AI Employees
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
persona(
|
|
13
|
+
id?: string, // get specific persona
|
|
14
|
+
query?: string, // search by name
|
|
15
|
+
all?: boolean, // list all
|
|
16
|
+
|
|
17
|
+
// Create/Clone
|
|
18
|
+
name?: string, // for create
|
|
19
|
+
type?: "voice" | "chat" | "dashboard",
|
|
20
|
+
input?: string, // natural language description
|
|
21
|
+
clone_from?: string, // clone source persona ID
|
|
22
|
+
clone_data?: boolean, // also clone files
|
|
23
|
+
sanitize?: boolean, // sanitize PII during clone
|
|
24
|
+
|
|
25
|
+
// Update
|
|
26
|
+
enabled?: boolean, // enable/disable
|
|
27
|
+
|
|
28
|
+
// Compare
|
|
29
|
+
compare_to?: string, // compare two personas
|
|
30
|
+
|
|
31
|
+
// Output control
|
|
32
|
+
include_workflow?: boolean, // include workflow_def in response
|
|
33
|
+
)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Examples:**
|
|
37
|
+
```
|
|
38
|
+
persona(all=true) # list all
|
|
39
|
+
persona(id="abc-123") # get specific
|
|
40
|
+
persona(query="support") # search
|
|
41
|
+
persona(name="My Bot", type="voice", input="...") # create
|
|
42
|
+
persona(clone_from="abc", name="Clone", clone_data=true, sanitize=true)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### 2. `data` - Manage Persona Data
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
data(
|
|
51
|
+
persona_id: string, // REQUIRED - data belongs to persona
|
|
52
|
+
mode?: "list" | "get" | "upload" | "delete" | "sanitize", // default: list
|
|
53
|
+
file_id?: string, // for get/delete specific
|
|
54
|
+
include_results?: boolean, // for dashboard: show extracted values
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Examples:**
|
|
59
|
+
```
|
|
60
|
+
data(persona_id="abc") # list files
|
|
61
|
+
data(persona_id="abc", file_id="x") # get file details
|
|
62
|
+
data(persona_id="abc", mode="upload") # upload (file from context)
|
|
63
|
+
data(persona_id="abc", mode="delete", file_id="x")
|
|
64
|
+
data(persona_id="abc", mode="sanitize") # sanitize all data
|
|
65
|
+
data(persona_id="abc", include_results=true) # list with extraction results
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**For dashboard personas, file listing includes:**
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"files": [{
|
|
72
|
+
"id": "file-123",
|
|
73
|
+
"name": "contract.pdf",
|
|
74
|
+
"processing": {
|
|
75
|
+
"status": "success",
|
|
76
|
+
"extracted": { "vendor": "Acme", "amount": "$50k" }
|
|
77
|
+
}
|
|
78
|
+
}]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 3. `workflow` - Workflow Operations
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
workflow(
|
|
88
|
+
persona_id?: string, // target persona
|
|
89
|
+
|
|
90
|
+
// Generate/Modify
|
|
91
|
+
input?: string, // natural language description
|
|
92
|
+
|
|
93
|
+
// Analyze
|
|
94
|
+
analyze?: boolean, // analyze current workflow
|
|
95
|
+
optimize?: boolean, // suggest optimizations
|
|
96
|
+
|
|
97
|
+
// Deploy
|
|
98
|
+
workflow_def?: object, // direct workflow deployment
|
|
99
|
+
preview?: boolean, // preview without deploying (default: true)
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Examples:**
|
|
104
|
+
```
|
|
105
|
+
workflow(persona_id="abc", input="Add email notification")
|
|
106
|
+
workflow(persona_id="abc", analyze=true)
|
|
107
|
+
workflow(persona_id="abc", optimize=true, preview=false)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 4. `reference` - All Reference Information
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
reference(
|
|
116
|
+
type?: "actions" | "templates" | "patterns" | "envs" | "concepts" | "guidance",
|
|
117
|
+
|
|
118
|
+
// For actions
|
|
119
|
+
action_id?: string, // get specific action
|
|
120
|
+
query?: string, // search
|
|
121
|
+
suggest?: string, // suggest actions for use case
|
|
122
|
+
|
|
123
|
+
// For guidance
|
|
124
|
+
topic?: string, // guidance topic
|
|
125
|
+
|
|
126
|
+
// For concepts
|
|
127
|
+
concept?: string, // specific concept
|
|
128
|
+
|
|
129
|
+
// Validation helpers
|
|
130
|
+
check_types?: { source: string, target: string },
|
|
131
|
+
validate_prompt?: string,
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Examples:**
|
|
136
|
+
```
|
|
137
|
+
reference(type="actions") # list all actions
|
|
138
|
+
reference(type="actions", query="email") # search actions
|
|
139
|
+
reference(type="actions", suggest="IT helpdesk")
|
|
140
|
+
reference(action_id="send_email") # get specific action
|
|
141
|
+
reference(type="templates") # list workflow templates
|
|
142
|
+
reference(type="patterns") # list patterns
|
|
143
|
+
reference(type="envs") # list environments
|
|
144
|
+
reference(type="concepts") # list concepts
|
|
145
|
+
reference(concept="HITL") # get specific concept
|
|
146
|
+
reference(type="guidance", topic="categorizer-routing")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 5. `sync` - Environment Sync
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
sync(
|
|
155
|
+
id?: string, // persona ID or name
|
|
156
|
+
target?: string, // target environment
|
|
157
|
+
dry_run?: boolean, // simulate without changes
|
|
158
|
+
|
|
159
|
+
// Status
|
|
160
|
+
mode?: "run" | "status" | "config",
|
|
161
|
+
list_synced?: boolean, // list all synced personas
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Examples:**
|
|
166
|
+
```
|
|
167
|
+
sync(id="IT Support", target="dev")
|
|
168
|
+
sync(id="abc-123", target="staging", dry_run=true)
|
|
169
|
+
sync(mode="status", id="abc-123")
|
|
170
|
+
sync(mode="config")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Migration Path
|
|
176
|
+
|
|
177
|
+
| Old Tool | New Location |
|
|
178
|
+
|----------|--------------|
|
|
179
|
+
| `env` | `reference(type="envs")` |
|
|
180
|
+
| `knowledge` | `data` |
|
|
181
|
+
| `demo` | Removed (generate separately or future addition) |
|
|
182
|
+
| `action` | `reference(type="actions")` |
|
|
183
|
+
| `template` | `reference(type="templates")` / `reference(type="patterns")` |
|
|
184
|
+
|
|
185
|
+
## Mental Model
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
┌─────────────────────────────────────────┐
|
|
189
|
+
│ PERSONA │
|
|
190
|
+
│ ┌─────────┐ ┌──────────┐ │
|
|
191
|
+
│ │ data │ │ workflow │ │
|
|
192
|
+
│ └─────────┘ └──────────┘ │
|
|
193
|
+
└─────────────────────────────────────────┘
|
|
194
|
+
│ │
|
|
195
|
+
└──────┬───────┘
|
|
196
|
+
│
|
|
197
|
+
┌───────────▼───────────┐
|
|
198
|
+
│ reference │ (actions, templates, guidance)
|
|
199
|
+
└───────────────────────┘
|
|
200
|
+
│
|
|
201
|
+
┌───────────▼───────────┐
|
|
202
|
+
│ sync │ (copy between envs)
|
|
203
|
+
└───────────────────────┘
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Implementation Checklist
|
|
207
|
+
|
|
208
|
+
- [ ] Update `tools-consolidated.ts` with new tool definitions
|
|
209
|
+
- [ ] Update `handlers-consolidated.ts` with routing logic
|
|
210
|
+
- [ ] Migrate `knowledge` handlers to `data`
|
|
211
|
+
- [ ] Migrate `action`, `template`, `env` to `reference`
|
|
212
|
+
- [ ] Remove deprecated tools
|
|
213
|
+
- [ ] Update tests
|
|
214
|
+
- [ ] Update documentation
|
|
215
|
+
- [ ] Add deprecation warnings for old tool names (backwards compat)
|
package/package.json
CHANGED