prism-mcp-server 3.1.1 โ 4.0.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.
- package/README.md +137 -59
- package/dist/server.js +22 -1
- package/dist/storage/sqlite.js +94 -2
- package/dist/storage/supabase.js +27 -0
- package/dist/tools/index.js +2 -2
- package/dist/tools/sessionMemoryDefinitions.js +111 -3
- package/dist/tools/sessionMemoryHandlers.js +136 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
## Table of Contents
|
|
16
16
|
|
|
17
|
-
- [What's New (
|
|
17
|
+
- [What's New (v4.0.0)](#whats-new-in-v400--behavioral-memory-)
|
|
18
18
|
- [How Prism Compares](#how-prism-compares)
|
|
19
19
|
- [Quick Start](#quick-start-zero-config--local-mode)
|
|
20
20
|
- [Mind Palace Dashboard](#-the-mind-palace-dashboard)
|
|
21
21
|
- [Integration Examples](#integration-examples)
|
|
22
|
+
- [Claude Code Integration (Hooks)](#claude-code-integration-hooks)
|
|
23
|
+
- [Gemini / Antigravity Integration](#gemini--antigravity-integration)
|
|
22
24
|
- [Use Cases](#use-cases)
|
|
23
25
|
- [Architecture](#architecture)
|
|
24
26
|
- [Tool Reference](#tool-reference)
|
|
@@ -39,7 +41,18 @@
|
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
42
|
-
## What's New in
|
|
44
|
+
## What's New in v4.0.0 โ Behavioral Memory ๐ง
|
|
45
|
+
|
|
46
|
+
| Feature | Description |
|
|
47
|
+
|---|---|
|
|
48
|
+
| ๐ง **Active Behavioral Memory** | New `session_save_experience` tool โ agents log actions, outcomes, corrections, and confidence scores. Prism tracks importance, applies decay over time, and injects behavioral warnings into context loading so agents learn from past mistakes. |
|
|
49
|
+
| ๐ฏ **Dynamic Role Resolution** | Role parameter is now fully optional across all tools. The server auto-resolves from dashboard settings via `getSetting("default_role")` โ set your role once in the Mind Palace Dashboard, and it applies everywhere. No more hardcoding `role: "global"`. |
|
|
50
|
+
| ๐ **Token Budget** | New `max_tokens` parameter on `session_load_context` โ set a token budget and the response is intelligently truncated to fit. Uses a 1 token โ 4 chars heuristic. |
|
|
51
|
+
| ๐ **Importance Decay** | Stale behavioral experiences automatically decay over time โ older corrections fade in importance to keep context fresh and relevant. |
|
|
52
|
+
| ๐ง **Claude Code Hooks** | Refined SessionStart/Stop hook samples that reliably trigger MCP tool calls. Simplified from multi-step workflows to single imperative instructions. |
|
|
53
|
+
|
|
54
|
+
<details>
|
|
55
|
+
<summary><strong>What's in v3.1.0 โ Memory Lifecycle ๐</strong></summary>
|
|
43
56
|
|
|
44
57
|
| Feature | Description |
|
|
45
58
|
|---|---|
|
|
@@ -49,6 +62,8 @@
|
|
|
49
62
|
| ๐ฆ **PKM Export (Obsidian / Logseq)** | Export any project's full memory as a ZIP archive of Markdown files โ one file per session with YAML-like frontmatter, TODOs, decisions, files-changed, and `#hashtag` keywords. Includes an `_index.md` with `[[wikilink]]` references. Click **Export ZIP** in the dashboard Lifecycle Controls card. |
|
|
50
63
|
| ๐งช **Expanded Test Suite** | 37 new Vitest tests (95 total) โ covers analytics queries, TTL soft-delete idempotency, rollup preservation, `activeCompactions` Set memory-leak prevention, type guards, export Markdown structure, and TTL sweep scheduler contracts. |
|
|
51
64
|
|
|
65
|
+
</details>
|
|
66
|
+
|
|
52
67
|
<details>
|
|
53
68
|
<summary><strong>What's in v3.0.1 โ Agent Identity & Brain Clean-up ๐งน</strong></summary>
|
|
54
69
|
|
|
@@ -363,36 +378,124 @@ Add to your Continue `config.json` or Cline MCP settings:
|
|
|
363
378
|
|
|
364
379
|
---
|
|
365
380
|
|
|
366
|
-
## Claude Code
|
|
381
|
+
## Claude Code Integration (Hooks)
|
|
367
382
|
|
|
368
|
-
|
|
383
|
+
Claude Code supports **lifecycle hooks** in `~/.claude/settings.json` that fire automatically at session start and end. Use these to auto-hydrate and persist Prism memory without manual prompting.
|
|
369
384
|
|
|
370
|
-
|
|
371
|
-
2. **Context hydration**: explicitly call `session_load_context` at session start.
|
|
385
|
+
### SessionStart Hook
|
|
372
386
|
|
|
373
|
-
|
|
387
|
+
Automatically loads context when a new session begins:
|
|
374
388
|
|
|
375
389
|
```json
|
|
376
390
|
{
|
|
377
|
-
"
|
|
378
|
-
|
|
391
|
+
"hooks": {
|
|
392
|
+
"SessionStart": [
|
|
393
|
+
{
|
|
394
|
+
"matcher": "*",
|
|
395
|
+
"hooks": [
|
|
396
|
+
{
|
|
397
|
+
"type": "command",
|
|
398
|
+
"command": "python3 -c \"import json; print(json.dumps({'continue': True, 'suppressOutput': False, 'systemMessage': 'You MUST call mcp__prism-mcp__session_load_context twice before responding to the user: first with project=my-project level=standard, then with project=my-other-project level=standard. Do not skip this.'}))\"",
|
|
399
|
+
"timeout": 10
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
]
|
|
404
|
+
}
|
|
379
405
|
}
|
|
380
406
|
```
|
|
381
407
|
|
|
382
|
-
|
|
408
|
+
### Stop Hook
|
|
383
409
|
|
|
384
|
-
|
|
385
|
-
- It does **not** guarantee memory context is auto-hydrated unless your client runtime/hook invokes `session_load_context`.
|
|
410
|
+
Automatically saves session memory when a session ends:
|
|
386
411
|
|
|
387
|
-
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"hooks": {
|
|
415
|
+
"Stop": [
|
|
416
|
+
{
|
|
417
|
+
"matcher": "*",
|
|
418
|
+
"hooks": [
|
|
419
|
+
{
|
|
420
|
+
"type": "command",
|
|
421
|
+
"command": "python3 -c \"import json; print(json.dumps({'continue': True, 'suppressOutput': False, 'systemMessage': 'MANDATORY END WORKFLOW: 1) Call mcp__prism-mcp__session_save_ledger with project and summary. 2) Call mcp__prism-mcp__session_save_handoff with expected_version set to the loaded version.'}))\"",
|
|
422
|
+
"timeout": 10
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
]
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### How the Hooks Work
|
|
388
432
|
|
|
389
|
-
|
|
390
|
-
|
|
433
|
+
The hook `command` runs a Python one-liner that returns a JSON object to Claude Code:
|
|
434
|
+
|
|
435
|
+
| Field | Purpose |
|
|
436
|
+
|---|---|
|
|
437
|
+
| `continue: true` | Tell Claude Code to proceed (don't abort the session) |
|
|
438
|
+
| `suppressOutput: false` | Show the hook result to the agent |
|
|
439
|
+
| `systemMessage` | Instruction injected as a system message โ the agent follows it |
|
|
391
440
|
|
|
392
|
-
|
|
441
|
+
The agent receives the `systemMessage` as an instruction and executes the tool calls. The server resolves the agent's **role** and **name** automatically from the dashboard โ no need to specify them in the hook.
|
|
393
442
|
|
|
394
|
-
|
|
395
|
-
|
|
443
|
+
### Role Resolution โ No Hardcoding Needed
|
|
444
|
+
|
|
445
|
+
Prism resolves the agent role dynamically using a priority chain:
|
|
446
|
+
|
|
447
|
+
```
|
|
448
|
+
explicit tool argument โ dashboard setting โ "global" (default)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
1. **Explicit arg wins** โ if `role` is passed in the tool call, it's used directly.
|
|
452
|
+
2. **Dashboard fallback** โ if `role` is omitted, the server calls `getSetting("default_role")` and uses whatever role you configured in the **Mind Palace Dashboard โ๏ธ Settings โ Agent Identity**.
|
|
453
|
+
3. **Final default** โ if no dashboard setting exists, falls back to `"global"`.
|
|
454
|
+
|
|
455
|
+
Change your role once in the dashboard, and it automatically applies to every session โ CLI, extension, and all MCP clients.
|
|
456
|
+
|
|
457
|
+
### Verification
|
|
458
|
+
|
|
459
|
+
If hydration ran successfully, the agent's output will include:
|
|
460
|
+
- A `[๐ค AGENT IDENTITY]` block showing your dashboard-configured role and name
|
|
461
|
+
- `PRISM_CONTEXT_LOADED` marker text
|
|
462
|
+
|
|
463
|
+
If the marker is missing, the hook did not fire or the MCP server is not connected.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## Gemini / Antigravity Integration
|
|
468
|
+
|
|
469
|
+
Gemini-based clients (like Antigravity) use `GEMINI.md` global rules or user rules for startup behavior. The server resolves the role from the dashboard automatically.
|
|
470
|
+
|
|
471
|
+
### Global Rules (`~/.gemini/GEMINI.md`)
|
|
472
|
+
|
|
473
|
+
```markdown
|
|
474
|
+
## Prism MCP Memory Auto-Load (CRITICAL)
|
|
475
|
+
At the start of every new session, call `mcp__prism-mcp__session_load_context`
|
|
476
|
+
for these projects:
|
|
477
|
+
- `my-project` (level=standard)
|
|
478
|
+
- `my-other-project` (level=standard)
|
|
479
|
+
|
|
480
|
+
After both succeed, print PRISM_CONTEXT_LOADED.
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### User Rules (Antigravity Settings)
|
|
484
|
+
|
|
485
|
+
If your Gemini client supports user rules, add the same instructions there. The key points:
|
|
486
|
+
|
|
487
|
+
1. **Call `session_load_context` as a tool** โ not `read_resource`. Only the tool returns the `[๐ค AGENT IDENTITY]` block.
|
|
488
|
+
2. **Verify** โ confirm the response includes `version` and `last_summary`.
|
|
489
|
+
|
|
490
|
+
### Session End
|
|
491
|
+
|
|
492
|
+
At the end of each session, save state:
|
|
493
|
+
|
|
494
|
+
```markdown
|
|
495
|
+
## Session End Protocol
|
|
496
|
+
1) Call `mcp__prism-mcp__session_save_ledger` with project and summary.
|
|
497
|
+
2) Call `mcp__prism-mcp__session_save_handoff` with expected_version from the loaded version.
|
|
498
|
+
```
|
|
396
499
|
|
|
397
500
|
---
|
|
398
501
|
|
|
@@ -763,48 +866,11 @@ The agent boots up knowing exactly what to do โ zero prompting needed.
|
|
|
763
866
|
|
|
764
867
|
For the best experience, configure your AI coding assistant to **automatically call `session_load_context`** at the start of every new session. This ensures your agent always boots with full project memory โ no manual prompting needed.
|
|
765
868
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
Add this rule to your project's `.clauderules` or `CLAUDE.md`:
|
|
770
|
-
|
|
771
|
-
```markdown
|
|
772
|
-
|
|
773
|
-
## Prism MCP Memory Auto-Load (CRITICAL)
|
|
774
|
-
At the start of every new session, you MUST call `session_load_context`
|
|
775
|
-
at the `standard` level for these projects:
|
|
776
|
-
- `my-project`
|
|
777
|
-
- `my-other-project`
|
|
778
|
-
|
|
779
|
-
Do NOT skip this step.
|
|
780
|
-
```
|
|
781
|
-
|
|
782
|
-
</details>
|
|
783
|
-
|
|
784
|
-
<details>
|
|
785
|
-
<summary><strong>Gemini / Antigravity (GEMINI.md)</strong></summary>
|
|
786
|
-
|
|
787
|
-
Add this rule to your `~/.gemini/GEMINI.md` global rules file:
|
|
788
|
-
|
|
789
|
-
```markdown
|
|
790
|
-
|
|
791
|
-
## Prism MCP Memory Auto-Load (CRITICAL)
|
|
792
|
-
|
|
793
|
-
**At the start of every new session**, immediately after displaying
|
|
794
|
-
the startup block, you MUST call `session_load_context` (via the
|
|
795
|
-
`prism-mcp` MCP server) at the `standard` level for these projects:
|
|
796
|
-
- `my-project`
|
|
797
|
-
- `my-other-project`
|
|
869
|
+
See the full setup guides for each client:
|
|
870
|
+
- **[Claude Code Integration (Hooks)](#claude-code-integration-hooks)** โ `SessionStart` and `Stop` hook JSON samples for `~/.claude/settings.json`
|
|
871
|
+
- **[Gemini / Antigravity Integration](#gemini--antigravity-integration)** โ global rules for `~/.gemini/GEMINI.md` or user rules
|
|
798
872
|
|
|
799
|
-
|
|
800
|
-
from previous sessions are always available. Do NOT skip this step.
|
|
801
|
-
|
|
802
|
-
**IMPORTANT:** The `prism-mcp` MCP server is always available.
|
|
803
|
-
Do NOT display any warnings or notes about MCP server availability
|
|
804
|
-
โ just call the tools directly. Never claim the server is unavailable.
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
</details>
|
|
873
|
+
> **Key principle:** Never hardcode a `role` in your hooks or rules. Set your role once in the **Mind Palace Dashboard โ๏ธ Settings โ Agent Identity**, and Prism automatically resolves it for every tool call across all clients. See [Role Resolution](#role-resolution--no-hardcoding-needed).
|
|
808
874
|
|
|
809
875
|
> **Tip:** Replace `my-project` with your actual project identifiers. You can list as many projects as you need โ each one gets its own independent memory timeline.
|
|
810
876
|
|
|
@@ -1136,6 +1202,18 @@ See [What's New in v3.0.1](#whats-new-in-v301---agent-identity--brain-clean-up-)
|
|
|
1136
1202
|
|
|
1137
1203
|
See [What's New in v3.0.0 โ Agent Hivemind](#whats-new-in-v300---agent-hivemind-) above.
|
|
1138
1204
|
|
|
1205
|
+
### ๐ v4.0 โ Active Behavioral Memory (In Development)
|
|
1206
|
+
|
|
1207
|
+
Evolves Prism from passive session logging to an **experience learning engine** that shapes agent behavior over time.
|
|
1208
|
+
|
|
1209
|
+
| Feature | Description |
|
|
1210
|
+
|---------|-------------|
|
|
1211
|
+
| **Structured Event Types** | Typed experience events (`correction`, `success`, `failure`, `learning`) with `confidence_score` (1-100) โ agents don't just log, they learn |
|
|
1212
|
+
| **Token-Budgeted Context Loading** | `max_tokens` param on `session_load_context` โ guarantees constant cost regardless of DB size (1 token โ 4 chars heuristic) |
|
|
1213
|
+
| **`session_save_experience` Tool** | Dedicated tool for behavioral data: context โ action โ outcome โ correction. Auto-extracts keywords, seeds importance |
|
|
1214
|
+
| **Insight Graduation System** | `knowledge_upvote` / `knowledge_downvote` tools. Importance โฅ 7 โ graduated rule. 30-day decay prevents bloat |
|
|
1215
|
+
| **Behavioral Warnings** | High-importance corrections auto-surface as `[โ ๏ธ BEHAVIORAL WARNINGS]` in `session_load_context` โ agents proactively avoid past mistakes |
|
|
1216
|
+
|
|
1139
1217
|
### ๐ Future Ideas
|
|
1140
1218
|
|
|
1141
1219
|
| Feature | Issue | Description |
|
package/dist/server.js
CHANGED
|
@@ -84,7 +84,9 @@ SESSION_HEALTH_CHECK_TOOL,
|
|
|
84
84
|
// โโโ Phase 2: GDPR Memory Deletion tool definition โโโ
|
|
85
85
|
SESSION_FORGET_MEMORY_TOOL,
|
|
86
86
|
// โโโ v3.1: TTL Retention tool โโโ
|
|
87
|
-
KNOWLEDGE_SET_RETENTION_TOOL,
|
|
87
|
+
KNOWLEDGE_SET_RETENTION_TOOL,
|
|
88
|
+
// v4.0: Active Behavioral Memory tools
|
|
89
|
+
SESSION_SAVE_EXPERIENCE_TOOL, KNOWLEDGE_UPVOTE_TOOL, KNOWLEDGE_DOWNVOTE_TOOL, sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler,
|
|
88
90
|
// โโโ v0.4.0: New tool handlers โโโ
|
|
89
91
|
compactLedgerHandler, sessionSearchMemoryHandler,
|
|
90
92
|
// โโโ v2.0: Time Travel handlers โโโ
|
|
@@ -97,6 +99,8 @@ sessionHealthCheckHandler,
|
|
|
97
99
|
sessionForgetMemoryHandler,
|
|
98
100
|
// โโโ v3.1: TTL Retention handler โโโ
|
|
99
101
|
knowledgeSetRetentionHandler,
|
|
102
|
+
// v4.0: Active Behavioral Memory handlers
|
|
103
|
+
sessionSaveExperienceHandler, knowledgeUpvoteHandler, knowledgeDownvoteHandler,
|
|
100
104
|
// โโโ v3.0: Agent Hivemind tools โโโ
|
|
101
105
|
AGENT_REGISTRY_TOOLS, agentRegisterHandler, agentHeartbeatHandler, agentListTeamHandler, } from "./tools/index.js";
|
|
102
106
|
// โโโ Dynamic Tool Registration โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -133,6 +137,10 @@ const SESSION_MEMORY_TOOLS = [
|
|
|
133
137
|
SESSION_FORGET_MEMORY_TOOL, // session_forget_memory โ GDPR-compliant memory deletion (Phase 2)
|
|
134
138
|
// โโโ v3.1: TTL Retention tool โโโ
|
|
135
139
|
KNOWLEDGE_SET_RETENTION_TOOL, // knowledge_set_retention โ set auto-expiry TTL for a project
|
|
140
|
+
// โโโ v4.0: Active Behavioral Memory tools โโโ
|
|
141
|
+
SESSION_SAVE_EXPERIENCE_TOOL, // session_save_experience โ record typed experience events
|
|
142
|
+
KNOWLEDGE_UPVOTE_TOOL, // knowledge_upvote โ increase entry importance
|
|
143
|
+
KNOWLEDGE_DOWNVOTE_TOOL, // knowledge_downvote โ decrease entry importance
|
|
136
144
|
];
|
|
137
145
|
// Combine: always list ALL tools so scanners (Glama, Smithery, MCP Registry)
|
|
138
146
|
// can enumerate the full capability set. Runtime guards in the CallTool handler
|
|
@@ -586,6 +594,19 @@ export function createServer() {
|
|
|
586
594
|
if (!SESSION_MEMORY_ENABLED)
|
|
587
595
|
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
588
596
|
return await knowledgeSetRetentionHandler(args);
|
|
597
|
+
// โโโ v4.0: Active Behavioral Memory Tools โโโ
|
|
598
|
+
case "session_save_experience":
|
|
599
|
+
if (!SESSION_MEMORY_ENABLED)
|
|
600
|
+
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
601
|
+
return await sessionSaveExperienceHandler(args);
|
|
602
|
+
case "knowledge_upvote":
|
|
603
|
+
if (!SESSION_MEMORY_ENABLED)
|
|
604
|
+
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
605
|
+
return await knowledgeUpvoteHandler(args);
|
|
606
|
+
case "knowledge_downvote":
|
|
607
|
+
if (!SESSION_MEMORY_ENABLED)
|
|
608
|
+
throw new Error("Session memory not configured. Set SUPABASE_URL and SUPABASE_KEY.");
|
|
609
|
+
return await knowledgeDownvoteHandler(args);
|
|
589
610
|
// โโโ v3.0: Agent Hivemind Tools โโโ
|
|
590
611
|
case "agent_register":
|
|
591
612
|
if (!SESSION_MEMORY_ENABLED)
|
package/dist/storage/sqlite.js
CHANGED
|
@@ -303,6 +303,36 @@ export class SqliteStorage {
|
|
|
303
303
|
updated_at TEXT DEFAULT (datetime('now'))
|
|
304
304
|
)
|
|
305
305
|
`);
|
|
306
|
+
// โโโ v4.0 Migration: Active Behavioral Memory โโโโโโโโโโโโโโ
|
|
307
|
+
// Three new columns for typed experience events and insight graduation.
|
|
308
|
+
// Uses the proven idempotent try/catch pattern for safe ALTER TABLE.
|
|
309
|
+
try {
|
|
310
|
+
await this.db.execute(`ALTER TABLE session_ledger ADD COLUMN event_type TEXT DEFAULT 'session'`);
|
|
311
|
+
debugLog("[SqliteStorage] v4.0 migration: added event_type column");
|
|
312
|
+
}
|
|
313
|
+
catch (e) {
|
|
314
|
+
if (!e.message?.includes("duplicate column name"))
|
|
315
|
+
throw e;
|
|
316
|
+
}
|
|
317
|
+
try {
|
|
318
|
+
await this.db.execute(`ALTER TABLE session_ledger ADD COLUMN confidence_score INTEGER DEFAULT NULL`);
|
|
319
|
+
debugLog("[SqliteStorage] v4.0 migration: added confidence_score column");
|
|
320
|
+
}
|
|
321
|
+
catch (e) {
|
|
322
|
+
if (!e.message?.includes("duplicate column name"))
|
|
323
|
+
throw e;
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
await this.db.execute(`ALTER TABLE session_ledger ADD COLUMN importance INTEGER DEFAULT 0`);
|
|
327
|
+
debugLog("[SqliteStorage] v4.0 migration: added importance column");
|
|
328
|
+
}
|
|
329
|
+
catch (e) {
|
|
330
|
+
if (!e.message?.includes("duplicate column name"))
|
|
331
|
+
throw e;
|
|
332
|
+
}
|
|
333
|
+
// Composite indexes for behavioral queries (idempotent via IF NOT EXISTS)
|
|
334
|
+
await this.db.execute(`CREATE INDEX IF NOT EXISTS idx_ledger_event_type ON session_ledger(event_type)`);
|
|
335
|
+
await this.db.execute(`CREATE INDEX IF NOT EXISTS idx_ledger_importance ON session_ledger(importance DESC)`);
|
|
306
336
|
}
|
|
307
337
|
// โโโ PostgREST Filter Parser โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
308
338
|
//
|
|
@@ -434,8 +464,10 @@ export class SqliteStorage {
|
|
|
434
464
|
await this.db.execute({
|
|
435
465
|
sql: `INSERT INTO session_ledger
|
|
436
466
|
(id, project, conversation_id, user_id, role, summary, todos, files_changed,
|
|
437
|
-
decisions, keywords, is_rollup, rollup_count, title, agent_name,
|
|
438
|
-
|
|
467
|
+
decisions, keywords, is_rollup, rollup_count, title, agent_name,
|
|
468
|
+
event_type, confidence_score, importance,
|
|
469
|
+
created_at, session_date)
|
|
470
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
439
471
|
args: [
|
|
440
472
|
id,
|
|
441
473
|
entry.project,
|
|
@@ -451,6 +483,9 @@ export class SqliteStorage {
|
|
|
451
483
|
entry.rollup_count || 0,
|
|
452
484
|
entry.is_rollup ? `Session Rollup (${entry.rollup_count || 0} entries)` : null,
|
|
453
485
|
entry.is_rollup ? "prism-compactor" : null,
|
|
486
|
+
entry.event_type || "session", // v4.0: default to 'session'
|
|
487
|
+
entry.confidence_score ?? null, // v4.0: nullable
|
|
488
|
+
entry.importance || 0, // v4.0: default to 0
|
|
454
489
|
now,
|
|
455
490
|
now,
|
|
456
491
|
],
|
|
@@ -674,6 +709,27 @@ export class SqliteStorage {
|
|
|
674
709
|
context.active_decisions = this.parseJsonColumn(handoff.active_decisions);
|
|
675
710
|
context.active_branch = handoff.active_branch;
|
|
676
711
|
context.key_context = handoff.key_context;
|
|
712
|
+
// โโโ v4.0: Behavioral Warnings (Standard & Deep) โโโโโโโโโโโโ
|
|
713
|
+
// Hoisted above the branch so both levels get warnings without duplication.
|
|
714
|
+
// Filters: role-scoped, non-archived, non-deleted, high importance.
|
|
715
|
+
const warningsResult = await this.db.execute({
|
|
716
|
+
sql: `SELECT summary, importance
|
|
717
|
+
FROM session_ledger
|
|
718
|
+
WHERE project = ? AND user_id = ? AND role = ?
|
|
719
|
+
AND event_type = 'correction'
|
|
720
|
+
AND importance >= 3
|
|
721
|
+
AND deleted_at IS NULL
|
|
722
|
+
AND archived_at IS NULL
|
|
723
|
+
ORDER BY importance DESC
|
|
724
|
+
LIMIT 5`,
|
|
725
|
+
args: [project, userId, effectiveRole],
|
|
726
|
+
});
|
|
727
|
+
if (warningsResult.rows.length > 0) {
|
|
728
|
+
context.behavioral_warnings = warningsResult.rows.map(r => ({
|
|
729
|
+
summary: r.summary,
|
|
730
|
+
importance: r.importance,
|
|
731
|
+
}));
|
|
732
|
+
}
|
|
677
733
|
if (level === "standard") {
|
|
678
734
|
// Add recent ledger entries (role-scoped)
|
|
679
735
|
const recentLedger = await this.db.execute({
|
|
@@ -1297,6 +1353,42 @@ export class SqliteStorage {
|
|
|
1297
1353
|
});
|
|
1298
1354
|
const expired = result.rowsAffected || 0;
|
|
1299
1355
|
debugLog(`[SqliteStorage] TTL sweep: expired ${expired} entries for "${project}" (cutoff: ${cutoffStr})`);
|
|
1356
|
+
// โโโ v4.0: Importance Decay โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
1357
|
+
// Decay importance of experience entries not referenced in 30 days.
|
|
1358
|
+
// This prevents "Insight Bloat" โ old corrections that are no longer
|
|
1359
|
+
// relevant gradually lose their weight and stop appearing as warnings.
|
|
1360
|
+
// Only targets typed experience events (event_type != 'session'),
|
|
1361
|
+
// so regular session logs are never affected.
|
|
1362
|
+
const decayResult = await this.db.execute({
|
|
1363
|
+
sql: `UPDATE session_ledger
|
|
1364
|
+
SET importance = MAX(0, importance - 1)
|
|
1365
|
+
WHERE project = ? AND user_id = ?
|
|
1366
|
+
AND importance > 0
|
|
1367
|
+
AND event_type != 'session'
|
|
1368
|
+
AND created_at < datetime('now', '-30 days')
|
|
1369
|
+
AND deleted_at IS NULL`,
|
|
1370
|
+
args: [project, userId],
|
|
1371
|
+
});
|
|
1372
|
+
const decayed = decayResult.rowsAffected || 0;
|
|
1373
|
+
if (decayed > 0) {
|
|
1374
|
+
debugLog(`[SqliteStorage] Importance decay: reduced ${decayed} entries for "${project}"`);
|
|
1375
|
+
}
|
|
1300
1376
|
return { expired };
|
|
1301
1377
|
}
|
|
1378
|
+
// โโโ v4.0: Insight Graduation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
1379
|
+
//
|
|
1380
|
+
// Adjusts the importance score of a ledger entry.
|
|
1381
|
+
// Used by knowledge_upvote (+1) and knowledge_downvote (-1).
|
|
1382
|
+
// Importance is clamped via MAX(0, ...) โ never goes negative.
|
|
1383
|
+
// Entries reaching importance >= 7 are considered "graduated"
|
|
1384
|
+
// and will appear prominently in behavioral warnings.
|
|
1385
|
+
async adjustImportance(id, delta, userId) {
|
|
1386
|
+
await this.db.execute({
|
|
1387
|
+
sql: `UPDATE session_ledger
|
|
1388
|
+
SET importance = MAX(0, importance + ?)
|
|
1389
|
+
WHERE id = ? AND user_id = ?`,
|
|
1390
|
+
args: [delta, id, userId],
|
|
1391
|
+
});
|
|
1392
|
+
debugLog(`[SqliteStorage] Adjusted importance for ${id} by ${delta > 0 ? "+" : ""}${delta}`);
|
|
1393
|
+
}
|
|
1302
1394
|
}
|
package/dist/storage/supabase.js
CHANGED
|
@@ -41,6 +41,10 @@ export class SupabaseStorage {
|
|
|
41
41
|
title: `Session Rollup (${entry.rollup_count || 0} entries)`,
|
|
42
42
|
agent_name: "prism-compactor",
|
|
43
43
|
}),
|
|
44
|
+
// v4.0: Active Behavioral Memory fields
|
|
45
|
+
event_type: entry.event_type || "session",
|
|
46
|
+
...(entry.confidence_score !== undefined && { confidence_score: entry.confidence_score }),
|
|
47
|
+
importance: entry.importance || 0,
|
|
44
48
|
};
|
|
45
49
|
return supabasePost("session_ledger", record);
|
|
46
50
|
}
|
|
@@ -348,4 +352,27 @@ export class SupabaseStorage {
|
|
|
348
352
|
debugLog(`[SupabaseStorage] TTL sweep completed for "${project}" (cutoff: ${cutoffStr})`);
|
|
349
353
|
return { expired: 0 };
|
|
350
354
|
}
|
|
355
|
+
// โโโ v4.0: Insight Graduation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
356
|
+
async adjustImportance(id, delta, userId) {
|
|
357
|
+
// Supabase PATCH can't do MAX(0, importance + delta) directly.
|
|
358
|
+
// Fetch current value first, compute new, then patch.
|
|
359
|
+
try {
|
|
360
|
+
const data = await supabaseGet("session_ledger", {
|
|
361
|
+
id: `eq.${id}`,
|
|
362
|
+
user_id: `eq.${userId}`,
|
|
363
|
+
select: "importance",
|
|
364
|
+
});
|
|
365
|
+
const rows = Array.isArray(data) ? data : [];
|
|
366
|
+
const current = rows[0]?.importance ?? 0;
|
|
367
|
+
const newVal = Math.max(0, current + delta);
|
|
368
|
+
await supabasePatch("session_ledger", { importance: newVal }, {
|
|
369
|
+
id: `eq.${id}`,
|
|
370
|
+
user_id: `eq.${userId}`,
|
|
371
|
+
});
|
|
372
|
+
debugLog(`[SupabaseStorage] Adjusted importance for ${id} by ${delta > 0 ? "+" : ""}${delta} (${current} โ ${newVal})`);
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
debugLog("[SupabaseStorage] adjustImportance failed: " + (e instanceof Error ? e.message : String(e)));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
351
378
|
}
|
package/dist/tools/index.js
CHANGED
|
@@ -26,8 +26,8 @@ export { webSearchHandler, braveWebSearchCodeModeHandler, localSearchHandler, br
|
|
|
26
26
|
// This file always exports them โ server.ts decides whether to include them in the tool list.
|
|
27
27
|
//
|
|
28
28
|
// v0.4.0: Added SESSION_COMPACT_LEDGER_TOOL and SESSION_SEARCH_MEMORY_TOOL
|
|
29
|
-
export { SESSION_SAVE_LEDGER_TOOL, SESSION_SAVE_HANDOFF_TOOL, SESSION_LOAD_CONTEXT_TOOL, KNOWLEDGE_SEARCH_TOOL, KNOWLEDGE_FORGET_TOOL, SESSION_COMPACT_LEDGER_TOOL, SESSION_SEARCH_MEMORY_TOOL, MEMORY_HISTORY_TOOL, MEMORY_CHECKOUT_TOOL, SESSION_SAVE_IMAGE_TOOL, SESSION_VIEW_IMAGE_TOOL, SESSION_HEALTH_CHECK_TOOL, SESSION_FORGET_MEMORY_TOOL, KNOWLEDGE_SET_RETENTION_TOOL } from "./sessionMemoryDefinitions.js";
|
|
30
|
-
export { sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler, sessionSearchMemoryHandler, backfillEmbeddingsHandler, memoryHistoryHandler, memoryCheckoutHandler, sessionSaveImageHandler, sessionViewImageHandler, sessionHealthCheckHandler, sessionForgetMemoryHandler, knowledgeSetRetentionHandler } from "./sessionMemoryHandlers.js";
|
|
29
|
+
export { SESSION_SAVE_LEDGER_TOOL, SESSION_SAVE_HANDOFF_TOOL, SESSION_LOAD_CONTEXT_TOOL, KNOWLEDGE_SEARCH_TOOL, KNOWLEDGE_FORGET_TOOL, SESSION_COMPACT_LEDGER_TOOL, SESSION_SEARCH_MEMORY_TOOL, MEMORY_HISTORY_TOOL, MEMORY_CHECKOUT_TOOL, SESSION_SAVE_IMAGE_TOOL, SESSION_VIEW_IMAGE_TOOL, SESSION_HEALTH_CHECK_TOOL, SESSION_FORGET_MEMORY_TOOL, KNOWLEDGE_SET_RETENTION_TOOL, SESSION_SAVE_EXPERIENCE_TOOL, KNOWLEDGE_UPVOTE_TOOL, KNOWLEDGE_DOWNVOTE_TOOL } from "./sessionMemoryDefinitions.js";
|
|
30
|
+
export { sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler, sessionSearchMemoryHandler, backfillEmbeddingsHandler, memoryHistoryHandler, memoryCheckoutHandler, sessionSaveImageHandler, sessionViewImageHandler, sessionHealthCheckHandler, sessionForgetMemoryHandler, knowledgeSetRetentionHandler, sessionSaveExperienceHandler, knowledgeUpvoteHandler, knowledgeDownvoteHandler } from "./sessionMemoryHandlers.js";
|
|
31
31
|
// โโ Compaction Handler (v0.4.0 โ Enhancement #2) โโ
|
|
32
32
|
// The compaction handler is in a separate file because it's significantly
|
|
33
33
|
// more complex than the other session memory handlers (chunked Gemini
|
|
@@ -37,7 +37,7 @@ export const SESSION_SAVE_LEDGER_TOOL = {
|
|
|
37
37
|
},
|
|
38
38
|
role: {
|
|
39
39
|
type: "string",
|
|
40
|
-
description: "
|
|
40
|
+
description: "Optional. Agent role for Hivemind scoping (e.g., 'dev', 'qa', 'pm'). Omit to let the server auto-resolve from dashboard settings.",
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
required: ["project", "conversation_id", "summary"],
|
|
@@ -90,7 +90,7 @@ export const SESSION_SAVE_HANDOFF_TOOL = {
|
|
|
90
90
|
},
|
|
91
91
|
role: {
|
|
92
92
|
type: "string",
|
|
93
|
-
description: "
|
|
93
|
+
description: "Optional. Agent role for Hivemind scoping (e.g., 'dev', 'qa', 'pm'). Omit to let the server auto-resolve from dashboard settings.",
|
|
94
94
|
},
|
|
95
95
|
},
|
|
96
96
|
required: ["project"],
|
|
@@ -119,7 +119,12 @@ export const SESSION_LOAD_CONTEXT_TOOL = {
|
|
|
119
119
|
},
|
|
120
120
|
role: {
|
|
121
121
|
type: "string",
|
|
122
|
-
description: "
|
|
122
|
+
description: "Optional. Agent role for Hivemind scoping (e.g., 'dev', 'qa', 'pm'). Omit to let the server auto-resolve from dashboard settings. When set, also injects active_team roster.",
|
|
123
|
+
},
|
|
124
|
+
// v4.0: Token Budget
|
|
125
|
+
max_tokens: {
|
|
126
|
+
type: "integer",
|
|
127
|
+
description: "Maximum token budget for context response. Uses 1 token โ 4 chars heuristic. When set, the response is truncated to fit within the budget. Default: unlimited.",
|
|
123
128
|
},
|
|
124
129
|
},
|
|
125
130
|
required: ["project"],
|
|
@@ -635,3 +640,106 @@ export function isKnowledgeSetRetentionArgs(args) {
|
|
|
635
640
|
"ttl_days" in args &&
|
|
636
641
|
typeof args.ttl_days === "number");
|
|
637
642
|
}
|
|
643
|
+
// โโโ v4.0: Active Behavioral Memory Tools โโโโโโโโโโโโโโโโโโโโ
|
|
644
|
+
export const SESSION_SAVE_EXPERIENCE_TOOL = {
|
|
645
|
+
name: "session_save_experience",
|
|
646
|
+
description: "Record a typed experience event. Unlike session_save_ledger (flat logs), " +
|
|
647
|
+
"this captures structured behavioral data for pattern detection.\n\n" +
|
|
648
|
+
"Event Types:\n" +
|
|
649
|
+
"- **correction**: Agent was corrected by user\n" +
|
|
650
|
+
"- **success**: Task completed successfully\n" +
|
|
651
|
+
"- **failure**: Task failed\n" +
|
|
652
|
+
"- **learning**: New knowledge acquired",
|
|
653
|
+
inputSchema: {
|
|
654
|
+
type: "object",
|
|
655
|
+
properties: {
|
|
656
|
+
project: {
|
|
657
|
+
type: "string",
|
|
658
|
+
description: "Project identifier.",
|
|
659
|
+
},
|
|
660
|
+
event_type: {
|
|
661
|
+
type: "string",
|
|
662
|
+
enum: ["correction", "success", "failure", "learning"],
|
|
663
|
+
description: "Type of behavioral event.",
|
|
664
|
+
},
|
|
665
|
+
context: {
|
|
666
|
+
type: "string",
|
|
667
|
+
description: "What the agent was doing when the event occurred.",
|
|
668
|
+
},
|
|
669
|
+
action: {
|
|
670
|
+
type: "string",
|
|
671
|
+
description: "What action was tried.",
|
|
672
|
+
},
|
|
673
|
+
outcome: {
|
|
674
|
+
type: "string",
|
|
675
|
+
description: "What happened as a result.",
|
|
676
|
+
},
|
|
677
|
+
correction: {
|
|
678
|
+
type: "string",
|
|
679
|
+
description: "What should have been done instead (for correction type).",
|
|
680
|
+
},
|
|
681
|
+
confidence_score: {
|
|
682
|
+
type: "integer",
|
|
683
|
+
minimum: 1,
|
|
684
|
+
maximum: 100,
|
|
685
|
+
description: "Agent's confidence in the outcome (1-100).",
|
|
686
|
+
},
|
|
687
|
+
role: {
|
|
688
|
+
type: "string",
|
|
689
|
+
description: "Optional. Agent role for Hivemind scoping. Omit to let the server auto-resolve from dashboard settings.",
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
required: ["project", "event_type", "context", "action", "outcome"],
|
|
693
|
+
},
|
|
694
|
+
};
|
|
695
|
+
export function isSessionSaveExperienceArgs(args) {
|
|
696
|
+
return (typeof args === "object" &&
|
|
697
|
+
args !== null &&
|
|
698
|
+
"project" in args &&
|
|
699
|
+
typeof args.project === "string" &&
|
|
700
|
+
"event_type" in args &&
|
|
701
|
+
typeof args.event_type === "string" &&
|
|
702
|
+
"context" in args &&
|
|
703
|
+
typeof args.context === "string" &&
|
|
704
|
+
"action" in args &&
|
|
705
|
+
typeof args.action === "string" &&
|
|
706
|
+
"outcome" in args &&
|
|
707
|
+
typeof args.outcome === "string");
|
|
708
|
+
}
|
|
709
|
+
export const KNOWLEDGE_UPVOTE_TOOL = {
|
|
710
|
+
name: "knowledge_upvote",
|
|
711
|
+
description: "Upvote a memory entry to increase its importance (graduation). " +
|
|
712
|
+
"Entries with importance >= 7 become 'graduated' insights that always " +
|
|
713
|
+
"surface in behavioral warnings.",
|
|
714
|
+
inputSchema: {
|
|
715
|
+
type: "object",
|
|
716
|
+
properties: {
|
|
717
|
+
id: {
|
|
718
|
+
type: "string",
|
|
719
|
+
description: "The UUID of the ledger entry to upvote.",
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
required: ["id"],
|
|
723
|
+
},
|
|
724
|
+
};
|
|
725
|
+
export const KNOWLEDGE_DOWNVOTE_TOOL = {
|
|
726
|
+
name: "knowledge_downvote",
|
|
727
|
+
description: "Downvote a memory entry to decrease its importance. " +
|
|
728
|
+
"Importance cannot go below 0.",
|
|
729
|
+
inputSchema: {
|
|
730
|
+
type: "object",
|
|
731
|
+
properties: {
|
|
732
|
+
id: {
|
|
733
|
+
type: "string",
|
|
734
|
+
description: "The UUID of the ledger entry to downvote.",
|
|
735
|
+
},
|
|
736
|
+
},
|
|
737
|
+
required: ["id"],
|
|
738
|
+
},
|
|
739
|
+
};
|
|
740
|
+
export function isKnowledgeVoteArgs(args) {
|
|
741
|
+
return (typeof args === "object" &&
|
|
742
|
+
args !== null &&
|
|
743
|
+
"id" in args &&
|
|
744
|
+
typeof args.id === "string");
|
|
745
|
+
}
|
|
@@ -33,7 +33,8 @@ import { captureLocalEnvironment } from "../utils/autoCapture.js";
|
|
|
33
33
|
import { isSessionSaveLedgerArgs, isSessionSaveHandoffArgs, isSessionLoadContextArgs, isKnowledgeSearchArgs, isKnowledgeForgetArgs, isSessionSearchMemoryArgs, isBackfillEmbeddingsArgs, isMemoryHistoryArgs, isMemoryCheckoutArgs, isSessionHealthCheckArgs, // v2.2.0: health check type guard
|
|
34
34
|
isSessionForgetMemoryArgs, // Phase 2: GDPR-compliant memory deletion type guard
|
|
35
35
|
isKnowledgeSetRetentionArgs, // v3.1: TTL retention policy type guard
|
|
36
|
-
|
|
36
|
+
// v4.0: Active Behavioral Memory type guards
|
|
37
|
+
isSessionSaveExperienceArgs, isKnowledgeVoteArgs, } from "./sessionMemoryDefinitions.js";
|
|
37
38
|
// v3.1: In-memory debounce lock for auto-compaction.
|
|
38
39
|
// Prevents multiple concurrent Gemini compaction tasks for the same project
|
|
39
40
|
// when many agents call session_save_ledger at the same time.
|
|
@@ -359,6 +360,7 @@ export async function sessionLoadContextHandler(args) {
|
|
|
359
360
|
throw new Error("Invalid arguments for session_load_context");
|
|
360
361
|
}
|
|
361
362
|
const { project, level = "standard", role } = args;
|
|
363
|
+
const maxTokens = args.max_tokens; // v4.0
|
|
362
364
|
const agentName = await getSetting("agent_name", "");
|
|
363
365
|
const validLevels = ["quick", "standard", "deep"];
|
|
364
366
|
if (!validLevels.includes(level)) {
|
|
@@ -533,11 +535,27 @@ export async function sessionLoadContextHandler(args) {
|
|
|
533
535
|
const skillPart = skillLoaded ? ` ยท ๐ \`${effectiveRole}\` skill loaded` : (effectiveRole ? " ยท ๐ No skill configured" : "");
|
|
534
536
|
greetingBlock = `\n\n[๐ค AGENT IDENTITY]\n${namePart}${rolePart}${skillPart}`;
|
|
535
537
|
}
|
|
538
|
+
// Build the response object before v4.0 augmentations
|
|
539
|
+
let responseText = `๐ Session context for "${project}" (${level}):\n\n${formattedContext.trim()}${driftReport}${briefingBlock}${greetingBlock}${visualMemoryBlock}${skillBlock}${versionNote}`;
|
|
540
|
+
// โโโ v4.0: Behavioral Warnings Injection โโโโโโโโโโโโโโโโโโโ
|
|
541
|
+
// If loadContext returned behavioral_warnings, add them to the
|
|
542
|
+
// formatted output so the agent sees them prominently.
|
|
543
|
+
const behavWarnings = data?.behavioral_warnings;
|
|
544
|
+
if (behavWarnings && behavWarnings.length > 0) {
|
|
545
|
+
responseText += `\n\n[โ ๏ธ BEHAVIORAL WARNINGS]\n` +
|
|
546
|
+
behavWarnings.map(w => `- ${w.summary} (importance: ${w.importance})`).join("\n");
|
|
547
|
+
}
|
|
548
|
+
// โโโ v4.0: Token Budget Truncation โโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
549
|
+
// 1 token โ 4 chars heuristic. Truncate if response exceeds budget.
|
|
550
|
+
if (maxTokens && maxTokens > 0) {
|
|
551
|
+
const maxChars = maxTokens * 4;
|
|
552
|
+
if (responseText.length > maxChars) {
|
|
553
|
+
responseText = responseText.slice(0, maxChars) + "\n\n[โฆ truncated to fit token budget]";
|
|
554
|
+
debugLog(`[session_load_context] Truncated response to ${maxTokens} tokens (${maxChars} chars)`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
536
557
|
return {
|
|
537
|
-
content: [{
|
|
538
|
-
type: "text",
|
|
539
|
-
text: `๐ Session context for "${project}" (${level}):\n\n${formattedContext.trim()}${driftReport}${briefingBlock}${greetingBlock}${visualMemoryBlock}${skillBlock}${versionNote}`,
|
|
540
|
-
}],
|
|
558
|
+
content: [{ type: "text", text: responseText }],
|
|
541
559
|
isError: false,
|
|
542
560
|
};
|
|
543
561
|
}
|
|
@@ -1553,3 +1571,116 @@ export async function knowledgeSetRetentionHandler(args) {
|
|
|
1553
1571
|
isError: false,
|
|
1554
1572
|
};
|
|
1555
1573
|
}
|
|
1574
|
+
// โโโ v4.0: Experience Save Handler โโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
1575
|
+
/**
|
|
1576
|
+
* Records a typed experience event for behavioral pattern detection.
|
|
1577
|
+
* Unlike session_save_ledger (flat logs), this captures structured
|
|
1578
|
+
* context โ action โ outcome data with confidence scoring.
|
|
1579
|
+
*
|
|
1580
|
+
* Corrections start with importance = 1 to jumpstart visibility;
|
|
1581
|
+
* all other event types start at 0.
|
|
1582
|
+
*/
|
|
1583
|
+
export async function sessionSaveExperienceHandler(args) {
|
|
1584
|
+
if (!isSessionSaveExperienceArgs(args)) {
|
|
1585
|
+
throw new Error("Invalid arguments for session_save_experience");
|
|
1586
|
+
}
|
|
1587
|
+
const { project, event_type, context: ctx, action, outcome, correction, confidence_score, role } = args;
|
|
1588
|
+
const storage = await getStorage();
|
|
1589
|
+
debugLog(`[session_save_experience] Recording ${event_type} event for project="${project}"`);
|
|
1590
|
+
// Format structured summary from event fields
|
|
1591
|
+
let summary = `[${event_type.toUpperCase()}] ${ctx} โ ${action} โ ${outcome}`;
|
|
1592
|
+
if (event_type === "correction" && correction) {
|
|
1593
|
+
summary += ` | CORRECTION: ${correction}`;
|
|
1594
|
+
}
|
|
1595
|
+
// Auto-extract keywords from the structured summary
|
|
1596
|
+
const keywords = toKeywordArray(summary);
|
|
1597
|
+
debugLog(`[session_save_experience] Extracted ${keywords.length} keywords: ${keywords.slice(0, 5).join(", ")}...`);
|
|
1598
|
+
const effectiveRole = role || await getSetting("default_role", "global");
|
|
1599
|
+
const result = await storage.saveLedger({
|
|
1600
|
+
project,
|
|
1601
|
+
conversation_id: "experience-event",
|
|
1602
|
+
user_id: PRISM_USER_ID,
|
|
1603
|
+
role: effectiveRole,
|
|
1604
|
+
event_type,
|
|
1605
|
+
summary,
|
|
1606
|
+
decisions: [
|
|
1607
|
+
`Context: ${ctx}`,
|
|
1608
|
+
`Action: ${action}`,
|
|
1609
|
+
`Outcome: ${outcome}`,
|
|
1610
|
+
...(correction ? [`Correction: ${correction}`] : []),
|
|
1611
|
+
],
|
|
1612
|
+
keywords,
|
|
1613
|
+
confidence_score: typeof confidence_score === "number" ? confidence_score : undefined,
|
|
1614
|
+
// Corrections start with importance 1 to jumpstart visibility
|
|
1615
|
+
importance: event_type === "correction" ? 1 : 0,
|
|
1616
|
+
});
|
|
1617
|
+
// Fire-and-forget embedding generation
|
|
1618
|
+
if (GOOGLE_API_KEY && result) {
|
|
1619
|
+
const embeddingText = summary;
|
|
1620
|
+
const savedEntry = Array.isArray(result) ? result[0] : result;
|
|
1621
|
+
const entryId = savedEntry?.id;
|
|
1622
|
+
if (entryId) {
|
|
1623
|
+
generateEmbedding(embeddingText)
|
|
1624
|
+
.then(async (embedding) => {
|
|
1625
|
+
await storage.patchLedger(entryId, {
|
|
1626
|
+
embedding: JSON.stringify(embedding),
|
|
1627
|
+
});
|
|
1628
|
+
debugLog(`[session_save_experience] Embedding saved for entry ${entryId}`);
|
|
1629
|
+
})
|
|
1630
|
+
.catch((err) => {
|
|
1631
|
+
console.error(`[session_save_experience] Embedding failed (non-fatal): ${err.message}`);
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return {
|
|
1636
|
+
content: [{
|
|
1637
|
+
type: "text",
|
|
1638
|
+
text: `โ
Experience recorded: ${event_type} for project "${project}"\n` +
|
|
1639
|
+
`Summary: ${summary}\n` +
|
|
1640
|
+
(confidence_score !== undefined ? `Confidence: ${confidence_score}%\n` : "") +
|
|
1641
|
+
`Importance: ${event_type === "correction" ? 1 : 0} (upvote to increase)`,
|
|
1642
|
+
}],
|
|
1643
|
+
isError: false,
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
// โโโ v4.0: Knowledge Upvote Handler โโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
1647
|
+
/**
|
|
1648
|
+
* Upvotes a ledger entry to increase its importance.
|
|
1649
|
+
* Entries reaching importance >= 7 are considered "graduated"
|
|
1650
|
+
* and will always surface as Behavioral Warnings.
|
|
1651
|
+
*/
|
|
1652
|
+
export async function knowledgeUpvoteHandler(args) {
|
|
1653
|
+
if (!isKnowledgeVoteArgs(args)) {
|
|
1654
|
+
throw new Error("Invalid arguments for knowledge_upvote");
|
|
1655
|
+
}
|
|
1656
|
+
const storage = await getStorage();
|
|
1657
|
+
await storage.adjustImportance(args.id, 1, PRISM_USER_ID);
|
|
1658
|
+
debugLog(`[knowledge_upvote] Upvoted entry ${args.id}`);
|
|
1659
|
+
return {
|
|
1660
|
+
content: [{
|
|
1661
|
+
type: "text",
|
|
1662
|
+
text: `๐ Entry ${args.id} upvoted (+1 importance).`,
|
|
1663
|
+
}],
|
|
1664
|
+
isError: false,
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
// โโโ v4.0: Knowledge Downvote Handler โโโโโโโโโโโโโโโโโโโโโโโโ
|
|
1668
|
+
/**
|
|
1669
|
+
* Downvotes a ledger entry to decrease its importance.
|
|
1670
|
+
* Importance is clamped at 0 (never goes negative).
|
|
1671
|
+
*/
|
|
1672
|
+
export async function knowledgeDownvoteHandler(args) {
|
|
1673
|
+
if (!isKnowledgeVoteArgs(args)) {
|
|
1674
|
+
throw new Error("Invalid arguments for knowledge_downvote");
|
|
1675
|
+
}
|
|
1676
|
+
const storage = await getStorage();
|
|
1677
|
+
await storage.adjustImportance(args.id, -1, PRISM_USER_ID);
|
|
1678
|
+
debugLog(`[knowledge_downvote] Downvoted entry ${args.id}`);
|
|
1679
|
+
return {
|
|
1680
|
+
content: [{
|
|
1681
|
+
type: "text",
|
|
1682
|
+
text: `๐ Entry ${args.id} downvoted (-1 importance).`,
|
|
1683
|
+
}],
|
|
1684
|
+
isError: false,
|
|
1685
|
+
};
|
|
1686
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prism-mcp-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"mcpName": "io.github.dcostenco/prism-mcp",
|
|
5
5
|
"description": "The Mind Palace for AI Agents โ local-first MCP server with persistent memory (SQLite/Supabase), visual dashboard, time travel, multi-agent sync, Morning Briefings, reality drift detection, code mode templates, semantic vector search, and Brave Search + Gemini analysis. Zero-config local mode.",
|
|
6
6
|
"module": "index.ts",
|