@ema.co/mcp-toolkit 2026.1.26 → 2026.1.27-2

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 (44) hide show
  1. package/dist/mcp/handlers/action/index.js +17 -20
  2. package/dist/mcp/handlers/data/index.js +75 -6
  3. package/dist/mcp/handlers/deprecation.js +50 -0
  4. package/dist/mcp/handlers/env/index.js +3 -3
  5. package/dist/mcp/handlers/knowledge/index.js +44 -237
  6. package/dist/mcp/handlers/persona/create.js +63 -18
  7. package/dist/mcp/handlers/persona/index.js +9 -10
  8. package/dist/mcp/handlers/persona/update.js +4 -2
  9. package/dist/mcp/handlers/reference/index.js +15 -2
  10. package/dist/mcp/handlers/sync/index.js +3 -18
  11. package/dist/mcp/handlers/workflow/analyze.js +53 -105
  12. package/dist/mcp/handlers/workflow/deploy.js +129 -0
  13. package/dist/mcp/handlers/workflow/generate.js +8 -28
  14. package/dist/mcp/handlers/workflow/index.js +258 -85
  15. package/dist/mcp/handlers/workflow/modify.js +9 -29
  16. package/dist/mcp/handlers/workflow/optimize.js +22 -108
  17. package/dist/mcp/handlers/workflow/utils.js +0 -102
  18. package/dist/mcp/handlers-consolidated.js +15 -38
  19. package/dist/mcp/prompts.js +82 -44
  20. package/dist/mcp/resources.js +335 -3
  21. package/dist/mcp/server.js +242 -457
  22. package/dist/mcp/tools.js +44 -61
  23. package/dist/sdk/action-schema-parser.js +11 -5
  24. package/dist/sdk/client.js +46 -17
  25. package/dist/sdk/ema-client.js +11 -0
  26. package/dist/sdk/generated/deprecated-actions.js +171 -0
  27. package/dist/sdk/guidance.js +58 -35
  28. package/dist/sdk/index.js +8 -7
  29. package/dist/sdk/knowledge.js +216 -1932
  30. package/dist/sdk/quality-gates.js +60 -336
  31. package/dist/sdk/validation-rules.js +33 -0
  32. package/dist/sdk/workflow-fixer.js +29 -360
  33. package/dist/sdk/workflow-intent.js +43 -3
  34. package/dist/sdk/workflow-transformer.js +0 -342
  35. package/docs/dashboard-operations.md +35 -0
  36. package/docs/ema-user-guide.md +66 -0
  37. package/docs/mcp-tools-guide.md +74 -45
  38. package/package.json +2 -2
  39. package/dist/mcp/handlers/persona/analyze.js +0 -275
  40. package/dist/mcp/handlers/persona/compare.js +0 -32
  41. package/dist/mcp/handlers/workflow/compile.js +0 -39
  42. package/docs/DEBUG-ANALYSIS-unused-category-type-mismatch.md +0 -481
  43. package/docs/TODO-fix-analyzer-and-modify.md +0 -182
  44. package/resources/action-schema.json +0 -5678
@@ -4,35 +4,30 @@
4
4
  * Provides action/agent lookup, filtering, and documentation.
5
5
  */
6
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
- }
7
+ import { handleDeprecatedParams } from "../deprecation.js";
20
8
  /**
21
9
  * Handle action tool requests - list, get, filter, and search actions
22
10
  */
23
11
  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
- }
12
+ // Check for deprecated params
13
+ handleDeprecatedParams(args, "action");
29
14
  const id = args.id;
30
15
  const identifier = args.identifier; // deprecated alias for 'id'
31
16
  const idOrName = id ?? identifier;
32
- // Categories list
17
+ // Categories list - API-first with catalog fallback
33
18
  if (args.categories) {
19
+ try {
20
+ const actions = await client.listActions();
21
+ const apiCategories = [...new Set(actions.map(a => a.category).filter(Boolean))];
22
+ if (apiCategories.length > 0) {
23
+ return { categories: apiCategories, count: apiCategories.length, source: "api" };
24
+ }
25
+ }
26
+ catch {
27
+ // Fallback to catalog
28
+ }
34
29
  const categories = [...new Set(Object.values(AGENT_CATALOG).map(a => a.category))];
35
- return { categories, count: categories.length };
30
+ return { categories, count: categories.length, source: "catalog" };
36
31
  }
