@andespindola/brainlink 1.0.4 → 1.0.6
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 +17 -9
- package/dist/application/add-note.js +2 -2
- package/dist/application/build-context.js +16 -10
- package/dist/application/canonical-context-links.js +44 -5
- package/dist/application/check-package-update.js +105 -0
- package/dist/application/frontend/client/chunk-fetch.js +236 -0
- package/dist/application/frontend/client/controls.js +178 -0
- package/dist/application/frontend/client/elements.js +122 -0
- package/dist/application/frontend/client/input.js +202 -0
- package/dist/application/frontend/client/node-details.js +191 -0
- package/dist/application/frontend/client/rendering.js +296 -0
- package/dist/application/frontend/client/scope-theme.js +114 -0
- package/dist/application/frontend/client/spatial.js +98 -0
- package/dist/application/frontend/client/storage.js +215 -0
- package/dist/application/frontend/client/upload.js +90 -0
- package/dist/application/frontend/client/worker-bootstrap.js +147 -0
- package/dist/application/frontend/client-js.js +24 -1837
- package/dist/application/frontend/client-render-worker-js.js +1 -1
- package/dist/application/index-vault-phases.js +189 -0
- package/dist/application/index-vault.js +44 -165
- package/dist/application/server/routes.js +12 -9
- package/dist/cli/commands/write/dedupe-commands.js +59 -0
- package/dist/cli/commands/write/index-commands.js +205 -0
- package/dist/cli/commands/write/link-commands.js +68 -0
- package/dist/cli/commands/write/note-commands.js +146 -0
- package/dist/cli/commands/write/server-commands.js +553 -0
- package/dist/cli/commands/write/shared.js +35 -0
- package/dist/cli/commands/write/vault-lifecycle-commands.js +270 -0
- package/dist/cli/commands/write-commands.js +12 -1303
- package/dist/cli/main.js +39 -3
- package/dist/domain/context.js +39 -3
- package/dist/domain/embeddings.js +31 -5
- package/dist/domain/graph-contexts.js +62 -57
- package/dist/domain/graph-layout/cauliflower-layout.js +116 -0
- package/dist/domain/graph-layout/collisions.js +100 -0
- package/dist/domain/graph-layout/hierarchy.js +135 -0
- package/dist/domain/graph-layout/metrics.js +111 -0
- package/dist/domain/graph-layout/segments.js +76 -0
- package/dist/domain/graph-layout/star-layout.js +110 -0
- package/dist/domain/graph-layout.js +4 -625
- package/dist/infrastructure/config.js +10 -4
- package/dist/infrastructure/file-index.js +13 -4
- package/dist/infrastructure/semantic-prefilter.js +24 -0
- package/dist/mcp/server.js +7 -0
- package/dist/mcp/tool-guard.js +29 -0
- package/dist/mcp/tools/maintenance-tools.js +409 -0
- package/dist/mcp/tools/read-tools.js +504 -0
- package/dist/mcp/tools/shared.js +216 -0
- package/dist/mcp/tools/write-tools.js +247 -0
- package/dist/mcp/tools.js +3 -1357
- package/docs/AGENT_USAGE.md +4 -4
- package/docs/QUICKSTART.md +5 -1
- package/package.json +2 -2
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getBrokenLinksReport, getOrphansReport, getStats, validateVault } from '../../application/analyze-vault.js';
|
|
3
|
+
import { buildContextPackage, readContextDataSignature } from '../../application/build-context.js';
|
|
4
|
+
import { getGraph } from '../../application/get-graph.js';
|
|
5
|
+
import { getGraphContexts } from '../../application/get-graph-contexts.js';
|
|
6
|
+
import { explainSearchResults, suggestBrokenLinkFixes, suggestContextLinks } from '../../application/memory-suggestions.js';
|
|
7
|
+
import { buildActionableDoctor } from '../../application/operational-workflows.js';
|
|
8
|
+
import { searchKnowledge } from '../../application/search-knowledge.js';
|
|
9
|
+
import { sanitizeContextStrategy, sanitizeSearchMode } from '../../infrastructure/config.js';
|
|
10
|
+
import { clearContextPacks, listContextPacks } from '../../infrastructure/context-packs.js';
|
|
11
|
+
import { getBootstrapPolicy, getBootstrapSessionStatus, getContextSessionStatus, touchContextSession } from '../../infrastructure/session-state.js';
|
|
12
|
+
import { getRuntimeMetadata } from '../runtime.js';
|
|
13
|
+
import { agentInput, contextStrategyInput, ensureBootstrapReady, ensureContextReady, jsonResult, optionalPositiveInteger, positiveInteger, resolveExecutionContext, searchModeInput, vaultInput } from './shared.js';
|
|
14
|
+
export const contextInputSchema = {
|
|
15
|
+
...vaultInput,
|
|
16
|
+
...agentInput,
|
|
17
|
+
...searchModeInput,
|
|
18
|
+
...contextStrategyInput,
|
|
19
|
+
query: z.string().min(1).describe('Task or question to retrieve Brainlink context for.'),
|
|
20
|
+
limit: optionalPositiveInteger().describe('Maximum search results before context selection.'),
|
|
21
|
+
tokens: optionalPositiveInteger().describe('Maximum estimated context tokens.')
|
|
22
|
+
};
|
|
23
|
+
export const contextPacksInputSchema = {
|
|
24
|
+
...vaultInput,
|
|
25
|
+
...agentInput,
|
|
26
|
+
action: z.enum(['list', 'clear']).optional().default('list').describe('Action to perform on persisted CAG context packs.'),
|
|
27
|
+
staleOnly: z.boolean().optional().default(false).describe('When clearing, remove only packs stale for the current index and volatile-memory signature.')
|
|
28
|
+
};
|
|
29
|
+
export const searchInputSchema = {
|
|
30
|
+
...vaultInput,
|
|
31
|
+
...agentInput,
|
|
32
|
+
...searchModeInput,
|
|
33
|
+
query: z.string().min(1).describe('Search query.'),
|
|
34
|
+
limit: optionalPositiveInteger().describe('Maximum result count.')
|
|
35
|
+
};
|
|
36
|
+
export const explainInputSchema = {
|
|
37
|
+
...vaultInput,
|
|
38
|
+
...agentInput,
|
|
39
|
+
...searchModeInput,
|
|
40
|
+
query: z.string().min(1).describe('Search query to explain.'),
|
|
41
|
+
limit: optionalPositiveInteger().describe('Maximum result count.')
|
|
42
|
+
};
|
|
43
|
+
export const validateInputSchema = {
|
|
44
|
+
...vaultInput,
|
|
45
|
+
...agentInput
|
|
46
|
+
};
|
|
47
|
+
export const doctorActionsInputSchema = {
|
|
48
|
+
...vaultInput,
|
|
49
|
+
...agentInput
|
|
50
|
+
};
|
|
51
|
+
export const graphInputSchema = {
|
|
52
|
+
...vaultInput,
|
|
53
|
+
...agentInput
|
|
54
|
+
};
|
|
55
|
+
export const graphContextsInputSchema = {
|
|
56
|
+
...vaultInput,
|
|
57
|
+
...agentInput
|
|
58
|
+
};
|
|
59
|
+
export const brokenLinksInputSchema = {
|
|
60
|
+
...vaultInput,
|
|
61
|
+
...agentInput
|
|
62
|
+
};
|
|
63
|
+
export const suggestLinksInputSchema = {
|
|
64
|
+
...vaultInput,
|
|
65
|
+
...agentInput,
|
|
66
|
+
content: z.string().min(1).optional().describe('Content to inspect for Context Link suggestions. Required unless broken=true.'),
|
|
67
|
+
broken: z.boolean().optional().default(false).describe('Suggest fixes for unresolved wiki links instead of content links.'),
|
|
68
|
+
limit: positiveInteger(5).describe('Maximum suggestions to return.')
|
|
69
|
+
};
|
|
70
|
+
export const orphansInputSchema = {
|
|
71
|
+
...vaultInput,
|
|
72
|
+
...agentInput
|
|
73
|
+
};
|
|
74
|
+
export const statsInputSchema = {
|
|
75
|
+
...vaultInput,
|
|
76
|
+
...agentInput
|
|
77
|
+
};
|
|
78
|
+
export const versionInputSchema = {
|
|
79
|
+
...vaultInput,
|
|
80
|
+
...agentInput
|
|
81
|
+
};
|
|
82
|
+
export const recommendationsInputSchema = {
|
|
83
|
+
...vaultInput,
|
|
84
|
+
...agentInput,
|
|
85
|
+
...searchModeInput,
|
|
86
|
+
...contextStrategyInput,
|
|
87
|
+
query: z.string().min(1).optional().describe('Optional current task query to generate context-focused recommendations.'),
|
|
88
|
+
limit: optionalPositiveInteger().describe('Optional context limit override for generated recommendations.'),
|
|
89
|
+
tokens: optionalPositiveInteger().describe('Optional context token budget override for generated recommendations.')
|
|
90
|
+
};
|
|
91
|
+
export const contextTool = async (input) => {
|
|
92
|
+
const context = await resolveExecutionContext(input);
|
|
93
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_context');
|
|
94
|
+
if (readiness.preflight) {
|
|
95
|
+
return readiness.preflight;
|
|
96
|
+
}
|
|
97
|
+
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
98
|
+
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
99
|
+
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
100
|
+
const tokens = input.tokens ?? context.defaults.defaultContextTokens;
|
|
101
|
+
const contextPackage = await buildContextPackage(context.vault, input.query, limit, tokens, context.agent, mode, strategy, context.defaults.defaultContextCacheTtlMs);
|
|
102
|
+
const contextSession = await touchContextSession(context.vault, context.agent);
|
|
103
|
+
return jsonResult({
|
|
104
|
+
vault: context.vault,
|
|
105
|
+
agent: context.agent,
|
|
106
|
+
mode,
|
|
107
|
+
strategy,
|
|
108
|
+
limit,
|
|
109
|
+
tokens,
|
|
110
|
+
contextSession,
|
|
111
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
112
|
+
...contextPackage
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
export const contextPacksTool = async (input) => {
|
|
116
|
+
const context = await resolveExecutionContext(input);
|
|
117
|
+
const dataSignature = await readContextDataSignature(context.vault);
|
|
118
|
+
if (input.action === 'clear') {
|
|
119
|
+
const result = await clearContextPacks(context.vault, {
|
|
120
|
+
staleOnly: input.staleOnly === true,
|
|
121
|
+
dataSignature
|
|
122
|
+
});
|
|
123
|
+
return jsonResult({
|
|
124
|
+
vault: context.vault,
|
|
125
|
+
agent: context.agent,
|
|
126
|
+
dataSignature,
|
|
127
|
+
action: 'clear',
|
|
128
|
+
staleOnly: input.staleOnly === true,
|
|
129
|
+
...result
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const packs = await listContextPacks(context.vault, dataSignature);
|
|
133
|
+
return jsonResult({
|
|
134
|
+
vault: context.vault,
|
|
135
|
+
agent: context.agent,
|
|
136
|
+
dataSignature,
|
|
137
|
+
action: 'list',
|
|
138
|
+
packs
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
export const searchTool = async (input) => {
|
|
142
|
+
const context = await resolveExecutionContext(input);
|
|
143
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_search');
|
|
144
|
+
if (readiness.preflight) {
|
|
145
|
+
return readiness.preflight;
|
|
146
|
+
}
|
|
147
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_search');
|
|
148
|
+
if (contextReadiness.preflight) {
|
|
149
|
+
return contextReadiness.preflight;
|
|
150
|
+
}
|
|
151
|
+
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
152
|
+
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
153
|
+
const results = await searchKnowledge(context.vault, input.query, limit, context.agent, mode);
|
|
154
|
+
return jsonResult({
|
|
155
|
+
vault: context.vault,
|
|
156
|
+
agent: context.agent,
|
|
157
|
+
query: input.query,
|
|
158
|
+
limit,
|
|
159
|
+
mode,
|
|
160
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
161
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
162
|
+
results
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
export const explainTool = async (input) => {
|
|
166
|
+
const context = await resolveExecutionContext(input);
|
|
167
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_explain');
|
|
168
|
+
if (readiness.preflight) {
|
|
169
|
+
return readiness.preflight;
|
|
170
|
+
}
|
|
171
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_explain');
|
|
172
|
+
if (contextReadiness.preflight) {
|
|
173
|
+
return contextReadiness.preflight;
|
|
174
|
+
}
|
|
175
|
+
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
176
|
+
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
177
|
+
const results = await explainSearchResults(context.vault, input.query, limit, context.agent, mode);
|
|
178
|
+
return jsonResult({
|
|
179
|
+
vault: context.vault,
|
|
180
|
+
agent: context.agent,
|
|
181
|
+
query: input.query,
|
|
182
|
+
limit,
|
|
183
|
+
mode,
|
|
184
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
185
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
186
|
+
results
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
export const validateTool = async (input) => {
|
|
190
|
+
const context = await resolveExecutionContext(input);
|
|
191
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_validate');
|
|
192
|
+
if (readiness.preflight) {
|
|
193
|
+
return readiness.preflight;
|
|
194
|
+
}
|
|
195
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_validate');
|
|
196
|
+
if (contextReadiness.preflight) {
|
|
197
|
+
return contextReadiness.preflight;
|
|
198
|
+
}
|
|
199
|
+
const validation = await validateVault(context.vault, context.agent);
|
|
200
|
+
return jsonResult({
|
|
201
|
+
vault: context.vault,
|
|
202
|
+
agent: context.agent,
|
|
203
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
204
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
205
|
+
...validation
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
export const doctorActionsTool = async (input) => {
|
|
209
|
+
const context = await resolveExecutionContext(input);
|
|
210
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_doctor_actions');
|
|
211
|
+
if (readiness.preflight) {
|
|
212
|
+
return readiness.preflight;
|
|
213
|
+
}
|
|
214
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_doctor_actions');
|
|
215
|
+
if (contextReadiness.preflight) {
|
|
216
|
+
return contextReadiness.preflight;
|
|
217
|
+
}
|
|
218
|
+
const report = await buildActionableDoctor(context.vault);
|
|
219
|
+
return jsonResult({
|
|
220
|
+
vault: context.vault,
|
|
221
|
+
agent: context.agent,
|
|
222
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
223
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
224
|
+
...report
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
export const graphTool = async (input) => {
|
|
228
|
+
const context = await resolveExecutionContext(input);
|
|
229
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_graph');
|
|
230
|
+
if (readiness.preflight) {
|
|
231
|
+
return readiness.preflight;
|
|
232
|
+
}
|
|
233
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_graph');
|
|
234
|
+
if (contextReadiness.preflight) {
|
|
235
|
+
return contextReadiness.preflight;
|
|
236
|
+
}
|
|
237
|
+
const graph = await getGraph(context.vault, context.agent);
|
|
238
|
+
return jsonResult({
|
|
239
|
+
vault: context.vault,
|
|
240
|
+
agent: context.agent,
|
|
241
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
242
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
243
|
+
...graph
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
export const graphContextsTool = async (input) => {
|
|
247
|
+
const context = await resolveExecutionContext(input);
|
|
248
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_graph_contexts');
|
|
249
|
+
if (readiness.preflight) {
|
|
250
|
+
return readiness.preflight;
|
|
251
|
+
}
|
|
252
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_graph_contexts');
|
|
253
|
+
if (contextReadiness.preflight) {
|
|
254
|
+
return contextReadiness.preflight;
|
|
255
|
+
}
|
|
256
|
+
const contexts = await getGraphContexts(context.vault, context.agent);
|
|
257
|
+
return jsonResult({
|
|
258
|
+
vault: context.vault,
|
|
259
|
+
agent: context.agent,
|
|
260
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
261
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
262
|
+
contexts
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
export const brokenLinksTool = async (input) => {
|
|
266
|
+
const context = await resolveExecutionContext(input);
|
|
267
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_broken_links');
|
|
268
|
+
if (readiness.preflight) {
|
|
269
|
+
return readiness.preflight;
|
|
270
|
+
}
|
|
271
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_broken_links');
|
|
272
|
+
if (contextReadiness.preflight) {
|
|
273
|
+
return contextReadiness.preflight;
|
|
274
|
+
}
|
|
275
|
+
const brokenLinks = await getBrokenLinksReport(context.vault, context.agent);
|
|
276
|
+
return jsonResult({
|
|
277
|
+
vault: context.vault,
|
|
278
|
+
agent: context.agent,
|
|
279
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
280
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
281
|
+
brokenLinks
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
export const suggestLinksTool = async (input) => {
|
|
285
|
+
const context = await resolveExecutionContext(input);
|
|
286
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_suggest_links');
|
|
287
|
+
if (readiness.preflight) {
|
|
288
|
+
return readiness.preflight;
|
|
289
|
+
}
|
|
290
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_suggest_links');
|
|
291
|
+
if (contextReadiness.preflight) {
|
|
292
|
+
return contextReadiness.preflight;
|
|
293
|
+
}
|
|
294
|
+
if (input.broken) {
|
|
295
|
+
const suggestions = await suggestBrokenLinkFixes(context.vault, context.agent, input.limit);
|
|
296
|
+
return jsonResult({
|
|
297
|
+
vault: context.vault,
|
|
298
|
+
agent: context.agent,
|
|
299
|
+
mode: 'broken-links',
|
|
300
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
301
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
302
|
+
suggestions
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (!input.content || input.content.trim().length === 0) {
|
|
306
|
+
throw new Error('content is required when broken=false.');
|
|
307
|
+
}
|
|
308
|
+
const suggestions = await suggestContextLinks(context.vault, input.content, context.agent, input.limit);
|
|
309
|
+
return jsonResult({
|
|
310
|
+
vault: context.vault,
|
|
311
|
+
agent: context.agent,
|
|
312
|
+
mode: 'content',
|
|
313
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
314
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
315
|
+
suggestions
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
export const orphansTool = async (input) => {
|
|
319
|
+
const context = await resolveExecutionContext(input);
|
|
320
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_orphans');
|
|
321
|
+
if (readiness.preflight) {
|
|
322
|
+
return readiness.preflight;
|
|
323
|
+
}
|
|
324
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_orphans');
|
|
325
|
+
if (contextReadiness.preflight) {
|
|
326
|
+
return contextReadiness.preflight;
|
|
327
|
+
}
|
|
328
|
+
const orphans = await getOrphansReport(context.vault, context.agent);
|
|
329
|
+
return jsonResult({
|
|
330
|
+
vault: context.vault,
|
|
331
|
+
agent: context.agent,
|
|
332
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
333
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
334
|
+
orphans
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
export const statsTool = async (input) => {
|
|
338
|
+
const context = await resolveExecutionContext(input);
|
|
339
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_stats');
|
|
340
|
+
if (readiness.preflight) {
|
|
341
|
+
return readiness.preflight;
|
|
342
|
+
}
|
|
343
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_stats');
|
|
344
|
+
if (contextReadiness.preflight) {
|
|
345
|
+
return contextReadiness.preflight;
|
|
346
|
+
}
|
|
347
|
+
const stats = await getStats(context.vault, context.agent);
|
|
348
|
+
return jsonResult({
|
|
349
|
+
vault: context.vault,
|
|
350
|
+
agent: context.agent,
|
|
351
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
352
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
353
|
+
stats
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
export const versionTool = async (input) => {
|
|
357
|
+
const context = await resolveExecutionContext(input);
|
|
358
|
+
return jsonResult({
|
|
359
|
+
vault: context.vault,
|
|
360
|
+
agent: context.agent,
|
|
361
|
+
runtime: getRuntimeMetadata()
|
|
362
|
+
});
|
|
363
|
+
};
|
|
364
|
+
export const recommendationsTool = async (input) => {
|
|
365
|
+
const context = await resolveExecutionContext(input);
|
|
366
|
+
const policy = await getBootstrapPolicy();
|
|
367
|
+
const bootstrapStatus = await getBootstrapSessionStatus(context.vault, context.agent);
|
|
368
|
+
const contextStatus = await getContextSessionStatus(context.vault, context.agent);
|
|
369
|
+
const stats = await getStats(context.vault, context.agent);
|
|
370
|
+
const mode = sanitizeSearchMode(input.mode, context.defaults.defaultSearchMode);
|
|
371
|
+
const strategy = sanitizeContextStrategy(input.strategy, context.defaults.defaultContextStrategy);
|
|
372
|
+
const limit = input.limit ?? context.defaults.defaultSearchLimit;
|
|
373
|
+
const tokens = input.tokens ?? context.defaults.defaultContextTokens;
|
|
374
|
+
const query = input.query?.trim();
|
|
375
|
+
const recommendations = [
|
|
376
|
+
...(policy.enforceBootstrap && (!policy.autoBootstrapOnRead || !policy.autoBootstrapOnStartup)
|
|
377
|
+
? [
|
|
378
|
+
{
|
|
379
|
+
tool: 'brainlink_policy',
|
|
380
|
+
reason: 'Enable fully automatic bootstrap for plug-and-play agent usage.',
|
|
381
|
+
args: {
|
|
382
|
+
preset: 'fully-auto'
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
: []),
|
|
387
|
+
...(!bootstrapStatus.ready && !policy.autoBootstrapOnRead
|
|
388
|
+
? [
|
|
389
|
+
{
|
|
390
|
+
tool: 'brainlink_bootstrap',
|
|
391
|
+
reason: 'Bootstrap is required before read tools when auto-bootstrap-on-read is disabled.',
|
|
392
|
+
args: {
|
|
393
|
+
vault: context.vault,
|
|
394
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
395
|
+
mode,
|
|
396
|
+
strategy,
|
|
397
|
+
...(query ? { query } : {})
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
]
|
|
401
|
+
: []),
|
|
402
|
+
...(policy.enforceContextFirst && !contextStatus.ready
|
|
403
|
+
? [
|
|
404
|
+
{
|
|
405
|
+
tool: 'brainlink_context',
|
|
406
|
+
reason: 'Context-first policy is enabled. Load context before other read operations.',
|
|
407
|
+
args: {
|
|
408
|
+
vault: context.vault,
|
|
409
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
410
|
+
query: query ?? '<task>',
|
|
411
|
+
mode,
|
|
412
|
+
strategy,
|
|
413
|
+
limit,
|
|
414
|
+
tokens
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
]
|
|
418
|
+
: []),
|
|
419
|
+
...(stats.documentCount === 0
|
|
420
|
+
? [
|
|
421
|
+
{
|
|
422
|
+
tool: 'brainlink_add_note',
|
|
423
|
+
reason: 'Seed the vault with a first durable note so retrieval can return useful context.',
|
|
424
|
+
args: {
|
|
425
|
+
vault: context.vault,
|
|
426
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
427
|
+
title: 'Architecture',
|
|
428
|
+
content: 'Seed durable memory with explicit [[links]] and #tags.'
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
tool: 'brainlink_index',
|
|
433
|
+
reason: 'Rebuild index after writing the first notes.',
|
|
434
|
+
args: {
|
|
435
|
+
vault: context.vault
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
]
|
|
439
|
+
: []),
|
|
440
|
+
{
|
|
441
|
+
tool: 'brainlink_context',
|
|
442
|
+
reason: 'Retrieve grounded memory context before responding.',
|
|
443
|
+
args: {
|
|
444
|
+
vault: context.vault,
|
|
445
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
446
|
+
query: query ?? '<task>',
|
|
447
|
+
mode,
|
|
448
|
+
strategy,
|
|
449
|
+
limit,
|
|
450
|
+
tokens
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
tool: 'brainlink_dedupe',
|
|
455
|
+
reason: 'Detect and resolve duplicate durable notes to keep memory quality high.',
|
|
456
|
+
args: {
|
|
457
|
+
vault: context.vault,
|
|
458
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
459
|
+
limit: 10,
|
|
460
|
+
minScore: 0.92,
|
|
461
|
+
semantic: true
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
tool: 'brainlink_add_note',
|
|
466
|
+
reason: 'Persist durable outcomes after task completion (write responses include connectivity metadata).',
|
|
467
|
+
args: {
|
|
468
|
+
vault: context.vault,
|
|
469
|
+
...(context.agent ? { agent: context.agent } : {}),
|
|
470
|
+
title: 'Task Update',
|
|
471
|
+
content: 'Durable findings connected to [[existing notes]].'
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
];
|
|
475
|
+
return jsonResult({
|
|
476
|
+
vault: context.vault,
|
|
477
|
+
agent: context.agent,
|
|
478
|
+
defaults: {
|
|
479
|
+
mode,
|
|
480
|
+
strategy,
|
|
481
|
+
limit,
|
|
482
|
+
tokens
|
|
483
|
+
},
|
|
484
|
+
contextStrategies: [
|
|
485
|
+
{
|
|
486
|
+
strategy: 'rag',
|
|
487
|
+
useWhen: 'Use for fresh retrieval and context assembly from the current index.'
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
strategy: 'cag',
|
|
491
|
+
useWhen: 'Use for repeated or stable task context so Brainlink can reuse a fresh persisted context pack.'
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
strategy: 'auto',
|
|
495
|
+
useWhen: 'Use when the agent wants Brainlink to choose CAG on fresh pack hits and RAG otherwise.'
|
|
496
|
+
}
|
|
497
|
+
],
|
|
498
|
+
policy,
|
|
499
|
+
bootstrapStatus,
|
|
500
|
+
contextStatus,
|
|
501
|
+
stats,
|
|
502
|
+
recommendations
|
|
503
|
+
});
|
|
504
|
+
};
|