@ema.co/mcp-toolkit 2026.3.24 → 2026.3.25-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.
- package/dist/knowledge/guidance-cache.js +60 -3
- package/dist/knowledge/intelligence/staleness.js +4 -0
- package/dist/knowledge/search-client.js +89 -1
- package/dist/mcp/domain/generation-schema.js +244 -31
- package/dist/mcp/domain/workflow-def-validator.js +321 -1
- package/dist/mcp/domain/workflow-static-validator.js +1 -1
- package/dist/mcp/guidance/classify.js +74 -0
- package/dist/mcp/guidance/defaults.js +114 -0
- package/dist/mcp/guidance/middleware.js +193 -0
- package/dist/mcp/guidance/types.js +7 -0
- package/dist/mcp/guidance.js +12 -8
- package/dist/mcp/handlers/data/index.js +1 -1
- package/dist/mcp/handlers/debug/index.js +80 -7
- package/dist/mcp/handlers/env/index.js +4 -4
- package/dist/mcp/handlers/feedback/coalesce.js +4 -1
- package/dist/mcp/handlers/feedback/index.js +15 -3
- package/dist/mcp/handlers/feedback/store.js +32 -12
- package/dist/mcp/handlers/template/crud.js +26 -9
- package/dist/mcp/handlers/workflow/adapter.js +2 -2
- package/dist/mcp/handlers/workflow/deploy.js +15 -15
- package/dist/mcp/handlers/workflow/index.js +23 -11
- package/dist/mcp/handlers/workflow/validate.js +30 -1
- package/dist/mcp/handlers/workflow/validation.js +4 -4
- package/dist/mcp/server.js +57 -5
- package/dist/mcp/tools.js +18 -11
- package/dist/sdk/client.js +7 -7
- package/dist/sdk/ema-client.js +16 -1
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { generateSchema } from "../../domain/generation-schema.js";
|
|
20
20
|
import { fingerprintPersona } from "../../../sync.js";
|
|
21
|
+
import { LLM_ACTIONS, LLM_WIDGET_INPUTS, widgetBinding } from "../../../config/widget-bindings.js";
|
|
21
22
|
// Re-export types
|
|
22
23
|
export * from "./types.js";
|
|
23
24
|
// Re-export utilities
|
|
@@ -172,7 +173,7 @@ function slimWorkflowDef(wf) {
|
|
|
172
173
|
*
|
|
173
174
|
* LLM uses this to generate or modify workflow_def
|
|
174
175
|
*/
|
|
175
|
-
async function handleWorkflowGet(args, client) {
|
|
176
|
+
async function handleWorkflowGet(args, client, cache) {
|
|
176
177
|
const personaId = args.persona_id;
|
|
177
178
|
if (!personaId) {
|
|
178
179
|
return { error: "persona_id required" };
|
|
@@ -191,8 +192,8 @@ async function handleWorkflowGet(args, client) {
|
|
|
191
192
|
name: w.name,
|
|
192
193
|
type: w.type,
|
|
193
194
|
}));
|
|
194
|
-
// Get generation schema for LLM
|
|
195
|
-
const schema = generateSchema();
|
|
195
|
+
// Get generation schema for LLM — API-first + DE-first for structural invariants
|
|
196
|
+
const schema = await generateSchema(client, cache);
|
|
196
197
|
// Get deprecated actions (API-first, with fallback)
|
|
197
198
|
const { deprecated: deprecatedActions, source: deprecationSource } = await getDeprecatedActions(client);
|
|
198
199
|
// Check if current workflow uses deprecated actions
|
|
@@ -217,6 +218,17 @@ async function handleWorkflowGet(args, client) {
|
|
|
217
218
|
agents: schema.agents,
|
|
218
219
|
constraints: schema.constraints,
|
|
219
220
|
input_rules: schema.inputRules,
|
|
221
|
+
widget_bindings: LLM_WIDGET_INPUTS.map(b => ({
|
|
222
|
+
input: b.inputName,
|
|
223
|
+
widget: b.widgetName,
|
|
224
|
+
required: b.required,
|
|
225
|
+
binding: widgetBinding(b),
|
|
226
|
+
})),
|
|
227
|
+
llm_actions: [...LLM_ACTIONS],
|
|
228
|
+
_source: schema.schema_source,
|
|
229
|
+
...(schema.schema_source === "catalog" ? {
|
|
230
|
+
_warning: "Using static catalog (API unavailable) — input lists may be incomplete. Search knowledge('<action_name> inputs') for full definitions.",
|
|
231
|
+
} : {}),
|
|
220
232
|
},
|
|
221
233
|
// HARD REQUIREMENTS (must be satisfied)
|
|
222
234
|
hard_requirements: {
|
|
@@ -255,8 +267,8 @@ async function handleWorkflowGet(args, client) {
|
|
|
255
267
|
"",
|
|
256
268
|
"IMPORTANT: Before deploying changes, re-run workflow(mode='get') and pass fingerprint as base_fingerprint to workflow(mode='deploy').",
|
|
257
269
|
"To analyze workflow health:",
|
|
258
|
-
"1.
|
|
259
|
-
"2.
|
|
270
|
+
"1. Search knowledge('workflow anti-patterns')",
|
|
271
|
+
"2. Search knowledge('structural invariants')",
|
|
260
272
|
"3. Check workflow_def nodes against the rules",
|
|
261
273
|
"4. Report issues YOU find (MCP does not pre-compute)",
|
|
262
274
|
"",
|
|
@@ -264,8 +276,8 @@ async function handleWorkflowGet(args, client) {
|
|
|
264
276
|
]
|
|
265
277
|
: [
|
|
266
278
|
"To analyze workflow health:",
|
|
267
|
-
"1.
|
|
268
|
-
"2.
|
|
279
|
+
"1. Search knowledge('workflow anti-patterns')",
|
|
280
|
+
"2. Search knowledge('structural invariants')",
|
|
269
281
|
"3. Check workflow_def nodes against the rules",
|
|
270
282
|
"4. Report issues YOU find (MCP does not pre-compute)",
|
|
271
283
|
"",
|
|
@@ -310,14 +322,14 @@ async function handleWorkflowGet(args, client) {
|
|
|
310
322
|
* PUBLIC modes: get, deploy, validate, optimize
|
|
311
323
|
* INTERNAL modes: modify, generate, analyze, compare (called from persona tool)
|
|
312
324
|
*/
|
|
313
|
-
export async function handleWorkflow(args, client, _getTemplateId) {
|
|
325
|
+
export async function handleWorkflow(args, client, _getTemplateId, cache) {
|
|
314
326
|
const personaId = args.persona_id;
|
|
315
327
|
const workflowDef = args.workflow_def;
|
|
316
328
|
// Explicit mode takes priority
|
|
317
329
|
const mode = args.mode;
|
|
318
330
|
// PUBLIC MODES (from workflow tool)
|
|
319
331
|
if (mode === "get") {
|
|
320
|
-
return handleWorkflowGet(args, client);
|
|
332
|
+
return handleWorkflowGet(args, client, cache);
|
|
321
333
|
}
|
|
322
334
|
if (mode === "deploy") {
|
|
323
335
|
return handleWorkflowDeploy(args, client);
|
|
@@ -347,10 +359,10 @@ export async function handleWorkflow(args, client, _getTemplateId) {
|
|
|
347
359
|
if (mode === "analyze" || mode === "compare") {
|
|
348
360
|
return {
|
|
349
361
|
error: `Mode "${mode}" has been removed.`,
|
|
350
|
-
reason: "LLM can do analysis/comparison by fetching
|
|
362
|
+
reason: "LLM can do analysis/comparison by fetching knowledge('anti-patterns') and reasoning about workflow_def.",
|
|
351
363
|
correct_flow: [
|
|
352
364
|
"1. workflow(mode='get', persona_id='...') - get current workflow_def",
|
|
353
|
-
"2. Fetch
|
|
365
|
+
"2. Fetch knowledge('anti-patterns') and knowledge('structural invariants')",
|
|
354
366
|
"3. LLM analyzes/compares the data",
|
|
355
367
|
],
|
|
356
368
|
};
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Validates: wiring, deprecated actions, circular refs, categorizer fallbacks, etc.
|
|
6
6
|
*/
|
|
7
7
|
import { validateWorkflowStatic } from "../../domain/workflow-static-validator.js";
|
|
8
|
-
import {
|
|
8
|
+
import { validateWorkflowDefStructure } from "../../domain/workflow-def-validator.js";
|
|
9
|
+
import { validateWorkflowSchema, validateNodeInputsWired, validateNoDeprecatedActions, validateExternalActionCallerTools, validateNoCircularReferences, validateCategorizersFallback, checkBestPractices, checkRunIfGatedDependencies, detectTypeMismatches, } from "./validation.js";
|
|
9
10
|
import { DEPRECATED_ACTIONS_MAP } from "../../../sdk/generated/deprecated-actions.js";
|
|
10
11
|
/**
|
|
11
12
|
* Handle workflow(mode="validate") - pre-deployment validation
|
|
@@ -85,6 +86,26 @@ export async function handleWorkflowValidate(args, client) {
|
|
|
85
86
|
_tip: "Fix structural errors first. Use workflow(mode='get') to see valid structure.",
|
|
86
87
|
};
|
|
87
88
|
}
|
|
89
|
+
// 0b. Proto structural validation — catches empty namespaces, wrong named_inputs
|
|
90
|
+
// format, invalid extraction_columns, missing typeArguments, etc. that cause
|
|
91
|
+
// opaque API 500s. MUST match the deploy handler's validation (deploy.ts:106).
|
|
92
|
+
const protoValidation = validateWorkflowDefStructure(workflowToValidate);
|
|
93
|
+
const protoErrors = protoValidation.issues.filter(i => i.severity === "error");
|
|
94
|
+
if (protoErrors.length > 0) {
|
|
95
|
+
for (const issue of protoErrors) {
|
|
96
|
+
errors.push({
|
|
97
|
+
check: "proto_structural",
|
|
98
|
+
message: `${issue.path}: ${issue.message}`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const protoWarnings = protoValidation.issues.filter(i => i.severity === "warning");
|
|
103
|
+
for (const issue of protoWarnings) {
|
|
104
|
+
warnings.push({
|
|
105
|
+
check: "proto_structural",
|
|
106
|
+
message: `${issue.path}: ${issue.message}`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
88
109
|
// 1. Node inputs must be wired
|
|
89
110
|
const inputsValidation = validateNodeInputsWired(workflowToValidate);
|
|
90
111
|
if (!inputsValidation.valid) {
|
|
@@ -155,6 +176,14 @@ export async function handleWorkflowValidate(args, client) {
|
|
|
155
176
|
message: gd.issue,
|
|
156
177
|
});
|
|
157
178
|
}
|
|
179
|
+
// 8. Type mismatch detection (warnings — uses generation schema type info)
|
|
180
|
+
const typeMismatches = detectTypeMismatches(workflowToValidate);
|
|
181
|
+
for (const tm of typeMismatches) {
|
|
182
|
+
warnings.push({
|
|
183
|
+
check: "type_mismatch",
|
|
184
|
+
message: `Type mismatch: "${tm.action}.${tm.input}" expects ${tm.expectedType} but receives ${tm.sourceType} from "${tm.sourceAction}.${tm.sourceOutput}"`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
158
187
|
const valid = errors.length === 0;
|
|
159
188
|
return {
|
|
160
189
|
valid,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { ConnectError, Code } from "@connectrpc/connect";
|
|
18
18
|
import { validateWorkflowDefSchema } from "../../domain/workflow-def-schema.js";
|
|
19
19
|
import { LLM_ACTIONS, MODEL_CONFIG, widgetBinding } from "../../../config/widget-bindings.js";
|
|
20
|
-
import {
|
|
20
|
+
import { generateSchemaSync, isTypeCompatible } from "../../domain/generation-schema.js";
|
|
21
21
|
// Re-export schema validation for use by other handlers
|
|
22
22
|
export { validateWorkflowDefSchema };
|
|
23
23
|
/**
|
|
@@ -585,7 +585,7 @@ export function validateNodeInputsWired(workflowDef) {
|
|
|
585
585
|
fixSteps.push("To find required inputs for an action:");
|
|
586
586
|
fixSteps.push(" knowledge(\"id=<action_type>\")");
|
|
587
587
|
fixSteps.push("For full input format reference:");
|
|
588
|
-
fixSteps.push("
|
|
588
|
+
fixSteps.push(" Search knowledge(\"input binding formats\") for correct wiring structure");
|
|
589
589
|
return {
|
|
590
590
|
valid: false,
|
|
591
591
|
error: `DEPLOYMENT BLOCKED: ${unwiredNodes.length} node(s) have empty inputs and are not wired to any data source.`,
|
|
@@ -1017,7 +1017,7 @@ export function checkBestPractices(workflowDef) {
|
|
|
1017
1017
|
issue: "custom_agent output consumed by json_mapper but no output_fields defined",
|
|
1018
1018
|
recommendation: "Add output_fields with extraction columns matching your JSON keys, OR " +
|
|
1019
1019
|
"ensure task_instructions prompt says 'output ONLY JSON, no markdown'. " +
|
|
1020
|
-
"
|
|
1020
|
+
"Search knowledge(\"json output patterns\") for the full pattern.",
|
|
1021
1021
|
severity: "warning",
|
|
1022
1022
|
});
|
|
1023
1023
|
}
|
|
@@ -1163,7 +1163,7 @@ export function checkRunIfGatedDependencies(workflowDef) {
|
|
|
1163
1163
|
* the schema may not cover all actions (custom actions, unknown versions).
|
|
1164
1164
|
*/
|
|
1165
1165
|
export function detectTypeMismatches(workflowDef) {
|
|
1166
|
-
const schema =
|
|
1166
|
+
const schema = generateSchemaSync();
|
|
1167
1167
|
const actions = (workflowDef.actions ?? []);
|
|
1168
1168
|
const mismatches = [];
|
|
1169
1169
|
// Build action name → schema agent lookup
|
package/dist/mcp/server.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
18
18
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
19
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, SubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
20
20
|
// Environment configuration, client factories, and toolkit metadata
|
|
21
21
|
import { TOOLKIT_NAME, TOOLKIT_VERSION, TOOLKIT_COMMIT, createClient, getSyncSDK, getAvailableEnvironments, getDefaultEnvName, initializeApiKeyTokens, } from "./handlers/env/config.js";
|
|
22
22
|
export { TOOLKIT_NAME, TOOLKIT_VERSION, TOOLKIT_COMMIT };
|
|
@@ -28,6 +28,27 @@ import { generateServerInstructions, getContextualTip, TOOL_GUIDANCE } from "./g
|
|
|
28
28
|
// Set EMA_GUIDANCE_CACHE=false to disable and use local constants only.
|
|
29
29
|
import { GuidanceCache } from "../knowledge/guidance-cache.js";
|
|
30
30
|
import { createDeSearchAdapter } from "../knowledge/search-adapter.js";
|
|
31
|
+
// Dynamic contextual guidance middleware — DE-first, defaults fallback
|
|
32
|
+
import { enrichWithGuidance } from "./guidance/middleware.js";
|
|
33
|
+
import { searchDocuments } from "../knowledge/search-client.js";
|
|
34
|
+
// Live DE search for contextual error guidance.
|
|
35
|
+
// On errors, the middleware queries DE with the error context to find
|
|
36
|
+
// relevant solutions — including agent-published fixes for similar errors.
|
|
37
|
+
const guidanceSearchFn = async (query, options) => {
|
|
38
|
+
const response = await searchDocuments(query, {
|
|
39
|
+
topK: options?.limit ?? 3,
|
|
40
|
+
filters: { type: ["contextual-guidance", "guidance", "entity", "pattern"] },
|
|
41
|
+
});
|
|
42
|
+
return response.results.map((r) => {
|
|
43
|
+
const doc = r.document;
|
|
44
|
+
return {
|
|
45
|
+
id: r.id,
|
|
46
|
+
score: r.score,
|
|
47
|
+
content: doc.description,
|
|
48
|
+
structData: doc.structData,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
};
|
|
31
52
|
const cacheEnabled = process.env.EMA_GUIDANCE_CACHE?.trim().toLowerCase() !== "false";
|
|
32
53
|
const guidanceCache = cacheEnabled ? new GuidanceCache(createDeSearchAdapter()) : undefined;
|
|
33
54
|
// Cache is warmed in startMcpServer() before generating server instructions.
|
|
@@ -162,7 +183,7 @@ const toolHandlers = {
|
|
|
162
183
|
},
|
|
163
184
|
// V2 adapters — routing + transformation extracted to handler files
|
|
164
185
|
workflow: async (args) => {
|
|
165
|
-
return handleWorkflowAdapter(args, createClient, getDefaultEnvName);
|
|
186
|
+
return handleWorkflowAdapter(args, createClient, getDefaultEnvName, guidanceCache);
|
|
166
187
|
},
|
|
167
188
|
sync: async (args) => {
|
|
168
189
|
return handleSyncAdapter(args, createClient, getDefaultEnvName, getSyncSDK);
|
|
@@ -355,15 +376,44 @@ export async function startMcpServer() {
|
|
|
355
376
|
if (name !== "feedback" && name !== "toolkit_feedback") {
|
|
356
377
|
recordTelemetry({ type: "tool_call", tool: name, op: operation, ok: true, ms: elapsedMs }).catch(() => { });
|
|
357
378
|
}
|
|
379
|
+
// ── Dynamic Contextual Guidance (DE-first, defaults fallback) ──────
|
|
380
|
+
// Classifies result shape and injects error-aware hints BEFORE
|
|
381
|
+
// the legacy hint injection layers below. Only sets fields the
|
|
382
|
+
// handler didn't already set.
|
|
383
|
+
const response = result;
|
|
384
|
+
try {
|
|
385
|
+
const method = (argsObj.method ?? argsObj.mode ?? operation);
|
|
386
|
+
let profileName;
|
|
387
|
+
let envName;
|
|
388
|
+
try {
|
|
389
|
+
const p = getActiveProfile();
|
|
390
|
+
profileName = p?.name;
|
|
391
|
+
envName = p?.env;
|
|
392
|
+
}
|
|
393
|
+
catch { /* config not available */ }
|
|
394
|
+
await enrichWithGuidance(response, {
|
|
395
|
+
tool: name,
|
|
396
|
+
method,
|
|
397
|
+
args: argsObj,
|
|
398
|
+
result: response,
|
|
399
|
+
env: envName,
|
|
400
|
+
profile: profileName,
|
|
401
|
+
}, guidanceCache, guidanceSearchFn);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Guidance middleware must never break tool dispatch
|
|
405
|
+
}
|
|
406
|
+
// ── Legacy hint injection (kept for backwards compatibility) ────────
|
|
407
|
+
// These layers run AFTER the middleware. They use ??= so they won't
|
|
408
|
+
// overwrite hints the middleware already set.
|
|
358
409
|
// Get contextual tip based on operation and result
|
|
359
410
|
const tip = getContextualTip({
|
|
360
411
|
operation,
|
|
361
412
|
args: argsObj,
|
|
362
|
-
result:
|
|
413
|
+
result: response,
|
|
363
414
|
}, guidanceCache);
|
|
364
415
|
// Add tip and next_step to response if available
|
|
365
|
-
|
|
366
|
-
if (tip) {
|
|
416
|
+
if (tip && !response._tip) {
|
|
367
417
|
response._tip = {
|
|
368
418
|
message: tip.message,
|
|
369
419
|
level: tip.level,
|
|
@@ -521,6 +571,8 @@ export async function startMcpServer() {
|
|
|
521
571
|
],
|
|
522
572
|
};
|
|
523
573
|
});
|
|
574
|
+
// Subscribe handler — no-op (resources are generated on-read, no push notifications yet)
|
|
575
|
+
server.setRequestHandler(SubscribeRequestSchema, async () => ({}));
|
|
524
576
|
const transport = new StdioServerTransport();
|
|
525
577
|
await server.connect(transport);
|
|
526
578
|
// Log startup with version, commit, and tool count
|
package/dist/mcp/tools.js
CHANGED
|
@@ -289,10 +289,10 @@ Sync a persona between environments (dev, staging, prod). Always preview first.
|
|
|
289
289
|
properties: {
|
|
290
290
|
method: {
|
|
291
291
|
type: "string",
|
|
292
|
-
enum: ["conversations", "conversation_detail", "show_work", "action_detail", "search"],
|
|
292
|
+
enum: ["conversations", "conversation_detail", "show_work", "action_detail", "workflow_runs", "search"],
|
|
293
293
|
description: "Debug operation to perform (required)"
|
|
294
294
|
},
|
|
295
|
-
conversation_id: { type: "string", description: "Conversation ID (for conversation_detail)" },
|
|
295
|
+
conversation_id: { type: "string", description: "Conversation ID (for conversation_detail). Also accepted by show_work." },
|
|
296
296
|
workflow_run_id: { type: "string", description: "Workflow run ID (for show_work, action_detail)" },
|
|
297
297
|
action_name: { type: "string", description: "Action name (for action_detail)" },
|
|
298
298
|
query: { type: "string", description: "Search query (for search)" },
|
|
@@ -777,6 +777,11 @@ Include \`knowledge_ref\` to correlate feedback with specific knowledge document
|
|
|
777
777
|
- \`feedback(method="analyze")\` - aggregate local insights and actionable items
|
|
778
778
|
- \`feedback(method="analyze", scope="global")\` - [Ema maintainers only] aggregate across ALL clients from cloud storage (requires EMA_INTERNAL=1 + gcloud auth with @ema.co account)
|
|
779
779
|
|
|
780
|
+
## Inter-Agent Messaging
|
|
781
|
+
- \`feedback(method="local")\` - read scoped messages from the in-memory session buffer
|
|
782
|
+
- \`feedback(method="local", scope="role:compliance")\` - filter by message scope
|
|
783
|
+
Messages are emitted by MCP response actions (search, publish, deploy) and stay in-memory for the session. Use for coordination between agents working on the same task.
|
|
784
|
+
|
|
780
785
|
## Maintenance
|
|
781
786
|
- \`feedback(method="flush")\` - force immediate upload of pending outbox entries to remote storage
|
|
782
787
|
|
|
@@ -791,8 +796,8 @@ Include \`knowledge_ref\` to correlate feedback with specific knowledge document
|
|
|
791
796
|
properties: {
|
|
792
797
|
method: {
|
|
793
798
|
type: "string",
|
|
794
|
-
enum: ["submit", "list", "analyze", "flush"],
|
|
795
|
-
description: "Operation to perform (required)",
|
|
799
|
+
enum: ["submit", "list", "local", "analyze", "flush"],
|
|
800
|
+
description: "Operation to perform (required). 'local' reads scoped messages from the in-memory session buffer for inter-agent coordination.",
|
|
796
801
|
},
|
|
797
802
|
category: {
|
|
798
803
|
type: "string",
|
|
@@ -858,12 +863,14 @@ Include \`knowledge_ref\` to correlate feedback with specific knowledge document
|
|
|
858
863
|
3. \`debug(method="show_work", persona_id="abc", workflow_run_id="...")\` - see all actions' execution traces
|
|
859
864
|
4. \`debug(method="action_detail", persona_id="abc", workflow_run_id="...", action_name="...")\` - deep trace
|
|
860
865
|
|
|
861
|
-
## Dashboard personas
|
|
862
|
-
|
|
863
|
-
1. Get \`workflow_run_id\` from the dashboard UI debug view
|
|
866
|
+
## Dashboard personas
|
|
867
|
+
1. \`debug(method="workflow_runs", persona_id="abc")\` - list recent workflow runs (dashboard rows)
|
|
864
868
|
2. \`debug(method="show_work", persona_id="abc", workflow_run_id="...")\` - see execution traces
|
|
865
869
|
3. \`debug(method="action_detail", persona_id="abc", workflow_run_id="...", action_name="...")\` - deep trace
|
|
866
870
|
|
|
871
|
+
## Auto-routing
|
|
872
|
+
If you pass a workflow_run_id to \`conversation_detail\`, it auto-routes to \`show_work\`. \`show_work\` also accepts \`conversation_id\` as an alias for \`workflow_run_id\`.
|
|
873
|
+
|
|
867
874
|
## Also available as persona sub-resource
|
|
868
875
|
- \`persona(id="abc", debug={method:"conversations"})\` - same as debug tool but scoped to persona`,
|
|
869
876
|
inputSchema: {
|
|
@@ -871,20 +878,20 @@ Dashboard personas do NOT create conversations. Skip steps 1-2:
|
|
|
871
878
|
properties: {
|
|
872
879
|
method: {
|
|
873
880
|
type: "string",
|
|
874
|
-
enum: ["conversations", "conversation_detail", "show_work", "action_detail"],
|
|
881
|
+
enum: ["conversations", "conversation_detail", "show_work", "action_detail", "workflow_runs", "search"],
|
|
875
882
|
description: "Operation to perform (required)",
|
|
876
883
|
},
|
|
877
884
|
persona_id: {
|
|
878
885
|
type: "string",
|
|
879
|
-
description: "Persona ID (required for conversations, show_work, action_detail, search)",
|
|
886
|
+
description: "Persona ID (required for conversations, workflow_runs, show_work, action_detail, search)",
|
|
880
887
|
},
|
|
881
888
|
conversation_id: {
|
|
882
889
|
type: "string",
|
|
883
|
-
description: "Conversation ID (for method=conversation_detail, or to scope search)",
|
|
890
|
+
description: "Conversation ID (for method=conversation_detail, or to scope search). Also accepted by show_work as alias for workflow_run_id.",
|
|
884
891
|
},
|
|
885
892
|
workflow_run_id: {
|
|
886
893
|
type: "string",
|
|
887
|
-
description: "Workflow run ID (for method=show_work, action_detail)",
|
|
894
|
+
description: "Workflow run ID (for method=show_work, action_detail). Auto-discovered via workflow_runs for dashboard personas.",
|
|
888
895
|
},
|
|
889
896
|
action_name: {
|
|
890
897
|
type: "string",
|
package/dist/sdk/client.js
CHANGED
|
@@ -1028,13 +1028,13 @@ export class EmaClient {
|
|
|
1028
1028
|
* that define pre-configured AI Employee configurations.
|
|
1029
1029
|
*/
|
|
1030
1030
|
async getPersonaTemplates() {
|
|
1031
|
-
//
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
});
|
|
1031
|
+
// POST first (original, frontend still uses), GET fallback (planned replacement).
|
|
1032
|
+
// Once backend drops POST, GET takes over automatically.
|
|
1033
|
+
let resp = await this.requestWithRetries("POST", "/api/personas/get_persona_templates", {
|
|
1034
|
+
json: {},
|
|
1035
|
+
});
|
|
1036
|
+
if (!resp.ok || resp.status === 405) {
|
|
1037
|
+
resp = await this.requestWithRetries("GET", "/api/personas/get_persona_templates", {});
|
|
1038
1038
|
}
|
|
1039
1039
|
if (!resp.ok) {
|
|
1040
1040
|
throw new EmaApiError({
|
package/dist/sdk/ema-client.js
CHANGED
|
@@ -293,9 +293,24 @@ export class EmaClientV2 {
|
|
|
293
293
|
// Persona Templates - REST API
|
|
294
294
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
295
295
|
/**
|
|
296
|
-
* List all persona templates available to the tenant
|
|
296
|
+
* List all persona templates available to the tenant.
|
|
297
|
+
*
|
|
298
|
+
* Backend has both POST (original, frontend still uses) and GET (planned
|
|
299
|
+
* replacement — TODO in backend to drop POST once frontend migrates).
|
|
300
|
+
* POST first since GET is not yet deployed everywhere; GET as fallback
|
|
301
|
+
* so we're ready when POST is eventually removed.
|
|
297
302
|
*/
|
|
298
303
|
async listPersonaTemplates() {
|
|
304
|
+
try {
|
|
305
|
+
const result = await api.listPersonaTemplatesPost({ client: this.restClient });
|
|
306
|
+
const response = result.data;
|
|
307
|
+
const templates = response?.templates ?? [];
|
|
308
|
+
if (templates.length > 0)
|
|
309
|
+
return templates;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
// POST failed (removed or 405) — fall through to GET
|
|
313
|
+
}
|
|
299
314
|
const result = await api.listPersonaTemplates({ client: this.restClient });
|
|
300
315
|
const response = result.data;
|
|
301
316
|
return response?.templates ?? [];
|
package/package.json
CHANGED