remember 0.2.0__tar.gz → 0.3.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.
- {remember-0.2.0 → remember-0.3.0}/.gitignore +10 -0
- remember-0.3.0/PKG-INFO +106 -0
- remember-0.3.0/README.md +85 -0
- {remember-0.2.0 → remember-0.3.0}/pyproject.toml +5 -5
- remember-0.3.0/src/remember/__init__.py +77 -0
- {remember-0.2.0 → remember-0.3.0}/src/remember/client.py +164 -6
- remember-0.3.0/tests/test_client_facade.py +195 -0
- {remember-0.2.0 → remember-0.3.0}/uv.lock +1 -1
- remember-0.2.0/PKG-INFO +0 -78
- remember-0.2.0/README.md +0 -57
- remember-0.2.0/src/remember/__init__.py +0 -74
- {remember-0.2.0 → remember-0.3.0}/src/remember/cli.py +0 -0
- {remember-0.2.0 → remember-0.3.0}/src/remember/errors.py +0 -0
- {remember-0.2.0 → remember-0.3.0}/src/remember/models.py +0 -0
- {remember-0.2.0 → remember-0.3.0}/src/remember/py.typed +0 -0
- {remember-0.2.0 → remember-0.3.0}/tests/test_cli.py +0 -0
- {remember-0.2.0 → remember-0.3.0}/tests/test_client.py +0 -0
|
@@ -32,6 +32,9 @@ fe/*.tsbuildinfo
|
|
|
32
32
|
fe/.pages-deploy.digest
|
|
33
33
|
fe/.agent-browser-shots/
|
|
34
34
|
fe/.pen-exports/
|
|
35
|
+
fe/playwright-report/
|
|
36
|
+
fe/test-results/
|
|
37
|
+
.e2e-runtime/
|
|
35
38
|
|
|
36
39
|
# Observability host — secret-bearing / generated deploy artifacts (never commit)
|
|
37
40
|
infra/obs/.env
|
|
@@ -47,6 +50,8 @@ infra/obs/certs/
|
|
|
47
50
|
*.env
|
|
48
51
|
!*.env.example
|
|
49
52
|
!infra/obs/.env.example
|
|
53
|
+
# Reviewed non-secret image/address inventory; credentials are separate files.
|
|
54
|
+
!infra/storage-cell/runtime.env
|
|
50
55
|
*.rendered.yaml
|
|
51
56
|
Caddyfile.rendered
|
|
52
57
|
**/umcobs0.conf
|
|
@@ -66,3 +71,8 @@ fe_admin/storybook-static/
|
|
|
66
71
|
# Built client distributions (published via the release workflow, never committed).
|
|
67
72
|
client/dist/
|
|
68
73
|
client/.venv/
|
|
74
|
+
|
|
75
|
+
# RememberFS local native build products (source and lockfiles remain tracked).
|
|
76
|
+
rememberfs/target/
|
|
77
|
+
experiments/rememberfs/rust-spike/target/
|
|
78
|
+
experiments/rememberfs/go-spike/rememberfs-go-spike
|
remember-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: remember
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Official Python client for the remember.dev managed memory service.
|
|
5
|
+
Project-URL: Homepage, https://remember.dev
|
|
6
|
+
Project-URL: Documentation, https://remember.dev/docs
|
|
7
|
+
Project-URL: Source, https://github.com/writeitai/ultimate-memory-cloud
|
|
8
|
+
Author-email: "WriteIt.ai s.r.o." <info@writeit.ai>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Keywords: agents,memory,remember.dev,rememberstack
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: httpx>=0.27
|
|
19
|
+
Requires-Dist: rememberstack>=0.8.1
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# remember
|
|
23
|
+
|
|
24
|
+
Official Python SDK for the [remember.dev](https://remember.dev) managed memory service.
|
|
25
|
+
|
|
26
|
+
This distribution provides:
|
|
27
|
+
- **`remember.Client`** (D65): The primary ergonomic client for memory operations. Connects directly to your dedicated tenant deployment ingress with a single deployment API token (`umc_dp_…`).
|
|
28
|
+
- **`remember.CloudClient`** (D53): The control-plane client for checking deployment readiness, credit balances, and spend gates using a control-plane token (`umc_cp_…`).
|
|
29
|
+
- **`remember-status`**: CLI tool for quick control-plane status checks.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
pip install remember
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This automatically installs `rememberstack` (which provides the `remember` CLI tool on `PATH`).
|
|
38
|
+
|
|
39
|
+
## Quickstart: Memory Operations (`Client`)
|
|
40
|
+
|
|
41
|
+
Mint an **API Token** (`umc_dp_…`) from your dashboard at **Settings → API Tokens**, then initialize `Client`:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import remember
|
|
45
|
+
|
|
46
|
+
# Client accepts a bare secret (umc_dp_...) or a full Bearer string,
|
|
47
|
+
# and converts string file paths automatically:
|
|
48
|
+
with remember.Client(
|
|
49
|
+
api_key="umc_dp_…",
|
|
50
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
51
|
+
) as memory:
|
|
52
|
+
landed = memory.ingest("notes/project.md")
|
|
53
|
+
print("Ingested version:", landed.version_id)
|
|
54
|
+
|
|
55
|
+
# Search claims or chunks
|
|
56
|
+
claims = memory.search_claims(query="architecture decisions")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Environment Variables
|
|
60
|
+
|
|
61
|
+
For zero-config agent setups, set `REMEMBER_API_KEY` and `REMEMBER_API_URL`:
|
|
62
|
+
|
|
63
|
+
```console
|
|
64
|
+
export REMEMBER_API_URL="https://<deployment-id>.dp.remember.dev"
|
|
65
|
+
export REMEMBER_API_KEY="umc_dp_…"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import remember
|
|
70
|
+
|
|
71
|
+
with remember.Client.from_env() as memory:
|
|
72
|
+
landed = memory.ingest("notes/project.md")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`Client` also automatically falls back to `REMEMBERSTACK_API_AUTHORIZATION` and `REMEMBERSTACK_API_URL` for seamless compatibility.
|
|
76
|
+
|
|
77
|
+
## Quickstart: Status & Balances (`CloudClient`)
|
|
78
|
+
|
|
79
|
+
To check billing balance and deployment readiness in CI or monitoring bots, use `CloudClient` with an organisation-scoped control-plane token (`umc_cp_…`).
|
|
80
|
+
|
|
81
|
+
Control tokens are read-only, expiring status credentials (D53/D65). Because they are an API-only operational surface, mint one via the control-plane endpoint while authenticated with an owner session:
|
|
82
|
+
- **Endpoint**: `POST /app/api/v1/orgs/{org_id}/control-tokens` (or `POST /v1/orgs/{org_id}/control-tokens` against the direct control-plane URL).
|
|
83
|
+
- **Body**: `{"label": "ci-monitor", "expires_in_days": 90}` (accepts `label` and optional `expires_in_days` up to 90).
|
|
84
|
+
|
|
85
|
+
```console
|
|
86
|
+
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
87
|
+
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from remember import CloudClient
|
|
92
|
+
|
|
93
|
+
with CloudClient.from_env() as cloud:
|
|
94
|
+
if cloud.is_ready():
|
|
95
|
+
print("Balance:", cloud.billing_status().balance)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can also run the status CLI:
|
|
99
|
+
|
|
100
|
+
```console
|
|
101
|
+
$ remember-status
|
|
102
|
+
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
103
|
+
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
104
|
+
billing active balance 42.10
|
|
105
|
+
spend allow
|
|
106
|
+
```
|
remember-0.3.0/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# remember
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [remember.dev](https://remember.dev) managed memory service.
|
|
4
|
+
|
|
5
|
+
This distribution provides:
|
|
6
|
+
- **`remember.Client`** (D65): The primary ergonomic client for memory operations. Connects directly to your dedicated tenant deployment ingress with a single deployment API token (`umc_dp_…`).
|
|
7
|
+
- **`remember.CloudClient`** (D53): The control-plane client for checking deployment readiness, credit balances, and spend gates using a control-plane token (`umc_cp_…`).
|
|
8
|
+
- **`remember-status`**: CLI tool for quick control-plane status checks.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
pip install remember
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This automatically installs `rememberstack` (which provides the `remember` CLI tool on `PATH`).
|
|
17
|
+
|
|
18
|
+
## Quickstart: Memory Operations (`Client`)
|
|
19
|
+
|
|
20
|
+
Mint an **API Token** (`umc_dp_…`) from your dashboard at **Settings → API Tokens**, then initialize `Client`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import remember
|
|
24
|
+
|
|
25
|
+
# Client accepts a bare secret (umc_dp_...) or a full Bearer string,
|
|
26
|
+
# and converts string file paths automatically:
|
|
27
|
+
with remember.Client(
|
|
28
|
+
api_key="umc_dp_…",
|
|
29
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
30
|
+
) as memory:
|
|
31
|
+
landed = memory.ingest("notes/project.md")
|
|
32
|
+
print("Ingested version:", landed.version_id)
|
|
33
|
+
|
|
34
|
+
# Search claims or chunks
|
|
35
|
+
claims = memory.search_claims(query="architecture decisions")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Environment Variables
|
|
39
|
+
|
|
40
|
+
For zero-config agent setups, set `REMEMBER_API_KEY` and `REMEMBER_API_URL`:
|
|
41
|
+
|
|
42
|
+
```console
|
|
43
|
+
export REMEMBER_API_URL="https://<deployment-id>.dp.remember.dev"
|
|
44
|
+
export REMEMBER_API_KEY="umc_dp_…"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import remember
|
|
49
|
+
|
|
50
|
+
with remember.Client.from_env() as memory:
|
|
51
|
+
landed = memory.ingest("notes/project.md")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`Client` also automatically falls back to `REMEMBERSTACK_API_AUTHORIZATION` and `REMEMBERSTACK_API_URL` for seamless compatibility.
|
|
55
|
+
|
|
56
|
+
## Quickstart: Status & Balances (`CloudClient`)
|
|
57
|
+
|
|
58
|
+
To check billing balance and deployment readiness in CI or monitoring bots, use `CloudClient` with an organisation-scoped control-plane token (`umc_cp_…`).
|
|
59
|
+
|
|
60
|
+
Control tokens are read-only, expiring status credentials (D53/D65). Because they are an API-only operational surface, mint one via the control-plane endpoint while authenticated with an owner session:
|
|
61
|
+
- **Endpoint**: `POST /app/api/v1/orgs/{org_id}/control-tokens` (or `POST /v1/orgs/{org_id}/control-tokens` against the direct control-plane URL).
|
|
62
|
+
- **Body**: `{"label": "ci-monitor", "expires_in_days": 90}` (accepts `label` and optional `expires_in_days` up to 90).
|
|
63
|
+
|
|
64
|
+
```console
|
|
65
|
+
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
66
|
+
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from remember import CloudClient
|
|
71
|
+
|
|
72
|
+
with CloudClient.from_env() as cloud:
|
|
73
|
+
if cloud.is_ready():
|
|
74
|
+
print("Balance:", cloud.billing_status().balance)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
You can also run the status CLI:
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
$ remember-status
|
|
81
|
+
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
82
|
+
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
83
|
+
billing active balance 42.10
|
|
84
|
+
spend allow
|
|
85
|
+
```
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "remember"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Official Python client for the remember.dev managed memory service."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = { text = "Apache-2.0" }
|
|
@@ -20,9 +20,9 @@ classifiers = [
|
|
|
20
20
|
"Typing :: Typed",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
-
# D43 rule 1: the cloud distribution
|
|
24
|
-
#
|
|
25
|
-
#
|
|
23
|
+
# D43 rule 1 & D65: the cloud distribution depends on rememberstack for the core
|
|
24
|
+
# memory client and engine wire models. This package exposes the ergonomic Client
|
|
25
|
+
# facade for data-plane memory operations and CloudClient for control-plane queries.
|
|
26
26
|
dependencies = [
|
|
27
27
|
"httpx>=0.27",
|
|
28
28
|
"rememberstack>=0.8.1",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Python client library for the remember.dev managed memory service (D65).
|
|
2
|
+
|
|
3
|
+
PyPI project **`remember`**, import name **`remember`**.
|
|
4
|
+
|
|
5
|
+
What this package provides
|
|
6
|
+
--------------------------
|
|
7
|
+
|
|
8
|
+
1. **`Client`** (D65):
|
|
9
|
+
The primary developer memory client. Accepts a single deployment API token
|
|
10
|
+
(``umc_dp_…``) or bare secret, connects directly to tenant deployment ingress,
|
|
11
|
+
and provides ergonomic access to all memory operations (ingest, search,
|
|
12
|
+
pipeline readiness, and assured operations).
|
|
13
|
+
|
|
14
|
+
import remember
|
|
15
|
+
|
|
16
|
+
with remember.Client(
|
|
17
|
+
api_key="umc_dp_…",
|
|
18
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
19
|
+
) as memory:
|
|
20
|
+
landed = memory.ingest("guide.pdf")
|
|
21
|
+
|
|
22
|
+
Or zero-config from environment variables (``REMEMBER_API_KEY`` and ``REMEMBER_API_URL``):
|
|
23
|
+
|
|
24
|
+
memory = remember.Client.from_env()
|
|
25
|
+
|
|
26
|
+
2. **`CloudClient`** (D53):
|
|
27
|
+
The control-plane client. Uses an organisation-scoped control-plane token
|
|
28
|
+
(``umc_cp_…``) to inspect deployment readiness, credit balance, and spend gates.
|
|
29
|
+
|
|
30
|
+
from remember import CloudClient
|
|
31
|
+
|
|
32
|
+
with CloudClient.from_env() as cloud:
|
|
33
|
+
status = cloud.billing_status()
|
|
34
|
+
print(status.state, status.balance)
|
|
35
|
+
|
|
36
|
+
3. **Core Re-exports**:
|
|
37
|
+
Typed models and errors (:class:`Envelope`, :class:`ContextBundleV1`,
|
|
38
|
+
:class:`IngestedVersion`, :class:`ReadinessRequirements`, :class:`MemoryApiError`)
|
|
39
|
+
are re-exported directly from ``remember`` for convenient typing.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from rememberstack.client import MemoryApiError
|
|
43
|
+
from rememberstack.client import ReadinessRequirements
|
|
44
|
+
from rememberstack.model import ContextBundleV1
|
|
45
|
+
from rememberstack.model import Envelope
|
|
46
|
+
from rememberstack.model import IngestedVersion
|
|
47
|
+
|
|
48
|
+
from remember.client import Client
|
|
49
|
+
from remember.client import CloudClient
|
|
50
|
+
from remember.errors import CloudError
|
|
51
|
+
from remember.errors import NotPermitted
|
|
52
|
+
from remember.errors import RateLimited
|
|
53
|
+
from remember.errors import Unauthenticated
|
|
54
|
+
from remember.models import BillingStatus
|
|
55
|
+
from remember.models import Deployment
|
|
56
|
+
from remember.models import LedgerEntry
|
|
57
|
+
from remember.models import SpendGate
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"BillingStatus",
|
|
61
|
+
"Client",
|
|
62
|
+
"CloudClient",
|
|
63
|
+
"CloudError",
|
|
64
|
+
"ContextBundleV1",
|
|
65
|
+
"Deployment",
|
|
66
|
+
"Envelope",
|
|
67
|
+
"IngestedVersion",
|
|
68
|
+
"LedgerEntry",
|
|
69
|
+
"MemoryApiError",
|
|
70
|
+
"NotPermitted",
|
|
71
|
+
"RateLimited",
|
|
72
|
+
"ReadinessRequirements",
|
|
73
|
+
"SpendGate",
|
|
74
|
+
"Unauthenticated",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
__version__ = "0.3.0"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
"""The
|
|
1
|
+
"""The remember.dev clients.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
- :class:`Client`: Ergonomic memory client connecting directly to tenant deployment
|
|
4
|
+
ingress for memory storage and retrieval (D65).
|
|
5
|
+
- :class:`CloudClient`: Control-plane client for organisation status, deployment
|
|
6
|
+
inspection, and billing balances (D53).
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from __future__ import annotations
|
|
@@ -10,11 +11,18 @@ from __future__ import annotations
|
|
|
10
11
|
from collections.abc import Iterator
|
|
11
12
|
from collections.abc import Mapping
|
|
12
13
|
from contextlib import contextmanager
|
|
14
|
+
from datetime import datetime
|
|
13
15
|
import os
|
|
16
|
+
from pathlib import Path
|
|
14
17
|
from types import TracebackType
|
|
15
18
|
from typing import Any
|
|
19
|
+
from typing import Literal
|
|
20
|
+
from typing import Self
|
|
16
21
|
|
|
17
22
|
import httpx
|
|
23
|
+
from rememberstack.client import ClientSettings
|
|
24
|
+
from rememberstack.client import MemoryClient
|
|
25
|
+
from rememberstack.model.documents import IngestedVersion
|
|
18
26
|
|
|
19
27
|
from remember.errors import CloudError
|
|
20
28
|
from remember.errors import NotPermitted
|
|
@@ -34,6 +42,156 @@ TOKEN_ENV = "REMEMBER_CLOUD_TOKEN"
|
|
|
34
42
|
ORG_ENV = "REMEMBER_CLOUD_ORG"
|
|
35
43
|
BASE_URL_ENV = "REMEMBER_CLOUD_URL"
|
|
36
44
|
|
|
45
|
+
#: Environment variables for the unified data-plane client (D65).
|
|
46
|
+
API_KEY_ENV = "REMEMBER_API_KEY"
|
|
47
|
+
API_URL_ENV = "REMEMBER_API_URL"
|
|
48
|
+
REMEMBERSTACK_AUTH_ENV = "REMEMBERSTACK_API_AUTHORIZATION"
|
|
49
|
+
REMEMBERSTACK_URL_ENV = "REMEMBERSTACK_API_URL"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _format_bearer(token: str) -> str:
|
|
53
|
+
"""Ensure a token string has the standard Bearer header prefix."""
|
|
54
|
+
if not token or not token.strip():
|
|
55
|
+
raise ValueError("API key or authorization token cannot be empty")
|
|
56
|
+
if "\r" in token or "\n" in token:
|
|
57
|
+
raise ValueError("Authorization token must not contain newline characters")
|
|
58
|
+
cleaned = token.strip()
|
|
59
|
+
if cleaned.lower() == "bearer":
|
|
60
|
+
raise ValueError("Bearer token value cannot be empty")
|
|
61
|
+
if cleaned.lower().startswith("bearer "):
|
|
62
|
+
rest = cleaned[7:].strip()
|
|
63
|
+
if not rest:
|
|
64
|
+
raise ValueError("Bearer token value cannot be empty")
|
|
65
|
+
return f"Bearer {rest}"
|
|
66
|
+
return f"Bearer {cleaned}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Client(MemoryClient):
|
|
70
|
+
"""Ergonomic data-plane memory client for remember.dev (D65).
|
|
71
|
+
|
|
72
|
+
Subclasses :class:`rememberstack.client.MemoryClient`, providing:
|
|
73
|
+
- ``api_key`` parameter accepting bare secrets (``umc_dp_...``) or full
|
|
74
|
+
``Bearer`` headers.
|
|
75
|
+
- Path string support in :meth:`ingest` (accepts ``str``, ``Path``, or ``bytes``).
|
|
76
|
+
- Environment configuration from ``REMEMBER_API_KEY`` and ``REMEMBER_API_URL``
|
|
77
|
+
with fallbacks to ``REMEMBERSTACK_API_AUTHORIZATION`` and ``REMEMBERSTACK_API_URL``.
|
|
78
|
+
- Direct connection to deployment ingress (queries are never proxied through
|
|
79
|
+
the control plane).
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
*,
|
|
85
|
+
api_key: str | None = None,
|
|
86
|
+
base_url: str | None = None,
|
|
87
|
+
authorization: str | None = None,
|
|
88
|
+
client: httpx.Client | None = None,
|
|
89
|
+
timeout: float | None = None,
|
|
90
|
+
settings: ClientSettings | None = None,
|
|
91
|
+
) -> None:
|
|
92
|
+
if client is not None and any(
|
|
93
|
+
value is not None
|
|
94
|
+
for value in (api_key, base_url, authorization, timeout, settings)
|
|
95
|
+
):
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"an injected client cannot be combined with client settings"
|
|
98
|
+
)
|
|
99
|
+
if client is not None:
|
|
100
|
+
super().__init__(client=client)
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
resolved_authorization: str | None = None
|
|
104
|
+
if api_key is not None:
|
|
105
|
+
resolved_authorization = _format_bearer(api_key)
|
|
106
|
+
elif authorization is not None:
|
|
107
|
+
resolved_authorization = authorization
|
|
108
|
+
elif settings is not None and settings.api_authorization is not None:
|
|
109
|
+
resolved_authorization = settings.api_authorization.get_secret_value()
|
|
110
|
+
elif os.getenv(API_KEY_ENV):
|
|
111
|
+
resolved_authorization = _format_bearer(os.environ[API_KEY_ENV])
|
|
112
|
+
elif os.getenv(REMEMBERSTACK_AUTH_ENV):
|
|
113
|
+
resolved_authorization = os.environ[REMEMBERSTACK_AUTH_ENV]
|
|
114
|
+
|
|
115
|
+
resolved_base_url: str | None = None
|
|
116
|
+
if base_url is not None:
|
|
117
|
+
resolved_base_url = base_url
|
|
118
|
+
elif settings is not None and settings.api_url:
|
|
119
|
+
resolved_base_url = settings.api_url
|
|
120
|
+
elif os.getenv(API_URL_ENV):
|
|
121
|
+
resolved_base_url = os.environ[API_URL_ENV]
|
|
122
|
+
elif os.getenv(REMEMBERSTACK_URL_ENV):
|
|
123
|
+
resolved_base_url = os.environ[REMEMBERSTACK_URL_ENV]
|
|
124
|
+
|
|
125
|
+
super().__init__(
|
|
126
|
+
base_url=resolved_base_url,
|
|
127
|
+
authorization=resolved_authorization,
|
|
128
|
+
timeout=timeout,
|
|
129
|
+
settings=settings,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_env(cls, **overrides: Any) -> Self:
|
|
134
|
+
"""Build from environment variables with keyword argument overrides."""
|
|
135
|
+
return cls(**overrides)
|
|
136
|
+
|
|
137
|
+
def ingest(
|
|
138
|
+
self,
|
|
139
|
+
source: str | Path | bytes,
|
|
140
|
+
*,
|
|
141
|
+
filename: str | None = None,
|
|
142
|
+
mime: str | None = None,
|
|
143
|
+
title: str | None = None,
|
|
144
|
+
source_kind: str | None = None,
|
|
145
|
+
source_ref: str | None = None,
|
|
146
|
+
source_modified_at: datetime | None = None,
|
|
147
|
+
versioning_mode: Literal["snapshot", "living"] = "snapshot",
|
|
148
|
+
source_version_ref: str | None = None,
|
|
149
|
+
) -> IngestedVersion:
|
|
150
|
+
"""Ingest a document from a file path, string path, or raw bytes."""
|
|
151
|
+
resolved_source = Path(source) if isinstance(source, str) else source
|
|
152
|
+
return super().ingest(
|
|
153
|
+
resolved_source,
|
|
154
|
+
filename=filename,
|
|
155
|
+
mime=mime,
|
|
156
|
+
title=title,
|
|
157
|
+
source_kind=source_kind,
|
|
158
|
+
source_ref=source_ref,
|
|
159
|
+
source_modified_at=source_modified_at,
|
|
160
|
+
versioning_mode=versioning_mode,
|
|
161
|
+
source_version_ref=source_version_ref,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def ingest_file(
|
|
165
|
+
self,
|
|
166
|
+
file_path: str | Path,
|
|
167
|
+
*,
|
|
168
|
+
filename: str | None = None,
|
|
169
|
+
mime: str | None = None,
|
|
170
|
+
title: str | None = None,
|
|
171
|
+
source_kind: str | None = None,
|
|
172
|
+
source_ref: str | None = None,
|
|
173
|
+
source_modified_at: datetime | None = None,
|
|
174
|
+
versioning_mode: Literal["snapshot", "living"] = "snapshot",
|
|
175
|
+
source_version_ref: str | None = None,
|
|
176
|
+
) -> IngestedVersion:
|
|
177
|
+
"""Alias for :meth:`ingest` accepting a string file path or :class:`pathlib.Path`."""
|
|
178
|
+
return self.ingest(
|
|
179
|
+
file_path,
|
|
180
|
+
filename=filename,
|
|
181
|
+
mime=mime,
|
|
182
|
+
title=title,
|
|
183
|
+
source_kind=source_kind,
|
|
184
|
+
source_ref=source_ref,
|
|
185
|
+
source_modified_at=source_modified_at,
|
|
186
|
+
versioning_mode=versioning_mode,
|
|
187
|
+
source_version_ref=source_version_ref,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
def __enter__(self) -> Self:
|
|
191
|
+
"""Support ``with Client(...) as memory:`` returning Self."""
|
|
192
|
+
super().__enter__()
|
|
193
|
+
return self
|
|
194
|
+
|
|
37
195
|
|
|
38
196
|
class CloudClient:
|
|
39
197
|
"""Ask the control plane what it knows about one organisation.
|
|
@@ -67,7 +225,7 @@ class CloudClient:
|
|
|
67
225
|
)
|
|
68
226
|
|
|
69
227
|
@classmethod
|
|
70
|
-
def from_env(cls, **overrides: Any) ->
|
|
228
|
+
def from_env(cls, **overrides: Any) -> Self:
|
|
71
229
|
"""Build from ``REMEMBER_CLOUD_TOKEN`` / ``_ORG`` / ``_URL``.
|
|
72
230
|
|
|
73
231
|
The usual shape for an agent: credentials in the environment, nothing in
|
|
@@ -168,7 +326,7 @@ class CloudClient:
|
|
|
168
326
|
"""Release the underlying connection pool."""
|
|
169
327
|
self._http.close()
|
|
170
328
|
|
|
171
|
-
def __enter__(self) ->
|
|
329
|
+
def __enter__(self) -> Self:
|
|
172
330
|
"""Support ``with CloudClient(...) as cloud:``."""
|
|
173
331
|
return self
|
|
174
332
|
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Tests for remember.Client facade (D65)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
from pydantic import SecretStr
|
|
9
|
+
import pytest
|
|
10
|
+
import remember
|
|
11
|
+
from remember import Client
|
|
12
|
+
from remember.client import _format_bearer
|
|
13
|
+
from rememberstack.client import ClientSettings
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_format_bearer() -> None:
|
|
17
|
+
assert _format_bearer("umc_dp_secret") == "Bearer umc_dp_secret"
|
|
18
|
+
assert _format_bearer("Bearer umc_dp_secret") == "Bearer umc_dp_secret"
|
|
19
|
+
assert _format_bearer("bearer umc_dp_secret") == "Bearer umc_dp_secret"
|
|
20
|
+
assert _format_bearer(" Bearer umc_dp_secret ") == "Bearer umc_dp_secret"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_format_bearer_validation() -> None:
|
|
24
|
+
with pytest.raises(ValueError, match="cannot be empty"):
|
|
25
|
+
_format_bearer("")
|
|
26
|
+
with pytest.raises(ValueError, match="cannot be empty"):
|
|
27
|
+
_format_bearer(" ")
|
|
28
|
+
with pytest.raises(ValueError, match="cannot be empty"):
|
|
29
|
+
_format_bearer("Bearer")
|
|
30
|
+
with pytest.raises(ValueError, match="cannot be empty"):
|
|
31
|
+
_format_bearer("Bearer ")
|
|
32
|
+
with pytest.raises(ValueError, match="newline"):
|
|
33
|
+
_format_bearer("umc_dp_key\r\n")
|
|
34
|
+
with pytest.raises(ValueError, match="newline"):
|
|
35
|
+
_format_bearer("Bearer secret\n")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_client_bare_api_key_formats_bearer() -> None:
|
|
39
|
+
client = Client(api_key="umc_dp_12345", base_url="https://dp.test")
|
|
40
|
+
auth_header = client._client.headers.get("Authorization")
|
|
41
|
+
assert auth_header == "Bearer umc_dp_12345"
|
|
42
|
+
assert str(client._client.base_url) == "https://dp.test"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_client_api_key_with_bearer_prefix() -> None:
|
|
46
|
+
client = Client(api_key="Bearer umc_dp_12345", base_url="https://dp.test")
|
|
47
|
+
auth_header = client._client.headers.get("Authorization")
|
|
48
|
+
assert auth_header == "Bearer umc_dp_12345"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_client_api_key_takes_precedence_over_authorization() -> None:
|
|
52
|
+
client = Client(
|
|
53
|
+
api_key="umc_dp_primary",
|
|
54
|
+
authorization="Bearer umc_dp_fallback",
|
|
55
|
+
base_url="https://dp.test",
|
|
56
|
+
)
|
|
57
|
+
assert client._client.headers.get("Authorization") == "Bearer umc_dp_primary"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_client_env_var_resolution(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
61
|
+
monkeypatch.setenv("REMEMBER_API_KEY", "umc_dp_from_env")
|
|
62
|
+
monkeypatch.setenv("REMEMBER_API_URL", "https://env.dp.remember.dev")
|
|
63
|
+
# Fallbacks that must be overridden
|
|
64
|
+
monkeypatch.setenv("REMEMBERSTACK_API_AUTHORIZATION", "Bearer rs_auth")
|
|
65
|
+
monkeypatch.setenv("REMEMBERSTACK_API_URL", "https://rs.dp.remember.dev")
|
|
66
|
+
|
|
67
|
+
client = Client.from_env()
|
|
68
|
+
assert client._client.headers.get("Authorization") == "Bearer umc_dp_from_env"
|
|
69
|
+
assert str(client._client.base_url) == "https://env.dp.remember.dev"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_client_falls_back_to_rememberstack_env(
|
|
73
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
74
|
+
) -> None:
|
|
75
|
+
monkeypatch.delenv("REMEMBER_API_KEY", raising=False)
|
|
76
|
+
monkeypatch.delenv("REMEMBER_API_URL", raising=False)
|
|
77
|
+
monkeypatch.setenv("REMEMBERSTACK_API_AUTHORIZATION", "Bearer rs_auth")
|
|
78
|
+
monkeypatch.setenv("REMEMBERSTACK_API_URL", "https://rs.dp.remember.dev")
|
|
79
|
+
|
|
80
|
+
client = Client.from_env()
|
|
81
|
+
assert client._client.headers.get("Authorization") == "Bearer rs_auth"
|
|
82
|
+
assert str(client._client.base_url) == "https://rs.dp.remember.dev"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_client_explicit_settings_overrides_env(
|
|
86
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
87
|
+
) -> None:
|
|
88
|
+
monkeypatch.setenv("REMEMBER_API_KEY", "umc_dp_ambient")
|
|
89
|
+
monkeypatch.setenv("REMEMBER_API_URL", "https://ambient.dp.remember.dev")
|
|
90
|
+
|
|
91
|
+
settings = ClientSettings(
|
|
92
|
+
api_url="https://settings.dp.remember.dev",
|
|
93
|
+
api_authorization=SecretStr("Bearer rs_settings_auth"),
|
|
94
|
+
)
|
|
95
|
+
client = Client(settings=settings)
|
|
96
|
+
assert client._client.headers.get("Authorization") == "Bearer rs_settings_auth"
|
|
97
|
+
assert str(client._client.base_url) == "https://settings.dp.remember.dev"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_client_ignores_cloud_token_and_org(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
101
|
+
monkeypatch.delenv("REMEMBER_API_KEY", raising=False)
|
|
102
|
+
monkeypatch.delenv("REMEMBER_API_URL", raising=False)
|
|
103
|
+
monkeypatch.delenv("REMEMBERSTACK_API_AUTHORIZATION", raising=False)
|
|
104
|
+
monkeypatch.delenv("REMEMBERSTACK_API_URL", raising=False)
|
|
105
|
+
monkeypatch.setenv("REMEMBER_CLOUD_TOKEN", "umc_cp_secret")
|
|
106
|
+
monkeypatch.setenv("REMEMBER_CLOUD_ORG", "some-org-id")
|
|
107
|
+
|
|
108
|
+
# Client must NOT pick up control-plane tokens
|
|
109
|
+
client = Client.from_env()
|
|
110
|
+
assert client._client.headers.get("Authorization") is None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_client_injected_client_refuses_settings() -> None:
|
|
114
|
+
mock_http = httpx.Client()
|
|
115
|
+
with pytest.raises(ValueError, match="injected client cannot be combined"):
|
|
116
|
+
Client(client=mock_http, api_key="umc_dp_test")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_client_ingest_string_path(tmp_path: Path) -> None:
|
|
120
|
+
test_file = tmp_path / "sample.txt"
|
|
121
|
+
test_file.write_text("hello memory")
|
|
122
|
+
|
|
123
|
+
seen_request: dict[str, str] = {}
|
|
124
|
+
|
|
125
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
126
|
+
seen_request["path"] = request.url.path
|
|
127
|
+
seen_request["filename"] = request.url.params.get("filename", "")
|
|
128
|
+
seen_request["mime"] = request.url.params.get("mime", "")
|
|
129
|
+
seen_request["content"] = request.content.decode()
|
|
130
|
+
return httpx.Response(
|
|
131
|
+
200,
|
|
132
|
+
json={
|
|
133
|
+
"deployment_id": "00000000-0000-0000-0000-000000000000",
|
|
134
|
+
"doc_id": "11111111-1111-1111-1111-111111111111",
|
|
135
|
+
"version_id": "22222222-2222-2222-2222-222222222222",
|
|
136
|
+
"content_hash": "sha256:abcd",
|
|
137
|
+
"created": True,
|
|
138
|
+
},
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
mock_client = httpx.Client(
|
|
142
|
+
base_url="https://dp.test", transport=httpx.MockTransport(handler)
|
|
143
|
+
)
|
|
144
|
+
with Client(client=mock_client) as memory:
|
|
145
|
+
landed = memory.ingest(str(test_file))
|
|
146
|
+
|
|
147
|
+
assert seen_request["path"] == "/ingest"
|
|
148
|
+
assert seen_request["filename"] == "sample.txt"
|
|
149
|
+
assert seen_request["mime"] == "text/plain"
|
|
150
|
+
assert seen_request["content"] == "hello memory"
|
|
151
|
+
assert str(landed.version_id) == "22222222-2222-2222-2222-222222222222"
|
|
152
|
+
assert landed.created is True
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_client_ingest_file_alias(tmp_path: Path) -> None:
|
|
156
|
+
test_file = tmp_path / "doc.md"
|
|
157
|
+
test_file.write_text("# Doc\n\nContent here.")
|
|
158
|
+
|
|
159
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
160
|
+
return httpx.Response(
|
|
161
|
+
200,
|
|
162
|
+
json={
|
|
163
|
+
"deployment_id": "00000000-0000-0000-0000-000000000000",
|
|
164
|
+
"doc_id": "11111111-1111-1111-1111-111111111111",
|
|
165
|
+
"version_id": "22222222-2222-2222-2222-222222222222",
|
|
166
|
+
"content_hash": "sha256:abcd",
|
|
167
|
+
"created": True,
|
|
168
|
+
},
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
mock_client = httpx.Client(
|
|
172
|
+
base_url="https://dp.test", transport=httpx.MockTransport(handler)
|
|
173
|
+
)
|
|
174
|
+
with Client(client=mock_client) as memory:
|
|
175
|
+
# String path
|
|
176
|
+
landed_str = memory.ingest_file(str(test_file))
|
|
177
|
+
assert landed_str.created is True
|
|
178
|
+
|
|
179
|
+
# Path object
|
|
180
|
+
landed_path = memory.ingest_file(test_file)
|
|
181
|
+
assert landed_path.created is True
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_top_level_exports() -> None:
|
|
185
|
+
assert hasattr(remember, "Client")
|
|
186
|
+
assert hasattr(remember, "CloudClient")
|
|
187
|
+
assert hasattr(remember, "Envelope")
|
|
188
|
+
assert hasattr(remember, "ContextBundleV1")
|
|
189
|
+
assert hasattr(remember, "IngestedVersion")
|
|
190
|
+
assert hasattr(remember, "MemoryApiError")
|
|
191
|
+
assert hasattr(remember, "ReadinessRequirements")
|
|
192
|
+
assert hasattr(remember, "BillingStatus")
|
|
193
|
+
assert hasattr(remember, "Deployment")
|
|
194
|
+
assert hasattr(remember, "LedgerEntry")
|
|
195
|
+
assert hasattr(remember, "SpendGate")
|
remember-0.2.0/PKG-INFO
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: remember
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: Control-plane client for the remember.dev managed memory service.
|
|
5
|
-
Project-URL: Homepage, https://remember.dev
|
|
6
|
-
Project-URL: Documentation, https://remember.dev/docs
|
|
7
|
-
Project-URL: Source, https://github.com/writeitai/ultimate-memory-cloud
|
|
8
|
-
Author-email: "WriteIt.ai s.r.o." <info@writeit.ai>
|
|
9
|
-
License: Apache-2.0
|
|
10
|
-
Keywords: agents,memory,remember.dev,rememberstack
|
|
11
|
-
Classifier: Development Status :: 3 - Alpha
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Classifier: Typing :: Typed
|
|
17
|
-
Requires-Python: >=3.12
|
|
18
|
-
Requires-Dist: httpx>=0.27
|
|
19
|
-
Requires-Dist: rememberstack>=0.8.1
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
|
-
# remember
|
|
23
|
-
|
|
24
|
-
Control-plane client for the [remember.dev](https://remember.dev) managed memory service.
|
|
25
|
-
|
|
26
|
-
`rememberstack` answers *memory* questions — ingest a document, search claims, run an assured
|
|
27
|
-
operation. This package answers the questions an operator of that memory also has:
|
|
28
|
-
|
|
29
|
-
- is my deployment ready?
|
|
30
|
-
- what is my balance, and what did that ingest cost?
|
|
31
|
-
- has spend safety parked my work?
|
|
32
|
-
|
|
33
|
-
```python
|
|
34
|
-
from remember import CloudClient
|
|
35
|
-
|
|
36
|
-
with CloudClient.from_env() as cloud:
|
|
37
|
-
if cloud.is_ready():
|
|
38
|
-
print(cloud.billing_status().balance)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```console
|
|
42
|
-
$ remember-status
|
|
43
|
-
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
44
|
-
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
45
|
-
billing active balance 42.10
|
|
46
|
-
spend allow
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Install
|
|
50
|
-
|
|
51
|
-
```console
|
|
52
|
-
pip install remember
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
This installs `rememberstack` too. The `remember` **command** comes from that package and is
|
|
56
|
-
unaffected by this one; this distribution adds only `remember-status`.
|
|
57
|
-
|
|
58
|
-
## Credentials
|
|
59
|
-
|
|
60
|
-
This client authenticates with a **control-plane token** (`umc_cp_…`) — the D53 credential kind.
|
|
61
|
-
It is not the same thing as a deployment API token (`umc_dp_…`): that one authenticates *memory*
|
|
62
|
-
calls at the deployment's ingress and will be rejected here.
|
|
63
|
-
|
|
64
|
-
Mint one with `POST /v1/orgs/<org>/control-tokens` while signed in to the app. There is no button
|
|
65
|
-
for this yet — the API landed before the interface did — so today it is a call, not a click:
|
|
66
|
-
|
|
67
|
-
```console
|
|
68
|
-
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
69
|
-
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The secret is shown once. The credential is organisation-scoped, **read-only**, expires (90 days by
|
|
73
|
-
default), and can be surrendered by its holder at any time.
|
|
74
|
-
|
|
75
|
-
## What it will not do
|
|
76
|
-
|
|
77
|
-
No memory verbs, no second ingest or search contract. To *use* the memory, use `rememberstack`
|
|
78
|
-
pointed at your deployment; this package tells you what that memory costs and whether it is ready.
|
remember-0.2.0/README.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# remember
|
|
2
|
-
|
|
3
|
-
Control-plane client for the [remember.dev](https://remember.dev) managed memory service.
|
|
4
|
-
|
|
5
|
-
`rememberstack` answers *memory* questions — ingest a document, search claims, run an assured
|
|
6
|
-
operation. This package answers the questions an operator of that memory also has:
|
|
7
|
-
|
|
8
|
-
- is my deployment ready?
|
|
9
|
-
- what is my balance, and what did that ingest cost?
|
|
10
|
-
- has spend safety parked my work?
|
|
11
|
-
|
|
12
|
-
```python
|
|
13
|
-
from remember import CloudClient
|
|
14
|
-
|
|
15
|
-
with CloudClient.from_env() as cloud:
|
|
16
|
-
if cloud.is_ready():
|
|
17
|
-
print(cloud.billing_status().balance)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
```console
|
|
21
|
-
$ remember-status
|
|
22
|
-
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
23
|
-
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
24
|
-
billing active balance 42.10
|
|
25
|
-
spend allow
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Install
|
|
29
|
-
|
|
30
|
-
```console
|
|
31
|
-
pip install remember
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
This installs `rememberstack` too. The `remember` **command** comes from that package and is
|
|
35
|
-
unaffected by this one; this distribution adds only `remember-status`.
|
|
36
|
-
|
|
37
|
-
## Credentials
|
|
38
|
-
|
|
39
|
-
This client authenticates with a **control-plane token** (`umc_cp_…`) — the D53 credential kind.
|
|
40
|
-
It is not the same thing as a deployment API token (`umc_dp_…`): that one authenticates *memory*
|
|
41
|
-
calls at the deployment's ingress and will be rejected here.
|
|
42
|
-
|
|
43
|
-
Mint one with `POST /v1/orgs/<org>/control-tokens` while signed in to the app. There is no button
|
|
44
|
-
for this yet — the API landed before the interface did — so today it is a call, not a click:
|
|
45
|
-
|
|
46
|
-
```console
|
|
47
|
-
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
48
|
-
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
The secret is shown once. The credential is organisation-scoped, **read-only**, expires (90 days by
|
|
52
|
-
default), and can be surrendered by its holder at any time.
|
|
53
|
-
|
|
54
|
-
## What it will not do
|
|
55
|
-
|
|
56
|
-
No memory verbs, no second ingest or search contract. To *use* the memory, use `rememberstack`
|
|
57
|
-
pointed at your deployment; this package tells you what that memory costs and whether it is ready.
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"""Control-plane client for the remember.dev managed service.
|
|
2
|
-
|
|
3
|
-
PyPI project **`remember`**, import name **`remember`** (D43 left the import name
|
|
4
|
-
open and required the first publish to document it; this is that record). The
|
|
5
|
-
distribution installs **no** ``remember`` console script — that entry point
|
|
6
|
-
belongs to ``rememberstack`` alone, and two distributions competing for one name
|
|
7
|
-
on ``PATH`` is the collision D43 rule 3 forbids.
|
|
8
|
-
|
|
9
|
-
What this package is for
|
|
10
|
-
------------------------
|
|
11
|
-
|
|
12
|
-
``rememberstack`` answers *memory* questions: ingest a document, search claims,
|
|
13
|
-
run an assured operation. It cannot answer the questions an operator of that
|
|
14
|
-
memory also has —
|
|
15
|
-
|
|
16
|
-
* is my deployment ready?
|
|
17
|
-
* what is my balance, and what did that ingest cost?
|
|
18
|
-
* has spend safety parked my work?
|
|
19
|
-
|
|
20
|
-
Those live on the control plane, which until D53 accepted only a browser session
|
|
21
|
-
cookie. This client speaks to it with a **control-plane token** (``umc_cp_…``):
|
|
22
|
-
organisation-scoped, read-only, bounded lifetime, revocable by its bearer.
|
|
23
|
-
|
|
24
|
-
from remember import CloudClient
|
|
25
|
-
|
|
26
|
-
with CloudClient.from_env() as cloud:
|
|
27
|
-
status = cloud.billing_status()
|
|
28
|
-
print(status.state, status.balance)
|
|
29
|
-
|
|
30
|
-
Getting a credential
|
|
31
|
-
--------------------
|
|
32
|
-
|
|
33
|
-
A control-plane token is not a deployment API token: `umc_dp_…` authenticates
|
|
34
|
-
*memory* calls at a deployment's ingress and is rejected here. Mint one with
|
|
35
|
-
`POST /v1/orgs/<org>/control-tokens` while signed in to the app — there is no
|
|
36
|
-
button for it yet, the API landed before the interface did. Then:
|
|
37
|
-
|
|
38
|
-
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
39
|
-
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
40
|
-
|
|
41
|
-
The secret is shown once. `remember login` does not yet mint this kind — that
|
|
42
|
-
needs an amendment to the device grant (D40), tracked in D53 §6.
|
|
43
|
-
|
|
44
|
-
What it deliberately does not do
|
|
45
|
-
--------------------------------
|
|
46
|
-
|
|
47
|
-
No memory verbs. No second ingest, search, or envelope contract (D35). If you
|
|
48
|
-
want to *use* the memory, use ``rememberstack``; this package tells you what the
|
|
49
|
-
memory costs and whether it is ready.
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
from remember.client import CloudClient
|
|
53
|
-
from remember.errors import CloudError
|
|
54
|
-
from remember.errors import NotPermitted
|
|
55
|
-
from remember.errors import RateLimited
|
|
56
|
-
from remember.errors import Unauthenticated
|
|
57
|
-
from remember.models import BillingStatus
|
|
58
|
-
from remember.models import Deployment
|
|
59
|
-
from remember.models import LedgerEntry
|
|
60
|
-
from remember.models import SpendGate
|
|
61
|
-
|
|
62
|
-
__all__ = [
|
|
63
|
-
"BillingStatus",
|
|
64
|
-
"CloudClient",
|
|
65
|
-
"CloudError",
|
|
66
|
-
"Deployment",
|
|
67
|
-
"LedgerEntry",
|
|
68
|
-
"NotPermitted",
|
|
69
|
-
"RateLimited",
|
|
70
|
-
"SpendGate",
|
|
71
|
-
"Unauthenticated",
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
__version__ = "0.2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|