mindgraph 0.15.1 → 0.17.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 +35 -7
- package/dist/index.d.mts +284 -6
- package/dist/index.d.ts +284 -6
- package/dist/index.js +187 -6
- package/dist/index.mjs +187 -6
- package/package.json +16 -3
package/dist/index.js
CHANGED
|
@@ -25,16 +25,120 @@ __export(index_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
|
|
28
|
+
// src/retry.ts
|
|
29
|
+
var READ_POSTS = /* @__PURE__ */ new Set([
|
|
30
|
+
"/search",
|
|
31
|
+
"/retrieve/context",
|
|
32
|
+
"/nodes/batch",
|
|
33
|
+
"/edges/batch",
|
|
34
|
+
"/subgraph",
|
|
35
|
+
"/embeddings/search",
|
|
36
|
+
"/embeddings/search-text",
|
|
37
|
+
"/ontology/query",
|
|
38
|
+
"/ontology/query/structured",
|
|
39
|
+
"/ontology/objects/search"
|
|
40
|
+
]);
|
|
41
|
+
var READ_ACTIONS = {
|
|
42
|
+
"/retrieve": [
|
|
43
|
+
"text",
|
|
44
|
+
"semantic",
|
|
45
|
+
"hybrid",
|
|
46
|
+
"active_goals",
|
|
47
|
+
"open_questions",
|
|
48
|
+
"preferences",
|
|
49
|
+
"weak_claims",
|
|
50
|
+
"pending_approvals",
|
|
51
|
+
"unresolved_contradictions",
|
|
52
|
+
"merge_candidates",
|
|
53
|
+
"stale_derivations",
|
|
54
|
+
"curation_counts",
|
|
55
|
+
"layer",
|
|
56
|
+
"recent"
|
|
57
|
+
],
|
|
58
|
+
"/traverse": ["chain", "top_k_paths", "neighborhood", "path", "subgraph"],
|
|
59
|
+
"/reality/series": ["window", "aggregate", "latest", "list_for_entity", "batch_latest", "batch_aggregate"],
|
|
60
|
+
"/intent/deliberation": ["get_open"],
|
|
61
|
+
"/action/risk": ["get_assessments"],
|
|
62
|
+
"/action/skill": ["get", "list"],
|
|
63
|
+
"/memory/config": ["get_preferences", "get_policies"],
|
|
64
|
+
"/memory/sync": ["status"],
|
|
65
|
+
"/agent/plan": ["get_plan", "resume_work"],
|
|
66
|
+
"/agent/governance": ["get_pending", "check"],
|
|
67
|
+
"/agent/execution": ["get_executions"],
|
|
68
|
+
"/evolve": ["history", "snapshot"]
|
|
69
|
+
};
|
|
70
|
+
var IDEMPOTENT_WORK = /* @__PURE__ */ new Set([
|
|
71
|
+
"claim_task",
|
|
72
|
+
"heartbeat",
|
|
73
|
+
"start_iteration",
|
|
74
|
+
"checkpoint_iteration",
|
|
75
|
+
"block_task",
|
|
76
|
+
"complete_task",
|
|
77
|
+
"abandon_iteration"
|
|
78
|
+
]);
|
|
79
|
+
function errorFields(body) {
|
|
80
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
81
|
+
const fields = body;
|
|
82
|
+
return {
|
|
83
|
+
...typeof fields.code === "string" ? { code: fields.code } : {},
|
|
84
|
+
...typeof fields.retriable === "boolean" ? { retriable: fields.retriable } : {}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function canRetryRequest(method, path, body) {
|
|
88
|
+
if (method === "GET" || method === "HEAD") return true;
|
|
89
|
+
if (method !== "POST") return false;
|
|
90
|
+
if (READ_POSTS.has(path)) return true;
|
|
91
|
+
const fields = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
92
|
+
if (typeof fields.action !== "string") return false;
|
|
93
|
+
if (Object.prototype.hasOwnProperty.call(READ_ACTIONS, path) && READ_ACTIONS[path].includes(fields.action)) return true;
|
|
94
|
+
return path === "/agent/plan" && IDEMPOTENT_WORK.has(fields.action) && typeof fields.idempotency_key === "string" && fields.idempotency_key.trim().length > 0;
|
|
95
|
+
}
|
|
96
|
+
function permitsRetry(fields) {
|
|
97
|
+
return fields.retriable !== false && ![
|
|
98
|
+
"query_memory_budget_exceeded",
|
|
99
|
+
"query_timeout",
|
|
100
|
+
"query_cancelled",
|
|
101
|
+
"vector_index_rebuilding"
|
|
102
|
+
].includes(fields.code ?? "");
|
|
103
|
+
}
|
|
104
|
+
function retryDelayMs(header, backoff, attempt) {
|
|
105
|
+
const hint = Number(header);
|
|
106
|
+
return Number.isFinite(hint) && hint > 0 ? Math.min(hint * 1e3, 1e4) : Math.min(backoff * 2 ** Math.min(attempt, 32), 1e4);
|
|
107
|
+
}
|
|
108
|
+
|
|
28
109
|
// src/client.ts
|
|
29
110
|
function seg(value) {
|
|
30
111
|
return encodeURIComponent(String(value));
|
|
31
112
|
}
|
|
113
|
+
function pathSteps(response) {
|
|
114
|
+
const wrapped = response && typeof response === "object" && !Array.isArray(response) ? response : void 0;
|
|
115
|
+
const raw = wrapped?.steps ?? response;
|
|
116
|
+
if (!Array.isArray(raw)) return [];
|
|
117
|
+
return raw.flatMap((value) => {
|
|
118
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
119
|
+
const step = value;
|
|
120
|
+
const taggedName = (tagged) => {
|
|
121
|
+
if (typeof tagged === "string") return tagged;
|
|
122
|
+
if (!tagged || typeof tagged !== "object" || Array.isArray(tagged)) return null;
|
|
123
|
+
const custom = tagged.Custom;
|
|
124
|
+
return typeof custom === "string" ? custom : null;
|
|
125
|
+
};
|
|
126
|
+
return [{
|
|
127
|
+
...step,
|
|
128
|
+
node_type: taggedName(step.node_type) ?? "Unknown",
|
|
129
|
+
edge_type: taggedName(step.edge_type)
|
|
130
|
+
}];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
32
133
|
var MindGraphError = class extends Error {
|
|
33
134
|
constructor(message, status, body) {
|
|
34
135
|
super(message);
|
|
35
136
|
this.status = status;
|
|
36
137
|
this.body = body;
|
|
37
138
|
this.name = "MindGraphError";
|
|
139
|
+
const fields = errorFields(body);
|
|
140
|
+
this.code = fields.code;
|
|
141
|
+
this.retriable = fields.retriable;
|
|
38
142
|
}
|
|
39
143
|
};
|
|
40
144
|
var MindGraph = class {
|
|
@@ -52,6 +156,18 @@ var MindGraph = class {
|
|
|
52
156
|
this.telemetrySurface = config.telemetrySurface;
|
|
53
157
|
this.maxRetries = config.maxRetries ?? 3;
|
|
54
158
|
this.retryBackoffMs = config.retryBackoffMs ?? 1e3;
|
|
159
|
+
if (!Number.isSafeInteger(this.maxRetries) || this.maxRetries < 0) {
|
|
160
|
+
throw new RangeError("maxRetries must be a non-negative safe integer");
|
|
161
|
+
}
|
|
162
|
+
if (!Number.isFinite(this.retryBackoffMs) || this.retryBackoffMs < 0) {
|
|
163
|
+
throw new RangeError("retryBackoffMs must be finite and non-negative");
|
|
164
|
+
}
|
|
165
|
+
if (config.timeoutMs !== void 0) {
|
|
166
|
+
if (!Number.isFinite(config.timeoutMs) || config.timeoutMs <= 0) {
|
|
167
|
+
throw new RangeError("timeoutMs must be a positive finite number of milliseconds");
|
|
168
|
+
}
|
|
169
|
+
this.timeoutMs = config.timeoutMs;
|
|
170
|
+
}
|
|
55
171
|
}
|
|
56
172
|
// ---- HTTP helpers ----
|
|
57
173
|
async request(method, path, body) {
|
|
@@ -68,9 +184,14 @@ var MindGraph = class {
|
|
|
68
184
|
if (body !== void 0) {
|
|
69
185
|
init.body = JSON.stringify(body);
|
|
70
186
|
}
|
|
187
|
+
const retrySafe = canRetryRequest(
|
|
188
|
+
method,
|
|
189
|
+
path,
|
|
190
|
+
typeof init.body === "string" ? JSON.parse(init.body) : void 0
|
|
191
|
+
);
|
|
71
192
|
let lastError;
|
|
72
193
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
73
|
-
const res = await
|
|
194
|
+
const res = await this.fetchWithDeadline(url, init, method, path);
|
|
74
195
|
if (!res.ok) {
|
|
75
196
|
const text2 = await res.text().catch(() => "");
|
|
76
197
|
let parsed;
|
|
@@ -84,10 +205,9 @@ var MindGraph = class {
|
|
|
84
205
|
res.status,
|
|
85
206
|
parsed
|
|
86
207
|
);
|
|
87
|
-
if (res.status === 503 && attempt < this.maxRetries) {
|
|
208
|
+
if (res.status === 503 && retrySafe && permitsRetry(err) && attempt < this.maxRetries) {
|
|
88
209
|
lastError = err;
|
|
89
|
-
const
|
|
90
|
-
const delay = Number.isFinite(retryAfterSecs) && retryAfterSecs > 0 ? Math.min(retryAfterSecs * 1e3, 1e4) : this.retryBackoffMs * 2 ** attempt;
|
|
210
|
+
const delay = retryDelayMs(res.headers.get("retry-after"), this.retryBackoffMs, attempt);
|
|
91
211
|
await new Promise((r) => setTimeout(r, delay));
|
|
92
212
|
continue;
|
|
93
213
|
}
|
|
@@ -99,6 +219,33 @@ var MindGraph = class {
|
|
|
99
219
|
}
|
|
100
220
|
throw lastError;
|
|
101
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* One HTTP attempt. With `timeoutMs` set, the attempt is aborted at the
|
|
224
|
+
* deadline and surfaces as a non-retriable `MindGraphError` (`code:
|
|
225
|
+
* "timeout"`, `status: 0`). Without it the request is sent unchanged — no
|
|
226
|
+
* AbortSignal is attached, preserving the pre-0.16 behaviour.
|
|
227
|
+
*/
|
|
228
|
+
async fetchWithDeadline(url, init, method, path) {
|
|
229
|
+
if (this.timeoutMs === void 0) {
|
|
230
|
+
return fetch(url, init);
|
|
231
|
+
}
|
|
232
|
+
const controller = new AbortController();
|
|
233
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
234
|
+
try {
|
|
235
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (controller.signal.aborted) {
|
|
238
|
+
throw new MindGraphError(
|
|
239
|
+
`${method} ${path} timed out after ${this.timeoutMs}ms`,
|
|
240
|
+
0,
|
|
241
|
+
{ error: "timeout", code: "timeout", retriable: false }
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
throw error;
|
|
245
|
+
} finally {
|
|
246
|
+
clearTimeout(timer);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
102
249
|
get(path) {
|
|
103
250
|
return this.request("GET", path);
|
|
104
251
|
}
|
|
@@ -348,6 +495,40 @@ var MindGraph = class {
|
|
|
348
495
|
async memorySync(req) {
|
|
349
496
|
return this.post("/memory/sync", req);
|
|
350
497
|
}
|
|
498
|
+
// ---- Memory (fast path) ----
|
|
499
|
+
/**
|
|
500
|
+
* Store a small piece of text as a memory, synchronously. The node is
|
|
501
|
+
* BM25- and vector-searchable when this resolves (`searchable` says which).
|
|
502
|
+
* Pass `custom_id` to make re-sends an upsert of the same node.
|
|
503
|
+
*/
|
|
504
|
+
async remember(text, options = {}) {
|
|
505
|
+
return this.post("/memory/remember", { text, ...options });
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Reversibly remove a memory by `uid` or `custom_id` (tombstone plus its
|
|
509
|
+
* connected edges). `dry_run: true` previews the affected edge uids first.
|
|
510
|
+
* Undo with `restore(uid)` and `evolve({ action: "restore_edge", uid })`.
|
|
511
|
+
*/
|
|
512
|
+
async forget(target, options = {}) {
|
|
513
|
+
return this.post("/memory/forget", { ...target, ...options });
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Operator guidance for what agents should remember into a Space; surfaced
|
|
517
|
+
* on every `remember()` response and on `retrieveContext()`. Empty clears it.
|
|
518
|
+
*/
|
|
519
|
+
async setRememberInstructions(text, options = {}) {
|
|
520
|
+
return this.post("/memory/config", {
|
|
521
|
+
action: "set_remember_instructions",
|
|
522
|
+
text,
|
|
523
|
+
...options
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
async getRememberInstructions(options = {}) {
|
|
527
|
+
return this.post("/memory/config", {
|
|
528
|
+
action: "get_remember_instructions",
|
|
529
|
+
...options
|
|
530
|
+
});
|
|
531
|
+
}
|
|
351
532
|
// ---- Agent Layer ----
|
|
352
533
|
async plan(req) {
|
|
353
534
|
return this.post("/agent/plan", req);
|
|
@@ -570,7 +751,7 @@ var MindGraph = class {
|
|
|
570
751
|
start_uid: uid,
|
|
571
752
|
max_depth: maxDepth
|
|
572
753
|
});
|
|
573
|
-
return r
|
|
754
|
+
return pathSteps(r);
|
|
574
755
|
}
|
|
575
756
|
async neighborhood(uid, maxDepth = 1) {
|
|
576
757
|
const r = await this.post("/traverse", {
|
|
@@ -578,7 +759,7 @@ var MindGraph = class {
|
|
|
578
759
|
start_uid: uid,
|
|
579
760
|
max_depth: maxDepth
|
|
580
761
|
});
|
|
581
|
-
return r
|
|
762
|
+
return pathSteps(r);
|
|
582
763
|
}
|
|
583
764
|
async subgraph(uid, opts) {
|
|
584
765
|
return this.post("/subgraph", { start_uids: [uid], ...opts });
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,117 @@
|
|
|
1
|
+
// src/retry.ts
|
|
2
|
+
var READ_POSTS = /* @__PURE__ */ new Set([
|
|
3
|
+
"/search",
|
|
4
|
+
"/retrieve/context",
|
|
5
|
+
"/nodes/batch",
|
|
6
|
+
"/edges/batch",
|
|
7
|
+
"/subgraph",
|
|
8
|
+
"/embeddings/search",
|
|
9
|
+
"/embeddings/search-text",
|
|
10
|
+
"/ontology/query",
|
|
11
|
+
"/ontology/query/structured",
|
|
12
|
+
"/ontology/objects/search"
|
|
13
|
+
]);
|
|
14
|
+
var READ_ACTIONS = {
|
|
15
|
+
"/retrieve": [
|
|
16
|
+
"text",
|
|
17
|
+
"semantic",
|
|
18
|
+
"hybrid",
|
|
19
|
+
"active_goals",
|
|
20
|
+
"open_questions",
|
|
21
|
+
"preferences",
|
|
22
|
+
"weak_claims",
|
|
23
|
+
"pending_approvals",
|
|
24
|
+
"unresolved_contradictions",
|
|
25
|
+
"merge_candidates",
|
|
26
|
+
"stale_derivations",
|
|
27
|
+
"curation_counts",
|
|
28
|
+
"layer",
|
|
29
|
+
"recent"
|
|
30
|
+
],
|
|
31
|
+
"/traverse": ["chain", "top_k_paths", "neighborhood", "path", "subgraph"],
|
|
32
|
+
"/reality/series": ["window", "aggregate", "latest", "list_for_entity", "batch_latest", "batch_aggregate"],
|
|
33
|
+
"/intent/deliberation": ["get_open"],
|
|
34
|
+
"/action/risk": ["get_assessments"],
|
|
35
|
+
"/action/skill": ["get", "list"],
|
|
36
|
+
"/memory/config": ["get_preferences", "get_policies"],
|
|
37
|
+
"/memory/sync": ["status"],
|
|
38
|
+
"/agent/plan": ["get_plan", "resume_work"],
|
|
39
|
+
"/agent/governance": ["get_pending", "check"],
|
|
40
|
+
"/agent/execution": ["get_executions"],
|
|
41
|
+
"/evolve": ["history", "snapshot"]
|
|
42
|
+
};
|
|
43
|
+
var IDEMPOTENT_WORK = /* @__PURE__ */ new Set([
|
|
44
|
+
"claim_task",
|
|
45
|
+
"heartbeat",
|
|
46
|
+
"start_iteration",
|
|
47
|
+
"checkpoint_iteration",
|
|
48
|
+
"block_task",
|
|
49
|
+
"complete_task",
|
|
50
|
+
"abandon_iteration"
|
|
51
|
+
]);
|
|
52
|
+
function errorFields(body) {
|
|
53
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
54
|
+
const fields = body;
|
|
55
|
+
return {
|
|
56
|
+
...typeof fields.code === "string" ? { code: fields.code } : {},
|
|
57
|
+
...typeof fields.retriable === "boolean" ? { retriable: fields.retriable } : {}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function canRetryRequest(method, path, body) {
|
|
61
|
+
if (method === "GET" || method === "HEAD") return true;
|
|
62
|
+
if (method !== "POST") return false;
|
|
63
|
+
if (READ_POSTS.has(path)) return true;
|
|
64
|
+
const fields = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
65
|
+
if (typeof fields.action !== "string") return false;
|
|
66
|
+
if (Object.prototype.hasOwnProperty.call(READ_ACTIONS, path) && READ_ACTIONS[path].includes(fields.action)) return true;
|
|
67
|
+
return path === "/agent/plan" && IDEMPOTENT_WORK.has(fields.action) && typeof fields.idempotency_key === "string" && fields.idempotency_key.trim().length > 0;
|
|
68
|
+
}
|
|
69
|
+
function permitsRetry(fields) {
|
|
70
|
+
return fields.retriable !== false && ![
|
|
71
|
+
"query_memory_budget_exceeded",
|
|
72
|
+
"query_timeout",
|
|
73
|
+
"query_cancelled",
|
|
74
|
+
"vector_index_rebuilding"
|
|
75
|
+
].includes(fields.code ?? "");
|
|
76
|
+
}
|
|
77
|
+
function retryDelayMs(header, backoff, attempt) {
|
|
78
|
+
const hint = Number(header);
|
|
79
|
+
return Number.isFinite(hint) && hint > 0 ? Math.min(hint * 1e3, 1e4) : Math.min(backoff * 2 ** Math.min(attempt, 32), 1e4);
|
|
80
|
+
}
|
|
81
|
+
|
|
1
82
|
// src/client.ts
|
|
2
83
|
function seg(value) {
|
|
3
84
|
return encodeURIComponent(String(value));
|
|
4
85
|
}
|
|
86
|
+
function pathSteps(response) {
|
|
87
|
+
const wrapped = response && typeof response === "object" && !Array.isArray(response) ? response : void 0;
|
|
88
|
+
const raw = wrapped?.steps ?? response;
|
|
89
|
+
if (!Array.isArray(raw)) return [];
|
|
90
|
+
return raw.flatMap((value) => {
|
|
91
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
92
|
+
const step = value;
|
|
93
|
+
const taggedName = (tagged) => {
|
|
94
|
+
if (typeof tagged === "string") return tagged;
|
|
95
|
+
if (!tagged || typeof tagged !== "object" || Array.isArray(tagged)) return null;
|
|
96
|
+
const custom = tagged.Custom;
|
|
97
|
+
return typeof custom === "string" ? custom : null;
|
|
98
|
+
};
|
|
99
|
+
return [{
|
|
100
|
+
...step,
|
|
101
|
+
node_type: taggedName(step.node_type) ?? "Unknown",
|
|
102
|
+
edge_type: taggedName(step.edge_type)
|
|
103
|
+
}];
|
|
104
|
+
});
|
|
105
|
+
}
|
|
5
106
|
var MindGraphError = class extends Error {
|
|
6
107
|
constructor(message, status, body) {
|
|
7
108
|
super(message);
|
|
8
109
|
this.status = status;
|
|
9
110
|
this.body = body;
|
|
10
111
|
this.name = "MindGraphError";
|
|
112
|
+
const fields = errorFields(body);
|
|
113
|
+
this.code = fields.code;
|
|
114
|
+
this.retriable = fields.retriable;
|
|
11
115
|
}
|
|
12
116
|
};
|
|
13
117
|
var MindGraph = class {
|
|
@@ -25,6 +129,18 @@ var MindGraph = class {
|
|
|
25
129
|
this.telemetrySurface = config.telemetrySurface;
|
|
26
130
|
this.maxRetries = config.maxRetries ?? 3;
|
|
27
131
|
this.retryBackoffMs = config.retryBackoffMs ?? 1e3;
|
|
132
|
+
if (!Number.isSafeInteger(this.maxRetries) || this.maxRetries < 0) {
|
|
133
|
+
throw new RangeError("maxRetries must be a non-negative safe integer");
|
|
134
|
+
}
|
|
135
|
+
if (!Number.isFinite(this.retryBackoffMs) || this.retryBackoffMs < 0) {
|
|
136
|
+
throw new RangeError("retryBackoffMs must be finite and non-negative");
|
|
137
|
+
}
|
|
138
|
+
if (config.timeoutMs !== void 0) {
|
|
139
|
+
if (!Number.isFinite(config.timeoutMs) || config.timeoutMs <= 0) {
|
|
140
|
+
throw new RangeError("timeoutMs must be a positive finite number of milliseconds");
|
|
141
|
+
}
|
|
142
|
+
this.timeoutMs = config.timeoutMs;
|
|
143
|
+
}
|
|
28
144
|
}
|
|
29
145
|
// ---- HTTP helpers ----
|
|
30
146
|
async request(method, path, body) {
|
|
@@ -41,9 +157,14 @@ var MindGraph = class {
|
|
|
41
157
|
if (body !== void 0) {
|
|
42
158
|
init.body = JSON.stringify(body);
|
|
43
159
|
}
|
|
160
|
+
const retrySafe = canRetryRequest(
|
|
161
|
+
method,
|
|
162
|
+
path,
|
|
163
|
+
typeof init.body === "string" ? JSON.parse(init.body) : void 0
|
|
164
|
+
);
|
|
44
165
|
let lastError;
|
|
45
166
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
46
|
-
const res = await
|
|
167
|
+
const res = await this.fetchWithDeadline(url, init, method, path);
|
|
47
168
|
if (!res.ok) {
|
|
48
169
|
const text2 = await res.text().catch(() => "");
|
|
49
170
|
let parsed;
|
|
@@ -57,10 +178,9 @@ var MindGraph = class {
|
|
|
57
178
|
res.status,
|
|
58
179
|
parsed
|
|
59
180
|
);
|
|
60
|
-
if (res.status === 503 && attempt < this.maxRetries) {
|
|
181
|
+
if (res.status === 503 && retrySafe && permitsRetry(err) && attempt < this.maxRetries) {
|
|
61
182
|
lastError = err;
|
|
62
|
-
const
|
|
63
|
-
const delay = Number.isFinite(retryAfterSecs) && retryAfterSecs > 0 ? Math.min(retryAfterSecs * 1e3, 1e4) : this.retryBackoffMs * 2 ** attempt;
|
|
183
|
+
const delay = retryDelayMs(res.headers.get("retry-after"), this.retryBackoffMs, attempt);
|
|
64
184
|
await new Promise((r) => setTimeout(r, delay));
|
|
65
185
|
continue;
|
|
66
186
|
}
|
|
@@ -72,6 +192,33 @@ var MindGraph = class {
|
|
|
72
192
|
}
|
|
73
193
|
throw lastError;
|
|
74
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* One HTTP attempt. With `timeoutMs` set, the attempt is aborted at the
|
|
197
|
+
* deadline and surfaces as a non-retriable `MindGraphError` (`code:
|
|
198
|
+
* "timeout"`, `status: 0`). Without it the request is sent unchanged — no
|
|
199
|
+
* AbortSignal is attached, preserving the pre-0.16 behaviour.
|
|
200
|
+
*/
|
|
201
|
+
async fetchWithDeadline(url, init, method, path) {
|
|
202
|
+
if (this.timeoutMs === void 0) {
|
|
203
|
+
return fetch(url, init);
|
|
204
|
+
}
|
|
205
|
+
const controller = new AbortController();
|
|
206
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
207
|
+
try {
|
|
208
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (controller.signal.aborted) {
|
|
211
|
+
throw new MindGraphError(
|
|
212
|
+
`${method} ${path} timed out after ${this.timeoutMs}ms`,
|
|
213
|
+
0,
|
|
214
|
+
{ error: "timeout", code: "timeout", retriable: false }
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
throw error;
|
|
218
|
+
} finally {
|
|
219
|
+
clearTimeout(timer);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
75
222
|
get(path) {
|
|
76
223
|
return this.request("GET", path);
|
|
77
224
|
}
|
|
@@ -321,6 +468,40 @@ var MindGraph = class {
|
|
|
321
468
|
async memorySync(req) {
|
|
322
469
|
return this.post("/memory/sync", req);
|
|
323
470
|
}
|
|
471
|
+
// ---- Memory (fast path) ----
|
|
472
|
+
/**
|
|
473
|
+
* Store a small piece of text as a memory, synchronously. The node is
|
|
474
|
+
* BM25- and vector-searchable when this resolves (`searchable` says which).
|
|
475
|
+
* Pass `custom_id` to make re-sends an upsert of the same node.
|
|
476
|
+
*/
|
|
477
|
+
async remember(text, options = {}) {
|
|
478
|
+
return this.post("/memory/remember", { text, ...options });
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Reversibly remove a memory by `uid` or `custom_id` (tombstone plus its
|
|
482
|
+
* connected edges). `dry_run: true` previews the affected edge uids first.
|
|
483
|
+
* Undo with `restore(uid)` and `evolve({ action: "restore_edge", uid })`.
|
|
484
|
+
*/
|
|
485
|
+
async forget(target, options = {}) {
|
|
486
|
+
return this.post("/memory/forget", { ...target, ...options });
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Operator guidance for what agents should remember into a Space; surfaced
|
|
490
|
+
* on every `remember()` response and on `retrieveContext()`. Empty clears it.
|
|
491
|
+
*/
|
|
492
|
+
async setRememberInstructions(text, options = {}) {
|
|
493
|
+
return this.post("/memory/config", {
|
|
494
|
+
action: "set_remember_instructions",
|
|
495
|
+
text,
|
|
496
|
+
...options
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
async getRememberInstructions(options = {}) {
|
|
500
|
+
return this.post("/memory/config", {
|
|
501
|
+
action: "get_remember_instructions",
|
|
502
|
+
...options
|
|
503
|
+
});
|
|
504
|
+
}
|
|
324
505
|
// ---- Agent Layer ----
|
|
325
506
|
async plan(req) {
|
|
326
507
|
return this.post("/agent/plan", req);
|
|
@@ -543,7 +724,7 @@ var MindGraph = class {
|
|
|
543
724
|
start_uid: uid,
|
|
544
725
|
max_depth: maxDepth
|
|
545
726
|
});
|
|
546
|
-
return r
|
|
727
|
+
return pathSteps(r);
|
|
547
728
|
}
|
|
548
729
|
async neighborhood(uid, maxDepth = 1) {
|
|
549
730
|
const r = await this.post("/traverse", {
|
|
@@ -551,7 +732,7 @@ var MindGraph = class {
|
|
|
551
732
|
start_uid: uid,
|
|
552
733
|
max_depth: maxDepth
|
|
553
734
|
});
|
|
554
|
-
return r
|
|
735
|
+
return pathSteps(r);
|
|
555
736
|
}
|
|
556
737
|
async subgraph(uid, opts) {
|
|
557
738
|
return this.post("/subgraph", { start_uids: [uid], ...opts });
|
package/package.json
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindgraph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "TypeScript client for the MindGraph Cloud API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"files": [
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
9
11
|
"scripts": {
|
|
12
|
+
"prepare": "npm run build",
|
|
10
13
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
11
14
|
"lint": "tsc --noEmit",
|
|
12
15
|
"test": "vitest run",
|
|
13
16
|
"test:offline": "vitest run src/offline.test.ts",
|
|
14
17
|
"test:e2e": "vitest run src/integration.test.ts"
|
|
15
18
|
},
|
|
16
|
-
"keywords": [
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mindgraph",
|
|
21
|
+
"knowledge-graph",
|
|
22
|
+
"cognitive",
|
|
23
|
+
"ai",
|
|
24
|
+
"agent"
|
|
25
|
+
],
|
|
17
26
|
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/shuruheel/mindgraph-ts.git"
|
|
30
|
+
},
|
|
18
31
|
"devDependencies": {
|
|
19
32
|
"@types/node": "^25.4.0",
|
|
20
33
|
"tsup": "^8.0.0",
|