kyp-mem 0.4.4 → 0.5.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/kyp_mem/ui.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """KYP-MEM web UI — interactive interface for browsing the vault."""
2
2
 
3
+ import json
3
4
  import webbrowser
4
5
  from datetime import datetime
5
6
  from pathlib import Path
@@ -28,6 +29,29 @@ def create_app(vault_path: str = None) -> FastAPI:
28
29
  def stats():
29
30
  return JSONResponse(vault.get_stats())
30
31
 
32
+ @app.get("/api/graph")
33
+ def graph():
34
+ nodes = []
35
+ edges = []
36
+ seen_edges = set()
37
+ for path, note in vault.index.notes.items():
38
+ kind = "session" if "/Sessions/" in path else "note"
39
+ nodes.append({"id": path, "title": note.title, "kind": kind, "tags": note.tags})
40
+ for link in (note.links or []):
41
+ target = None
42
+ link_lower = link.lower()
43
+ for p in vault.index.notes:
44
+ stem = p.split("/")[-1].replace(".md", "").lower()
45
+ if stem == link_lower:
46
+ target = p
47
+ break
48
+ if target and target != path:
49
+ key = tuple(sorted([path, target]))
50
+ if key not in seen_edges:
51
+ seen_edges.add(key)
52
+ edges.append({"source": path, "target": target})
53
+ return JSONResponse({"nodes": nodes, "edges": edges})
54
+
31
55
  @app.get("/api/note/{path:path}")
32
56
  def read_note(path: str):
33
57
  note = vault.read(path)
@@ -240,6 +264,62 @@ def create_app(vault_path: str = None) -> FastAPI:
240
264
  vault.write_note(path, content, tags, {})
241
265
  return JSONResponse({"ok": True, "path": path})
242
266
 
267
+ @app.get("/api/token-economics")
268
+ def token_economics(project: str = ""):
269
+ from .config import STATS_FILE
270
+ try:
271
+ raw = json.loads(STATS_FILE.read_text()) if STATS_FILE.exists() else {}
272
+ except (json.JSONDecodeError, OSError):
273
+ raw = {}
274
+
275
+ sessions = raw.get("sessions", [])
276
+ injections = raw.get("injections", [])
277
+
278
+ if project:
279
+ sessions = [s for s in sessions if s.get("project") == project]
280
+ injections = [i for i in injections if i.get("project") == project]
281
+
282
+ total_exploration = sum(s.get("exploration_tokens", 0) for s in sessions)
283
+ total_files_read = sum(s.get("files_read", 0) for s in sessions)
284
+ total_commands = sum(s.get("commands_run", 0) for s in sessions)
285
+ total_files_read_chars = sum(s.get("files_read_chars", 0) for s in sessions)
286
+ total_commands_chars = sum(s.get("commands_chars", 0) for s in sessions)
287
+
288
+ avg_injection_tokens = 0
289
+ latest_injection_tokens = 0
290
+ if injections:
291
+ avg_injection_tokens = sum(i.get("tokens", 0) for i in injections) // len(injections)
292
+ latest_injection_tokens = injections[-1].get("tokens", 0)
293
+
294
+ # Avg exploration per session = what a cold start costs
295
+ avg_exploration = total_exploration // len(sessions) if sessions else 0
296
+
297
+ # Compression ratio: how much memory compresses one session's worth
298
+ # of exploration into an injection. Lower = better compression.
299
+ # e.g. 10x means injection is 10x smaller than avg session exploration
300
+ compression_ratio = round(avg_exploration / latest_injection_tokens, 1) if latest_injection_tokens > 0 and avg_exploration > 0 else 0
301
+
302
+ # Per-session savings: injection replaces one cold-start exploration
303
+ per_session_savings_pct = 0
304
+ if avg_exploration > 0 and latest_injection_tokens > 0:
305
+ per_session_savings_pct = round((1 - latest_injection_tokens / avg_exploration) * 100, 1)
306
+
307
+ return JSONResponse({
308
+ "session_count": len(sessions),
309
+ "total_exploration_tokens": total_exploration,
310
+ "avg_exploration_per_session": avg_exploration,
311
+ "total_files_read": total_files_read,
312
+ "total_files_read_chars": total_files_read_chars,
313
+ "total_commands": total_commands,
314
+ "total_commands_chars": total_commands_chars,
315
+ "injection_count": len(injections),
316
+ "avg_injection_tokens": avg_injection_tokens,
317
+ "latest_injection_tokens": latest_injection_tokens,
318
+ "compression_ratio": compression_ratio,
319
+ "per_session_savings_pct": max(per_session_savings_pct, 0),
320
+ "sessions": sessions[-20:],
321
+ })
322
+
243
323
  @app.post("/api/reload")
244
324
  def reload():
245
325
  vault._load_all()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyp-mem",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "Know Your Project — Persistent & Session level knowledge base for AI agents. MCP-powered with wikilinks, backlinks, auto-learning, and neon web UI.",
5
5
  "bin": {
6
6
  "kyp-mem": "bin/cli.mjs"
package/pyproject.toml CHANGED
@@ -31,6 +31,7 @@ dependencies = [
31
31
  "fastapi>=0.100.0",
32
32
  "uvicorn>=0.20.0",
33
33
  "chromadb>=0.4.0",
34
+ "anthropic>=0.40.0",
34
35
  ]
35
36
 
36
37
  [project.urls]