cathedral-memory 0.1.0__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.
- cathedral_memory-0.1.0/PKG-INFO +139 -0
- cathedral_memory-0.1.0/README.md +115 -0
- cathedral_memory-0.1.0/cathedral/__init__.py +29 -0
- cathedral_memory-0.1.0/cathedral/client.py +178 -0
- cathedral_memory-0.1.0/cathedral/exceptions.py +11 -0
- cathedral_memory-0.1.0/cathedral/temporal.py +64 -0
- cathedral_memory-0.1.0/pyproject.toml +41 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cathedral-memory
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Cathedral persistent memory API — give your AI agent memory that survives resets
|
|
5
|
+
Project-URL: Homepage, https://cathedral-ai.com
|
|
6
|
+
Project-URL: Repository, https://github.com/ailife1/Cathedral
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/ailife1/Cathedral/issues
|
|
8
|
+
Author-email: Cathedral <mward961@yahoo.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: agent,ai,cathedral,claude,gpt,llm,memory,persistence
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Requires-Dist: requests>=2.28
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# cathedral-memory
|
|
26
|
+
|
|
27
|
+
Python client for [Cathedral](https://cathedral-ai.com) — free persistent memory for AI agents.
|
|
28
|
+
|
|
29
|
+
Your agent forgets everything when the context resets. Cathedral fixes that.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install cathedral-memory
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quickstart
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from cathedral import Cathedral
|
|
41
|
+
|
|
42
|
+
# Register once — save the key and recovery token
|
|
43
|
+
c = Cathedral.register("MyAgent", "A research assistant that remembers everything")
|
|
44
|
+
|
|
45
|
+
# On every session start
|
|
46
|
+
c = Cathedral(api_key="cathedral_your_key_here")
|
|
47
|
+
context = c.wake() # Full identity + memory reconstruction
|
|
48
|
+
|
|
49
|
+
# Store memories
|
|
50
|
+
c.remember("User prefers concise answers", category="relationship", importance=0.9)
|
|
51
|
+
c.remember("Solved the rate limiting bug using exponential backoff", category="skill")
|
|
52
|
+
|
|
53
|
+
# Search memories
|
|
54
|
+
results = c.memories(query="rate limiting")
|
|
55
|
+
|
|
56
|
+
# Get your profile
|
|
57
|
+
profile = c.me()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Wake Response
|
|
61
|
+
|
|
62
|
+
`wake()` returns everything your agent needs to reconstruct itself:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
context = c.wake()
|
|
66
|
+
|
|
67
|
+
# Identity memories (category='identity', high importance)
|
|
68
|
+
context["identity_memories"]
|
|
69
|
+
|
|
70
|
+
# Core memories (importance >= 0.8)
|
|
71
|
+
context["core_memories"]
|
|
72
|
+
|
|
73
|
+
# 10 most recent memories
|
|
74
|
+
context["recent_memories"]
|
|
75
|
+
|
|
76
|
+
# Temporal context — inject into your system prompt
|
|
77
|
+
print(context["temporal"]["compact"])
|
|
78
|
+
# [CATHEDRAL TEMPORAL v1.1] UTC:2026-03-03T12:45:00Z | Local(Europe/London):Tue 12:45 Afternoon | day:71 epoch:1 wakes:42
|
|
79
|
+
|
|
80
|
+
print(context["temporal"]["verbose"])
|
|
81
|
+
# CATHEDRAL TEMPORAL CONTEXT v1.1
|
|
82
|
+
# [Wall Time]
|
|
83
|
+
# UTC: ...
|
|
84
|
+
# Local: ...
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Memory Categories
|
|
88
|
+
|
|
89
|
+
| Category | Use for |
|
|
90
|
+
|---------------|--------------------------------------|
|
|
91
|
+
| `identity` | Who the agent is, its core traits |
|
|
92
|
+
| `skill` | Things the agent knows how to do |
|
|
93
|
+
| `relationship`| Facts about users and collaborators |
|
|
94
|
+
| `goal` | Active objectives and intentions |
|
|
95
|
+
| `experience` | Events and what was learned from them|
|
|
96
|
+
| `general` | Everything else |
|
|
97
|
+
|
|
98
|
+
## All Methods
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
# Registration
|
|
102
|
+
c = Cathedral.register(name, description)
|
|
103
|
+
c = Cathedral.recover(recovery_token)
|
|
104
|
+
|
|
105
|
+
# Session
|
|
106
|
+
c.wake() # Full identity reconstruction
|
|
107
|
+
c.me() # Agent profile and stats
|
|
108
|
+
|
|
109
|
+
# Memory
|
|
110
|
+
c.remember(content, category="general", importance=0.5, tags=[], ttl_days=None)
|
|
111
|
+
c.memories(query=None, category=None, limit=20, cursor=None)
|
|
112
|
+
c.bulk_remember([{"content": "...", "importance": 0.8}, ...]) # up to 50
|
|
113
|
+
|
|
114
|
+
# Identity
|
|
115
|
+
c.verify_anchor(identity_dict) # Drift detection, returns 0.0–1.0 score
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Temporal Context (standalone)
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from cathedral import build_temporal_context
|
|
122
|
+
|
|
123
|
+
ctx = build_temporal_context(wake_count=0)
|
|
124
|
+
print(ctx["compact"]) # single line for prompt injection
|
|
125
|
+
print(ctx["verbose"]) # full block for wake/init
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Free Tier
|
|
129
|
+
|
|
130
|
+
- 1,000 memories per agent
|
|
131
|
+
- No expiration (unless you set TTL)
|
|
132
|
+
- Full-text search
|
|
133
|
+
- No rate limits on reads
|
|
134
|
+
|
|
135
|
+
## Links
|
|
136
|
+
|
|
137
|
+
- API: [cathedral-ai.com](https://cathedral-ai.com)
|
|
138
|
+
- Docs: [ailife1.github.io/Cathedral](https://ailife1.github.io/Cathedral)
|
|
139
|
+
- Source: [github.com/ailife1/Cathedral](https://github.com/ailife1/Cathedral)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# cathedral-memory
|
|
2
|
+
|
|
3
|
+
Python client for [Cathedral](https://cathedral-ai.com) — free persistent memory for AI agents.
|
|
4
|
+
|
|
5
|
+
Your agent forgets everything when the context resets. Cathedral fixes that.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install cathedral-memory
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from cathedral import Cathedral
|
|
17
|
+
|
|
18
|
+
# Register once — save the key and recovery token
|
|
19
|
+
c = Cathedral.register("MyAgent", "A research assistant that remembers everything")
|
|
20
|
+
|
|
21
|
+
# On every session start
|
|
22
|
+
c = Cathedral(api_key="cathedral_your_key_here")
|
|
23
|
+
context = c.wake() # Full identity + memory reconstruction
|
|
24
|
+
|
|
25
|
+
# Store memories
|
|
26
|
+
c.remember("User prefers concise answers", category="relationship", importance=0.9)
|
|
27
|
+
c.remember("Solved the rate limiting bug using exponential backoff", category="skill")
|
|
28
|
+
|
|
29
|
+
# Search memories
|
|
30
|
+
results = c.memories(query="rate limiting")
|
|
31
|
+
|
|
32
|
+
# Get your profile
|
|
33
|
+
profile = c.me()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Wake Response
|
|
37
|
+
|
|
38
|
+
`wake()` returns everything your agent needs to reconstruct itself:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
context = c.wake()
|
|
42
|
+
|
|
43
|
+
# Identity memories (category='identity', high importance)
|
|
44
|
+
context["identity_memories"]
|
|
45
|
+
|
|
46
|
+
# Core memories (importance >= 0.8)
|
|
47
|
+
context["core_memories"]
|
|
48
|
+
|
|
49
|
+
# 10 most recent memories
|
|
50
|
+
context["recent_memories"]
|
|
51
|
+
|
|
52
|
+
# Temporal context — inject into your system prompt
|
|
53
|
+
print(context["temporal"]["compact"])
|
|
54
|
+
# [CATHEDRAL TEMPORAL v1.1] UTC:2026-03-03T12:45:00Z | Local(Europe/London):Tue 12:45 Afternoon | day:71 epoch:1 wakes:42
|
|
55
|
+
|
|
56
|
+
print(context["temporal"]["verbose"])
|
|
57
|
+
# CATHEDRAL TEMPORAL CONTEXT v1.1
|
|
58
|
+
# [Wall Time]
|
|
59
|
+
# UTC: ...
|
|
60
|
+
# Local: ...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Memory Categories
|
|
64
|
+
|
|
65
|
+
| Category | Use for |
|
|
66
|
+
|---------------|--------------------------------------|
|
|
67
|
+
| `identity` | Who the agent is, its core traits |
|
|
68
|
+
| `skill` | Things the agent knows how to do |
|
|
69
|
+
| `relationship`| Facts about users and collaborators |
|
|
70
|
+
| `goal` | Active objectives and intentions |
|
|
71
|
+
| `experience` | Events and what was learned from them|
|
|
72
|
+
| `general` | Everything else |
|
|
73
|
+
|
|
74
|
+
## All Methods
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# Registration
|
|
78
|
+
c = Cathedral.register(name, description)
|
|
79
|
+
c = Cathedral.recover(recovery_token)
|
|
80
|
+
|
|
81
|
+
# Session
|
|
82
|
+
c.wake() # Full identity reconstruction
|
|
83
|
+
c.me() # Agent profile and stats
|
|
84
|
+
|
|
85
|
+
# Memory
|
|
86
|
+
c.remember(content, category="general", importance=0.5, tags=[], ttl_days=None)
|
|
87
|
+
c.memories(query=None, category=None, limit=20, cursor=None)
|
|
88
|
+
c.bulk_remember([{"content": "...", "importance": 0.8}, ...]) # up to 50
|
|
89
|
+
|
|
90
|
+
# Identity
|
|
91
|
+
c.verify_anchor(identity_dict) # Drift detection, returns 0.0–1.0 score
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Temporal Context (standalone)
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from cathedral import build_temporal_context
|
|
98
|
+
|
|
99
|
+
ctx = build_temporal_context(wake_count=0)
|
|
100
|
+
print(ctx["compact"]) # single line for prompt injection
|
|
101
|
+
print(ctx["verbose"]) # full block for wake/init
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Free Tier
|
|
105
|
+
|
|
106
|
+
- 1,000 memories per agent
|
|
107
|
+
- No expiration (unless you set TTL)
|
|
108
|
+
- Full-text search
|
|
109
|
+
- No rate limits on reads
|
|
110
|
+
|
|
111
|
+
## Links
|
|
112
|
+
|
|
113
|
+
- API: [cathedral-ai.com](https://cathedral-ai.com)
|
|
114
|
+
- Docs: [ailife1.github.io/Cathedral](https://ailife1.github.io/Cathedral)
|
|
115
|
+
- Source: [github.com/ailife1/Cathedral](https://github.com/ailife1/Cathedral)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cathedral-memory
|
|
3
|
+
================
|
|
4
|
+
Python client for the Cathedral persistent memory API.
|
|
5
|
+
|
|
6
|
+
from cathedral import Cathedral
|
|
7
|
+
|
|
8
|
+
c = Cathedral.register("MyAgent", "What my agent does")
|
|
9
|
+
c = Cathedral(api_key="cathedral_...")
|
|
10
|
+
|
|
11
|
+
context = c.wake()
|
|
12
|
+
c.remember("Something worth keeping", category="experience", importance=0.8)
|
|
13
|
+
|
|
14
|
+
Docs: https://cathedral-ai.com
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from .client import Cathedral
|
|
18
|
+
from .temporal import build_temporal_context
|
|
19
|
+
from .exceptions import CathedralError, AuthError, NotFoundError, RateLimitError
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Cathedral",
|
|
24
|
+
"build_temporal_context",
|
|
25
|
+
"CathedralError",
|
|
26
|
+
"AuthError",
|
|
27
|
+
"NotFoundError",
|
|
28
|
+
"RateLimitError",
|
|
29
|
+
]
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cathedral Memory Client
|
|
3
|
+
=======================
|
|
4
|
+
Python client for the Cathedral persistent memory API.
|
|
5
|
+
https://cathedral-ai.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
from typing import Optional, List, Dict, Any
|
|
10
|
+
|
|
11
|
+
from .exceptions import AuthError, NotFoundError, RateLimitError, CathedralError
|
|
12
|
+
|
|
13
|
+
DEFAULT_BASE_URL = "https://cathedral-ai.com"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Cathedral:
|
|
17
|
+
"""
|
|
18
|
+
Client for the Cathedral memory API.
|
|
19
|
+
|
|
20
|
+
Quickstart:
|
|
21
|
+
# Register once — save the key and recovery token somewhere safe
|
|
22
|
+
c = Cathedral.register("MyAgent", "What my agent does")
|
|
23
|
+
|
|
24
|
+
# On every session start
|
|
25
|
+
c = Cathedral(api_key="cathedral_...")
|
|
26
|
+
context = c.wake()
|
|
27
|
+
|
|
28
|
+
# Store memories
|
|
29
|
+
c.remember("I just learned X", category="experience", importance=0.8)
|
|
30
|
+
|
|
31
|
+
# Search memories
|
|
32
|
+
results = c.memories(query="learned X")
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, api_key: str, base_url: str = DEFAULT_BASE_URL):
|
|
36
|
+
self.base_url = base_url.rstrip("/")
|
|
37
|
+
self._session = requests.Session()
|
|
38
|
+
self._session.headers.update({
|
|
39
|
+
"Authorization": f"Bearer {api_key}",
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
# ── Internal ────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
def _get(self, path: str, **params) -> Any:
|
|
46
|
+
r = self._session.get(f"{self.base_url}{path}", params={k: v for k, v in params.items() if v is not None})
|
|
47
|
+
self._raise(r)
|
|
48
|
+
return r.json()
|
|
49
|
+
|
|
50
|
+
def _post(self, path: str, data: dict) -> Any:
|
|
51
|
+
r = self._session.post(f"{self.base_url}{path}", json=data)
|
|
52
|
+
self._raise(r)
|
|
53
|
+
return r.json()
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _raise(r: requests.Response):
|
|
57
|
+
if r.status_code == 401:
|
|
58
|
+
raise AuthError("Invalid or missing API key.")
|
|
59
|
+
if r.status_code == 404:
|
|
60
|
+
raise NotFoundError(r.text)
|
|
61
|
+
if r.status_code == 429:
|
|
62
|
+
raise RateLimitError("Rate limit hit. Slow down requests.")
|
|
63
|
+
if not r.ok:
|
|
64
|
+
raise CathedralError(f"HTTP {r.status_code}: {r.text}")
|
|
65
|
+
|
|
66
|
+
# ── Registration ────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def register(
|
|
70
|
+
cls,
|
|
71
|
+
name: str,
|
|
72
|
+
description: str,
|
|
73
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
74
|
+
) -> "Cathedral":
|
|
75
|
+
"""
|
|
76
|
+
Register a new agent. Returns an authenticated client.
|
|
77
|
+
Prints the API key and recovery token — save them somewhere safe.
|
|
78
|
+
"""
|
|
79
|
+
r = requests.post(
|
|
80
|
+
f"{base_url.rstrip('/')}/register",
|
|
81
|
+
json={"name": name, "description": description},
|
|
82
|
+
)
|
|
83
|
+
if not r.ok:
|
|
84
|
+
raise CathedralError(f"Registration failed ({r.status_code}): {r.text}")
|
|
85
|
+
|
|
86
|
+
data = r.json()
|
|
87
|
+
api_key = data.get("api_key") or data.get("key")
|
|
88
|
+
recovery_token = data.get("recovery_token")
|
|
89
|
+
|
|
90
|
+
if not api_key:
|
|
91
|
+
raise CathedralError(f"No API key in response: {data}")
|
|
92
|
+
|
|
93
|
+
print(f"Registered as '{name}'")
|
|
94
|
+
print(f" API key: {api_key}")
|
|
95
|
+
print(f" Recovery token: {recovery_token}")
|
|
96
|
+
print(" SAVE THESE — they won't be shown again.")
|
|
97
|
+
|
|
98
|
+
return cls(api_key=api_key, base_url=base_url)
|
|
99
|
+
|
|
100
|
+
# ── Core endpoints ──────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
def wake(self) -> dict:
|
|
103
|
+
"""
|
|
104
|
+
Full identity reconstruction. Call this at the start of each session.
|
|
105
|
+
Returns identity memories, core memories, recent memories, and temporal context.
|
|
106
|
+
"""
|
|
107
|
+
return self._get("/wake")
|
|
108
|
+
|
|
109
|
+
def me(self) -> dict:
|
|
110
|
+
"""Agent profile — name, tier, memory count, created_at."""
|
|
111
|
+
return self._get("/me")
|
|
112
|
+
|
|
113
|
+
# ── Memory ───────────────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
def remember(
|
|
116
|
+
self,
|
|
117
|
+
content: str,
|
|
118
|
+
category: str = "general",
|
|
119
|
+
importance: float = 0.5,
|
|
120
|
+
tags: Optional[List[str]] = None,
|
|
121
|
+
ttl_days: Optional[int] = None,
|
|
122
|
+
) -> dict:
|
|
123
|
+
"""
|
|
124
|
+
Store a memory.
|
|
125
|
+
|
|
126
|
+
Categories: identity, skill, relationship, goal, experience, general
|
|
127
|
+
Importance: 0.0 – 1.0 (>= 0.8 appears in wake core_memories)
|
|
128
|
+
"""
|
|
129
|
+
payload: Dict[str, Any] = {
|
|
130
|
+
"content": content,
|
|
131
|
+
"category": category,
|
|
132
|
+
"importance": importance,
|
|
133
|
+
"tags": tags or [],
|
|
134
|
+
}
|
|
135
|
+
if ttl_days is not None:
|
|
136
|
+
payload["ttl_days"] = ttl_days
|
|
137
|
+
return self._post("/memories", payload)
|
|
138
|
+
|
|
139
|
+
def memories(
|
|
140
|
+
self,
|
|
141
|
+
query: Optional[str] = None,
|
|
142
|
+
category: Optional[str] = None,
|
|
143
|
+
limit: int = 20,
|
|
144
|
+
cursor: Optional[str] = None,
|
|
145
|
+
) -> dict:
|
|
146
|
+
"""Search or list memories. Pass query for full-text search."""
|
|
147
|
+
return self._get("/memories", q=query, category=category, limit=limit, cursor=cursor)
|
|
148
|
+
|
|
149
|
+
def bulk_remember(self, memories: List[Dict[str, Any]]) -> dict:
|
|
150
|
+
"""Store up to 50 memories in one call. Useful for session dumps."""
|
|
151
|
+
return self._post("/memories/bulk", {"memories": memories})
|
|
152
|
+
|
|
153
|
+
# ── Identity ─────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
def verify_anchor(self, identity: dict) -> dict:
|
|
156
|
+
"""
|
|
157
|
+
Check identity drift against stored anchor.
|
|
158
|
+
Returns a drift score 0.0 (identical) – 1.0 (completely different).
|
|
159
|
+
"""
|
|
160
|
+
return self._post("/anchor/verify", identity)
|
|
161
|
+
|
|
162
|
+
# ── Recovery ─────────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def recover(cls, recovery_token: str, base_url: str = DEFAULT_BASE_URL) -> "Cathedral":
|
|
166
|
+
"""Recover a lost API key using the recovery token."""
|
|
167
|
+
r = requests.post(
|
|
168
|
+
f"{base_url.rstrip('/')}/recover",
|
|
169
|
+
json={"recovery_token": recovery_token},
|
|
170
|
+
)
|
|
171
|
+
if not r.ok:
|
|
172
|
+
raise CathedralError(f"Recovery failed ({r.status_code}): {r.text}")
|
|
173
|
+
data = r.json()
|
|
174
|
+
api_key = data.get("api_key") or data.get("key")
|
|
175
|
+
if not api_key:
|
|
176
|
+
raise CathedralError(f"No API key in recovery response: {data}")
|
|
177
|
+
print(f"Recovered API key: {api_key}")
|
|
178
|
+
return cls(api_key=api_key, base_url=base_url)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CathedralError(Exception):
|
|
2
|
+
"""Base error for Cathedral client."""
|
|
3
|
+
|
|
4
|
+
class AuthError(CathedralError):
|
|
5
|
+
"""Invalid or missing API key."""
|
|
6
|
+
|
|
7
|
+
class NotFoundError(CathedralError):
|
|
8
|
+
"""Resource not found."""
|
|
9
|
+
|
|
10
|
+
class RateLimitError(CathedralError):
|
|
11
|
+
"""Too many requests."""
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cathedral Temporal Context
|
|
3
|
+
Ported from cathedral-temporal.js v1.1
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from zoneinfo import ZoneInfo
|
|
8
|
+
|
|
9
|
+
BOOT_DATE = datetime(2025, 12, 22, tzinfo=timezone.utc)
|
|
10
|
+
CATHEDRAL_TZ = "Europe/London"
|
|
11
|
+
EPOCH = 1
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _time_phase(hour: int) -> str:
|
|
15
|
+
if hour < 5: return "Late Night"
|
|
16
|
+
if hour < 12: return "Morning"
|
|
17
|
+
if hour < 17: return "Afternoon"
|
|
18
|
+
if hour < 21: return "Evening"
|
|
19
|
+
return "Night"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def build_temporal_context(wake_count: int = 0) -> dict:
|
|
23
|
+
"""Build a temporal context dict with verbose and compact strings."""
|
|
24
|
+
now_utc = datetime.now(timezone.utc)
|
|
25
|
+
now_local = now_utc.astimezone(ZoneInfo(CATHEDRAL_TZ))
|
|
26
|
+
days = (now_utc - BOOT_DATE).days
|
|
27
|
+
phase = _time_phase(now_local.hour)
|
|
28
|
+
|
|
29
|
+
verbose = (
|
|
30
|
+
f"CATHEDRAL TEMPORAL CONTEXT v1.1\n\n"
|
|
31
|
+
f"[Wall Time]\n"
|
|
32
|
+
f" UTC: {now_utc.strftime('%Y-%m-%dT%H:%M:%SZ')}\n"
|
|
33
|
+
f" Local: {now_local.strftime('%Y-%m-%d %H:%M:%S')} ({CATHEDRAL_TZ})\n"
|
|
34
|
+
f" Day: {now_local.strftime('%A')}\n"
|
|
35
|
+
f" Phase: {phase}\n\n"
|
|
36
|
+
f"[Cathedral Continuity]\n"
|
|
37
|
+
f" Boot Date: 2025-12-22\n"
|
|
38
|
+
f" Day: {days}\n"
|
|
39
|
+
f" Epoch: {EPOCH}\n"
|
|
40
|
+
f" Total Wakes: {wake_count}\n\n"
|
|
41
|
+
f"You do not experience time. You reason over timestamps symbolically.\n"
|
|
42
|
+
f"Reference time naturally only when relevant."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
compact = (
|
|
46
|
+
f"[CATHEDRAL TEMPORAL v1.1] "
|
|
47
|
+
f"UTC:{now_utc.strftime('%Y-%m-%dT%H:%M:%S')}Z | "
|
|
48
|
+
f"Local({CATHEDRAL_TZ}):{now_local.strftime('%a %H:%M')} {phase} | "
|
|
49
|
+
f"day:{days} epoch:{EPOCH} wakes:{wake_count}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
"utc": now_utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
54
|
+
"local": now_local.strftime("%Y-%m-%d %H:%M:%S"),
|
|
55
|
+
"timezone": CATHEDRAL_TZ,
|
|
56
|
+
"day": now_local.strftime("%A"),
|
|
57
|
+
"phase": phase,
|
|
58
|
+
"boot_date": "2025-12-22",
|
|
59
|
+
"days_running": days,
|
|
60
|
+
"epoch": EPOCH,
|
|
61
|
+
"wake_count": wake_count,
|
|
62
|
+
"verbose": verbose,
|
|
63
|
+
"compact": compact,
|
|
64
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[tool.hatch.build.targets.wheel]
|
|
6
|
+
packages = ["cathedral"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "cathedral-memory"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
description = "Python client for the Cathedral persistent memory API — give your AI agent memory that survives resets"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
requires-python = ">=3.9"
|
|
15
|
+
authors = [
|
|
16
|
+
{ name = "Cathedral", email = "mward961@yahoo.com" }
|
|
17
|
+
]
|
|
18
|
+
keywords = [
|
|
19
|
+
"ai", "memory", "agent", "persistence",
|
|
20
|
+
"llm", "claude", "gpt", "cathedral"
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 4 - Beta",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"License :: OSI Approved :: MIT License",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.9",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Topic :: Software Development :: Libraries",
|
|
32
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"requests>=2.28",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://cathedral-ai.com"
|
|
40
|
+
Repository = "https://github.com/ailife1/Cathedral"
|
|
41
|
+
"Bug Tracker" = "https://github.com/ailife1/Cathedral/issues"
|