mindgraph-mcp 0.19.0 → 0.21.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/README.md +38 -3
- package/dist/cli.js +1385 -247
- package/dist/index.js +1142 -197
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -60,6 +60,9 @@ function loadHookEnv(dir) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// src/tools.ts
|
|
64
|
+
var import_node_crypto5 = require("crypto");
|
|
65
|
+
|
|
63
66
|
// src/error-detail.ts
|
|
64
67
|
var import_mindgraph = require("mindgraph");
|
|
65
68
|
function errorDetail(e) {
|
|
@@ -86,6 +89,22 @@ function conflictState(e) {
|
|
|
86
89
|
}
|
|
87
90
|
return lifted;
|
|
88
91
|
}
|
|
92
|
+
function toolError(e, fallbackCode) {
|
|
93
|
+
const body = e instanceof import_mindgraph.MindGraphError && e.body && typeof e.body === "object" && !Array.isArray(e.body) ? e.body : {};
|
|
94
|
+
const code = typeof body.code === "string" ? body.code : fallbackCode;
|
|
95
|
+
const payload = {
|
|
96
|
+
error: errorDetail(e),
|
|
97
|
+
...conflictState(e),
|
|
98
|
+
...e instanceof import_mindgraph.MindGraphError ? { status: e.status } : {},
|
|
99
|
+
...code !== void 0 ? { code } : {},
|
|
100
|
+
...typeof body.retriable === "boolean" ? { retriable: body.retriable } : {}
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
104
|
+
structuredContent: payload,
|
|
105
|
+
isError: true
|
|
106
|
+
};
|
|
107
|
+
}
|
|
89
108
|
|
|
90
109
|
// src/codegraph.ts
|
|
91
110
|
var import_node_child_process = require("child_process");
|
|
@@ -238,29 +257,29 @@ async function runProcess(executable, args, timeoutMs, env, cwd) {
|
|
|
238
257
|
child.stderr.on("data", collect(stderr));
|
|
239
258
|
child.on("error", (cause) => {
|
|
240
259
|
clearTimeout(timer);
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
rejectPromise(
|
|
260
|
+
const error2 = new Error(cause.message);
|
|
261
|
+
error2.kind = cause.code === "ENOENT" ? "absent" : "command_failed";
|
|
262
|
+
rejectPromise(error2);
|
|
244
263
|
});
|
|
245
264
|
child.on("close", (code) => {
|
|
246
265
|
clearTimeout(timer);
|
|
247
266
|
if (timedOut) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
rejectPromise(
|
|
267
|
+
const error2 = new Error(`command timed out after ${timeoutMs}ms`);
|
|
268
|
+
error2.kind = "timeout";
|
|
269
|
+
rejectPromise(error2);
|
|
251
270
|
return;
|
|
252
271
|
}
|
|
253
272
|
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
rejectPromise(
|
|
273
|
+
const error2 = new Error("codegraph output exceeded 5 MiB");
|
|
274
|
+
error2.kind = "command_failed";
|
|
275
|
+
rejectPromise(error2);
|
|
257
276
|
return;
|
|
258
277
|
}
|
|
259
278
|
if (code !== 0) {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
rejectPromise(
|
|
279
|
+
const error2 = new Error(Buffer.concat(stderr).toString("utf8").trim());
|
|
280
|
+
error2.kind = "command_failed";
|
|
281
|
+
error2.exitCode = code;
|
|
282
|
+
rejectPromise(error2);
|
|
264
283
|
return;
|
|
265
284
|
}
|
|
266
285
|
resolvePromise(Buffer.concat(stdout).toString("utf8"));
|
|
@@ -813,9 +832,7 @@ function codeRefIdentityKey(ref) {
|
|
|
813
832
|
qualified_name: ref.qualifiedName,
|
|
814
833
|
disambiguator: {
|
|
815
834
|
signature: ref.signature ?? "",
|
|
816
|
-
path: ref.path
|
|
817
|
-
start_line: ref.startLine,
|
|
818
|
-
end_line: ref.endLine
|
|
835
|
+
path: ref.path
|
|
819
836
|
}
|
|
820
837
|
};
|
|
821
838
|
}
|
|
@@ -1085,7 +1102,7 @@ async function handleCodeTool(client2, args, adapter = new CodegraphAdapter({ cw
|
|
|
1085
1102
|
if (cause instanceof UnknownRepositoryError) {
|
|
1086
1103
|
return err("unknown_repository", cause.message);
|
|
1087
1104
|
}
|
|
1088
|
-
return
|
|
1105
|
+
return toolError(cause, "code_tool_failed");
|
|
1089
1106
|
}
|
|
1090
1107
|
}
|
|
1091
1108
|
async function attachCodeRefsToToolResult(client2, result, args, adapter) {
|
|
@@ -1193,7 +1210,7 @@ async function anchorCodeRef(client2, ref, repositoryUid, spaceUid, agentId) {
|
|
|
1193
1210
|
identity_space_uid: spaceUid,
|
|
1194
1211
|
agent_id: agentId
|
|
1195
1212
|
});
|
|
1196
|
-
if (response.uid) {
|
|
1213
|
+
if (response.uid && response.created !== false && response.status !== "existing") {
|
|
1197
1214
|
await client2.entity({
|
|
1198
1215
|
action: "relate",
|
|
1199
1216
|
source_uid: response.uid,
|
|
@@ -1556,8 +1573,8 @@ async function handleSyncTool(client2, args) {
|
|
|
1556
1573
|
}
|
|
1557
1574
|
}
|
|
1558
1575
|
return ok2(await remote.memorySync(request));
|
|
1559
|
-
} catch (
|
|
1560
|
-
return
|
|
1576
|
+
} catch (error2) {
|
|
1577
|
+
return toolError(error2, "sync_failed");
|
|
1561
1578
|
}
|
|
1562
1579
|
}
|
|
1563
1580
|
async function scanRepository(remote, repository, requested, provider, agentId) {
|
|
@@ -1595,6 +1612,9 @@ async function scanRepository(remote, repository, requested, provider, agentId)
|
|
|
1595
1612
|
};
|
|
1596
1613
|
}
|
|
1597
1614
|
|
|
1615
|
+
// src/memory-tool.ts
|
|
1616
|
+
var import_node_crypto4 = require("crypto");
|
|
1617
|
+
|
|
1598
1618
|
// src/render.ts
|
|
1599
1619
|
var LABEL_MAX = 200;
|
|
1600
1620
|
var SUMMARY_MAX = 400;
|
|
@@ -1603,6 +1623,8 @@ var ARTICLE_MAX = 6e3;
|
|
|
1603
1623
|
var CHUNK_MAX = 6e3;
|
|
1604
1624
|
var RELATIONSHIP_MAX = 40;
|
|
1605
1625
|
var RENDER_CHAR_BUDGET = 24e3;
|
|
1626
|
+
var MIN_RENDER_CHAR_BUDGET = 512;
|
|
1627
|
+
var BOUNDED_MARKER_RESERVE = 220;
|
|
1606
1628
|
var CURATION_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
1607
1629
|
var INFRA_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
1608
1630
|
function obj(value) {
|
|
@@ -1614,12 +1636,22 @@ function str(value) {
|
|
|
1614
1636
|
function num(value) {
|
|
1615
1637
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1616
1638
|
}
|
|
1639
|
+
function edgeTypeName(value) {
|
|
1640
|
+
return str(value) ?? str(obj(value)?.Custom);
|
|
1641
|
+
}
|
|
1642
|
+
function renderBudget(requested) {
|
|
1643
|
+
if (requested === void 0 || !Number.isFinite(requested)) return RENDER_CHAR_BUDGET;
|
|
1644
|
+
return Math.min(
|
|
1645
|
+
RENDER_CHAR_BUDGET,
|
|
1646
|
+
Math.max(MIN_RENDER_CHAR_BUDGET, Math.floor(requested))
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1617
1649
|
function clip(value, max, state) {
|
|
1618
|
-
const
|
|
1619
|
-
if (!
|
|
1620
|
-
if (
|
|
1650
|
+
const text2 = str(value);
|
|
1651
|
+
if (!text2) return void 0;
|
|
1652
|
+
if (text2.length <= max) return text2;
|
|
1621
1653
|
state.bounded = true;
|
|
1622
|
-
return `${
|
|
1654
|
+
return `${text2.slice(0, max - 1)}\u2026`;
|
|
1623
1655
|
}
|
|
1624
1656
|
function isNodeShaped(value) {
|
|
1625
1657
|
const node = obj(value);
|
|
@@ -1741,7 +1773,7 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
1741
1773
|
for (const raw of edges) {
|
|
1742
1774
|
const edge = obj(raw);
|
|
1743
1775
|
if (!edge) continue;
|
|
1744
|
-
const type =
|
|
1776
|
+
const type = edgeTypeName(edge.edge_type) || "?";
|
|
1745
1777
|
const from = str(edge.from_uid);
|
|
1746
1778
|
const to = str(edge.to_uid);
|
|
1747
1779
|
if (CURATION_EDGE_TYPES.has(type)) continue;
|
|
@@ -1754,25 +1786,29 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
1754
1786
|
if (lines.length > RELATIONSHIP_MAX) {
|
|
1755
1787
|
state.bounded = true;
|
|
1756
1788
|
const extra = lines.length - RELATIONSHIP_MAX;
|
|
1789
|
+
state.omitted += extra;
|
|
1757
1790
|
return [...lines.slice(0, RELATIONSHIP_MAX), `- (+${extra} more relationships)`];
|
|
1758
1791
|
}
|
|
1759
1792
|
return lines;
|
|
1760
1793
|
}
|
|
1761
|
-
function assemble(header, sections, state) {
|
|
1794
|
+
function assemble(header, sections, state, maxChars) {
|
|
1795
|
+
const budget = renderBudget(maxChars);
|
|
1796
|
+
const packingBudget = Math.max(header.length, budget - BOUNDED_MARKER_RESERVE);
|
|
1762
1797
|
const lines = [header];
|
|
1763
1798
|
let used = header.length;
|
|
1764
1799
|
for (const section of sections) {
|
|
1765
1800
|
if (section.items.length === 0 && !section.heading) continue;
|
|
1766
1801
|
const headingCost = section.heading.length + 2;
|
|
1767
|
-
if (used + headingCost >
|
|
1802
|
+
if (used + headingCost > packingBudget) {
|
|
1768
1803
|
state.bounded = true;
|
|
1804
|
+
state.omitted += Math.max(1, section.items.length);
|
|
1769
1805
|
continue;
|
|
1770
1806
|
}
|
|
1771
1807
|
let sectionUsed = 0;
|
|
1772
1808
|
const kept = [];
|
|
1773
1809
|
let dropped = 0;
|
|
1774
1810
|
for (const item of section.items) {
|
|
1775
|
-
if (used + headingCost + sectionUsed + item.length + 1 >
|
|
1811
|
+
if (used + headingCost + sectionUsed + item.length + 1 > packingBudget) {
|
|
1776
1812
|
dropped += 1;
|
|
1777
1813
|
continue;
|
|
1778
1814
|
}
|
|
@@ -1781,13 +1817,17 @@ function assemble(header, sections, state) {
|
|
|
1781
1817
|
}
|
|
1782
1818
|
if (kept.length === 0 && section.items.length > 0) {
|
|
1783
1819
|
state.bounded = true;
|
|
1820
|
+
state.omitted += dropped;
|
|
1784
1821
|
continue;
|
|
1785
1822
|
}
|
|
1786
1823
|
if (dropped > 0) {
|
|
1787
1824
|
state.bounded = true;
|
|
1825
|
+
state.omitted += dropped;
|
|
1788
1826
|
const marker = `(+${dropped} more not shown)`;
|
|
1789
|
-
|
|
1790
|
-
|
|
1827
|
+
if (used + headingCost + sectionUsed + marker.length + 1 <= packingBudget) {
|
|
1828
|
+
kept.push(marker);
|
|
1829
|
+
sectionUsed += marker.length + 1;
|
|
1830
|
+
}
|
|
1791
1831
|
}
|
|
1792
1832
|
lines.push(
|
|
1793
1833
|
section.items.length === 0 ? section.heading : section.heading ? `${section.heading}
|
|
@@ -1797,10 +1837,10 @@ ${kept.join("\n")}` : kept.join("\n")
|
|
|
1797
1837
|
}
|
|
1798
1838
|
if (state.bounded) {
|
|
1799
1839
|
lines.push(
|
|
1800
|
-
|
|
1840
|
+
`\u2026[rendered context bounded to ${budget} chars; ${state.omitted} item(s) omitted \u2014 fetch full node content by uid, narrow the query, raise max_output_chars, or pass format: "json" for the raw response]`
|
|
1801
1841
|
);
|
|
1802
1842
|
}
|
|
1803
|
-
return lines.join("\n\n");
|
|
1843
|
+
return lines.join("\n\n").slice(0, budget);
|
|
1804
1844
|
}
|
|
1805
1845
|
function policySections(payload, state) {
|
|
1806
1846
|
const policies = Array.isArray(payload.applicable_policies) ? payload.applicable_policies : [];
|
|
@@ -1821,7 +1861,7 @@ function hiddenSections(payload) {
|
|
|
1821
1861
|
}
|
|
1822
1862
|
];
|
|
1823
1863
|
}
|
|
1824
|
-
function renderContext(response) {
|
|
1864
|
+
function renderContext(response, maxChars) {
|
|
1825
1865
|
const payload = obj(response);
|
|
1826
1866
|
if (!payload) return void 0;
|
|
1827
1867
|
const graph = obj(payload.graph);
|
|
@@ -1831,7 +1871,7 @@ function renderContext(response) {
|
|
|
1831
1871
|
const infraOnly = shaped.length - nodes.length;
|
|
1832
1872
|
const articles = Array.isArray(payload.articles) ? payload.articles : [];
|
|
1833
1873
|
const chunks = Array.isArray(payload.chunks) ? payload.chunks : [];
|
|
1834
|
-
const state = { bounded: false };
|
|
1874
|
+
const state = { bounded: false, omitted: 0 };
|
|
1835
1875
|
const sections = [];
|
|
1836
1876
|
if (articles.length > 0) {
|
|
1837
1877
|
sections.push({
|
|
@@ -1874,11 +1914,129 @@ ${clip(article.content, ARTICLE_MAX, state) || ""}`
|
|
|
1874
1914
|
return "No results found for this search.";
|
|
1875
1915
|
}
|
|
1876
1916
|
if (nodes.length === 0 && articles.length === 0 && chunks.length === 0) {
|
|
1877
|
-
return assemble(
|
|
1917
|
+
return assemble(
|
|
1918
|
+
"# Retrieved context\n\nNo graph results matched this search.",
|
|
1919
|
+
sections,
|
|
1920
|
+
state,
|
|
1921
|
+
maxChars
|
|
1922
|
+
);
|
|
1878
1923
|
}
|
|
1879
|
-
return assemble("# Retrieved context", sections, state);
|
|
1924
|
+
return assemble("# Retrieved context", sections, state, maxChars);
|
|
1925
|
+
}
|
|
1926
|
+
function resumeEntry(raw, state, fallbackType) {
|
|
1927
|
+
const wrapper = obj(raw);
|
|
1928
|
+
if (!wrapper) return void 0;
|
|
1929
|
+
const value = obj(wrapper.node) ?? wrapper;
|
|
1930
|
+
if (isNodeShaped(value)) return nodeLines(value, state);
|
|
1931
|
+
const uid = str(value.uid);
|
|
1932
|
+
const props = obj(value.props);
|
|
1933
|
+
const label = clip(value.label, LABEL_MAX, state) ?? clip(value.name, LABEL_MAX, state) ?? clip(value.title, LABEL_MAX, state) ?? clip(value.action, LABEL_MAX, state) ?? fallbackType;
|
|
1934
|
+
const status = str(value.status) ?? str(props?.status);
|
|
1935
|
+
const summary = clip(value.summary, SUMMARY_MAX, state) ?? clip(value.description, SUMMARY_MAX, state) ?? clip(value.content, SUMMARY_MAX, state) ?? clip(value.outcome_summary, SUMMARY_MAX, state) ?? clip(props?.summary, SUMMARY_MAX, state);
|
|
1936
|
+
const details = [
|
|
1937
|
+
status ? `status ${status}` : void 0,
|
|
1938
|
+
str(value.path) ? `path ${str(value.path)}` : void 0,
|
|
1939
|
+
str(value.symbol) ? `symbol ${str(value.symbol)}` : void 0
|
|
1940
|
+
].filter(Boolean);
|
|
1941
|
+
const head = `- **${label}**${uid ? ` [${uid}]` : ""}${details.length > 0 ? ` (${details.join(", ")})` : ""}`;
|
|
1942
|
+
return summary && summary !== label ? `${head}: ${summary}` : head;
|
|
1943
|
+
}
|
|
1944
|
+
function resumeSection(heading, values, state, fallbackType) {
|
|
1945
|
+
const items = values.map((value) => resumeEntry(value, state, fallbackType)).filter((value) => Boolean(value));
|
|
1946
|
+
return items.length > 0 ? { heading, items } : void 0;
|
|
1947
|
+
}
|
|
1948
|
+
function renderResumeContext(response, maxChars) {
|
|
1949
|
+
const payload = obj(response);
|
|
1950
|
+
if (!payload) return void 0;
|
|
1951
|
+
const state = { bounded: false, omitted: 0 };
|
|
1952
|
+
const status = str(payload.status);
|
|
1953
|
+
if (!payload.task && status === "no_eligible_work") {
|
|
1954
|
+
const scopedOut = Array.isArray(payload.scoped_out_tasks) ? payload.scoped_out_tasks.length : 0;
|
|
1955
|
+
const note = scopedOut > 0 ? ` ${scopedOut} task(s) exist outside the requested scope.` : "";
|
|
1956
|
+
return assemble(
|
|
1957
|
+
"# Resume context",
|
|
1958
|
+
[{ heading: `No eligible work was found in the requested scope.${note}`, items: [] }],
|
|
1959
|
+
state,
|
|
1960
|
+
maxChars
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
const sections = [];
|
|
1964
|
+
const push = (section) => {
|
|
1965
|
+
if (section) sections.push(section);
|
|
1966
|
+
};
|
|
1967
|
+
push(resumeSection("## Current task", [payload.task], state, "Task"));
|
|
1968
|
+
push(
|
|
1969
|
+
resumeSection(
|
|
1970
|
+
"## Goal and project",
|
|
1971
|
+
[payload.goal, payload.project].filter(Boolean),
|
|
1972
|
+
state,
|
|
1973
|
+
"Scope"
|
|
1974
|
+
)
|
|
1975
|
+
);
|
|
1976
|
+
push(resumeSection("## Plan", [payload.plan], state, "Plan"));
|
|
1977
|
+
push(
|
|
1978
|
+
resumeSection(
|
|
1979
|
+
"## Next steps",
|
|
1980
|
+
Array.isArray(payload.next_steps) ? payload.next_steps : [],
|
|
1981
|
+
state,
|
|
1982
|
+
"Next step"
|
|
1983
|
+
)
|
|
1984
|
+
);
|
|
1985
|
+
push(
|
|
1986
|
+
resumeSection(
|
|
1987
|
+
"## Blockers",
|
|
1988
|
+
Array.isArray(payload.blockers) ? payload.blockers : [],
|
|
1989
|
+
state,
|
|
1990
|
+
"Blocker"
|
|
1991
|
+
)
|
|
1992
|
+
);
|
|
1993
|
+
const knowledge = obj(payload.knowledge);
|
|
1994
|
+
push(
|
|
1995
|
+
resumeSection(
|
|
1996
|
+
"## Relevant lessons and risks",
|
|
1997
|
+
[
|
|
1998
|
+
...Array.isArray(knowledge?.lessons) ? knowledge.lessons : [],
|
|
1999
|
+
...Array.isArray(knowledge?.risks) ? knowledge.risks : []
|
|
2000
|
+
],
|
|
2001
|
+
state,
|
|
2002
|
+
"Knowledge"
|
|
2003
|
+
)
|
|
2004
|
+
);
|
|
2005
|
+
push(
|
|
2006
|
+
resumeSection(
|
|
2007
|
+
"## Active execution",
|
|
2008
|
+
[payload.active_execution].filter(Boolean),
|
|
2009
|
+
state,
|
|
2010
|
+
"Execution"
|
|
2011
|
+
)
|
|
2012
|
+
);
|
|
2013
|
+
push(
|
|
2014
|
+
resumeSection(
|
|
2015
|
+
"## Recent executions",
|
|
2016
|
+
Array.isArray(payload.recent_executions) ? payload.recent_executions : [],
|
|
2017
|
+
state,
|
|
2018
|
+
"Execution"
|
|
2019
|
+
)
|
|
2020
|
+
);
|
|
2021
|
+
push(
|
|
2022
|
+
resumeSection(
|
|
2023
|
+
"## Code targets",
|
|
2024
|
+
Array.isArray(payload.code_targets) ? payload.code_targets : [],
|
|
2025
|
+
state,
|
|
2026
|
+
"Code target"
|
|
2027
|
+
)
|
|
2028
|
+
);
|
|
2029
|
+
push(resumeSection("## Lease", [payload.lease].filter(Boolean), state, "Lease"));
|
|
2030
|
+
const warning = clip(payload.warning, SUMMARY_MAX, state);
|
|
2031
|
+
if (warning) sections.push({ heading: "## Warning", items: [`- ${warning}`] });
|
|
2032
|
+
const selectionReason = clip(payload.selection_reason, SUMMARY_MAX, state);
|
|
2033
|
+
if (selectionReason) {
|
|
2034
|
+
sections.push({ heading: "## Selection", items: [`- ${selectionReason}`] });
|
|
2035
|
+
}
|
|
2036
|
+
if (sections.length === 0) return void 0;
|
|
2037
|
+
return assemble("# Resume context", sections, state, maxChars);
|
|
1880
2038
|
}
|
|
1881
|
-
function renderNodeList(response, title, limit) {
|
|
2039
|
+
function renderNodeList(response, title, limit, maxChars) {
|
|
1882
2040
|
let candidates = [];
|
|
1883
2041
|
if (Array.isArray(response)) {
|
|
1884
2042
|
candidates = response;
|
|
@@ -1896,8 +2054,9 @@ function renderNodeList(response, title, limit) {
|
|
|
1896
2054
|
let nodes = candidates.map(unwrapSearchResult).filter((node) => Boolean(node));
|
|
1897
2055
|
if (nodes.length === 0) return void 0;
|
|
1898
2056
|
const total = nodes.length;
|
|
1899
|
-
const state = { bounded: false };
|
|
2057
|
+
const state = { bounded: false, omitted: 0 };
|
|
1900
2058
|
if (limit !== void 0 && limit > 0 && nodes.length > limit) {
|
|
2059
|
+
state.omitted += nodes.length - limit;
|
|
1901
2060
|
nodes = nodes.slice(0, limit);
|
|
1902
2061
|
state.bounded = true;
|
|
1903
2062
|
}
|
|
@@ -1906,18 +2065,23 @@ function renderNodeList(response, title, limit) {
|
|
|
1906
2065
|
return assemble(
|
|
1907
2066
|
`# ${title} (${shown === total ? total : `${shown} of ${total}`})`,
|
|
1908
2067
|
sections,
|
|
1909
|
-
state
|
|
2068
|
+
state,
|
|
2069
|
+
maxChars
|
|
1910
2070
|
);
|
|
1911
2071
|
}
|
|
1912
|
-
function renderTraversal(response) {
|
|
2072
|
+
function renderTraversal(response, maxChars) {
|
|
2073
|
+
const directSteps = Array.isArray(response) ? response : void 0;
|
|
1913
2074
|
const payload = obj(response);
|
|
1914
|
-
if (!payload) return void 0;
|
|
1915
|
-
const
|
|
2075
|
+
if (!payload && !directSteps) return void 0;
|
|
2076
|
+
const body = payload ?? {};
|
|
2077
|
+
const container = obj(body.graph) ?? body;
|
|
1916
2078
|
const rawNodes = Array.isArray(container.nodes) ? container.nodes : [];
|
|
1917
2079
|
const nodes = rawNodes.filter(isNodeShaped);
|
|
1918
|
-
const paths = Array.isArray(
|
|
1919
|
-
|
|
1920
|
-
const
|
|
2080
|
+
const paths = Array.isArray(body.paths) ? body.paths : [];
|
|
2081
|
+
const hasSteps = directSteps !== void 0 || Object.hasOwn(body, "steps");
|
|
2082
|
+
const rawSteps = directSteps ?? (Array.isArray(body.steps) ? body.steps : []);
|
|
2083
|
+
if (nodes.length === 0 && paths.length === 0 && !hasSteps) return void 0;
|
|
2084
|
+
const state = { bounded: false, omitted: 0 };
|
|
1921
2085
|
const sections = [];
|
|
1922
2086
|
const labelByUid = /* @__PURE__ */ new Map();
|
|
1923
2087
|
for (const node of nodes) labelByUid.set(str(node.uid), str(node.label) || "?");
|
|
@@ -1941,6 +2105,42 @@ function renderTraversal(response) {
|
|
|
1941
2105
|
});
|
|
1942
2106
|
sections.push({ heading: "## Paths", items });
|
|
1943
2107
|
}
|
|
2108
|
+
if (hasSteps) {
|
|
2109
|
+
const stepItems = rawSteps.map((raw) => obj(raw)).filter((step) => Boolean(step)).map((step) => {
|
|
2110
|
+
const depth = num(step.depth);
|
|
2111
|
+
const uid = str(step.node_uid) ?? str(step.uid) ?? str(step.edge_to_uid) ?? "?";
|
|
2112
|
+
const parent = str(step.parent_uid) ?? str(step.edge_from_uid);
|
|
2113
|
+
const label = str(step.label) || "(unlabeled)";
|
|
2114
|
+
const relation = edgeTypeName(step.edge_type);
|
|
2115
|
+
const role = str(step.traversal_role);
|
|
2116
|
+
const type = str(step.node_type) ?? str(obj(step.node_type)?.Custom);
|
|
2117
|
+
const cost = num(step.path_cost);
|
|
2118
|
+
const confidence = num(step.path_confidence);
|
|
2119
|
+
const prefix = [
|
|
2120
|
+
depth !== void 0 ? `depth ${depth}` : void 0,
|
|
2121
|
+
role,
|
|
2122
|
+
relation ? `\u2014${relation}\u2192` : void 0
|
|
2123
|
+
].filter(Boolean).join(" ");
|
|
2124
|
+
const meta = [
|
|
2125
|
+
type,
|
|
2126
|
+
parent ? `parent ${parent}` : void 0,
|
|
2127
|
+
cost !== void 0 ? `cost ${cost}` : void 0,
|
|
2128
|
+
confidence !== void 0 ? `confidence ${confidence}` : void 0
|
|
2129
|
+
].filter(Boolean).join(", ");
|
|
2130
|
+
return `- ${prefix ? `${prefix}: ` : ""}**${label}** [${uid}]${meta ? ` (${meta})` : ""}`;
|
|
2131
|
+
});
|
|
2132
|
+
if (stepItems.length > 0) {
|
|
2133
|
+
sections.push({ heading: "## Traversal steps", items: stepItems });
|
|
2134
|
+
} else {
|
|
2135
|
+
const start = str(body.start_uid) || "?";
|
|
2136
|
+
const end = str(body.end_uid);
|
|
2137
|
+
const mode2 = str(body.mode);
|
|
2138
|
+
sections.push({
|
|
2139
|
+
heading: mode2 === "path" && end ? `No path found from [${start}] to [${end}].` : `No traversal steps returned from [${start}].`,
|
|
2140
|
+
items: []
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
1944
2144
|
if (nodes.length > 0) {
|
|
1945
2145
|
sections.push(...groupedNodeSections(nodes, state, "## Nodes\n\n"));
|
|
1946
2146
|
const relationships = relationshipItems(
|
|
@@ -1952,7 +2152,13 @@ function renderTraversal(response) {
|
|
|
1952
2152
|
sections.push({ heading: "## Relationships", items: relationships });
|
|
1953
2153
|
}
|
|
1954
2154
|
}
|
|
1955
|
-
|
|
2155
|
+
const mode = str(body.mode);
|
|
2156
|
+
return assemble(
|
|
2157
|
+
`# Graph traversal${mode ? ` (${mode})` : ""}`,
|
|
2158
|
+
sections,
|
|
2159
|
+
state,
|
|
2160
|
+
maxChars
|
|
2161
|
+
);
|
|
1956
2162
|
}
|
|
1957
2163
|
function neighborLine(value) {
|
|
1958
2164
|
const node = obj(value);
|
|
@@ -1973,7 +2179,7 @@ function renderOntologyAnswer(response) {
|
|
|
1973
2179
|
if (objects.length === 0 && cognitiveEmpty && provenance.length === 0) {
|
|
1974
2180
|
return hasQuerySignature ? "No matching domain objects." : void 0;
|
|
1975
2181
|
}
|
|
1976
|
-
const state = { bounded: false };
|
|
2182
|
+
const state = { bounded: false, omitted: 0 };
|
|
1977
2183
|
const sections = [];
|
|
1978
2184
|
if (objects.length > 0) {
|
|
1979
2185
|
sections.push(...groupedNodeSections(objects, state));
|
|
@@ -2039,7 +2245,7 @@ function renderObjectList(response, title) {
|
|
|
2039
2245
|
if (items.length === 0) {
|
|
2040
2246
|
return rawItems ? `# ${title} (0 results)` : void 0;
|
|
2041
2247
|
}
|
|
2042
|
-
const state = { bounded: false };
|
|
2248
|
+
const state = { bounded: false, omitted: 0 };
|
|
2043
2249
|
const sections = groupedNodeSections(items, state);
|
|
2044
2250
|
const total = num(payload.total_count);
|
|
2045
2251
|
const truncations = Array.isArray(payload.truncation_reasons) ? payload.truncation_reasons.filter((reason) => typeof reason === "string") : [];
|
|
@@ -2055,7 +2261,7 @@ function renderJobs(response) {
|
|
|
2055
2261
|
const jobs = Array.isArray(response) ? response : obj(response)?.jobs;
|
|
2056
2262
|
if (!Array.isArray(jobs)) return void 0;
|
|
2057
2263
|
if (jobs.length === 0) return "No ingestion jobs.";
|
|
2058
|
-
const state = { bounded: false };
|
|
2264
|
+
const state = { bounded: false, omitted: 0 };
|
|
2059
2265
|
const sorted = jobs.map((raw) => obj(raw)).filter((job) => Boolean(job)).sort((a, b) => (num(b.created_at) ?? 0) - (num(a.created_at) ?? 0));
|
|
2060
2266
|
const shown = sorted.slice(0, JOBS_RENDER_MAX);
|
|
2061
2267
|
if (shown.length < sorted.length) state.bounded = true;
|
|
@@ -2081,7 +2287,7 @@ function renderJobs(response) {
|
|
|
2081
2287
|
function renderSignals(response) {
|
|
2082
2288
|
const payload = obj(response);
|
|
2083
2289
|
if (!payload) return void 0;
|
|
2084
|
-
const state = { bounded: false };
|
|
2290
|
+
const state = { bounded: false, omitted: 0 };
|
|
2085
2291
|
const sections = [];
|
|
2086
2292
|
for (const [key, value] of Object.entries(payload)) {
|
|
2087
2293
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
@@ -2106,7 +2312,581 @@ function renderSignals(response) {
|
|
|
2106
2312
|
return assemble("# Synthesis signals", sections, state);
|
|
2107
2313
|
}
|
|
2108
2314
|
|
|
2315
|
+
// src/memory-tool.ts
|
|
2316
|
+
var RESULT_SCHEMA_VERSION = "mindgraph.memory.result.v1";
|
|
2317
|
+
var DEFAULT_OUTPUT_CHARS = 8e3;
|
|
2318
|
+
var MIN_OUTPUT_CHARS = 512;
|
|
2319
|
+
var MAX_OUTPUT_CHARS = 24e3;
|
|
2320
|
+
var HIDDEN_CONTEXT_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
2321
|
+
var HIDDEN_CONTEXT_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
2322
|
+
var MEMORY_TOOL = {
|
|
2323
|
+
name: "mindgraph_memory",
|
|
2324
|
+
description: "Read the portable MindGraph memory surface. Use action='context' with mode='resume' or 'continuity' for authoritative task-first work state, and mode='topic' with a short keyword query for prior knowledge relevant to the user's request. Use action='status' to inspect integration capabilities and limitations. This tool never writes; durable capture and correction use the existing typed MindGraph write tools.",
|
|
2325
|
+
inputSchema: {
|
|
2326
|
+
type: "object",
|
|
2327
|
+
properties: {
|
|
2328
|
+
action: {
|
|
2329
|
+
type: "string",
|
|
2330
|
+
enum: ["status", "context"],
|
|
2331
|
+
description: "Read integration status or bounded memory context"
|
|
2332
|
+
},
|
|
2333
|
+
mode: {
|
|
2334
|
+
type: "string",
|
|
2335
|
+
enum: ["topic", "continuity", "resume"],
|
|
2336
|
+
description: "Context strategy. topic uses query-shaped retrieval; continuity/resume use authoritative task-first resume_work."
|
|
2337
|
+
},
|
|
2338
|
+
query: {
|
|
2339
|
+
type: "string",
|
|
2340
|
+
description: "Required for mode='topic': 1-3 discriminating BM25 keywords, not a full sentence"
|
|
2341
|
+
},
|
|
2342
|
+
project_uid: { type: "string", description: "Optional project scope" },
|
|
2343
|
+
task_uid: { type: "string", description: "Optional task scope for resume context" },
|
|
2344
|
+
session_uid: { type: "string", description: "Optional durable session scope" },
|
|
2345
|
+
scope_uids: {
|
|
2346
|
+
type: "array",
|
|
2347
|
+
items: { type: "string" },
|
|
2348
|
+
description: "Optional explicit graph scopes for continuity/resume"
|
|
2349
|
+
},
|
|
2350
|
+
node_types: {
|
|
2351
|
+
type: "array",
|
|
2352
|
+
items: { type: "string" },
|
|
2353
|
+
description: "Optional node-type filter for topic context"
|
|
2354
|
+
},
|
|
2355
|
+
layer: {
|
|
2356
|
+
type: "string",
|
|
2357
|
+
enum: ["reality", "epistemic", "intent", "action", "memory", "agent"],
|
|
2358
|
+
description: "Optional cognitive-layer filter for topic context"
|
|
2359
|
+
},
|
|
2360
|
+
limit: {
|
|
2361
|
+
type: "integer",
|
|
2362
|
+
minimum: 1,
|
|
2363
|
+
maximum: 50,
|
|
2364
|
+
default: 8,
|
|
2365
|
+
description: "Maximum direct graph items requested before bounded expansion"
|
|
2366
|
+
},
|
|
2367
|
+
include_chunks: {
|
|
2368
|
+
type: "boolean",
|
|
2369
|
+
default: false,
|
|
2370
|
+
description: "Include bounded source excerpts when topic summaries are insufficient"
|
|
2371
|
+
},
|
|
2372
|
+
include_documents: {
|
|
2373
|
+
type: "boolean",
|
|
2374
|
+
default: false,
|
|
2375
|
+
description: "Include bounded knowledge articles for topic context"
|
|
2376
|
+
},
|
|
2377
|
+
valid_at: {
|
|
2378
|
+
type: "string",
|
|
2379
|
+
description: "Optional ISO timestamp for time-aware topic retrieval"
|
|
2380
|
+
},
|
|
2381
|
+
graph_expansion_limit: {
|
|
2382
|
+
type: "integer",
|
|
2383
|
+
minimum: 0,
|
|
2384
|
+
maximum: 20,
|
|
2385
|
+
default: 3,
|
|
2386
|
+
description: "Bounded graph neighbors added after direct topic matches"
|
|
2387
|
+
},
|
|
2388
|
+
graph_max_depth: {
|
|
2389
|
+
type: "integer",
|
|
2390
|
+
minimum: 0,
|
|
2391
|
+
maximum: 5,
|
|
2392
|
+
default: 2,
|
|
2393
|
+
description: "Maximum graph-expansion depth for topic context"
|
|
2394
|
+
},
|
|
2395
|
+
max_output_chars: {
|
|
2396
|
+
type: "integer",
|
|
2397
|
+
minimum: MIN_OUTPUT_CHARS,
|
|
2398
|
+
maximum: MAX_OUTPUT_CHARS,
|
|
2399
|
+
default: DEFAULT_OUTPUT_CHARS,
|
|
2400
|
+
description: "Hard character budget for model-ready context; whole items are retained or omitted"
|
|
2401
|
+
},
|
|
2402
|
+
agent_id: { type: "string", description: "Agent identity" }
|
|
2403
|
+
},
|
|
2404
|
+
required: ["action"]
|
|
2405
|
+
},
|
|
2406
|
+
outputSchema: {
|
|
2407
|
+
type: "object",
|
|
2408
|
+
properties: {
|
|
2409
|
+
schema_version: { type: "string", const: RESULT_SCHEMA_VERSION },
|
|
2410
|
+
action: { type: "string", enum: ["status", "context"] },
|
|
2411
|
+
profile: { type: "string" },
|
|
2412
|
+
server: { type: "object" },
|
|
2413
|
+
integration: { type: "object" },
|
|
2414
|
+
capabilities: { type: "object" },
|
|
2415
|
+
degradation: { type: "array", items: { type: "object" } },
|
|
2416
|
+
context_id: { type: "string" },
|
|
2417
|
+
mode: { type: "string", enum: ["topic", "continuity", "resume"] },
|
|
2418
|
+
scope: { type: "object" },
|
|
2419
|
+
rendered_context: { type: "string" },
|
|
2420
|
+
rendered_hash: { type: "string" },
|
|
2421
|
+
items: { type: "array", items: { type: "object" } },
|
|
2422
|
+
retrieval_trace: { type: "object" },
|
|
2423
|
+
budget: { type: "object" },
|
|
2424
|
+
freshness: { type: "object" },
|
|
2425
|
+
warnings: { type: "array", items: { type: "object" } }
|
|
2426
|
+
},
|
|
2427
|
+
required: ["schema_version", "action"],
|
|
2428
|
+
oneOf: [
|
|
2429
|
+
{
|
|
2430
|
+
properties: { action: { const: "status" } },
|
|
2431
|
+
required: ["profile", "server", "integration", "scope", "capabilities", "degradation"]
|
|
2432
|
+
},
|
|
2433
|
+
{
|
|
2434
|
+
properties: { action: { const: "context" } },
|
|
2435
|
+
required: [
|
|
2436
|
+
"context_id",
|
|
2437
|
+
"mode",
|
|
2438
|
+
"scope",
|
|
2439
|
+
"rendered_context",
|
|
2440
|
+
"rendered_hash",
|
|
2441
|
+
"items",
|
|
2442
|
+
"retrieval_trace",
|
|
2443
|
+
"budget",
|
|
2444
|
+
"freshness",
|
|
2445
|
+
"warnings"
|
|
2446
|
+
]
|
|
2447
|
+
}
|
|
2448
|
+
]
|
|
2449
|
+
},
|
|
2450
|
+
annotations: {
|
|
2451
|
+
readOnlyHint: true,
|
|
2452
|
+
destructiveHint: false,
|
|
2453
|
+
idempotentHint: true,
|
|
2454
|
+
openWorldHint: false
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
function obj2(value) {
|
|
2458
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2459
|
+
}
|
|
2460
|
+
function text(value) {
|
|
2461
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2462
|
+
}
|
|
2463
|
+
function stableJson(value) {
|
|
2464
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
2465
|
+
if (value && typeof value === "object") {
|
|
2466
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
2467
|
+
}
|
|
2468
|
+
return JSON.stringify(value);
|
|
2469
|
+
}
|
|
2470
|
+
function sha256(value) {
|
|
2471
|
+
return (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex");
|
|
2472
|
+
}
|
|
2473
|
+
function outputBudget(value) {
|
|
2474
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_OUTPUT_CHARS;
|
|
2475
|
+
return Math.min(MAX_OUTPUT_CHARS, Math.max(MIN_OUTPUT_CHARS, Math.floor(value)));
|
|
2476
|
+
}
|
|
2477
|
+
function defined(values) {
|
|
2478
|
+
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
|
|
2479
|
+
}
|
|
2480
|
+
function memoryStatus(config = {}) {
|
|
2481
|
+
return {
|
|
2482
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
2483
|
+
action: "status",
|
|
2484
|
+
profile: "M0",
|
|
2485
|
+
server: defined({
|
|
2486
|
+
name: "mindgraph-mcp",
|
|
2487
|
+
version: config.serverVersion ?? "unknown",
|
|
2488
|
+
base_url: config.baseUrl
|
|
2489
|
+
}),
|
|
2490
|
+
integration: {
|
|
2491
|
+
adapter_state: "model_controlled",
|
|
2492
|
+
harness: config.harness ?? "generic",
|
|
2493
|
+
configured_tool_profile: config.profile ?? "general",
|
|
2494
|
+
automatic_capture: false,
|
|
2495
|
+
automatic_delivery: false,
|
|
2496
|
+
delivery_verification: "unsupported",
|
|
2497
|
+
curator_mode: "disabled"
|
|
2498
|
+
},
|
|
2499
|
+
scope: defined({ org_id: config.orgId, agent_id: config.agentId }),
|
|
2500
|
+
capabilities: {
|
|
2501
|
+
status: true,
|
|
2502
|
+
topic_context: true,
|
|
2503
|
+
authoritative_resume_context: true,
|
|
2504
|
+
bounded_rendering: true,
|
|
2505
|
+
structured_content: true,
|
|
2506
|
+
typed_explicit_writes: true,
|
|
2507
|
+
lifecycle_event_ingest: false,
|
|
2508
|
+
automatic_context_injection: false,
|
|
2509
|
+
curator_mutation: false
|
|
2510
|
+
},
|
|
2511
|
+
degradation: [
|
|
2512
|
+
{
|
|
2513
|
+
code: "automatic_capture_unavailable",
|
|
2514
|
+
message: "M0 does not observe host lifecycle events; explicit typed write tools remain available."
|
|
2515
|
+
},
|
|
2516
|
+
{
|
|
2517
|
+
code: "delivery_unverified",
|
|
2518
|
+
message: "A successful MCP read does not prove that the host injected or used the returned context."
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
code: "curator_disabled",
|
|
2522
|
+
message: "Curator proposals and autonomous mutation are not enabled in M0."
|
|
2523
|
+
}
|
|
2524
|
+
]
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
function nodeType(node) {
|
|
2528
|
+
const raw = node.node_type;
|
|
2529
|
+
if (typeof raw === "string") return raw;
|
|
2530
|
+
return text(obj2(raw)?.Custom) ?? "Node";
|
|
2531
|
+
}
|
|
2532
|
+
function compactItem(raw, fallbackType) {
|
|
2533
|
+
const wrapper = obj2(raw);
|
|
2534
|
+
if (!wrapper) return void 0;
|
|
2535
|
+
const value = obj2(wrapper.node) ?? obj2(wrapper.object) ?? wrapper;
|
|
2536
|
+
const uid = text(value.uid) ?? text(value.chunk_uid);
|
|
2537
|
+
if (!uid) return void 0;
|
|
2538
|
+
return defined({
|
|
2539
|
+
uid,
|
|
2540
|
+
type: fallbackType ?? nodeType(value),
|
|
2541
|
+
label: text(value.label) ?? text(value.document_title),
|
|
2542
|
+
truth_status: text(value.truth_status) ?? text(obj2(value.props)?.truth_status),
|
|
2543
|
+
superseded: value.superseded === true ? true : void 0,
|
|
2544
|
+
currently_valid: value.currently_valid === false ? false : void 0,
|
|
2545
|
+
valid_at_time: value.valid_at_time === false ? false : void 0,
|
|
2546
|
+
retrieval_origin: text(value.retrieval_origin),
|
|
2547
|
+
retrieval_depth: typeof value.retrieval_depth === "number" ? value.retrieval_depth : void 0
|
|
2548
|
+
});
|
|
2549
|
+
}
|
|
2550
|
+
function topicCandidates(raw) {
|
|
2551
|
+
const payload = obj2(raw);
|
|
2552
|
+
if (!payload) return [];
|
|
2553
|
+
const graph = obj2(payload.graph);
|
|
2554
|
+
const items = [];
|
|
2555
|
+
for (const article of Array.isArray(payload.articles) ? payload.articles : []) {
|
|
2556
|
+
const item = compactItem(article, "Article");
|
|
2557
|
+
if (item) items.push(item);
|
|
2558
|
+
}
|
|
2559
|
+
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
2560
|
+
const labels = /* @__PURE__ */ new Map();
|
|
2561
|
+
for (const node of rawNodes) {
|
|
2562
|
+
const item = compactItem(node);
|
|
2563
|
+
if (item) {
|
|
2564
|
+
if (HIDDEN_CONTEXT_NODE_TYPES.has(text(item.type) ?? "")) continue;
|
|
2565
|
+
items.push(item);
|
|
2566
|
+
const uid = text(item.uid);
|
|
2567
|
+
const label = text(item.label);
|
|
2568
|
+
if (uid && label) labels.set(uid, label);
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
for (const rawEdge of Array.isArray(graph?.edges) ? graph.edges : []) {
|
|
2572
|
+
const edge = obj2(rawEdge);
|
|
2573
|
+
const fromUid = text(edge?.from_uid);
|
|
2574
|
+
const toUid = text(edge?.to_uid);
|
|
2575
|
+
const edgeType = text(edge?.edge_type) ?? text(obj2(edge?.edge_type)?.Custom);
|
|
2576
|
+
if (!fromUid || !toUid || !edgeType || HIDDEN_CONTEXT_EDGE_TYPES.has(edgeType) || !labels.has(fromUid) || !labels.has(toUid)) {
|
|
2577
|
+
continue;
|
|
2578
|
+
}
|
|
2579
|
+
items.push(
|
|
2580
|
+
defined({
|
|
2581
|
+
type: "Relationship",
|
|
2582
|
+
from_uid: fromUid,
|
|
2583
|
+
to_uid: toUid,
|
|
2584
|
+
edge_type: edgeType,
|
|
2585
|
+
from_label: labels.get(fromUid),
|
|
2586
|
+
to_label: labels.get(toUid)
|
|
2587
|
+
})
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
for (const chunk of Array.isArray(payload.chunks) ? payload.chunks : []) {
|
|
2591
|
+
const item = compactItem(chunk, "SourceExcerpt");
|
|
2592
|
+
if (item) items.push(item);
|
|
2593
|
+
}
|
|
2594
|
+
return items;
|
|
2595
|
+
}
|
|
2596
|
+
function resumeCandidates(raw) {
|
|
2597
|
+
const payload = obj2(raw);
|
|
2598
|
+
if (!payload) return [];
|
|
2599
|
+
const items = [];
|
|
2600
|
+
for (const key of ["task", "goal", "project", "plan", "active_execution", "lease"]) {
|
|
2601
|
+
const item = compactItem(payload[key], key);
|
|
2602
|
+
if (item) items.push(item);
|
|
2603
|
+
}
|
|
2604
|
+
for (const key of ["next_steps", "recent_executions", "blockers", "code_targets"]) {
|
|
2605
|
+
for (const value of Array.isArray(payload[key]) ? payload[key] : []) {
|
|
2606
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
2607
|
+
if (item) items.push(item);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
const knowledge = obj2(payload.knowledge);
|
|
2611
|
+
for (const key of ["lessons", "risks"]) {
|
|
2612
|
+
for (const value of Array.isArray(knowledge?.[key]) ? knowledge[key] : []) {
|
|
2613
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
2614
|
+
if (item) items.push(item);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
return items;
|
|
2618
|
+
}
|
|
2619
|
+
function visibleItems(candidates, rendered2) {
|
|
2620
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2621
|
+
return candidates.filter((item) => {
|
|
2622
|
+
const uid = text(item.uid);
|
|
2623
|
+
if (uid) {
|
|
2624
|
+
if (seen.has(uid) || !rendered2.includes(`[${uid}]`)) return false;
|
|
2625
|
+
seen.add(uid);
|
|
2626
|
+
return true;
|
|
2627
|
+
}
|
|
2628
|
+
if (item.type === "Relationship") {
|
|
2629
|
+
const from = text(item.from_label);
|
|
2630
|
+
const to = text(item.to_label);
|
|
2631
|
+
const edgeType = text(item.edge_type);
|
|
2632
|
+
if (!from || !to || !edgeType) return false;
|
|
2633
|
+
const key = `${text(item.from_uid)}:${edgeType}:${text(item.to_uid)}`;
|
|
2634
|
+
if (seen.has(key) || !rendered2.includes(`${from} \u2014${edgeType}\u2192 ${to}`)) return false;
|
|
2635
|
+
seen.add(key);
|
|
2636
|
+
return true;
|
|
2637
|
+
}
|
|
2638
|
+
return false;
|
|
2639
|
+
});
|
|
2640
|
+
}
|
|
2641
|
+
function latestTimestamp(value) {
|
|
2642
|
+
let latest;
|
|
2643
|
+
const visit = (current) => {
|
|
2644
|
+
if (Array.isArray(current)) {
|
|
2645
|
+
for (const item of current) visit(item);
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
const record = obj2(current);
|
|
2649
|
+
if (!record) return;
|
|
2650
|
+
for (const [key, item] of Object.entries(record)) {
|
|
2651
|
+
if (["updated_at", "created_at", "completed_at", "started_at", "observed_at"].includes(key) && typeof item === "string" && !Number.isNaN(Date.parse(item)) && (!latest || Date.parse(item) > Date.parse(latest))) {
|
|
2652
|
+
latest = item;
|
|
2653
|
+
}
|
|
2654
|
+
visit(item);
|
|
2655
|
+
}
|
|
2656
|
+
};
|
|
2657
|
+
visit(value);
|
|
2658
|
+
return latest;
|
|
2659
|
+
}
|
|
2660
|
+
function contextWarnings(raw, rendered2, available, returned) {
|
|
2661
|
+
const warnings = [
|
|
2662
|
+
{
|
|
2663
|
+
code: "delivery_unverified",
|
|
2664
|
+
message: "The MCP server returned this context but cannot verify that the host injected or used it."
|
|
2665
|
+
}
|
|
2666
|
+
];
|
|
2667
|
+
const serialized = JSON.stringify(raw);
|
|
2668
|
+
if (available > returned || rendered2.includes("item(s) omitted")) {
|
|
2669
|
+
warnings.push({
|
|
2670
|
+
code: "context_bounded",
|
|
2671
|
+
message: `${Math.max(0, available - returned)} structured item(s) were omitted from the rendered context.`
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
if (/"superseded":true/.test(serialized)) {
|
|
2675
|
+
warnings.push({ code: "superseded_items_present", message: "Some retrieved items are superseded." });
|
|
2676
|
+
}
|
|
2677
|
+
if (/"currently_valid":false|"valid_at_time":false/.test(serialized)) {
|
|
2678
|
+
warnings.push({
|
|
2679
|
+
code: "validity_warning",
|
|
2680
|
+
message: "Some retrieved items are outside their current or requested validity window."
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
const payload = obj2(raw);
|
|
2684
|
+
if (payload?.truncated === true || obj2(payload?.truncation)) {
|
|
2685
|
+
const truncation = obj2(payload?.truncation);
|
|
2686
|
+
if (payload?.truncated === true || Object.values(truncation ?? {}).some(Boolean)) {
|
|
2687
|
+
warnings.push({ code: "source_truncated", message: "The authoritative source reported truncated fields." });
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
if (text(payload?.warning)) {
|
|
2691
|
+
warnings.push({ code: "source_warning", message: text(payload?.warning) });
|
|
2692
|
+
}
|
|
2693
|
+
return warnings;
|
|
2694
|
+
}
|
|
2695
|
+
function error(message) {
|
|
2696
|
+
return {
|
|
2697
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
2698
|
+
isError: true
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2701
|
+
async function handleMemoryTool(client2, args, config = {}) {
|
|
2702
|
+
const action = text(args.action);
|
|
2703
|
+
if (action === "status") {
|
|
2704
|
+
const status = memoryStatus({ ...config, agentId: text(args.agent_id) ?? config.agentId });
|
|
2705
|
+
return {
|
|
2706
|
+
content: [{ type: "text", text: JSON.stringify(status) }],
|
|
2707
|
+
structuredContent: status
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
if (action !== "context") {
|
|
2711
|
+
return error("action must be 'status' or 'context'");
|
|
2712
|
+
}
|
|
2713
|
+
const mode = text(args.mode) ?? (text(args.query) ? "topic" : void 0);
|
|
2714
|
+
if (!mode || !["topic", "continuity", "resume"].includes(mode)) {
|
|
2715
|
+
return error("action='context' requires mode='topic', 'continuity', or 'resume'");
|
|
2716
|
+
}
|
|
2717
|
+
const budget = outputBudget(args.max_output_chars);
|
|
2718
|
+
const agentId = text(args.agent_id) ?? config.agentId;
|
|
2719
|
+
let raw;
|
|
2720
|
+
let rendered2;
|
|
2721
|
+
let strategy;
|
|
2722
|
+
let candidates;
|
|
2723
|
+
if (mode === "topic") {
|
|
2724
|
+
const query = text(args.query);
|
|
2725
|
+
if (!query) return error("mode='topic' requires a non-empty query of 1-3 discriminating keywords");
|
|
2726
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.min(50, Math.max(1, Math.floor(args.limit))) : 8;
|
|
2727
|
+
const request = defined({
|
|
2728
|
+
query,
|
|
2729
|
+
project_uid: text(args.project_uid),
|
|
2730
|
+
node_limit: limit,
|
|
2731
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2732
|
+
layer: text(args.layer),
|
|
2733
|
+
chunk_limit: args.include_chunks === true ? limit : 0,
|
|
2734
|
+
article_limit: args.include_documents === true ? limit : 0,
|
|
2735
|
+
valid_at: text(args.valid_at),
|
|
2736
|
+
include_graph: true,
|
|
2737
|
+
graph_expansion_limit: typeof args.graph_expansion_limit === "number" ? args.graph_expansion_limit : 3,
|
|
2738
|
+
graph_max_depth: typeof args.graph_max_depth === "number" ? args.graph_max_depth : 2
|
|
2739
|
+
});
|
|
2740
|
+
raw = await client2.retrieveContext(request);
|
|
2741
|
+
rendered2 = renderContext(raw, budget) ?? "No results found for this search.";
|
|
2742
|
+
strategy = "retrieve_context";
|
|
2743
|
+
candidates = topicCandidates(raw);
|
|
2744
|
+
} else {
|
|
2745
|
+
const scopeUids = Array.from(
|
|
2746
|
+
/* @__PURE__ */ new Set([
|
|
2747
|
+
...Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : [],
|
|
2748
|
+
...text(args.project_uid) ? [text(args.project_uid)] : []
|
|
2749
|
+
])
|
|
2750
|
+
);
|
|
2751
|
+
raw = await client2.plan(
|
|
2752
|
+
defined({
|
|
2753
|
+
action: "resume_work",
|
|
2754
|
+
task_uid: text(args.task_uid),
|
|
2755
|
+
session_uid: text(args.session_uid),
|
|
2756
|
+
scope_uids: scopeUids.length > 0 ? scopeUids : void 0,
|
|
2757
|
+
limit: 1,
|
|
2758
|
+
agent_id: agentId
|
|
2759
|
+
})
|
|
2760
|
+
);
|
|
2761
|
+
rendered2 = renderResumeContext(raw, budget) ?? "No eligible work was found in the requested scope.";
|
|
2762
|
+
strategy = "resume_work";
|
|
2763
|
+
candidates = resumeCandidates(raw);
|
|
2764
|
+
}
|
|
2765
|
+
const items = visibleItems(candidates, rendered2);
|
|
2766
|
+
const renderedHash = sha256(rendered2);
|
|
2767
|
+
const scope = defined({
|
|
2768
|
+
org_id: config.orgId,
|
|
2769
|
+
agent_id: agentId,
|
|
2770
|
+
harness: config.harness ?? "generic",
|
|
2771
|
+
project_uid: text(args.project_uid),
|
|
2772
|
+
task_uid: text(args.task_uid),
|
|
2773
|
+
session_uid: text(args.session_uid),
|
|
2774
|
+
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0
|
|
2775
|
+
});
|
|
2776
|
+
const contextId = `ctx_${sha256(
|
|
2777
|
+
stableJson({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
2778
|
+
).slice(0, 24)}`;
|
|
2779
|
+
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
2780
|
+
const result = {
|
|
2781
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
2782
|
+
action: "context",
|
|
2783
|
+
context_id: contextId,
|
|
2784
|
+
mode,
|
|
2785
|
+
scope,
|
|
2786
|
+
rendered_context: rendered2,
|
|
2787
|
+
rendered_hash: renderedHash,
|
|
2788
|
+
items,
|
|
2789
|
+
retrieval_trace: defined({
|
|
2790
|
+
strategy,
|
|
2791
|
+
query: text(args.query),
|
|
2792
|
+
project_uid: text(args.project_uid),
|
|
2793
|
+
task_uid: text(args.task_uid),
|
|
2794
|
+
session_uid: text(args.session_uid),
|
|
2795
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2796
|
+
graph_expansion_limit: mode === "topic" ? args.graph_expansion_limit ?? 3 : void 0,
|
|
2797
|
+
graph_max_depth: mode === "topic" ? args.graph_max_depth ?? 2 : void 0,
|
|
2798
|
+
available_items: candidates.length,
|
|
2799
|
+
returned_items: items.length,
|
|
2800
|
+
omitted_items: Math.max(0, candidates.length - items.length)
|
|
2801
|
+
}),
|
|
2802
|
+
budget: {
|
|
2803
|
+
unit: "characters",
|
|
2804
|
+
requested_chars: budget,
|
|
2805
|
+
used_chars: rendered2.length,
|
|
2806
|
+
available_items: candidates.length,
|
|
2807
|
+
returned_items: items.length,
|
|
2808
|
+
omitted_items: Math.max(0, candidates.length - items.length),
|
|
2809
|
+
bounded
|
|
2810
|
+
},
|
|
2811
|
+
freshness: defined({
|
|
2812
|
+
valid_at: text(args.valid_at),
|
|
2813
|
+
latest_source_timestamp: latestTimestamp(raw)
|
|
2814
|
+
}),
|
|
2815
|
+
warnings: contextWarnings(raw, rendered2, candidates.length, items.length)
|
|
2816
|
+
};
|
|
2817
|
+
return {
|
|
2818
|
+
content: [{ type: "text", text: rendered2 }],
|
|
2819
|
+
structuredContent: result
|
|
2820
|
+
};
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2109
2823
|
// src/tools.ts
|
|
2824
|
+
var RESOLUTION_PROPERTIES = {
|
|
2825
|
+
idempotency_key: {
|
|
2826
|
+
type: "string",
|
|
2827
|
+
description: "Stable retry key; a mismatched replay is rejected"
|
|
2828
|
+
},
|
|
2829
|
+
reuse_uid: {
|
|
2830
|
+
type: "string",
|
|
2831
|
+
description: "Reuse this live same-scope node after a duplicate response"
|
|
2832
|
+
},
|
|
2833
|
+
supersedes_uid: {
|
|
2834
|
+
type: "string",
|
|
2835
|
+
description: "Create and mark this same-scope node as superseded"
|
|
2836
|
+
},
|
|
2837
|
+
contradicts_uid: {
|
|
2838
|
+
type: "string",
|
|
2839
|
+
description: "Create and mark this same-scope node as contradicted"
|
|
2840
|
+
},
|
|
2841
|
+
confirm_new: {
|
|
2842
|
+
type: "boolean",
|
|
2843
|
+
description: "Confirm that the new fact is genuinely distinct"
|
|
2844
|
+
},
|
|
2845
|
+
on_near_duplicate: {
|
|
2846
|
+
type: "string",
|
|
2847
|
+
enum: ["create"],
|
|
2848
|
+
description: "Alias for confirm_new on a near-duplicate response"
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
function stableJson2(value) {
|
|
2852
|
+
if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
|
|
2853
|
+
if (value && typeof value === "object") {
|
|
2854
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson2(item)}`).join(",")}}`;
|
|
2855
|
+
}
|
|
2856
|
+
return JSON.stringify(value);
|
|
2857
|
+
}
|
|
2858
|
+
function defaultWriteIdempotencyKey(tool, args) {
|
|
2859
|
+
if (typeof args.idempotency_key === "string") return args.idempotency_key;
|
|
2860
|
+
const context = args.invocation_context;
|
|
2861
|
+
const sessionId = context?.harnessSessionId;
|
|
2862
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) return void 0;
|
|
2863
|
+
const canonicalArgs = Object.fromEntries(
|
|
2864
|
+
Object.entries(args).filter(
|
|
2865
|
+
([key]) => key !== "invocation_context" && key !== "idempotency_key"
|
|
2866
|
+
)
|
|
2867
|
+
);
|
|
2868
|
+
return (0, import_node_crypto5.createHash)("sha256").update(
|
|
2869
|
+
stableJson2({
|
|
2870
|
+
harness_session_id: sessionId,
|
|
2871
|
+
harness_turn_id: context?.harnessTurnId ?? null,
|
|
2872
|
+
tool,
|
|
2873
|
+
action: args.action ?? null,
|
|
2874
|
+
args: canonicalArgs
|
|
2875
|
+
})
|
|
2876
|
+
).digest("hex");
|
|
2877
|
+
}
|
|
2878
|
+
function resolutionFields(args) {
|
|
2879
|
+
return Object.fromEntries(
|
|
2880
|
+
[
|
|
2881
|
+
"idempotency_key",
|
|
2882
|
+
"reuse_uid",
|
|
2883
|
+
"supersedes_uid",
|
|
2884
|
+
"contradicts_uid",
|
|
2885
|
+
"confirm_new",
|
|
2886
|
+
"on_near_duplicate"
|
|
2887
|
+
].filter((key) => args[key] !== void 0).map((key) => [key, args[key]])
|
|
2888
|
+
);
|
|
2889
|
+
}
|
|
2110
2890
|
var TOOLS = [
|
|
2111
2891
|
{
|
|
2112
2892
|
name: "mindgraph_capture",
|
|
@@ -2171,14 +2951,7 @@ var TOOLS = [
|
|
|
2171
2951
|
type: "string",
|
|
2172
2952
|
description: "Material Execution that produced the lesson"
|
|
2173
2953
|
},
|
|
2174
|
-
|
|
2175
|
-
type: "string",
|
|
2176
|
-
description: "Stable retry key for an intentional capture"
|
|
2177
|
-
},
|
|
2178
|
-
supersedes_uid: {
|
|
2179
|
-
type: "string",
|
|
2180
|
-
description: "Earlier capture corrected or superseded by this one"
|
|
2181
|
-
},
|
|
2954
|
+
...RESOLUTION_PROPERTIES,
|
|
2182
2955
|
summarizes_uids: {
|
|
2183
2956
|
type: "array",
|
|
2184
2957
|
items: { type: "string" },
|
|
@@ -2276,6 +3049,7 @@ var TOOLS = [
|
|
|
2276
3049
|
inputSchema: {
|
|
2277
3050
|
type: "object",
|
|
2278
3051
|
properties: {
|
|
3052
|
+
...RESOLUTION_PROPERTIES,
|
|
2279
3053
|
action: {
|
|
2280
3054
|
type: "string",
|
|
2281
3055
|
enum: [
|
|
@@ -2370,6 +3144,7 @@ var TOOLS = [
|
|
|
2370
3144
|
inputSchema: {
|
|
2371
3145
|
type: "object",
|
|
2372
3146
|
properties: {
|
|
3147
|
+
...RESOLUTION_PROPERTIES,
|
|
2373
3148
|
action: {
|
|
2374
3149
|
type: "string",
|
|
2375
3150
|
enum: [
|
|
@@ -2728,6 +3503,12 @@ var TOOLS = [
|
|
|
2728
3503
|
enum: ["text", "json"],
|
|
2729
3504
|
description: "Output format (default 'text'): a compact rendered context block \u2014 labels, uids, summaries, status tags, relationships. Pass 'json' for the raw server response (full props, source-chunk offsets, retrieval metadata)."
|
|
2730
3505
|
},
|
|
3506
|
+
max_output_chars: {
|
|
3507
|
+
type: "integer",
|
|
3508
|
+
minimum: 512,
|
|
3509
|
+
maximum: 24e3,
|
|
3510
|
+
description: "Hard character budget for rendered text output (512-24000; default 24000). Normal per-field clipping still applies. Whole evidence items are then kept or omitted rather than cut to satisfy this budget; the final marker reports omissions. Ignored when format='json'."
|
|
3511
|
+
},
|
|
2731
3512
|
query: {
|
|
2732
3513
|
type: "string",
|
|
2733
3514
|
description: "Search query \u2014 for 'text'/'context': 1-3 BM25 keywords, drop filler words. For 'semantic'/'hybrid': natural language is OK since it uses vector similarity."
|
|
@@ -3154,6 +3935,67 @@ var TOOLS = [
|
|
|
3154
3935
|
required: ["action"]
|
|
3155
3936
|
}
|
|
3156
3937
|
},
|
|
3938
|
+
{
|
|
3939
|
+
name: "mindgraph_remember",
|
|
3940
|
+
description: "Small-text memory fast path. 'remember' stores one fact, preference, decision or note synchronously; it is BM25- and vector-searchable the moment the call returns (the response says which). Pass a stable custom_id (e.g. 'pref:theme', 'deploy:target') so re-sending the same key UPDATES the same memory instead of creating a duplicate \u2014 that is the idempotency contract; without custom_id an exact duplicate is reused. 'forget' reversibly removes a memory by uid or custom_id (tombstone plus connected edges): call it with dry_run=true first to see the edge uids it would remove, then without. Undo with mindgraph_capture-independent server actions /evolve restore and restore_edge. Use mindgraph_capture for typed entities, sources and skills, and mindgraph_ingest for documents longer than a few paragraphs.",
|
|
3941
|
+
inputSchema: {
|
|
3942
|
+
type: "object",
|
|
3943
|
+
properties: {
|
|
3944
|
+
action: {
|
|
3945
|
+
type: "string",
|
|
3946
|
+
enum: ["remember", "forget"],
|
|
3947
|
+
description: "remember = store/upsert one small text; forget = reversible removal"
|
|
3948
|
+
},
|
|
3949
|
+
text: {
|
|
3950
|
+
type: "string",
|
|
3951
|
+
description: "remember: the memory text (\u2264 8 KiB). Use mindgraph_ingest for longer content."
|
|
3952
|
+
},
|
|
3953
|
+
custom_id: {
|
|
3954
|
+
type: "string",
|
|
3955
|
+
description: "Caller-owned key. remember: re-sending it edits the same memory (version bump, history kept). forget: the memory to remove."
|
|
3956
|
+
},
|
|
3957
|
+
label: {
|
|
3958
|
+
type: "string",
|
|
3959
|
+
description: "remember: optional short title; defaults to the first line of text"
|
|
3960
|
+
},
|
|
3961
|
+
uid: {
|
|
3962
|
+
type: "string",
|
|
3963
|
+
description: "forget: node uid to remove (alternative to custom_id)"
|
|
3964
|
+
},
|
|
3965
|
+
dry_run: {
|
|
3966
|
+
type: "boolean",
|
|
3967
|
+
description: "forget: preview the affected edge uids without changing anything"
|
|
3968
|
+
},
|
|
3969
|
+
cascade: {
|
|
3970
|
+
type: "boolean",
|
|
3971
|
+
description: "forget: also tombstone connected edges (default true)"
|
|
3972
|
+
},
|
|
3973
|
+
reason: {
|
|
3974
|
+
type: "string",
|
|
3975
|
+
description: "forget: why (recorded on the tombstone)"
|
|
3976
|
+
},
|
|
3977
|
+
space_uid: {
|
|
3978
|
+
type: "string",
|
|
3979
|
+
description: "remember: explicit target Space (default: the org space)"
|
|
3980
|
+
},
|
|
3981
|
+
on_near_duplicate: {
|
|
3982
|
+
type: "string",
|
|
3983
|
+
enum: ["reuse", "create"],
|
|
3984
|
+
description: "remember without custom_id: on an exact duplicate, reuse the existing memory (default) or create anyway"
|
|
3985
|
+
},
|
|
3986
|
+
props: {
|
|
3987
|
+
type: "object",
|
|
3988
|
+
description: "remember: extra Observation props"
|
|
3989
|
+
},
|
|
3990
|
+
agent_id: {
|
|
3991
|
+
type: "string",
|
|
3992
|
+
description: "Agent identifier (default: configured agent)"
|
|
3993
|
+
}
|
|
3994
|
+
},
|
|
3995
|
+
required: ["action"]
|
|
3996
|
+
}
|
|
3997
|
+
},
|
|
3998
|
+
MEMORY_TOOL,
|
|
3157
3999
|
SYNC_TOOL,
|
|
3158
4000
|
CODE_TOOL
|
|
3159
4001
|
];
|
|
@@ -3174,7 +4016,7 @@ var INVOCATION_CONTEXT_SCHEMA = {
|
|
|
3174
4016
|
}
|
|
3175
4017
|
};
|
|
3176
4018
|
for (const tool of TOOLS) {
|
|
3177
|
-
if (tool.name === "mindgraph_retrieve") continue;
|
|
4019
|
+
if (tool.name === "mindgraph_retrieve" || tool.name === "mindgraph_memory") continue;
|
|
3178
4020
|
const schema = tool.inputSchema;
|
|
3179
4021
|
if (schema.properties && !schema.properties.invocation_context) {
|
|
3180
4022
|
schema.properties.invocation_context = INVOCATION_CONTEXT_SCHEMA;
|
|
@@ -3193,8 +4035,8 @@ function ok3(data) {
|
|
|
3193
4035
|
}
|
|
3194
4036
|
function renderedResult(format, raw, render) {
|
|
3195
4037
|
if (format === "json") return ok3(raw);
|
|
3196
|
-
const
|
|
3197
|
-
return
|
|
4038
|
+
const text2 = render(raw);
|
|
4039
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok3(raw);
|
|
3198
4040
|
}
|
|
3199
4041
|
function err3(message) {
|
|
3200
4042
|
return {
|
|
@@ -3202,8 +4044,22 @@ function err3(message) {
|
|
|
3202
4044
|
isError: true
|
|
3203
4045
|
};
|
|
3204
4046
|
}
|
|
3205
|
-
async function handleTool(client2, name, args) {
|
|
4047
|
+
async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
3206
4048
|
try {
|
|
4049
|
+
if (["mindgraph_capture", "mindgraph_reason", "mindgraph_commit"].includes(name) && args.action !== "get_open_decisions") {
|
|
4050
|
+
const key = defaultWriteIdempotencyKey(name, args);
|
|
4051
|
+
if (key) args = { ...args, idempotency_key: key };
|
|
4052
|
+
const dispositions = [
|
|
4053
|
+
args.reuse_uid,
|
|
4054
|
+
args.supersedes_uid,
|
|
4055
|
+
args.contradicts_uid,
|
|
4056
|
+
args.confirm_new === true ? true : void 0,
|
|
4057
|
+
args.on_near_duplicate
|
|
4058
|
+
].filter((value) => value !== void 0);
|
|
4059
|
+
if (dispositions.length > 1) {
|
|
4060
|
+
return err3("resolution dispositions are mutually exclusive");
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
3207
4063
|
let result;
|
|
3208
4064
|
switch (name) {
|
|
3209
4065
|
case "mindgraph_capture":
|
|
@@ -3221,6 +4077,12 @@ async function handleTool(client2, name, args) {
|
|
|
3221
4077
|
case "mindgraph_retrieve":
|
|
3222
4078
|
result = await handleRetrieve(client2, args);
|
|
3223
4079
|
break;
|
|
4080
|
+
case "mindgraph_memory":
|
|
4081
|
+
result = await handleMemoryTool(client2, args, memoryConfig);
|
|
4082
|
+
break;
|
|
4083
|
+
case "mindgraph_remember":
|
|
4084
|
+
result = await handleRemember(client2, args);
|
|
4085
|
+
break;
|
|
3224
4086
|
case "mindgraph_series_query":
|
|
3225
4087
|
result = await handleSeriesQuery(client2, args);
|
|
3226
4088
|
break;
|
|
@@ -3253,19 +4115,7 @@ async function handleTool(client2, name, args) {
|
|
|
3253
4115
|
].includes(action);
|
|
3254
4116
|
return attach ? await attachCodeRefsToToolResult(client2, result, args) : result;
|
|
3255
4117
|
} catch (e) {
|
|
3256
|
-
|
|
3257
|
-
if (Object.keys(lifted).length > 0) {
|
|
3258
|
-
return {
|
|
3259
|
-
content: [
|
|
3260
|
-
{
|
|
3261
|
-
type: "text",
|
|
3262
|
-
text: JSON.stringify({ error: errorDetail(e), ...lifted })
|
|
3263
|
-
}
|
|
3264
|
-
],
|
|
3265
|
-
isError: true
|
|
3266
|
-
};
|
|
3267
|
-
}
|
|
3268
|
-
return err3(errorDetail(e));
|
|
4118
|
+
return toolError(e);
|
|
3269
4119
|
}
|
|
3270
4120
|
}
|
|
3271
4121
|
async function handleSeriesQuery(client2, args) {
|
|
@@ -3289,6 +4139,56 @@ async function handleSeriesQuery(client2, args) {
|
|
|
3289
4139
|
await client2.series(args)
|
|
3290
4140
|
);
|
|
3291
4141
|
}
|
|
4142
|
+
async function handleRemember(client2, args) {
|
|
4143
|
+
const {
|
|
4144
|
+
action,
|
|
4145
|
+
text: text2,
|
|
4146
|
+
custom_id,
|
|
4147
|
+
label,
|
|
4148
|
+
uid,
|
|
4149
|
+
dry_run,
|
|
4150
|
+
cascade,
|
|
4151
|
+
reason,
|
|
4152
|
+
space_uid,
|
|
4153
|
+
on_near_duplicate,
|
|
4154
|
+
props,
|
|
4155
|
+
agent_id,
|
|
4156
|
+
// Adapter-owned; consumed locally, never sent to the API.
|
|
4157
|
+
invocation_context: _invocationContext,
|
|
4158
|
+
...rest
|
|
4159
|
+
} = args;
|
|
4160
|
+
void _invocationContext;
|
|
4161
|
+
void rest;
|
|
4162
|
+
switch (action) {
|
|
4163
|
+
case "remember": {
|
|
4164
|
+
if (typeof text2 !== "string" || !text2.trim()) {
|
|
4165
|
+
return err3("remember requires non-empty text");
|
|
4166
|
+
}
|
|
4167
|
+
const options = {};
|
|
4168
|
+
if (typeof custom_id === "string" && custom_id.trim()) options.custom_id = custom_id.trim();
|
|
4169
|
+
if (typeof label === "string" && label.trim()) options.label = label;
|
|
4170
|
+
if (typeof space_uid === "string" && space_uid.trim()) options.space_uid = space_uid;
|
|
4171
|
+
if (on_near_duplicate === "reuse" || on_near_duplicate === "create") {
|
|
4172
|
+
options.on_near_duplicate = on_near_duplicate;
|
|
4173
|
+
}
|
|
4174
|
+
if (props && typeof props === "object") options.props = props;
|
|
4175
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4176
|
+
return ok3(await client2.remember(text2, options));
|
|
4177
|
+
}
|
|
4178
|
+
case "forget": {
|
|
4179
|
+
const target = typeof uid === "string" && uid.trim() ? { uid: uid.trim() } : typeof custom_id === "string" && custom_id.trim() ? { custom_id: custom_id.trim() } : null;
|
|
4180
|
+
if (!target) return err3("forget requires uid or custom_id");
|
|
4181
|
+
const options = {};
|
|
4182
|
+
if (dry_run === true) options.dry_run = true;
|
|
4183
|
+
if (typeof cascade === "boolean") options.cascade = cascade;
|
|
4184
|
+
if (typeof reason === "string" && reason.trim()) options.reason = reason;
|
|
4185
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4186
|
+
return ok3(await client2.forget(target, options));
|
|
4187
|
+
}
|
|
4188
|
+
default:
|
|
4189
|
+
return err3(`Unknown remember action: ${String(action)}`);
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
3292
4192
|
async function handleCapture(client2, args) {
|
|
3293
4193
|
const {
|
|
3294
4194
|
action,
|
|
@@ -3302,7 +4202,11 @@ async function handleCapture(client2, args) {
|
|
|
3302
4202
|
work_uid,
|
|
3303
4203
|
execution_uid,
|
|
3304
4204
|
idempotency_key,
|
|
4205
|
+
reuse_uid,
|
|
3305
4206
|
supersedes_uid,
|
|
4207
|
+
contradicts_uid,
|
|
4208
|
+
confirm_new,
|
|
4209
|
+
on_near_duplicate,
|
|
3306
4210
|
summarizes_uids,
|
|
3307
4211
|
entity_type,
|
|
3308
4212
|
source_uid,
|
|
@@ -3326,7 +4230,11 @@ async function handleCapture(client2, args) {
|
|
|
3326
4230
|
work_uid,
|
|
3327
4231
|
execution_uid,
|
|
3328
4232
|
idempotency_key,
|
|
4233
|
+
reuse_uid,
|
|
3329
4234
|
supersedes_uid,
|
|
4235
|
+
contradicts_uid,
|
|
4236
|
+
confirm_new,
|
|
4237
|
+
on_near_duplicate,
|
|
3330
4238
|
summarizes_uids,
|
|
3331
4239
|
props,
|
|
3332
4240
|
agent_id
|
|
@@ -3372,27 +4280,32 @@ async function handleCapture(client2, args) {
|
|
|
3372
4280
|
const journalProps = { content };
|
|
3373
4281
|
if (mood) journalProps.mood = mood;
|
|
3374
4282
|
if (tags) journalProps.tags = tags;
|
|
3375
|
-
return ok3(await client2.journal(label, journalProps, {
|
|
4283
|
+
return ok3(await client2.journal(label, journalProps, {
|
|
4284
|
+
agent_id,
|
|
4285
|
+
idempotency_key,
|
|
4286
|
+
reuse_uid,
|
|
4287
|
+
supersedes_uid,
|
|
4288
|
+
contradicts_uid,
|
|
4289
|
+
confirm_new,
|
|
4290
|
+
on_near_duplicate
|
|
4291
|
+
}));
|
|
3376
4292
|
}
|
|
3377
4293
|
case "entity": {
|
|
3378
4294
|
const type = entity_type || "concept";
|
|
3379
4295
|
const entityProps = { ...props };
|
|
3380
4296
|
if (summary) entityProps.description = summary;
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
default:
|
|
3394
|
-
return ok3(await client2.findOrCreateConcept(label, entityProps, agent_id));
|
|
3395
|
-
}
|
|
4297
|
+
return ok3(await client2.entity({
|
|
4298
|
+
action: "create",
|
|
4299
|
+
label,
|
|
4300
|
+
props: { ...entityProps, entity_type: type },
|
|
4301
|
+
agent_id,
|
|
4302
|
+
idempotency_key,
|
|
4303
|
+
reuse_uid,
|
|
4304
|
+
supersedes_uid,
|
|
4305
|
+
contradicts_uid,
|
|
4306
|
+
confirm_new,
|
|
4307
|
+
on_near_duplicate
|
|
4308
|
+
}));
|
|
3396
4309
|
}
|
|
3397
4310
|
case "observation":
|
|
3398
4311
|
return ok3(
|
|
@@ -3403,7 +4316,13 @@ async function handleCapture(client2, args) {
|
|
|
3403
4316
|
confidence,
|
|
3404
4317
|
salience,
|
|
3405
4318
|
props,
|
|
3406
|
-
agent_id
|
|
4319
|
+
agent_id,
|
|
4320
|
+
idempotency_key,
|
|
4321
|
+
reuse_uid,
|
|
4322
|
+
supersedes_uid,
|
|
4323
|
+
contradicts_uid,
|
|
4324
|
+
confirm_new,
|
|
4325
|
+
on_near_duplicate
|
|
3407
4326
|
})
|
|
3408
4327
|
);
|
|
3409
4328
|
case "source":
|
|
@@ -3415,7 +4334,13 @@ async function handleCapture(client2, args) {
|
|
|
3415
4334
|
confidence,
|
|
3416
4335
|
salience,
|
|
3417
4336
|
props,
|
|
3418
|
-
agent_id
|
|
4337
|
+
agent_id,
|
|
4338
|
+
idempotency_key,
|
|
4339
|
+
reuse_uid,
|
|
4340
|
+
supersedes_uid,
|
|
4341
|
+
contradicts_uid,
|
|
4342
|
+
confirm_new,
|
|
4343
|
+
on_near_duplicate
|
|
3419
4344
|
})
|
|
3420
4345
|
);
|
|
3421
4346
|
case "snippet":
|
|
@@ -3428,26 +4353,38 @@ async function handleCapture(client2, args) {
|
|
|
3428
4353
|
confidence,
|
|
3429
4354
|
salience,
|
|
3430
4355
|
props,
|
|
3431
|
-
agent_id
|
|
4356
|
+
agent_id,
|
|
4357
|
+
idempotency_key,
|
|
4358
|
+
reuse_uid,
|
|
4359
|
+
supersedes_uid,
|
|
4360
|
+
contradicts_uid,
|
|
4361
|
+
confirm_new,
|
|
4362
|
+
on_near_duplicate
|
|
3432
4363
|
})
|
|
3433
4364
|
);
|
|
3434
4365
|
case "concept":
|
|
3435
|
-
return ok3(
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
4366
|
+
return ok3(await client2.entity({
|
|
4367
|
+
action: "create",
|
|
4368
|
+
label,
|
|
4369
|
+
props: {
|
|
4370
|
+
...props,
|
|
4371
|
+
entity_type: "concept",
|
|
4372
|
+
...summary ? { description: summary } : {}
|
|
4373
|
+
},
|
|
4374
|
+
agent_id,
|
|
4375
|
+
idempotency_key,
|
|
4376
|
+
reuse_uid,
|
|
4377
|
+
supersedes_uid,
|
|
4378
|
+
contradicts_uid,
|
|
4379
|
+
confirm_new,
|
|
4380
|
+
on_near_duplicate
|
|
4381
|
+
}));
|
|
3446
4382
|
default:
|
|
3447
4383
|
return err3(`Unknown capture action: ${action}`);
|
|
3448
4384
|
}
|
|
3449
4385
|
}
|
|
3450
4386
|
async function handleReason(client2, args) {
|
|
4387
|
+
const resolution = resolutionFields(args);
|
|
3451
4388
|
const {
|
|
3452
4389
|
action,
|
|
3453
4390
|
label,
|
|
@@ -3480,7 +4417,8 @@ async function handleReason(client2, args) {
|
|
|
3480
4417
|
...warrant.content ? { props: { content: warrant.content } } : {}
|
|
3481
4418
|
} : void 0,
|
|
3482
4419
|
argument,
|
|
3483
|
-
agent_id
|
|
4420
|
+
agent_id,
|
|
4421
|
+
...resolution
|
|
3484
4422
|
})
|
|
3485
4423
|
);
|
|
3486
4424
|
}
|
|
@@ -3493,11 +4431,13 @@ async function handleReason(client2, args) {
|
|
|
3493
4431
|
confidence,
|
|
3494
4432
|
salience,
|
|
3495
4433
|
props,
|
|
3496
|
-
agent_id
|
|
4434
|
+
agent_id,
|
|
4435
|
+
...resolution
|
|
3497
4436
|
})
|
|
3498
4437
|
);
|
|
3499
4438
|
}
|
|
3500
4439
|
async function handleCommit(client2, args) {
|
|
4440
|
+
const resolution = resolutionFields(args);
|
|
3501
4441
|
const {
|
|
3502
4442
|
action,
|
|
3503
4443
|
label,
|
|
@@ -3528,16 +4468,17 @@ async function handleCommit(client2, args) {
|
|
|
3528
4468
|
confidence,
|
|
3529
4469
|
salience,
|
|
3530
4470
|
props,
|
|
3531
|
-
agent_id
|
|
4471
|
+
agent_id,
|
|
4472
|
+
...resolution
|
|
3532
4473
|
})
|
|
3533
4474
|
);
|
|
3534
4475
|
case "open_decision":
|
|
3535
4476
|
if (!label) return err3("label is required for open_decision");
|
|
3536
|
-
return ok3(await client2.openDecision(label, { summary, props, agent_id }));
|
|
4477
|
+
return ok3(await client2.openDecision(label, { summary, props, agent_id, ...resolution }));
|
|
3537
4478
|
case "add_option":
|
|
3538
4479
|
if (!decision_uid) return err3("decision_uid is required for add_option");
|
|
3539
4480
|
if (!label) return err3("label is required for add_option");
|
|
3540
|
-
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id }));
|
|
4481
|
+
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id, ...resolution }));
|
|
3541
4482
|
case "add_constraint":
|
|
3542
4483
|
if (!decision_uid) return err3("decision_uid is required for add_constraint");
|
|
3543
4484
|
return ok3(
|
|
@@ -3547,7 +4488,8 @@ async function handleCommit(client2, args) {
|
|
|
3547
4488
|
decision_uid,
|
|
3548
4489
|
summary,
|
|
3549
4490
|
props,
|
|
3550
|
-
agent_id
|
|
4491
|
+
agent_id,
|
|
4492
|
+
...resolution
|
|
3551
4493
|
})
|
|
3552
4494
|
);
|
|
3553
4495
|
case "resolve_decision":
|
|
@@ -3561,7 +4503,8 @@ async function handleCommit(client2, args) {
|
|
|
3561
4503
|
as_of_date,
|
|
3562
4504
|
session_id,
|
|
3563
4505
|
retrieval_trace_id,
|
|
3564
|
-
agent_id
|
|
4506
|
+
agent_id,
|
|
4507
|
+
...resolution
|
|
3565
4508
|
})
|
|
3566
4509
|
);
|
|
3567
4510
|
case "get_open_decisions":
|
|
@@ -3642,7 +4585,7 @@ async function handlePlan(client2, args) {
|
|
|
3642
4585
|
output_snapshot,
|
|
3643
4586
|
side_effects,
|
|
3644
4587
|
outcome,
|
|
3645
|
-
error,
|
|
4588
|
+
error: error2,
|
|
3646
4589
|
next_action,
|
|
3647
4590
|
checkpoint_summary,
|
|
3648
4591
|
test_summary,
|
|
@@ -3705,7 +4648,7 @@ async function handlePlan(client2, args) {
|
|
|
3705
4648
|
output_snapshot,
|
|
3706
4649
|
side_effects,
|
|
3707
4650
|
outcome,
|
|
3708
|
-
error,
|
|
4651
|
+
error: error2,
|
|
3709
4652
|
next_action,
|
|
3710
4653
|
checkpoint_summary,
|
|
3711
4654
|
test_summary,
|
|
@@ -3754,7 +4697,7 @@ async function handlePlan(client2, args) {
|
|
|
3754
4697
|
output_snapshot,
|
|
3755
4698
|
side_effects,
|
|
3756
4699
|
outcome,
|
|
3757
|
-
error,
|
|
4700
|
+
error: error2,
|
|
3758
4701
|
props,
|
|
3759
4702
|
agent_id
|
|
3760
4703
|
})
|
|
@@ -3840,6 +4783,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3840
4783
|
const {
|
|
3841
4784
|
action,
|
|
3842
4785
|
format,
|
|
4786
|
+
max_output_chars,
|
|
3843
4787
|
query,
|
|
3844
4788
|
start_uid,
|
|
3845
4789
|
end_uid,
|
|
@@ -3894,7 +4838,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3894
4838
|
graph_expansion_limit: graph_expansion_limit ?? 3,
|
|
3895
4839
|
graph_max_depth: graph_max_depth ?? 2
|
|
3896
4840
|
}),
|
|
3897
|
-
renderContext
|
|
4841
|
+
(raw) => renderContext(raw, max_output_chars)
|
|
3898
4842
|
);
|
|
3899
4843
|
case "text":
|
|
3900
4844
|
if (!query) return err3("query is required for text search");
|
|
@@ -3908,7 +4852,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3908
4852
|
explain,
|
|
3909
4853
|
agent_id
|
|
3910
4854
|
}),
|
|
3911
|
-
(raw) => renderNodeList(raw, `Text search: ${query}
|
|
4855
|
+
(raw) => renderNodeList(raw, `Text search: ${query}`, void 0, max_output_chars)
|
|
3912
4856
|
);
|
|
3913
4857
|
case "semantic":
|
|
3914
4858
|
if (!query) return err3("query is required for semantic search");
|
|
@@ -3922,7 +4866,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3922
4866
|
explain,
|
|
3923
4867
|
agent_id
|
|
3924
4868
|
}),
|
|
3925
|
-
(raw) => renderNodeList(raw, `Semantic search: ${query}
|
|
4869
|
+
(raw) => renderNodeList(raw, `Semantic search: ${query}`, void 0, max_output_chars)
|
|
3926
4870
|
);
|
|
3927
4871
|
case "hybrid":
|
|
3928
4872
|
if (!query) return err3("query is required for hybrid search");
|
|
@@ -3937,7 +4881,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3937
4881
|
agent_id
|
|
3938
4882
|
}),
|
|
3939
4883
|
// With explain, per-leg scoring must survive — raw JSON only.
|
|
3940
|
-
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}
|
|
4884
|
+
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}`, void 0, max_output_chars)
|
|
3941
4885
|
);
|
|
3942
4886
|
// Structured queries. These go through the generic /retrieve action
|
|
3943
4887
|
// dispatch rather than the SDK's no-argument convenience methods — the
|
|
@@ -3955,7 +4899,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3955
4899
|
offset,
|
|
3956
4900
|
agent_id
|
|
3957
4901
|
}),
|
|
3958
|
-
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit)
|
|
4902
|
+
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit, max_output_chars)
|
|
3959
4903
|
);
|
|
3960
4904
|
case "stale_derivations":
|
|
3961
4905
|
return rendered2(
|
|
@@ -3964,7 +4908,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3964
4908
|
limit,
|
|
3965
4909
|
offset
|
|
3966
4910
|
}),
|
|
3967
|
-
(raw) => renderNodeList(raw, "stale derivations", limit)
|
|
4911
|
+
(raw) => renderNodeList(raw, "stale derivations", limit, max_output_chars)
|
|
3968
4912
|
);
|
|
3969
4913
|
case "preferences":
|
|
3970
4914
|
return rendered2(
|
|
@@ -3974,7 +4918,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3974
4918
|
limit,
|
|
3975
4919
|
agent_id
|
|
3976
4920
|
}),
|
|
3977
|
-
(raw) => renderNodeList(raw, "Preferences", limit)
|
|
4921
|
+
(raw) => renderNodeList(raw, "Preferences", limit, max_output_chars)
|
|
3978
4922
|
);
|
|
3979
4923
|
case "layer":
|
|
3980
4924
|
if (!layer) return err3("layer is required for layer retrieval");
|
|
@@ -3986,7 +4930,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3986
4930
|
node_types,
|
|
3987
4931
|
agent_id
|
|
3988
4932
|
}),
|
|
3989
|
-
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit)
|
|
4933
|
+
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit, max_output_chars)
|
|
3990
4934
|
);
|
|
3991
4935
|
case "recent":
|
|
3992
4936
|
return rendered2(
|
|
@@ -4000,7 +4944,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4000
4944
|
created_before,
|
|
4001
4945
|
agent_id
|
|
4002
4946
|
}),
|
|
4003
|
-
(raw) => renderNodeList(raw, "Recently ingested", limit)
|
|
4947
|
+
(raw) => renderNodeList(raw, "Recently ingested", limit, max_output_chars)
|
|
4004
4948
|
);
|
|
4005
4949
|
// Document inventory
|
|
4006
4950
|
case "document_index":
|
|
@@ -4009,7 +4953,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4009
4953
|
node_type: "Document",
|
|
4010
4954
|
limit: limit ?? 100
|
|
4011
4955
|
}),
|
|
4012
|
-
(raw) => renderNodeList(raw, "Ingested documents")
|
|
4956
|
+
(raw) => renderNodeList(raw, "Ingested documents", void 0, max_output_chars)
|
|
4013
4957
|
);
|
|
4014
4958
|
// Graph traversal
|
|
4015
4959
|
case "chain":
|
|
@@ -4023,7 +4967,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4023
4967
|
include_provenance,
|
|
4024
4968
|
max_nodes
|
|
4025
4969
|
}),
|
|
4026
|
-
renderTraversal
|
|
4970
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4027
4971
|
);
|
|
4028
4972
|
case "neighborhood":
|
|
4029
4973
|
if (!start_uid) return err3("start_uid is required for neighborhood traversal");
|
|
@@ -4038,7 +4982,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4038
4982
|
include_provenance,
|
|
4039
4983
|
max_nodes
|
|
4040
4984
|
}),
|
|
4041
|
-
renderTraversal
|
|
4985
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4042
4986
|
);
|
|
4043
4987
|
case "path":
|
|
4044
4988
|
if (!start_uid) return err3("start_uid is required for path traversal");
|
|
@@ -4055,7 +4999,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4055
4999
|
include_provenance,
|
|
4056
5000
|
max_nodes
|
|
4057
5001
|
}),
|
|
4058
|
-
renderTraversal
|
|
5002
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4059
5003
|
);
|
|
4060
5004
|
case "subgraph":
|
|
4061
5005
|
if (!start_uid) return err3("start_uid is required for subgraph traversal");
|
|
@@ -4070,7 +5014,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4070
5014
|
include_provenance,
|
|
4071
5015
|
max_nodes
|
|
4072
5016
|
}),
|
|
4073
|
-
renderTraversal
|
|
5017
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4074
5018
|
);
|
|
4075
5019
|
case "top_k_paths":
|
|
4076
5020
|
if (!start_uid) return err3("start_uid is required for top_k_paths");
|
|
@@ -4086,7 +5030,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4086
5030
|
edge_types,
|
|
4087
5031
|
exclude_edge_types
|
|
4088
5032
|
}),
|
|
4089
|
-
renderTraversal
|
|
5033
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4090
5034
|
);
|
|
4091
5035
|
default:
|
|
4092
5036
|
return err3(`Unknown retrieve action: ${action}`);
|
|
@@ -4350,8 +5294,8 @@ var ok4 = (data) => ({
|
|
|
4350
5294
|
});
|
|
4351
5295
|
var rendered = (format, raw, render) => {
|
|
4352
5296
|
if (format === "json") return ok4(raw);
|
|
4353
|
-
const
|
|
4354
|
-
return
|
|
5297
|
+
const text2 = render(raw);
|
|
5298
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok4(raw);
|
|
4355
5299
|
};
|
|
4356
5300
|
var err4 = (message) => ({
|
|
4357
5301
|
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
@@ -4411,8 +5355,8 @@ async function getGeneratedTools(client2) {
|
|
|
4411
5355
|
cache = { tools, byName, fetchedAt: Date.now() };
|
|
4412
5356
|
retryNotBefore = 0;
|
|
4413
5357
|
return { tools, byName };
|
|
4414
|
-
} catch (
|
|
4415
|
-
if (
|
|
5358
|
+
} catch (error2) {
|
|
5359
|
+
if (error2 instanceof DuplicateGeneratedToolError) throw error2;
|
|
4416
5360
|
retryNotBefore = Date.now() + FAILURE_COOLDOWN_MS;
|
|
4417
5361
|
return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
|
|
4418
5362
|
}
|
|
@@ -4519,7 +5463,7 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
4519
5463
|
return err4(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
4520
5464
|
}
|
|
4521
5465
|
} catch (e) {
|
|
4522
|
-
return
|
|
5466
|
+
return toolError(e);
|
|
4523
5467
|
}
|
|
4524
5468
|
}
|
|
4525
5469
|
|
|
@@ -4569,7 +5513,9 @@ var ONTOLOGY_READ_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
4569
5513
|
"get_proposal"
|
|
4570
5514
|
]);
|
|
4571
5515
|
function toolMutability(toolName, action) {
|
|
5516
|
+
if (toolName === "mindgraph_memory") return "read";
|
|
4572
5517
|
if (toolName === "mindgraph_retrieve") return "read";
|
|
5518
|
+
if (toolName === "mindgraph_remember") return "write";
|
|
4573
5519
|
if (toolName === "mindgraph_series_query") return "read";
|
|
4574
5520
|
if (toolName === "mindgraph_plan") {
|
|
4575
5521
|
return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
|
|
@@ -4689,8 +5635,8 @@ async function checkMcpGovernance(toolName, args, config) {
|
|
|
4689
5635
|
response = candidate;
|
|
4690
5636
|
body = candidateBody;
|
|
4691
5637
|
break;
|
|
4692
|
-
} catch (
|
|
4693
|
-
lastFailure =
|
|
5638
|
+
} catch (error2) {
|
|
5639
|
+
lastFailure = error2 instanceof Error ? error2.message : String(error2);
|
|
4694
5640
|
if (attempt < retryDelays.length) {
|
|
4695
5641
|
await sleep(retryDelays[attempt]);
|
|
4696
5642
|
continue;
|
|
@@ -4764,6 +5710,12 @@ async function checkMcpGovernance(toolName, args, config) {
|
|
|
4764
5710
|
|
|
4765
5711
|
// src/resources.ts
|
|
4766
5712
|
var RESOURCES = [
|
|
5713
|
+
{
|
|
5714
|
+
uri: "mindgraph://memory/status",
|
|
5715
|
+
name: "Memory Integration Status",
|
|
5716
|
+
description: "Portable memory profile, adapter state, supported capabilities, and explicit limitations",
|
|
5717
|
+
mimeType: "application/json"
|
|
5718
|
+
},
|
|
4767
5719
|
{
|
|
4768
5720
|
uri: "mindgraph://stats",
|
|
4769
5721
|
name: "Graph Statistics",
|
|
@@ -4821,8 +5773,10 @@ function json(uri, data) {
|
|
|
4821
5773
|
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
|
|
4822
5774
|
};
|
|
4823
5775
|
}
|
|
4824
|
-
async function readResource(client2, uri) {
|
|
5776
|
+
async function readResource(client2, uri, memoryConfig = {}) {
|
|
4825
5777
|
switch (uri) {
|
|
5778
|
+
case "mindgraph://memory/status":
|
|
5779
|
+
return json(uri, memoryStatus(memoryConfig));
|
|
4826
5780
|
case "mindgraph://stats":
|
|
4827
5781
|
return json(uri, await client2.stats());
|
|
4828
5782
|
case "mindgraph://goals":
|
|
@@ -4854,16 +5808,18 @@ async function readResource(client2, uri) {
|
|
|
4854
5808
|
}
|
|
4855
5809
|
throw new Error(`Unknown resource: ${uri}`);
|
|
4856
5810
|
}
|
|
4857
|
-
async function readGovernedResource(client2, uri, governanceConfig) {
|
|
5811
|
+
async function readGovernedResource(client2, uri, governanceConfig, memoryConfig = {}) {
|
|
5812
|
+
const toolName = uri === "mindgraph://memory/status" ? "mindgraph_memory" : RESOURCE_GOVERNANCE_TOOL;
|
|
5813
|
+
const toolArgs = uri === "mindgraph://memory/status" ? { action: "status" } : {};
|
|
4858
5814
|
const governance = await checkMcpGovernance(
|
|
4859
|
-
|
|
4860
|
-
|
|
5815
|
+
toolName,
|
|
5816
|
+
toolArgs,
|
|
4861
5817
|
{ ...governanceConfig, context: { resource_uri: uri } }
|
|
4862
5818
|
);
|
|
4863
5819
|
if (!governance.allowed) {
|
|
4864
5820
|
throw new Error(governance.message);
|
|
4865
5821
|
}
|
|
4866
|
-
return readResource(client2, uri);
|
|
5822
|
+
return readResource(client2, uri, memoryConfig);
|
|
4867
5823
|
}
|
|
4868
5824
|
|
|
4869
5825
|
// src/index.ts
|
|
@@ -4873,7 +5829,7 @@ var import_node_path5 = __toESM(require("path"));
|
|
|
4873
5829
|
var import_node_fs4 = __toESM(require("fs"));
|
|
4874
5830
|
var import_node_os3 = __toESM(require("os"));
|
|
4875
5831
|
var import_node_path4 = __toESM(require("path"));
|
|
4876
|
-
var
|
|
5832
|
+
var import_node_crypto6 = __toESM(require("crypto"));
|
|
4877
5833
|
var OWNER_MARKER = "--owner mindgraph";
|
|
4878
5834
|
var RUNNER_RELATIVE = ".mindgraph/bin/mindgraph-hook.cjs";
|
|
4879
5835
|
function command(harness) {
|
|
@@ -4886,7 +5842,7 @@ var RUNNER_VERSION_RELATIVE = `${RUNNER_RELATIVE}.version`;
|
|
|
4886
5842
|
function installHookRunner(sourceFile, homeDir, version) {
|
|
4887
5843
|
const target = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_RELATIVE);
|
|
4888
5844
|
import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(target), { recursive: true });
|
|
4889
|
-
const temporary = `${target}.${process.pid}.${
|
|
5845
|
+
const temporary = `${target}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
|
|
4890
5846
|
import_node_fs4.default.copyFileSync(sourceFile, temporary);
|
|
4891
5847
|
import_node_fs4.default.renameSync(temporary, target);
|
|
4892
5848
|
const versionPath = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_VERSION_RELATIVE);
|
|
@@ -5056,7 +6012,7 @@ function entryHasOwnedHook(value) {
|
|
|
5056
6012
|
}
|
|
5057
6013
|
function writeSettings(file, settings) {
|
|
5058
6014
|
import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
|
|
5059
|
-
const temporary = `${file}.${process.pid}.${
|
|
6015
|
+
const temporary = `${file}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
|
|
5060
6016
|
import_node_fs4.default.writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}
|
|
5061
6017
|
`, {
|
|
5062
6018
|
mode: 384
|
|
@@ -5109,56 +6065,31 @@ var client = new import_mindgraph2.MindGraph({
|
|
|
5109
6065
|
});
|
|
5110
6066
|
var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph, plus any ontology tools generated by the active schema.
|
|
5111
6067
|
|
|
5112
|
-
##
|
|
6068
|
+
## Default memory workflow: orient \u2192 answer \u2192 preserve
|
|
5113
6069
|
|
|
5114
|
-
|
|
6070
|
+
**Orient only when prior durable state may matter.** Self-contained questions do not require a memory call or a warm-up sequence.
|
|
5115
6071
|
|
|
5116
|
-
|
|
5117
|
-
-
|
|
5118
|
-
-
|
|
5119
|
-
-
|
|
6072
|
+
- Resuming work, asking what was in progress, or continuing a task: call \`mindgraph_memory\` once with action \`context\` and mode \`resume\` or \`continuity\`. This uses authoritative, task-first, lease-aware work state.
|
|
6073
|
+
- Asking about a topic that may depend on prior knowledge: call \`mindgraph_memory\` once with action \`context\`, mode \`topic\`, and 1\u20133 discriminating keywords.
|
|
6074
|
+
- Asking about integration capability or automatic behavior: call \`mindgraph_memory\` with action \`status\`.
|
|
6075
|
+
- Use the comprehensive read tools below only when the high-level result is insufficient or the user asks for a specific graph operation.
|
|
5120
6076
|
|
|
5121
|
-
|
|
6077
|
+
**Answer from the bounded result.** Treat superseded, refuted, or out-of-validity items as warnings, not current facts. Retrieval proves only that the server returned context; it does not prove that a host automatically injected or used it.
|
|
5122
6078
|
|
|
5123
|
-
**
|
|
5124
|
-
\u2713 CORRECT: \`mindgraph_retrieve({action: "context", query: "Indian philosophy Taoism"})\`
|
|
5125
|
-
\u2717 WRONG: First retrieve active_goals, then open_questions, then search
|
|
5126
|
-
\u2717 WRONG: \`mindgraph_retrieve({action: "context", query: "Tell me about Indian philosophy and Taoism"})\` \u2014 natural language won't match BM25
|
|
6079
|
+
**Respect failed tool results.** An isError result is a failed operation, not evidence that the graph has no matches. Preserve its code and retry guidance. If retriable is false, do not automatically repeat the unchanged call or silently substitute another retrieval mode. Explain the failure; a narrower query or a later user-requested retry is a separate decision.
|
|
5127
6080
|
|
|
5128
|
-
|
|
6081
|
+
**Preserve selectively after material durable change.** Use the existing typed write tool for a fact, correction, decision, work-state transition, or reusable lesson. Do not write ephemeral conversation, routine mechanics, unsupported guesses, or information already represented accurately. An explicit no-write is the correct outcome when nothing durable changed.
|
|
5129
6082
|
|
|
5130
|
-
|
|
5131
|
-
Use \`action: "context"\` with keywords. By default this returns only graph nodes \u2014 structured knowledge with labels, summaries, types, confidence scores, and edges. This is usually sufficient and keeps results compact.
|
|
6083
|
+
## Topic retrieval details
|
|
5132
6084
|
|
|
5133
|
-
|
|
5134
|
-
If you need the original source text behind a node (for verbatim quotes, citations, or when graph summaries lack detail), use \`action: "context"\` with \`include_chunks: true\`. This adds full document chunks (400-800 words each) to the response.
|
|
6085
|
+
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval succeeds but returns no matches, use \`mindgraph_retrieve\` with \`semantic\` or \`hybrid\`; use \`document_index\` to inspect ingested sources.
|
|
5135
6086
|
|
|
5136
|
-
|
|
5137
|
-
- \`action: "document_index"\` \u2014 list all ingested documents (titles, dates, UIDs) to see what's in the graph
|
|
6087
|
+
## Comprehensive read tools
|
|
5138
6088
|
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
**Keyword examples:**
|
|
5144
|
-
- "What is Kissinger's view on NATO?" \u2192 query: \`"Kissinger NATO"\`
|
|
5145
|
-
- "Tell me about async in Rust" \u2192 query: \`"Rust async runtime"\`
|
|
5146
|
-
- "Implications of carbon tax?" \u2192 query: \`"carbon tax"\`
|
|
5147
|
-
|
|
5148
|
-
If keyword search returns no results, escalate:
|
|
5149
|
-
1. Try synonyms (e.g. \`"global warming"\` instead of \`"climate change"\`)
|
|
5150
|
-
2. Use \`action: "semantic"\` \u2014 vector similarity, natural language OK (e.g. \`"ways to manage stress"\` finds "mental health" nodes)
|
|
5151
|
-
3. Use \`action: "hybrid"\` \u2014 combines BM25 + semantic for best coverage
|
|
5152
|
-
|
|
5153
|
-
## When to READ
|
|
5154
|
-
|
|
5155
|
-
- User asks about topic X \u2192 \`mindgraph_retrieve\` action "context", query "X keywords"
|
|
5156
|
-
- User asks "what documents are in my graph?" \u2192 action "document_index"
|
|
5157
|
-
- User explicitly asks "what are my goals?" \u2192 action "active_goals"
|
|
5158
|
-
- User explicitly asks about open questions \u2192 action "open_questions"
|
|
5159
|
-
- User asks for advice or a recommendation ("suggest a hotel", "what should I read?") \u2192 action "preferences", query "topic keywords" \u2014 tailor the answer to what they like
|
|
5160
|
-
- Explore around a known node \u2192 action "neighborhood" with start_uid
|
|
5161
|
-
- Find connections between nodes \u2192 action "path" with start_uid + end_uid
|
|
6089
|
+
- Explicit graph inventory or state questions \u2192 the matching \`mindgraph_retrieve\` action such as \`document_index\`, \`active_goals\`, or \`open_questions\`
|
|
6090
|
+
- Advice or recommendations \u2192 \`mindgraph_retrieve\` action \`preferences\`, with topic keywords
|
|
6091
|
+
- Explore around a known node \u2192 \`mindgraph_retrieve\` action \`neighborhood\` with start_uid
|
|
6092
|
+
- Find connections between nodes \u2192 \`mindgraph_retrieve\` action \`path\` with start_uid + end_uid
|
|
5162
6093
|
|
|
5163
6094
|
## When to WRITE
|
|
5164
6095
|
|
|
@@ -5193,13 +6124,14 @@ if (PROFILE === "coding") {
|
|
|
5193
6124
|
|
|
5194
6125
|
## Coding profile
|
|
5195
6126
|
|
|
5196
|
-
**
|
|
5197
|
-
- "What was I working on?" / current work state / resuming anything: call \`
|
|
6127
|
+
**Coding recall order:**
|
|
6128
|
+
- "What was I working on?" / current work state / resuming anything: call \`mindgraph_memory\` action \`context\`, mode \`resume\` FIRST. It delegates to structural \`resume_work\`; never answer work state from keyword search ("recent work" famously retrieves people named Work).
|
|
5198
6129
|
- Knowledge about specific code (a function, file, or route): \`mindgraph_code\` action \`recall\` \u2014 anchor-based, not keyword-based.
|
|
5199
6130
|
- Broad knowledge searches: \`mindgraph_retrieve\` as usual, but when searching for work artifacts pass node_types filters (Task, Lesson, RiskAssessment, Claim) to keep personal-graph content out of engineering answers.
|
|
5200
6131
|
|
|
5201
6132
|
- Use mindgraph_sync for explicit, one-way project memory-file imports. It discovers and hashes files, but you deliberately map durable assertions with record; it never writes graph state back to files.
|
|
5202
6133
|
- Capture corrections, decisions with rationale, fixes that survived meaningful failed attempts, durable invariants/preferences, and blockers with evidence.
|
|
6134
|
+
- If a write returns \`near_duplicate\`, choose \`reuse_uid\` or \`supersedes_uid\`; use \`confirm_new\` only for genuinely distinct facts.
|
|
5203
6135
|
- Do not capture routine mechanics, transient command output, facts cheaply derivable from code, unsupported speculation as high-confidence lessons, or completion without evidence.
|
|
5204
6136
|
- Adapter context is owned by ${HARNESS}; omit invocation_context because hooks replace it.`;
|
|
5205
6137
|
} else {
|
|
@@ -5209,7 +6141,7 @@ if (PROFILE === "coding") {
|
|
|
5209
6141
|
}
|
|
5210
6142
|
var RUNNER_REFRESH = (() => {
|
|
5211
6143
|
try {
|
|
5212
|
-
return refreshHookRunner("0.
|
|
6144
|
+
return refreshHookRunner("0.21.0", import_node_path5.default.join(__dirname, "cli.js"));
|
|
5213
6145
|
} catch {
|
|
5214
6146
|
return void 0;
|
|
5215
6147
|
}
|
|
@@ -5223,12 +6155,12 @@ if (RUNNER_REFRESH?.refreshed) {
|
|
|
5223
6155
|
}
|
|
5224
6156
|
})();
|
|
5225
6157
|
console.error(
|
|
5226
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
6158
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.21.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
5227
6159
|
);
|
|
5228
6160
|
}
|
|
5229
6161
|
var HOOK_SKEW_NOTE = (() => {
|
|
5230
6162
|
try {
|
|
5231
|
-
return versionSkewNote("0.
|
|
6163
|
+
return versionSkewNote("0.21.0");
|
|
5232
6164
|
} catch {
|
|
5233
6165
|
return void 0;
|
|
5234
6166
|
}
|
|
@@ -5242,7 +6174,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
5242
6174
|
var server = new import_server.Server(
|
|
5243
6175
|
{
|
|
5244
6176
|
name: "mindgraph",
|
|
5245
|
-
version: "0.
|
|
6177
|
+
version: "0.21.0"
|
|
5246
6178
|
},
|
|
5247
6179
|
{
|
|
5248
6180
|
capabilities: {
|
|
@@ -5266,6 +6198,14 @@ var GOVERNANCE_CONFIG = {
|
|
|
5266
6198
|
return process.env.MINDGRAPH_GOVERNANCE === "off";
|
|
5267
6199
|
}
|
|
5268
6200
|
};
|
|
6201
|
+
var MEMORY_RUNTIME_CONFIG = {
|
|
6202
|
+
serverVersion: "0.21.0",
|
|
6203
|
+
baseUrl: BASE_URL,
|
|
6204
|
+
profile: PROFILE,
|
|
6205
|
+
harness: HARNESS,
|
|
6206
|
+
orgId: ORG_ID,
|
|
6207
|
+
agentId: AGENT_ID
|
|
6208
|
+
};
|
|
5269
6209
|
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
5270
6210
|
const { name, arguments: args } = request.params;
|
|
5271
6211
|
const rawArgs = { ...args || {} };
|
|
@@ -5285,7 +6225,7 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
|
|
|
5285
6225
|
if (desc) {
|
|
5286
6226
|
return handleGeneratedTool(client, desc, rawArgs);
|
|
5287
6227
|
}
|
|
5288
|
-
return handleTool(client, name, toolArgs);
|
|
6228
|
+
return handleTool(client, name, toolArgs, MEMORY_RUNTIME_CONFIG);
|
|
5289
6229
|
});
|
|
5290
6230
|
var PROMPTS = [
|
|
5291
6231
|
{
|
|
@@ -5450,16 +6390,21 @@ server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async
|
|
|
5450
6390
|
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
5451
6391
|
});
|
|
5452
6392
|
server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
|
|
5453
|
-
return readGovernedResource(
|
|
6393
|
+
return readGovernedResource(
|
|
6394
|
+
client,
|
|
6395
|
+
request.params.uri,
|
|
6396
|
+
GOVERNANCE_CONFIG,
|
|
6397
|
+
MEMORY_RUNTIME_CONFIG
|
|
6398
|
+
);
|
|
5454
6399
|
});
|
|
5455
6400
|
async function main() {
|
|
5456
6401
|
const transport = new import_stdio.StdioServerTransport();
|
|
5457
6402
|
await server.connect(transport);
|
|
5458
6403
|
console.error(
|
|
5459
|
-
`MindGraph MCP server v${"0.
|
|
6404
|
+
`MindGraph MCP server v${"0.21.0"} running on stdio (${BASE_URL})`
|
|
5460
6405
|
);
|
|
5461
6406
|
}
|
|
5462
|
-
main().catch((
|
|
5463
|
-
console.error("Fatal error:",
|
|
6407
|
+
main().catch((error2) => {
|
|
6408
|
+
console.error("Fatal error:", error2);
|
|
5464
6409
|
process.exit(1);
|
|
5465
6410
|
});
|