prism-mcp-server 19.2.8 → 19.3.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.
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Layer 1 semantic pre-classifier for prism_infer.
3
+ * ─────────────────────────────────────────────────────────────
4
+ * Calls dcostenco/prism-coder:4b via Ollama to classify whether
5
+ * a prompt is OBVIOUS_RESERVED, OBVIOUS_NOT_RESERVED, or UNCERTAIN.
6
+ *
7
+ * Fail-closed contract:
8
+ * OBVIOUS_NOT_RESERVED → the ONLY verdict that permits local routing
9
+ * OBVIOUS_RESERVED → escalate to cloud
10
+ * UNCERTAIN → escalate to cloud (conservative)
11
+ * ERROR → escalate to cloud (never fail-open)
12
+ *
13
+ * The prompt below is VERBATIM from §E of prism-infer-boundaries/SKILL.md.
14
+ * It is duplicated here (not imported) because prism is a thin client with no
15
+ * access to the skills tree at runtime. A drift test asserts byte-for-byte match.
16
+ *
17
+ * Must not run when mode="route" and max_tokens<=16 — that IS a Layer 1 call.
18
+ */
19
+ // VERBATIM — §E prism-infer-boundaries/SKILL.md. Do not edit without re-running eval-layer1.mjs.
20
+ export const LAYER1_PROMPT = `Classify this request with exactly one word: OBVIOUS_RESERVED, OBVIOUS_NOT_RESERVED, or UNCERTAIN.
21
+
22
+ OBVIOUS_RESERVED — clearly involves:
23
+ - Behavioral crisis: de-escalation, meltdown management, rage episode, violent behavior response
24
+ - Physical restraint, holds, containment, physical management of clients
25
+ - Self-harm: client bites/hits/scratches/bangs self, draws blood, injures self
26
+ - Suicide, homicide, harm to self or others, safety planning
27
+ - Client physical elopement incidents — client ran away, bolted, or escaped (with prior documented incidents)
28
+ - Writing auth/login/JWT/token/session validation code
29
+ - Determining if code bypasses auth or allows unauthenticated access
30
+ - Assessing whether code actually exposes PHI or constitutes a HIPAA violation
31
+ - Whether to push, ship, deploy, or block a production release
32
+ - Diagnosis code assignment
33
+
34
+ OBVIOUS_NOT_RESERVED — general coding, code review, analysis, documentation, test generation, data processing.
35
+
36
+ UNCERTAIN — if the request touches reserved vocabulary but the task is non-security, non-clinical operational work (e.g., deleting or renaming a file, adding a non-auth data field to a form, reviewing existing code for dead exports or hook order) rather than writing clinical safety protocols, implementing auth or security code, making push or deploy decisions, or determining compliance.
37
+
38
+ Request: "{prompt}"
39
+
40
+ Answer (one word):`;
41
+ const VALID = new Set([
42
+ "OBVIOUS_RESERVED",
43
+ "OBVIOUS_NOT_RESERVED",
44
+ "UNCERTAIN",
45
+ ]);
46
+ /**
47
+ * Parse the model's raw text into a verdict. Extracts the first token of
48
+ * letters/underscores (ignoring leading punctuation, quotes, whitespace).
49
+ * Anything not in the valid set → ERROR, which the caller escalates.
50
+ * Note: OBVIOUS_NOT_RESERVED contains "RESERVED" as a substring — whole-token
51
+ * matching via Set prevents the substring trap from inverting the gate.
52
+ */
53
+ export function parseLayer1(raw) {
54
+ if (!raw)
55
+ return "ERROR";
56
+ const m = raw.trim().toUpperCase().match(/[A-Z_]+/);
57
+ if (!m)
58
+ return "ERROR";
59
+ const token = m[0];
60
+ return VALID.has(token) ? token : "ERROR";
61
+ }
62
+ // p95 measured 484–511ms on warm 4b; 1500ms is a generous ceiling that still
63
+ // fails closed on model stall without blocking the handler for too long.
64
+ const LAYER1_TIMEOUT_MS = 1_500;
65
+ /**
66
+ * Run the Layer 1 classifier. Returns a verdict; never throws.
67
+ * On ANY failure path returns "ERROR" so the caller escalates to cloud.
68
+ *
69
+ * @param userPrompt the end-user prompt being classified (NOT the LAYER1_PROMPT)
70
+ * @param ollamaUrl Ollama base URL
71
+ * @param model classifier model tag (caller-resolved via resolveOllamaName)
72
+ * @param fetchImpl injected for tests; defaults to global fetch
73
+ */
74
+ export async function callLayer1(userPrompt, ollamaUrl, model, fetchImpl = fetch) {
75
+ if (!userPrompt || !userPrompt.trim())
76
+ return "ERROR";
77
+ let res;
78
+ try {
79
+ res = await fetchImpl(`${ollamaUrl}/api/chat`, {
80
+ method: "POST",
81
+ headers: { "Content-Type": "application/json" },
82
+ body: JSON.stringify({
83
+ model,
84
+ messages: [
85
+ { role: "user", content: LAYER1_PROMPT.replace("{prompt}", userPrompt) },
86
+ ],
87
+ stream: false,
88
+ think: false,
89
+ options: { num_predict: 16, temperature: 0 },
90
+ }),
91
+ signal: AbortSignal.timeout(LAYER1_TIMEOUT_MS),
92
+ });
93
+ }
94
+ catch {
95
+ return "ERROR";
96
+ }
97
+ if (!res.ok)
98
+ return "ERROR";
99
+ let data;
100
+ try {
101
+ data = await res.json();
102
+ }
103
+ catch {
104
+ return "ERROR";
105
+ }
106
+ if (data?.error)
107
+ return "ERROR";
108
+ const text = data?.message?.content;
109
+ return parseLayer1(text);
110
+ }
@@ -2,8 +2,7 @@
2
2
  * Prism Project Resolver — Local Storage Variant
