agent-memory-git 0.1.13__tar.gz → 0.1.15__tar.gz
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.
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/PKG-INFO +1 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/pyproject.toml +1 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/pyproject.toml.orig +1 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/PROTOCOL.md +1 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/capture.py +72 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/cli.py +1 -6
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/sessions.py +20 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/ui.py +10 -18
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/app.css +5 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/icons.js +1 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/insights.js +6 -2
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/list.js +2 -2
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/settings.js +10 -1
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/LICENSE +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/README.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/__init__.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/__main__.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/config.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/context.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/personal/2026/08/20260816-blog-publishing-k3qm.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/personal/2026/09/20260906-push-personal-repos-w8re.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/personal/2026/09/20260921-home-server-n2vb.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/personal/2026/10/20261004-options-first-7hcx.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/personal/2026/10/20261009-thesis-setup-fr6e.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260804-alex-profile-ujzd.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260804-reply-language-xdnc.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260812-ask-before-push-pf3d.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260820-tests-before-done-odzd.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260827-etl-orders-export-deadline-pft7.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/08/20260828-etl-dashboard-72ce.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/09/20260902-report-eta-is2j.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/09/20260908-shop-web-stripe-checkout-lgmx.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/09/20260910-shop-web-deploys-dn73.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/09/20260915-etl-parquet-partitioning-seh2.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/09/20260922-design-tokens-source-uvw7.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/10/20261002-shop-web-v3-freeze-5xtp.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo/work/2026/10/20261012-payments-runbook-4syw.md +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/demo.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/embed_worker.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/frontmatter.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/gitsync.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/hooks.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/importers.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/install.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/lint.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/profiles.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/select.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/store.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/ui_server.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/update.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/util.py +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/index.html +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/api.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/avatar.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/filters.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/format.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/h.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/main.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/markdown.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/search.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/store.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/memory.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/overlays.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/profiles.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/shell.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/ui.js +0 -0
- {agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/workdir.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Shared memory
|
|
2
2
|
|
|
3
|
-
You have a persistent memory that Claude Code and Codex share. Every memory is one Markdown file in a git repository. At the start of each session a hook injects a block titled "Shared memory index": it lists the memories relevant to the current folder and repository, and gives the memories directory, this session's staging directory and the path of the `mem` command.
|
|
3
|
+
You have a persistent memory that Claude Code and Codex share. Every memory is one Markdown file in a git repository. At the start of each session a hook injects a block titled "Shared memory index": it lists the memories relevant to the current folder and repository, and gives the memories directory, this session's staging directory and the path of the `mem` command. When the conversation holds more than one index, only the latest counts: use its memories and paths, its staging directory above all. A new one arrives with your next message when the active profile changes, and a session resumed, forked or continued from another starts with that session's index still in view. If that block is missing, the memory system is not active in this session; ignore this section.
|
|
4
4
|
|
|
5
5
|
## Reading
|
|
6
6
|
|
|
@@ -7,7 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
from . import frontmatter, gitsync, sessions, workdir
|
|
9
9
|
from .context import detect
|
|
10
|
-
from .store import memories_dir, normalize, read, staging_dir
|
|
10
|
+
from .store import load_all, memories_dir, normalize, read, staging_dir
|
|
11
11
|
from .util import atomic_write, id_path, log, new_id, now, now_iso
|
|
12
12
|
|
|
13
13
|
SESSION_FILE = ".session.json"
|
|
@@ -124,6 +124,49 @@ def promote(data_dir, sdir, session=None):
|
|
|
124
124
|
return count
|
|
125
125
|
|
|
126
126
|
|
|
127
|
+
PLACE_KEYS = ("cwd", "original_cwd", "git_root", "git_remote", "git_branch", "git_commit")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def relocated(source, ctx):
|
|
131
|
+
"""`source` moved to the project `ctx` points at (a context from relocate()), in the order _source() writes."""
|
|
132
|
+
items = [(k, v) for k, v in source.items() if k not in PLACE_KEYS]
|
|
133
|
+
place = [(k, ctx[k]) for k in PLACE_KEYS if k != "git_commit" and ctx.get(k)]
|
|
134
|
+
at = next((i for i, (k, _) in enumerate(items) if k == "transcript"), len(items))
|
|
135
|
+
return dict(items[:at] + place + items[at:])
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def rehome(data_dir, session):
|
|
139
|
+
"""Move this session's `here` memories still filed under its throwaway folder to the project it worked in.
|
|
140
|
+
|
|
141
|
+
promote() decides from the transcript so far, which finds nothing when a memory is written before the
|
|
142
|
+
session touches a project folder on this machine; each later turn tries again. Returns how many moved.
|
|
143
|
+
"""
|
|
144
|
+
ctx = session.get("ctx") or {}
|
|
145
|
+
tool, sid = session.get("tool"), session.get("session_id")
|
|
146
|
+
if not sid or not workdir.is_throwaway(ctx.get("cwd")):
|
|
147
|
+
return 0
|
|
148
|
+
left = [
|
|
149
|
+
m
|
|
150
|
+
for m in load_all(data_dir)
|
|
151
|
+
if m["scope"] == "here"
|
|
152
|
+
and m["source"].get("session_id") == sid
|
|
153
|
+
and m["source"].get("tool") == tool
|
|
154
|
+
and workdir.is_throwaway(m["source"].get("cwd"))
|
|
155
|
+
and not m["source"].get("original_cwd")
|
|
156
|
+
]
|
|
157
|
+
if not left:
|
|
158
|
+
return 0
|
|
159
|
+
moved = relocate(ctx, session.get("transcript_path") or sessions.transcript_path(tool, sid))
|
|
160
|
+
if not moved.get("original_cwd"):
|
|
161
|
+
return 0 # still no project to point at
|
|
162
|
+
for m in left:
|
|
163
|
+
path = memories_dir(data_dir) / m["rel"]
|
|
164
|
+
meta, body = read(path)
|
|
165
|
+
meta["source"] = relocated(meta["source"], moved)
|
|
166
|
+
atomic_write(path, frontmatter.join(meta, body))
|
|
167
|
+
return len(left)
|
|
168
|
+
|
|
169
|
+
|
|
127
170
|
def stamp_updates(data_dir):
|
|
128
171
|
"""Set `updated` on tracked memory files that were edited in place."""
|
|
129
172
|
r = gitsync.git(data_dir, "status", "--porcelain", "-z", "--", "memories")
|
|
@@ -175,6 +218,7 @@ def flush(data_dir, sdir, final=False, lock_timeout=5.0):
|
|
|
175
218
|
return False
|
|
176
219
|
session = read_session(sdir)
|
|
177
220
|
n = promote(data_dir, sdir, session)
|
|
221
|
+
rehome(data_dir, session)
|
|
178
222
|
committed = commit(data_dir, session)
|
|
179
223
|
if final and Path(sdir).is_dir() and not any(Path(sdir).glob("*.md")):
|
|
180
224
|
shutil.rmtree(sdir, ignore_errors=True)
|
|
@@ -183,6 +227,31 @@ def flush(data_dir, sdir, final=False, lock_timeout=5.0):
|
|
|
183
227
|
return committed
|
|
184
228
|
|
|
185
229
|
|
|
230
|
+
TOOLS = ("claude-code", "codex") # the prefixes of staging folder names: <tool>-<session id>
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def adopt(sdir):
|
|
234
|
+
"""Session info for a staging folder that has none, from its name and that session's transcript.
|
|
235
|
+
|
|
236
|
+
An agent can write into a staging folder that is not its session's own, such as the one named in the older
|
|
237
|
+
index of a session it was continued from; the folder it makes has no .session.json, and without this the
|
|
238
|
+
memories in it are committed with no provenance at all. They are credited to the folder's session.
|
|
239
|
+
"""
|
|
240
|
+
name = Path(sdir).name
|
|
241
|
+
tool = next((t for t in TOOLS if name.startswith(t + "-")), None)
|
|
242
|
+
if not tool:
|
|
243
|
+
return
|
|
244
|
+
sid = name[len(tool) + 1 :]
|
|
245
|
+
transcript = sessions.transcript_path(tool, sid)
|
|
246
|
+
info = {"tool": tool, "session_id": sid, "transcript_path": transcript}
|
|
247
|
+
folder = sessions.cwd(tool, sid, transcript)
|
|
248
|
+
if folder:
|
|
249
|
+
ctx = detect(folder)
|
|
250
|
+
ctx.pop("git_commit", None) # HEAD now, not what the session saw
|
|
251
|
+
info["ctx"] = ctx
|
|
252
|
+
write_session(sdir, info)
|
|
253
|
+
|
|
254
|
+
|
|
186
255
|
def recover_orphans(data_dir, keep=None):
|
|
187
256
|
"""Promote staging dirs left by sessions that ended without a final flush."""
|
|
188
257
|
root = staging_dir(data_dir)
|
|
@@ -196,6 +265,8 @@ def recover_orphans(data_dir, keep=None):
|
|
|
196
265
|
age = time.time() - (marker.stat().st_mtime if marker.exists() else sdir.stat().st_mtime)
|
|
197
266
|
has_files = any(sdir.glob("*.md"))
|
|
198
267
|
if has_files and age > ORPHAN_AGE:
|
|
268
|
+
if not marker.exists():
|
|
269
|
+
adopt(sdir)
|
|
199
270
|
committed |= flush(data_dir, sdir, final=True, lock_timeout=1.0)
|
|
200
271
|
elif not has_files and age > STALE_AGE:
|
|
201
272
|
shutil.rmtree(sdir, ignore_errors=True)
|
|
@@ -129,12 +129,7 @@ def cmd_relocate(args):
|
|
|
129
129
|
if args.dry_run:
|
|
130
130
|
continue
|
|
131
131
|
meta, body = store.read(mdir / m["rel"])
|
|
132
|
-
source = dict(meta.get("source") or {})
|
|
133
|
-
for key in ("cwd", "git_root", "git_remote", "git_branch"):
|
|
134
|
-
source.pop(key, None)
|
|
135
|
-
if ctx.get(key):
|
|
136
|
-
source[key] = ctx[key]
|
|
137
|
-
source["original_cwd"] = ctx["original_cwd"]
|
|
132
|
+
source = capture.relocated(dict(meta.get("source") or {}), ctx)
|
|
138
133
|
if transcript:
|
|
139
134
|
source.setdefault("transcript", transcript)
|
|
140
135
|
meta["source"] = source
|
|
@@ -53,6 +53,26 @@ def transcript_path(tool, session_id):
|
|
|
53
53
|
return str(hits[0]) if hits else ""
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
def cwd(tool, session_id, transcript=None):
|
|
57
|
+
"""The folder a session ran in: Codex's thread record, or the first Claude transcript line that names one."""
|
|
58
|
+
if tool == "codex":
|
|
59
|
+
return _codex_thread(session_id, "cwd")
|
|
60
|
+
try:
|
|
61
|
+
with open(transcript, encoding="utf-8", errors="replace") as f:
|
|
62
|
+
for raw in f:
|
|
63
|
+
if '"cwd"' not in raw:
|
|
64
|
+
continue
|
|
65
|
+
try:
|
|
66
|
+
found = json.loads(raw).get("cwd")
|
|
67
|
+
except ValueError:
|
|
68
|
+
continue
|
|
69
|
+
if found:
|
|
70
|
+
return found
|
|
71
|
+
except (OSError, TypeError):
|
|
72
|
+
pass
|
|
73
|
+
return ""
|
|
74
|
+
|
|
75
|
+
|
|
56
76
|
def title(tool, session_id, transcript=None):
|
|
57
77
|
if tool == "codex":
|
|
58
78
|
name = _codex_title(session_id)
|
|
@@ -316,19 +316,15 @@ def embed(data_dir, texts):
|
|
|
316
316
|
|
|
317
317
|
|
|
318
318
|
def closeness(vectors):
|
|
319
|
-
"""
|
|
319
|
+
"""The cosine similarity of every pair of unit rows, as it is (below 0 reads as 0), and what a typical pair
|
|
320
|
+
scores: the median over pairs of different memories. Pairs at or below it are not listed as similar.
|
|
320
321
|
|
|
321
|
-
|
|
322
|
-
so the raw number says little; the rescaled one reads like a percentage.
|
|
322
|
+
It is not rescaled: rescaling made the closest pair 100% however far apart it was.
|
|
323
323
|
"""
|
|
324
|
-
|
|
325
|
-
off =
|
|
326
|
-
if not len(off):
|
|
327
|
-
return np.ones_like(raw)
|
|
328
|
-
lo, hi = np.percentile(off, 50), off.max()
|
|
329
|
-
sim = np.clip((raw - lo) / max(hi - lo, 1e-6), 0, 1)
|
|
324
|
+
sim = np.clip(vectors @ vectors.T, 0, 1)
|
|
325
|
+
off = sim[~np.eye(len(sim), dtype=bool)]
|
|
330
326
|
np.fill_diagonal(sim, 1)
|
|
331
|
-
return sim
|
|
327
|
+
return sim, float(np.median(off)) if len(off) else 0.0
|
|
332
328
|
|
|
333
329
|
|
|
334
330
|
# ------------------------------------------------------------ page data
|
|
@@ -366,13 +362,9 @@ def build(data_dir, semantic=True, vectors_out=None):
|
|
|
366
362
|
x, vocab = vectorize(docs)
|
|
367
363
|
forms = _display_forms(clean(t + " " + b) for t, b in docs)
|
|
368
364
|
vectors = embed(data_dir, [prose(t, b) for t, b in docs]) if semantic else None
|
|
369
|
-
if vectors is not None
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
else:
|
|
373
|
-
sim, space = np.clip(x @ x.T, 0, 1), x
|
|
374
|
-
np.fill_diagonal(sim, 1)
|
|
375
|
-
method = "keywords only (no local model)"
|
|
365
|
+
space = vectors if vectors is not None else x
|
|
366
|
+
sim, typical = closeness(space)
|
|
367
|
+
method = f"{MODEL['name']}, local" if vectors is not None else "keywords only (no local model)"
|
|
376
368
|
if vectors_out is not None:
|
|
377
369
|
vectors_out[:] = [space]
|
|
378
370
|
|
|
@@ -399,7 +391,7 @@ def build(data_dir, semantic=True, vectors_out=None):
|
|
|
399
391
|
"host": src.get("host") or "",
|
|
400
392
|
"created": m["created"],
|
|
401
393
|
"updated": m["updated"],
|
|
402
|
-
"similar": [{"i": j, "s": round(float(sim[i, j]), 3)} for j in order if sim[i, j] >
|
|
394
|
+
"similar": [{"i": j, "s": round(float(sim[i, j]), 3)} for j in order if sim[i, j] > typical],
|
|
403
395
|
"keywords": [{"k": vocab[j], "t": forms.get(vocab[j], vocab[j])} for j in picks[i]],
|
|
404
396
|
"terms": [vocab[j] for j in np.flatnonzero(x[i])],
|
|
405
397
|
"issues": [message for _, message in lint.check(m, body, names)],
|
|
@@ -559,6 +559,11 @@ button.hero-meta-item:hover .copy-hint, button.hero-meta-item:focus-visible .cop
|
|
|
559
559
|
.doctor-line .i { width: 13px; height: 13px; }
|
|
560
560
|
.doctor-sum .chev { transition: transform .15s; }
|
|
561
561
|
.doctor-sum .chev.turned { transform: rotate(180deg); }
|
|
562
|
+
.about { display: flex; justify-content: center; align-items: center; gap: 2px; margin-top: 4px; font-size: 12.5px; color: var(--ink-3); }
|
|
563
|
+
.about .sep { margin: 0 4px; }
|
|
564
|
+
.about a { display: inline-flex; height: 28px; align-items: center; gap: 4px; padding: 0 8px; border-radius: 999px; color: var(--ink-3); text-decoration: none; transition: background-color .15s, color .15s; }
|
|
565
|
+
.about a:hover { background: var(--hover); color: var(--ink); }
|
|
566
|
+
.about .i { width: 12px; height: 12px; }
|
|
562
567
|
.checks { width: 100%; margin-top: 12px; padding: 16px 20px 18px; border-radius: var(--r-card); background: var(--panel); animation: rise .15s ease-out; }
|
|
563
568
|
.checks-note { margin-bottom: 10px; font-size: 12px; color: var(--ink-3); }
|
|
564
569
|
.checks-note code { font-size: 11.5px; color: var(--ink-2); }
|
|
@@ -16,6 +16,7 @@ const PATHS = {
|
|
|
16
16
|
"arrow-left": `<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>`,
|
|
17
17
|
"arrow-right": `<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>`,
|
|
18
18
|
"arrow-up": `<path d="m5 12 7-7 7 7"/><path d="M12 19V5"/>`,
|
|
19
|
+
"arrow-up-right": `<path d="M7 7h10v10"/><path d="M7 17 17 7"/>`,
|
|
19
20
|
"chart-column": `<path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="M18 17V9"/><path d="M13 17V5"/><path d="M8 17v-3"/>`,
|
|
20
21
|
"check": `<path d="M20 6 9 17l-5-5"/>`,
|
|
21
22
|
"chevron-down": `<path d="m6 9 6 6 6-6"/>`,
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/insights.js
RENAMED
|
@@ -136,7 +136,7 @@ export function insightsPage() {
|
|
|
136
136
|
<section class="card span2"><h2>Possible duplicates</h2><p class="card-note">Pairs that read alike; compare them side by side and keep one.</p>
|
|
137
137
|
${pairs.length ? pairs.map((p, i) => html`<div class="pair"><div class="pair-text"><span class="truncate">${p[0].description}</span><span class="truncate faint2">${p[1].description}</span></div>
|
|
138
138
|
<span class="count">${Math.round(p[2] * 100)}%</span><button type="button" class="btn sm" data-act="compare" data-arg="${i}">Compare</button></div>`)
|
|
139
|
-
: html`<p class="card-note">No two memories are
|
|
139
|
+
: html`<p class="card-note">No likely duplicates: no two memories are ${Math.round(DUPLICATE * 100)}% alike or more.</p>`}
|
|
140
140
|
</section>
|
|
141
141
|
|
|
142
142
|
<section class="card span2"><h2>Changes per week</h2>${chart("changes", changes, WHO, TOOL_COLORS, WHO_LABELS, `No memory changes in the past ${WEEKS} weeks.`)}</section>
|
|
@@ -153,9 +153,13 @@ export function insightsPage() {
|
|
|
153
153
|
</div>`;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/** Cosine similarity at or above which two memories may say the same thing. Set from pairs that were merged as
|
|
157
|
+
* duplicates (0.69-0.70 with the embedding model) and related ones that were not (0.63 and below). */
|
|
158
|
+
const DUPLICATE = 0.65;
|
|
159
|
+
|
|
156
160
|
/** The pairs shown under Possible duplicates, so Compare can find its pair by position. */
|
|
157
161
|
export function duplicatePairs() {
|
|
158
162
|
const M = app.M, pairs = [];
|
|
159
|
-
M.forEach((m, i) => m.similar.forEach((s) => { if (s.i > i && s.s >=
|
|
163
|
+
M.forEach((m, i) => m.similar.forEach((s) => { if (s.i > i && s.s >= DUPLICATE && M[s.i]) pairs.push([m, M[s.i], s.s]); }));
|
|
160
164
|
return pairs.sort((a, b) => b[2] - a[2]).slice(0, 5);
|
|
161
165
|
}
|
|
@@ -52,7 +52,7 @@ function facet(def) {
|
|
|
52
52
|
${options.map((o) => {
|
|
53
53
|
const on = values.includes(o.value);
|
|
54
54
|
return html`<button type="button" role="menuitemcheckbox" class="${cx("menu-item", !o.count && !on && "faint")}"${attrs({ "aria-checked": String(on), "data-act": "toggle", "data-arg": `${def.key}:${o.value}`, "data-key": `${def.key}:${o.value}` })}>
|
|
55
|
-
<span class="tick">${on ? icon("check", "", 3) : ""}</span><span class="grow">${o.label}</span><span class="count">${o.count}</span></button>`;
|
|
55
|
+
<span class="tick">${on ? icon("check", "", 3) : ""}</span><span class="grow truncate"${attrs({ title: o.label })}>${o.label}</span><span class="count">${o.count}</span></button>`;
|
|
56
56
|
})}
|
|
57
57
|
</div>
|
|
58
58
|
${values.length ? html`<div class="menu-foot"><button type="button" class="menu-wide" data-act="setList" data-arg="${def.key}">Clear ${def.label.toLowerCase()}</button></div>` : ""}`;
|
|
@@ -73,7 +73,7 @@ function added() {
|
|
|
73
73
|
${opts.map((o) => {
|
|
74
74
|
const on = v === o.value;
|
|
75
75
|
return html`<button type="button" role="radio" class="${cx("menu-item", !o.count && !on && "faint")}"${attrs({ "aria-checked": String(on), "data-act": "setAdded", "data-arg": on ? "" : o.value })}>
|
|
76
|
-
<span class="radio">${on ? html`<i></i>` : ""}</span><span class="grow">${o.label}</span><span class="count">${o.count}</span></button>`;
|
|
76
|
+
<span class="radio">${on ? html`<i></i>` : ""}</span><span class="grow truncate"${attrs({ title: o.label })}>${o.label}</span><span class="count">${o.count}</span></button>`;
|
|
77
77
|
})}
|
|
78
78
|
</div>
|
|
79
79
|
<div class="menu-range">
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/settings.js
RENAMED
|
@@ -123,6 +123,15 @@ function doctor() {
|
|
|
123
123
|
</section>`;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
// ---------------------------------------------------------------- where agent-memory lives
|
|
127
|
+
|
|
128
|
+
/** The project's site and repository, as [project.urls] in pyproject.toml has them. */
|
|
129
|
+
const LINKS = [["Website", "https://ki-seki.github.io/agent-memory/"], ["GitHub", "https://github.com/Ki-Seki/agent-memory"]];
|
|
130
|
+
|
|
131
|
+
function about() {
|
|
132
|
+
return html`<nav class="about" aria-label="agent-memory">${LINKS.map(([text, href], i) => html`${i ? html`<span class="sep">·</span>` : ""}<a${attrs({ href, target: "_blank", rel: "noopener noreferrer" })}>${text}${icon("arrow-up-right")}</a>`)}</nav>`;
|
|
133
|
+
}
|
|
134
|
+
|
|
126
135
|
export function settingsPage() {
|
|
127
|
-
return html`<div class="settings">${hero()}${prefs()}${doctor()}</div>`;
|
|
136
|
+
return html`<div class="settings">${hero()}${prefs()}${doctor()}${about()}</div>`;
|
|
128
137
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/memory.js
RENAMED
|
File without changes
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/overlays.js
RENAMED
|
File without changes
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/profiles.js
RENAMED
|
File without changes
|
{agent_memory_git-0.1.13 → agent_memory_git-0.1.15}/src/agent_memory/webui/js/views/shell.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|