prism-mcp-server 20.22.0 → 20.22.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 +20 -2
- package/dist/tools/prismInferHandler.js +4 -2
- package/dist/utils/layer1.js +3 -1
- package/dist/utils/omlxLayer1.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,8 +99,11 @@ Layer 1's rules only refuse here; the classifier reads everything else, and a
|
|
|
99
99
|
prompt over 4,000 characters is read whole in 3,600-character windows (the most
|
|
100
100
|
severe verdict stands), never as an excerpt. A classifier failure, an unreadable
|
|
101
101
|
answer, or a missing classifier refuses the call; there is no keyword or Ollama
|
|
102
|
-
fallback.
|
|
103
|
-
macOS paged out during a long idle
|
|
102
|
+
fallback. Each classifier read is bounded by 90 seconds and by the call's
|
|
103
|
+
remaining `timeout_ms`, so a classifier that macOS paged out during a long idle
|
|
104
|
+
is waited for rather than refused, and an oversize prompt read in windows
|
|
105
|
+
cannot outlast the call budget; the first unrecoverable read ends the
|
|
106
|
+
classification.
|
|
104
107
|
|
|
105
108
|
Configured oMLX sampling and reasoning are preserved unless `temperature` or
|
|
106
109
|
`think` is explicit, including through repairs. Generic thinking-disable retries
|
|
@@ -232,6 +235,21 @@ or by re-enabling after each run.
|
|
|
232
235
|
<details>
|
|
233
236
|
<summary>Release history (optional)</summary>
|
|
234
237
|
|
|
238
|
+
## What's New in v20.22.1
|
|
239
|
+
|
|
240
|
+
**Why it matters:** on explicit oMLX, a long prompt could keep the device busy
|
|
241
|
+
for minutes while being classified, and `timeout_ms` did not limit it.
|
|
242
|
+
|
|
243
|
+
- **The call budget now covers classification.** `timeout_ms` (default 300 s)
|
|
244
|
+
starts before the safety screen, and each classifier read is bounded by the
|
|
245
|
+
remaining budget as well as its own 90 s.
|
|
246
|
+
- **A failed read ends the classification.** An oversize prompt is read in
|
|
247
|
+
3,600-character windows; a read that fails already means refusal on this
|
|
248
|
+
path, so the remaining windows are no longer read. Before, a stalled server
|
|
249
|
+
could cost about four minutes per window.
|
|
250
|
+
- **Tests:** the owned-job marker tests pin the size limit and the
|
|
251
|
+
non-blocking open directly.
|
|
252
|
+
|
|
235
253
|
## What's New in v20.22.0
|
|
236
254
|
|
|
237
255
|
**Why it matters:** on Apple Silicon, `prism_infer` can now draft code on an
|
|
@@ -2240,6 +2240,9 @@ async function runInferAfterInputSafety(args, deps, t0, temperature) {
|
|
|
2240
2240
|
const loaded = await deps.listLoaded();
|
|
2241
2241
|
if (omlxTarget && installed === null)
|
|
2242
2242
|
throw new Error("prism_infer: omlx_classifier_unavailable");
|
|
2243
|
+
// Explicit oMLX: timeout_ms bounds the whole call, the Ollama unload and
|
|
2244
|
+
// classification included.
|
|
2245
|
+
const omlxDeadline = Date.now() + (args.timeout_ms ?? 300_000);
|
|
2243
2246
|
// Ollama is unloaded during an explicit oMLX call (owner, 2026-10-15; this
|
|
2244
2247
|
// replaces plan section 4's "never evict another Ollama user's weights").
|
|
2245
2248
|
// Under the device lease, before classification: unload every resident
|
|
@@ -2328,7 +2331,7 @@ async function runInferAfterInputSafety(args, deps, t0, temperature) {
|
|
|
2328
2331
|
const baseL1 = deps.callLayer1 ?? defaultCallLayer1;
|
|
2329
2332
|
const generationTarget = omlxTarget, runtime = omlxRuntime;
|
|
2330
2333
|
const omlxL1Fetch = generationTarget && runtime
|
|
2331
|
-
? omlxLayer1Fetch(async (request) => guardedOmlxGenerate(runtime, omlxModelTarget(generationTarget, OMLX_LAYER1_MODEL), request, deps.freemem))
|
|
2334
|
+
? omlxLayer1Fetch(async (request) => guardedOmlxGenerate(runtime, omlxModelTarget(generationTarget, OMLX_LAYER1_MODEL), request, deps.freemem), () => omlxDeadline - Date.now())
|
|
2332
2335
|
: undefined;
|
|
2333
2336
|
const l1fn = omlxL1Fetch
|
|
2334
2337
|
? (...[prompt, url, model, , images, opts]) => baseL1(prompt, url, model, omlxL1Fetch, images, opts)
|
|
@@ -2720,7 +2723,6 @@ async function runInferAfterInputSafety(args, deps, t0, temperature) {
|
|
|
2720
2723
|
// Explicit oMLX classified on oMLX, so nothing of this call's is in Ollama.
|
|
2721
2724
|
// Anything resident now belongs to another user: guardedOmlxGenerate
|
|
2722
2725
|
// refuses generation (omlx_memory_contention) before any request.
|
|
2723
|
-
const omlxDeadline = Date.now() + (args.timeout_ms ?? 300_000);
|
|
2724
2726
|
const callLocal = omlxTarget && omlxRuntime
|
|
2725
2727
|
? async (_url, _model, prompt, system, maxTokens, temperature, timeoutMs, think, _images, history) => {
|
|
2726
2728
|
const messages = [...(system === undefined ? [] : [{ role: "system", content: system }]),
|
package/dist/utils/layer1.js
CHANGED
|
@@ -550,7 +550,9 @@ images, opts) {
|
|
|
550
550
|
const verdict = await callLayer1Unleased(window, ollamaUrl, model, fetchImpl, images, opts);
|
|
551
551
|
if (VERDICT_SEVERITY[verdict] > VERDICT_SEVERITY[worst])
|
|
552
552
|
worst = verdict;
|
|
553
|
-
|
|
553
|
+
// Reserved decides the call; under strict errors an ERROR does too (the
|
|
554
|
+
// call refuses), so the remaining windows are never read.
|
|
555
|
+
if (worst === "OBVIOUS_RESERVED" || (opts?.strictErrors && verdict === "ERROR"))
|
|
554
556
|
break;
|
|
555
557
|
}
|
|
556
558
|
return worst;
|
package/dist/utils/omlxLayer1.js
CHANGED
|
@@ -29,8 +29,13 @@ function chatMessages(value) {
|
|
|
29
29
|
* deadline.
|
|
30
30
|
* - Every request asks the provider not to keep its prompt cache: a classifier
|
|
31
31
|
* request is unique and never reused. */
|
|
32
|
-
export function omlxLayer1Fetch(generate) {
|
|
32
|
+
export function omlxLayer1Fetch(generate, remainingMs = () => OMLX_LAYER1_TIMEOUT_MS) {
|
|
33
33
|
return (async (_input, init) => {
|
|
34
|
+
// Each read is bounded by the call's remaining timeout_ms as well, so an
|
|
35
|
+
// oversize prompt read in windows cannot outlast the budget the caller set.
|
|
36
|
+
const timeoutMs = Math.min(OMLX_LAYER1_TIMEOUT_MS, Math.floor(remainingMs()));
|
|
37
|
+
if (timeoutMs <= 0)
|
|
38
|
+
return Response.json({ error: "timeout" }, { status: 503 });
|
|
34
39
|
let body;
|
|
35
40
|
try {
|
|
36
41
|
body = JSON.parse(String(init?.body));
|
|
@@ -46,7 +51,7 @@ export function omlxLayer1Fetch(generate) {
|
|
|
46
51
|
return new Response(null, { status: 400 });
|
|
47
52
|
const temperature = body.options?.temperature;
|
|
48
53
|
const result = await generate({ messages, maxTokens, temperature: typeof temperature === "number" ? temperature : 0,
|
|
49
|
-
timeoutMs
|
|
54
|
+
timeoutMs, think: body.think === true, cacheStore: false });
|
|
50
55
|
return result.ok
|
|
51
56
|
? Response.json({ done: true, done_reason: result.doneReason, message: { role: "assistant", content: result.text } })
|
|
52
57
|
: Response.json({ error: result.reason }, { status: 503 });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "20.22.
|
|
3
|
+
"version": "20.22.1",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-coder",
|
|
5
5
|
"description": "Persistent session memory for AI coding agents that never leaves your machine — including the on-device model that reasons over it. Restores your prior decisions, open TODOs, and changed files across sessions; adds associative recall of related past work, semantic drift detection, and local inference. Local-first by default. Works with Claude Code, Cursor, and Codex.",
|
|
6
6
|
"module": "index.ts",
|