@dypai-ai/mcp 1.0.10 → 1.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/package.json +5 -2
- package/src/index.js +231 -66
- package/src/tools/codegen.js +362 -0
- package/src/tools/deploy.js +9 -32
- package/src/tools/domains.js +49 -52
- package/src/tools/enrich.js +17 -0
- package/src/tools/frontend.js +93 -0
- package/src/tools/project-context.js +84 -0
- package/src/tools/proxy.js +14 -6
- package/src/tools/sql-side-effects.js +91 -0
- package/src/tools/sync/codec.js +185 -0
- package/src/tools/sync/describe.js +149 -0
- package/src/tools/sync/diff.js +83 -0
- package/src/tools/sync/index.js +18 -0
- package/src/tools/sync/planner.js +426 -0
- package/src/tools/sync/pull.js +411 -0
- package/src/tools/sync/push.js +397 -0
- package/src/tools/sync/schema-dump.js +96 -0
- package/src/tools/sync/test-endpoint.js +210 -0
- package/src/tools/sync/test.js +343 -0
- package/src/tools/sync/transforms.js +157 -0
- package/src/tools/sync/validate.js +567 -0
- package/src/tools/trace-summarize.js +178 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarize a per-node workflow trace for the agent without blowing its
|
|
3
|
+
* context window.
|
|
4
|
+
*
|
|
5
|
+
* The engine returns trace shape:
|
|
6
|
+
* { execution_id, workflow: {...}, execution_order: [...],
|
|
7
|
+
* nodes: { <id>: { status, duration_ms, output_summary, error?,
|
|
8
|
+
* failure_snapshot?, branch_decision?, events } } }
|
|
9
|
+
*
|
|
10
|
+
* Modes:
|
|
11
|
+
* - "smart" (default) — success → minimal; failure → focused on failing node
|
|
12
|
+
* - "full" — raw trace (opt-in, for deep dives)
|
|
13
|
+
* - "minimal" — just success/failure + duration + execution_order
|
|
14
|
+
*
|
|
15
|
+
* The raw `events[]` array (node-scoped event log) is always dropped from
|
|
16
|
+
* "smart" and "minimal" — it's redundant with the parsed fields.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const MAX_FIELD_CHARS = 2000 // per-string truncation threshold
|
|
20
|
+
const MAX_SNAPSHOT_KEYS = 6 // summarize large snapshots into a key outline
|
|
21
|
+
|
|
22
|
+
function truncateString(s, max = MAX_FIELD_CHARS) {
|
|
23
|
+
if (typeof s !== "string") return s
|
|
24
|
+
if (s.length <= max) return s
|
|
25
|
+
return s.slice(0, max) + `... [truncated ${s.length - max} chars, call dypai_trace with full=true]`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function summarizeValue(v) {
|
|
29
|
+
if (v == null) return v
|
|
30
|
+
if (typeof v === "string") return truncateString(v)
|
|
31
|
+
if (Array.isArray(v)) {
|
|
32
|
+
if (v.length > MAX_SNAPSHOT_KEYS) {
|
|
33
|
+
return [...v.slice(0, MAX_SNAPSHOT_KEYS).map(summarizeValue), `... ${v.length - MAX_SNAPSHOT_KEYS} more`]
|
|
34
|
+
}
|
|
35
|
+
return v.map(summarizeValue)
|
|
36
|
+
}
|
|
37
|
+
if (typeof v === "object") {
|
|
38
|
+
const keys = Object.keys(v)
|
|
39
|
+
if (keys.length > MAX_SNAPSHOT_KEYS) {
|
|
40
|
+
const sample = {}
|
|
41
|
+
for (const k of keys.slice(0, MAX_SNAPSHOT_KEYS)) sample[k] = summarizeValue(v[k])
|
|
42
|
+
sample[`_truncated_keys`] = keys.length - MAX_SNAPSHOT_KEYS
|
|
43
|
+
return sample
|
|
44
|
+
}
|
|
45
|
+
const out = {}
|
|
46
|
+
for (const [k, val] of Object.entries(v)) out[k] = summarizeValue(val)
|
|
47
|
+
return out
|
|
48
|
+
}
|
|
49
|
+
return v
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Build a hint string from the error message based on common patterns. */
|
|
53
|
+
function hintFromError(err) {
|
|
54
|
+
const m = String(err?.message || "")
|
|
55
|
+
if (/relation .* does not exist/i.test(m)) return "Table not found. Check dypai/schema.sql."
|
|
56
|
+
if (/column .* does not exist/i.test(m)) return "Column not found. Verify the SQL column against the table schema."
|
|
57
|
+
if (/placeholder|\$\{/i.test(m)) return "Placeholder resolution failed. Inspect node inputs."
|
|
58
|
+
if (/credential/i.test(m)) return "Credential lookup failed. Check the credential name exists remotely."
|
|
59
|
+
if (/timeout|timed out/i.test(m)) return "Node timed out. Consider a faster query or raise the node timeout."
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function summarizeTrace(trace, mode = "smart") {
|
|
64
|
+
if (!trace || typeof trace !== "object") return trace
|
|
65
|
+
if (mode === "full") return trace
|
|
66
|
+
|
|
67
|
+
const wf = trace.workflow || {}
|
|
68
|
+
const execOrder = Array.isArray(trace.execution_order) ? trace.execution_order : []
|
|
69
|
+
const nodes = trace.nodes || {}
|
|
70
|
+
|
|
71
|
+
if (mode === "minimal") {
|
|
72
|
+
return {
|
|
73
|
+
execution_id: trace.execution_id,
|
|
74
|
+
status: wf.status,
|
|
75
|
+
duration_ms: wf.duration_ms,
|
|
76
|
+
execution_order: execOrder,
|
|
77
|
+
error: wf.error || undefined,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// "smart" mode
|
|
82
|
+
const failed = wf.status === "failed"
|
|
83
|
+
const failedNodeId = failed
|
|
84
|
+
? Object.values(nodes).find(n => n && n.status === "failed")?.node_id
|
|
85
|
+
: null
|
|
86
|
+
|
|
87
|
+
const nodeSummaries = []
|
|
88
|
+
for (const id of execOrder) {
|
|
89
|
+
const n = nodes[id]
|
|
90
|
+
if (!n) continue
|
|
91
|
+
|
|
92
|
+
const base = {
|
|
93
|
+
id: n.node_id,
|
|
94
|
+
type: n.node_type,
|
|
95
|
+
status: n.status,
|
|
96
|
+
duration_ms: n.duration_ms,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// On success: keep it tiny — just id/type/status/duration
|
|
100
|
+
if (n.status === "completed") {
|
|
101
|
+
// include output_summary only if it's the LAST node (likely the final result)
|
|
102
|
+
if (id === execOrder[execOrder.length - 1] && n.output_summary) {
|
|
103
|
+
base.output_summary = summarizeValue(n.output_summary)
|
|
104
|
+
}
|
|
105
|
+
nodeSummaries.push(base)
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// On the failing node: include full detail (error + snapshot outline)
|
|
110
|
+
if (n.status === "failed") {
|
|
111
|
+
base.error = {
|
|
112
|
+
message: truncateString(n.error?.message),
|
|
113
|
+
type: n.error?.type,
|
|
114
|
+
stack: truncateString(n.error?.stack, 800),
|
|
115
|
+
}
|
|
116
|
+
// failure_snapshot: reduce to a key outline — not full values
|
|
117
|
+
if (n.failure_snapshot) {
|
|
118
|
+
const snap = n.failure_snapshot
|
|
119
|
+
base.failure_snapshot = {
|
|
120
|
+
inputs_keys: Object.keys(snap.nodes_inputs || {}),
|
|
121
|
+
results_keys: Object.keys(snap.nodes_results || {}),
|
|
122
|
+
hint: "Use dypai_trace(execution_id, full=true) to see full snapshot values.",
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (n.branch_decision) base.branch_decision = summarizeValue(n.branch_decision)
|
|
126
|
+
nodeSummaries.push(base)
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
nodeSummaries.push(base)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const summary = {
|
|
134
|
+
execution_id: trace.execution_id,
|
|
135
|
+
success: wf.status === "completed",
|
|
136
|
+
status: wf.status,
|
|
137
|
+
duration_ms: wf.duration_ms,
|
|
138
|
+
failed_at: failedNodeId,
|
|
139
|
+
execution_order: execOrder,
|
|
140
|
+
nodes: nodeSummaries,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (failed) {
|
|
144
|
+
const failedNode = nodes[failedNodeId]
|
|
145
|
+
const hint = hintFromError(failedNode?.error)
|
|
146
|
+
if (hint) summary.hint = hint
|
|
147
|
+
summary.next_step =
|
|
148
|
+
`Inspect the failing node's input above. For full snapshot use: dypai_trace(execution_id='${trace.execution_id}', full=true).`
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return summary
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Given a test_workflow response that includes a `trace` field (from the
|
|
156
|
+
* updated remote MCP), apply summarization. Safe no-op if no trace present.
|
|
157
|
+
*/
|
|
158
|
+
export function summarizeTestWorkflowResponse(response, mode = "smart") {
|
|
159
|
+
if (!response || typeof response !== "object") return response
|
|
160
|
+
if (!response.trace) return response // older engine or trace fetch failed
|
|
161
|
+
return {
|
|
162
|
+
...response,
|
|
163
|
+
trace: summarizeTrace(response.trace, mode),
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Summarize a dypai_trace response. The response may contain either:
|
|
169
|
+
* - { execution_id, trace: {...} } (single trace)
|
|
170
|
+
* - { executions: [...] } (listing, already compact)
|
|
171
|
+
*/
|
|
172
|
+
export function summarizeDypaiTraceResponse(response, mode = "smart") {
|
|
173
|
+
if (!response || typeof response !== "object") return response
|
|
174
|
+
if (response.trace) {
|
|
175
|
+
return { ...response, trace: summarizeTrace(response.trace, mode) }
|
|
176
|
+
}
|
|
177
|
+
return response
|
|
178
|
+
}
|