Instructions to use Falln87/clerk-memory with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use Falln87/clerk-memory with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
generator: temporal answer uses slot-held value; gold ADD evicts first when ledger full; budget default 12 for eviction pressure
Browse files- clerk/generator.py +34 -11
clerk/generator.py
CHANGED
|
@@ -15,6 +15,8 @@ Invariants the code maintains:
|
|
| 15 |
* n_uses (the salience signal) is incremented at the moment a question
|
| 16 |
is asked, so the eviction oracle at session t only sees evidence
|
| 17 |
available up to t.
|
|
|
|
|
|
|
| 18 |
* Everything is seeded: the same --seed yields byte-identical data.
|
| 19 |
|
| 20 |
Author: Justin Wolcott (fallnai-research.org)
|
|
@@ -210,7 +212,7 @@ def render_session(
|
|
| 210 |
qas.append({"q": q, "a": ANSWER_UNKNOWN, "type": "unknown",
|
| 211 |
"pred": spec["p"], "value": None})
|
| 212 |
elif f["state"] == "tombstoned":
|
| 213 |
-
old = f["
|
| 214 |
if old and rng.random() < 0.5:
|
| 215 |
q2 = rng.choice(Q_TEMPLATES_TEMPORAL).replace("{h}", spec["h"])
|
| 216 |
qas.append({"q": q2, "a": ANSWER_TEMPORAL.replace("{v}", old),
|
|
@@ -267,6 +269,10 @@ def _slot_id_for(ledger: List[Slot], pending: List[Dict[str, Any]],
|
|
| 267 |
return None
|
| 268 |
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
def gold_ops_for_events(
|
| 271 |
ledger: List[Slot],
|
| 272 |
persona_name: str,
|
|
@@ -276,21 +282,36 @@ def gold_ops_for_events(
|
|
| 276 |
"""Build the gold edit program for one session's events, in transcript
|
| 277 |
order, then apply budget pressure with the salience oracle.
|
| 278 |
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
an
|
|
|
|
| 282 |
ops: List[Dict[str, Any]] = []
|
| 283 |
ledger_now = [Slot(**vars(s)) for s in ledger]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
for ev in events:
|
| 285 |
-
if ev["kind"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
op = {"op": "ADD", "s": persona_name, "p": ev["pred"], "o": ev["value"]}
|
| 287 |
elif ev["kind"] == "UPDATE":
|
| 288 |
sid = _slot_id_for(ledger_now, ops, persona_name, ev["pred"])
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
else:
|
| 292 |
-
op = {"op": "UPDATE", "i": sid, "s": persona_name,
|
| 293 |
-
"p": ev["pred"], "o": ev["value"]}
|
| 294 |
else: # TOMBSTONE
|
| 295 |
sid = _slot_id_for(ledger_now, ops, persona_name, ev["pred"])
|
| 296 |
if sid is None:
|
|
@@ -363,7 +384,9 @@ def main() -> None:
|
|
| 363 |
ap = argparse.ArgumentParser(description="CLERK synthetic session generator")
|
| 364 |
ap.add_argument("--personas", type=int, default=100)
|
| 365 |
ap.add_argument("--sessions", type=int, default=8)
|
| 366 |
-
ap.add_argument("--budget", type=int, default=
|
|
|
|
|
|
|
| 367 |
ap.add_argument("--seed", type=int, default=137)
|
| 368 |
ap.add_argument("--split", choices=["train", "test"], default="train")
|
| 369 |
ap.add_argument("--out", type=str, required=True)
|
|
|
|
| 15 |
* n_uses (the salience signal) is incremented at the moment a question
|
| 16 |
is asked, so the eviction oracle at session t only sees evidence
|
| 17 |
available up to t.
|
| 18 |
+
* Gold programs are always executable: if an ADD would overflow a full
|
| 19 |
+
ledger, the oracle emits EVICT (lowest salience) first, then the ADD.
|
| 20 |
* Everything is seeded: the same --seed yields byte-identical data.
|
| 21 |
|
| 22 |
Author: Justin Wolcott (fallnai-research.org)
|
|
|
|
| 212 |
qas.append({"q": q, "a": ANSWER_UNKNOWN, "type": "unknown",
|
| 213 |
"pred": spec["p"], "value": None})
|
| 214 |
elif f["state"] == "tombstoned":
|
| 215 |
+
old = f["value"] # value the tombstoned slot holds
|
| 216 |
if old and rng.random() < 0.5:
|
| 217 |
q2 = rng.choice(Q_TEMPLATES_TEMPORAL).replace("{h}", spec["h"])
|
| 218 |
qas.append({"q": q2, "a": ANSWER_TEMPORAL.replace("{v}", old),
|
|
|
|
| 269 |
return None
|
| 270 |
|
| 271 |
|
| 272 |
+
def _free_slot(sim: List[Slot]) -> Optional[Slot]:
|
| 273 |
+
return next((s for s in sim if not s.occupied), None)
|
| 274 |
+
|
| 275 |
+
|
| 276 |
def gold_ops_for_events(
|
| 277 |
ledger: List[Slot],
|
| 278 |
persona_name: str,
|
|
|
|
| 282 |
"""Build the gold edit program for one session's events, in transcript
|
| 283 |
order, then apply budget pressure with the salience oracle.
|
| 284 |
|
| 285 |
+
Always-executable: if an ADD would overflow a full ledger, the program
|
| 286 |
+
first EVICTs the lowest-salience occupied slot, then ADDs. If a
|
| 287 |
+
predicate's slot was already evicted, an UPDATE degrades to an ADD and a
|
| 288 |
+
TOMBSTONE of an absent slot is skipped."""
|
| 289 |
ops: List[Dict[str, Any]] = []
|
| 290 |
ledger_now = [Slot(**vars(s)) for s in ledger]
|
| 291 |
+
|
| 292 |
+
def sim_after_pending() -> List[Slot]:
|
| 293 |
+
s, _ = apply_ops(ledger_now, ops, session_idx)
|
| 294 |
+
return s
|
| 295 |
+
|
| 296 |
for ev in events:
|
| 297 |
+
if ev["kind"] in ("ADD", "UPDATE degraded to ADD"):
|
| 298 |
+
pass # fallthrough handled below
|
| 299 |
+
if ev["kind"] == "ADD" or (ev["kind"] == "UPDATE" and
|
| 300 |
+
_slot_id_for(ledger_now, ops, persona_name,
|
| 301 |
+
ev["pred"]) is None):
|
| 302 |
+
# evict-first if the ledger is full
|
| 303 |
+
if _free_slot(sim_after_pending()) is None:
|
| 304 |
+
cur, _ = apply_ops(ledger_now, ops, session_idx)
|
| 305 |
+
victim = min((s for s in cur if s.occupied),
|
| 306 |
+
key=lambda s: salience(s, session_idx))
|
| 307 |
+
evict = {"op": "EVICT", "i": victim.id}
|
| 308 |
+
ops.append(evict)
|
| 309 |
+
ledger_now, _ = apply_ops(ledger_now, [evict], session_idx)
|
| 310 |
op = {"op": "ADD", "s": persona_name, "p": ev["pred"], "o": ev["value"]}
|
| 311 |
elif ev["kind"] == "UPDATE":
|
| 312 |
sid = _slot_id_for(ledger_now, ops, persona_name, ev["pred"])
|
| 313 |
+
op = {"op": "UPDATE", "i": sid, "s": persona_name,
|
| 314 |
+
"p": ev["pred"], "o": ev["value"]}
|
|
|
|
|
|
|
|
|
|
| 315 |
else: # TOMBSTONE
|
| 316 |
sid = _slot_id_for(ledger_now, ops, persona_name, ev["pred"])
|
| 317 |
if sid is None:
|
|
|
|
| 384 |
ap = argparse.ArgumentParser(description="CLERK synthetic session generator")
|
| 385 |
ap.add_argument("--personas", type=int, default=100)
|
| 386 |
ap.add_argument("--sessions", type=int, default=8)
|
| 387 |
+
ap.add_argument("--budget", type=int, default=12,
|
| 388 |
+
help="ledger budget; 12 guarantees eviction pressure "
|
| 389 |
+
"(personas accumulate up to ~18 facts)")
|
| 390 |
ap.add_argument("--seed", type=int, default=137)
|
| 391 |
ap.add_argument("--split", choices=["train", "test"], default="train")
|
| 392 |
ap.add_argument("--out", type=str, required=True)
|