@unson/brainbase-mcp 0.10.14 → 0.10.15
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/dist/judgment-frame.d.ts +26 -0
- package/dist/judgment-frame.js +132 -0
- package/package.json +2 -2
package/dist/judgment-frame.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
1
2
|
/**
|
|
2
3
|
* Judgment frame (brainbase-project ADR-014).
|
|
3
4
|
*
|
|
@@ -99,3 +100,28 @@ export declare function renderJudgmentFrameCatalog(catalog: JudgmentFrameCatalog
|
|
|
99
100
|
* selection is used in at least one option with the role of its kind.
|
|
100
101
|
*/
|
|
101
102
|
export declare function validateJudgmentFrameRecord(value: unknown, catalog: JudgmentFrameCatalog): JudgmentFrameValidation;
|
|
103
|
+
export declare const judgmentFrameTools: Tool[];
|
|
104
|
+
export type JudgmentFrameRecordsPage = {
|
|
105
|
+
readonly status: 'ok';
|
|
106
|
+
readonly records: readonly JudgmentFrameSourceRecord[];
|
|
107
|
+
} | {
|
|
108
|
+
readonly status: 'unavailable' | 'error';
|
|
109
|
+
readonly code: string;
|
|
110
|
+
readonly message: string;
|
|
111
|
+
};
|
|
112
|
+
export interface JudgmentFrameToolDependencies {
|
|
113
|
+
/** Read every record of one kind visible to the caller, at most `limit`. */
|
|
114
|
+
readonly loadRecords: (kind: JudgmentFrameKind, limit: number) => Promise<JudgmentFrameRecordsPage>;
|
|
115
|
+
}
|
|
116
|
+
export type JudgmentFrameToolResult = {
|
|
117
|
+
readonly status: 'ok';
|
|
118
|
+
readonly data: Record<string, unknown>;
|
|
119
|
+
} | {
|
|
120
|
+
readonly status: 'unavailable' | 'error';
|
|
121
|
+
readonly error: {
|
|
122
|
+
code: string;
|
|
123
|
+
message: string;
|
|
124
|
+
details?: unknown;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
export declare function handleJudgmentFrameToolCall(name: string, args: Record<string, unknown>, dependencies: JudgmentFrameToolDependencies): Promise<JudgmentFrameToolResult | null>;
|
package/dist/judgment-frame.js
CHANGED
|
@@ -249,3 +249,135 @@ export function validateJudgmentFrameRecord(value, catalog) {
|
|
|
249
249
|
}
|
|
250
250
|
return { valid: issues.length === 0, issues, escalations };
|
|
251
251
|
}
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// MCP tools. The host injects how Graph records are read; these definitions
|
|
254
|
+
// and the validation stay shared so every host enforces the same contract.
|
|
255
|
+
const FRAME_PAGE_LIMIT = 500;
|
|
256
|
+
const frameUseSchema = {
|
|
257
|
+
type: 'object',
|
|
258
|
+
additionalProperties: false,
|
|
259
|
+
properties: {
|
|
260
|
+
ref: { type: 'string', minLength: 1, maxLength: 1_000 },
|
|
261
|
+
role: { type: 'string', enum: ['constraint', 'criterion', 'prediction'] },
|
|
262
|
+
note: { type: 'string', minLength: 1, maxLength: MAX_NOTE },
|
|
263
|
+
verdict: { type: 'string', enum: ['satisfied', 'violated', 'tension'], description: 'Required when role is constraint.' },
|
|
264
|
+
},
|
|
265
|
+
required: ['ref', 'role', 'note'],
|
|
266
|
+
};
|
|
267
|
+
export const judgmentFrameTools = [{
|
|
268
|
+
name: 'brainbase_judgment_frame_catalog',
|
|
269
|
+
description: 'On a judgment-bearing turn, read the catalog of philosophy, objectives, and world models visible to you. Select only what bears on this decision. Status is a label (draft objectives and adopted_unverified models are still usable as hypotheses); it is not a reason to skip them. Then call brainbase_judgment_frame_record with the returned catalog_digest.',
|
|
270
|
+
inputSchema: { type: 'object', additionalProperties: false, properties: {} },
|
|
271
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
272
|
+
}, {
|
|
273
|
+
name: 'brainbase_judgment_frame_record',
|
|
274
|
+
description: 'Record the judgment frame: which catalog references you selected and why, and for each evaluated option how each selected reference was used. Philosophy is a constraint (give verdict satisfied, violated, or tension), an objective is a criterion, a world model is a prediction. Every selection must be used by at least one option. For a kind with no applicable reference, give the reason in none instead of selecting. Name the option you chose. The tool rejects references outside the catalog; it does not judge semantic quality. If escalations are returned, ask the human before acting on the chosen option.',
|
|
275
|
+
inputSchema: {
|
|
276
|
+
type: 'object',
|
|
277
|
+
additionalProperties: false,
|
|
278
|
+
properties: {
|
|
279
|
+
record_version: { type: 'string', const: JUDGMENT_FRAME_RECORD_VERSION },
|
|
280
|
+
catalog_digest: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
|
|
281
|
+
selections: {
|
|
282
|
+
type: 'array',
|
|
283
|
+
maxItems: MAX_SELECTIONS,
|
|
284
|
+
items: {
|
|
285
|
+
type: 'object',
|
|
286
|
+
additionalProperties: false,
|
|
287
|
+
properties: {
|
|
288
|
+
ref: { type: 'string', minLength: 1, maxLength: 1_000 },
|
|
289
|
+
kind: { type: 'string', enum: [...KINDS] },
|
|
290
|
+
why: { type: 'string', minLength: 1, maxLength: MAX_NOTE },
|
|
291
|
+
},
|
|
292
|
+
required: ['ref', 'kind', 'why'],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
none: {
|
|
296
|
+
type: 'object',
|
|
297
|
+
additionalProperties: false,
|
|
298
|
+
properties: Object.fromEntries(KINDS.map((kind) => [kind, { type: 'string', minLength: 1, maxLength: MAX_NOTE }])),
|
|
299
|
+
},
|
|
300
|
+
options: {
|
|
301
|
+
type: 'array',
|
|
302
|
+
minItems: 1,
|
|
303
|
+
maxItems: MAX_OPTIONS,
|
|
304
|
+
items: {
|
|
305
|
+
type: 'object',
|
|
306
|
+
additionalProperties: false,
|
|
307
|
+
properties: {
|
|
308
|
+
label: { type: 'string', minLength: 1, maxLength: 400 },
|
|
309
|
+
uses: { type: 'array', maxItems: MAX_USES, items: frameUseSchema },
|
|
310
|
+
},
|
|
311
|
+
required: ['label', 'uses'],
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
chosen_option: { type: 'string', minLength: 1, maxLength: 400 },
|
|
315
|
+
},
|
|
316
|
+
required: ['record_version', 'catalog_digest', 'selections', 'options', 'chosen_option'],
|
|
317
|
+
},
|
|
318
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
319
|
+
}];
|
|
320
|
+
const toolError = (status, code, message, details) => ({
|
|
321
|
+
status, error: { code, message, ...(details === undefined ? {} : { details }) },
|
|
322
|
+
});
|
|
323
|
+
async function loadFrameCatalog(dependencies) {
|
|
324
|
+
const records = [];
|
|
325
|
+
for (const kind of KINDS) {
|
|
326
|
+
let page;
|
|
327
|
+
try {
|
|
328
|
+
page = await dependencies.loadRecords(kind, FRAME_PAGE_LIMIT);
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
return toolError('unavailable', 'judgment_frame_catalog_unavailable', `Graph ${kind} records could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
332
|
+
}
|
|
333
|
+
if (page.status !== 'ok')
|
|
334
|
+
return toolError(page.status, page.code, page.message);
|
|
335
|
+
// A full page may be truncated; a silently shorter catalog would hide references.
|
|
336
|
+
if (page.records.length >= FRAME_PAGE_LIMIT) {
|
|
337
|
+
return toolError('error', 'judgment_frame_catalog_truncated', `Graph returned ${page.records.length} ${kind} records; the catalog may be incomplete`);
|
|
338
|
+
}
|
|
339
|
+
records.push(...page.records);
|
|
340
|
+
}
|
|
341
|
+
return buildJudgmentFrameCatalog(records);
|
|
342
|
+
}
|
|
343
|
+
export async function handleJudgmentFrameToolCall(name, args, dependencies) {
|
|
344
|
+
if (name !== 'brainbase_judgment_frame_catalog' && name !== 'brainbase_judgment_frame_record')
|
|
345
|
+
return null;
|
|
346
|
+
if (name === 'brainbase_judgment_frame_catalog' && Object.keys(args).length > 0) {
|
|
347
|
+
return toolError('error', 'judgment_frame_catalog_input_invalid', 'brainbase_judgment_frame_catalog takes no arguments');
|
|
348
|
+
}
|
|
349
|
+
const loaded = await loadFrameCatalog(dependencies);
|
|
350
|
+
if ('status' in loaded)
|
|
351
|
+
return loaded;
|
|
352
|
+
const { catalog, excluded } = loaded;
|
|
353
|
+
if (name === 'brainbase_judgment_frame_catalog') {
|
|
354
|
+
return {
|
|
355
|
+
status: 'ok',
|
|
356
|
+
data: {
|
|
357
|
+
schema_version: 'brainbase-judgment-frame-catalog-v1',
|
|
358
|
+
catalog_digest: catalog.digest,
|
|
359
|
+
counts: Object.fromEntries(KINDS.map((kind) => [kind, catalog.items.filter((item) => item.kind === kind).length])),
|
|
360
|
+
excluded_count: excluded.length,
|
|
361
|
+
catalog: renderJudgmentFrameCatalog(catalog),
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
const validation = validateJudgmentFrameRecord(args, catalog);
|
|
366
|
+
if (!validation.valid) {
|
|
367
|
+
return toolError('error', 'judgment_frame_invalid', 'The judgment frame does not match the catalog contract', {
|
|
368
|
+
issues: validation.issues,
|
|
369
|
+
current_catalog_digest: catalog.digest,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
status: 'ok',
|
|
374
|
+
data: {
|
|
375
|
+
schema_version: 'brainbase-judgment-frame-v1',
|
|
376
|
+
catalog_digest: catalog.digest,
|
|
377
|
+
selections: args.selections.map(({ ref, kind }) => ({ ref, kind })),
|
|
378
|
+
option_count: args.options.length,
|
|
379
|
+
chosen_option: args.chosen_option,
|
|
380
|
+
escalations: validation.escalations,
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.15",
|
|
4
4
|
"description": "Local-first Brainbase judgment OS that lets supported AI agents reuse a user's approved goals, priorities, decisions, and judgment criteria.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -344,5 +344,5 @@
|
|
|
344
344
|
"engines": {
|
|
345
345
|
"node": ">=20"
|
|
346
346
|
},
|
|
347
|
-
"gitHead": "
|
|
347
|
+
"gitHead": "04f1192c75877ca241970ee379c274e37c6693cc"
|
|
348
348
|
}
|