37
32
  // Suggest for use case
38
33
  if (args.suggest) {
@@ -112,6 +107,7 @@ export async function handleAction(args, client) {
112
107
  ...a,
113
108
  documentation: a.name ? getAgentByName(a.name) : undefined,
114
109
  })),
110
+ source: "api",
115
111
  };
116
112
  }
117
113
  return {
@@ -122,6 +118,7 @@ export async function handleAction(args, client) {
122
118
  category: a.category,
123
119
  enabled: a.enabled,
124
120
  })),
121
+ source: "api",
125
122
  };
126
123
  }
127
124
  catch (e) {
@@ -138,6 +138,8 @@ export async function handleData(args, client, readFile) {
138
138
  // Upload file or LLM-generated content (dashboard rows)
139
139
  const filePath = (dataArgs?.path ?? dataArgs?.file ?? args.file);
140
140
  const items = dataArgs?.items;
141
+ // Widget name for targeting specific upload widgets (especially for Document Generation personas)
142
+ const widgetName = (dataArgs?.widget_name ?? args.widget_name);
141
143
  if (filePath) {
142
144
  // File upload - use provided readFile or fall back to fs
143
145
  try {
@@ -151,12 +153,18 @@ export async function handleData(args, client, readFile) {
151
153
  }
152
154
  const path = await import("path");
153
155
  const filename = path.basename(filePath);
154
- const result = await client.uploadDataSource(personaId, fileContent, filename);
156
+ const result = await client.uploadDataSource(personaId, fileContent, filename, {
157
+ widgetName: widgetName, // Pass through widget_name for doc gen personas
158
+ });
155
159
  return {
156
160
  method: "upload",
157
161
  persona_id: personaId,
158
162
  path: filePath,
163
+ widget_name: widgetName ?? "fileUpload",
159
164
  ...result,
165
+ _warning: "IMPORTANT: Uploaded documents will NOT be used unless your workflow has a search node (search/v2).",
166
+ _next_step: `Verify workflow has search: workflow(mode='get', persona_id='${personaId}') → check for search node. If missing, add one.`,
167
+ _validation: "Deploy will BLOCK if you have documents but no search node in your workflow.",
160
168
  };
161
169
  }
162
170
  catch (error) {
@@ -164,14 +172,74 @@ export async function handleData(args, client, readFile) {
164
172
  }
165
173
  }
166
174
  else if (items && items.length > 0) {
167
- // Dashboard row upload (LLM-generated content)
175
+ // Dashboard row upload (LLM-generated content or file attachments)
168
176
  try {
169
177
  const results = [];
178
+ const path = await import("path");
179
+ const fs = await import("fs/promises");
170
180
  for (const item of items) {
171
- // Convert item to DashboardInput format (name + string_value)
172
- const inputs = Object.entries(item).map(([key, value]) => ({
173
- name: key,
174
- string_value: typeof value === "string" ? value : JSON.stringify(value),
181
+ // Convert item to DashboardInput format
182
+ // Supports: string_value, number_value, boolean_value, document_value
183
+ const inputs = await Promise.all(Object.entries(item).map(async ([key, value]) => {
184
+ // File attachment: { file: "/path/to/file.pdf" } or { file_path: "..." }
185
+ if (typeof value === "object" && value !== null && ("file" in value || "file_path" in value)) {
186
+ const filePath = value.file ?? value.file_path;
187
+ if (typeof filePath === "string") {
188
+ let fileContent;
189
+ if (readFile) {
190
+ fileContent = await readFile(filePath);
191
+ }
192
+ else {
193
+ fileContent = await fs.readFile(filePath);
194
+ }
195
+ const filename = path.basename(filePath);
196
+ const ext = path.extname(filePath).toLowerCase();
197
+ const mimeTypes = {
198
+ ".pdf": "application/pdf",
199
+ ".json": "application/json",
200
+ ".txt": "text/plain",
201
+ ".csv": "text/csv",
202
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
203
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
204
+ };
205
+ return {
206
+ name: key,
207
+ document_value: [{
208
+ name: filename,
209
+ contents: fileContent.toString("base64"),
210
+ is_base64_encoded: true,
211
+ mime_type: mimeTypes[ext] ?? "application/octet-stream",
212
+ }],
213
+ };
214
+ }
215
+ }
216
+ // Inline document: { contents: "...", mime_type: "..." }
217
+ if (typeof value === "object" && value !== null && "contents" in value) {
218
+ const doc = value;
219
+ return {
220
+ name: key,
221
+ document_value: [{
222
+ name: doc.name ?? `${key}.txt`,
223
+ contents: typeof doc.contents === "string" && doc.is_base64_encoded
224
+ ? doc.contents
225
+ : Buffer.from(String(doc.contents)).toString("base64"),
226
+ is_base64_encoded: true,
227
+ mime_type: doc.mime_type ?? "text/plain",
228
+ }],
229
+ };
230
+ }
231
+ // Primitive values
232
+ if (typeof value === "number") {
233
+ return { name: key, number_value: value };
234
+ }
235
+ if (typeof value === "boolean") {
236
+ return { name: key, boolean_value: value };
237
+ }
238
+ // Default: string value
239
+ return {
240
+ name: key,
241
+ string_value: typeof value === "string" ? value : JSON.stringify(value),
242
+ };
175
243
  }));
176
244
  const result = await client.uploadAndRunDashboardRow(personaId, inputs);
177
245
  results.push(result);
@@ -181,6 +249,7 @@ export async function handleData(args, client, readFile) {
181
249
  persona_id: personaId,
182
250
  uploaded_rows: results.length,
183
251
  row_ids: results.map(r => r.row_id),
252
+ _tip: "Dashboard rows created with file attachments trigger workflow execution automatically",
184
253
  };
185
254
  }
186
255
  catch (error) {
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Deprecation Tracking - Single Source of Truth
3
+ *
4
+ * Centralized deprecation warnings for parameter names.
5
+ * Used by all handlers to ensure consistent messaging.
6
+ */
7
+ /**
8
+ * Deprecated parameter mappings
9
+ *
10
+ * Key: old parameter name
11
+ * Value: { newName, removeVersion }
12
+ */
13
+ export const DEPRECATED_PARAMS = {
14
+ identifier: { newName: "id", removeVersion: "2.0.0" },
15
+ clone_from: { newName: "from", removeVersion: "2.0.0" },
16
+ template_id: { newName: "from", removeVersion: "2.0.0" },
17
+ clone_data: { newName: "include_data", removeVersion: "2.0.0" },
18
+ };
19
+ /**
20
+ * Check args for deprecated params and return warnings.
21
+ */
22
+ export function checkDeprecatedParams(args) {
23
+ const warnings = [];
24
+ for (const [oldName, { newName, removeVersion }] of Object.entries(DEPRECATED_PARAMS)) {
25
+ if (args[oldName] !== undefined) {
26
+ warnings.push(`'${oldName}' is deprecated, use '${newName}' instead (will be removed in v${removeVersion})`);
27
+ }
28
+ }
29
+ return warnings;
30
+ }
31
+ /**
32
+ * Add deprecation warnings to a result object.
33
+ */
34
+ export function addDeprecationWarnings(result, warnings) {
35
+ if (warnings.length > 0) {
36
+ return { ...result, _deprecation_warnings: warnings };
37
+ }
38
+ return result;
39
+ }
40
+ /**
41
+ * Log and return deprecation warnings for an args object.
42
+ * Call this at the start of handlers that accept deprecated params.
43
+ */
44
+ export function handleDeprecatedParams(args, context) {
45
+ const warnings = checkDeprecatedParams(args);
46
+ for (const warning of warnings) {
47
+ console.warn(`[${context}] Deprecation: ${warning}`);
48
+ }
49
+ return warnings;
50
+ }
@@ -25,9 +25,9 @@ export async function handleEnv(_args, getEnvironments, toolkit) {
25
25
  getting_started: {
26
26
  workflow: [
27
27
  "1. List personas: persona(method=\"list\")",
28
- "2. Get details: persona(method=\"get\", id=\"...\")",
29
- "3. Analyze before modifying: persona(method=\"get\", id=\"...\", analyze=true)",
30
- "4. Preview before deploying: persona(method=\"update\", id=\"...\", preview=true, ...)",
28
+ "2. Get workflow data: workflow(mode=\"get\", persona_id=\"...\")",
29
+ "3. Analyze workflow: Fetch ema://rules/anti-patterns and check workflow_def against rules",
30
+ "4. Preview before deploying: workflow(mode=\"deploy\", persona_id=\"...\", workflow_def={...}, preview=true)",
31
31
  ],
32
32
  critical_rules: criticalRules,
33
33
  resources: [
@@ -1,247 +1,54 @@
1
1
  /**
2
- * Knowledge Handler
2
+ * Knowledge Handler - DEPRECATED
3
3
  *
4
- * Manages data sources (files, embeddings, dashboard rows) for personas.
5
- * Note: This is deprecated in favor of the 'data' tool.
4
+ * This handler is deprecated. Use the 'data' tool instead.
5
+ * All calls are routed to handleData with a deprecation warning.
6
6
  */
7
- import { hasExtractedDataHandler, getDataModeHandler, } from "../data/index.js";
7
+ import { handleData } from "../data/index.js";
8
8
  /**
9
- * Handle knowledge tool requests - manage data sources for personas
9
+ * Mode mapping from knowledge tool to data tool
10
+ */
11
+ const MODE_MAPPING = {
12
+ list: "list",
13
+ aggregates: "stats",
14
+ upload: "upload",
15
+ delete: "delete",
16
+ status: "embedding",
17
+ toggle: "embedding",
18
+ attach: "attach",
19
+ dashboard_rows: "dashboard_rows",
20
+ dashboard_clone: "copy",
21
+ dashboard_generate: "generate",
22
+ };
23
+ /**
24
+ * Handle knowledge tool requests
10
25
  *
11
- * @deprecated Use data() tool instead
26
+ * @deprecated Use data() tool instead. This handler routes to handleData.
12
27
  */
13
- export async function handleKnowledge(args, client, readFile, opts) {
14
- const personaId = args.persona_id;
28
+ export async function handleKnowledge(args, client, readFile) {
29
+ console.warn("[knowledge] DEPRECATED: Use data() tool instead");
15
30
  const mode = args.mode || "list";
16
- const includeWarning = opts?.includeDeprecationWarning ?? true;
17
- // Deprecation warning (added to response when called directly)
18
- const deprecationWarning = includeWarning ? {
19
- _deprecation: {
20
- message: "The 'knowledge' tool is deprecated. Please use 'data' tool instead.",
21
- migration: {
22
- "knowledge(mode='list')": "data(mode='list')",
23
- "knowledge(mode='upload')": "data(mode='upload')",
24
- "knowledge(mode='delete')": "data(mode='delete')",
25
- "knowledge(mode='status')": "data(mode='embedding')",
26
- "knowledge(mode='toggle')": "data(mode='embedding', enabled=...)",
27
- },
28
- },
29
- } : {};
30
- // Helper to wrap result with deprecation warning
31
- const withWarning = (result) => {
32
- if (typeof result === 'object' && result !== null) {
33
- return { ...deprecationWarning, ...result };
34
- }
35
- return result;
31
+ const mappedMode = MODE_MAPPING[mode] || mode;
32
+ // Route to data handler
33
+ const dataArgs = {
34
+ ...args,
35
+ mode: mappedMode,
36
36
  };
37
- switch (mode) {
38
- case "list": {
39
- const page = args.page;
40
- const limit = args.limit;
41
- const widgetName = args.widget_name;
42
- const result = await client.listDataSourceFiles(personaId, { page, limit, widgetName });
43
- return withWarning({
44
- persona_id: personaId,
45
- widget_name: result.widgetName,
46
- files: result.files,
47
- count: result.files.length,
48
- pagination: result.pagination,
49
- });
50
- }
51
- case "aggregates": {
52
- const widgetName = args.widget_name;
53
- const agg = await client.getDataSourceAggregates(personaId, widgetName);
54
- return withWarning({
55
- persona_id: personaId,
56
- widget_name: agg.widgetName,
57
- total_files: agg.total,
58
- by_status: {
59
- pending: agg.pending,
60
- success: agg.success,
61
- failed: agg.failed,
62
- },
63
- });
64
- }
65
- case "upload": {
66
- const filePath = args.file;
67
- if (!filePath) {
68
- return withWarning({ error: "file path required for upload" });
69
- }
70
- const content = await readFile(filePath);
71
- const filename = filePath.split("/").pop() || "file";
72
- const result = await client.uploadDataSource(personaId, content, filename, { tags: args.tags });
73
- return withWarning({ success: true, ...result });
74
- }
75
- case "delete": {
76
- const fileId = args.file_id;
77
- if (!fileId) {
78
- return withWarning({ error: "file_id required for delete" });
79
- }
80
- const result = await client.deleteDataSource(personaId, fileId);
81
- return withWarning(result);
82
- }
83
- case "status": {
84
- const persona = await client.getPersonaById(personaId);
85
- if (!persona) {
86
- return withWarning({ error: `Persona not found: ${personaId}` });
87
- }
88
- return withWarning({
89
- persona_id: personaId,
90
- embedding_enabled: persona.embedding_enabled,
91
- });
92
- }
93
- case "toggle": {
94
- if (args.enabled === undefined) {
95
- return withWarning({ error: "enabled flag required for toggle" });
96
- }
97
- const persona = await client.getPersonaById(personaId);
98
- if (!persona) {
99
- return withWarning({ error: `Persona not found: ${personaId}` });
100
- }
101
- // IMPORTANT: The Ema API requires workflow to be sent along with proto_config
102
- // for proto_config changes to persist. This matches what the UI does.
103
- await client.updateAiEmployee({
104
- persona_id: personaId,
105
- embedding_enabled: args.enabled,
106
- proto_config: persona.proto_config,
107
- workflow: persona.workflow_def,
108
- });
109
- return withWarning({
110
- success: true,
111
- persona_id: personaId,
112
- embedding_enabled: args.enabled,
113
- });
114
- }
115
- case "attach": {
116
- // Attach a data source widget to a workflow node's datastore_configs input
117
- const nodeName = args.node_name;
118
- const widgetName = args.widget_name || "fileUpload";
119
- if (!nodeName) {
120
- return withWarning({ error: "node_name required (e.g., 'knowledge_search_1')" });
121
- }
122
- const persona = await client.getPersonaById(personaId);
123
- if (!persona) {
124
- return withWarning({ error: `Persona not found: ${personaId}` });
125
- }
126
- const workflowDef = persona.workflow_def;
127
- if (!workflowDef) {
128
- return withWarning({ error: "Persona has no workflow_def" });
129
- }
130
- const actions = workflowDef.actions;
131
- if (!actions) {
132
- return withWarning({ error: "Workflow has no actions" });
133
- }
134
- // Find the target node
135
- const nodeIndex = actions.findIndex(a => a.name === nodeName);
136
- if (nodeIndex < 0) {
137
- const availableNodes = actions.map(a => a.name).filter(Boolean);
138
- return withWarning({
139
- error: `Node '${nodeName}' not found`,
140
- available_nodes: availableNodes,
141
- });
142
- }
143
- const node = actions[nodeIndex];
144
- const inputs = (node.inputs || {});
145
- // Build the datastore_configs binding with multiBinding
146
- const datastoreBinding = {
147
- multiBinding: {
148
- elements: [
149
- {
150
- widgetConfig: { widgetName },
151
- autoDetectedBinding: false,
152
- },
153
- ],
154
- },
155
- autoDetectedBinding: false,
156
- };
157
- // Update the node's inputs
158
- inputs.datastore_configs = datastoreBinding;
159
- node.inputs = inputs;
160
- actions[nodeIndex] = node;
161
- workflowDef.actions = actions;
162
- // Update the persona with the modified workflow
163
- await client.updateAiEmployee({
164
- persona_id: personaId,
165
- proto_config: persona.proto_config,
166
- workflow: workflowDef,
167
- });
168
- return withWarning({
169
- success: true,
170
- persona_id: personaId,
171
- node_name: nodeName,
172
- widget_name: widgetName,
173
- message: `Data source '${widgetName}' attached to node '${nodeName}'`,
174
- });
175
- }
176
- case "dashboard_rows": {
177
- // Get rows from a dashboard persona
178
- const persona = await client.getPersonaById(personaId);
179
- if (!persona) {
180
- return withWarning({ error: `Persona not found: ${personaId}` });
181
- }
182
- const dashboardId = persona.workflow_dashboard_id;
183
- if (!dashboardId) {
184
- return withWarning({
185
- error: "This persona has no dashboard. Use dashboard_rows only for Dashboard-type AI Employees.",
186
- hint: "Check that the persona has trigger_type=DASHBOARD",
187
- });
188
- }
189
- const limit = args.limit ?? 100;
190
- const result = await client.getDashboardRows(dashboardId, personaId, { limit });
191
- // Return schema and rows in a structured format
192
- return withWarning({
193
- persona_id: personaId,
194
- dashboard_id: dashboardId,
195
- dashboard_name: result.dashboardName,
196
- total_rows: result.totalCount,
197
- schema: {
198
- input_columns: result.schema.columns.filter(c => c.isInput),
199
- output_columns: result.schema.columns.filter(c => !c.isInput),
200
- },
201
- rows: result.rows.map(row => ({
202
- id: row.id,
203
- state: row.state,
204
- created_at: row.dashboardRowMetadata.createdAt,
205
- input_values: row.columnValues
206
- .filter(cv => result.schema.columns.find(c => c.columnId === cv.columnId)?.isInput)
207
- .map(cv => ({
208
- column: result.schema.columns.find(c => c.columnId === cv.columnId)?.name ?? cv.columnId,
209
- value: cv.value.stringValue ?? cv.value.documentCellValue?.documentValues?.[0]?.name ?? cv.value.arrayValue?.arrayValues?.[0]?.stringValue ?? "(complex)",
210
- })),
211
- })),
212
- });
213
- }
214
- case "dashboard_clone": {
215
- // Delegated to extracted handler
216
- if (hasExtractedDataHandler("dashboard_clone")) {
217
- const handler = getDataModeHandler("dashboard_clone");
218
- // Map args to extracted handler format
219
- const cloneArgs = {
220
- id: personaId,
221
- clone_dashboard_from: args.source_persona_id,
222
- clone_limit: args.limit ?? 100,
223
- sanitize: args.sanitize,
224
- sanitize_examples: args.sanitize_examples,
225
- };
226
- return withWarning(await handler(cloneArgs, client));
227
- }
228
- return withWarning({ error: "dashboard_clone handler not found" });
229
- }
230
- case "dashboard_generate": {
231
- // Delegated to extracted handler
232
- if (hasExtractedDataHandler("dashboard_generate")) {
233
- const handler = getDataModeHandler("dashboard_generate");
234
- // Map args to extracted handler format
235
- const generateArgs = {
236
- id: personaId,
237
- dashboard_generate: args.count ?? args.dashboard_generate ?? 5,
238
- dashboard_template: args.template ?? args.dashboard_template,
239
- };
240
- return withWarning(await handler(generateArgs, client));
241
- }
242
- return withWarning({ error: "dashboard_generate handler not found" });
243
- }
244
- default:
245
- return withWarning({ error: `Unknown mode: ${mode}` });
37
+ // Map old param names to new
38
+ if (args.file)
39
+ dataArgs.file_path = args.file;
40
+ if (args.source_persona_id)
41
+ dataArgs.from = args.source_persona_id;
42
+ const result = await handleData(dataArgs, client, readFile);
43
+ // Add deprecation warning to result
44
+ if (typeof result === "object" && result !== null) {
45
+ return {
46
+ _deprecation: {
47
+ message: "The 'knowledge' tool is deprecated. Use 'data' tool instead.",
48
+ migration: `data(method="${mappedMode}", ...)`,
49
+ },
50
+ ...result,
51
+ };
246
52
  }
53
+ return result;
247
54
  }