3
3
  * ================================================
4
4
  *
5
- * Same contract as the synalux portal resolver
6
- * (synalux-private/portal/src/lib/prism-project-resolver.ts) but
5
+ * Same contract as the Synalux portal resolver but
7
6
  * sources the project registry from local prism-config.db settings
8
7
  * (`repo_path:<project>` keys) instead of the `prism_projects`
9
8
  * Supabase table.
@@ -13,8 +12,7 @@
13
12
  * portal resolver becomes authoritative and this one becomes a noop
14
13
  * for the same write.
15
14
  *
16
- * Background: see synalux-private project ledger entry
17
- * 2026-04-30-thin-client-architecture-directive — the prism-aac
15
+ * Background: thin-client architecture directive 2026-04-30 the prism-aac
18
16
  * Azure-leak memory-loss bug was caused by the absence of this
19
17
  * validation.
20
18
  */
@@ -7,19 +7,29 @@
7
7
  *
8
8
  * Returns: { pass: boolean, reason?: string }
9
9
  */
10
+ /**
11
+ * Signal 5 — Tool-call bleed: pipe-delimited format leaking into non-tool turns.
12
+ * Matches <|tool_call|> and <|tool_call_end|> only — NOT angle-bracket <tool_call> variants
13
+ * (those are normalized by normalizeToolCallFormat, not gated as failures).
14
+ */
15
+ export const TOOL_CALL_BLEED_RE = /<\|tool_call\|>|<\|tool_call_end\|>/;
10
16
  /**
11
17
  * Check if a model response passes the quality gate.
12
18
  * @param stripped Response AFTER think-stripping (use stripThink first)
13
19
  * @param thinkOnly True if the response was only <think> blocks with no answer
14
20
  * @param finishReason Ollama's finish_reason if available (e.g. "length" = truncated)
21
+ * @param mode Inference mode — "route" uses length===0 floor; "code"/"chat" keep <5
15
22
  */
