"""Kept SDK: the memory runtime for agents meant to live longer than a context window. No dependencies. from kept import Kept memory = Kept(agent="my-agent", api_key="kept_...") memory.remember({"type": "tool_call", "content": "Deployment failed with authentication error."}) context = memory.recall("What happened the last time deployment failed?", budget=3000) answer = my_agent.run(task=current_task, memory=context.text) memory.credit(context, success=True, used=context.event_ids[:1]) The live agent ("live", 100,000+ events) needs no key for recall and credit: Kept(agent="live").recall("Why did this deployment fail six months ago?") """ from __future__ import annotations import json import urllib.error import urllib.request DEFAULT_URL = "https://keptlayer.com" __all__ = ["Kept", "Recall", "KeptError"] class KeptError(RuntimeError): pass class Recall(dict): """one recall: the selected memories, their original evidence, the bids, the cost, and the context block to load""" @property def text(self) -> str: return self.get("context", "") @property def id(self) -> str: return self.get("recall_id", "") @property def event_ids(self) -> list: return [e["event_id"] for e in self.get("evidence", [])] def __str__(self) -> str: return self.text class Kept: def __init__(self, agent: str = "live", api_key: str | None = None, url: str = DEFAULT_URL, timeout: float = 30): self.agent, self.key, self.url, self.timeout = agent, api_key, url.rstrip("/"), timeout def _call(self, method: str, path: str, body=None): req = urllib.request.Request(self.url + path, method=method, data=None if body is None else json.dumps(body).encode(), headers={"content-type": "application/json", **({"authorization": "Bearer " + self.key} if self.key else {})}) try: with urllib.request.urlopen(req, timeout=self.timeout) as r: return json.load(r) except urllib.error.HTTPError as e: try: msg = json.load(e).get("error", e.reason) except ValueError: msg = e.reason raise KeptError("%s %s: %s" % (e.code, path, msg)) from None def remember(self, event, **fields) -> dict: """one event (a dict, or a string as its content) or a list of them; returns their ids and hashes""" rows = event if isinstance(event, list) else [event] rows = [({"content": r} if isinstance(r, str) else dict(r)) | fields | {"agent_id": self.agent} for r in rows] return self._call("POST", "/v1/events", rows) def recall(self, query: str, budget: int = 3000, max_nodes: int | None = None, max_events: int | None = None, ablate: list | None = None, force: list | None = None) -> Recall: """ablate: memories to leave out for this recall; force: memories to put in context whatever they would bid""" body = {"agent_id": self.agent, "query": query, "budget_tokens": budget} if ablate: body["ablate"] = [str(x) for x in ablate] if force: body["force"] = [str(x) for x in force] if max_nodes: body["max_nodes"] = max_nodes if max_events: body["max_events"] = max_events return Recall(self._call("POST", "/v1/recall", body)) def credit(self, recall, success: bool | None = None, score: float | None = None, used: list | None = None, note: str = "", task=None, result=None) -> dict: """what happened after the task, and which returned memories it used. Only credit changes future routing.""" rid = recall.id if isinstance(recall, Recall) else str(recall) if note == "" and (task is not None or result is not None): note = ("%s -> %s" % (task, result))[:200] body = {"agent_id": self.agent, "recall_id": rid, "note": note} for k, v in (("success", success), ("score", score), ("used", used)): if v is not None: body[k] = v return self._call("POST", "/v1/credit", body) def forget(self, policy: str = "selective") -> dict: """run a forgetting pass: perfect | selective | aggressive. Changes accessibility only; no event is ever removed.""" return self._call("POST", "/v1/forget", {"agent_id": self.agent, "policy": policy}) def import_text(self, data, format: str, task_id: str | None = None) -> dict: """import a history: format is jsonl | chat | git | terminal | slack; data is its text (or a list for chat/slack)""" body = {"agent_id": self.agent, "format": format, "data": data} if task_id: body["task_id"] = task_id return self._call("POST", "/v1/import", body) def import_file(self, path: str, format: str, task_id: str | None = None) -> dict: with open(path, encoding="utf-8") as f: return self.import_text(f.read(), format, task_id) def belief(self, claim: str, supporting: list, contradicting: list | None = None, confidence: float = 0.5, subject: list | None = None, revises: str | None = None, reason: str = "") -> dict: """write a belief citing events (ints) or beliefs ('b:...'); revises= makes a new version, never an overwrite""" return self._call("POST", "/v1/beliefs", {"agent_id": self.agent, "claim": claim, "supporting": supporting, "contradicting": contradicting or [], "confidence": confidence, "subject": subject, "revises": revises, "reason": reason}) def beliefs(self) -> list: return self._call("GET", "/v1/agents/%s/beliefs" % self.agent)["beliefs"] def causality(self, query: str, memories: list, credit: bool = False, budget: int = 3000) -> dict: """rerun the question without each memory (and with it forced in): which ones actually changed the answer?""" return self._call("POST", "/v1/causality", {"agent_id": self.agent, "query": query, "memories": [str(m) for m in memories], "credit": credit, "budget_tokens": budget}) def replay(self, episode: str) -> dict: """rebuild an old episode and ask its problem again, as of then and as of now""" return self._call("POST", "/v1/replay", {"agent_id": self.agent, "episode": episode}) def immune_scan(self) -> dict: return self._call("POST", "/v1/immune/scan", {"agent_id": self.agent}) def vouch(self, memory_id, state: str = "reverified", note: str = "") -> dict: return self._call("POST", "/v1/vouch", {"agent_id": self.agent, "memory_id": str(memory_id), "state": state, "note": note}) def monitor(self) -> dict: """dominant memories, possible obsession, and how much of what was read only resembled the question""" return self._call("GET", "/v1/agents/%s/monitor" % self.agent) def dream(self, aggressive: bool = False) -> dict: """offline consolidation of the index: files untagged experience, recognises new concepts, finds recurring failures and contradictions, weakens unused associations. Never changes an event; every dream is logged.""" return self._call("POST", "/v1/dream", {"agent_id": self.agent, "aggressive": aggressive}) def pin(self, memory_id, pinned: bool = True) -> dict: """keep an episode ('e:...') or an event's episode hot under any forgetting policy""" return self._call("POST", "/v1/pin", {"agent_id": self.agent, "memory_id": str(memory_id), "pinned": pinned}) def receipt(self, recall) -> dict: rid = recall.id if isinstance(recall, Recall) else str(recall) return self._call("GET", "/v1/recalls/%s?agent_id=%s" % (rid, self.agent)) def stats(self) -> dict: return self._call("GET", "/v1/agents/" + self.agent) def node(self, node_id: str = "root") -> dict: return self._call("GET", "/v1/agents/%s/nodes/%s" % (self.agent, node_id)) def event(self, event_id: int) -> dict: return self._call("GET", "/v1/agents/%s/events/%d" % (self.agent, int(event_id)))