mindgraph-mcp 0.18.0 → 0.20.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 +27 -4
- package/dist/cli.js +1792 -290
- package/dist/index.js +1153 -189
- 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) {
|
|
@@ -238,29 +241,29 @@ async function runProcess(executable, args, timeoutMs, env, cwd) {
|
|
|
238
241
|
child.stderr.on("data", collect(stderr));
|
|
239
242
|
child.on("error", (cause) => {
|
|
240
243
|
clearTimeout(timer);
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
rejectPromise(
|
|
244
|
+
const error2 = new Error(cause.message);
|
|
245
|
+
error2.kind = cause.code === "ENOENT" ? "absent" : "command_failed";
|
|
246
|
+
rejectPromise(error2);
|
|
244
247
|
});
|
|
245
248
|
child.on("close", (code) => {
|
|
246
249
|
clearTimeout(timer);
|
|
247
250
|
if (timedOut) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
rejectPromise(
|
|
251
|
+
const error2 = new Error(`command timed out after ${timeoutMs}ms`);
|
|
252
|
+
error2.kind = "timeout";
|
|
253
|
+
rejectPromise(error2);
|
|
251
254
|
return;
|
|
252
255
|
}
|
|
253
256
|
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
rejectPromise(
|
|
257
|
+
const error2 = new Error("codegraph output exceeded 5 MiB");
|
|
258
|
+
error2.kind = "command_failed";
|
|
259
|
+
rejectPromise(error2);
|
|
257
260
|
return;
|
|
258
261
|
}
|
|
259
262
|
if (code !== 0) {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
rejectPromise(
|
|
263
|
+
const error2 = new Error(Buffer.concat(stderr).toString("utf8").trim());
|
|
264
|
+
error2.kind = "command_failed";
|
|
265
|
+
error2.exitCode = code;
|
|
266
|
+
rejectPromise(error2);
|
|
264
267
|
return;
|
|
265
268
|
}
|
|
266
269
|
resolvePromise(Buffer.concat(stdout).toString("utf8"));
|
|
@@ -813,9 +816,7 @@ function codeRefIdentityKey(ref) {
|
|
|
813
816
|
qualified_name: ref.qualifiedName,
|
|
814
817
|
disambiguator: {
|
|
815
818
|
signature: ref.signature ?? "",
|
|
816
|
-
path: ref.path
|
|
817
|
-
start_line: ref.startLine,
|
|
818
|
-
end_line: ref.endLine
|
|
819
|
+
path: ref.path
|
|
819
820
|
}
|
|
820
821
|
};
|
|
821
822
|
}
|
|
@@ -1193,7 +1194,7 @@ async function anchorCodeRef(client2, ref, repositoryUid, spaceUid, agentId) {
|
|
|
1193
1194
|
identity_space_uid: spaceUid,
|
|
1194
1195
|
agent_id: agentId
|
|
1195
1196
|
});
|
|
1196
|
-
if (response.uid) {
|
|
1197
|
+
if (response.uid && response.created !== false && response.status !== "existing") {
|
|
1197
1198
|
await client2.entity({
|
|
1198
1199
|
action: "relate",
|
|
1199
1200
|
source_uid: response.uid,
|
|
@@ -1556,8 +1557,8 @@ async function handleSyncTool(client2, args) {
|
|
|
1556
1557
|
}
|
|
1557
1558
|
}
|
|
1558
1559
|
return ok2(await remote.memorySync(request));
|
|
1559
|
-
} catch (
|
|
1560
|
-
return err2("sync_failed", errorDetail(
|
|
1560
|
+
} catch (error2) {
|
|
1561
|
+
return err2("sync_failed", errorDetail(error2));
|
|
1561
1562
|
}
|
|
1562
1563
|
}
|
|
1563
1564
|
async function scanRepository(remote, repository, requested, provider, agentId) {
|
|
@@ -1595,6 +1596,9 @@ async function scanRepository(remote, repository, requested, provider, agentId)
|
|
|
1595
1596
|
};
|
|
1596
1597
|
}
|
|
1597
1598
|
|
|
1599
|
+
// src/memory-tool.ts
|
|
1600
|
+
var import_node_crypto4 = require("crypto");
|
|
1601
|
+
|
|
1598
1602
|
// src/render.ts
|
|
1599
1603
|
var LABEL_MAX = 200;
|
|
1600
1604
|
var SUMMARY_MAX = 400;
|
|
@@ -1603,6 +1607,8 @@ var ARTICLE_MAX = 6e3;
|
|
|
1603
1607
|
var CHUNK_MAX = 6e3;
|
|
1604
1608
|
var RELATIONSHIP_MAX = 40;
|
|
1605
1609
|
var RENDER_CHAR_BUDGET = 24e3;
|
|
1610
|
+
var MIN_RENDER_CHAR_BUDGET = 512;
|
|
1611
|
+
var BOUNDED_MARKER_RESERVE = 220;
|
|
1606
1612
|
var CURATION_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
1607
1613
|
var INFRA_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
1608
1614
|
function obj(value) {
|
|
@@ -1614,12 +1620,22 @@ function str(value) {
|
|
|
1614
1620
|
function num(value) {
|
|
1615
1621
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1616
1622
|
}
|
|
1623
|
+
function edgeTypeName(value) {
|
|
1624
|
+
return str(value) ?? str(obj(value)?.Custom);
|
|
1625
|
+
}
|
|
1626
|
+
function renderBudget(requested) {
|
|
1627
|
+
if (requested === void 0 || !Number.isFinite(requested)) return RENDER_CHAR_BUDGET;
|
|
1628
|
+
return Math.min(
|
|
1629
|
+
RENDER_CHAR_BUDGET,
|
|
1630
|
+
Math.max(MIN_RENDER_CHAR_BUDGET, Math.floor(requested))
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1617
1633
|
function clip(value, max, state) {
|
|
1618
|
-
const
|
|
1619
|
-
if (!
|
|
1620
|
-
if (
|
|
1634
|
+
const text2 = str(value);
|
|
1635
|
+
if (!text2) return void 0;
|
|
1636
|
+
if (text2.length <= max) return text2;
|
|
1621
1637
|
state.bounded = true;
|
|
1622
|
-
return `${
|
|
1638
|
+
return `${text2.slice(0, max - 1)}\u2026`;
|
|
1623
1639
|
}
|
|
1624
1640
|
function isNodeShaped(value) {
|
|
1625
1641
|
const node = obj(value);
|
|
@@ -1741,7 +1757,7 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
1741
1757
|
for (const raw of edges) {
|
|
1742
1758
|
const edge = obj(raw);
|
|
1743
1759
|
if (!edge) continue;
|
|
1744
|
-
const type =
|
|
1760
|
+
const type = edgeTypeName(edge.edge_type) || "?";
|
|
1745
1761
|
const from = str(edge.from_uid);
|
|
1746
1762
|
const to = str(edge.to_uid);
|
|
1747
1763
|
if (CURATION_EDGE_TYPES.has(type)) continue;
|
|
@@ -1754,25 +1770,29 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
1754
1770
|
if (lines.length > RELATIONSHIP_MAX) {
|
|
1755
1771
|
state.bounded = true;
|
|
1756
1772
|
const extra = lines.length - RELATIONSHIP_MAX;
|
|
1773
|
+
state.omitted += extra;
|
|
1757
1774
|
return [...lines.slice(0, RELATIONSHIP_MAX), `- (+${extra} more relationships)`];
|
|
1758
1775
|
}
|
|
1759
1776
|
return lines;
|
|
1760
1777
|
}
|
|
1761
|
-
function assemble(header, sections, state) {
|
|
1778
|
+
function assemble(header, sections, state, maxChars) {
|
|
1779
|
+
const budget = renderBudget(maxChars);
|
|
1780
|
+
const packingBudget = Math.max(header.length, budget - BOUNDED_MARKER_RESERVE);
|
|
1762
1781
|
const lines = [header];
|
|
1763
1782
|
let used = header.length;
|
|
1764
1783
|
for (const section of sections) {
|
|
1765
1784
|
if (section.items.length === 0 && !section.heading) continue;
|
|
1766
1785
|
const headingCost = section.heading.length + 2;
|
|
1767
|
-
if (used + headingCost >
|
|
1786
|
+
if (used + headingCost > packingBudget) {
|
|
1768
1787
|
state.bounded = true;
|
|
1788
|
+
state.omitted += Math.max(1, section.items.length);
|
|
1769
1789
|
continue;
|
|
1770
1790
|
}
|
|
1771
1791
|
let sectionUsed = 0;
|
|
1772
1792
|
const kept = [];
|
|
1773
1793
|
let dropped = 0;
|
|
1774
1794
|
for (const item of section.items) {
|
|
1775
|
-
if (used + headingCost + sectionUsed + item.length + 1 >
|
|
1795
|
+
if (used + headingCost + sectionUsed + item.length + 1 > packingBudget) {
|
|
1776
1796
|
dropped += 1;
|
|
1777
1797
|
continue;
|
|
1778
1798
|
}
|
|
@@ -1781,13 +1801,17 @@ function assemble(header, sections, state) {
|
|
|
1781
1801
|
}
|
|
1782
1802
|
if (kept.length === 0 && section.items.length > 0) {
|
|
1783
1803
|
state.bounded = true;
|
|
1804
|
+
state.omitted += dropped;
|
|
1784
1805
|
continue;
|
|
1785
1806
|
}
|
|
1786
1807
|
if (dropped > 0) {
|
|
1787
1808
|
state.bounded = true;
|
|
1809
|
+
state.omitted += dropped;
|
|
1788
1810
|
const marker = `(+${dropped} more not shown)`;
|
|
1789
|
-
|
|
1790
|
-
|
|
1811
|
+
if (used + headingCost + sectionUsed + marker.length + 1 <= packingBudget) {
|
|
1812
|
+
kept.push(marker);
|
|
1813
|
+
sectionUsed += marker.length + 1;
|
|
1814
|
+
}
|
|
1791
1815
|
}
|
|
1792
1816
|
lines.push(
|
|
1793
1817
|
section.items.length === 0 ? section.heading : section.heading ? `${section.heading}
|
|
@@ -1797,10 +1821,10 @@ ${kept.join("\n")}` : kept.join("\n")
|
|
|
1797
1821
|
}
|
|
1798
1822
|
if (state.bounded) {
|
|
1799
1823
|
lines.push(
|
|
1800
|
-
|
|
1824
|
+
`\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
1825
|
);
|
|
1802
1826
|
}
|
|
1803
|
-
return lines.join("\n\n");
|
|
1827
|
+
return lines.join("\n\n").slice(0, budget);
|
|
1804
1828
|
}
|
|
1805
1829
|
function policySections(payload, state) {
|
|
1806
1830
|
const policies = Array.isArray(payload.applicable_policies) ? payload.applicable_policies : [];
|
|
@@ -1821,7 +1845,7 @@ function hiddenSections(payload) {
|
|
|
1821
1845
|
}
|
|
1822
1846
|
];
|
|
1823
1847
|
}
|
|
1824
|
-
function renderContext(response) {
|
|
1848
|
+
function renderContext(response, maxChars) {
|
|
1825
1849
|
const payload = obj(response);
|
|
1826
1850
|
if (!payload) return void 0;
|
|
1827
1851
|
const graph = obj(payload.graph);
|
|
@@ -1831,7 +1855,7 @@ function renderContext(response) {
|
|
|
1831
1855
|
const infraOnly = shaped.length - nodes.length;
|
|
1832
1856
|
const articles = Array.isArray(payload.articles) ? payload.articles : [];
|
|
1833
1857
|
const chunks = Array.isArray(payload.chunks) ? payload.chunks : [];
|
|
1834
|
-
const state = { bounded: false };
|
|
1858
|
+
const state = { bounded: false, omitted: 0 };
|
|
1835
1859
|
const sections = [];
|
|
1836
1860
|
if (articles.length > 0) {
|
|
1837
1861
|
sections.push({
|
|
@@ -1874,11 +1898,129 @@ ${clip(article.content, ARTICLE_MAX, state) || ""}`
|
|
|
1874
1898
|
return "No results found for this search.";
|
|
1875
1899
|
}
|
|
1876
1900
|
if (nodes.length === 0 && articles.length === 0 && chunks.length === 0) {
|
|
1877
|
-
return assemble(
|
|
1901
|
+
return assemble(
|
|
1902
|
+
"# Retrieved context\n\nNo graph results matched this search.",
|
|
1903
|
+
sections,
|
|
1904
|
+
state,
|
|
1905
|
+
maxChars
|
|
1906
|
+
);
|
|
1878
1907
|
}
|
|
1879
|
-
return assemble("# Retrieved context", sections, state);
|
|
1908
|
+
return assemble("# Retrieved context", sections, state, maxChars);
|
|
1909
|
+
}
|
|
1910
|
+
function resumeEntry(raw, state, fallbackType) {
|
|
1911
|
+
const wrapper = obj(raw);
|
|
1912
|
+
if (!wrapper) return void 0;
|
|
1913
|
+
const value = obj(wrapper.node) ?? wrapper;
|
|
1914
|
+
if (isNodeShaped(value)) return nodeLines(value, state);
|
|
1915
|
+
const uid = str(value.uid);
|
|
1916
|
+
const props = obj(value.props);
|
|
1917
|
+
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;
|
|
1918
|
+
const status = str(value.status) ?? str(props?.status);
|
|
1919
|
+
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);
|
|
1920
|
+
const details = [
|
|
1921
|
+
status ? `status ${status}` : void 0,
|
|
1922
|
+
str(value.path) ? `path ${str(value.path)}` : void 0,
|
|
1923
|
+
str(value.symbol) ? `symbol ${str(value.symbol)}` : void 0
|
|
1924
|
+
].filter(Boolean);
|
|
1925
|
+
const head = `- **${label}**${uid ? ` [${uid}]` : ""}${details.length > 0 ? ` (${details.join(", ")})` : ""}`;
|
|
1926
|
+
return summary && summary !== label ? `${head}: ${summary}` : head;
|
|
1880
1927
|
}
|
|
1881
|
-
function
|
|
1928
|
+
function resumeSection(heading, values, state, fallbackType) {
|
|
1929
|
+
const items = values.map((value) => resumeEntry(value, state, fallbackType)).filter((value) => Boolean(value));
|
|
1930
|
+
return items.length > 0 ? { heading, items } : void 0;
|
|
1931
|
+
}
|
|
1932
|
+
function renderResumeContext(response, maxChars) {
|
|
1933
|
+
const payload = obj(response);
|
|
1934
|
+
if (!payload) return void 0;
|
|
1935
|
+
const state = { bounded: false, omitted: 0 };
|
|
1936
|
+
const status = str(payload.status);
|
|
1937
|
+
if (!payload.task && status === "no_eligible_work") {
|
|
1938
|
+
const scopedOut = Array.isArray(payload.scoped_out_tasks) ? payload.scoped_out_tasks.length : 0;
|
|
1939
|
+
const note = scopedOut > 0 ? ` ${scopedOut} task(s) exist outside the requested scope.` : "";
|
|
1940
|
+
return assemble(
|
|
1941
|
+
"# Resume context",
|
|
1942
|
+
[{ heading: `No eligible work was found in the requested scope.${note}`, items: [] }],
|
|
1943
|
+
state,
|
|
1944
|
+
maxChars
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
const sections = [];
|
|
1948
|
+
const push = (section) => {
|
|
1949
|
+
if (section) sections.push(section);
|
|
1950
|
+
};
|
|
1951
|
+
push(resumeSection("## Current task", [payload.task], state, "Task"));
|
|
1952
|
+
push(
|
|
1953
|
+
resumeSection(
|
|
1954
|
+
"## Goal and project",
|
|
1955
|
+
[payload.goal, payload.project].filter(Boolean),
|
|
1956
|
+
state,
|
|
1957
|
+
"Scope"
|
|
1958
|
+
)
|
|
1959
|
+
);
|
|
1960
|
+
push(resumeSection("## Plan", [payload.plan], state, "Plan"));
|
|
1961
|
+
push(
|
|
1962
|
+
resumeSection(
|
|
1963
|
+
"## Next steps",
|
|
1964
|
+
Array.isArray(payload.next_steps) ? payload.next_steps : [],
|
|
1965
|
+
state,
|
|
1966
|
+
"Next step"
|
|
1967
|
+
)
|
|
1968
|
+
);
|
|
1969
|
+
push(
|
|
1970
|
+
resumeSection(
|
|
1971
|
+
"## Blockers",
|
|
1972
|
+
Array.isArray(payload.blockers) ? payload.blockers : [],
|
|
1973
|
+
state,
|
|
1974
|
+
"Blocker"
|
|
1975
|
+
)
|
|
1976
|
+
);
|
|
1977
|
+
const knowledge = obj(payload.knowledge);
|
|
1978
|
+
push(
|
|
1979
|
+
resumeSection(
|
|
1980
|
+
"## Relevant lessons and risks",
|
|
1981
|
+
[
|
|
1982
|
+
...Array.isArray(knowledge?.lessons) ? knowledge.lessons : [],
|
|
1983
|
+
...Array.isArray(knowledge?.risks) ? knowledge.risks : []
|
|
1984
|
+
],
|
|
1985
|
+
state,
|
|
1986
|
+
"Knowledge"
|
|
1987
|
+
)
|
|
1988
|
+
);
|
|
1989
|
+
push(
|
|
1990
|
+
resumeSection(
|
|
1991
|
+
"## Active execution",
|
|
1992
|
+
[payload.active_execution].filter(Boolean),
|
|
1993
|
+
state,
|
|
1994
|
+
"Execution"
|
|
1995
|
+
)
|
|
1996
|
+
);
|
|
1997
|
+
push(
|
|
1998
|
+
resumeSection(
|
|
1999
|
+
"## Recent executions",
|
|
2000
|
+
Array.isArray(payload.recent_executions) ? payload.recent_executions : [],
|
|
2001
|
+
state,
|
|
2002
|
+
"Execution"
|
|
2003
|
+
)
|
|
2004
|
+
);
|
|
2005
|
+
push(
|
|
2006
|
+
resumeSection(
|
|
2007
|
+
"## Code targets",
|
|
2008
|
+
Array.isArray(payload.code_targets) ? payload.code_targets : [],
|
|
2009
|
+
state,
|
|
2010
|
+
"Code target"
|
|
2011
|
+
)
|
|
2012
|
+
);
|
|
2013
|
+
push(resumeSection("## Lease", [payload.lease].filter(Boolean), state, "Lease"));
|
|
2014
|
+
const warning = clip(payload.warning, SUMMARY_MAX, state);
|
|
2015
|
+
if (warning) sections.push({ heading: "## Warning", items: [`- ${warning}`] });
|
|
2016
|
+
const selectionReason = clip(payload.selection_reason, SUMMARY_MAX, state);
|
|
2017
|
+
if (selectionReason) {
|
|
2018
|
+
sections.push({ heading: "## Selection", items: [`- ${selectionReason}`] });
|
|
2019
|
+
}
|
|
2020
|
+
if (sections.length === 0) return void 0;
|
|
2021
|
+
return assemble("# Resume context", sections, state, maxChars);
|
|
2022
|
+
}
|
|
2023
|
+
function renderNodeList(response, title, limit, maxChars) {
|
|
1882
2024
|
let candidates = [];
|
|
1883
2025
|
if (Array.isArray(response)) {
|
|
1884
2026
|
candidates = response;
|
|
@@ -1896,8 +2038,9 @@ function renderNodeList(response, title, limit) {
|
|
|
1896
2038
|
let nodes = candidates.map(unwrapSearchResult).filter((node) => Boolean(node));
|
|
1897
2039
|
if (nodes.length === 0) return void 0;
|
|
1898
2040
|
const total = nodes.length;
|
|
1899
|
-
const state = { bounded: false };
|
|
2041
|
+
const state = { bounded: false, omitted: 0 };
|
|
1900
2042
|
if (limit !== void 0 && limit > 0 && nodes.length > limit) {
|
|
2043
|
+
state.omitted += nodes.length - limit;
|
|
1901
2044
|
nodes = nodes.slice(0, limit);
|
|
1902
2045
|
state.bounded = true;
|
|
1903
2046
|
}
|
|
@@ -1906,18 +2049,23 @@ function renderNodeList(response, title, limit) {
|
|
|
1906
2049
|
return assemble(
|
|
1907
2050
|
`# ${title} (${shown === total ? total : `${shown} of ${total}`})`,
|
|
1908
2051
|
sections,
|
|
1909
|
-
state
|
|
2052
|
+
state,
|
|
2053
|
+
maxChars
|
|
1910
2054
|
);
|
|
1911
2055
|
}
|
|
1912
|
-
function renderTraversal(response) {
|
|
2056
|
+
function renderTraversal(response, maxChars) {
|
|
2057
|
+
const directSteps = Array.isArray(response) ? response : void 0;
|
|
1913
2058
|
const payload = obj(response);
|
|
1914
|
-
if (!payload) return void 0;
|
|
1915
|
-
const
|
|
2059
|
+
if (!payload && !directSteps) return void 0;
|
|
2060
|
+
const body = payload ?? {};
|
|
2061
|
+
const container = obj(body.graph) ?? body;
|
|
1916
2062
|
const rawNodes = Array.isArray(container.nodes) ? container.nodes : [];
|
|
1917
2063
|
const nodes = rawNodes.filter(isNodeShaped);
|
|
1918
|
-
const paths = Array.isArray(
|
|
1919
|
-
|
|
1920
|
-
const
|
|
2064
|
+
const paths = Array.isArray(body.paths) ? body.paths : [];
|
|
2065
|
+
const hasSteps = directSteps !== void 0 || Object.hasOwn(body, "steps");
|
|
2066
|
+
const rawSteps = directSteps ?? (Array.isArray(body.steps) ? body.steps : []);
|
|
2067
|
+
if (nodes.length === 0 && paths.length === 0 && !hasSteps) return void 0;
|
|
2068
|
+
const state = { bounded: false, omitted: 0 };
|
|
1921
2069
|
const sections = [];
|
|
1922
2070
|
const labelByUid = /* @__PURE__ */ new Map();
|
|
1923
2071
|
for (const node of nodes) labelByUid.set(str(node.uid), str(node.label) || "?");
|
|
@@ -1941,6 +2089,42 @@ function renderTraversal(response) {
|
|
|
1941
2089
|
});
|
|
1942
2090
|
sections.push({ heading: "## Paths", items });
|
|
1943
2091
|
}
|
|
2092
|
+
if (hasSteps) {
|
|
2093
|
+
const stepItems = rawSteps.map((raw) => obj(raw)).filter((step) => Boolean(step)).map((step) => {
|
|
2094
|
+
const depth = num(step.depth);
|
|
2095
|
+
const uid = str(step.node_uid) ?? str(step.uid) ?? str(step.edge_to_uid) ?? "?";
|
|
2096
|
+
const parent = str(step.parent_uid) ?? str(step.edge_from_uid);
|
|
2097
|
+
const label = str(step.label) || "(unlabeled)";
|
|
2098
|
+
const relation = edgeTypeName(step.edge_type);
|
|
2099
|
+
const role = str(step.traversal_role);
|
|
2100
|
+
const type = str(step.node_type) ?? str(obj(step.node_type)?.Custom);
|
|
2101
|
+
const cost = num(step.path_cost);
|
|
2102
|
+
const confidence = num(step.path_confidence);
|
|
2103
|
+
const prefix = [
|
|
2104
|
+
depth !== void 0 ? `depth ${depth}` : void 0,
|
|
2105
|
+
role,
|
|
2106
|
+
relation ? `\u2014${relation}\u2192` : void 0
|
|
2107
|
+
].filter(Boolean).join(" ");
|
|
2108
|
+
const meta = [
|
|
2109
|
+
type,
|
|
2110
|
+
parent ? `parent ${parent}` : void 0,
|
|
2111
|
+
cost !== void 0 ? `cost ${cost}` : void 0,
|
|
2112
|
+
confidence !== void 0 ? `confidence ${confidence}` : void 0
|
|
2113
|
+
].filter(Boolean).join(", ");
|
|
2114
|
+
return `- ${prefix ? `${prefix}: ` : ""}**${label}** [${uid}]${meta ? ` (${meta})` : ""}`;
|
|
2115
|
+
});
|
|
2116
|
+
if (stepItems.length > 0) {
|
|
2117
|
+
sections.push({ heading: "## Traversal steps", items: stepItems });
|
|
2118
|
+
} else {
|
|
2119
|
+
const start = str(body.start_uid) || "?";
|
|
2120
|
+
const end = str(body.end_uid);
|
|
2121
|
+
const mode2 = str(body.mode);
|
|
2122
|
+
sections.push({
|
|
2123
|
+
heading: mode2 === "path" && end ? `No path found from [${start}] to [${end}].` : `No traversal steps returned from [${start}].`,
|
|
2124
|
+
items: []
|
|
2125
|
+
});
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
1944
2128
|
if (nodes.length > 0) {
|
|
1945
2129
|
sections.push(...groupedNodeSections(nodes, state, "## Nodes\n\n"));
|
|
1946
2130
|
const relationships = relationshipItems(
|
|
@@ -1952,7 +2136,13 @@ function renderTraversal(response) {
|
|
|
1952
2136
|
sections.push({ heading: "## Relationships", items: relationships });
|
|
1953
2137
|
}
|
|
1954
2138
|
}
|
|
1955
|
-
|
|
2139
|
+
const mode = str(body.mode);
|
|
2140
|
+
return assemble(
|
|
2141
|
+
`# Graph traversal${mode ? ` (${mode})` : ""}`,
|
|
2142
|
+
sections,
|
|
2143
|
+
state,
|
|
2144
|
+
maxChars
|
|
2145
|
+
);
|
|
1956
2146
|
}
|
|
1957
2147
|
function neighborLine(value) {
|
|
1958
2148
|
const node = obj(value);
|
|
@@ -1973,7 +2163,7 @@ function renderOntologyAnswer(response) {
|
|
|
1973
2163
|
if (objects.length === 0 && cognitiveEmpty && provenance.length === 0) {
|
|
1974
2164
|
return hasQuerySignature ? "No matching domain objects." : void 0;
|
|
1975
2165
|
}
|
|
1976
|
-
const state = { bounded: false };
|
|
2166
|
+
const state = { bounded: false, omitted: 0 };
|
|
1977
2167
|
const sections = [];
|
|
1978
2168
|
if (objects.length > 0) {
|
|
1979
2169
|
sections.push(...groupedNodeSections(objects, state));
|
|
@@ -2039,7 +2229,7 @@ function renderObjectList(response, title) {
|
|
|
2039
2229
|
if (items.length === 0) {
|
|
2040
2230
|
return rawItems ? `# ${title} (0 results)` : void 0;
|
|
2041
2231
|
}
|
|
2042
|
-
const state = { bounded: false };
|
|
2232
|
+
const state = { bounded: false, omitted: 0 };
|
|
2043
2233
|
const sections = groupedNodeSections(items, state);
|
|
2044
2234
|
const total = num(payload.total_count);
|
|
2045
2235
|
const truncations = Array.isArray(payload.truncation_reasons) ? payload.truncation_reasons.filter((reason) => typeof reason === "string") : [];
|
|
@@ -2055,7 +2245,7 @@ function renderJobs(response) {
|
|
|
2055
2245
|
const jobs = Array.isArray(response) ? response : obj(response)?.jobs;
|
|
2056
2246
|
if (!Array.isArray(jobs)) return void 0;
|
|
2057
2247
|
if (jobs.length === 0) return "No ingestion jobs.";
|
|
2058
|
-
const state = { bounded: false };
|
|
2248
|
+
const state = { bounded: false, omitted: 0 };
|
|
2059
2249
|
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
2250
|
const shown = sorted.slice(0, JOBS_RENDER_MAX);
|
|
2061
2251
|
if (shown.length < sorted.length) state.bounded = true;
|
|
@@ -2081,7 +2271,7 @@ function renderJobs(response) {
|
|
|
2081
2271
|
function renderSignals(response) {
|
|
2082
2272
|
const payload = obj(response);
|
|
2083
2273
|
if (!payload) return void 0;
|
|
2084
|
-
const state = { bounded: false };
|
|
2274
|
+
const state = { bounded: false, omitted: 0 };
|
|
2085
2275
|
const sections = [];
|
|
2086
2276
|
for (const [key, value] of Object.entries(payload)) {
|
|
2087
2277
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
@@ -2106,11 +2296,585 @@ function renderSignals(response) {
|
|
|
2106
2296
|
return assemble("# Synthesis signals", sections, state);
|
|
2107
2297
|
}
|
|
2108
2298
|
|
|
2299
|
+
// src/memory-tool.ts
|
|
2300
|
+
var RESULT_SCHEMA_VERSION = "mindgraph.memory.result.v1";
|
|
2301
|
+
var DEFAULT_OUTPUT_CHARS = 8e3;
|
|
2302
|
+
var MIN_OUTPUT_CHARS = 512;
|
|
2303
|
+
var MAX_OUTPUT_CHARS = 24e3;
|
|
2304
|
+
var HIDDEN_CONTEXT_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
2305
|
+
var HIDDEN_CONTEXT_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
2306
|
+
var MEMORY_TOOL = {
|
|
2307
|
+
name: "mindgraph_memory",
|
|
2308
|
+
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.",
|
|
2309
|
+
inputSchema: {
|
|
2310
|
+
type: "object",
|
|
2311
|
+
properties: {
|
|
2312
|
+
action: {
|
|
2313
|
+
type: "string",
|
|
2314
|
+
enum: ["status", "context"],
|
|
2315
|
+
description: "Read integration status or bounded memory context"
|
|
2316
|
+
},
|
|
2317
|
+
mode: {
|
|
2318
|
+
type: "string",
|
|
2319
|
+
enum: ["topic", "continuity", "resume"],
|
|
2320
|
+
description: "Context strategy. topic uses query-shaped retrieval; continuity/resume use authoritative task-first resume_work."
|
|
2321
|
+
},
|
|
2322
|
+
query: {
|
|
2323
|
+
type: "string",
|
|
2324
|
+
description: "Required for mode='topic': 1-3 discriminating BM25 keywords, not a full sentence"
|
|
2325
|
+
},
|
|
2326
|
+
project_uid: { type: "string", description: "Optional project scope" },
|
|
2327
|
+
task_uid: { type: "string", description: "Optional task scope for resume context" },
|
|
2328
|
+
session_uid: { type: "string", description: "Optional durable session scope" },
|
|
2329
|
+
scope_uids: {
|
|
2330
|
+
type: "array",
|
|
2331
|
+
items: { type: "string" },
|
|
2332
|
+
description: "Optional explicit graph scopes for continuity/resume"
|
|
2333
|
+
},
|
|
2334
|
+
node_types: {
|
|
2335
|
+
type: "array",
|
|
2336
|
+
items: { type: "string" },
|
|
2337
|
+
description: "Optional node-type filter for topic context"
|
|
2338
|
+
},
|
|
2339
|
+
layer: {
|
|
2340
|
+
type: "string",
|
|
2341
|
+
enum: ["reality", "epistemic", "intent", "action", "memory", "agent"],
|
|
2342
|
+
description: "Optional cognitive-layer filter for topic context"
|
|
2343
|
+
},
|
|
2344
|
+
limit: {
|
|
2345
|
+
type: "integer",
|
|
2346
|
+
minimum: 1,
|
|
2347
|
+
maximum: 50,
|
|
2348
|
+
default: 8,
|
|
2349
|
+
description: "Maximum direct graph items requested before bounded expansion"
|
|
2350
|
+
},
|
|
2351
|
+
include_chunks: {
|
|
2352
|
+
type: "boolean",
|
|
2353
|
+
default: false,
|
|
2354
|
+
description: "Include bounded source excerpts when topic summaries are insufficient"
|
|
2355
|
+
},
|
|
2356
|
+
include_documents: {
|
|
2357
|
+
type: "boolean",
|
|
2358
|
+
default: false,
|
|
2359
|
+
description: "Include bounded knowledge articles for topic context"
|
|
2360
|
+
},
|
|
2361
|
+
valid_at: {
|
|
2362
|
+
type: "string",
|
|
2363
|
+
description: "Optional ISO timestamp for time-aware topic retrieval"
|
|
2364
|
+
},
|
|
2365
|
+
graph_expansion_limit: {
|
|
2366
|
+
type: "integer",
|
|
2367
|
+
minimum: 0,
|
|
2368
|
+
maximum: 20,
|
|
2369
|
+
default: 3,
|
|
2370
|
+
description: "Bounded graph neighbors added after direct topic matches"
|
|
2371
|
+
},
|
|
2372
|
+
graph_max_depth: {
|
|
2373
|
+
type: "integer",
|
|
2374
|
+
minimum: 0,
|
|
2375
|
+
maximum: 5,
|
|
2376
|
+
default: 2,
|
|
2377
|
+
description: "Maximum graph-expansion depth for topic context"
|
|
2378
|
+
},
|
|
2379
|
+
max_output_chars: {
|
|
2380
|
+
type: "integer",
|
|
2381
|
+
minimum: MIN_OUTPUT_CHARS,
|
|
2382
|
+
maximum: MAX_OUTPUT_CHARS,
|
|
2383
|
+
default: DEFAULT_OUTPUT_CHARS,
|
|
2384
|
+
description: "Hard character budget for model-ready context; whole items are retained or omitted"
|
|
2385
|
+
},
|
|
2386
|
+
agent_id: { type: "string", description: "Agent identity" }
|
|
2387
|
+
},
|
|
2388
|
+
required: ["action"]
|
|
2389
|
+
},
|
|
2390
|
+
outputSchema: {
|
|
2391
|
+
type: "object",
|
|
2392
|
+
properties: {
|
|
2393
|
+
schema_version: { type: "string", const: RESULT_SCHEMA_VERSION },
|
|
2394
|
+
action: { type: "string", enum: ["status", "context"] },
|
|
2395
|
+
profile: { type: "string" },
|
|
2396
|
+
server: { type: "object" },
|
|
2397
|
+
integration: { type: "object" },
|
|
2398
|
+
capabilities: { type: "object" },
|
|
2399
|
+
degradation: { type: "array", items: { type: "object" } },
|
|
2400
|
+
context_id: { type: "string" },
|
|
2401
|
+
mode: { type: "string", enum: ["topic", "continuity", "resume"] },
|
|
2402
|
+
scope: { type: "object" },
|
|
2403
|
+
rendered_context: { type: "string" },
|
|
2404
|
+
rendered_hash: { type: "string" },
|
|
2405
|
+
items: { type: "array", items: { type: "object" } },
|
|
2406
|
+
retrieval_trace: { type: "object" },
|
|
2407
|
+
budget: { type: "object" },
|
|
2408
|
+
freshness: { type: "object" },
|
|
2409
|
+
warnings: { type: "array", items: { type: "object" } }
|
|
2410
|
+
},
|
|
2411
|
+
required: ["schema_version", "action"],
|
|
2412
|
+
oneOf: [
|
|
2413
|
+
{
|
|
2414
|
+
properties: { action: { const: "status" } },
|
|
2415
|
+
required: ["profile", "server", "integration", "scope", "capabilities", "degradation"]
|
|
2416
|
+
},
|
|
2417
|
+
{
|
|
2418
|
+
properties: { action: { const: "context" } },
|
|
2419
|
+
required: [
|
|
2420
|
+
"context_id",
|
|
2421
|
+
"mode",
|
|
2422
|
+
"scope",
|
|
2423
|
+
"rendered_context",
|
|
2424
|
+
"rendered_hash",
|
|
2425
|
+
"items",
|
|
2426
|
+
"retrieval_trace",
|
|
2427
|
+
"budget",
|
|
2428
|
+
"freshness",
|
|
2429
|
+
"warnings"
|
|
2430
|
+
]
|
|
2431
|
+
}
|
|
2432
|
+
]
|
|
2433
|
+
},
|
|
2434
|
+
annotations: {
|
|
2435
|
+
readOnlyHint: true,
|
|
2436
|
+
destructiveHint: false,
|
|
2437
|
+
idempotentHint: true,
|
|
2438
|
+
openWorldHint: false
|
|
2439
|
+
}
|
|
2440
|
+
};
|
|
2441
|
+
function obj2(value) {
|
|
2442
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2443
|
+
}
|
|
2444
|
+
function text(value) {
|
|
2445
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2446
|
+
}
|
|
2447
|
+
function stableJson(value) {
|
|
2448
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
2449
|
+
if (value && typeof value === "object") {
|
|
2450
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
2451
|
+
}
|
|
2452
|
+
return JSON.stringify(value);
|
|
2453
|
+
}
|
|
2454
|
+
function sha256(value) {
|
|
2455
|
+
return (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex");
|
|
2456
|
+
}
|
|
2457
|
+
function outputBudget(value) {
|
|
2458
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_OUTPUT_CHARS;
|
|
2459
|
+
return Math.min(MAX_OUTPUT_CHARS, Math.max(MIN_OUTPUT_CHARS, Math.floor(value)));
|
|
2460
|
+
}
|
|
2461
|
+
function defined(values) {
|
|
2462
|
+
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
|
|
2463
|
+
}
|
|
2464
|
+
function memoryStatus(config = {}) {
|
|
2465
|
+
return {
|
|
2466
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
2467
|
+
action: "status",
|
|
2468
|
+
profile: "M0",
|
|
2469
|
+
server: defined({
|
|
2470
|
+
name: "mindgraph-mcp",
|
|
2471
|
+
version: config.serverVersion ?? "unknown",
|
|
2472
|
+
base_url: config.baseUrl
|
|
2473
|
+
}),
|
|
2474
|
+
integration: {
|
|
2475
|
+
adapter_state: "model_controlled",
|
|
2476
|
+
harness: config.harness ?? "generic",
|
|
2477
|
+
configured_tool_profile: config.profile ?? "general",
|
|
2478
|
+
automatic_capture: false,
|
|
2479
|
+
automatic_delivery: false,
|
|
2480
|
+
delivery_verification: "unsupported",
|
|
2481
|
+
curator_mode: "disabled"
|
|
2482
|
+
},
|
|
2483
|
+
scope: defined({ org_id: config.orgId, agent_id: config.agentId }),
|
|
2484
|
+
capabilities: {
|
|
2485
|
+
status: true,
|
|
2486
|
+
topic_context: true,
|
|
2487
|
+
authoritative_resume_context: true,
|
|
2488
|
+
bounded_rendering: true,
|
|
2489
|
+
structured_content: true,
|
|
2490
|
+
typed_explicit_writes: true,
|
|
2491
|
+
lifecycle_event_ingest: false,
|
|
2492
|
+
automatic_context_injection: false,
|
|
2493
|
+
curator_mutation: false
|
|
2494
|
+
},
|
|
2495
|
+
degradation: [
|
|
2496
|
+
{
|
|
2497
|
+
code: "automatic_capture_unavailable",
|
|
2498
|
+
message: "M0 does not observe host lifecycle events; explicit typed write tools remain available."
|
|
2499
|
+
},
|
|
2500
|
+
{
|
|
2501
|
+
code: "delivery_unverified",
|
|
2502
|
+
message: "A successful MCP read does not prove that the host injected or used the returned context."
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
code: "curator_disabled",
|
|
2506
|
+
message: "Curator proposals and autonomous mutation are not enabled in M0."
|
|
2507
|
+
}
|
|
2508
|
+
]
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
function nodeType(node) {
|
|
2512
|
+
const raw = node.node_type;
|
|
2513
|
+
if (typeof raw === "string") return raw;
|
|
2514
|
+
return text(obj2(raw)?.Custom) ?? "Node";
|
|
2515
|
+
}
|
|
2516
|
+
function compactItem(raw, fallbackType) {
|
|
2517
|
+
const wrapper = obj2(raw);
|
|
2518
|
+
if (!wrapper) return void 0;
|
|
2519
|
+
const value = obj2(wrapper.node) ?? obj2(wrapper.object) ?? wrapper;
|
|
2520
|
+
const uid = text(value.uid) ?? text(value.chunk_uid);
|
|
2521
|
+
if (!uid) return void 0;
|
|
2522
|
+
return defined({
|
|
2523
|
+
uid,
|
|
2524
|
+
type: fallbackType ?? nodeType(value),
|
|
2525
|
+
label: text(value.label) ?? text(value.document_title),
|
|
2526
|
+
truth_status: text(value.truth_status) ?? text(obj2(value.props)?.truth_status),
|
|
2527
|
+
superseded: value.superseded === true ? true : void 0,
|
|
2528
|
+
currently_valid: value.currently_valid === false ? false : void 0,
|
|
2529
|
+
valid_at_time: value.valid_at_time === false ? false : void 0,
|
|
2530
|
+
retrieval_origin: text(value.retrieval_origin),
|
|
2531
|
+
retrieval_depth: typeof value.retrieval_depth === "number" ? value.retrieval_depth : void 0
|
|
2532
|
+
});
|
|
2533
|
+
}
|
|
2534
|
+
function topicCandidates(raw) {
|
|
2535
|
+
const payload = obj2(raw);
|
|
2536
|
+
if (!payload) return [];
|
|
2537
|
+
const graph = obj2(payload.graph);
|
|
2538
|
+
const items = [];
|
|
2539
|
+
for (const article of Array.isArray(payload.articles) ? payload.articles : []) {
|
|
2540
|
+
const item = compactItem(article, "Article");
|
|
2541
|
+
if (item) items.push(item);
|
|
2542
|
+
}
|
|
2543
|
+
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
2544
|
+
const labels = /* @__PURE__ */ new Map();
|
|
2545
|
+
for (const node of rawNodes) {
|
|
2546
|
+
const item = compactItem(node);
|
|
2547
|
+
if (item) {
|
|
2548
|
+
if (HIDDEN_CONTEXT_NODE_TYPES.has(text(item.type) ?? "")) continue;
|
|
2549
|
+
items.push(item);
|
|
2550
|
+
const uid = text(item.uid);
|
|
2551
|
+
const label = text(item.label);
|
|
2552
|
+
if (uid && label) labels.set(uid, label);
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
for (const rawEdge of Array.isArray(graph?.edges) ? graph.edges : []) {
|
|
2556
|
+
const edge = obj2(rawEdge);
|
|
2557
|
+
const fromUid = text(edge?.from_uid);
|
|
2558
|
+
const toUid = text(edge?.to_uid);
|
|
2559
|
+
const edgeType = text(edge?.edge_type) ?? text(obj2(edge?.edge_type)?.Custom);
|
|
2560
|
+
if (!fromUid || !toUid || !edgeType || HIDDEN_CONTEXT_EDGE_TYPES.has(edgeType) || !labels.has(fromUid) || !labels.has(toUid)) {
|
|
2561
|
+
continue;
|
|
2562
|
+
}
|
|
2563
|
+
items.push(
|
|
2564
|
+
defined({
|
|
2565
|
+
type: "Relationship",
|
|
2566
|
+
from_uid: fromUid,
|
|
2567
|
+
to_uid: toUid,
|
|
2568
|
+
edge_type: edgeType,
|
|
2569
|
+
from_label: labels.get(fromUid),
|
|
2570
|
+
to_label: labels.get(toUid)
|
|
2571
|
+
})
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2574
|
+
for (const chunk of Array.isArray(payload.chunks) ? payload.chunks : []) {
|
|
2575
|
+
const item = compactItem(chunk, "SourceExcerpt");
|
|
2576
|
+
if (item) items.push(item);
|
|
2577
|
+
}
|
|
2578
|
+
return items;
|
|
2579
|
+
}
|
|
2580
|
+
function resumeCandidates(raw) {
|
|
2581
|
+
const payload = obj2(raw);
|
|
2582
|
+
if (!payload) return [];
|
|
2583
|
+
const items = [];
|
|
2584
|
+
for (const key of ["task", "goal", "project", "plan", "active_execution", "lease"]) {
|
|
2585
|
+
const item = compactItem(payload[key], key);
|
|
2586
|
+
if (item) items.push(item);
|
|
2587
|
+
}
|
|
2588
|
+
for (const key of ["next_steps", "recent_executions", "blockers", "code_targets"]) {
|
|
2589
|
+
for (const value of Array.isArray(payload[key]) ? payload[key] : []) {
|
|
2590
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
2591
|
+
if (item) items.push(item);
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
const knowledge = obj2(payload.knowledge);
|
|
2595
|
+
for (const key of ["lessons", "risks"]) {
|
|
2596
|
+
for (const value of Array.isArray(knowledge?.[key]) ? knowledge[key] : []) {
|
|
2597
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
2598
|
+
if (item) items.push(item);
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
return items;
|
|
2602
|
+
}
|
|
2603
|
+
function visibleItems(candidates, rendered2) {
|
|
2604
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2605
|
+
return candidates.filter((item) => {
|
|
2606
|
+
const uid = text(item.uid);
|
|
2607
|
+
if (uid) {
|
|
2608
|
+
if (seen.has(uid) || !rendered2.includes(`[${uid}]`)) return false;
|
|
2609
|
+
seen.add(uid);
|
|
2610
|
+
return true;
|
|
2611
|
+
}
|
|
2612
|
+
if (item.type === "Relationship") {
|
|
2613
|
+
const from = text(item.from_label);
|
|
2614
|
+
const to = text(item.to_label);
|
|
2615
|
+
const edgeType = text(item.edge_type);
|
|
2616
|
+
if (!from || !to || !edgeType) return false;
|
|
2617
|
+
const key = `${text(item.from_uid)}:${edgeType}:${text(item.to_uid)}`;
|
|
2618
|
+
if (seen.has(key) || !rendered2.includes(`${from} \u2014${edgeType}\u2192 ${to}`)) return false;
|
|
2619
|
+
seen.add(key);
|
|
2620
|
+
return true;
|
|
2621
|
+
}
|
|
2622
|
+
return false;
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
function latestTimestamp(value) {
|
|
2626
|
+
let latest;
|
|
2627
|
+
const visit = (current) => {
|
|
2628
|
+
if (Array.isArray(current)) {
|
|
2629
|
+
for (const item of current) visit(item);
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
const record = obj2(current);
|
|
2633
|
+
if (!record) return;
|
|
2634
|
+
for (const [key, item] of Object.entries(record)) {
|
|
2635
|
+
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))) {
|
|
2636
|
+
latest = item;
|
|
2637
|
+
}
|
|
2638
|
+
visit(item);
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
visit(value);
|
|
2642
|
+
return latest;
|
|
2643
|
+
}
|
|
2644
|
+
function contextWarnings(raw, rendered2, available, returned) {
|
|
2645
|
+
const warnings = [
|
|
2646
|
+
{
|
|
2647
|
+
code: "delivery_unverified",
|
|
2648
|
+
message: "The MCP server returned this context but cannot verify that the host injected or used it."
|
|
2649
|
+
}
|
|
2650
|
+
];
|
|
2651
|
+
const serialized = JSON.stringify(raw);
|
|
2652
|
+
if (available > returned || rendered2.includes("item(s) omitted")) {
|
|
2653
|
+
warnings.push({
|
|
2654
|
+
code: "context_bounded",
|
|
2655
|
+
message: `${Math.max(0, available - returned)} structured item(s) were omitted from the rendered context.`
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
if (/"superseded":true/.test(serialized)) {
|
|
2659
|
+
warnings.push({ code: "superseded_items_present", message: "Some retrieved items are superseded." });
|
|
2660
|
+
}
|
|
2661
|
+
if (/"currently_valid":false|"valid_at_time":false/.test(serialized)) {
|
|
2662
|
+
warnings.push({
|
|
2663
|
+
code: "validity_warning",
|
|
2664
|
+
message: "Some retrieved items are outside their current or requested validity window."
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
const payload = obj2(raw);
|
|
2668
|
+
if (payload?.truncated === true || obj2(payload?.truncation)) {
|
|
2669
|
+
const truncation = obj2(payload?.truncation);
|
|
2670
|
+
if (payload?.truncated === true || Object.values(truncation ?? {}).some(Boolean)) {
|
|
2671
|
+
warnings.push({ code: "source_truncated", message: "The authoritative source reported truncated fields." });
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
if (text(payload?.warning)) {
|
|
2675
|
+
warnings.push({ code: "source_warning", message: text(payload?.warning) });
|
|
2676
|
+
}
|
|
2677
|
+
return warnings;
|
|
2678
|
+
}
|
|
2679
|
+
function error(message) {
|
|
2680
|
+
return {
|
|
2681
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
2682
|
+
isError: true
|
|
2683
|
+
};
|
|
2684
|
+
}
|
|
2685
|
+
async function handleMemoryTool(client2, args, config = {}) {
|
|
2686
|
+
const action = text(args.action);
|
|
2687
|
+
if (action === "status") {
|
|
2688
|
+
const status = memoryStatus({ ...config, agentId: text(args.agent_id) ?? config.agentId });
|
|
2689
|
+
return {
|
|
2690
|
+
content: [{ type: "text", text: JSON.stringify(status) }],
|
|
2691
|
+
structuredContent: status
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
if (action !== "context") {
|
|
2695
|
+
return error("action must be 'status' or 'context'");
|
|
2696
|
+
}
|
|
2697
|
+
const mode = text(args.mode) ?? (text(args.query) ? "topic" : void 0);
|
|
2698
|
+
if (!mode || !["topic", "continuity", "resume"].includes(mode)) {
|
|
2699
|
+
return error("action='context' requires mode='topic', 'continuity', or 'resume'");
|
|
2700
|
+
}
|
|
2701
|
+
const budget = outputBudget(args.max_output_chars);
|
|
2702
|
+
const agentId = text(args.agent_id) ?? config.agentId;
|
|
2703
|
+
let raw;
|
|
2704
|
+
let rendered2;
|
|
2705
|
+
let strategy;
|
|
2706
|
+
let candidates;
|
|
2707
|
+
if (mode === "topic") {
|
|
2708
|
+
const query = text(args.query);
|
|
2709
|
+
if (!query) return error("mode='topic' requires a non-empty query of 1-3 discriminating keywords");
|
|
2710
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.min(50, Math.max(1, Math.floor(args.limit))) : 8;
|
|
2711
|
+
const request = defined({
|
|
2712
|
+
query,
|
|
2713
|
+
project_uid: text(args.project_uid),
|
|
2714
|
+
node_limit: limit,
|
|
2715
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2716
|
+
layer: text(args.layer),
|
|
2717
|
+
chunk_limit: args.include_chunks === true ? limit : 0,
|
|
2718
|
+
article_limit: args.include_documents === true ? limit : 0,
|
|
2719
|
+
valid_at: text(args.valid_at),
|
|
2720
|
+
include_graph: true,
|
|
2721
|
+
graph_expansion_limit: typeof args.graph_expansion_limit === "number" ? args.graph_expansion_limit : 3,
|
|
2722
|
+
graph_max_depth: typeof args.graph_max_depth === "number" ? args.graph_max_depth : 2
|
|
2723
|
+
});
|
|
2724
|
+
raw = await client2.retrieveContext(request);
|
|
2725
|
+
rendered2 = renderContext(raw, budget) ?? "No results found for this search.";
|
|
2726
|
+
strategy = "retrieve_context";
|
|
2727
|
+
candidates = topicCandidates(raw);
|
|
2728
|
+
} else {
|
|
2729
|
+
const scopeUids = Array.from(
|
|
2730
|
+
/* @__PURE__ */ new Set([
|
|
2731
|
+
...Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : [],
|
|
2732
|
+
...text(args.project_uid) ? [text(args.project_uid)] : []
|
|
2733
|
+
])
|
|
2734
|
+
);
|
|
2735
|
+
raw = await client2.plan(
|
|
2736
|
+
defined({
|
|
2737
|
+
action: "resume_work",
|
|
2738
|
+
task_uid: text(args.task_uid),
|
|
2739
|
+
session_uid: text(args.session_uid),
|
|
2740
|
+
scope_uids: scopeUids.length > 0 ? scopeUids : void 0,
|
|
2741
|
+
limit: 1,
|
|
2742
|
+
agent_id: agentId
|
|
2743
|
+
})
|
|
2744
|
+
);
|
|
2745
|
+
rendered2 = renderResumeContext(raw, budget) ?? "No eligible work was found in the requested scope.";
|
|
2746
|
+
strategy = "resume_work";
|
|
2747
|
+
candidates = resumeCandidates(raw);
|
|
2748
|
+
}
|
|
2749
|
+
const items = visibleItems(candidates, rendered2);
|
|
2750
|
+
const renderedHash = sha256(rendered2);
|
|
2751
|
+
const scope = defined({
|
|
2752
|
+
org_id: config.orgId,
|
|
2753
|
+
agent_id: agentId,
|
|
2754
|
+
harness: config.harness ?? "generic",
|
|
2755
|
+
project_uid: text(args.project_uid),
|
|
2756
|
+
task_uid: text(args.task_uid),
|
|
2757
|
+
session_uid: text(args.session_uid),
|
|
2758
|
+
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0
|
|
2759
|
+
});
|
|
2760
|
+
const contextId = `ctx_${sha256(
|
|
2761
|
+
stableJson({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
2762
|
+
).slice(0, 24)}`;
|
|
2763
|
+
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
2764
|
+
const result = {
|
|
2765
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
2766
|
+
action: "context",
|
|
2767
|
+
context_id: contextId,
|
|
2768
|
+
mode,
|
|
2769
|
+
scope,
|
|
2770
|
+
rendered_context: rendered2,
|
|
2771
|
+
rendered_hash: renderedHash,
|
|
2772
|
+
items,
|
|
2773
|
+
retrieval_trace: defined({
|
|
2774
|
+
strategy,
|
|
2775
|
+
query: text(args.query),
|
|
2776
|
+
project_uid: text(args.project_uid),
|
|
2777
|
+
task_uid: text(args.task_uid),
|
|
2778
|
+
session_uid: text(args.session_uid),
|
|
2779
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
2780
|
+
graph_expansion_limit: mode === "topic" ? args.graph_expansion_limit ?? 3 : void 0,
|
|
2781
|
+
graph_max_depth: mode === "topic" ? args.graph_max_depth ?? 2 : void 0,
|
|
2782
|
+
available_items: candidates.length,
|
|
2783
|
+
returned_items: items.length,
|
|
2784
|
+
omitted_items: Math.max(0, candidates.length - items.length)
|
|
2785
|
+
}),
|
|
2786
|
+
budget: {
|
|
2787
|
+
unit: "characters",
|
|
2788
|
+
requested_chars: budget,
|
|
2789
|
+
used_chars: rendered2.length,
|
|
2790
|
+
available_items: candidates.length,
|
|
2791
|
+
returned_items: items.length,
|
|
2792
|
+
omitted_items: Math.max(0, candidates.length - items.length),
|
|
2793
|
+
bounded
|
|
2794
|
+
},
|
|
2795
|
+
freshness: defined({
|
|
2796
|
+
valid_at: text(args.valid_at),
|
|
2797
|
+
latest_source_timestamp: latestTimestamp(raw)
|
|
2798
|
+
}),
|
|
2799
|
+
warnings: contextWarnings(raw, rendered2, candidates.length, items.length)
|
|
2800
|
+
};
|
|
2801
|
+
return {
|
|
2802
|
+
content: [{ type: "text", text: rendered2 }],
|
|
2803
|
+
structuredContent: result
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2109
2807
|
// src/tools.ts
|
|
2808
|
+
var RESOLUTION_PROPERTIES = {
|
|
2809
|
+
idempotency_key: {
|
|
2810
|
+
type: "string",
|
|
2811
|
+
description: "Stable retry key; a mismatched replay is rejected"
|
|
2812
|
+
},
|
|
2813
|
+
reuse_uid: {
|
|
2814
|
+
type: "string",
|
|
2815
|
+
description: "Reuse this live same-scope node after a duplicate response"
|
|
2816
|
+
},
|
|
2817
|
+
supersedes_uid: {
|
|
2818
|
+
type: "string",
|
|
2819
|
+
description: "Create and mark this same-scope node as superseded"
|
|
2820
|
+
},
|
|
2821
|
+
contradicts_uid: {
|
|
2822
|
+
type: "string",
|
|
2823
|
+
description: "Create and mark this same-scope node as contradicted"
|
|
2824
|
+
},
|
|
2825
|
+
confirm_new: {
|
|
2826
|
+
type: "boolean",
|
|
2827
|
+
description: "Confirm that the new fact is genuinely distinct"
|
|
2828
|
+
},
|
|
2829
|
+
on_near_duplicate: {
|
|
2830
|
+
type: "string",
|
|
2831
|
+
enum: ["create"],
|
|
2832
|
+
description: "Alias for confirm_new on a near-duplicate response"
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2835
|
+
function stableJson2(value) {
|
|
2836
|
+
if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
|
|
2837
|
+
if (value && typeof value === "object") {
|
|
2838
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson2(item)}`).join(",")}}`;
|
|
2839
|
+
}
|
|
2840
|
+
return JSON.stringify(value);
|
|
2841
|
+
}
|
|
2842
|
+
function defaultWriteIdempotencyKey(tool, args) {
|
|
2843
|
+
if (typeof args.idempotency_key === "string") return args.idempotency_key;
|
|
2844
|
+
const context = args.invocation_context;
|
|
2845
|
+
const sessionId = context?.harnessSessionId;
|
|
2846
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) return void 0;
|
|
2847
|
+
const canonicalArgs = Object.fromEntries(
|
|
2848
|
+
Object.entries(args).filter(
|
|
2849
|
+
([key]) => key !== "invocation_context" && key !== "idempotency_key"
|
|
2850
|
+
)
|
|
2851
|
+
);
|
|
2852
|
+
return (0, import_node_crypto5.createHash)("sha256").update(
|
|
2853
|
+
stableJson2({
|
|
2854
|
+
harness_session_id: sessionId,
|
|
2855
|
+
harness_turn_id: context?.harnessTurnId ?? null,
|
|
2856
|
+
tool,
|
|
2857
|
+
action: args.action ?? null,
|
|
2858
|
+
args: canonicalArgs
|
|
2859
|
+
})
|
|
2860
|
+
).digest("hex");
|
|
2861
|
+
}
|
|
2862
|
+
function resolutionFields(args) {
|
|
2863
|
+
return Object.fromEntries(
|
|
2864
|
+
[
|
|
2865
|
+
"idempotency_key",
|
|
2866
|
+
"reuse_uid",
|
|
2867
|
+
"supersedes_uid",
|
|
2868
|
+
"contradicts_uid",
|
|
2869
|
+
"confirm_new",
|
|
2870
|
+
"on_near_duplicate"
|
|
2871
|
+
].filter((key) => args[key] !== void 0).map((key) => [key, args[key]])
|
|
2872
|
+
);
|
|
2873
|
+
}
|
|
2110
2874
|
var TOOLS = [
|
|
2111
2875
|
{
|
|
2112
2876
|
name: "mindgraph_capture",
|
|
2113
|
-
description: "Capture knowledge into the graph. Use 'entity' for people/orgs/places/events/nations/concepts (auto-deduplicates \u2014 safe to call even if already exists), 'observation' for factual statements, 'source' for documents/URLs, 'snippet' for quotes from a source, and 'concept' for abstract ideas. Use 'journal' for quick personal notes
|
|
2877
|
+
description: "Capture knowledge into the graph. Use 'entity' for people/orgs/places/events/nations/concepts (auto-deduplicates \u2014 safe to call even if already exists), 'observation' for factual statements, 'source' for documents/URLs, 'snippet' for quotes from a source, and 'concept' for abstract ideas. Use 'journal' for quick personal notes, 'lesson' for a durable learning, and 'skill' for a reusable procedure authored from completed work. Skill capture always creates a candidate requiring admin review; it never publishes. Skill names must be 1-64 lowercase a-z, digits, or hyphens, with no leading/trailing/consecutive hyphens and no 'anthropic' or 'claude'. Provide at least one provenance field and write instructions, not a transcript dump.",
|
|
2114
2878
|
inputSchema: {
|
|
2115
2879
|
type: "object",
|
|
2116
2880
|
properties: {
|
|
@@ -2123,7 +2887,8 @@ var TOOLS = [
|
|
|
2123
2887
|
"snippet",
|
|
2124
2888
|
"concept",
|
|
2125
2889
|
"journal",
|
|
2126
|
-
"lesson"
|
|
2890
|
+
"lesson",
|
|
2891
|
+
"skill"
|
|
2127
2892
|
],
|
|
2128
2893
|
description: "Type of knowledge to capture"
|
|
2129
2894
|
},
|
|
@@ -2137,11 +2902,30 @@ var TOOLS = [
|
|
|
2137
2902
|
},
|
|
2138
2903
|
content: {
|
|
2139
2904
|
type: "string",
|
|
2140
|
-
|
|
2905
|
+
maxLength: 65536,
|
|
2906
|
+
description: "Journal body (action=journal) or complete SKILL.md instructions, at most 64 KiB UTF-8 (action=skill)"
|
|
2907
|
+
},
|
|
2908
|
+
name: {
|
|
2909
|
+
type: "string",
|
|
2910
|
+
minLength: 1,
|
|
2911
|
+
maxLength: 64,
|
|
2912
|
+
pattern: "^(?!.*(?:anthropic|claude))(?!-)(?!.*--)[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$",
|
|
2913
|
+
description: "Stable skill identifier using lowercase a-z, digits, and hyphens (for action=skill)"
|
|
2914
|
+
},
|
|
2915
|
+
description: {
|
|
2916
|
+
type: "string",
|
|
2917
|
+
minLength: 1,
|
|
2918
|
+
maxLength: 1024,
|
|
2919
|
+
description: "When the skill should be used; XML tags are rejected (for action=skill)"
|
|
2920
|
+
},
|
|
2921
|
+
license: {
|
|
2922
|
+
type: "string",
|
|
2923
|
+
description: "Optional skill license (for action=skill)"
|
|
2141
2924
|
},
|
|
2142
2925
|
session_uid: {
|
|
2143
2926
|
type: "string",
|
|
2144
|
-
|
|
2927
|
+
minLength: 1,
|
|
2928
|
+
description: "Session UID that produced a lesson or skill"
|
|
2145
2929
|
},
|
|
2146
2930
|
work_uid: {
|
|
2147
2931
|
type: "string",
|
|
@@ -2151,18 +2935,12 @@ var TOOLS = [
|
|
|
2151
2935
|
type: "string",
|
|
2152
2936
|
description: "Material Execution that produced the lesson"
|
|
2153
2937
|
},
|
|
2154
|
-
|
|
2155
|
-
type: "string",
|
|
2156
|
-
description: "Stable retry key for an intentional capture"
|
|
2157
|
-
},
|
|
2158
|
-
supersedes_uid: {
|
|
2159
|
-
type: "string",
|
|
2160
|
-
description: "Earlier capture corrected or superseded by this one"
|
|
2161
|
-
},
|
|
2938
|
+
...RESOLUTION_PROPERTIES,
|
|
2162
2939
|
summarizes_uids: {
|
|
2163
2940
|
type: "array",
|
|
2164
2941
|
items: { type: "string" },
|
|
2165
|
-
|
|
2942
|
+
minItems: 1,
|
|
2943
|
+
description: "Source node UIDs the lesson or skill was learned from"
|
|
2166
2944
|
},
|
|
2167
2945
|
entity_type: {
|
|
2168
2946
|
type: "string",
|
|
@@ -2229,7 +3007,24 @@ var TOOLS = [
|
|
|
2229
3007
|
description: "Agent identity"
|
|
2230
3008
|
}
|
|
2231
3009
|
},
|
|
2232
|
-
required: ["action", "label"]
|
|
3010
|
+
required: ["action", "label"],
|
|
3011
|
+
allOf: [
|
|
3012
|
+
{
|
|
3013
|
+
if: {
|
|
3014
|
+
properties: { action: { const: "skill" } },
|
|
3015
|
+
required: ["action"]
|
|
3016
|
+
},
|
|
3017
|
+
then: {
|
|
3018
|
+
required: ["name", "description", "content"],
|
|
3019
|
+
anyOf: [
|
|
3020
|
+
{ required: ["session_uid"] },
|
|
3021
|
+
{ required: ["work_uid"] },
|
|
3022
|
+
{ required: ["execution_uid"] },
|
|
3023
|
+
{ required: ["summarizes_uids"] }
|
|
3024
|
+
]
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
]
|
|
2233
3028
|
}
|
|
2234
3029
|
},
|
|
2235
3030
|
{
|
|
@@ -2238,6 +3033,7 @@ var TOOLS = [
|
|
|
2238
3033
|
inputSchema: {
|
|
2239
3034
|
type: "object",
|
|
2240
3035
|
properties: {
|
|
3036
|
+
...RESOLUTION_PROPERTIES,
|
|
2241
3037
|
action: {
|
|
2242
3038
|
type: "string",
|
|
2243
3039
|
enum: [
|
|
@@ -2332,6 +3128,7 @@ var TOOLS = [
|
|
|
2332
3128
|
inputSchema: {
|
|
2333
3129
|
type: "object",
|
|
2334
3130
|
properties: {
|
|
3131
|
+
...RESOLUTION_PROPERTIES,
|
|
2335
3132
|
action: {
|
|
2336
3133
|
type: "string",
|
|
2337
3134
|
enum: [
|
|
@@ -2690,6 +3487,12 @@ var TOOLS = [
|
|
|
2690
3487
|
enum: ["text", "json"],
|
|
2691
3488
|
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)."
|
|
2692
3489
|
},
|
|
3490
|
+
max_output_chars: {
|
|
3491
|
+
type: "integer",
|
|
3492
|
+
minimum: 512,
|
|
3493
|
+
maximum: 24e3,
|
|
3494
|
+
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'."
|
|
3495
|
+
},
|
|
2693
3496
|
query: {
|
|
2694
3497
|
type: "string",
|
|
2695
3498
|
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."
|
|
@@ -2815,6 +3618,42 @@ var TOOLS = [
|
|
|
2815
3618
|
required: ["action"]
|
|
2816
3619
|
}
|
|
2817
3620
|
},
|
|
3621
|
+
{
|
|
3622
|
+
name: "mindgraph_series_query",
|
|
3623
|
+
description: "Read dense numeric time series without placing raw points in general retrieval context. Use list_for_entity to discover series, latest for cached statistics, window for [from,to) keyset pages, and aggregate for bounded calendar buckets.",
|
|
3624
|
+
inputSchema: {
|
|
3625
|
+
type: "object",
|
|
3626
|
+
additionalProperties: false,
|
|
3627
|
+
properties: {
|
|
3628
|
+
action: {
|
|
3629
|
+
type: "string",
|
|
3630
|
+
enum: ["list_for_entity", "latest", "window", "aggregate"]
|
|
3631
|
+
},
|
|
3632
|
+
entity_uid: { type: "string" },
|
|
3633
|
+
series_uid: { type: "string" },
|
|
3634
|
+
from: { type: "number" },
|
|
3635
|
+
to: { type: "number" },
|
|
3636
|
+
cursor: { type: "number" },
|
|
3637
|
+
limit: { type: "number", minimum: 1, maximum: 1e4 },
|
|
3638
|
+
bucket: {
|
|
3639
|
+
type: "string",
|
|
3640
|
+
enum: ["year", "quarter", "month", "week", "day", "hour"]
|
|
3641
|
+
},
|
|
3642
|
+
agg: {
|
|
3643
|
+
type: "string",
|
|
3644
|
+
enum: ["sum", "mean", "min", "max", "count", "std_dev", "last"]
|
|
3645
|
+
},
|
|
3646
|
+
fill: { type: "string", enum: ["none", "null", "prev"] }
|
|
3647
|
+
},
|
|
3648
|
+
required: ["action"]
|
|
3649
|
+
},
|
|
3650
|
+
annotations: {
|
|
3651
|
+
readOnlyHint: true,
|
|
3652
|
+
destructiveHint: false,
|
|
3653
|
+
idempotentHint: true,
|
|
3654
|
+
openWorldHint: false
|
|
3655
|
+
}
|
|
3656
|
+
},
|
|
2818
3657
|
{
|
|
2819
3658
|
name: "mindgraph_ingest",
|
|
2820
3659
|
description: "Ingest long-form content (articles, transcripts, documents, meeting notes) into the knowledge graph. The pipeline automatically chunks the text, extracts entities/claims/relationships via LLM, and deduplicates against existing nodes. Use 'chunk' for a single passage (synchronous), 'document' for full documents (async \u2014 returns a job ID), 'session' for conversation transcripts. Use 'job_status' to check progress. For short individual facts, use the specific cognitive tools instead.",
|
|
@@ -3080,6 +3919,7 @@ var TOOLS = [
|
|
|
3080
3919
|
required: ["action"]
|
|
3081
3920
|
}
|
|
3082
3921
|
},
|
|
3922
|
+
MEMORY_TOOL,
|
|
3083
3923
|
SYNC_TOOL,
|
|
3084
3924
|
CODE_TOOL
|
|
3085
3925
|
];
|
|
@@ -3100,7 +3940,7 @@ var INVOCATION_CONTEXT_SCHEMA = {
|
|
|
3100
3940
|
}
|
|
3101
3941
|
};
|
|
3102
3942
|
for (const tool of TOOLS) {
|
|
3103
|
-
if (tool.name === "mindgraph_retrieve") continue;
|
|
3943
|
+
if (tool.name === "mindgraph_retrieve" || tool.name === "mindgraph_memory") continue;
|
|
3104
3944
|
const schema = tool.inputSchema;
|
|
3105
3945
|
if (schema.properties && !schema.properties.invocation_context) {
|
|
3106
3946
|
schema.properties.invocation_context = INVOCATION_CONTEXT_SCHEMA;
|
|
@@ -3119,8 +3959,8 @@ function ok3(data) {
|
|
|
3119
3959
|
}
|
|
3120
3960
|
function renderedResult(format, raw, render) {
|
|
3121
3961
|
if (format === "json") return ok3(raw);
|
|
3122
|
-
const
|
|
3123
|
-
return
|
|
3962
|
+
const text2 = render(raw);
|
|
3963
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok3(raw);
|
|
3124
3964
|
}
|
|
3125
3965
|
function err3(message) {
|
|
3126
3966
|
return {
|
|
@@ -3128,8 +3968,22 @@ function err3(message) {
|
|
|
3128
3968
|
isError: true
|
|
3129
3969
|
};
|
|
3130
3970
|
}
|
|
3131
|
-
async function handleTool(client2, name, args) {
|
|
3971
|
+
async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
3132
3972
|
try {
|
|
3973
|
+
if (["mindgraph_capture", "mindgraph_reason", "mindgraph_commit"].includes(name) && args.action !== "get_open_decisions") {
|
|
3974
|
+
const key = defaultWriteIdempotencyKey(name, args);
|
|
3975
|
+
if (key) args = { ...args, idempotency_key: key };
|
|
3976
|
+
const dispositions = [
|
|
3977
|
+
args.reuse_uid,
|
|
3978
|
+
args.supersedes_uid,
|
|
3979
|
+
args.contradicts_uid,
|
|
3980
|
+
args.confirm_new === true ? true : void 0,
|
|
3981
|
+
args.on_near_duplicate
|
|
3982
|
+
].filter((value) => value !== void 0);
|
|
3983
|
+
if (dispositions.length > 1) {
|
|
3984
|
+
return err3("resolution dispositions are mutually exclusive");
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3133
3987
|
let result;
|
|
3134
3988
|
switch (name) {
|
|
3135
3989
|
case "mindgraph_capture":
|
|
@@ -3147,6 +4001,12 @@ async function handleTool(client2, name, args) {
|
|
|
3147
4001
|
case "mindgraph_retrieve":
|
|
3148
4002
|
result = await handleRetrieve(client2, args);
|
|
3149
4003
|
break;
|
|
4004
|
+
case "mindgraph_memory":
|
|
4005
|
+
result = await handleMemoryTool(client2, args, memoryConfig);
|
|
4006
|
+
break;
|
|
4007
|
+
case "mindgraph_series_query":
|
|
4008
|
+
result = await handleSeriesQuery(client2, args);
|
|
4009
|
+
break;
|
|
3150
4010
|
case "mindgraph_ingest":
|
|
3151
4011
|
result = await handleIngest(client2, args);
|
|
3152
4012
|
break;
|
|
@@ -3191,17 +4051,45 @@ async function handleTool(client2, name, args) {
|
|
|
3191
4051
|
return err3(errorDetail(e));
|
|
3192
4052
|
}
|
|
3193
4053
|
}
|
|
4054
|
+
async function handleSeriesQuery(client2, args) {
|
|
4055
|
+
const action = typeof args.action === "string" ? args.action : "";
|
|
4056
|
+
if (!["list_for_entity", "latest", "window", "aggregate"].includes(action)) {
|
|
4057
|
+
return err3(`Unknown series query action: ${action}`);
|
|
4058
|
+
}
|
|
4059
|
+
if (action === "list_for_entity" && typeof args.entity_uid !== "string") {
|
|
4060
|
+
return err3("entity_uid is required for action='list_for_entity'");
|
|
4061
|
+
}
|
|
4062
|
+
if (action !== "list_for_entity" && typeof args.series_uid !== "string") {
|
|
4063
|
+
return err3(`series_uid is required for action='${action}'`);
|
|
4064
|
+
}
|
|
4065
|
+
if ((action === "window" || action === "aggregate") && (typeof args.from !== "number" || typeof args.to !== "number")) {
|
|
4066
|
+
return err3(`from and to are required for action='${action}'`);
|
|
4067
|
+
}
|
|
4068
|
+
if (action === "aggregate" && (typeof args.bucket !== "string" || typeof args.agg !== "string")) {
|
|
4069
|
+
return err3("bucket and agg are required for action='aggregate'");
|
|
4070
|
+
}
|
|
4071
|
+
return ok3(
|
|
4072
|
+
await client2.series(args)
|
|
4073
|
+
);
|
|
4074
|
+
}
|
|
3194
4075
|
async function handleCapture(client2, args) {
|
|
3195
4076
|
const {
|
|
3196
4077
|
action,
|
|
3197
4078
|
label,
|
|
3198
4079
|
summary,
|
|
3199
4080
|
content,
|
|
4081
|
+
name,
|
|
4082
|
+
description,
|
|
4083
|
+
license,
|
|
3200
4084
|
session_uid,
|
|
3201
4085
|
work_uid,
|
|
3202
4086
|
execution_uid,
|
|
3203
4087
|
idempotency_key,
|
|
4088
|
+
reuse_uid,
|
|
3204
4089
|
supersedes_uid,
|
|
4090
|
+
contradicts_uid,
|
|
4091
|
+
confirm_new,
|
|
4092
|
+
on_near_duplicate,
|
|
3205
4093
|
summarizes_uids,
|
|
3206
4094
|
entity_type,
|
|
3207
4095
|
source_uid,
|
|
@@ -3225,38 +4113,82 @@ async function handleCapture(client2, args) {
|
|
|
3225
4113
|
work_uid,
|
|
3226
4114
|
execution_uid,
|
|
3227
4115
|
idempotency_key,
|
|
4116
|
+
reuse_uid,
|
|
3228
4117
|
supersedes_uid,
|
|
4118
|
+
contradicts_uid,
|
|
4119
|
+
confirm_new,
|
|
4120
|
+
on_near_duplicate,
|
|
3229
4121
|
summarizes_uids,
|
|
3230
4122
|
props,
|
|
3231
4123
|
agent_id
|
|
3232
4124
|
})
|
|
3233
4125
|
);
|
|
4126
|
+
case "skill": {
|
|
4127
|
+
if (!name) return err3("name is required for action=skill");
|
|
4128
|
+
if (!description) return err3("description is required for action=skill");
|
|
4129
|
+
if (content === void 0) return err3("content is required for action=skill");
|
|
4130
|
+
const hasProvenance = [session_uid, work_uid, execution_uid].some(
|
|
4131
|
+
(uid) => typeof uid === "string" && uid.length > 0
|
|
4132
|
+
) || Array.isArray(summarizes_uids) && summarizes_uids.some((uid) => typeof uid === "string" && uid.length > 0);
|
|
4133
|
+
if (!hasProvenance) {
|
|
4134
|
+
return err3(
|
|
4135
|
+
"at least one of session_uid, work_uid, execution_uid, or summarizes_uids is required for action=skill"
|
|
4136
|
+
);
|
|
4137
|
+
}
|
|
4138
|
+
return ok3(
|
|
4139
|
+
await client2.distill({
|
|
4140
|
+
label,
|
|
4141
|
+
output_type: "skill",
|
|
4142
|
+
summary,
|
|
4143
|
+
confidence,
|
|
4144
|
+
salience,
|
|
4145
|
+
session_uid,
|
|
4146
|
+
work_uid,
|
|
4147
|
+
execution_uid,
|
|
4148
|
+
idempotency_key,
|
|
4149
|
+
supersedes_uid,
|
|
4150
|
+
summarizes_uids,
|
|
4151
|
+
props: {
|
|
4152
|
+
name,
|
|
4153
|
+
description,
|
|
4154
|
+
content,
|
|
4155
|
+
...license ? { license } : {}
|
|
4156
|
+
},
|
|
4157
|
+
agent_id
|
|
4158
|
+
})
|
|
4159
|
+
);
|
|
4160
|
+
}
|
|
3234
4161
|
case "journal": {
|
|
3235
4162
|
if (!content) return err3("content is required for action=journal");
|
|
3236
4163
|
const journalProps = { content };
|
|
3237
4164
|
if (mood) journalProps.mood = mood;
|
|
3238
4165
|
if (tags) journalProps.tags = tags;
|
|
3239
|
-
return ok3(await client2.journal(label, journalProps, {
|
|
4166
|
+
return ok3(await client2.journal(label, journalProps, {
|
|
4167
|
+
agent_id,
|
|
4168
|
+
idempotency_key,
|
|
4169
|
+
reuse_uid,
|
|
4170
|
+
supersedes_uid,
|
|
4171
|
+
contradicts_uid,
|
|
4172
|
+
confirm_new,
|
|
4173
|
+
on_near_duplicate
|
|
4174
|
+
}));
|
|
3240
4175
|
}
|
|
3241
4176
|
case "entity": {
|
|
3242
4177
|
const type = entity_type || "concept";
|
|
3243
4178
|
const entityProps = { ...props };
|
|
3244
4179
|
if (summary) entityProps.description = summary;
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
default:
|
|
3258
|
-
return ok3(await client2.findOrCreateConcept(label, entityProps, agent_id));
|
|
3259
|
-
}
|
|
4180
|
+
return ok3(await client2.entity({
|
|
4181
|
+
action: "create",
|
|
4182
|
+
label,
|
|
4183
|
+
props: { ...entityProps, entity_type: type },
|
|
4184
|
+
agent_id,
|
|
4185
|
+
idempotency_key,
|
|
4186
|
+
reuse_uid,
|
|
4187
|
+
supersedes_uid,
|
|
4188
|
+
contradicts_uid,
|
|
4189
|
+
confirm_new,
|
|
4190
|
+
on_near_duplicate
|
|
4191
|
+
}));
|
|
3260
4192
|
}
|
|
3261
4193
|
case "observation":
|
|
3262
4194
|
return ok3(
|
|
@@ -3267,7 +4199,13 @@ async function handleCapture(client2, args) {
|
|
|
3267
4199
|
confidence,
|
|
3268
4200
|
salience,
|
|
3269
4201
|
props,
|
|
3270
|
-
agent_id
|
|
4202
|
+
agent_id,
|
|
4203
|
+
idempotency_key,
|
|
4204
|
+
reuse_uid,
|
|
4205
|
+
supersedes_uid,
|
|
4206
|
+
contradicts_uid,
|
|
4207
|
+
confirm_new,
|
|
4208
|
+
on_near_duplicate
|
|
3271
4209
|
})
|
|
3272
4210
|
);
|
|
3273
4211
|
case "source":
|
|
@@ -3279,7 +4217,13 @@ async function handleCapture(client2, args) {
|
|
|
3279
4217
|
confidence,
|
|
3280
4218
|
salience,
|
|
3281
4219
|
props,
|
|
3282
|
-
agent_id
|
|
4220
|
+
agent_id,
|
|
4221
|
+
idempotency_key,
|
|
4222
|
+
reuse_uid,
|
|
4223
|
+
supersedes_uid,
|
|
4224
|
+
contradicts_uid,
|
|
4225
|
+
confirm_new,
|
|
4226
|
+
on_near_duplicate
|
|
3283
4227
|
})
|
|
3284
4228
|
);
|
|
3285
4229
|
case "snippet":
|
|
@@ -3292,26 +4236,38 @@ async function handleCapture(client2, args) {
|
|
|
3292
4236
|
confidence,
|
|
3293
4237
|
salience,
|
|
3294
4238
|
props,
|
|
3295
|
-
agent_id
|
|
4239
|
+
agent_id,
|
|
4240
|
+
idempotency_key,
|
|
4241
|
+
reuse_uid,
|
|
4242
|
+
supersedes_uid,
|
|
4243
|
+
contradicts_uid,
|
|
4244
|
+
confirm_new,
|
|
4245
|
+
on_near_duplicate
|
|
3296
4246
|
})
|
|
3297
4247
|
);
|
|
3298
4248
|
case "concept":
|
|
3299
|
-
return ok3(
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
4249
|
+
return ok3(await client2.entity({
|
|
4250
|
+
action: "create",
|
|
4251
|
+
label,
|
|
4252
|
+
props: {
|
|
4253
|
+
...props,
|
|
4254
|
+
entity_type: "concept",
|
|
4255
|
+
...summary ? { description: summary } : {}
|
|
4256
|
+
},
|
|
4257
|
+
agent_id,
|
|
4258
|
+
idempotency_key,
|
|
4259
|
+
reuse_uid,
|
|
4260
|
+
supersedes_uid,
|
|
4261
|
+
contradicts_uid,
|
|
4262
|
+
confirm_new,
|
|
4263
|
+
on_near_duplicate
|
|
4264
|
+
}));
|
|
3310
4265
|
default:
|
|
3311
4266
|
return err3(`Unknown capture action: ${action}`);
|
|
3312
4267
|
}
|
|
3313
4268
|
}
|
|
3314
4269
|
async function handleReason(client2, args) {
|
|
4270
|
+
const resolution = resolutionFields(args);
|
|
3315
4271
|
const {
|
|
3316
4272
|
action,
|
|
3317
4273
|
label,
|
|
@@ -3344,7 +4300,8 @@ async function handleReason(client2, args) {
|
|
|
3344
4300
|
...warrant.content ? { props: { content: warrant.content } } : {}
|
|
3345
4301
|
} : void 0,
|
|
3346
4302
|
argument,
|
|
3347
|
-
agent_id
|
|
4303
|
+
agent_id,
|
|
4304
|
+
...resolution
|
|
3348
4305
|
})
|
|
3349
4306
|
);
|
|
3350
4307
|
}
|
|
@@ -3357,11 +4314,13 @@ async function handleReason(client2, args) {
|
|
|
3357
4314
|
confidence,
|
|
3358
4315
|
salience,
|
|
3359
4316
|
props,
|
|
3360
|
-
agent_id
|
|
4317
|
+
agent_id,
|
|
4318
|
+
...resolution
|
|
3361
4319
|
})
|
|
3362
4320
|
);
|
|
3363
4321
|
}
|
|
3364
4322
|
async function handleCommit(client2, args) {
|
|
4323
|
+
const resolution = resolutionFields(args);
|
|
3365
4324
|
const {
|
|
3366
4325
|
action,
|
|
3367
4326
|
label,
|
|
@@ -3392,16 +4351,17 @@ async function handleCommit(client2, args) {
|
|
|
3392
4351
|
confidence,
|
|
3393
4352
|
salience,
|
|
3394
4353
|
props,
|
|
3395
|
-
agent_id
|
|
4354
|
+
agent_id,
|
|
4355
|
+
...resolution
|
|
3396
4356
|
})
|
|
3397
4357
|
);
|
|
3398
4358
|
case "open_decision":
|
|
3399
4359
|
if (!label) return err3("label is required for open_decision");
|
|
3400
|
-
return ok3(await client2.openDecision(label, { summary, props, agent_id }));
|
|
4360
|
+
return ok3(await client2.openDecision(label, { summary, props, agent_id, ...resolution }));
|
|
3401
4361
|
case "add_option":
|
|
3402
4362
|
if (!decision_uid) return err3("decision_uid is required for add_option");
|
|
3403
4363
|
if (!label) return err3("label is required for add_option");
|
|
3404
|
-
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id }));
|
|
4364
|
+
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id, ...resolution }));
|
|
3405
4365
|
case "add_constraint":
|
|
3406
4366
|
if (!decision_uid) return err3("decision_uid is required for add_constraint");
|
|
3407
4367
|
return ok3(
|
|
@@ -3411,7 +4371,8 @@ async function handleCommit(client2, args) {
|
|
|
3411
4371
|
decision_uid,
|
|
3412
4372
|
summary,
|
|
3413
4373
|
props,
|
|
3414
|
-
agent_id
|
|
4374
|
+
agent_id,
|
|
4375
|
+
...resolution
|
|
3415
4376
|
})
|
|
3416
4377
|
);
|
|
3417
4378
|
case "resolve_decision":
|
|
@@ -3425,7 +4386,8 @@ async function handleCommit(client2, args) {
|
|
|
3425
4386
|
as_of_date,
|
|
3426
4387
|
session_id,
|
|
3427
4388
|
retrieval_trace_id,
|
|
3428
|
-
agent_id
|
|
4389
|
+
agent_id,
|
|
4390
|
+
...resolution
|
|
3429
4391
|
})
|
|
3430
4392
|
);
|
|
3431
4393
|
case "get_open_decisions":
|
|
@@ -3506,7 +4468,7 @@ async function handlePlan(client2, args) {
|
|
|
3506
4468
|
output_snapshot,
|
|
3507
4469
|
side_effects,
|
|
3508
4470
|
outcome,
|
|
3509
|
-
error,
|
|
4471
|
+
error: error2,
|
|
3510
4472
|
next_action,
|
|
3511
4473
|
checkpoint_summary,
|
|
3512
4474
|
test_summary,
|
|
@@ -3569,7 +4531,7 @@ async function handlePlan(client2, args) {
|
|
|
3569
4531
|
output_snapshot,
|
|
3570
4532
|
side_effects,
|
|
3571
4533
|
outcome,
|
|
3572
|
-
error,
|
|
4534
|
+
error: error2,
|
|
3573
4535
|
next_action,
|
|
3574
4536
|
checkpoint_summary,
|
|
3575
4537
|
test_summary,
|
|
@@ -3618,7 +4580,7 @@ async function handlePlan(client2, args) {
|
|
|
3618
4580
|
output_snapshot,
|
|
3619
4581
|
side_effects,
|
|
3620
4582
|
outcome,
|
|
3621
|
-
error,
|
|
4583
|
+
error: error2,
|
|
3622
4584
|
props,
|
|
3623
4585
|
agent_id
|
|
3624
4586
|
})
|
|
@@ -3704,6 +4666,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3704
4666
|
const {
|
|
3705
4667
|
action,
|
|
3706
4668
|
format,
|
|
4669
|
+
max_output_chars,
|
|
3707
4670
|
query,
|
|
3708
4671
|
start_uid,
|
|
3709
4672
|
end_uid,
|
|
@@ -3758,7 +4721,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3758
4721
|
graph_expansion_limit: graph_expansion_limit ?? 3,
|
|
3759
4722
|
graph_max_depth: graph_max_depth ?? 2
|
|
3760
4723
|
}),
|
|
3761
|
-
renderContext
|
|
4724
|
+
(raw) => renderContext(raw, max_output_chars)
|
|
3762
4725
|
);
|
|
3763
4726
|
case "text":
|
|
3764
4727
|
if (!query) return err3("query is required for text search");
|
|
@@ -3772,7 +4735,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3772
4735
|
explain,
|
|
3773
4736
|
agent_id
|
|
3774
4737
|
}),
|
|
3775
|
-
(raw) => renderNodeList(raw, `Text search: ${query}
|
|
4738
|
+
(raw) => renderNodeList(raw, `Text search: ${query}`, void 0, max_output_chars)
|
|
3776
4739
|
);
|
|
3777
4740
|
case "semantic":
|
|
3778
4741
|
if (!query) return err3("query is required for semantic search");
|
|
@@ -3786,7 +4749,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3786
4749
|
explain,
|
|
3787
4750
|
agent_id
|
|
3788
4751
|
}),
|
|
3789
|
-
(raw) => renderNodeList(raw, `Semantic search: ${query}
|
|
4752
|
+
(raw) => renderNodeList(raw, `Semantic search: ${query}`, void 0, max_output_chars)
|
|
3790
4753
|
);
|
|
3791
4754
|
case "hybrid":
|
|
3792
4755
|
if (!query) return err3("query is required for hybrid search");
|
|
@@ -3801,7 +4764,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3801
4764
|
agent_id
|
|
3802
4765
|
}),
|
|
3803
4766
|
// With explain, per-leg scoring must survive — raw JSON only.
|
|
3804
|
-
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}
|
|
4767
|
+
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}`, void 0, max_output_chars)
|
|
3805
4768
|
);
|
|
3806
4769
|
// Structured queries. These go through the generic /retrieve action
|
|
3807
4770
|
// dispatch rather than the SDK's no-argument convenience methods — the
|
|
@@ -3819,7 +4782,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3819
4782
|
offset,
|
|
3820
4783
|
agent_id
|
|
3821
4784
|
}),
|
|
3822
|
-
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit)
|
|
4785
|
+
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit, max_output_chars)
|
|
3823
4786
|
);
|
|
3824
4787
|
case "stale_derivations":
|
|
3825
4788
|
return rendered2(
|
|
@@ -3828,7 +4791,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3828
4791
|
limit,
|
|
3829
4792
|
offset
|
|
3830
4793
|
}),
|
|
3831
|
-
(raw) => renderNodeList(raw, "stale derivations", limit)
|
|
4794
|
+
(raw) => renderNodeList(raw, "stale derivations", limit, max_output_chars)
|
|
3832
4795
|
);
|
|
3833
4796
|
case "preferences":
|
|
3834
4797
|
return rendered2(
|
|
@@ -3838,7 +4801,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3838
4801
|
limit,
|
|
3839
4802
|
agent_id
|
|
3840
4803
|
}),
|
|
3841
|
-
(raw) => renderNodeList(raw, "Preferences", limit)
|
|
4804
|
+
(raw) => renderNodeList(raw, "Preferences", limit, max_output_chars)
|
|
3842
4805
|
);
|
|
3843
4806
|
case "layer":
|
|
3844
4807
|
if (!layer) return err3("layer is required for layer retrieval");
|
|
@@ -3850,7 +4813,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3850
4813
|
node_types,
|
|
3851
4814
|
agent_id
|
|
3852
4815
|
}),
|
|
3853
|
-
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit)
|
|
4816
|
+
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit, max_output_chars)
|
|
3854
4817
|
);
|
|
3855
4818
|
case "recent":
|
|
3856
4819
|
return rendered2(
|
|
@@ -3864,7 +4827,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3864
4827
|
created_before,
|
|
3865
4828
|
agent_id
|
|
3866
4829
|
}),
|
|
3867
|
-
(raw) => renderNodeList(raw, "Recently ingested", limit)
|
|
4830
|
+
(raw) => renderNodeList(raw, "Recently ingested", limit, max_output_chars)
|
|
3868
4831
|
);
|
|
3869
4832
|
// Document inventory
|
|
3870
4833
|
case "document_index":
|
|
@@ -3873,7 +4836,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3873
4836
|
node_type: "Document",
|
|
3874
4837
|
limit: limit ?? 100
|
|
3875
4838
|
}),
|
|
3876
|
-
(raw) => renderNodeList(raw, "Ingested documents")
|
|
4839
|
+
(raw) => renderNodeList(raw, "Ingested documents", void 0, max_output_chars)
|
|
3877
4840
|
);
|
|
3878
4841
|
// Graph traversal
|
|
3879
4842
|
case "chain":
|
|
@@ -3887,7 +4850,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3887
4850
|
include_provenance,
|
|
3888
4851
|
max_nodes
|
|
3889
4852
|
}),
|
|
3890
|
-
renderTraversal
|
|
4853
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
3891
4854
|
);
|
|
3892
4855
|
case "neighborhood":
|
|
3893
4856
|
if (!start_uid) return err3("start_uid is required for neighborhood traversal");
|
|
@@ -3902,7 +4865,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3902
4865
|
include_provenance,
|
|
3903
4866
|
max_nodes
|
|
3904
4867
|
}),
|
|
3905
|
-
renderTraversal
|
|
4868
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
3906
4869
|
);
|
|
3907
4870
|
case "path":
|
|
3908
4871
|
if (!start_uid) return err3("start_uid is required for path traversal");
|
|
@@ -3919,7 +4882,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3919
4882
|
include_provenance,
|
|
3920
4883
|
max_nodes
|
|
3921
4884
|
}),
|
|
3922
|
-
renderTraversal
|
|
4885
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
3923
4886
|
);
|
|
3924
4887
|
case "subgraph":
|
|
3925
4888
|
if (!start_uid) return err3("start_uid is required for subgraph traversal");
|
|
@@ -3934,7 +4897,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3934
4897
|
include_provenance,
|
|
3935
4898
|
max_nodes
|
|
3936
4899
|
}),
|
|
3937
|
-
renderTraversal
|
|
4900
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
3938
4901
|
);
|
|
3939
4902
|
case "top_k_paths":
|
|
3940
4903
|
if (!start_uid) return err3("start_uid is required for top_k_paths");
|
|
@@ -3950,7 +4913,7 @@ async function handleRetrieve(client2, args) {
|
|
|
3950
4913
|
edge_types,
|
|
3951
4914
|
exclude_edge_types
|
|
3952
4915
|
}),
|
|
3953
|
-
renderTraversal
|
|
4916
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
3954
4917
|
);
|
|
3955
4918
|
default:
|
|
3956
4919
|
return err3(`Unknown retrieve action: ${action}`);
|
|
@@ -4214,8 +5177,8 @@ var ok4 = (data) => ({
|
|
|
4214
5177
|
});
|
|
4215
5178
|
var rendered = (format, raw, render) => {
|
|
4216
5179
|
if (format === "json") return ok4(raw);
|
|
4217
|
-
const
|
|
4218
|
-
return
|
|
5180
|
+
const text2 = render(raw);
|
|
5181
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok4(raw);
|
|
4219
5182
|
};
|
|
4220
5183
|
var err4 = (message) => ({
|
|
4221
5184
|
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
@@ -4275,8 +5238,8 @@ async function getGeneratedTools(client2) {
|
|
|
4275
5238
|
cache = { tools, byName, fetchedAt: Date.now() };
|
|
4276
5239
|
retryNotBefore = 0;
|
|
4277
5240
|
return { tools, byName };
|
|
4278
|
-
} catch (
|
|
4279
|
-
if (
|
|
5241
|
+
} catch (error2) {
|
|
5242
|
+
if (error2 instanceof DuplicateGeneratedToolError) throw error2;
|
|
4280
5243
|
retryNotBefore = Date.now() + FAILURE_COOLDOWN_MS;
|
|
4281
5244
|
return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
|
|
4282
5245
|
}
|
|
@@ -4433,7 +5396,9 @@ var ONTOLOGY_READ_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
4433
5396
|
"get_proposal"
|
|
4434
5397
|
]);
|
|
4435
5398
|
function toolMutability(toolName, action) {
|
|
5399
|
+
if (toolName === "mindgraph_memory") return "read";
|
|
4436
5400
|
if (toolName === "mindgraph_retrieve") return "read";
|
|
5401
|
+
if (toolName === "mindgraph_series_query") return "read";
|
|
4437
5402
|
if (toolName === "mindgraph_plan") {
|
|
4438
5403
|
return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
|
|
4439
5404
|
}
|
|
@@ -4460,6 +5425,8 @@ function toolMutability(toolName, action) {
|
|
|
4460
5425
|
var UID_FIELDS = [
|
|
4461
5426
|
"uid",
|
|
4462
5427
|
"source_uid",
|
|
5428
|
+
"entity_uid",
|
|
5429
|
+
"series_uid",
|
|
4463
5430
|
"session_uid",
|
|
4464
5431
|
"work_uid",
|
|
4465
5432
|
"goal_uid",
|
|
@@ -4550,8 +5517,8 @@ async function checkMcpGovernance(toolName, args, config) {
|
|
|
4550
5517
|
response = candidate;
|
|
4551
5518
|
body = candidateBody;
|
|
4552
5519
|
break;
|
|
4553
|
-
} catch (
|
|
4554
|
-
lastFailure =
|
|
5520
|
+
} catch (error2) {
|
|
5521
|
+
lastFailure = error2 instanceof Error ? error2.message : String(error2);
|
|
4555
5522
|
if (attempt < retryDelays.length) {
|
|
4556
5523
|
await sleep(retryDelays[attempt]);
|
|
4557
5524
|
continue;
|
|
@@ -4625,6 +5592,12 @@ async function checkMcpGovernance(toolName, args, config) {
|
|
|
4625
5592
|
|
|
4626
5593
|
// src/resources.ts
|
|
4627
5594
|
var RESOURCES = [
|
|
5595
|
+
{
|
|
5596
|
+
uri: "mindgraph://memory/status",
|
|
5597
|
+
name: "Memory Integration Status",
|
|
5598
|
+
description: "Portable memory profile, adapter state, supported capabilities, and explicit limitations",
|
|
5599
|
+
mimeType: "application/json"
|
|
5600
|
+
},
|
|
4628
5601
|
{
|
|
4629
5602
|
uri: "mindgraph://stats",
|
|
4630
5603
|
name: "Graph Statistics",
|
|
@@ -4682,8 +5655,10 @@ function json(uri, data) {
|
|
|
4682
5655
|
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
|
|
4683
5656
|
};
|
|
4684
5657
|
}
|
|
4685
|
-
async function readResource(client2, uri) {
|
|
5658
|
+
async function readResource(client2, uri, memoryConfig = {}) {
|
|
4686
5659
|
switch (uri) {
|
|
5660
|
+
case "mindgraph://memory/status":
|
|
5661
|
+
return json(uri, memoryStatus(memoryConfig));
|
|
4687
5662
|
case "mindgraph://stats":
|
|
4688
5663
|
return json(uri, await client2.stats());
|
|
4689
5664
|
case "mindgraph://goals":
|
|
@@ -4715,16 +5690,18 @@ async function readResource(client2, uri) {
|
|
|
4715
5690
|
}
|
|
4716
5691
|
throw new Error(`Unknown resource: ${uri}`);
|
|
4717
5692
|
}
|
|
4718
|
-
async function readGovernedResource(client2, uri, governanceConfig) {
|
|
5693
|
+
async function readGovernedResource(client2, uri, governanceConfig, memoryConfig = {}) {
|
|
5694
|
+
const toolName = uri === "mindgraph://memory/status" ? "mindgraph_memory" : RESOURCE_GOVERNANCE_TOOL;
|
|
5695
|
+
const toolArgs = uri === "mindgraph://memory/status" ? { action: "status" } : {};
|
|
4719
5696
|
const governance = await checkMcpGovernance(
|
|
4720
|
-
|
|
4721
|
-
|
|
5697
|
+
toolName,
|
|
5698
|
+
toolArgs,
|
|
4722
5699
|
{ ...governanceConfig, context: { resource_uri: uri } }
|
|
4723
5700
|
);
|
|
4724
5701
|
if (!governance.allowed) {
|
|
4725
5702
|
throw new Error(governance.message);
|
|
4726
5703
|
}
|
|
4727
|
-
return readResource(client2, uri);
|
|
5704
|
+
return readResource(client2, uri, memoryConfig);
|
|
4728
5705
|
}
|
|
4729
5706
|
|
|
4730
5707
|
// src/index.ts
|
|
@@ -4734,7 +5711,7 @@ var import_node_path5 = __toESM(require("path"));
|
|
|
4734
5711
|
var import_node_fs4 = __toESM(require("fs"));
|
|
4735
5712
|
var import_node_os3 = __toESM(require("os"));
|
|
4736
5713
|
var import_node_path4 = __toESM(require("path"));
|
|
4737
|
-
var
|
|
5714
|
+
var import_node_crypto6 = __toESM(require("crypto"));
|
|
4738
5715
|
var OWNER_MARKER = "--owner mindgraph";
|
|
4739
5716
|
var RUNNER_RELATIVE = ".mindgraph/bin/mindgraph-hook.cjs";
|
|
4740
5717
|
function command(harness) {
|
|
@@ -4747,7 +5724,7 @@ var RUNNER_VERSION_RELATIVE = `${RUNNER_RELATIVE}.version`;
|
|
|
4747
5724
|
function installHookRunner(sourceFile, homeDir, version) {
|
|
4748
5725
|
const target = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_RELATIVE);
|
|
4749
5726
|
import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(target), { recursive: true });
|
|
4750
|
-
const temporary = `${target}.${process.pid}.${
|
|
5727
|
+
const temporary = `${target}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
|
|
4751
5728
|
import_node_fs4.default.copyFileSync(sourceFile, temporary);
|
|
4752
5729
|
import_node_fs4.default.renameSync(temporary, target);
|
|
4753
5730
|
const versionPath = import_node_path4.default.join(homeDir || import_node_os3.default.homedir(), RUNNER_VERSION_RELATIVE);
|
|
@@ -4917,7 +5894,7 @@ function entryHasOwnedHook(value) {
|
|
|
4917
5894
|
}
|
|
4918
5895
|
function writeSettings(file, settings) {
|
|
4919
5896
|
import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
|
|
4920
|
-
const temporary = `${file}.${process.pid}.${
|
|
5897
|
+
const temporary = `${file}.${process.pid}.${import_node_crypto6.default.randomUUID()}.tmp`;
|
|
4921
5898
|
import_node_fs4.default.writeFileSync(temporary, `${JSON.stringify(settings, null, 2)}
|
|
4922
5899
|
`, {
|
|
4923
5900
|
mode: 384
|
|
@@ -4970,56 +5947,29 @@ var client = new import_mindgraph2.MindGraph({
|
|
|
4970
5947
|
});
|
|
4971
5948
|
var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph, plus any ontology tools generated by the active schema.
|
|
4972
5949
|
|
|
4973
|
-
##
|
|
4974
|
-
|
|
4975
|
-
When the user asks about something, your FIRST and ONLY action should be a SINGLE \`mindgraph_retrieve\` call with action "context" and keyword terms from their message. Nothing else first.
|
|
5950
|
+
## Default memory workflow: orient \u2192 answer \u2192 preserve
|
|
4976
5951
|
|
|
4977
|
-
**
|
|
4978
|
-
- Do NOT retrieve active_goals, open_questions, contradictions, or weak_claims
|
|
4979
|
-
- Do NOT follow a "session lifecycle" or "warm-up" sequence
|
|
4980
|
-
- Do NOT make multiple serial retrieve calls when one "context" call covers it
|
|
5952
|
+
**Orient only when prior durable state may matter.** Self-contained questions do not require a memory call or a warm-up sequence.
|
|
4981
5953
|
|
|
4982
|
-
|
|
5954
|
+
- 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.
|
|
5955
|
+
- Asking about a topic that may depend on prior knowledge: call \`mindgraph_memory\` once with action \`context\`, mode \`topic\`, and 1\u20133 discriminating keywords.
|
|
5956
|
+
- Asking about integration capability or automatic behavior: call \`mindgraph_memory\` with action \`status\`.
|
|
5957
|
+
- Use the comprehensive read tools below only when the high-level result is insufficient or the user asks for a specific graph operation.
|
|
4983
5958
|
|
|
4984
|
-
**
|
|
4985
|
-
\u2713 CORRECT: \`mindgraph_retrieve({action: "context", query: "Indian philosophy Taoism"})\`
|
|
4986
|
-
\u2717 WRONG: First retrieve active_goals, then open_questions, then search
|
|
4987
|
-
\u2717 WRONG: \`mindgraph_retrieve({action: "context", query: "Tell me about Indian philosophy and Taoism"})\` \u2014 natural language won't match BM25
|
|
5959
|
+
**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.
|
|
4988
5960
|
|
|
4989
|
-
|
|
5961
|
+
**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.
|
|
4990
5962
|
|
|
4991
|
-
|
|
4992
|
-
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.
|
|
5963
|
+
## Topic retrieval details
|
|
4993
5964
|
|
|
4994
|
-
|
|
4995
|
-
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.
|
|
5965
|
+
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 fails, use \`mindgraph_retrieve\` with \`semantic\` or \`hybrid\`; use \`document_index\` to inspect ingested sources.
|
|
4996
5966
|
|
|
4997
|
-
|
|
4998
|
-
- \`action: "document_index"\` \u2014 list all ingested documents (titles, dates, UIDs) to see what's in the graph
|
|
5967
|
+
## Comprehensive read tools
|
|
4999
5968
|
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
**Keyword examples:**
|
|
5005
|
-
- "What is Kissinger's view on NATO?" \u2192 query: \`"Kissinger NATO"\`
|
|
5006
|
-
- "Tell me about async in Rust" \u2192 query: \`"Rust async runtime"\`
|
|
5007
|
-
- "Implications of carbon tax?" \u2192 query: \`"carbon tax"\`
|
|
5008
|
-
|
|
5009
|
-
If keyword search returns no results, escalate:
|
|
5010
|
-
1. Try synonyms (e.g. \`"global warming"\` instead of \`"climate change"\`)
|
|
5011
|
-
2. Use \`action: "semantic"\` \u2014 vector similarity, natural language OK (e.g. \`"ways to manage stress"\` finds "mental health" nodes)
|
|
5012
|
-
3. Use \`action: "hybrid"\` \u2014 combines BM25 + semantic for best coverage
|
|
5013
|
-
|
|
5014
|
-
## When to READ
|
|
5015
|
-
|
|
5016
|
-
- User asks about topic X \u2192 \`mindgraph_retrieve\` action "context", query "X keywords"
|
|
5017
|
-
- User asks "what documents are in my graph?" \u2192 action "document_index"
|
|
5018
|
-
- User explicitly asks "what are my goals?" \u2192 action "active_goals"
|
|
5019
|
-
- User explicitly asks about open questions \u2192 action "open_questions"
|
|
5020
|
-
- 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
|
|
5021
|
-
- Explore around a known node \u2192 action "neighborhood" with start_uid
|
|
5022
|
-
- Find connections between nodes \u2192 action "path" with start_uid + end_uid
|
|
5969
|
+
- Explicit graph inventory or state questions \u2192 the matching \`mindgraph_retrieve\` action such as \`document_index\`, \`active_goals\`, or \`open_questions\`
|
|
5970
|
+
- Advice or recommendations \u2192 \`mindgraph_retrieve\` action \`preferences\`, with topic keywords
|
|
5971
|
+
- Explore around a known node \u2192 \`mindgraph_retrieve\` action \`neighborhood\` with start_uid
|
|
5972
|
+
- Find connections between nodes \u2192 \`mindgraph_retrieve\` action \`path\` with start_uid + end_uid
|
|
5023
5973
|
|
|
5024
5974
|
## When to WRITE
|
|
5025
5975
|
|
|
@@ -5054,13 +6004,14 @@ if (PROFILE === "coding") {
|
|
|
5054
6004
|
|
|
5055
6005
|
## Coding profile
|
|
5056
6006
|
|
|
5057
|
-
**
|
|
5058
|
-
- "What was I working on?" / current work state / resuming anything: call \`
|
|
6007
|
+
**Coding recall order:**
|
|
6008
|
+
- "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).
|
|
5059
6009
|
- Knowledge about specific code (a function, file, or route): \`mindgraph_code\` action \`recall\` \u2014 anchor-based, not keyword-based.
|
|
5060
6010
|
- 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.
|
|
5061
6011
|
|
|
5062
6012
|
- 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.
|
|
5063
6013
|
- Capture corrections, decisions with rationale, fixes that survived meaningful failed attempts, durable invariants/preferences, and blockers with evidence.
|
|
6014
|
+
- If a write returns \`near_duplicate\`, choose \`reuse_uid\` or \`supersedes_uid\`; use \`confirm_new\` only for genuinely distinct facts.
|
|
5064
6015
|
- Do not capture routine mechanics, transient command output, facts cheaply derivable from code, unsupported speculation as high-confidence lessons, or completion without evidence.
|
|
5065
6016
|
- Adapter context is owned by ${HARNESS}; omit invocation_context because hooks replace it.`;
|
|
5066
6017
|
} else {
|
|
@@ -5070,7 +6021,7 @@ if (PROFILE === "coding") {
|
|
|
5070
6021
|
}
|
|
5071
6022
|
var RUNNER_REFRESH = (() => {
|
|
5072
6023
|
try {
|
|
5073
|
-
return refreshHookRunner("0.
|
|
6024
|
+
return refreshHookRunner("0.20.0", import_node_path5.default.join(__dirname, "cli.js"));
|
|
5074
6025
|
} catch {
|
|
5075
6026
|
return void 0;
|
|
5076
6027
|
}
|
|
@@ -5084,12 +6035,12 @@ if (RUNNER_REFRESH?.refreshed) {
|
|
|
5084
6035
|
}
|
|
5085
6036
|
})();
|
|
5086
6037
|
console.error(
|
|
5087
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
6038
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.20.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
5088
6039
|
);
|
|
5089
6040
|
}
|
|
5090
6041
|
var HOOK_SKEW_NOTE = (() => {
|
|
5091
6042
|
try {
|
|
5092
|
-
return versionSkewNote("0.
|
|
6043
|
+
return versionSkewNote("0.20.0");
|
|
5093
6044
|
} catch {
|
|
5094
6045
|
return void 0;
|
|
5095
6046
|
}
|
|
@@ -5103,7 +6054,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
5103
6054
|
var server = new import_server.Server(
|
|
5104
6055
|
{
|
|
5105
6056
|
name: "mindgraph",
|
|
5106
|
-
version: "0.
|
|
6057
|
+
version: "0.20.0"
|
|
5107
6058
|
},
|
|
5108
6059
|
{
|
|
5109
6060
|
capabilities: {
|
|
@@ -5127,6 +6078,14 @@ var GOVERNANCE_CONFIG = {
|
|
|
5127
6078
|
return process.env.MINDGRAPH_GOVERNANCE === "off";
|
|
5128
6079
|
}
|
|
5129
6080
|
};
|
|
6081
|
+
var MEMORY_RUNTIME_CONFIG = {
|
|
6082
|
+
serverVersion: "0.20.0",
|
|
6083
|
+
baseUrl: BASE_URL,
|
|
6084
|
+
profile: PROFILE,
|
|
6085
|
+
harness: HARNESS,
|
|
6086
|
+
orgId: ORG_ID,
|
|
6087
|
+
agentId: AGENT_ID
|
|
6088
|
+
};
|
|
5130
6089
|
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
5131
6090
|
const { name, arguments: args } = request.params;
|
|
5132
6091
|
const rawArgs = { ...args || {} };
|
|
@@ -5146,7 +6105,7 @@ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) =>
|
|
|
5146
6105
|
if (desc) {
|
|
5147
6106
|
return handleGeneratedTool(client, desc, rawArgs);
|
|
5148
6107
|
}
|
|
5149
|
-
return handleTool(client, name, toolArgs);
|
|
6108
|
+
return handleTool(client, name, toolArgs, MEMORY_RUNTIME_CONFIG);
|
|
5150
6109
|
});
|
|
5151
6110
|
var PROMPTS = [
|
|
5152
6111
|
{
|
|
@@ -5311,16 +6270,21 @@ server.setRequestHandler(import_types.ListResourceTemplatesRequestSchema, async
|
|
|
5311
6270
|
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
5312
6271
|
});
|
|
5313
6272
|
server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
|
|
5314
|
-
return readGovernedResource(
|
|
6273
|
+
return readGovernedResource(
|
|
6274
|
+
client,
|
|
6275
|
+
request.params.uri,
|
|
6276
|
+
GOVERNANCE_CONFIG,
|
|
6277
|
+
MEMORY_RUNTIME_CONFIG
|
|
6278
|
+
);
|
|
5315
6279
|
});
|
|
5316
6280
|
async function main() {
|
|
5317
6281
|
const transport = new import_stdio.StdioServerTransport();
|
|
5318
6282
|
await server.connect(transport);
|
|
5319
6283
|
console.error(
|
|
5320
|
-
`MindGraph MCP server v${"0.
|
|
6284
|
+
`MindGraph MCP server v${"0.20.0"} running on stdio (${BASE_URL})`
|
|
5321
6285
|
);
|
|
5322
6286
|
}
|
|
5323
|
-
main().catch((
|
|
5324
|
-
console.error("Fatal error:",
|
|
6287
|
+
main().catch((error2) => {
|
|
6288
|
+
console.error("Fatal error:", error2);
|
|
5325
6289
|
process.exit(1);
|
|
5326
6290
|
});
|