prism-mcp-server 17.1.1 → 18.0.1
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 +69 -4
- package/dist/scholar/webScholar.js +85 -46
- package/dist/server.js +8 -12
- package/dist/tools/ledgerHandlers.js +6 -2
- package/dist/tools/prismInferHandler.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,12 +28,12 @@ Ask "what did I decide about the auth flow last month?" and get the answer with
|
|
|
28
28
|
### 🧬 Cognitive routing
|
|
29
29
|
Different memory types live in different stores: episodic (what happened), semantic (what's true), procedural (how to do X). The router picks where to store and where to retrieve.
|
|
30
30
|
|
|
31
|
-
### 🔄 Proactive session drift detection *(new in v15)*
|
|
31
|
+
### 🔄 Proactive session drift detection *(new in v15, HRR-powered in v17)*
|
|
32
32
|
Your AI agent can now detect when it has drifted from your original goals — mid-session, automatically — and self-correct before you notice the problem.
|
|
33
33
|
|
|
34
34
|
Three direct Prism calls:
|
|
35
35
|
1. **`session_save_ledger`** — snapshot current state
|
|
36
|
-
2. **`
|
|
36
|
+
2. **`session_detect_drift`** — HRR-powered semantic comparison of current work vs original goals, returns `on_track / minor_drift / major_drift` with domain-specific signals (BCBA/Coding/AAC)
|
|
37
37
|
3. **`session_compact_ledger`** — if drifted, compress and reload only what matters
|
|
38
38
|
|
|
39
39
|
When major drift is detected, the alert routes to the **Synalux portal** so it's visible across sessions and devices — not just in the current conversation.
|
|
@@ -42,6 +42,19 @@ When major drift is detected, the alert routes to the **Synalux portal** so it's
|
|
|
42
42
|
|
|
43
43
|
No scripts. No cron. No hooks. Three tool calls, Prism handles the rest.
|
|
44
44
|
|
|
45
|
+
### 🛡 PHI Guard *(v17+)*
|
|
46
|
+
Automatic Protected Health Information detection and redaction in the memory pipeline. Every `session_save_ledger` and `session_save_handoff` call passes through the PHI guard before storage.
|
|
47
|
+
|
|
48
|
+
**What it catches:** DOBs, SSNs, MRNs, phone numbers, email addresses, and other structured HIPAA identifiers (18 categories). Redaction is deterministic (regex + pattern matching, no LLM) — zero false negatives on format-constrained identifiers (SSN, MRN, phone, email). Names require NER for reliable detection and are best-effort.
|
|
49
|
+
|
|
50
|
+
**Fail-closed:** PHI detection errors log to stderr (never suppressed) and block the save. Metric: `phi_guard.detected` count per category is always emitted for audit compliance.
|
|
51
|
+
|
|
52
|
+
### ⚡ Prompt-based skill routing *(v17+)*
|
|
53
|
+
114 agent skills auto-load based on prompt keywords. No manual skill selection needed — the MCP server scans the user's prompt and injects the relevant skill instructions into the session context before the AI responds.
|
|
54
|
+
|
|
55
|
+
### 💰 Tier enforcement *(v17.1+)*
|
|
56
|
+
`prism_infer` now enforces subscription-tier gates: model ceiling, max tokens, daily limits, and cloud fallback are all gated by your plan. Free users get local-only inference up to 4b; paid tiers unlock higher models, more tokens, and cloud fallback. Flat-rate seat caps via `max_seats` per plan.
|
|
57
|
+
|
|
45
58
|
### 🛡 Local-first — security + speed
|
|
46
59
|
Free tier runs entirely on your machine — SQLite, local embedding model, no API keys, no cloud. Paid tier adds cloud sync via Synalux portal.
|
|
47
60
|
|
|
@@ -155,7 +168,58 @@ Categories: abstention, adversarial traps, cascade, disambiguation, edge cases,
|
|
|
155
168
|
**What it does NOT mean**: these scores measure routing precision on a 17-tool taxonomy, not general intelligence. Claude outperforms on everything outside this task. The value is **offline reliability at zero cost**, not replacing Claude. Code and clinical knowledge come from RAG via `knowledge_search`.
|
|
156
169
|
|
|
157
170
|
### 🔍 L3 Grounding Verifier
|
|
158
|
-
|
|
171
|
+
|
|
172
|
+
Fail-closed fact-checking layer. When `prism_infer` receives an `evidence` payload, a separate verifier model (default: `prism-coder:4b`) checks every factual claim in the draft against the evidence before serving it. This is the third layer (L3) of the cascade — after tool routing (L1) and confidence gating (L2).
|
|
173
|
+
|
|
174
|
+
**Three-tier pre-check:**
|
|
175
|
+
|
|
176
|
+
| Tier | Condition | Action |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| **0 — Conversational** | Draft has no numbers, dates, names, codes, or $ amounts | Serve without verification |
|
|
179
|
+
| **0a — No evidence** | Assertive draft + zero evidence snippets | Refuse (fail-closed) |
|
|
180
|
+
| **2 — NLI** | Assertive draft + evidence provided | Verify each claim against evidence |
|
|
181
|
+
|
|
182
|
+
**Per-claim verdicts:**
|
|
183
|
+
- `ENTAILED` — claim matches evidence (including arithmetic identity: "3" ≈ "three")
|
|
184
|
+
- `CONTRADICTED` — evidence states a different value for the same fact → **refuse**
|
|
185
|
+
- `NEUTRAL` — claim not covered by evidence → **refuse** (fail-closed default)
|
|
186
|
+
|
|
187
|
+
**Fail-closed guarantees:** HTTP errors, malformed JSON, timeouts → all treated as refusal. The caller gets the specific claim that failed and can retry with more evidence or fall back to cloud.
|
|
188
|
+
|
|
189
|
+
**Usage with `prism_infer`:**
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"prompt": "What was the patient's last A1C?",
|
|
193
|
+
"evidence": [
|
|
194
|
+
{ "source": "lab_2026-05-01", "content": "HbA1c: 6.8% (ref <7.0)" }
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Structured output:**
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"output": "The patient's last A1C was 6.8%.",
|
|
203
|
+
"verification": {
|
|
204
|
+
"action": "served",
|
|
205
|
+
"claims": [{ "text": "A1C was 6.8%", "verdict": "ENTAILED" }],
|
|
206
|
+
"verifierChain": [{ "model": "prism-coder:4b", "verdict": "ENTAILED", "latencyMs": 340 }]
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
When a claim is contradicted or unsupported:
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"output": "⚠ Verification failed: claim 'A1C was 7.2%' is CONTRADICTED by evidence.",
|
|
215
|
+
"verification": {
|
|
216
|
+
"action": "refused_fabricated",
|
|
217
|
+
"refusalClaim": "A1C was 7.2%"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The verifier model (`prism-coder:4b`) is intentionally different from the inference model — satisfying the independent-reviewer principle. Requires a paid plan (see [Plans](#plans)). Set `verify: false` to explicitly skip verification even when evidence is provided.
|
|
159
223
|
|
|
160
224
|
### 🧠 HRR Semantic Drift Detection (v17.0)
|
|
161
225
|
Detects when long AI agent sessions drift from their original goal — using Holographic Reduced Representations for temporal trajectory encoding and anomaly detection.
|
|
@@ -366,6 +430,7 @@ Paid Synalux subscribers get a built-in analytics dashboard at `/app/memory-anal
|
|
|
366
430
|
| `knowledge_search` | Semantic + keyword search over all memories |
|
|
367
431
|
| `query_memory_natural` | Natural-language Q&A over your Mind Palace |
|
|
368
432
|
| `extract_entities` | Pull people / projects / decisions from text |
|
|
433
|
+
| `session_detect_drift` | HRR-powered semantic drift detection (BCBA/Coding/AAC) |
|
|
369
434
|
| `session_synthesize_edges` | Auto-link related memories into a graph |
|
|
370
435
|
|
|
371
436
|
(35+ tools total — full TypeScript signatures in `src/tools/`. Architecture overview in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).)
|
|
@@ -675,7 +740,7 @@ prism register-models # Alias dcostenco/prism-coder:* → prism-coder:*
|
|
|
675
740
|
## Testing
|
|
676
741
|
|
|
677
742
|
```bash
|
|
678
|
-
npm test # 2,
|
|
743
|
+
npm test # 2,676 test cases across 89 files (vitest)
|
|
679
744
|
npm test -- --coverage # coverage report
|
|
680
745
|
python3 tests/benchmarks/prism-routing-100/benchmark.py --models 1b7 14b 32b
|
|
681
746
|
```
|
|
@@ -3,6 +3,9 @@ import { getStorage } from "../storage/index.js";
|
|
|
3
3
|
import { debugLog } from "../utils/logger.js";
|
|
4
4
|
import { getLLMProvider } from "../utils/llm/factory.js";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { homedir } from "node:os";
|
|
6
9
|
import { performWebSearchRaw } from "../utils/braveApi.js";
|
|
7
10
|
import { performGoogleSearch } from "../utils/googleSearchApi.js";
|
|
8
11
|
import { getTracer } from "../utils/telemetry.js";
|
|
@@ -58,9 +61,20 @@ async function selectTopic() {
|
|
|
58
61
|
const topics = PRISM_SCHOLAR_TOPICS;
|
|
59
62
|
if (!topics || topics.length === 0)
|
|
60
63
|
return "";
|
|
61
|
-
|
|
64
|
+
// Filter out topics already researched in the last 24h
|
|
65
|
+
const uncovered = [];
|
|
66
|
+
for (const t of topics) {
|
|
67
|
+
if (!(await hasRecentResearch(t, SCHOLAR_PROJECT, PRISM_USER_ID, 24))) {
|
|
68
|
+
uncovered.push(t);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (uncovered.length === 0) {
|
|
72
|
+
debugLog("[WebScholar] All topics researched in last 24h — sleeping until tomorrow");
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
const pick = uncovered[Math.floor(Math.random() * uncovered.length)];
|
|
62
76
|
if (!PRISM_ENABLE_HIVEMIND)
|
|
63
|
-
return
|
|
77
|
+
return pick;
|
|
64
78
|
try {
|
|
65
79
|
const storage = await getStorage();
|
|
66
80
|
const allAgents = await storage.getAllAgents(PRISM_USER_ID);
|
|
@@ -68,22 +82,79 @@ async function selectTopic() {
|
|
|
68
82
|
.filter(a => a.role !== SCHOLAR_ROLE && a.status === "active" && a.current_task)
|
|
69
83
|
.map(a => a.current_task.toLowerCase());
|
|
70
84
|
if (activeTasks.length === 0)
|
|
71
|
-
return
|
|
85
|
+
return pick;
|
|
72
86
|
const taskText = activeTasks.join(" ");
|
|
73
|
-
const matched =
|
|
87
|
+
const matched = uncovered.filter(t => taskText.includes(t.toLowerCase()));
|
|
74
88
|
if (matched.length > 0)
|
|
75
89
|
return matched[Math.floor(Math.random() * matched.length)];
|
|
76
90
|
}
|
|
77
91
|
catch { }
|
|
78
|
-
return
|
|
92
|
+
return pick;
|
|
93
|
+
}
|
|
94
|
+
// ─── Dedup + Cross-Process Lock ─────────────────────────────
|
|
95
|
+
async function hasRecentResearch(topic, project, userId, windowHours = 24) {
|
|
96
|
+
try {
|
|
97
|
+
const storage = await getStorage();
|
|
98
|
+
const entries = await storage.getLedgerEntries({
|
|
99
|
+
project,
|
|
100
|
+
user_id: userId,
|
|
101
|
+
event_type: "learning",
|
|
102
|
+
limit: 20,
|
|
103
|
+
});
|
|
104
|
+
const cutoff = new Date(Date.now() - windowHours * 3600_000).toISOString();
|
|
105
|
+
return entries.some(e => (e.created_at ?? "") > cutoff && (e.summary ?? "").startsWith(`Research: ${topic}\n`));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const LOCK_PATH = join(homedir(), ".prism-mcp", "scholar.lock");
|
|
112
|
+
const LOCK_STALE_MS = 10 * 60_000;
|
|
113
|
+
function acquireFileLock() {
|
|
114
|
+
try {
|
|
115
|
+
const lockDir = dirname(LOCK_PATH);
|
|
116
|
+
if (!existsSync(lockDir))
|
|
117
|
+
mkdirSync(lockDir, { recursive: true });
|
|
118
|
+
if (existsSync(LOCK_PATH)) {
|
|
119
|
+
const stat = statSync(LOCK_PATH);
|
|
120
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
121
|
+
if (ageMs < LOCK_STALE_MS)
|
|
122
|
+
return false;
|
|
123
|
+
unlinkSync(LOCK_PATH);
|
|
124
|
+
}
|
|
125
|
+
// wx = exclusive create — throws EEXIST if another process won the race
|
|
126
|
+
writeFileSync(LOCK_PATH, `${process.pid}\n${new Date().toISOString()}`, { flag: "wx" });
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (err?.code === "EEXIST")
|
|
131
|
+
return false;
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function releaseFileLock() {
|
|
136
|
+
try {
|
|
137
|
+
if (!existsSync(LOCK_PATH))
|
|
138
|
+
return;
|
|
139
|
+
const content = readFileSync(LOCK_PATH, "utf-8");
|
|
140
|
+
const lockPid = parseInt(content.split("\n")[0], 10);
|
|
141
|
+
if (lockPid === process.pid) {
|
|
142
|
+
unlinkSync(LOCK_PATH);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch { }
|
|
79
146
|
}
|
|
80
147
|
// ─── Core Pipeline ───────────────────────────────────────────
|
|
81
148
|
let isRunning = false;
|
|
82
149
|
export async function runWebScholar(overrideTopic, overrideProject) {
|
|
83
150
|
if (isRunning) {
|
|
84
|
-
debugLog("[WebScholar] Skipped: already running");
|
|
151
|
+
debugLog("[WebScholar] Skipped: already running in this process");
|
|
85
152
|
return "Skipped: already running";
|
|
86
153
|
}
|
|
154
|
+
if (!acquireFileLock()) {
|
|
155
|
+
debugLog("[WebScholar] Skipped: another instance holds the lock");
|
|
156
|
+
return "Skipped: another instance is running";
|
|
157
|
+
}
|
|
87
158
|
isRunning = true;
|
|
88
159
|
const tracer = getTracer();
|
|
89
160
|
const span = tracer.startSpan("background.web_scholar");
|
|
@@ -97,6 +168,11 @@ export async function runWebScholar(overrideTopic, overrideProject) {
|
|
|
97
168
|
span.setAttribute("scholar.skipped_reason", "no_topics");
|
|
98
169
|
return "No topics configured";
|
|
99
170
|
}
|
|
171
|
+
if (await hasRecentResearch(topic, project, PRISM_USER_ID)) {
|
|
172
|
+
debugLog(`[WebScholar] Skipped: "${topic}" already researched in last 24h`);
|
|
173
|
+
span.setAttribute("scholar.skipped_reason", "dedup");
|
|
174
|
+
return `Skipped: "${topic}" already researched recently`;
|
|
175
|
+
}
|
|
100
176
|
debugLog(`[WebScholar] 🧠 Starting research on: "${topic}"`);
|
|
101
177
|
await hivemindRegister(topic);
|
|
102
178
|
await hivemindHeartbeat(`Searching for: ${topic}`);
|
|
@@ -146,11 +222,11 @@ export async function runWebScholar(overrideTopic, overrideProject) {
|
|
|
146
222
|
await storage.saveLedger({
|
|
147
223
|
id: randomUUID(),
|
|
148
224
|
project: project,
|
|
149
|
-
conversation_id:
|
|
225
|
+
conversation_id: `scholar-${randomUUID().slice(0, 8)}`,
|
|
150
226
|
user_id: PRISM_USER_ID,
|
|
151
227
|
role: "scholar",
|
|
152
228
|
summary: `Research: ${topic}\n\n${summary}`,
|
|
153
|
-
keywords: [topic, "research"],
|
|
229
|
+
keywords: [topic, "research", "auto-scholar"],
|
|
154
230
|
event_type: "learning",
|
|
155
231
|
importance: 7,
|
|
156
232
|
created_at: new Date().toISOString()
|
|
@@ -164,6 +240,7 @@ export async function runWebScholar(overrideTopic, overrideProject) {
|
|
|
164
240
|
}
|
|
165
241
|
finally {
|
|
166
242
|
await hivemindIdle();
|
|
243
|
+
releaseFileLock();
|
|
167
244
|
isRunning = false;
|
|
168
245
|
span.end();
|
|
169
246
|
}
|
|
@@ -215,41 +292,3 @@ async function searchSemanticScholar(query, count) {
|
|
|
215
292
|
return [];
|
|
216
293
|
}
|
|
217
294
|
}
|
|
218
|
-
let watcherInterval = null;
|
|
219
|
-
export async function startScholarWatcher() {
|
|
220
|
-
if (watcherInterval)
|
|
221
|
-
return;
|
|
222
|
-
debugLog("[WebScholar] Starting bridge watcher (polling for research_tasks)");
|
|
223
|
-
watcherInterval = setInterval(async () => {
|
|
224
|
-
try {
|
|
225
|
-
const storage = await getStorage();
|
|
226
|
-
const pending = await storage.listPendingResearchTasks();
|
|
227
|
-
for (const task of pending) {
|
|
228
|
-
debugLog(`[WebScholar] Bridge pickup: Task ${task.id} (topic: ${task.topic})`);
|
|
229
|
-
await storage.updateResearchTask(task.id, { status: 'RUNNING' });
|
|
230
|
-
try {
|
|
231
|
-
const result = await runWebScholar(task.topic, task.project);
|
|
232
|
-
await storage.updateResearchTask(task.id, {
|
|
233
|
-
status: 'COMPLETED',
|
|
234
|
-
result_summary: result.slice(0, 1000) // snippet
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
catch (err) {
|
|
238
|
-
await storage.updateResearchTask(task.id, {
|
|
239
|
-
status: 'FAILED',
|
|
240
|
-
error_message: err.message || String(err)
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
debugLog(`[WebScholar] Bridge poll failed: ${err}`);
|
|
247
|
-
}
|
|
248
|
-
}, 10_000); // Poll every 10 seconds
|
|
249
|
-
}
|
|
250
|
-
export function stopScholarWatcher() {
|
|
251
|
-
if (watcherInterval) {
|
|
252
|
-
clearInterval(watcherInterval);
|
|
253
|
-
watcherInterval = null;
|
|
254
|
-
}
|
|
255
|
-
}
|
package/dist/server.js
CHANGED
|
@@ -59,9 +59,9 @@ ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequ
|
|
|
59
59
|
// Claude Desktop that the attached resource has changed.
|
|
60
60
|
// Without this, the paperclipped context becomes stale.
|
|
61
61
|
SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
62
|
-
import { SERVER_CONFIG, SESSION_MEMORY_ENABLED, PRISM_USER_ID, PRISM_ENABLE_HIVEMIND, WATCHDOG_INTERVAL_MS, WATCHDOG_STALE_MIN, WATCHDOG_FROZEN_MIN, WATCHDOG_OFFLINE_MIN, WATCHDOG_LOOP_THRESHOLD, PRISM_SCHEDULER_ENABLED, PRISM_SCHEDULER_INTERVAL_MS,
|
|
62
|
+
import { SERVER_CONFIG, SESSION_MEMORY_ENABLED, PRISM_USER_ID, PRISM_ENABLE_HIVEMIND, WATCHDOG_INTERVAL_MS, WATCHDOG_STALE_MIN, WATCHDOG_FROZEN_MIN, WATCHDOG_OFFLINE_MIN, WATCHDOG_LOOP_THRESHOLD, PRISM_SCHEDULER_ENABLED, PRISM_SCHEDULER_INTERVAL_MS, PRISM_HDC_ENABLED, PRISM_TASK_ROUTER_ENABLED_ENV, PRISM_DARK_FACTORY_ENABLED, } from "./config.js";
|
|
63
63
|
import { startWatchdog, drainAlerts } from "./hivemindWatchdog.js";
|
|
64
|
-
import { startScheduler
|
|
64
|
+
import { startScheduler } from "./backgroundScheduler.js";
|
|
65
65
|
import { startDarkFactoryRunner } from "./darkfactory/runner.js";
|
|
66
66
|
import { getSyncBus } from "./sync/factory.js";
|
|
67
67
|
import { startDashboardServer } from "./dashboard/server.js";
|
|
@@ -1353,16 +1353,12 @@ export async function startServer() {
|
|
|
1353
1353
|
console.error(`[Scheduler] Startup failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
1354
1354
|
});
|
|
1355
1355
|
}
|
|
1356
|
-
// ─── v5.4: Autonomous Web Scholar
|
|
1357
|
-
//
|
|
1358
|
-
//
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
}).catch(err => {
|
|
1363
|
-
console.error(`[WebScholar] Startup failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1356
|
+
// ─── v5.4: Autonomous Web Scholar — REMOVED (v18.0.0) ────
|
|
1357
|
+
// Auto-scheduler removed. Scholar now runs server-side via
|
|
1358
|
+
// Vercel cron (/api/v1/cron/scholar) every 6h. The client-side
|
|
1359
|
+
// scheduler caused 5,293 garbage entries when multiple MCP
|
|
1360
|
+
// instances ran in parallel. Manual trigger via MCP tool still
|
|
1361
|
+
// works for local/free-tier users. See: webScholar.ts
|
|
1366
1362
|
// ─── v7.3: Dark Factory Background Runner ────────────────
|
|
1367
1363
|
// Autonomous pipeline orchestration engine. Picks up RUNNING
|
|
1368
1364
|
// pipelines and advances them through PLAN → EXECUTE → VERIFY
|
|
@@ -801,11 +801,15 @@ export async function sessionLoadContextHandler(args) {
|
|
|
801
801
|
const eff = computeEffectiveImportance(s.importance, s.last_accessed_at, s.created_at, Boolean(s.is_rollup));
|
|
802
802
|
impStr = ` [Imp: ${eff}]`;
|
|
803
803
|
}
|
|
804
|
-
|
|
804
|
+
const dateStr = (s.session_date || s.created_at || s.date || "unknown").split("T")[0];
|
|
805
|
+
return ` [${dateStr}]${impStr} ${s.summary}`;
|
|
805
806
|
}).join("\n") + `\n`;
|
|
806
807
|
}
|
|
807
808
|
if (d.session_history?.length) {
|
|
808
|
-
formattedContext += `\n📂 Session History (${d.session_history.length} entries):\n` + d.session_history.map((s) =>
|
|
809
|
+
formattedContext += `\n📂 Session History (${d.session_history.length} entries):\n` + d.session_history.map((s) => {
|
|
810
|
+
const dateStr = (s.session_date || s.created_at || s.date || "unknown").split("T")[0];
|
|
811
|
+
return ` [${dateStr}] ${s.summary}`;
|
|
812
|
+
}).join("\n") + `\n`;
|
|
809
813
|
}
|
|
810
814
|
if (d.recent_validations?.length) {
|
|
811
815
|
formattedContext += `\n🔬 Recent Validations:\n` + d.recent_validations.map((v) => {
|
|
@@ -91,12 +91,12 @@ export const PRISM_INFER_TOOL = {
|
|
|
91
91
|
type: "boolean",
|
|
92
92
|
description: "Enable the L3 grounding verifier. Default: true when `evidence` is provided, " +
|
|
93
93
|
"false otherwise. When enabled, the model's draft is checked by a different model " +
|
|
94
|
-
"(prism-coder:
|
|
94
|
+
"(prism-coder:4b by default) against the supplied `evidence`. Drafts with " +
|
|
95
95
|
"NEUTRAL or CONTRADICTED claims are refused.",
|
|
96
96
|
},
|
|
97
97
|
verifier_model: {
|
|
98
98
|
type: "string",
|
|
99
|
-
description: "Override the verifier model. Default: prism-coder:
|
|
99
|
+
description: "Override the verifier model. Default: prism-coder:4b.",
|
|
100
100
|
},
|
|
101
101
|
verifier_timeout_ms: {
|
|
102
102
|
type: "number",
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.1",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-coder",
|
|
5
|
-
"description": "Prism Coder — Cognitive memory + tool-calling intelligence for AI agents. Mind Palace persistent memory (BFCL Gold Certified, 100% Tool-Call Accuracy, 114 Agent Skills, Zero-Search HDC/HRR retrieval, HRR Semantic Drift Detection across BCBA/Coding/AAC domains, HIPAA-hardened local-first storage, SLERP-optimized GRPO alignment) plus the prism-coder 1.7B–32B open-weights LLM fleet.",
|
|
5
|
+
"description": "Prism Coder — Cognitive memory + tool-calling intelligence for AI agents. Mind Palace persistent memory (BFCL Gold Certified, 100% Tool-Call Accuracy, 114 Agent Skills, PHI Guard, Tier Enforcement, Prompt-Based Skill Routing, Zero-Search HDC/HRR retrieval, HRR Semantic Drift Detection across BCBA/Coding/AAC domains, HIPAA-hardened local-first storage, SLERP-optimized GRPO alignment) plus the prism-coder 1.7B–32B open-weights LLM fleet.",
|
|
6
6
|
"module": "index.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/server.js",
|