mindgraph-mcp 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -3
- package/dist/cli.js +1385 -247
- package/dist/index.js +1142 -197
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -27,25 +27,127 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
|
|
29
29
|
// node_modules/mindgraph/dist/index.mjs
|
|
30
|
+
function errorFields(body) {
|
|
31
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
32
|
+
const fields = body;
|
|
33
|
+
return {
|
|
34
|
+
...typeof fields.code === "string" ? { code: fields.code } : {},
|
|
35
|
+
...typeof fields.retriable === "boolean" ? { retriable: fields.retriable } : {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function canRetryRequest(method, path8, body) {
|
|
39
|
+
if (method === "GET" || method === "HEAD") return true;
|
|
40
|
+
if (method !== "POST") return false;
|
|
41
|
+
if (READ_POSTS.has(path8)) return true;
|
|
42
|
+
const fields = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
43
|
+
if (typeof fields.action !== "string") return false;
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(READ_ACTIONS, path8) && READ_ACTIONS[path8].includes(fields.action)) return true;
|
|
45
|
+
return path8 === "/agent/plan" && IDEMPOTENT_WORK.has(fields.action) && typeof fields.idempotency_key === "string" && fields.idempotency_key.trim().length > 0;
|
|
46
|
+
}
|
|
47
|
+
function permitsRetry(fields) {
|
|
48
|
+
return fields.retriable !== false && ![
|
|
49
|
+
"query_memory_budget_exceeded",
|
|
50
|
+
"query_timeout",
|
|
51
|
+
"query_cancelled",
|
|
52
|
+
"vector_index_rebuilding"
|
|
53
|
+
].includes(fields.code ?? "");
|
|
54
|
+
}
|
|
55
|
+
function retryDelayMs(header, backoff, attempt) {
|
|
56
|
+
const hint = Number(header);
|
|
57
|
+
return Number.isFinite(hint) && hint > 0 ? Math.min(hint * 1e3, 1e4) : Math.min(backoff * 2 ** Math.min(attempt, 32), 1e4);
|
|
58
|
+
}
|
|
30
59
|
function seg(value) {
|
|
31
60
|
return encodeURIComponent(String(value));
|
|
32
61
|
}
|
|
62
|
+
function pathSteps(response) {
|
|
63
|
+
const wrapped = response && typeof response === "object" && !Array.isArray(response) ? response : void 0;
|
|
64
|
+
const raw = wrapped?.steps ?? response;
|
|
65
|
+
if (!Array.isArray(raw)) return [];
|
|
66
|
+
return raw.flatMap((value) => {
|
|
67
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
68
|
+
const step = value;
|
|
69
|
+
const taggedName = (tagged) => {
|
|
70
|
+
if (typeof tagged === "string") return tagged;
|
|
71
|
+
if (!tagged || typeof tagged !== "object" || Array.isArray(tagged)) return null;
|
|
72
|
+
const custom = tagged.Custom;
|
|
73
|
+
return typeof custom === "string" ? custom : null;
|
|
74
|
+
};
|
|
75
|
+
return [{
|
|
76
|
+
...step,
|
|
77
|
+
node_type: taggedName(step.node_type) ?? "Unknown",
|
|
78
|
+
edge_type: taggedName(step.edge_type)
|
|
79
|
+
}];
|
|
80
|
+
});
|
|
81
|
+
}
|
|
33
82
|
function createRequestId() {
|
|
34
83
|
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
35
84
|
return globalThis.crypto.randomUUID();
|
|
36
85
|
}
|
|
37
86
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
38
87
|
}
|
|
39
|
-
var MindGraphError, MindGraph;
|
|
88
|
+
var READ_POSTS, READ_ACTIONS, IDEMPOTENT_WORK, MindGraphError, MindGraph;
|
|
40
89
|
var init_dist = __esm({
|
|
41
90
|
"node_modules/mindgraph/dist/index.mjs"() {
|
|
42
91
|
"use strict";
|
|
92
|
+
READ_POSTS = /* @__PURE__ */ new Set([
|
|
93
|
+
"/search",
|
|
94
|
+
"/retrieve/context",
|
|
95
|
+
"/nodes/batch",
|
|
96
|
+
"/edges/batch",
|
|
97
|
+
"/subgraph",
|
|
98
|
+
"/embeddings/search",
|
|
99
|
+
"/embeddings/search-text",
|
|
100
|
+
"/ontology/query",
|
|
101
|
+
"/ontology/query/structured",
|
|
102
|
+
"/ontology/objects/search"
|
|
103
|
+
]);
|
|
104
|
+
READ_ACTIONS = {
|
|
105
|
+
"/retrieve": [
|
|
106
|
+
"text",
|
|
107
|
+
"semantic",
|
|
108
|
+
"hybrid",
|
|
109
|
+
"active_goals",
|
|
110
|
+
"open_questions",
|
|
111
|
+
"preferences",
|
|
112
|
+
"weak_claims",
|
|
113
|
+
"pending_approvals",
|
|
114
|
+
"unresolved_contradictions",
|
|
115
|
+
"merge_candidates",
|
|
116
|
+
"stale_derivations",
|
|
117
|
+
"curation_counts",
|
|
118
|
+
"layer",
|
|
119
|
+
"recent"
|
|
120
|
+
],
|
|
121
|
+
"/traverse": ["chain", "top_k_paths", "neighborhood", "path", "subgraph"],
|
|
122
|
+
"/reality/series": ["window", "aggregate", "latest", "list_for_entity", "batch_latest", "batch_aggregate"],
|
|
123
|
+
"/intent/deliberation": ["get_open"],
|
|
124
|
+
"/action/risk": ["get_assessments"],
|
|
125
|
+
"/action/skill": ["get", "list"],
|
|
126
|
+
"/memory/config": ["get_preferences", "get_policies"],
|
|
127
|
+
"/memory/sync": ["status"],
|
|
128
|
+
"/agent/plan": ["get_plan", "resume_work"],
|
|
129
|
+
"/agent/governance": ["get_pending", "check"],
|
|
130
|
+
"/agent/execution": ["get_executions"],
|
|
131
|
+
"/evolve": ["history", "snapshot"]
|
|
132
|
+
};
|
|
133
|
+
IDEMPOTENT_WORK = /* @__PURE__ */ new Set([
|
|
134
|
+
"claim_task",
|
|
135
|
+
"heartbeat",
|
|
136
|
+
"start_iteration",
|
|
137
|
+
"checkpoint_iteration",
|
|
138
|
+
"block_task",
|
|
139
|
+
"complete_task",
|
|
140
|
+
"abandon_iteration"
|
|
141
|
+
]);
|
|
43
142
|
MindGraphError = class extends Error {
|
|
44
143
|
constructor(message, status, body) {
|
|
45
144
|
super(message);
|
|
46
145
|
this.status = status;
|
|
47
146
|
this.body = body;
|
|
48
147
|
this.name = "MindGraphError";
|
|
148
|
+
const fields = errorFields(body);
|
|
149
|
+
this.code = fields.code;
|
|
150
|
+
this.retriable = fields.retriable;
|
|
49
151
|
}
|
|
50
152
|
};
|
|
51
153
|
MindGraph = class {
|
|
@@ -63,6 +165,18 @@ var init_dist = __esm({
|
|
|
63
165
|
this.telemetrySurface = config.telemetrySurface;
|
|
64
166
|
this.maxRetries = config.maxRetries ?? 3;
|
|
65
167
|
this.retryBackoffMs = config.retryBackoffMs ?? 1e3;
|
|
168
|
+
if (!Number.isSafeInteger(this.maxRetries) || this.maxRetries < 0) {
|
|
169
|
+
throw new RangeError("maxRetries must be a non-negative safe integer");
|
|
170
|
+
}
|
|
171
|
+
if (!Number.isFinite(this.retryBackoffMs) || this.retryBackoffMs < 0) {
|
|
172
|
+
throw new RangeError("retryBackoffMs must be finite and non-negative");
|
|
173
|
+
}
|
|
174
|
+
if (config.timeoutMs !== void 0) {
|
|
175
|
+
if (!Number.isFinite(config.timeoutMs) || config.timeoutMs <= 0) {
|
|
176
|
+
throw new RangeError("timeoutMs must be a positive finite number of milliseconds");
|
|
177
|
+
}
|
|
178
|
+
this.timeoutMs = config.timeoutMs;
|
|
179
|
+
}
|
|
66
180
|
}
|
|
67
181
|
// ---- HTTP helpers ----
|
|
68
182
|
async request(method, path8, body) {
|
|
@@ -79,37 +193,68 @@ var init_dist = __esm({
|
|
|
79
193
|
if (body !== void 0) {
|
|
80
194
|
init.body = JSON.stringify(body);
|
|
81
195
|
}
|
|
196
|
+
const retrySafe = canRetryRequest(
|
|
197
|
+
method,
|
|
198
|
+
path8,
|
|
199
|
+
typeof init.body === "string" ? JSON.parse(init.body) : void 0
|
|
200
|
+
);
|
|
82
201
|
let lastError;
|
|
83
202
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
84
|
-
const res = await
|
|
203
|
+
const res = await this.fetchWithDeadline(url, init, method, path8);
|
|
85
204
|
if (!res.ok) {
|
|
86
|
-
const
|
|
205
|
+
const text22 = await res.text().catch(() => "");
|
|
87
206
|
let parsed;
|
|
88
207
|
try {
|
|
89
|
-
parsed = JSON.parse(
|
|
208
|
+
parsed = JSON.parse(text22);
|
|
90
209
|
} catch {
|
|
91
|
-
parsed =
|
|
210
|
+
parsed = text22;
|
|
92
211
|
}
|
|
93
212
|
const err5 = new MindGraphError(
|
|
94
213
|
`${method} ${path8} failed: ${res.status}`,
|
|
95
214
|
res.status,
|
|
96
215
|
parsed
|
|
97
216
|
);
|
|
98
|
-
if (res.status === 503 && attempt < this.maxRetries) {
|
|
217
|
+
if (res.status === 503 && retrySafe && permitsRetry(err5) && attempt < this.maxRetries) {
|
|
99
218
|
lastError = err5;
|
|
100
|
-
const
|
|
101
|
-
const delay = Number.isFinite(retryAfterSecs) && retryAfterSecs > 0 ? Math.min(retryAfterSecs * 1e3, 1e4) : this.retryBackoffMs * 2 ** attempt;
|
|
219
|
+
const delay = retryDelayMs(res.headers.get("retry-after"), this.retryBackoffMs, attempt);
|
|
102
220
|
await new Promise((r) => setTimeout(r, delay));
|
|
103
221
|
continue;
|
|
104
222
|
}
|
|
105
223
|
throw err5;
|
|
106
224
|
}
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
109
|
-
return JSON.parse(
|
|
225
|
+
const text2 = await res.text();
|
|
226
|
+
if (!text2) return void 0;
|
|
227
|
+
return JSON.parse(text2);
|
|
110
228
|
}
|
|
111
229
|
throw lastError;
|
|
112
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* One HTTP attempt. With `timeoutMs` set, the attempt is aborted at the
|
|
233
|
+
* deadline and surfaces as a non-retriable `MindGraphError` (`code:
|
|
234
|
+
* "timeout"`, `status: 0`). Without it the request is sent unchanged — no
|
|
235
|
+
* AbortSignal is attached, preserving the pre-0.16 behaviour.
|
|
236
|
+
*/
|
|
237
|
+
async fetchWithDeadline(url, init, method, path8) {
|
|
238
|
+
if (this.timeoutMs === void 0) {
|
|
239
|
+
return fetch(url, init);
|
|
240
|
+
}
|
|
241
|
+
const controller = new AbortController();
|
|
242
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
243
|
+
try {
|
|
244
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
245
|
+
} catch (error2) {
|
|
246
|
+
if (controller.signal.aborted) {
|
|
247
|
+
throw new MindGraphError(
|
|
248
|
+
`${method} ${path8} timed out after ${this.timeoutMs}ms`,
|
|
249
|
+
0,
|
|
250
|
+
{ error: "timeout", code: "timeout", retriable: false }
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
throw error2;
|
|
254
|
+
} finally {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
113
258
|
get(path8) {
|
|
114
259
|
return this.request("GET", path8);
|
|
115
260
|
}
|
|
@@ -232,10 +377,10 @@ var init_dist = __esm({
|
|
|
232
377
|
* Resolve text to an existing entity via alias matching.
|
|
233
378
|
* Returns `{ uid: string | null }`.
|
|
234
379
|
*/
|
|
235
|
-
async resolveEntity(
|
|
380
|
+
async resolveEntity(text2, agentId) {
|
|
236
381
|
return this.post("/reality/entity", {
|
|
237
382
|
action: "resolve",
|
|
238
|
-
text,
|
|
383
|
+
text: text2,
|
|
239
384
|
agent_id: agentId
|
|
240
385
|
});
|
|
241
386
|
}
|
|
@@ -243,10 +388,10 @@ var init_dist = __esm({
|
|
|
243
388
|
* Fuzzy-match text against existing entities.
|
|
244
389
|
* Returns `{ matches: [{ uid, label, score }] }`.
|
|
245
390
|
*/
|
|
246
|
-
async fuzzyResolveEntity(
|
|
391
|
+
async fuzzyResolveEntity(text2, limit = 5, agentId) {
|
|
247
392
|
return this.post("/reality/entity", {
|
|
248
393
|
action: "fuzzy_resolve",
|
|
249
|
-
text,
|
|
394
|
+
text: text2,
|
|
250
395
|
limit,
|
|
251
396
|
agent_id: agentId
|
|
252
397
|
});
|
|
@@ -359,6 +504,40 @@ var init_dist = __esm({
|
|
|
359
504
|
async memorySync(req) {
|
|
360
505
|
return this.post("/memory/sync", req);
|
|
361
506
|
}
|
|
507
|
+
// ---- Memory (fast path) ----
|
|
508
|
+
/**
|
|
509
|
+
* Store a small piece of text as a memory, synchronously. The node is
|
|
510
|
+
* BM25- and vector-searchable when this resolves (`searchable` says which).
|
|
511
|
+
* Pass `custom_id` to make re-sends an upsert of the same node.
|
|
512
|
+
*/
|
|
513
|
+
async remember(text2, options = {}) {
|
|
514
|
+
return this.post("/memory/remember", { text: text2, ...options });
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Reversibly remove a memory by `uid` or `custom_id` (tombstone plus its
|
|
518
|
+
* connected edges). `dry_run: true` previews the affected edge uids first.
|
|
519
|
+
* Undo with `restore(uid)` and `evolve({ action: "restore_edge", uid })`.
|
|
520
|
+
*/
|
|
521
|
+
async forget(target, options = {}) {
|
|
522
|
+
return this.post("/memory/forget", { ...target, ...options });
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Operator guidance for what agents should remember into a Space; surfaced
|
|
526
|
+
* on every `remember()` response and on `retrieveContext()`. Empty clears it.
|
|
527
|
+
*/
|
|
528
|
+
async setRememberInstructions(text2, options = {}) {
|
|
529
|
+
return this.post("/memory/config", {
|
|
530
|
+
action: "set_remember_instructions",
|
|
531
|
+
text: text2,
|
|
532
|
+
...options
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
async getRememberInstructions(options = {}) {
|
|
536
|
+
return this.post("/memory/config", {
|
|
537
|
+
action: "get_remember_instructions",
|
|
538
|
+
...options
|
|
539
|
+
});
|
|
540
|
+
}
|
|
362
541
|
// ---- Agent Layer ----
|
|
363
542
|
async plan(req) {
|
|
364
543
|
return this.post("/agent/plan", req);
|
|
@@ -545,8 +724,8 @@ var init_dist = __esm({
|
|
|
545
724
|
async getAliases(uid) {
|
|
546
725
|
return this.get(`/aliases/${seg(uid)}`);
|
|
547
726
|
}
|
|
548
|
-
async resolveAlias(
|
|
549
|
-
return this.get(`/resolve?text=${encodeURIComponent(
|
|
727
|
+
async resolveAlias(text2) {
|
|
728
|
+
return this.get(`/resolve?text=${encodeURIComponent(text2)}`);
|
|
550
729
|
}
|
|
551
730
|
// ---- Export / Import ----
|
|
552
731
|
async exportGraph() {
|
|
@@ -581,7 +760,7 @@ var init_dist = __esm({
|
|
|
581
760
|
start_uid: uid,
|
|
582
761
|
max_depth: maxDepth
|
|
583
762
|
});
|
|
584
|
-
return r
|
|
763
|
+
return pathSteps(r);
|
|
585
764
|
}
|
|
586
765
|
async neighborhood(uid, maxDepth = 1) {
|
|
587
766
|
const r = await this.post("/traverse", {
|
|
@@ -589,7 +768,7 @@ var init_dist = __esm({
|
|
|
589
768
|
start_uid: uid,
|
|
590
769
|
max_depth: maxDepth
|
|
591
770
|
});
|
|
592
|
-
return r
|
|
771
|
+
return pathSteps(r);
|
|
593
772
|
}
|
|
594
773
|
async subgraph(uid, opts) {
|
|
595
774
|
return this.post("/subgraph", { start_uids: [uid], ...opts });
|
|
@@ -960,11 +1139,19 @@ var init_dist = __esm({
|
|
|
960
1139
|
/**
|
|
961
1140
|
* Create a domain object by hand (auto-approved). Returns the created node
|
|
962
1141
|
* uid + the audit proposal id. Throws 409 if an object of the same type +
|
|
963
|
-
* canonical_name already exists, unless `allow_duplicate` is set.
|
|
1142
|
+
* canonical_name already exists, unless `allow_duplicate` is set. The
|
|
1143
|
+
* schema's identity key is always enforced.
|
|
964
1144
|
*/
|
|
965
1145
|
async createDomainObject(req) {
|
|
966
1146
|
return this.post("/v1/ontology/objects", req);
|
|
967
1147
|
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Schema-validated authored update with optimistic concurrency. Identity
|
|
1150
|
+
* fields are immutable; create and explicitly merge when identity changes.
|
|
1151
|
+
*/
|
|
1152
|
+
async updateDomainObject(uid, req) {
|
|
1153
|
+
return this.patch(`/v1/ontology/objects/${seg(uid)}`, req);
|
|
1154
|
+
}
|
|
968
1155
|
async linkDomainObjects(req) {
|
|
969
1156
|
return this.post("/ontology/relation", { action: "create", ...req });
|
|
970
1157
|
}
|
|
@@ -1163,29 +1350,29 @@ async function runProcess(executable, args, timeoutMs, env, cwd) {
|
|
|
1163
1350
|
child.stderr.on("data", collect(stderr));
|
|
1164
1351
|
child.on("error", (cause) => {
|
|
1165
1352
|
clearTimeout(timer);
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
rejectPromise(
|
|
1353
|
+
const error2 = new Error(cause.message);
|
|
1354
|
+
error2.kind = cause.code === "ENOENT" ? "absent" : "command_failed";
|
|
1355
|
+
rejectPromise(error2);
|
|
1169
1356
|
});
|
|
1170
1357
|
child.on("close", (code) => {
|
|
1171
1358
|
clearTimeout(timer);
|
|
1172
1359
|
if (timedOut) {
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
rejectPromise(
|
|
1360
|
+
const error2 = new Error(`command timed out after ${timeoutMs}ms`);
|
|
1361
|
+
error2.kind = "timeout";
|
|
1362
|
+
rejectPromise(error2);
|
|
1176
1363
|
return;
|
|
1177
1364
|
}
|
|
1178
1365
|
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
rejectPromise(
|
|
1366
|
+
const error2 = new Error("codegraph output exceeded 5 MiB");
|
|
1367
|
+
error2.kind = "command_failed";
|
|
1368
|
+
rejectPromise(error2);
|
|
1182
1369
|
return;
|
|
1183
1370
|
}
|
|
1184
1371
|
if (code !== 0) {
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
rejectPromise(
|
|
1372
|
+
const error2 = new Error(Buffer.concat(stderr).toString("utf8").trim());
|
|
1373
|
+
error2.kind = "command_failed";
|
|
1374
|
+
error2.exitCode = code;
|
|
1375
|
+
rejectPromise(error2);
|
|
1189
1376
|
return;
|
|
1190
1377
|
}
|
|
1191
1378
|
resolvePromise(Buffer.concat(stdout).toString("utf8"));
|
|
@@ -1213,9 +1400,7 @@ function codeRefIdentityKey(ref) {
|
|
|
1213
1400
|
qualified_name: ref.qualifiedName,
|
|
1214
1401
|
disambiguator: {
|
|
1215
1402
|
signature: ref.signature ?? "",
|
|
1216
|
-
path: ref.path
|
|
1217
|
-
start_line: ref.startLine,
|
|
1218
|
-
end_line: ref.endLine
|
|
1403
|
+
path: ref.path
|
|
1219
1404
|
}
|
|
1220
1405
|
};
|
|
1221
1406
|
}
|
|
@@ -1789,6 +1974,22 @@ function conflictState(e) {
|
|
|
1789
1974
|
}
|
|
1790
1975
|
return lifted;
|
|
1791
1976
|
}
|
|
1977
|
+
function toolError(e, fallbackCode) {
|
|
1978
|
+
const body = e instanceof MindGraphError && e.body && typeof e.body === "object" && !Array.isArray(e.body) ? e.body : {};
|
|
1979
|
+
const code = typeof body.code === "string" ? body.code : fallbackCode;
|
|
1980
|
+
const payload = {
|
|
1981
|
+
error: errorDetail(e),
|
|
1982
|
+
...conflictState(e),
|
|
1983
|
+
...e instanceof MindGraphError ? { status: e.status } : {},
|
|
1984
|
+
...code !== void 0 ? { code } : {},
|
|
1985
|
+
...typeof body.retriable === "boolean" ? { retriable: body.retriable } : {}
|
|
1986
|
+
};
|
|
1987
|
+
return {
|
|
1988
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
1989
|
+
structuredContent: payload,
|
|
1990
|
+
isError: true
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1792
1993
|
var CONFLICT_STATE_KEYS;
|
|
1793
1994
|
var init_error_detail = __esm({
|
|
1794
1995
|
"src/error-detail.ts"() {
|
|
@@ -1996,7 +2197,7 @@ async function handleCodeTool(client2, args, adapter = new CodegraphAdapter({ cw
|
|
|
1996
2197
|
if (cause instanceof UnknownRepositoryError) {
|
|
1997
2198
|
return err("unknown_repository", cause.message);
|
|
1998
2199
|
}
|
|
1999
|
-
return
|
|
2200
|
+
return toolError(cause, "code_tool_failed");
|
|
2000
2201
|
}
|
|
2001
2202
|
}
|
|
2002
2203
|
async function attachCodeRefsToToolResult(client2, result, args, adapter) {
|
|
@@ -2104,7 +2305,7 @@ async function anchorCodeRef(client2, ref, repositoryUid, spaceUid, agentId) {
|
|
|
2104
2305
|
identity_space_uid: spaceUid,
|
|
2105
2306
|
agent_id: agentId
|
|
2106
2307
|
});
|
|
2107
|
-
if (response.uid) {
|
|
2308
|
+
if (response.uid && response.created !== false && response.status !== "existing") {
|
|
2108
2309
|
await client2.entity({
|
|
2109
2310
|
action: "relate",
|
|
2110
2311
|
source_uid: response.uid,
|
|
@@ -2739,8 +2940,8 @@ async function handleSyncTool(client2, args) {
|
|
|
2739
2940
|
}
|
|
2740
2941
|
}
|
|
2741
2942
|
return ok2(await remote.memorySync(request));
|
|
2742
|
-
} catch (
|
|
2743
|
-
return
|
|
2943
|
+
} catch (error2) {
|
|
2944
|
+
return toolError(error2, "sync_failed");
|
|
2744
2945
|
}
|
|
2745
2946
|
}
|
|
2746
2947
|
async function scanRepository(remote, repository, requested, provider, agentId) {
|
|
@@ -2874,12 +3075,22 @@ function str(value) {
|
|
|
2874
3075
|
function num(value) {
|
|
2875
3076
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2876
3077
|
}
|
|
3078
|
+
function edgeTypeName(value) {
|
|
3079
|
+
return str(value) ?? str(obj(value)?.Custom);
|
|
3080
|
+
}
|
|
3081
|
+
function renderBudget(requested) {
|
|
3082
|
+
if (requested === void 0 || !Number.isFinite(requested)) return RENDER_CHAR_BUDGET;
|
|
3083
|
+
return Math.min(
|
|
3084
|
+
RENDER_CHAR_BUDGET,
|
|
3085
|
+
Math.max(MIN_RENDER_CHAR_BUDGET, Math.floor(requested))
|
|
3086
|
+
);
|
|
3087
|
+
}
|
|
2877
3088
|
function clip(value, max, state) {
|
|
2878
|
-
const
|
|
2879
|
-
if (!
|
|
2880
|
-
if (
|
|
3089
|
+
const text2 = str(value);
|
|
3090
|
+
if (!text2) return void 0;
|
|
3091
|
+
if (text2.length <= max) return text2;
|
|
2881
3092
|
state.bounded = true;
|
|
2882
|
-
return `${
|
|
3093
|
+
return `${text2.slice(0, max - 1)}\u2026`;
|
|
2883
3094
|
}
|
|
2884
3095
|
function isNodeShaped(value) {
|
|
2885
3096
|
const node = obj(value);
|
|
@@ -3001,7 +3212,7 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
3001
3212
|
for (const raw of edges) {
|
|
3002
3213
|
const edge = obj(raw);
|
|
3003
3214
|
if (!edge) continue;
|
|
3004
|
-
const type =
|
|
3215
|
+
const type = edgeTypeName(edge.edge_type) || "?";
|
|
3005
3216
|
const from = str(edge.from_uid);
|
|
3006
3217
|
const to = str(edge.to_uid);
|
|
3007
3218
|
if (CURATION_EDGE_TYPES.has(type)) continue;
|
|
@@ -3014,25 +3225,29 @@ function relationshipItems(edges, labelByUid, state, options) {
|
|
|
3014
3225
|
if (lines.length > RELATIONSHIP_MAX) {
|
|
3015
3226
|
state.bounded = true;
|
|
3016
3227
|
const extra = lines.length - RELATIONSHIP_MAX;
|
|
3228
|
+
state.omitted += extra;
|
|
3017
3229
|
return [...lines.slice(0, RELATIONSHIP_MAX), `- (+${extra} more relationships)`];
|
|
3018
3230
|
}
|
|
3019
3231
|
return lines;
|
|
3020
3232
|
}
|
|
3021
|
-
function assemble(header, sections, state) {
|
|
3233
|
+
function assemble(header, sections, state, maxChars) {
|
|
3234
|
+
const budget = renderBudget(maxChars);
|
|
3235
|
+
const packingBudget = Math.max(header.length, budget - BOUNDED_MARKER_RESERVE);
|
|
3022
3236
|
const lines = [header];
|
|
3023
3237
|
let used = header.length;
|
|
3024
3238
|
for (const section of sections) {
|
|
3025
3239
|
if (section.items.length === 0 && !section.heading) continue;
|
|
3026
3240
|
const headingCost = section.heading.length + 2;
|
|
3027
|
-
if (used + headingCost >
|
|
3241
|
+
if (used + headingCost > packingBudget) {
|
|
3028
3242
|
state.bounded = true;
|
|
3243
|
+
state.omitted += Math.max(1, section.items.length);
|
|
3029
3244
|
continue;
|
|
3030
3245
|
}
|
|
3031
3246
|
let sectionUsed = 0;
|
|
3032
3247
|
const kept = [];
|
|
3033
3248
|
let dropped = 0;
|
|
3034
3249
|
for (const item of section.items) {
|
|
3035
|
-
if (used + headingCost + sectionUsed + item.length + 1 >
|
|
3250
|
+
if (used + headingCost + sectionUsed + item.length + 1 > packingBudget) {
|
|
3036
3251
|
dropped += 1;
|
|
3037
3252
|
continue;
|
|
3038
3253
|
}
|
|
@@ -3041,13 +3256,17 @@ function assemble(header, sections, state) {
|
|
|
3041
3256
|
}
|
|
3042
3257
|
if (kept.length === 0 && section.items.length > 0) {
|
|
3043
3258
|
state.bounded = true;
|
|
3259
|
+
state.omitted += dropped;
|
|
3044
3260
|
continue;
|
|
3045
3261
|
}
|
|
3046
3262
|
if (dropped > 0) {
|
|
3047
3263
|
state.bounded = true;
|
|
3264
|
+
state.omitted += dropped;
|
|
3048
3265
|
const marker = `(+${dropped} more not shown)`;
|
|
3049
|
-
|
|
3050
|
-
|
|
3266
|
+
if (used + headingCost + sectionUsed + marker.length + 1 <= packingBudget) {
|
|
3267
|
+
kept.push(marker);
|
|
3268
|
+
sectionUsed += marker.length + 1;
|
|
3269
|
+
}
|
|
3051
3270
|
}
|
|
3052
3271
|
lines.push(
|
|
3053
3272
|
section.items.length === 0 ? section.heading : section.heading ? `${section.heading}
|
|
@@ -3057,10 +3276,10 @@ ${kept.join("\n")}` : kept.join("\n")
|
|
|
3057
3276
|
}
|
|
3058
3277
|
if (state.bounded) {
|
|
3059
3278
|
lines.push(
|
|
3060
|
-
|
|
3279
|
+
`\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]`
|
|
3061
3280
|
);
|
|
3062
3281
|
}
|
|
3063
|
-
return lines.join("\n\n");
|
|
3282
|
+
return lines.join("\n\n").slice(0, budget);
|
|
3064
3283
|
}
|
|
3065
3284
|
function policySections(payload, state) {
|
|
3066
3285
|
const policies = Array.isArray(payload.applicable_policies) ? payload.applicable_policies : [];
|
|
@@ -3081,7 +3300,7 @@ function hiddenSections(payload) {
|
|
|
3081
3300
|
}
|
|
3082
3301
|
];
|
|
3083
3302
|
}
|
|
3084
|
-
function renderContext(response) {
|
|
3303
|
+
function renderContext(response, maxChars) {
|
|
3085
3304
|
const payload = obj(response);
|
|
3086
3305
|
if (!payload) return void 0;
|
|
3087
3306
|
const graph = obj(payload.graph);
|
|
@@ -3091,7 +3310,7 @@ function renderContext(response) {
|
|
|
3091
3310
|
const infraOnly = shaped.length - nodes.length;
|
|
3092
3311
|
const articles = Array.isArray(payload.articles) ? payload.articles : [];
|
|
3093
3312
|
const chunks = Array.isArray(payload.chunks) ? payload.chunks : [];
|
|
3094
|
-
const state = { bounded: false };
|
|
3313
|
+
const state = { bounded: false, omitted: 0 };
|
|
3095
3314
|
const sections = [];
|
|
3096
3315
|
if (articles.length > 0) {
|
|
3097
3316
|
sections.push({
|
|
@@ -3134,11 +3353,129 @@ ${clip(article.content, ARTICLE_MAX, state) || ""}`
|
|
|
3134
3353
|
return "No results found for this search.";
|
|
3135
3354
|
}
|
|
3136
3355
|
if (nodes.length === 0 && articles.length === 0 && chunks.length === 0) {
|
|
3137
|
-
return assemble(
|
|
3356
|
+
return assemble(
|
|
3357
|
+
"# Retrieved context\n\nNo graph results matched this search.",
|
|
3358
|
+
sections,
|
|
3359
|
+
state,
|
|
3360
|
+
maxChars
|
|
3361
|
+
);
|
|
3362
|
+
}
|
|
3363
|
+
return assemble("# Retrieved context", sections, state, maxChars);
|
|
3364
|
+
}
|
|
3365
|
+
function resumeEntry(raw, state, fallbackType) {
|
|
3366
|
+
const wrapper = obj(raw);
|
|
3367
|
+
if (!wrapper) return void 0;
|
|
3368
|
+
const value = obj(wrapper.node) ?? wrapper;
|
|
3369
|
+
if (isNodeShaped(value)) return nodeLines(value, state);
|
|
3370
|
+
const uid = str(value.uid);
|
|
3371
|
+
const props = obj(value.props);
|
|
3372
|
+
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;
|
|
3373
|
+
const status = str(value.status) ?? str(props?.status);
|
|
3374
|
+
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);
|
|
3375
|
+
const details = [
|
|
3376
|
+
status ? `status ${status}` : void 0,
|
|
3377
|
+
str(value.path) ? `path ${str(value.path)}` : void 0,
|
|
3378
|
+
str(value.symbol) ? `symbol ${str(value.symbol)}` : void 0
|
|
3379
|
+
].filter(Boolean);
|
|
3380
|
+
const head = `- **${label}**${uid ? ` [${uid}]` : ""}${details.length > 0 ? ` (${details.join(", ")})` : ""}`;
|
|
3381
|
+
return summary && summary !== label ? `${head}: ${summary}` : head;
|
|
3382
|
+
}
|
|
3383
|
+
function resumeSection(heading, values, state, fallbackType) {
|
|
3384
|
+
const items = values.map((value) => resumeEntry(value, state, fallbackType)).filter((value) => Boolean(value));
|
|
3385
|
+
return items.length > 0 ? { heading, items } : void 0;
|
|
3386
|
+
}
|
|
3387
|
+
function renderResumeContext(response, maxChars) {
|
|
3388
|
+
const payload = obj(response);
|
|
3389
|
+
if (!payload) return void 0;
|
|
3390
|
+
const state = { bounded: false, omitted: 0 };
|
|
3391
|
+
const status = str(payload.status);
|
|
3392
|
+
if (!payload.task && status === "no_eligible_work") {
|
|
3393
|
+
const scopedOut = Array.isArray(payload.scoped_out_tasks) ? payload.scoped_out_tasks.length : 0;
|
|
3394
|
+
const note = scopedOut > 0 ? ` ${scopedOut} task(s) exist outside the requested scope.` : "";
|
|
3395
|
+
return assemble(
|
|
3396
|
+
"# Resume context",
|
|
3397
|
+
[{ heading: `No eligible work was found in the requested scope.${note}`, items: [] }],
|
|
3398
|
+
state,
|
|
3399
|
+
maxChars
|
|
3400
|
+
);
|
|
3401
|
+
}
|
|
3402
|
+
const sections = [];
|
|
3403
|
+
const push = (section) => {
|
|
3404
|
+
if (section) sections.push(section);
|
|
3405
|
+
};
|
|
3406
|
+
push(resumeSection("## Current task", [payload.task], state, "Task"));
|
|
3407
|
+
push(
|
|
3408
|
+
resumeSection(
|
|
3409
|
+
"## Goal and project",
|
|
3410
|
+
[payload.goal, payload.project].filter(Boolean),
|
|
3411
|
+
state,
|
|
3412
|
+
"Scope"
|
|
3413
|
+
)
|
|
3414
|
+
);
|
|
3415
|
+
push(resumeSection("## Plan", [payload.plan], state, "Plan"));
|
|
3416
|
+
push(
|
|
3417
|
+
resumeSection(
|
|
3418
|
+
"## Next steps",
|
|
3419
|
+
Array.isArray(payload.next_steps) ? payload.next_steps : [],
|
|
3420
|
+
state,
|
|
3421
|
+
"Next step"
|
|
3422
|
+
)
|
|
3423
|
+
);
|
|
3424
|
+
push(
|
|
3425
|
+
resumeSection(
|
|
3426
|
+
"## Blockers",
|
|
3427
|
+
Array.isArray(payload.blockers) ? payload.blockers : [],
|
|
3428
|
+
state,
|
|
3429
|
+
"Blocker"
|
|
3430
|
+
)
|
|
3431
|
+
);
|
|
3432
|
+
const knowledge = obj(payload.knowledge);
|
|
3433
|
+
push(
|
|
3434
|
+
resumeSection(
|
|
3435
|
+
"## Relevant lessons and risks",
|
|
3436
|
+
[
|
|
3437
|
+
...Array.isArray(knowledge?.lessons) ? knowledge.lessons : [],
|
|
3438
|
+
...Array.isArray(knowledge?.risks) ? knowledge.risks : []
|
|
3439
|
+
],
|
|
3440
|
+
state,
|
|
3441
|
+
"Knowledge"
|
|
3442
|
+
)
|
|
3443
|
+
);
|
|
3444
|
+
push(
|
|
3445
|
+
resumeSection(
|
|
3446
|
+
"## Active execution",
|
|
3447
|
+
[payload.active_execution].filter(Boolean),
|
|
3448
|
+
state,
|
|
3449
|
+
"Execution"
|
|
3450
|
+
)
|
|
3451
|
+
);
|
|
3452
|
+
push(
|
|
3453
|
+
resumeSection(
|
|
3454
|
+
"## Recent executions",
|
|
3455
|
+
Array.isArray(payload.recent_executions) ? payload.recent_executions : [],
|
|
3456
|
+
state,
|
|
3457
|
+
"Execution"
|
|
3458
|
+
)
|
|
3459
|
+
);
|
|
3460
|
+
push(
|
|
3461
|
+
resumeSection(
|
|
3462
|
+
"## Code targets",
|
|
3463
|
+
Array.isArray(payload.code_targets) ? payload.code_targets : [],
|
|
3464
|
+
state,
|
|
3465
|
+
"Code target"
|
|
3466
|
+
)
|
|
3467
|
+
);
|
|
3468
|
+
push(resumeSection("## Lease", [payload.lease].filter(Boolean), state, "Lease"));
|
|
3469
|
+
const warning = clip(payload.warning, SUMMARY_MAX, state);
|
|
3470
|
+
if (warning) sections.push({ heading: "## Warning", items: [`- ${warning}`] });
|
|
3471
|
+
const selectionReason = clip(payload.selection_reason, SUMMARY_MAX, state);
|
|
3472
|
+
if (selectionReason) {
|
|
3473
|
+
sections.push({ heading: "## Selection", items: [`- ${selectionReason}`] });
|
|
3138
3474
|
}
|
|
3139
|
-
|
|
3475
|
+
if (sections.length === 0) return void 0;
|
|
3476
|
+
return assemble("# Resume context", sections, state, maxChars);
|
|
3140
3477
|
}
|
|
3141
|
-
function renderNodeList(response, title, limit) {
|
|
3478
|
+
function renderNodeList(response, title, limit, maxChars) {
|
|
3142
3479
|
let candidates = [];
|
|
3143
3480
|
if (Array.isArray(response)) {
|
|
3144
3481
|
candidates = response;
|
|
@@ -3156,8 +3493,9 @@ function renderNodeList(response, title, limit) {
|
|
|
3156
3493
|
let nodes = candidates.map(unwrapSearchResult).filter((node) => Boolean(node));
|
|
3157
3494
|
if (nodes.length === 0) return void 0;
|
|
3158
3495
|
const total = nodes.length;
|
|
3159
|
-
const state = { bounded: false };
|
|
3496
|
+
const state = { bounded: false, omitted: 0 };
|
|
3160
3497
|
if (limit !== void 0 && limit > 0 && nodes.length > limit) {
|
|
3498
|
+
state.omitted += nodes.length - limit;
|
|
3161
3499
|
nodes = nodes.slice(0, limit);
|
|
3162
3500
|
state.bounded = true;
|
|
3163
3501
|
}
|
|
@@ -3166,18 +3504,23 @@ function renderNodeList(response, title, limit) {
|
|
|
3166
3504
|
return assemble(
|
|
3167
3505
|
`# ${title} (${shown === total ? total : `${shown} of ${total}`})`,
|
|
3168
3506
|
sections,
|
|
3169
|
-
state
|
|
3507
|
+
state,
|
|
3508
|
+
maxChars
|
|
3170
3509
|
);
|
|
3171
3510
|
}
|
|
3172
|
-
function renderTraversal(response) {
|
|
3511
|
+
function renderTraversal(response, maxChars) {
|
|
3512
|
+
const directSteps = Array.isArray(response) ? response : void 0;
|
|
3173
3513
|
const payload = obj(response);
|
|
3174
|
-
if (!payload) return void 0;
|
|
3175
|
-
const
|
|
3514
|
+
if (!payload && !directSteps) return void 0;
|
|
3515
|
+
const body = payload ?? {};
|
|
3516
|
+
const container = obj(body.graph) ?? body;
|
|
3176
3517
|
const rawNodes = Array.isArray(container.nodes) ? container.nodes : [];
|
|
3177
3518
|
const nodes = rawNodes.filter(isNodeShaped);
|
|
3178
|
-
const paths = Array.isArray(
|
|
3179
|
-
|
|
3180
|
-
const
|
|
3519
|
+
const paths = Array.isArray(body.paths) ? body.paths : [];
|
|
3520
|
+
const hasSteps = directSteps !== void 0 || Object.hasOwn(body, "steps");
|
|
3521
|
+
const rawSteps = directSteps ?? (Array.isArray(body.steps) ? body.steps : []);
|
|
3522
|
+
if (nodes.length === 0 && paths.length === 0 && !hasSteps) return void 0;
|
|
3523
|
+
const state = { bounded: false, omitted: 0 };
|
|
3181
3524
|
const sections = [];
|
|
3182
3525
|
const labelByUid = /* @__PURE__ */ new Map();
|
|
3183
3526
|
for (const node of nodes) labelByUid.set(str(node.uid), str(node.label) || "?");
|
|
@@ -3201,6 +3544,42 @@ function renderTraversal(response) {
|
|
|
3201
3544
|
});
|
|
3202
3545
|
sections.push({ heading: "## Paths", items });
|
|
3203
3546
|
}
|
|
3547
|
+
if (hasSteps) {
|
|
3548
|
+
const stepItems = rawSteps.map((raw) => obj(raw)).filter((step) => Boolean(step)).map((step) => {
|
|
3549
|
+
const depth = num(step.depth);
|
|
3550
|
+
const uid = str(step.node_uid) ?? str(step.uid) ?? str(step.edge_to_uid) ?? "?";
|
|
3551
|
+
const parent = str(step.parent_uid) ?? str(step.edge_from_uid);
|
|
3552
|
+
const label = str(step.label) || "(unlabeled)";
|
|
3553
|
+
const relation = edgeTypeName(step.edge_type);
|
|
3554
|
+
const role = str(step.traversal_role);
|
|
3555
|
+
const type = str(step.node_type) ?? str(obj(step.node_type)?.Custom);
|
|
3556
|
+
const cost = num(step.path_cost);
|
|
3557
|
+
const confidence = num(step.path_confidence);
|
|
3558
|
+
const prefix = [
|
|
3559
|
+
depth !== void 0 ? `depth ${depth}` : void 0,
|
|
3560
|
+
role,
|
|
3561
|
+
relation ? `\u2014${relation}\u2192` : void 0
|
|
3562
|
+
].filter(Boolean).join(" ");
|
|
3563
|
+
const meta = [
|
|
3564
|
+
type,
|
|
3565
|
+
parent ? `parent ${parent}` : void 0,
|
|
3566
|
+
cost !== void 0 ? `cost ${cost}` : void 0,
|
|
3567
|
+
confidence !== void 0 ? `confidence ${confidence}` : void 0
|
|
3568
|
+
].filter(Boolean).join(", ");
|
|
3569
|
+
return `- ${prefix ? `${prefix}: ` : ""}**${label}** [${uid}]${meta ? ` (${meta})` : ""}`;
|
|
3570
|
+
});
|
|
3571
|
+
if (stepItems.length > 0) {
|
|
3572
|
+
sections.push({ heading: "## Traversal steps", items: stepItems });
|
|
3573
|
+
} else {
|
|
3574
|
+
const start = str(body.start_uid) || "?";
|
|
3575
|
+
const end = str(body.end_uid);
|
|
3576
|
+
const mode2 = str(body.mode);
|
|
3577
|
+
sections.push({
|
|
3578
|
+
heading: mode2 === "path" && end ? `No path found from [${start}] to [${end}].` : `No traversal steps returned from [${start}].`,
|
|
3579
|
+
items: []
|
|
3580
|
+
});
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3204
3583
|
if (nodes.length > 0) {
|
|
3205
3584
|
sections.push(...groupedNodeSections(nodes, state, "## Nodes\n\n"));
|
|
3206
3585
|
const relationships = relationshipItems(
|
|
@@ -3212,7 +3591,13 @@ function renderTraversal(response) {
|
|
|
3212
3591
|
sections.push({ heading: "## Relationships", items: relationships });
|
|
3213
3592
|
}
|
|
3214
3593
|
}
|
|
3215
|
-
|
|
3594
|
+
const mode = str(body.mode);
|
|
3595
|
+
return assemble(
|
|
3596
|
+
`# Graph traversal${mode ? ` (${mode})` : ""}`,
|
|
3597
|
+
sections,
|
|
3598
|
+
state,
|
|
3599
|
+
maxChars
|
|
3600
|
+
);
|
|
3216
3601
|
}
|
|
3217
3602
|
function neighborLine(value) {
|
|
3218
3603
|
const node = obj(value);
|
|
@@ -3233,7 +3618,7 @@ function renderOntologyAnswer(response) {
|
|
|
3233
3618
|
if (objects.length === 0 && cognitiveEmpty && provenance.length === 0) {
|
|
3234
3619
|
return hasQuerySignature ? "No matching domain objects." : void 0;
|
|
3235
3620
|
}
|
|
3236
|
-
const state = { bounded: false };
|
|
3621
|
+
const state = { bounded: false, omitted: 0 };
|
|
3237
3622
|
const sections = [];
|
|
3238
3623
|
if (objects.length > 0) {
|
|
3239
3624
|
sections.push(...groupedNodeSections(objects, state));
|
|
@@ -3299,7 +3684,7 @@ function renderObjectList(response, title) {
|
|
|
3299
3684
|
if (items.length === 0) {
|
|
3300
3685
|
return rawItems ? `# ${title} (0 results)` : void 0;
|
|
3301
3686
|
}
|
|
3302
|
-
const state = { bounded: false };
|
|
3687
|
+
const state = { bounded: false, omitted: 0 };
|
|
3303
3688
|
const sections = groupedNodeSections(items, state);
|
|
3304
3689
|
const total = num(payload.total_count);
|
|
3305
3690
|
const truncations = Array.isArray(payload.truncation_reasons) ? payload.truncation_reasons.filter((reason) => typeof reason === "string") : [];
|
|
@@ -3314,7 +3699,7 @@ function renderJobs(response) {
|
|
|
3314
3699
|
const jobs = Array.isArray(response) ? response : obj(response)?.jobs;
|
|
3315
3700
|
if (!Array.isArray(jobs)) return void 0;
|
|
3316
3701
|
if (jobs.length === 0) return "No ingestion jobs.";
|
|
3317
|
-
const state = { bounded: false };
|
|
3702
|
+
const state = { bounded: false, omitted: 0 };
|
|
3318
3703
|
const sorted = jobs.map((raw) => obj(raw)).filter((job) => Boolean(job)).sort((a, b) => (num(b.created_at) ?? 0) - (num(a.created_at) ?? 0));
|
|
3319
3704
|
const shown = sorted.slice(0, JOBS_RENDER_MAX);
|
|
3320
3705
|
if (shown.length < sorted.length) state.bounded = true;
|
|
@@ -3340,7 +3725,7 @@ function renderJobs(response) {
|
|
|
3340
3725
|
function renderSignals(response) {
|
|
3341
3726
|
const payload = obj(response);
|
|
3342
3727
|
if (!payload) return void 0;
|
|
3343
|
-
const state = { bounded: false };
|
|
3728
|
+
const state = { bounded: false, omitted: 0 };
|
|
3344
3729
|
const sections = [];
|
|
3345
3730
|
for (const [key, value] of Object.entries(payload)) {
|
|
3346
3731
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
@@ -3364,7 +3749,7 @@ function renderSignals(response) {
|
|
|
3364
3749
|
if (sections.length === 0) return void 0;
|
|
3365
3750
|
return assemble("# Synthesis signals", sections, state);
|
|
3366
3751
|
}
|
|
3367
|
-
var LABEL_MAX, SUMMARY_MAX, QUOTE_MAX, ARTICLE_MAX, CHUNK_MAX, RELATIONSHIP_MAX, RENDER_CHAR_BUDGET, CURATION_EDGE_TYPES, INFRA_NODE_TYPES, JOBS_RENDER_MAX;
|
|
3752
|
+
var LABEL_MAX, SUMMARY_MAX, QUOTE_MAX, ARTICLE_MAX, CHUNK_MAX, RELATIONSHIP_MAX, RENDER_CHAR_BUDGET, MIN_RENDER_CHAR_BUDGET, BOUNDED_MARKER_RESERVE, CURATION_EDGE_TYPES, INFRA_NODE_TYPES, JOBS_RENDER_MAX;
|
|
3368
3753
|
var init_render = __esm({
|
|
3369
3754
|
"src/render.ts"() {
|
|
3370
3755
|
"use strict";
|
|
@@ -3375,13 +3760,570 @@ var init_render = __esm({
|
|
|
3375
3760
|
CHUNK_MAX = 6e3;
|
|
3376
3761
|
RELATIONSHIP_MAX = 40;
|
|
3377
3762
|
RENDER_CHAR_BUDGET = 24e3;
|
|
3763
|
+
MIN_RENDER_CHAR_BUDGET = 512;
|
|
3764
|
+
BOUNDED_MARKER_RESERVE = 220;
|
|
3378
3765
|
CURATION_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
3379
3766
|
INFRA_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
3380
3767
|
JOBS_RENDER_MAX = 20;
|
|
3381
3768
|
}
|
|
3382
3769
|
});
|
|
3383
3770
|
|
|
3771
|
+
// src/memory-tool.ts
|
|
3772
|
+
function obj2(value) {
|
|
3773
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3774
|
+
}
|
|
3775
|
+
function text(value) {
|
|
3776
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3777
|
+
}
|
|
3778
|
+
function stableJson(value) {
|
|
3779
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
3780
|
+
if (value && typeof value === "object") {
|
|
3781
|
+
return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
3782
|
+
}
|
|
3783
|
+
return JSON.stringify(value);
|
|
3784
|
+
}
|
|
3785
|
+
function sha2562(value) {
|
|
3786
|
+
return (0, import_node_crypto7.createHash)("sha256").update(value).digest("hex");
|
|
3787
|
+
}
|
|
3788
|
+
function outputBudget(value) {
|
|
3789
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_OUTPUT_CHARS;
|
|
3790
|
+
return Math.min(MAX_OUTPUT_CHARS, Math.max(MIN_OUTPUT_CHARS, Math.floor(value)));
|
|
3791
|
+
}
|
|
3792
|
+
function defined(values) {
|
|
3793
|
+
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
|
|
3794
|
+
}
|
|
3795
|
+
function memoryStatus(config = {}) {
|
|
3796
|
+
return {
|
|
3797
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
3798
|
+
action: "status",
|
|
3799
|
+
profile: "M0",
|
|
3800
|
+
server: defined({
|
|
3801
|
+
name: "mindgraph-mcp",
|
|
3802
|
+
version: config.serverVersion ?? "unknown",
|
|
3803
|
+
base_url: config.baseUrl
|
|
3804
|
+
}),
|
|
3805
|
+
integration: {
|
|
3806
|
+
adapter_state: "model_controlled",
|
|
3807
|
+
harness: config.harness ?? "generic",
|
|
3808
|
+
configured_tool_profile: config.profile ?? "general",
|
|
3809
|
+
automatic_capture: false,
|
|
3810
|
+
automatic_delivery: false,
|
|
3811
|
+
delivery_verification: "unsupported",
|
|
3812
|
+
curator_mode: "disabled"
|
|
3813
|
+
},
|
|
3814
|
+
scope: defined({ org_id: config.orgId, agent_id: config.agentId }),
|
|
3815
|
+
capabilities: {
|
|
3816
|
+
status: true,
|
|
3817
|
+
topic_context: true,
|
|
3818
|
+
authoritative_resume_context: true,
|
|
3819
|
+
bounded_rendering: true,
|
|
3820
|
+
structured_content: true,
|
|
3821
|
+
typed_explicit_writes: true,
|
|
3822
|
+
lifecycle_event_ingest: false,
|
|
3823
|
+
automatic_context_injection: false,
|
|
3824
|
+
curator_mutation: false
|
|
3825
|
+
},
|
|
3826
|
+
degradation: [
|
|
3827
|
+
{
|
|
3828
|
+
code: "automatic_capture_unavailable",
|
|
3829
|
+
message: "M0 does not observe host lifecycle events; explicit typed write tools remain available."
|
|
3830
|
+
},
|
|
3831
|
+
{
|
|
3832
|
+
code: "delivery_unverified",
|
|
3833
|
+
message: "A successful MCP read does not prove that the host injected or used the returned context."
|
|
3834
|
+
},
|
|
3835
|
+
{
|
|
3836
|
+
code: "curator_disabled",
|
|
3837
|
+
message: "Curator proposals and autonomous mutation are not enabled in M0."
|
|
3838
|
+
}
|
|
3839
|
+
]
|
|
3840
|
+
};
|
|
3841
|
+
}
|
|
3842
|
+
function nodeType(node) {
|
|
3843
|
+
const raw = node.node_type;
|
|
3844
|
+
if (typeof raw === "string") return raw;
|
|
3845
|
+
return text(obj2(raw)?.Custom) ?? "Node";
|
|
3846
|
+
}
|
|
3847
|
+
function compactItem(raw, fallbackType) {
|
|
3848
|
+
const wrapper = obj2(raw);
|
|
3849
|
+
if (!wrapper) return void 0;
|
|
3850
|
+
const value = obj2(wrapper.node) ?? obj2(wrapper.object) ?? wrapper;
|
|
3851
|
+
const uid = text(value.uid) ?? text(value.chunk_uid);
|
|
3852
|
+
if (!uid) return void 0;
|
|
3853
|
+
return defined({
|
|
3854
|
+
uid,
|
|
3855
|
+
type: fallbackType ?? nodeType(value),
|
|
3856
|
+
label: text(value.label) ?? text(value.document_title),
|
|
3857
|
+
truth_status: text(value.truth_status) ?? text(obj2(value.props)?.truth_status),
|
|
3858
|
+
superseded: value.superseded === true ? true : void 0,
|
|
3859
|
+
currently_valid: value.currently_valid === false ? false : void 0,
|
|
3860
|
+
valid_at_time: value.valid_at_time === false ? false : void 0,
|
|
3861
|
+
retrieval_origin: text(value.retrieval_origin),
|
|
3862
|
+
retrieval_depth: typeof value.retrieval_depth === "number" ? value.retrieval_depth : void 0
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
function topicCandidates(raw) {
|
|
3866
|
+
const payload = obj2(raw);
|
|
3867
|
+
if (!payload) return [];
|
|
3868
|
+
const graph = obj2(payload.graph);
|
|
3869
|
+
const items = [];
|
|
3870
|
+
for (const article of Array.isArray(payload.articles) ? payload.articles : []) {
|
|
3871
|
+
const item = compactItem(article, "Article");
|
|
3872
|
+
if (item) items.push(item);
|
|
3873
|
+
}
|
|
3874
|
+
const rawNodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
3875
|
+
const labels = /* @__PURE__ */ new Map();
|
|
3876
|
+
for (const node of rawNodes) {
|
|
3877
|
+
const item = compactItem(node);
|
|
3878
|
+
if (item) {
|
|
3879
|
+
if (HIDDEN_CONTEXT_NODE_TYPES.has(text(item.type) ?? "")) continue;
|
|
3880
|
+
items.push(item);
|
|
3881
|
+
const uid = text(item.uid);
|
|
3882
|
+
const label = text(item.label);
|
|
3883
|
+
if (uid && label) labels.set(uid, label);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
for (const rawEdge of Array.isArray(graph?.edges) ? graph.edges : []) {
|
|
3887
|
+
const edge = obj2(rawEdge);
|
|
3888
|
+
const fromUid = text(edge?.from_uid);
|
|
3889
|
+
const toUid = text(edge?.to_uid);
|
|
3890
|
+
const edgeType = text(edge?.edge_type) ?? text(obj2(edge?.edge_type)?.Custom);
|
|
3891
|
+
if (!fromUid || !toUid || !edgeType || HIDDEN_CONTEXT_EDGE_TYPES.has(edgeType) || !labels.has(fromUid) || !labels.has(toUid)) {
|
|
3892
|
+
continue;
|
|
3893
|
+
}
|
|
3894
|
+
items.push(
|
|
3895
|
+
defined({
|
|
3896
|
+
type: "Relationship",
|
|
3897
|
+
from_uid: fromUid,
|
|
3898
|
+
to_uid: toUid,
|
|
3899
|
+
edge_type: edgeType,
|
|
3900
|
+
from_label: labels.get(fromUid),
|
|
3901
|
+
to_label: labels.get(toUid)
|
|
3902
|
+
})
|
|
3903
|
+
);
|
|
3904
|
+
}
|
|
3905
|
+
for (const chunk of Array.isArray(payload.chunks) ? payload.chunks : []) {
|
|
3906
|
+
const item = compactItem(chunk, "SourceExcerpt");
|
|
3907
|
+
if (item) items.push(item);
|
|
3908
|
+
}
|
|
3909
|
+
return items;
|
|
3910
|
+
}
|
|
3911
|
+
function resumeCandidates(raw) {
|
|
3912
|
+
const payload = obj2(raw);
|
|
3913
|
+
if (!payload) return [];
|
|
3914
|
+
const items = [];
|
|
3915
|
+
for (const key of ["task", "goal", "project", "plan", "active_execution", "lease"]) {
|
|
3916
|
+
const item = compactItem(payload[key], key);
|
|
3917
|
+
if (item) items.push(item);
|
|
3918
|
+
}
|
|
3919
|
+
for (const key of ["next_steps", "recent_executions", "blockers", "code_targets"]) {
|
|
3920
|
+
for (const value of Array.isArray(payload[key]) ? payload[key] : []) {
|
|
3921
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
3922
|
+
if (item) items.push(item);
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
const knowledge = obj2(payload.knowledge);
|
|
3926
|
+
for (const key of ["lessons", "risks"]) {
|
|
3927
|
+
for (const value of Array.isArray(knowledge?.[key]) ? knowledge[key] : []) {
|
|
3928
|
+
const item = compactItem(value, key.replace(/s$/, ""));
|
|
3929
|
+
if (item) items.push(item);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
return items;
|
|
3933
|
+
}
|
|
3934
|
+
function visibleItems(candidates, rendered2) {
|
|
3935
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3936
|
+
return candidates.filter((item) => {
|
|
3937
|
+
const uid = text(item.uid);
|
|
3938
|
+
if (uid) {
|
|
3939
|
+
if (seen.has(uid) || !rendered2.includes(`[${uid}]`)) return false;
|
|
3940
|
+
seen.add(uid);
|
|
3941
|
+
return true;
|
|
3942
|
+
}
|
|
3943
|
+
if (item.type === "Relationship") {
|
|
3944
|
+
const from = text(item.from_label);
|
|
3945
|
+
const to = text(item.to_label);
|
|
3946
|
+
const edgeType = text(item.edge_type);
|
|
3947
|
+
if (!from || !to || !edgeType) return false;
|
|
3948
|
+
const key = `${text(item.from_uid)}:${edgeType}:${text(item.to_uid)}`;
|
|
3949
|
+
if (seen.has(key) || !rendered2.includes(`${from} \u2014${edgeType}\u2192 ${to}`)) return false;
|
|
3950
|
+
seen.add(key);
|
|
3951
|
+
return true;
|
|
3952
|
+
}
|
|
3953
|
+
return false;
|
|
3954
|
+
});
|
|
3955
|
+
}
|
|
3956
|
+
function latestTimestamp(value) {
|
|
3957
|
+
let latest;
|
|
3958
|
+
const visit = (current) => {
|
|
3959
|
+
if (Array.isArray(current)) {
|
|
3960
|
+
for (const item of current) visit(item);
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
const record = obj2(current);
|
|
3964
|
+
if (!record) return;
|
|
3965
|
+
for (const [key, item] of Object.entries(record)) {
|
|
3966
|
+
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))) {
|
|
3967
|
+
latest = item;
|
|
3968
|
+
}
|
|
3969
|
+
visit(item);
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
visit(value);
|
|
3973
|
+
return latest;
|
|
3974
|
+
}
|
|
3975
|
+
function contextWarnings(raw, rendered2, available, returned) {
|
|
3976
|
+
const warnings = [
|
|
3977
|
+
{
|
|
3978
|
+
code: "delivery_unverified",
|
|
3979
|
+
message: "The MCP server returned this context but cannot verify that the host injected or used it."
|
|
3980
|
+
}
|
|
3981
|
+
];
|
|
3982
|
+
const serialized = JSON.stringify(raw);
|
|
3983
|
+
if (available > returned || rendered2.includes("item(s) omitted")) {
|
|
3984
|
+
warnings.push({
|
|
3985
|
+
code: "context_bounded",
|
|
3986
|
+
message: `${Math.max(0, available - returned)} structured item(s) were omitted from the rendered context.`
|
|
3987
|
+
});
|
|
3988
|
+
}
|
|
3989
|
+
if (/"superseded":true/.test(serialized)) {
|
|
3990
|
+
warnings.push({ code: "superseded_items_present", message: "Some retrieved items are superseded." });
|
|
3991
|
+
}
|
|
3992
|
+
if (/"currently_valid":false|"valid_at_time":false/.test(serialized)) {
|
|
3993
|
+
warnings.push({
|
|
3994
|
+
code: "validity_warning",
|
|
3995
|
+
message: "Some retrieved items are outside their current or requested validity window."
|
|
3996
|
+
});
|
|
3997
|
+
}
|
|
3998
|
+
const payload = obj2(raw);
|
|
3999
|
+
if (payload?.truncated === true || obj2(payload?.truncation)) {
|
|
4000
|
+
const truncation = obj2(payload?.truncation);
|
|
4001
|
+
if (payload?.truncated === true || Object.values(truncation ?? {}).some(Boolean)) {
|
|
4002
|
+
warnings.push({ code: "source_truncated", message: "The authoritative source reported truncated fields." });
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
if (text(payload?.warning)) {
|
|
4006
|
+
warnings.push({ code: "source_warning", message: text(payload?.warning) });
|
|
4007
|
+
}
|
|
4008
|
+
return warnings;
|
|
4009
|
+
}
|
|
4010
|
+
function error(message) {
|
|
4011
|
+
return {
|
|
4012
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
4013
|
+
isError: true
|
|
4014
|
+
};
|
|
4015
|
+
}
|
|
4016
|
+
async function handleMemoryTool(client2, args, config = {}) {
|
|
4017
|
+
const action = text(args.action);
|
|
4018
|
+
if (action === "status") {
|
|
4019
|
+
const status = memoryStatus({ ...config, agentId: text(args.agent_id) ?? config.agentId });
|
|
4020
|
+
return {
|
|
4021
|
+
content: [{ type: "text", text: JSON.stringify(status) }],
|
|
4022
|
+
structuredContent: status
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
if (action !== "context") {
|
|
4026
|
+
return error("action must be 'status' or 'context'");
|
|
4027
|
+
}
|
|
4028
|
+
const mode = text(args.mode) ?? (text(args.query) ? "topic" : void 0);
|
|
4029
|
+
if (!mode || !["topic", "continuity", "resume"].includes(mode)) {
|
|
4030
|
+
return error("action='context' requires mode='topic', 'continuity', or 'resume'");
|
|
4031
|
+
}
|
|
4032
|
+
const budget = outputBudget(args.max_output_chars);
|
|
4033
|
+
const agentId = text(args.agent_id) ?? config.agentId;
|
|
4034
|
+
let raw;
|
|
4035
|
+
let rendered2;
|
|
4036
|
+
let strategy;
|
|
4037
|
+
let candidates;
|
|
4038
|
+
if (mode === "topic") {
|
|
4039
|
+
const query = text(args.query);
|
|
4040
|
+
if (!query) return error("mode='topic' requires a non-empty query of 1-3 discriminating keywords");
|
|
4041
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit) ? Math.min(50, Math.max(1, Math.floor(args.limit))) : 8;
|
|
4042
|
+
const request = defined({
|
|
4043
|
+
query,
|
|
4044
|
+
project_uid: text(args.project_uid),
|
|
4045
|
+
node_limit: limit,
|
|
4046
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
4047
|
+
layer: text(args.layer),
|
|
4048
|
+
chunk_limit: args.include_chunks === true ? limit : 0,
|
|
4049
|
+
article_limit: args.include_documents === true ? limit : 0,
|
|
4050
|
+
valid_at: text(args.valid_at),
|
|
4051
|
+
include_graph: true,
|
|
4052
|
+
graph_expansion_limit: typeof args.graph_expansion_limit === "number" ? args.graph_expansion_limit : 3,
|
|
4053
|
+
graph_max_depth: typeof args.graph_max_depth === "number" ? args.graph_max_depth : 2
|
|
4054
|
+
});
|
|
4055
|
+
raw = await client2.retrieveContext(request);
|
|
4056
|
+
rendered2 = renderContext(raw, budget) ?? "No results found for this search.";
|
|
4057
|
+
strategy = "retrieve_context";
|
|
4058
|
+
candidates = topicCandidates(raw);
|
|
4059
|
+
} else {
|
|
4060
|
+
const scopeUids = Array.from(
|
|
4061
|
+
/* @__PURE__ */ new Set([
|
|
4062
|
+
...Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : [],
|
|
4063
|
+
...text(args.project_uid) ? [text(args.project_uid)] : []
|
|
4064
|
+
])
|
|
4065
|
+
);
|
|
4066
|
+
raw = await client2.plan(
|
|
4067
|
+
defined({
|
|
4068
|
+
action: "resume_work",
|
|
4069
|
+
task_uid: text(args.task_uid),
|
|
4070
|
+
session_uid: text(args.session_uid),
|
|
4071
|
+
scope_uids: scopeUids.length > 0 ? scopeUids : void 0,
|
|
4072
|
+
limit: 1,
|
|
4073
|
+
agent_id: agentId
|
|
4074
|
+
})
|
|
4075
|
+
);
|
|
4076
|
+
rendered2 = renderResumeContext(raw, budget) ?? "No eligible work was found in the requested scope.";
|
|
4077
|
+
strategy = "resume_work";
|
|
4078
|
+
candidates = resumeCandidates(raw);
|
|
4079
|
+
}
|
|
4080
|
+
const items = visibleItems(candidates, rendered2);
|
|
4081
|
+
const renderedHash = sha2562(rendered2);
|
|
4082
|
+
const scope = defined({
|
|
4083
|
+
org_id: config.orgId,
|
|
4084
|
+
agent_id: agentId,
|
|
4085
|
+
harness: config.harness ?? "generic",
|
|
4086
|
+
project_uid: text(args.project_uid),
|
|
4087
|
+
task_uid: text(args.task_uid),
|
|
4088
|
+
session_uid: text(args.session_uid),
|
|
4089
|
+
scope_uids: Array.isArray(args.scope_uids) ? args.scope_uids.map(String) : void 0
|
|
4090
|
+
});
|
|
4091
|
+
const contextId = `ctx_${sha2562(
|
|
4092
|
+
stableJson({ mode, scope, strategy, query: text(args.query), rendered_hash: renderedHash })
|
|
4093
|
+
).slice(0, 24)}`;
|
|
4094
|
+
const bounded = candidates.length > items.length || rendered2.includes("item(s) omitted");
|
|
4095
|
+
const result = {
|
|
4096
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
4097
|
+
action: "context",
|
|
4098
|
+
context_id: contextId,
|
|
4099
|
+
mode,
|
|
4100
|
+
scope,
|
|
4101
|
+
rendered_context: rendered2,
|
|
4102
|
+
rendered_hash: renderedHash,
|
|
4103
|
+
items,
|
|
4104
|
+
retrieval_trace: defined({
|
|
4105
|
+
strategy,
|
|
4106
|
+
query: text(args.query),
|
|
4107
|
+
project_uid: text(args.project_uid),
|
|
4108
|
+
task_uid: text(args.task_uid),
|
|
4109
|
+
session_uid: text(args.session_uid),
|
|
4110
|
+
node_types: Array.isArray(args.node_types) ? args.node_types.map(String) : void 0,
|
|
4111
|
+
graph_expansion_limit: mode === "topic" ? args.graph_expansion_limit ?? 3 : void 0,
|
|
4112
|
+
graph_max_depth: mode === "topic" ? args.graph_max_depth ?? 2 : void 0,
|
|
4113
|
+
available_items: candidates.length,
|
|
4114
|
+
returned_items: items.length,
|
|
4115
|
+
omitted_items: Math.max(0, candidates.length - items.length)
|
|
4116
|
+
}),
|
|
4117
|
+
budget: {
|
|
4118
|
+
unit: "characters",
|
|
4119
|
+
requested_chars: budget,
|
|
4120
|
+
used_chars: rendered2.length,
|
|
4121
|
+
available_items: candidates.length,
|
|
4122
|
+
returned_items: items.length,
|
|
4123
|
+
omitted_items: Math.max(0, candidates.length - items.length),
|
|
4124
|
+
bounded
|
|
4125
|
+
},
|
|
4126
|
+
freshness: defined({
|
|
4127
|
+
valid_at: text(args.valid_at),
|
|
4128
|
+
latest_source_timestamp: latestTimestamp(raw)
|
|
4129
|
+
}),
|
|
4130
|
+
warnings: contextWarnings(raw, rendered2, candidates.length, items.length)
|
|
4131
|
+
};
|
|
4132
|
+
return {
|
|
4133
|
+
content: [{ type: "text", text: rendered2 }],
|
|
4134
|
+
structuredContent: result
|
|
4135
|
+
};
|
|
4136
|
+
}
|
|
4137
|
+
var import_node_crypto7, RESULT_SCHEMA_VERSION, DEFAULT_OUTPUT_CHARS, MIN_OUTPUT_CHARS, MAX_OUTPUT_CHARS, HIDDEN_CONTEXT_NODE_TYPES, HIDDEN_CONTEXT_EDGE_TYPES, MEMORY_TOOL;
|
|
4138
|
+
var init_memory_tool = __esm({
|
|
4139
|
+
"src/memory-tool.ts"() {
|
|
4140
|
+
"use strict";
|
|
4141
|
+
import_node_crypto7 = require("crypto");
|
|
4142
|
+
init_render();
|
|
4143
|
+
RESULT_SCHEMA_VERSION = "mindgraph.memory.result.v1";
|
|
4144
|
+
DEFAULT_OUTPUT_CHARS = 8e3;
|
|
4145
|
+
MIN_OUTPUT_CHARS = 512;
|
|
4146
|
+
MAX_OUTPUT_CHARS = 24e3;
|
|
4147
|
+
HIDDEN_CONTEXT_NODE_TYPES = /* @__PURE__ */ new Set(["Chunk", "Document", "Article"]);
|
|
4148
|
+
HIDDEN_CONTEXT_EDGE_TYPES = /* @__PURE__ */ new Set(["POSSIBLE_DUPLICATE", "PossibleDuplicate"]);
|
|
4149
|
+
MEMORY_TOOL = {
|
|
4150
|
+
name: "mindgraph_memory",
|
|
4151
|
+
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.",
|
|
4152
|
+
inputSchema: {
|
|
4153
|
+
type: "object",
|
|
4154
|
+
properties: {
|
|
4155
|
+
action: {
|
|
4156
|
+
type: "string",
|
|
4157
|
+
enum: ["status", "context"],
|
|
4158
|
+
description: "Read integration status or bounded memory context"
|
|
4159
|
+
},
|
|
4160
|
+
mode: {
|
|
4161
|
+
type: "string",
|
|
4162
|
+
enum: ["topic", "continuity", "resume"],
|
|
4163
|
+
description: "Context strategy. topic uses query-shaped retrieval; continuity/resume use authoritative task-first resume_work."
|
|
4164
|
+
},
|
|
4165
|
+
query: {
|
|
4166
|
+
type: "string",
|
|
4167
|
+
description: "Required for mode='topic': 1-3 discriminating BM25 keywords, not a full sentence"
|
|
4168
|
+
},
|
|
4169
|
+
project_uid: { type: "string", description: "Optional project scope" },
|
|
4170
|
+
task_uid: { type: "string", description: "Optional task scope for resume context" },
|
|
4171
|
+
session_uid: { type: "string", description: "Optional durable session scope" },
|
|
4172
|
+
scope_uids: {
|
|
4173
|
+
type: "array",
|
|
4174
|
+
items: { type: "string" },
|
|
4175
|
+
description: "Optional explicit graph scopes for continuity/resume"
|
|
4176
|
+
},
|
|
4177
|
+
node_types: {
|
|
4178
|
+
type: "array",
|
|
4179
|
+
items: { type: "string" },
|
|
4180
|
+
description: "Optional node-type filter for topic context"
|
|
4181
|
+
},
|
|
4182
|
+
layer: {
|
|
4183
|
+
type: "string",
|
|
4184
|
+
enum: ["reality", "epistemic", "intent", "action", "memory", "agent"],
|
|
4185
|
+
description: "Optional cognitive-layer filter for topic context"
|
|
4186
|
+
},
|
|
4187
|
+
limit: {
|
|
4188
|
+
type: "integer",
|
|
4189
|
+
minimum: 1,
|
|
4190
|
+
maximum: 50,
|
|
4191
|
+
default: 8,
|
|
4192
|
+
description: "Maximum direct graph items requested before bounded expansion"
|
|
4193
|
+
},
|
|
4194
|
+
include_chunks: {
|
|
4195
|
+
type: "boolean",
|
|
4196
|
+
default: false,
|
|
4197
|
+
description: "Include bounded source excerpts when topic summaries are insufficient"
|
|
4198
|
+
},
|
|
4199
|
+
include_documents: {
|
|
4200
|
+
type: "boolean",
|
|
4201
|
+
default: false,
|
|
4202
|
+
description: "Include bounded knowledge articles for topic context"
|
|
4203
|
+
},
|
|
4204
|
+
valid_at: {
|
|
4205
|
+
type: "string",
|
|
4206
|
+
description: "Optional ISO timestamp for time-aware topic retrieval"
|
|
4207
|
+
},
|
|
4208
|
+
graph_expansion_limit: {
|
|
4209
|
+
type: "integer",
|
|
4210
|
+
minimum: 0,
|
|
4211
|
+
maximum: 20,
|
|
4212
|
+
default: 3,
|
|
4213
|
+
description: "Bounded graph neighbors added after direct topic matches"
|
|
4214
|
+
},
|
|
4215
|
+
graph_max_depth: {
|
|
4216
|
+
type: "integer",
|
|
4217
|
+
minimum: 0,
|
|
4218
|
+
maximum: 5,
|
|
4219
|
+
default: 2,
|
|
4220
|
+
description: "Maximum graph-expansion depth for topic context"
|
|
4221
|
+
},
|
|
4222
|
+
max_output_chars: {
|
|
4223
|
+
type: "integer",
|
|
4224
|
+
minimum: MIN_OUTPUT_CHARS,
|
|
4225
|
+
maximum: MAX_OUTPUT_CHARS,
|
|
4226
|
+
default: DEFAULT_OUTPUT_CHARS,
|
|
4227
|
+
description: "Hard character budget for model-ready context; whole items are retained or omitted"
|
|
4228
|
+
},
|
|
4229
|
+
agent_id: { type: "string", description: "Agent identity" }
|
|
4230
|
+
},
|
|
4231
|
+
required: ["action"]
|
|
4232
|
+
},
|
|
4233
|
+
outputSchema: {
|
|
4234
|
+
type: "object",
|
|
4235
|
+
properties: {
|
|
4236
|
+
schema_version: { type: "string", const: RESULT_SCHEMA_VERSION },
|
|
4237
|
+
action: { type: "string", enum: ["status", "context"] },
|
|
4238
|
+
profile: { type: "string" },
|
|
4239
|
+
server: { type: "object" },
|
|
4240
|
+
integration: { type: "object" },
|
|
4241
|
+
capabilities: { type: "object" },
|
|
4242
|
+
degradation: { type: "array", items: { type: "object" } },
|
|
4243
|
+
context_id: { type: "string" },
|
|
4244
|
+
mode: { type: "string", enum: ["topic", "continuity", "resume"] },
|
|
4245
|
+
scope: { type: "object" },
|
|
4246
|
+
rendered_context: { type: "string" },
|
|
4247
|
+
rendered_hash: { type: "string" },
|
|
4248
|
+
items: { type: "array", items: { type: "object" } },
|
|
4249
|
+
retrieval_trace: { type: "object" },
|
|
4250
|
+
budget: { type: "object" },
|
|
4251
|
+
freshness: { type: "object" },
|
|
4252
|
+
warnings: { type: "array", items: { type: "object" } }
|
|
4253
|
+
},
|
|
4254
|
+
required: ["schema_version", "action"],
|
|
4255
|
+
oneOf: [
|
|
4256
|
+
{
|
|
4257
|
+
properties: { action: { const: "status" } },
|
|
4258
|
+
required: ["profile", "server", "integration", "scope", "capabilities", "degradation"]
|
|
4259
|
+
},
|
|
4260
|
+
{
|
|
4261
|
+
properties: { action: { const: "context" } },
|
|
4262
|
+
required: [
|
|
4263
|
+
"context_id",
|
|
4264
|
+
"mode",
|
|
4265
|
+
"scope",
|
|
4266
|
+
"rendered_context",
|
|
4267
|
+
"rendered_hash",
|
|
4268
|
+
"items",
|
|
4269
|
+
"retrieval_trace",
|
|
4270
|
+
"budget",
|
|
4271
|
+
"freshness",
|
|
4272
|
+
"warnings"
|
|
4273
|
+
]
|
|
4274
|
+
}
|
|
4275
|
+
]
|
|
4276
|
+
},
|
|
4277
|
+
annotations: {
|
|
4278
|
+
readOnlyHint: true,
|
|
4279
|
+
destructiveHint: false,
|
|
4280
|
+
idempotentHint: true,
|
|
4281
|
+
openWorldHint: false
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
}
|
|
4285
|
+
});
|
|
4286
|
+
|
|
3384
4287
|
// src/tools.ts
|
|
4288
|
+
function stableJson2(value) {
|
|
4289
|
+
if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
|
|
4290
|
+
if (value && typeof value === "object") {
|
|
4291
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson2(item)}`).join(",")}}`;
|
|
4292
|
+
}
|
|
4293
|
+
return JSON.stringify(value);
|
|
4294
|
+
}
|
|
4295
|
+
function defaultWriteIdempotencyKey(tool, args) {
|
|
4296
|
+
if (typeof args.idempotency_key === "string") return args.idempotency_key;
|
|
4297
|
+
const context = args.invocation_context;
|
|
4298
|
+
const sessionId = context?.harnessSessionId;
|
|
4299
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) return void 0;
|
|
4300
|
+
const canonicalArgs = Object.fromEntries(
|
|
4301
|
+
Object.entries(args).filter(
|
|
4302
|
+
([key]) => key !== "invocation_context" && key !== "idempotency_key"
|
|
4303
|
+
)
|
|
4304
|
+
);
|
|
4305
|
+
return (0, import_node_crypto8.createHash)("sha256").update(
|
|
4306
|
+
stableJson2({
|
|
4307
|
+
harness_session_id: sessionId,
|
|
4308
|
+
harness_turn_id: context?.harnessTurnId ?? null,
|
|
4309
|
+
tool,
|
|
4310
|
+
action: args.action ?? null,
|
|
4311
|
+
args: canonicalArgs
|
|
4312
|
+
})
|
|
4313
|
+
).digest("hex");
|
|
4314
|
+
}
|
|
4315
|
+
function resolutionFields(args) {
|
|
4316
|
+
return Object.fromEntries(
|
|
4317
|
+
[
|
|
4318
|
+
"idempotency_key",
|
|
4319
|
+
"reuse_uid",
|
|
4320
|
+
"supersedes_uid",
|
|
4321
|
+
"contradicts_uid",
|
|
4322
|
+
"confirm_new",
|
|
4323
|
+
"on_near_duplicate"
|
|
4324
|
+
].filter((key) => args[key] !== void 0).map((key) => [key, args[key]])
|
|
4325
|
+
);
|
|
4326
|
+
}
|
|
3385
4327
|
function toolsForProfile(profile = process.env.MINDGRAPH_PROFILE || "general") {
|
|
3386
4328
|
if (profile === "coding") return TOOLS;
|
|
3387
4329
|
return TOOLS.filter(
|
|
@@ -3395,8 +4337,8 @@ function ok3(data) {
|
|
|
3395
4337
|
}
|
|
3396
4338
|
function renderedResult(format, raw, render) {
|
|
3397
4339
|
if (format === "json") return ok3(raw);
|
|
3398
|
-
const
|
|
3399
|
-
return
|
|
4340
|
+
const text2 = render(raw);
|
|
4341
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok3(raw);
|
|
3400
4342
|
}
|
|
3401
4343
|
function err3(message) {
|
|
3402
4344
|
return {
|
|
@@ -3404,8 +4346,22 @@ function err3(message) {
|
|
|
3404
4346
|
isError: true
|
|
3405
4347
|
};
|
|
3406
4348
|
}
|
|
3407
|
-
async function handleTool(client2, name, args) {
|
|
4349
|
+
async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
3408
4350
|
try {
|
|
4351
|
+
if (["mindgraph_capture", "mindgraph_reason", "mindgraph_commit"].includes(name) && args.action !== "get_open_decisions") {
|
|
4352
|
+
const key = defaultWriteIdempotencyKey(name, args);
|
|
4353
|
+
if (key) args = { ...args, idempotency_key: key };
|
|
4354
|
+
const dispositions = [
|
|
4355
|
+
args.reuse_uid,
|
|
4356
|
+
args.supersedes_uid,
|
|
4357
|
+
args.contradicts_uid,
|
|
4358
|
+
args.confirm_new === true ? true : void 0,
|
|
4359
|
+
args.on_near_duplicate
|
|
4360
|
+
].filter((value) => value !== void 0);
|
|
4361
|
+
if (dispositions.length > 1) {
|
|
4362
|
+
return err3("resolution dispositions are mutually exclusive");
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
3409
4365
|
let result;
|
|
3410
4366
|
switch (name) {
|
|
3411
4367
|
case "mindgraph_capture":
|
|
@@ -3423,6 +4379,12 @@ async function handleTool(client2, name, args) {
|
|
|
3423
4379
|
case "mindgraph_retrieve":
|
|
3424
4380
|
result = await handleRetrieve(client2, args);
|
|
3425
4381
|
break;
|
|
4382
|
+
case "mindgraph_memory":
|
|
4383
|
+
result = await handleMemoryTool(client2, args, memoryConfig);
|
|
4384
|
+
break;
|
|
4385
|
+
case "mindgraph_remember":
|
|
4386
|
+
result = await handleRemember(client2, args);
|
|
4387
|
+
break;
|
|
3426
4388
|
case "mindgraph_series_query":
|
|
3427
4389
|
result = await handleSeriesQuery(client2, args);
|
|
3428
4390
|
break;
|
|
@@ -3455,19 +4417,7 @@ async function handleTool(client2, name, args) {
|
|
|
3455
4417
|
].includes(action);
|
|
3456
4418
|
return attach ? await attachCodeRefsToToolResult(client2, result, args) : result;
|
|
3457
4419
|
} catch (e) {
|
|
3458
|
-
|
|
3459
|
-
if (Object.keys(lifted).length > 0) {
|
|
3460
|
-
return {
|
|
3461
|
-
content: [
|
|
3462
|
-
{
|
|
3463
|
-
type: "text",
|
|
3464
|
-
text: JSON.stringify({ error: errorDetail(e), ...lifted })
|
|
3465
|
-
}
|
|
3466
|
-
],
|
|
3467
|
-
isError: true
|
|
3468
|
-
};
|
|
3469
|
-
}
|
|
3470
|
-
return err3(errorDetail(e));
|
|
4420
|
+
return toolError(e);
|
|
3471
4421
|
}
|
|
3472
4422
|
}
|
|
3473
4423
|
async function handleSeriesQuery(client2, args) {
|
|
@@ -3491,6 +4441,56 @@ async function handleSeriesQuery(client2, args) {
|
|
|
3491
4441
|
await client2.series(args)
|
|
3492
4442
|
);
|
|
3493
4443
|
}
|
|
4444
|
+
async function handleRemember(client2, args) {
|
|
4445
|
+
const {
|
|
4446
|
+
action,
|
|
4447
|
+
text: text2,
|
|
4448
|
+
custom_id,
|
|
4449
|
+
label,
|
|
4450
|
+
uid,
|
|
4451
|
+
dry_run,
|
|
4452
|
+
cascade,
|
|
4453
|
+
reason,
|
|
4454
|
+
space_uid,
|
|
4455
|
+
on_near_duplicate,
|
|
4456
|
+
props,
|
|
4457
|
+
agent_id,
|
|
4458
|
+
// Adapter-owned; consumed locally, never sent to the API.
|
|
4459
|
+
invocation_context: _invocationContext,
|
|
4460
|
+
...rest
|
|
4461
|
+
} = args;
|
|
4462
|
+
void _invocationContext;
|
|
4463
|
+
void rest;
|
|
4464
|
+
switch (action) {
|
|
4465
|
+
case "remember": {
|
|
4466
|
+
if (typeof text2 !== "string" || !text2.trim()) {
|
|
4467
|
+
return err3("remember requires non-empty text");
|
|
4468
|
+
}
|
|
4469
|
+
const options = {};
|
|
4470
|
+
if (typeof custom_id === "string" && custom_id.trim()) options.custom_id = custom_id.trim();
|
|
4471
|
+
if (typeof label === "string" && label.trim()) options.label = label;
|
|
4472
|
+
if (typeof space_uid === "string" && space_uid.trim()) options.space_uid = space_uid;
|
|
4473
|
+
if (on_near_duplicate === "reuse" || on_near_duplicate === "create") {
|
|
4474
|
+
options.on_near_duplicate = on_near_duplicate;
|
|
4475
|
+
}
|
|
4476
|
+
if (props && typeof props === "object") options.props = props;
|
|
4477
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4478
|
+
return ok3(await client2.remember(text2, options));
|
|
4479
|
+
}
|
|
4480
|
+
case "forget": {
|
|
4481
|
+
const target = typeof uid === "string" && uid.trim() ? { uid: uid.trim() } : typeof custom_id === "string" && custom_id.trim() ? { custom_id: custom_id.trim() } : null;
|
|
4482
|
+
if (!target) return err3("forget requires uid or custom_id");
|
|
4483
|
+
const options = {};
|
|
4484
|
+
if (dry_run === true) options.dry_run = true;
|
|
4485
|
+
if (typeof cascade === "boolean") options.cascade = cascade;
|
|
4486
|
+
if (typeof reason === "string" && reason.trim()) options.reason = reason;
|
|
4487
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4488
|
+
return ok3(await client2.forget(target, options));
|
|
4489
|
+
}
|
|
4490
|
+
default:
|
|
4491
|
+
return err3(`Unknown remember action: ${String(action)}`);
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
3494
4494
|
async function handleCapture(client2, args) {
|
|
3495
4495
|
const {
|
|
3496
4496
|
action,
|
|
@@ -3504,7 +4504,11 @@ async function handleCapture(client2, args) {
|
|
|
3504
4504
|
work_uid,
|
|
3505
4505
|
execution_uid,
|
|
3506
4506
|
idempotency_key,
|
|
4507
|
+
reuse_uid,
|
|
3507
4508
|
supersedes_uid,
|
|
4509
|
+
contradicts_uid,
|
|
4510
|
+
confirm_new,
|
|
4511
|
+
on_near_duplicate,
|
|
3508
4512
|
summarizes_uids,
|
|
3509
4513
|
entity_type,
|
|
3510
4514
|
source_uid,
|
|
@@ -3528,7 +4532,11 @@ async function handleCapture(client2, args) {
|
|
|
3528
4532
|
work_uid,
|
|
3529
4533
|
execution_uid,
|
|
3530
4534
|
idempotency_key,
|
|
4535
|
+
reuse_uid,
|
|
3531
4536
|
supersedes_uid,
|
|
4537
|
+
contradicts_uid,
|
|
4538
|
+
confirm_new,
|
|
4539
|
+
on_near_duplicate,
|
|
3532
4540
|
summarizes_uids,
|
|
3533
4541
|
props,
|
|
3534
4542
|
agent_id
|
|
@@ -3574,27 +4582,32 @@ async function handleCapture(client2, args) {
|
|
|
3574
4582
|
const journalProps = { content };
|
|
3575
4583
|
if (mood) journalProps.mood = mood;
|
|
3576
4584
|
if (tags) journalProps.tags = tags;
|
|
3577
|
-
return ok3(await client2.journal(label, journalProps, {
|
|
4585
|
+
return ok3(await client2.journal(label, journalProps, {
|
|
4586
|
+
agent_id,
|
|
4587
|
+
idempotency_key,
|
|
4588
|
+
reuse_uid,
|
|
4589
|
+
supersedes_uid,
|
|
4590
|
+
contradicts_uid,
|
|
4591
|
+
confirm_new,
|
|
4592
|
+
on_near_duplicate
|
|
4593
|
+
}));
|
|
3578
4594
|
}
|
|
3579
4595
|
case "entity": {
|
|
3580
4596
|
const type = entity_type || "concept";
|
|
3581
4597
|
const entityProps = { ...props };
|
|
3582
4598
|
if (summary) entityProps.description = summary;
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
default:
|
|
3596
|
-
return ok3(await client2.findOrCreateConcept(label, entityProps, agent_id));
|
|
3597
|
-
}
|
|
4599
|
+
return ok3(await client2.entity({
|
|
4600
|
+
action: "create",
|
|
4601
|
+
label,
|
|
4602
|
+
props: { ...entityProps, entity_type: type },
|
|
4603
|
+
agent_id,
|
|
4604
|
+
idempotency_key,
|
|
4605
|
+
reuse_uid,
|
|
4606
|
+
supersedes_uid,
|
|
4607
|
+
contradicts_uid,
|
|
4608
|
+
confirm_new,
|
|
4609
|
+
on_near_duplicate
|
|
4610
|
+
}));
|
|
3598
4611
|
}
|
|
3599
4612
|
case "observation":
|
|
3600
4613
|
return ok3(
|
|
@@ -3605,7 +4618,13 @@ async function handleCapture(client2, args) {
|
|
|
3605
4618
|
confidence,
|
|
3606
4619
|
salience,
|
|
3607
4620
|
props,
|
|
3608
|
-
agent_id
|
|
4621
|
+
agent_id,
|
|
4622
|
+
idempotency_key,
|
|
4623
|
+
reuse_uid,
|
|
4624
|
+
supersedes_uid,
|
|
4625
|
+
contradicts_uid,
|
|
4626
|
+
confirm_new,
|
|
4627
|
+
on_near_duplicate
|
|
3609
4628
|
})
|
|
3610
4629
|
);
|
|
3611
4630
|
case "source":
|
|
@@ -3617,7 +4636,13 @@ async function handleCapture(client2, args) {
|
|
|
3617
4636
|
confidence,
|
|
3618
4637
|
salience,
|
|
3619
4638
|
props,
|
|
3620
|
-
agent_id
|
|
4639
|
+
agent_id,
|
|
4640
|
+
idempotency_key,
|
|
4641
|
+
reuse_uid,
|
|
4642
|
+
supersedes_uid,
|
|
4643
|
+
contradicts_uid,
|
|
4644
|
+
confirm_new,
|
|
4645
|
+
on_near_duplicate
|
|
3621
4646
|
})
|
|
3622
4647
|
);
|
|
3623
4648
|
case "snippet":
|
|
@@ -3630,26 +4655,38 @@ async function handleCapture(client2, args) {
|
|
|
3630
4655
|
confidence,
|
|
3631
4656
|
salience,
|
|
3632
4657
|
props,
|
|
3633
|
-
agent_id
|
|
4658
|
+
agent_id,
|
|
4659
|
+
idempotency_key,
|
|
4660
|
+
reuse_uid,
|
|
4661
|
+
supersedes_uid,
|
|
4662
|
+
contradicts_uid,
|
|
4663
|
+
confirm_new,
|
|
4664
|
+
on_near_duplicate
|
|
3634
4665
|
})
|
|
3635
4666
|
);
|
|
3636
4667
|
case "concept":
|
|
3637
|
-
return ok3(
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
4668
|
+
return ok3(await client2.entity({
|
|
4669
|
+
action: "create",
|
|
4670
|
+
label,
|
|
4671
|
+
props: {
|
|
4672
|
+
...props,
|
|
4673
|
+
entity_type: "concept",
|
|
4674
|
+
...summary ? { description: summary } : {}
|
|
4675
|
+
},
|
|
4676
|
+
agent_id,
|
|
4677
|
+
idempotency_key,
|
|
4678
|
+
reuse_uid,
|
|
4679
|
+
supersedes_uid,
|
|
4680
|
+
contradicts_uid,
|
|
4681
|
+
confirm_new,
|
|
4682
|
+
on_near_duplicate
|
|
4683
|
+
}));
|
|
3648
4684
|
default:
|
|
3649
4685
|
return err3(`Unknown capture action: ${action}`);
|
|
3650
4686
|
}
|
|
3651
4687
|
}
|
|
3652
4688
|
async function handleReason(client2, args) {
|
|
4689
|
+
const resolution = resolutionFields(args);
|
|
3653
4690
|
const {
|
|
3654
4691
|
action,
|
|
3655
4692
|
label,
|
|
@@ -3682,7 +4719,8 @@ async function handleReason(client2, args) {
|
|
|
3682
4719
|
...warrant.content ? { props: { content: warrant.content } } : {}
|
|
3683
4720
|
} : void 0,
|
|
3684
4721
|
argument,
|
|
3685
|
-
agent_id
|
|
4722
|
+
agent_id,
|
|
4723
|
+
...resolution
|
|
3686
4724
|
})
|
|
3687
4725
|
);
|
|
3688
4726
|
}
|
|
@@ -3695,11 +4733,13 @@ async function handleReason(client2, args) {
|
|
|
3695
4733
|
confidence,
|
|
3696
4734
|
salience,
|
|
3697
4735
|
props,
|
|
3698
|
-
agent_id
|
|
4736
|
+
agent_id,
|
|
4737
|
+
...resolution
|
|
3699
4738
|
})
|
|
3700
4739
|
);
|
|
3701
4740
|
}
|
|
3702
4741
|
async function handleCommit(client2, args) {
|
|
4742
|
+
const resolution = resolutionFields(args);
|
|
3703
4743
|
const {
|
|
3704
4744
|
action,
|
|
3705
4745
|
label,
|
|
@@ -3730,16 +4770,17 @@ async function handleCommit(client2, args) {
|
|
|
3730
4770
|
confidence,
|
|
3731
4771
|
salience,
|
|
3732
4772
|
props,
|
|
3733
|
-
agent_id
|
|
4773
|
+
agent_id,
|
|
4774
|
+
...resolution
|
|
3734
4775
|
})
|
|
3735
4776
|
);
|
|
3736
4777
|
case "open_decision":
|
|
3737
4778
|
if (!label) return err3("label is required for open_decision");
|
|
3738
|
-
return ok3(await client2.openDecision(label, { summary, props, agent_id }));
|
|
4779
|
+
return ok3(await client2.openDecision(label, { summary, props, agent_id, ...resolution }));
|
|
3739
4780
|
case "add_option":
|
|
3740
4781
|
if (!decision_uid) return err3("decision_uid is required for add_option");
|
|
3741
4782
|
if (!label) return err3("label is required for add_option");
|
|
3742
|
-
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id }));
|
|
4783
|
+
return ok3(await client2.addOption(decision_uid, label, { summary, props, agent_id, ...resolution }));
|
|
3743
4784
|
case "add_constraint":
|
|
3744
4785
|
if (!decision_uid) return err3("decision_uid is required for add_constraint");
|
|
3745
4786
|
return ok3(
|
|
@@ -3749,7 +4790,8 @@ async function handleCommit(client2, args) {
|
|
|
3749
4790
|
decision_uid,
|
|
3750
4791
|
summary,
|
|
3751
4792
|
props,
|
|
3752
|
-
agent_id
|
|
4793
|
+
agent_id,
|
|
4794
|
+
...resolution
|
|
3753
4795
|
})
|
|
3754
4796
|
);
|
|
3755
4797
|
case "resolve_decision":
|
|
@@ -3763,7 +4805,8 @@ async function handleCommit(client2, args) {
|
|
|
3763
4805
|
as_of_date,
|
|
3764
4806
|
session_id,
|
|
3765
4807
|
retrieval_trace_id,
|
|
3766
|
-
agent_id
|
|
4808
|
+
agent_id,
|
|
4809
|
+
...resolution
|
|
3767
4810
|
})
|
|
3768
4811
|
);
|
|
3769
4812
|
case "get_open_decisions":
|
|
@@ -3844,7 +4887,7 @@ async function handlePlan(client2, args) {
|
|
|
3844
4887
|
output_snapshot,
|
|
3845
4888
|
side_effects,
|
|
3846
4889
|
outcome,
|
|
3847
|
-
error,
|
|
4890
|
+
error: error2,
|
|
3848
4891
|
next_action,
|
|
3849
4892
|
checkpoint_summary,
|
|
3850
4893
|
test_summary,
|
|
@@ -3907,7 +4950,7 @@ async function handlePlan(client2, args) {
|
|
|
3907
4950
|
output_snapshot,
|
|
3908
4951
|
side_effects,
|
|
3909
4952
|
outcome,
|
|
3910
|
-
error,
|
|
4953
|
+
error: error2,
|
|
3911
4954
|
next_action,
|
|
3912
4955
|
checkpoint_summary,
|
|
3913
4956
|
test_summary,
|
|
@@ -3956,7 +4999,7 @@ async function handlePlan(client2, args) {
|
|
|
3956
4999
|
output_snapshot,
|
|
3957
5000
|
side_effects,
|
|
3958
5001
|
outcome,
|
|
3959
|
-
error,
|
|
5002
|
+
error: error2,
|
|
3960
5003
|
props,
|
|
3961
5004
|
agent_id
|
|
3962
5005
|
})
|
|
@@ -4042,6 +5085,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4042
5085
|
const {
|
|
4043
5086
|
action,
|
|
4044
5087
|
format,
|
|
5088
|
+
max_output_chars,
|
|
4045
5089
|
query,
|
|
4046
5090
|
start_uid,
|
|
4047
5091
|
end_uid,
|
|
@@ -4096,7 +5140,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4096
5140
|
graph_expansion_limit: graph_expansion_limit ?? 3,
|
|
4097
5141
|
graph_max_depth: graph_max_depth ?? 2
|
|
4098
5142
|
}),
|
|
4099
|
-
renderContext
|
|
5143
|
+
(raw) => renderContext(raw, max_output_chars)
|
|
4100
5144
|
);
|
|
4101
5145
|
case "text":
|
|
4102
5146
|
if (!query) return err3("query is required for text search");
|
|
@@ -4110,7 +5154,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4110
5154
|
explain,
|
|
4111
5155
|
agent_id
|
|
4112
5156
|
}),
|
|
4113
|
-
(raw) => renderNodeList(raw, `Text search: ${query}
|
|
5157
|
+
(raw) => renderNodeList(raw, `Text search: ${query}`, void 0, max_output_chars)
|
|
4114
5158
|
);
|
|
4115
5159
|
case "semantic":
|
|
4116
5160
|
if (!query) return err3("query is required for semantic search");
|
|
@@ -4124,7 +5168,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4124
5168
|
explain,
|
|
4125
5169
|
agent_id
|
|
4126
5170
|
}),
|
|
4127
|
-
(raw) => renderNodeList(raw, `Semantic search: ${query}
|
|
5171
|
+
(raw) => renderNodeList(raw, `Semantic search: ${query}`, void 0, max_output_chars)
|
|
4128
5172
|
);
|
|
4129
5173
|
case "hybrid":
|
|
4130
5174
|
if (!query) return err3("query is required for hybrid search");
|
|
@@ -4139,7 +5183,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4139
5183
|
agent_id
|
|
4140
5184
|
}),
|
|
4141
5185
|
// With explain, per-leg scoring must survive — raw JSON only.
|
|
4142
|
-
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}
|
|
5186
|
+
explain ? () => void 0 : (raw) => renderNodeList(raw, `Hybrid search: ${query}`, void 0, max_output_chars)
|
|
4143
5187
|
);
|
|
4144
5188
|
// Structured queries. These go through the generic /retrieve action
|
|
4145
5189
|
// dispatch rather than the SDK's no-argument convenience methods — the
|
|
@@ -4157,7 +5201,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4157
5201
|
offset,
|
|
4158
5202
|
agent_id
|
|
4159
5203
|
}),
|
|
4160
|
-
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit)
|
|
5204
|
+
(raw) => renderNodeList(raw, action.replace(/_/g, " "), limit, max_output_chars)
|
|
4161
5205
|
);
|
|
4162
5206
|
case "stale_derivations":
|
|
4163
5207
|
return rendered2(
|
|
@@ -4166,7 +5210,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4166
5210
|
limit,
|
|
4167
5211
|
offset
|
|
4168
5212
|
}),
|
|
4169
|
-
(raw) => renderNodeList(raw, "stale derivations", limit)
|
|
5213
|
+
(raw) => renderNodeList(raw, "stale derivations", limit, max_output_chars)
|
|
4170
5214
|
);
|
|
4171
5215
|
case "preferences":
|
|
4172
5216
|
return rendered2(
|
|
@@ -4176,7 +5220,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4176
5220
|
limit,
|
|
4177
5221
|
agent_id
|
|
4178
5222
|
}),
|
|
4179
|
-
(raw) => renderNodeList(raw, "Preferences", limit)
|
|
5223
|
+
(raw) => renderNodeList(raw, "Preferences", limit, max_output_chars)
|
|
4180
5224
|
);
|
|
4181
5225
|
case "layer":
|
|
4182
5226
|
if (!layer) return err3("layer is required for layer retrieval");
|
|
@@ -4188,7 +5232,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4188
5232
|
node_types,
|
|
4189
5233
|
agent_id
|
|
4190
5234
|
}),
|
|
4191
|
-
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit)
|
|
5235
|
+
(raw) => renderNodeList(raw, `Layer: ${layer}`, limit, max_output_chars)
|
|
4192
5236
|
);
|
|
4193
5237
|
case "recent":
|
|
4194
5238
|
return rendered2(
|
|
@@ -4202,7 +5246,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4202
5246
|
created_before,
|
|
4203
5247
|
agent_id
|
|
4204
5248
|
}),
|
|
4205
|
-
(raw) => renderNodeList(raw, "Recently ingested", limit)
|
|
5249
|
+
(raw) => renderNodeList(raw, "Recently ingested", limit, max_output_chars)
|
|
4206
5250
|
);
|
|
4207
5251
|
// Document inventory
|
|
4208
5252
|
case "document_index":
|
|
@@ -4211,7 +5255,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4211
5255
|
node_type: "Document",
|
|
4212
5256
|
limit: limit ?? 100
|
|
4213
5257
|
}),
|
|
4214
|
-
(raw) => renderNodeList(raw, "Ingested documents")
|
|
5258
|
+
(raw) => renderNodeList(raw, "Ingested documents", void 0, max_output_chars)
|
|
4215
5259
|
);
|
|
4216
5260
|
// Graph traversal
|
|
4217
5261
|
case "chain":
|
|
@@ -4225,7 +5269,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4225
5269
|
include_provenance,
|
|
4226
5270
|
max_nodes
|
|
4227
5271
|
}),
|
|
4228
|
-
renderTraversal
|
|
5272
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4229
5273
|
);
|
|
4230
5274
|
case "neighborhood":
|
|
4231
5275
|
if (!start_uid) return err3("start_uid is required for neighborhood traversal");
|
|
@@ -4240,7 +5284,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4240
5284
|
include_provenance,
|
|
4241
5285
|
max_nodes
|
|
4242
5286
|
}),
|
|
4243
|
-
renderTraversal
|
|
5287
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4244
5288
|
);
|
|
4245
5289
|
case "path":
|
|
4246
5290
|
if (!start_uid) return err3("start_uid is required for path traversal");
|
|
@@ -4257,7 +5301,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4257
5301
|
include_provenance,
|
|
4258
5302
|
max_nodes
|
|
4259
5303
|
}),
|
|
4260
|
-
renderTraversal
|
|
5304
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4261
5305
|
);
|
|
4262
5306
|
case "subgraph":
|
|
4263
5307
|
if (!start_uid) return err3("start_uid is required for subgraph traversal");
|
|
@@ -4272,7 +5316,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4272
5316
|
include_provenance,
|
|
4273
5317
|
max_nodes
|
|
4274
5318
|
}),
|
|
4275
|
-
renderTraversal
|
|
5319
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4276
5320
|
);
|
|
4277
5321
|
case "top_k_paths":
|
|
4278
5322
|
if (!start_uid) return err3("start_uid is required for top_k_paths");
|
|
@@ -4288,7 +5332,7 @@ async function handleRetrieve(client2, args) {
|
|
|
4288
5332
|
edge_types,
|
|
4289
5333
|
exclude_edge_types
|
|
4290
5334
|
}),
|
|
4291
|
-
renderTraversal
|
|
5335
|
+
(raw) => renderTraversal(raw, max_output_chars)
|
|
4292
5336
|
);
|
|
4293
5337
|
default:
|
|
4294
5338
|
return err3(`Unknown retrieve action: ${action}`);
|
|
@@ -4544,15 +5588,44 @@ async function handleOntology(client2, args) {
|
|
|
4544
5588
|
return err3(`Unknown ontology action: ${action}`);
|
|
4545
5589
|
}
|
|
4546
5590
|
}
|
|
4547
|
-
var TOOLS, INVOCATION_CONTEXT_SCHEMA;
|
|
5591
|
+
var import_node_crypto8, RESOLUTION_PROPERTIES, TOOLS, INVOCATION_CONTEXT_SCHEMA;
|
|
4548
5592
|
var init_tools = __esm({
|
|
4549
5593
|
"src/tools.ts"() {
|
|
4550
5594
|
"use strict";
|
|
5595
|
+
import_node_crypto8 = require("crypto");
|
|
4551
5596
|
init_error_detail();
|
|
4552
5597
|
init_code_tool();
|
|
4553
5598
|
init_codegraph();
|
|
4554
5599
|
init_sync_tool();
|
|
5600
|
+
init_memory_tool();
|
|
4555
5601
|
init_render();
|
|
5602
|
+
RESOLUTION_PROPERTIES = {
|
|
5603
|
+
idempotency_key: {
|
|
5604
|
+
type: "string",
|
|
5605
|
+
description: "Stable retry key; a mismatched replay is rejected"
|
|
5606
|
+
},
|
|
5607
|
+
reuse_uid: {
|
|
5608
|
+
type: "string",
|
|
5609
|
+
description: "Reuse this live same-scope node after a duplicate response"
|
|
5610
|
+
},
|
|
5611
|
+
supersedes_uid: {
|
|
5612
|
+
type: "string",
|
|
5613
|
+
description: "Create and mark this same-scope node as superseded"
|
|
5614
|
+
},
|
|
5615
|
+
contradicts_uid: {
|
|
5616
|
+
type: "string",
|
|
5617
|
+
description: "Create and mark this same-scope node as contradicted"
|
|
5618
|
+
},
|
|
5619
|
+
confirm_new: {
|
|
5620
|
+
type: "boolean",
|
|
5621
|
+
description: "Confirm that the new fact is genuinely distinct"
|
|
5622
|
+
},
|
|
5623
|
+
on_near_duplicate: {
|
|
5624
|
+
type: "string",
|
|
5625
|
+
enum: ["create"],
|
|
5626
|
+
description: "Alias for confirm_new on a near-duplicate response"
|
|
5627
|
+
}
|
|
5628
|
+
};
|
|
4556
5629
|
TOOLS = [
|
|
4557
5630
|
{
|
|
4558
5631
|
name: "mindgraph_capture",
|
|
@@ -4617,14 +5690,7 @@ var init_tools = __esm({
|
|
|
4617
5690
|
type: "string",
|
|
4618
5691
|
description: "Material Execution that produced the lesson"
|
|
4619
5692
|
},
|
|
4620
|
-
|
|
4621
|
-
type: "string",
|
|
4622
|
-
description: "Stable retry key for an intentional capture"
|
|
4623
|
-
},
|
|
4624
|
-
supersedes_uid: {
|
|
4625
|
-
type: "string",
|
|
4626
|
-
description: "Earlier capture corrected or superseded by this one"
|
|
4627
|
-
},
|
|
5693
|
+
...RESOLUTION_PROPERTIES,
|
|
4628
5694
|
summarizes_uids: {
|
|
4629
5695
|
type: "array",
|
|
4630
5696
|
items: { type: "string" },
|
|
@@ -4722,6 +5788,7 @@ var init_tools = __esm({
|
|
|
4722
5788
|
inputSchema: {
|
|
4723
5789
|
type: "object",
|
|
4724
5790
|
properties: {
|
|
5791
|
+
...RESOLUTION_PROPERTIES,
|
|
4725
5792
|
action: {
|
|
4726
5793
|
type: "string",
|
|
4727
5794
|
enum: [
|
|
@@ -4816,6 +5883,7 @@ var init_tools = __esm({
|
|
|
4816
5883
|
inputSchema: {
|
|
4817
5884
|
type: "object",
|
|
4818
5885
|
properties: {
|
|
5886
|
+
...RESOLUTION_PROPERTIES,
|
|
4819
5887
|
action: {
|
|
4820
5888
|
type: "string",
|
|
4821
5889
|
enum: [
|
|
@@ -5174,6 +6242,12 @@ var init_tools = __esm({
|
|
|
5174
6242
|
enum: ["text", "json"],
|
|
5175
6243
|
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)."
|
|
5176
6244
|
},
|
|
6245
|
+
max_output_chars: {
|
|
6246
|
+
type: "integer",
|
|
6247
|
+
minimum: 512,
|
|
6248
|
+
maximum: 24e3,
|
|
6249
|
+
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'."
|
|
6250
|
+
},
|
|
5177
6251
|
query: {
|
|
5178
6252
|
type: "string",
|
|
5179
6253
|
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."
|
|
@@ -5600,6 +6674,67 @@ var init_tools = __esm({
|
|
|
5600
6674
|
required: ["action"]
|
|
5601
6675
|
}
|
|
5602
6676
|
},
|
|
6677
|
+
{
|
|
6678
|
+
name: "mindgraph_remember",
|
|
6679
|
+
description: "Small-text memory fast path. 'remember' stores one fact, preference, decision or note synchronously; it is BM25- and vector-searchable the moment the call returns (the response says which). Pass a stable custom_id (e.g. 'pref:theme', 'deploy:target') so re-sending the same key UPDATES the same memory instead of creating a duplicate \u2014 that is the idempotency contract; without custom_id an exact duplicate is reused. 'forget' reversibly removes a memory by uid or custom_id (tombstone plus connected edges): call it with dry_run=true first to see the edge uids it would remove, then without. Undo with mindgraph_capture-independent server actions /evolve restore and restore_edge. Use mindgraph_capture for typed entities, sources and skills, and mindgraph_ingest for documents longer than a few paragraphs.",
|
|
6680
|
+
inputSchema: {
|
|
6681
|
+
type: "object",
|
|
6682
|
+
properties: {
|
|
6683
|
+
action: {
|
|
6684
|
+
type: "string",
|
|
6685
|
+
enum: ["remember", "forget"],
|
|
6686
|
+
description: "remember = store/upsert one small text; forget = reversible removal"
|
|
6687
|
+
},
|
|
6688
|
+
text: {
|
|
6689
|
+
type: "string",
|
|
6690
|
+
description: "remember: the memory text (\u2264 8 KiB). Use mindgraph_ingest for longer content."
|
|
6691
|
+
},
|
|
6692
|
+
custom_id: {
|
|
6693
|
+
type: "string",
|
|
6694
|
+
description: "Caller-owned key. remember: re-sending it edits the same memory (version bump, history kept). forget: the memory to remove."
|
|
6695
|
+
},
|
|
6696
|
+
label: {
|
|
6697
|
+
type: "string",
|
|
6698
|
+
description: "remember: optional short title; defaults to the first line of text"
|
|
6699
|
+
},
|
|
6700
|
+
uid: {
|
|
6701
|
+
type: "string",
|
|
6702
|
+
description: "forget: node uid to remove (alternative to custom_id)"
|
|
6703
|
+
},
|
|
6704
|
+
dry_run: {
|
|
6705
|
+
type: "boolean",
|
|
6706
|
+
description: "forget: preview the affected edge uids without changing anything"
|
|
6707
|
+
},
|
|
6708
|
+
cascade: {
|
|
6709
|
+
type: "boolean",
|
|
6710
|
+
description: "forget: also tombstone connected edges (default true)"
|
|
6711
|
+
},
|
|
6712
|
+
reason: {
|
|
6713
|
+
type: "string",
|
|
6714
|
+
description: "forget: why (recorded on the tombstone)"
|
|
6715
|
+
},
|
|
6716
|
+
space_uid: {
|
|
6717
|
+
type: "string",
|
|
6718
|
+
description: "remember: explicit target Space (default: the org space)"
|
|
6719
|
+
},
|
|
6720
|
+
on_near_duplicate: {
|
|
6721
|
+
type: "string",
|
|
6722
|
+
enum: ["reuse", "create"],
|
|
6723
|
+
description: "remember without custom_id: on an exact duplicate, reuse the existing memory (default) or create anyway"
|
|
6724
|
+
},
|
|
6725
|
+
props: {
|
|
6726
|
+
type: "object",
|
|
6727
|
+
description: "remember: extra Observation props"
|
|
6728
|
+
},
|
|
6729
|
+
agent_id: {
|
|
6730
|
+
type: "string",
|
|
6731
|
+
description: "Agent identifier (default: configured agent)"
|
|
6732
|
+
}
|
|
6733
|
+
},
|
|
6734
|
+
required: ["action"]
|
|
6735
|
+
}
|
|
6736
|
+
},
|
|
6737
|
+
MEMORY_TOOL,
|
|
5603
6738
|
SYNC_TOOL,
|
|
5604
6739
|
CODE_TOOL
|
|
5605
6740
|
];
|
|
@@ -5620,7 +6755,7 @@ var init_tools = __esm({
|
|
|
5620
6755
|
}
|
|
5621
6756
|
};
|
|
5622
6757
|
for (const tool of TOOLS) {
|
|
5623
|
-
if (tool.name === "mindgraph_retrieve") continue;
|
|
6758
|
+
if (tool.name === "mindgraph_retrieve" || tool.name === "mindgraph_memory") continue;
|
|
5624
6759
|
const schema = tool.inputSchema;
|
|
5625
6760
|
if (schema.properties && !schema.properties.invocation_context) {
|
|
5626
6761
|
schema.properties.invocation_context = INVOCATION_CONTEXT_SCHEMA;
|
|
@@ -5674,8 +6809,8 @@ async function getGeneratedTools(client2) {
|
|
|
5674
6809
|
cache = { tools, byName, fetchedAt: Date.now() };
|
|
5675
6810
|
retryNotBefore = 0;
|
|
5676
6811
|
return { tools, byName };
|
|
5677
|
-
} catch (
|
|
5678
|
-
if (
|
|
6812
|
+
} catch (error2) {
|
|
6813
|
+
if (error2 instanceof DuplicateGeneratedToolError) throw error2;
|
|
5679
6814
|
retryNotBefore = Date.now() + FAILURE_COOLDOWN_MS;
|
|
5680
6815
|
return cache ? { tools: cache.tools, byName: cache.byName } : EMPTY;
|
|
5681
6816
|
}
|
|
@@ -5774,13 +6909,14 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
5774
6909
|
return err4(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
5775
6910
|
}
|
|
5776
6911
|
} catch (e) {
|
|
5777
|
-
return
|
|
6912
|
+
return toolError(e);
|
|
5778
6913
|
}
|
|
5779
6914
|
}
|
|
5780
6915
|
var ok4, rendered, err4, CACHE_TTL_MS, FAILURE_COOLDOWN_MS, cache, retryNotBefore, EMPTY, DuplicateGeneratedToolError, STRUCTURED_QUERY_PASSTHROUGH;
|
|
5781
6916
|
var init_generated_tools = __esm({
|
|
5782
6917
|
"src/generated-tools.ts"() {
|
|
5783
6918
|
"use strict";
|
|
6919
|
+
init_error_detail();
|
|
5784
6920
|
init_render();
|
|
5785
6921
|
ok4 = (data) => ({
|
|
5786
6922
|
// Compact on purpose — pretty-printing doubled the token cost.
|
|
@@ -5788,8 +6924,8 @@ var init_generated_tools = __esm({
|
|
|
5788
6924
|
});
|
|
5789
6925
|
rendered = (format, raw, render) => {
|
|
5790
6926
|
if (format === "json") return ok4(raw);
|
|
5791
|
-
const
|
|
5792
|
-
return
|
|
6927
|
+
const text2 = render(raw);
|
|
6928
|
+
return text2 !== void 0 ? { content: [{ type: "text", text: text2 }] } : ok4(raw);
|
|
5793
6929
|
};
|
|
5794
6930
|
err4 = (message) => ({
|
|
5795
6931
|
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
@@ -5838,7 +6974,9 @@ function unsupportedResponse(status, body) {
|
|
|
5838
6974
|
return lower.includes("unknown governance action") || lower.includes("unknown action") || lower.includes("invalid_governance_action");
|
|
5839
6975
|
}
|
|
5840
6976
|
function toolMutability(toolName, action) {
|
|
6977
|
+
if (toolName === "mindgraph_memory") return "read";
|
|
5841
6978
|
if (toolName === "mindgraph_retrieve") return "read";
|
|
6979
|
+
if (toolName === "mindgraph_remember") return "write";
|
|
5842
6980
|
if (toolName === "mindgraph_series_query") return "read";
|
|
5843
6981
|
if (toolName === "mindgraph_plan") {
|
|
5844
6982
|
return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
|
|
@@ -5921,8 +7059,8 @@ async function checkMcpGovernance(toolName, args, config) {
|
|
|
5921
7059
|
response = candidate;
|
|
5922
7060
|
body = candidateBody;
|
|
5923
7061
|
break;
|
|
5924
|
-
} catch (
|
|
5925
|
-
lastFailure =
|
|
7062
|
+
} catch (error2) {
|
|
7063
|
+
lastFailure = error2 instanceof Error ? error2.message : String(error2);
|
|
5926
7064
|
if (attempt < retryDelays.length) {
|
|
5927
7065
|
await sleep(retryDelays[attempt]);
|
|
5928
7066
|
continue;
|
|
@@ -6067,8 +7205,10 @@ function json(uri, data) {
|
|
|
6067
7205
|
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data) }]
|
|
6068
7206
|
};
|
|
6069
7207
|
}
|
|
6070
|
-
async function readResource(client2, uri) {
|
|
7208
|
+
async function readResource(client2, uri, memoryConfig = {}) {
|
|
6071
7209
|
switch (uri) {
|
|
7210
|
+
case "mindgraph://memory/status":
|
|
7211
|
+
return json(uri, memoryStatus(memoryConfig));
|
|
6072
7212
|
case "mindgraph://stats":
|
|
6073
7213
|
return json(uri, await client2.stats());
|
|
6074
7214
|
case "mindgraph://goals":
|
|
@@ -6100,23 +7240,32 @@ async function readResource(client2, uri) {
|
|
|
6100
7240
|
}
|
|
6101
7241
|
throw new Error(`Unknown resource: ${uri}`);
|
|
6102
7242
|
}
|
|
6103
|
-
async function readGovernedResource(client2, uri, governanceConfig) {
|
|
7243
|
+
async function readGovernedResource(client2, uri, governanceConfig, memoryConfig = {}) {
|
|
7244
|
+
const toolName = uri === "mindgraph://memory/status" ? "mindgraph_memory" : RESOURCE_GOVERNANCE_TOOL;
|
|
7245
|
+
const toolArgs = uri === "mindgraph://memory/status" ? { action: "status" } : {};
|
|
6104
7246
|
const governance = await checkMcpGovernance(
|
|
6105
|
-
|
|
6106
|
-
|
|
7247
|
+
toolName,
|
|
7248
|
+
toolArgs,
|
|
6107
7249
|
{ ...governanceConfig, context: { resource_uri: uri } }
|
|
6108
7250
|
);
|
|
6109
7251
|
if (!governance.allowed) {
|
|
6110
7252
|
throw new Error(governance.message);
|
|
6111
7253
|
}
|
|
6112
|
-
return readResource(client2, uri);
|
|
7254
|
+
return readResource(client2, uri, memoryConfig);
|
|
6113
7255
|
}
|
|
6114
7256
|
var RESOURCES, RESOURCE_TEMPLATES, RESOURCE_GOVERNANCE_TOOL;
|
|
6115
7257
|
var init_resources = __esm({
|
|
6116
7258
|
"src/resources.ts"() {
|
|
6117
7259
|
"use strict";
|
|
6118
7260
|
init_governance();
|
|
7261
|
+
init_memory_tool();
|
|
6119
7262
|
RESOURCES = [
|
|
7263
|
+
{
|
|
7264
|
+
uri: "mindgraph://memory/status",
|
|
7265
|
+
name: "Memory Integration Status",
|
|
7266
|
+
description: "Portable memory profile, adapter state, supported capabilities, and explicit limitations",
|
|
7267
|
+
mimeType: "application/json"
|
|
7268
|
+
},
|
|
6120
7269
|
{
|
|
6121
7270
|
uri: "mindgraph://stats",
|
|
6122
7271
|
name: "Graph Statistics",
|
|
@@ -6178,10 +7327,10 @@ async function main() {
|
|
|
6178
7327
|
const transport = new import_stdio.StdioServerTransport();
|
|
6179
7328
|
await server.connect(transport);
|
|
6180
7329
|
console.error(
|
|
6181
|
-
`MindGraph MCP server v${"0.
|
|
7330
|
+
`MindGraph MCP server v${"0.21.0"} running on stdio (${BASE_URL})`
|
|
6182
7331
|
);
|
|
6183
7332
|
}
|
|
6184
|
-
var import_server, import_stdio, import_types, import_node_path6, API_KEY, BASE_URL, AGENT_ID, ORG_ID, PROFILE, HARNESS, client, INSTRUCTIONS, RUNNER_REFRESH, HOOK_SKEW_NOTE, server, GOVERNANCE_CONFIG, PROMPTS;
|
|
7333
|
+
var import_server, import_stdio, import_types, import_node_path6, API_KEY, BASE_URL, AGENT_ID, ORG_ID, PROFILE, HARNESS, client, INSTRUCTIONS, RUNNER_REFRESH, HOOK_SKEW_NOTE, server, GOVERNANCE_CONFIG, MEMORY_RUNTIME_CONFIG, PROMPTS;
|
|
6185
7334
|
var init_src = __esm({
|
|
6186
7335
|
"src/index.ts"() {
|
|
6187
7336
|
"use strict";
|
|
@@ -6219,56 +7368,31 @@ var init_src = __esm({
|
|
|
6219
7368
|
});
|
|
6220
7369
|
INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGraph, plus any ontology tools generated by the active schema.
|
|
6221
7370
|
|
|
6222
|
-
##
|
|
6223
|
-
|
|
6224
|
-
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.
|
|
6225
|
-
|
|
6226
|
-
**NEVER do any of these before addressing the user's topic:**
|
|
6227
|
-
- Do NOT retrieve active_goals, open_questions, contradictions, or weak_claims
|
|
6228
|
-
- Do NOT follow a "session lifecycle" or "warm-up" sequence
|
|
6229
|
-
- Do NOT make multiple serial retrieve calls when one "context" call covers it
|
|
6230
|
-
|
|
6231
|
-
There is no session to open. There is no context to pre-load. Just search for what the user asked about.
|
|
6232
|
-
|
|
6233
|
-
**Example:** User says "Tell me about Indian philosophy and Taoism"
|
|
6234
|
-
\u2713 CORRECT: \`mindgraph_retrieve({action: "context", query: "Indian philosophy Taoism"})\`
|
|
6235
|
-
\u2717 WRONG: First retrieve active_goals, then open_questions, then search
|
|
6236
|
-
\u2717 WRONG: \`mindgraph_retrieve({action: "context", query: "Tell me about Indian philosophy and Taoism"})\` \u2014 natural language won't match BM25
|
|
7371
|
+
## Default memory workflow: orient \u2192 answer \u2192 preserve
|
|
6237
7372
|
|
|
6238
|
-
|
|
7373
|
+
**Orient only when prior durable state may matter.** Self-contained questions do not require a memory call or a warm-up sequence.
|
|
6239
7374
|
|
|
6240
|
-
|
|
6241
|
-
|
|
7375
|
+
- 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.
|
|
7376
|
+
- Asking about a topic that may depend on prior knowledge: call \`mindgraph_memory\` once with action \`context\`, mode \`topic\`, and 1\u20133 discriminating keywords.
|
|
7377
|
+
- Asking about integration capability or automatic behavior: call \`mindgraph_memory\` with action \`status\`.
|
|
7378
|
+
- Use the comprehensive read tools below only when the high-level result is insufficient or the user asks for a specific graph operation.
|
|
6242
7379
|
|
|
6243
|
-
**
|
|
6244
|
-
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.
|
|
7380
|
+
**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.
|
|
6245
7381
|
|
|
6246
|
-
**
|
|
6247
|
-
- \`action: "document_index"\` \u2014 list all ingested documents (titles, dates, UIDs) to see what's in the graph
|
|
7382
|
+
**Respect failed tool results.** An isError result is a failed operation, not evidence that the graph has no matches. Preserve its code and retry guidance. If retriable is false, do not automatically repeat the unchanged call or silently substitute another retrieval mode. Explain the failure; a narrower query or a later user-requested retry is a separate decision.
|
|
6248
7383
|
|
|
6249
|
-
|
|
7384
|
+
**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.
|
|
6250
7385
|
|
|
6251
|
-
|
|
7386
|
+
## Topic retrieval details
|
|
6252
7387
|
|
|
6253
|
-
|
|
6254
|
-
- "What is Kissinger's view on NATO?" \u2192 query: \`"Kissinger NATO"\`
|
|
6255
|
-
- "Tell me about async in Rust" \u2192 query: \`"Rust async runtime"\`
|
|
6256
|
-
- "Implications of carbon tax?" \u2192 query: \`"carbon tax"\`
|
|
7388
|
+
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval succeeds but returns no matches, use \`mindgraph_retrieve\` with \`semantic\` or \`hybrid\`; use \`document_index\` to inspect ingested sources.
|
|
6257
7389
|
|
|
6258
|
-
|
|
6259
|
-
1. Try synonyms (e.g. \`"global warming"\` instead of \`"climate change"\`)
|
|
6260
|
-
2. Use \`action: "semantic"\` \u2014 vector similarity, natural language OK (e.g. \`"ways to manage stress"\` finds "mental health" nodes)
|
|
6261
|
-
3. Use \`action: "hybrid"\` \u2014 combines BM25 + semantic for best coverage
|
|
7390
|
+
## Comprehensive read tools
|
|
6262
7391
|
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
-
|
|
6266
|
-
-
|
|
6267
|
-
- User explicitly asks "what are my goals?" \u2192 action "active_goals"
|
|
6268
|
-
- User explicitly asks about open questions \u2192 action "open_questions"
|
|
6269
|
-
- 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
|
|
6270
|
-
- Explore around a known node \u2192 action "neighborhood" with start_uid
|
|
6271
|
-
- Find connections between nodes \u2192 action "path" with start_uid + end_uid
|
|
7392
|
+
- Explicit graph inventory or state questions \u2192 the matching \`mindgraph_retrieve\` action such as \`document_index\`, \`active_goals\`, or \`open_questions\`
|
|
7393
|
+
- Advice or recommendations \u2192 \`mindgraph_retrieve\` action \`preferences\`, with topic keywords
|
|
7394
|
+
- Explore around a known node \u2192 \`mindgraph_retrieve\` action \`neighborhood\` with start_uid
|
|
7395
|
+
- Find connections between nodes \u2192 \`mindgraph_retrieve\` action \`path\` with start_uid + end_uid
|
|
6272
7396
|
|
|
6273
7397
|
## When to WRITE
|
|
6274
7398
|
|
|
@@ -6303,13 +7427,14 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
6303
7427
|
|
|
6304
7428
|
## Coding profile
|
|
6305
7429
|
|
|
6306
|
-
**
|
|
6307
|
-
- "What was I working on?" / current work state / resuming anything: call \`
|
|
7430
|
+
**Coding recall order:**
|
|
7431
|
+
- "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).
|
|
6308
7432
|
- Knowledge about specific code (a function, file, or route): \`mindgraph_code\` action \`recall\` \u2014 anchor-based, not keyword-based.
|
|
6309
7433
|
- 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.
|
|
6310
7434
|
|
|
6311
7435
|
- 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.
|
|
6312
7436
|
- Capture corrections, decisions with rationale, fixes that survived meaningful failed attempts, durable invariants/preferences, and blockers with evidence.
|
|
7437
|
+
- If a write returns \`near_duplicate\`, choose \`reuse_uid\` or \`supersedes_uid\`; use \`confirm_new\` only for genuinely distinct facts.
|
|
6313
7438
|
- Do not capture routine mechanics, transient command output, facts cheaply derivable from code, unsupported speculation as high-confidence lessons, or completion without evidence.
|
|
6314
7439
|
- Adapter context is owned by ${HARNESS}; omit invocation_context because hooks replace it.`;
|
|
6315
7440
|
} else {
|
|
@@ -6319,7 +7444,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
6319
7444
|
}
|
|
6320
7445
|
RUNNER_REFRESH = (() => {
|
|
6321
7446
|
try {
|
|
6322
|
-
return refreshHookRunner("0.
|
|
7447
|
+
return refreshHookRunner("0.21.0", import_node_path6.default.join(__dirname, "cli.js"));
|
|
6323
7448
|
} catch {
|
|
6324
7449
|
return void 0;
|
|
6325
7450
|
}
|
|
@@ -6333,12 +7458,12 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
6333
7458
|
}
|
|
6334
7459
|
})();
|
|
6335
7460
|
console.error(
|
|
6336
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
7461
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.21.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
6337
7462
|
);
|
|
6338
7463
|
}
|
|
6339
7464
|
HOOK_SKEW_NOTE = (() => {
|
|
6340
7465
|
try {
|
|
6341
|
-
return versionSkewNote("0.
|
|
7466
|
+
return versionSkewNote("0.21.0");
|
|
6342
7467
|
} catch {
|
|
6343
7468
|
return void 0;
|
|
6344
7469
|
}
|
|
@@ -6352,7 +7477,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
6352
7477
|
server = new import_server.Server(
|
|
6353
7478
|
{
|
|
6354
7479
|
name: "mindgraph",
|
|
6355
|
-
version: "0.
|
|
7480
|
+
version: "0.21.0"
|
|
6356
7481
|
},
|
|
6357
7482
|
{
|
|
6358
7483
|
capabilities: {
|
|
@@ -6376,6 +7501,14 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
6376
7501
|
return process.env.MINDGRAPH_GOVERNANCE === "off";
|
|
6377
7502
|
}
|
|
6378
7503
|
};
|
|
7504
|
+
MEMORY_RUNTIME_CONFIG = {
|
|
7505
|
+
serverVersion: "0.21.0",
|
|
7506
|
+
baseUrl: BASE_URL,
|
|
7507
|
+
profile: PROFILE,
|
|
7508
|
+
harness: HARNESS,
|
|
7509
|
+
orgId: ORG_ID,
|
|
7510
|
+
agentId: AGENT_ID
|
|
7511
|
+
};
|
|
6379
7512
|
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
6380
7513
|
const { name, arguments: args } = request.params;
|
|
6381
7514
|
const rawArgs = { ...args || {} };
|
|
@@ -6395,7 +7528,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
6395
7528
|
if (desc) {
|
|
6396
7529
|
return handleGeneratedTool(client, desc, rawArgs);
|
|
6397
7530
|
}
|
|
6398
|
-
return handleTool(client, name, toolArgs);
|
|
7531
|
+
return handleTool(client, name, toolArgs, MEMORY_RUNTIME_CONFIG);
|
|
6399
7532
|
});
|
|
6400
7533
|
PROMPTS = [
|
|
6401
7534
|
{
|
|
@@ -6560,10 +7693,15 @@ ${conversation}`
|
|
|
6560
7693
|
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
6561
7694
|
});
|
|
6562
7695
|
server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
|
|
6563
|
-
return readGovernedResource(
|
|
7696
|
+
return readGovernedResource(
|
|
7697
|
+
client,
|
|
7698
|
+
request.params.uri,
|
|
7699
|
+
GOVERNANCE_CONFIG,
|
|
7700
|
+
MEMORY_RUNTIME_CONFIG
|
|
7701
|
+
);
|
|
6564
7702
|
});
|
|
6565
|
-
main().catch((
|
|
6566
|
-
console.error("Fatal error:",
|
|
7703
|
+
main().catch((error2) => {
|
|
7704
|
+
console.error("Fatal error:", error2);
|
|
6567
7705
|
process.exit(1);
|
|
6568
7706
|
});
|
|
6569
7707
|
}
|
|
@@ -6761,12 +7899,12 @@ function scalar(raw) {
|
|
|
6761
7899
|
}
|
|
6762
7900
|
return trimmed;
|
|
6763
7901
|
}
|
|
6764
|
-
function parseSkillMd(
|
|
6765
|
-
if (!
|
|
6766
|
-
const end =
|
|
7902
|
+
function parseSkillMd(text2) {
|
|
7903
|
+
if (!text2.startsWith("---\n")) return null;
|
|
7904
|
+
const end = text2.indexOf("\n---\n", 4);
|
|
6767
7905
|
if (end < 0) return null;
|
|
6768
|
-
const frontmatter =
|
|
6769
|
-
const body =
|
|
7906
|
+
const frontmatter = text2.slice(4, end + 1);
|
|
7907
|
+
const body = text2.slice(end + 5).replace(/^\n/, "").replace(/\n$/, "");
|
|
6770
7908
|
const entries = [];
|
|
6771
7909
|
for (const line of frontmatter.split("\n")) {
|
|
6772
7910
|
const top = /^([A-Za-z0-9_-]+):(.*)$/.exec(line);
|
|
@@ -6812,8 +7950,8 @@ ${line}`;
|
|
|
6812
7950
|
return result;
|
|
6813
7951
|
}
|
|
6814
7952
|
var STATE_FILE = ".mindgraph-skills-state.json";
|
|
6815
|
-
function sha256(
|
|
6816
|
-
return (0, import_node_crypto2.createHash)("sha256").update(
|
|
7953
|
+
function sha256(text2) {
|
|
7954
|
+
return (0, import_node_crypto2.createHash)("sha256").update(text2).digest("hex");
|
|
6817
7955
|
}
|
|
6818
7956
|
function loadState(dir) {
|
|
6819
7957
|
try {
|
|
@@ -6959,13 +8097,13 @@ async function skillsPush(api, skillPath) {
|
|
|
6959
8097
|
if (isSymlink(file)) {
|
|
6960
8098
|
return { outcome: "error", message: `${file} is a symlink; refusing` };
|
|
6961
8099
|
}
|
|
6962
|
-
let
|
|
8100
|
+
let text2;
|
|
6963
8101
|
try {
|
|
6964
|
-
|
|
8102
|
+
text2 = fs2.readFileSync(file, "utf8");
|
|
6965
8103
|
} catch {
|
|
6966
8104
|
return { outcome: "error", message: `could not read ${file}` };
|
|
6967
8105
|
}
|
|
6968
|
-
const parsed = parseSkillMd(
|
|
8106
|
+
const parsed = parseSkillMd(text2);
|
|
6969
8107
|
if (!parsed) {
|
|
6970
8108
|
return {
|
|
6971
8109
|
outcome: "error",
|
|
@@ -7083,8 +8221,8 @@ function withLedger(sessionId, options, update) {
|
|
|
7083
8221
|
try {
|
|
7084
8222
|
lockFd = import_node_fs3.default.openSync(lock, "wx", 384);
|
|
7085
8223
|
break;
|
|
7086
|
-
} catch (
|
|
7087
|
-
if (
|
|
8224
|
+
} catch (error2) {
|
|
8225
|
+
if (error2.code !== "EEXIST") throw error2;
|
|
7088
8226
|
try {
|
|
7089
8227
|
if (Date.now() - import_node_fs3.default.statSync(lock).mtimeMs > 3e3) import_node_fs3.default.unlinkSync(lock);
|
|
7090
8228
|
} catch {
|
|
@@ -7189,11 +8327,11 @@ var BRIEF_CHAR_BUDGET = 9e3;
|
|
|
7189
8327
|
function renderBrief(brief, meta) {
|
|
7190
8328
|
let bounded = false;
|
|
7191
8329
|
const clipTracked = (value, max) => {
|
|
7192
|
-
const
|
|
7193
|
-
if (!
|
|
7194
|
-
if (
|
|
8330
|
+
const text2 = string(value);
|
|
8331
|
+
if (!text2) return void 0;
|
|
8332
|
+
if (text2.length <= max) return text2;
|
|
7195
8333
|
bounded = true;
|
|
7196
|
-
return `${
|
|
8334
|
+
return `${text2.slice(0, max - 1)}\u2026`;
|
|
7197
8335
|
};
|
|
7198
8336
|
const nodeLine = (value, summaryMax) => {
|
|
7199
8337
|
const node = object(value);
|
|
@@ -7352,9 +8490,9 @@ async function repositoryScopeUids(input, client2, options, agentId) {
|
|
|
7352
8490
|
`${repository.repoId}: ${string(payload?.status) || "unresolved"}`
|
|
7353
8491
|
);
|
|
7354
8492
|
return void 0;
|
|
7355
|
-
} catch (
|
|
8493
|
+
} catch (error2) {
|
|
7356
8494
|
failures.push(
|
|
7357
|
-
`${repository.repoId}: ${
|
|
8495
|
+
`${repository.repoId}: ${error2?.message || "resolve failed"}`
|
|
7358
8496
|
);
|
|
7359
8497
|
return void 0;
|
|
7360
8498
|
}
|
|
@@ -7378,12 +8516,12 @@ function hasMindgraphServer(servers) {
|
|
|
7378
8516
|
for (const [name, entry] of Object.entries(servers)) {
|
|
7379
8517
|
if (name === "mindgraph") return true;
|
|
7380
8518
|
const cfg = entry && typeof entry === "object" ? entry : void 0;
|
|
7381
|
-
const
|
|
8519
|
+
const text2 = [
|
|
7382
8520
|
String(cfg?.command ?? ""),
|
|
7383
8521
|
Array.isArray(cfg?.args) ? cfg.args.join(" ") : "",
|
|
7384
8522
|
String(cfg?.url ?? "")
|
|
7385
8523
|
].join(" ");
|
|
7386
|
-
if (
|
|
8524
|
+
if (text2.includes("mindgraph-mcp")) return true;
|
|
7387
8525
|
}
|
|
7388
8526
|
return false;
|
|
7389
8527
|
}
|
|
@@ -7613,7 +8751,7 @@ async function postTool(input, client2, options) {
|
|
|
7613
8751
|
ledger.mutatingOperations += 1;
|
|
7614
8752
|
}
|
|
7615
8753
|
if (!payload?.error) {
|
|
7616
|
-
if (name.includes("mindgraph_capture") && ["lesson", "journal", "skill"].includes(action || "") || name.includes("mindgraph_commit") && action === "resolve_decision" || name.includes("mindgraph_plan") && action === "assess_risk") {
|
|
8754
|
+
if (name.includes("mindgraph_capture") && (["lesson", "journal", "skill"].includes(action || "") || ["observation", "entity"].includes(action || "") && (Array.isArray(args.code_refs) || typeof args.supersedes_uid === "string")) || name.includes("mindgraph_commit") && action === "resolve_decision" || name.includes("mindgraph_plan") && action === "assess_risk") {
|
|
7617
8755
|
ledger.memoryWritten = true;
|
|
7618
8756
|
}
|
|
7619
8757
|
}
|
|
@@ -7894,7 +9032,7 @@ async function runCodexHook(input, client2, options = {}) {
|
|
|
7894
9032
|
|
|
7895
9033
|
// src/cli.ts
|
|
7896
9034
|
init_hook_installer();
|
|
7897
|
-
function recordHookHealth(harness,
|
|
9035
|
+
function recordHookHealth(harness, error2) {
|
|
7898
9036
|
try {
|
|
7899
9037
|
const dir = process.env.MINDGRAPH_RUNTIME_DIR || path7.join(os4.homedir(), ".mindgraph", "runtime");
|
|
7900
9038
|
fs6.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -7908,7 +9046,7 @@ function recordHookHealth(harness, error) {
|
|
|
7908
9046
|
file,
|
|
7909
9047
|
`${JSON.stringify({
|
|
7910
9048
|
harness,
|
|
7911
|
-
lastError:
|
|
9049
|
+
lastError: error2.slice(0, 500),
|
|
7912
9050
|
lastFailureAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7913
9051
|
consecutiveFailures: failures + 1
|
|
7914
9052
|
})}
|
|
@@ -8131,7 +9269,7 @@ function withHooksFlag() {
|
|
|
8131
9269
|
}
|
|
8132
9270
|
function finishCodeInstall(apiKey, baseUrl, withHooks, agentId) {
|
|
8133
9271
|
if (withHooks) {
|
|
8134
|
-
const runner = installHookRunner(__filename, void 0, "0.
|
|
9272
|
+
const runner = installHookRunner(__filename, void 0, "0.21.0");
|
|
8135
9273
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
8136
9274
|
const result = installClaudeHooks("user");
|
|
8137
9275
|
console.log(
|
|
@@ -8446,7 +9584,7 @@ ${total} skill(s) synced.`);
|
|
|
8446
9584
|
if (hookHarness !== "claude-code" && hookHarness !== "codex") {
|
|
8447
9585
|
throw new Error("--harness must be claude-code or codex");
|
|
8448
9586
|
}
|
|
8449
|
-
const runner = installHookRunner(__filename, void 0, "0.
|
|
9587
|
+
const runner = installHookRunner(__filename, void 0, "0.21.0");
|
|
8450
9588
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
8451
9589
|
const result = hookHarness === "codex" ? installCodexHooks(scope, projectDir) : installClaudeHooks(scope, projectDir);
|
|
8452
9590
|
console.log(
|
|
@@ -8527,13 +9665,13 @@ ${total} skill(s) synced.`);
|
|
|
8527
9665
|
process.stdout.write(`${JSON.stringify(output)}
|
|
8528
9666
|
`);
|
|
8529
9667
|
clearHookHealth(hookHarness);
|
|
8530
|
-
} catch (
|
|
9668
|
+
} catch (error2) {
|
|
8531
9669
|
recordHookHealth(
|
|
8532
9670
|
hookHarness,
|
|
8533
|
-
|
|
9671
|
+
error2?.message || "hook failed"
|
|
8534
9672
|
);
|
|
8535
9673
|
console.error(
|
|
8536
|
-
`mindgraph-hook: failing open (${
|
|
9674
|
+
`mindgraph-hook: failing open (${error2?.message || "unknown error"})`
|
|
8537
9675
|
);
|
|
8538
9676
|
process.stdout.write("{}\n");
|
|
8539
9677
|
}
|
|
@@ -8552,7 +9690,7 @@ ${total} skill(s) synced.`);
|
|
|
8552
9690
|
process.exit(1);
|
|
8553
9691
|
}
|
|
8554
9692
|
}
|
|
8555
|
-
main2().catch((
|
|
8556
|
-
console.error("Error:",
|
|
9693
|
+
main2().catch((error2) => {
|
|
9694
|
+
console.error("Error:", error2.message || error2);
|
|
8557
9695
|
process.exit(1);
|
|
8558
9696
|
});
|