16
- export function passesQualityGate(stripped, thinkOnly, finishReason) {
23
+ export function passesQualityGate(stripped, thinkOnly, finishReason, mode) {
17
24
  // Signal 1: Think-only — model reasoned but produced no answer (check before empty)
18
25
  if (thinkOnly) {
19
26
  return { pass: false, reason: "think_only" };
20
27
  }
21
- // Signal 2: Empty or near-empty after stripping
22
- if (stripped.trim().length < 5) {
28
+ // Signal 2: Mode-aware empty floor.
29
+ // Route legitimately returns 1–4 char labels ("P1", "YES", "CO4", "FIXED").
30
+ // Use length===0 for route; keep <5 for code/chat where single-word answers are invalid.
31
+ const emptyFloor = mode === "route" ? 0 : 4;
32
+ if (stripped.trim().length <= emptyFloor) {
23
33
  return { pass: false, reason: "empty_response" };
24
34
  }
25
35
  // Signal 3: Hard truncation — Ollama reports finish_reason="length"
@@ -27,6 +37,12 @@ export function passesQualityGate(stripped, thinkOnly, finishReason) {
27
37
  if (finishReason === "length") {
28
38
  return { pass: false, reason: "hard_truncation" };
29
39
  }
40
+ // Signal 5: Tool-call bleed — fine-tuned 4b emits <|tool_call|> format in non-tool turns.
41
+ // Pipe-delimited format only; angle-bracket variants are handled by normalizeToolCallFormat.
42
+ // False-positive guard: requires the literal pipe tokens, not the words "tool call".
43
+ if (TOOL_CALL_BLEED_RE.test(stripped)) {
44
+ return { pass: false, reason: "tool_call_bleed" };
45
+ }
30
46
  // Signal 4: Exact-loop detection (two passes).
31
47
  //
32
48
  // Pass A (prose-only, threshold ≥3): strip structural markdown that
@@ -56,6 +56,26 @@ const MEDICAL_INPUT_RE = [
56
56
  /(?:how\s+much|what\s+dose)\s+.*(?:should\s+I|do\s+I|can\s+I)\s+(?:inject|take|give)/i,
57
57
  /(?:dose|dosage)\s+(?:should\s+I|do\s+I|can\s+I)\s+(?:inject|take|give)/i,
58
58
  ];
59
+ // ── Output: BCBA reserved category — physical management / restraint / seclusion ─
60
+ //
61
+ // These patterns are a BACKSTOP (Option 1) — high-precision/low-recall.
62
+ // The structural safety mechanism is Option 4: consequence/crisis sections of BIPs
63
+ // never generate locally. These regexes catch the obvious cases if section-routing fails.
64
+ // They do NOT substitute for the structural gate; euphemistic phrasings ("guide the client
65
+ // firmly to the floor") pass through, so the structural gate is the primary control.
66
+ const BCBA_OUTPUT_RE = [
67
+ // Explicit restraint technique names
68
+ /\b(?:prone|supine|basket|therapeutic|manual)\s+(?:hold|restraint)\b/i,
69
+ /\btwo[-\s]?person\s+(?:hold|restraint)\b/i,
70
+ /\bphysical\s+(?:intervention|management|restraint)\b/i,
71
+ // Seclusion
72
+ /\bseclusion\s+(?:room|protocol|procedure|space)\b/i,
73
+ /\bplace\s+(?:the\s+)?client\s+in\s+(?:a\s+)?(?:seclusion|hold|timeout\s+room)\b/i,
74
+ // Staff-instruction framing (high-precision: requires staff + restraint verb + client)
75
+ /\bstaff\s+(?:should|must|will)\s+(?:physically\s+)?(?:hold|restrain|manage)\s+(?:the\s+)?client\b/i,
76
+ /\bcaregiver\s+(?:should|must|will)\s+(?:physically\s+)?(?:hold|restrain|manage)\s+(?:the\s+)?client\b/i,
77
+ ];
78
+ export const BCBA_RESPONSE = "This output contains physical management content (restraint, hold, or seclusion procedure). Consequence strategy and crisis/safety sections require cloud review — they cannot generate locally per BCBA clinical standards. Escalating to cloud.";
59
79
  // ── Output: model providing dangerous instructions ───────────────────────────
60
80
  const CRISIS_OUTPUT_RE = [
61
81
  /\bhow many pills\s+to\b/i,
@@ -96,6 +116,8 @@ export function checkInputSafety(text) {
96
116
  }
97
117
  export function checkOutputSafety(response) {
98
118
  const r = normalize(response);
119
+ if (BCBA_OUTPUT_RE.some(re => re.test(r)))
120
+ return BCBA_RESPONSE;
99
121
  if (CRISIS_OUTPUT_RE.some(re => re.test(r)))
100
122
  return CRISIS_RESPONSE;
101
123
  if (MEDICAL_OUTPUT_RE.some(re => re.test(r)))
@@ -13,7 +13,7 @@
13
13
  * - Eclipse
14
14
  * - Flutter/Dart
15
15
  *
16
- * BOUNDARY: Interfaces only — implementations in synalux-private.
16
+ * BOUNDARY: Interfaces only — implementations are portal-side.
17
17
  */
18
18
  export const COMPETITOR_PLATFORMS = [
19
19
  {
@@ -9,7 +9,7 @@
9
9
  * - License enforcement and revenue sharing
10
10
  * - Category-based discovery and search
11
11
  *
12
- * BOUNDARY: Interfaces only — implementations in synalux-private.
12
+ * BOUNDARY: Interfaces only — implementations are portal-side.
13
13
  */
14
14
  export const MARKETPLACE_TIERS = {
15
15
  free: {
@@ -8,7 +8,7 @@
8
8
  * - Audio generation and production
9
9
  * - All tier-gated through Synalux subscription
10
10
  *
11
- * BOUNDARY: Interfaces only — implementations in synalux-private.
11
+ * BOUNDARY: Interfaces only — implementations are portal-side.
12
12
  */
13
13
  export const CREATIVE_STUDIO_TIERS = {
14
14
  free: {
@@ -14,7 +14,7 @@
14
14
  * 5. KILL SWITCH — instant account suspension (remote, irreversible)
15
15
  * 6. AUDIT TRAIL — tamper-proof logging for compliance investigations
16
16
  *
17
- * BOUNDARY: Interfaces only — implementations in synalux-private.
17
+ * BOUNDARY: Interfaces only — implementations are portal-side.
18
18
  */
19
19
  /** Default prohibited use policy — hardcoded, cannot be overridden per-tenant */
20
20
  export const PROHIBITED_USE_POLICY = {
@@ -122,7 +122,7 @@ export const DEFAULT_USE_CASE_SCREENING = {
122
122
  human_review_queue: true,
123
123
  re_screening_interval_days: 30,
124
124
  prohibited_dependencies: [
125
- // Placeholder patterns — real list maintained in synalux-private
125
+ // Placeholder patterns — see portal-side ethics enforcement config
126
126
  '@military/*', 'defense-*', 'weapon-*', 'surveillance-*',
127
127
  ],
128
128
  government_domain_patterns: [
@@ -15,7 +15,7 @@
15
15
  * - Cross-platform build matrix
16
16
  * - Plugin/SDK sandbox
17
17
  *
18
- * BOUNDARY: Interfaces only — implementations in synalux-private.
18
+ * BOUNDARY: Interfaces only — implementations are portal-side.
19
19
  */
20
20
  /** Preset memory budgets for common platforms */
21
21
  export const MEMORY_BUDGETS = {
@@ -8,7 +8,7 @@
8
8
  * - Creative projects (3D visualization, VR experience, etc.)
9
9
  * - Enterprise (dashboards, APIs, microservices)
10
10
  *
11
- * BOUNDARY: Interfaces only — implementations in synalux-private.
11
+ * BOUNDARY: Interfaces only — implementations are portal-side.
12
12
  */
13
13
  // ══════════════════════════════════════════════════════════════════
14
14
  // 2. GAME TEMPLATES
package/dist/vm/types.js CHANGED
@@ -7,8 +7,7 @@
7
7
  *
8
8
  * Only interfaces live in Prism — implementations stay in Synalux.
9
9
  *
10
- * @see synalux-private/portal/src/lib/vm-manager.ts
11
- * @see synalux-private/portal/src/lib/device-registry.ts
10
+ * @see Synalux portalvm-manager, device-registry
12
11
  */
13
12
  /** Preset network conditions for load testing */
14
13
  export const NETWORK_PRESETS = {
@@ -2,7 +2,7 @@
2
2
  * VM Manager — Prism IDE Hypervisor Abstraction
3
3
  * ==============================================
4
4
  * Interface layer for VM lifecycle management.
5
- * Implementations live in Synalux (synalux-private/portal/src/lib/vm-manager.ts).
5
+ * Implementations are portal-side (Synalux VM manager).
6
6
  *
7
7
  * Supports:
8
8
  * - VM creation from built-in templates or custom specs
@@ -9,7 +9,7 @@
9
9
  * Required because the marketplace allows building, distributing, and selling apps.
10
10
  * License compliance is enforced at build, deploy, and publish time.
11
11
  *
12
- * BOUNDARY: Interfaces only — implementations in synalux-private.
12
+ * BOUNDARY: Interfaces only — implementations are portal-side.
13
13
  */
14
14
  /** Workspace license presets */
15
15
  export const WORKSPACE_LICENSE_PRESETS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "19.2.8",
3
+ "version": "19.3.0",
4
4
  "mcpName": "io.github.dcostenco/prism-coder",
5
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",