areev 0.0.0__py3-none-any.whl

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.
areev/__init__.py ADDED
@@ -0,0 +1,49 @@
1
+ """Areev Python SDK — client library for the Areev knowledge database."""
2
+
3
+ from areev.client import Areev, AsyncAreev
4
+ from areev.types import (
5
+ AddOptions,
6
+ AddRequest,
7
+ AddResponse,
8
+ AreevConfig,
9
+ AreevError,
10
+ GetResponse,
11
+ GrainType,
12
+ HealthResponse,
13
+ RecallRequest,
14
+ RecallResponse,
15
+ RememberRequest,
16
+ RememberResponse,
17
+ SearchHit,
18
+ StatsResponse,
19
+ SupersedeRequest,
20
+ SupersedeResponse,
21
+ )
22
+ from areev.http import HttpClient
23
+
24
+ __all__ = [
25
+ # High-level clients (recommended)
26
+ "Areev",
27
+ "AsyncAreev",
28
+ # Low-level async client
29
+ "HttpClient",
30
+ # Types
31
+ "AddOptions",
32
+ "AddRequest",
33
+ "AddResponse",
34
+ "AreevConfig",
35
+ "AreevError",
36
+ "GetResponse",
37
+ "GrainType",
38
+ "HealthResponse",
39
+ "RecallRequest",
40
+ "RecallResponse",
41
+ "RememberRequest",
42
+ "RememberResponse",
43
+ "SearchHit",
44
+ "StatsResponse",
45
+ "SupersedeRequest",
46
+ "SupersedeResponse",
47
+ ]
48
+
49
+ __version__ = "0.1.0"
areev/client.py ADDED
@@ -0,0 +1,219 @@
1
+ """High-level Areev client with minimal boilerplate."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from typing import Any
7
+
8
+ import httpx
9
+
10
+ from areev.types import (
11
+ AddResponse,
12
+ AreevError,
13
+ GetResponse,
14
+ GrainType,
15
+ HealthResponse,
16
+ RecallResponse,
17
+ RememberResponse,
18
+ StatsResponse,
19
+ SupersedeResponse,
20
+ )
21
+
22
+ _DEFAULT_URL = "https://app.areev.ai"
23
+ _DEFAULT_MEMORY = "default"
24
+
25
+
26
+ def _resolve(
27
+ api_key: str | None,
28
+ url: str | None,
29
+ memory_id: str | None,
30
+ ) -> tuple[str | None, str, str]:
31
+ return (
32
+ api_key or os.environ.get("AREEV_API_KEY"),
33
+ (url or os.environ.get("AREEV_URL", _DEFAULT_URL)).rstrip("/"),
34
+ memory_id or os.environ.get("AREEV_MEMORY_ID", _DEFAULT_MEMORY),
35
+ )
36
+
37
+
38
+ def _check(resp: httpx.Response) -> Any:
39
+ if resp.status_code >= 400:
40
+ raise AreevError(resp.status_code, resp.text)
41
+ if resp.status_code == 204 or not resp.content:
42
+ return None
43
+ return resp.json()
44
+
45
+
46
+ def _compact(d: dict) -> dict:
47
+ return {k: v for k, v in d.items() if v is not None}
48
+
49
+
50
+ class Areev:
51
+ """Synchronous Areev client.
52
+
53
+ Reads ``AREEV_API_KEY``, ``AREEV_URL``, and ``AREEV_MEMORY_ID`` from the
54
+ environment when no explicit values are provided.
55
+
56
+ Usage::
57
+
58
+ from areev import Areev
59
+
60
+ areev = Areev()
61
+ areev.remember("John likes coffee")
62
+ results = areev.recall("what does John like?")
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ *,
68
+ api_key: str | None = None,
69
+ url: str | None = None,
70
+ memory_id: str | None = None,
71
+ ) -> None:
72
+ key, self._url, self._memory_id = _resolve(api_key, url, memory_id)
73
+ headers: dict[str, str] = {}
74
+ if key:
75
+ headers["X-API-Key"] = key
76
+ self._http = httpx.Client(headers=headers)
77
+
78
+ def _path(self, endpoint: str) -> str:
79
+ return f"{self._url}/api/memories/{self._memory_id}/{endpoint}"
80
+
81
+ # -- Primary methods -----------------------------------------------
82
+
83
+ def remember(self, text: str, *, sync: bool = True, **kwargs: Any) -> RememberResponse:
84
+ """Store a natural-language memory. Returns extraction details."""
85
+ body = _compact({"text": text, "sync": sync, **kwargs})
86
+ return RememberResponse(**_check(self._http.post(self._path("remember"), json=body)))
87
+
88
+ def recall(self, query: str, *, limit: int = 10, **kwargs: Any) -> RecallResponse:
89
+ """Search memories. Returns matching grains."""
90
+ params = _compact({"query": query, "limit": limit, **kwargs})
91
+ return RecallResponse(**_check(self._http.get(self._path("recall"), params=params)))
92
+
93
+ def forget(self, hash: str) -> None:
94
+ """Delete a memory by hash."""
95
+ _check(self._http.delete(self._path(f"grains/{hash}")))
96
+
97
+ # -- Low-level methods ---------------------------------------------
98
+
99
+ def add(self, grain_type: str | GrainType, /, **fields: Any) -> str:
100
+ """Add a typed grain. Returns the grain hash."""
101
+ grain = grain_type.value if isinstance(grain_type, GrainType) else grain_type
102
+ body = _compact({"grain_type": grain, **fields})
103
+ return AddResponse(**_check(self._http.post(self._path("add"), json=body))).hash
104
+
105
+ def get(self, hash: str) -> GetResponse:
106
+ """Get a grain by hash."""
107
+ return GetResponse(**_check(self._http.get(self._path(f"grains/{hash}"))))
108
+
109
+ def supersede(self, old_hash: str, grain_type: str | GrainType, /, **fields: Any) -> str:
110
+ """Update a grain. Returns the new hash."""
111
+ grain = grain_type.value if isinstance(grain_type, GrainType) else grain_type
112
+ body = _compact({"old_hash": old_hash, "grain_type": grain, **fields})
113
+ return SupersedeResponse(**_check(self._http.post(self._path("supersede"), json=body))).new_hash
114
+
115
+ def health(self) -> HealthResponse:
116
+ """Health check."""
117
+ return HealthResponse(**_check(self._http.get(f"{self._url}/health")))
118
+
119
+ def stats(self) -> StatsResponse:
120
+ """Database statistics."""
121
+ return StatsResponse(**_check(self._http.get(self._path("stats"))))
122
+
123
+ def flush(self) -> None:
124
+ """Flush write buffer."""
125
+ _check(self._http.post(self._path("flush")))
126
+
127
+ # -- Lifecycle -----------------------------------------------------
128
+
129
+ def close(self) -> None:
130
+ """Close the HTTP connection."""
131
+ self._http.close()
132
+
133
+ def __enter__(self) -> Areev:
134
+ return self
135
+
136
+ def __exit__(self, *args: Any) -> None:
137
+ self.close()
138
+
139
+
140
+ class AsyncAreev:
141
+ """Async Areev client.
142
+
143
+ Same API as :class:`Areev` but all methods are coroutines.
144
+
145
+ Usage::
146
+
147
+ from areev import AsyncAreev
148
+
149
+ async with AsyncAreev() as areev:
150
+ await areev.remember("John likes coffee")
151
+ """
152
+
153
+ def __init__(
154
+ self,
155
+ *,
156
+ api_key: str | None = None,
157
+ url: str | None = None,
158
+ memory_id: str | None = None,
159
+ ) -> None:
160
+ key, self._url, self._memory_id = _resolve(api_key, url, memory_id)
161
+ headers: dict[str, str] = {}
162
+ if key:
163
+ headers["X-API-Key"] = key
164
+ self._http = httpx.AsyncClient(headers=headers)
165
+
166
+ def _path(self, endpoint: str) -> str:
167
+ return f"{self._url}/api/memories/{self._memory_id}/{endpoint}"
168
+
169
+ async def remember(self, text: str, *, sync: bool = True, **kwargs: Any) -> RememberResponse:
170
+ """Store a natural-language memory. Returns extraction details."""
171
+ body = _compact({"text": text, "sync": sync, **kwargs})
172
+ return RememberResponse(**_check(await self._http.post(self._path("remember"), json=body)))
173
+
174
+ async def recall(self, query: str, *, limit: int = 10, **kwargs: Any) -> RecallResponse:
175
+ """Search memories. Returns matching grains."""
176
+ params = _compact({"query": query, "limit": limit, **kwargs})
177
+ return RecallResponse(**_check(await self._http.get(self._path("recall"), params=params)))
178
+
179
+ async def forget(self, hash: str) -> None:
180
+ """Delete a memory by hash."""
181
+ _check(await self._http.delete(self._path(f"grains/{hash}")))
182
+
183
+ async def add(self, grain_type: str | GrainType, /, **fields: Any) -> str:
184
+ """Add a typed grain. Returns the grain hash."""
185
+ grain = grain_type.value if isinstance(grain_type, GrainType) else grain_type
186
+ body = _compact({"grain_type": grain, **fields})
187
+ return AddResponse(**_check(await self._http.post(self._path("add"), json=body))).hash
188
+
189
+ async def get(self, hash: str) -> GetResponse:
190
+ """Get a grain by hash."""
191
+ return GetResponse(**_check(await self._http.get(self._path(f"grains/{hash}"))))
192
+
193
+ async def supersede(self, old_hash: str, grain_type: str | GrainType, /, **fields: Any) -> str:
194
+ """Update a grain. Returns the new hash."""
195
+ grain = grain_type.value if isinstance(grain_type, GrainType) else grain_type
196
+ body = _compact({"old_hash": old_hash, "grain_type": grain, **fields})
197
+ return SupersedeResponse(**_check(await self._http.post(self._path("supersede"), json=body))).new_hash
198
+
199
+ async def health(self) -> HealthResponse:
200
+ """Health check."""
201
+ return HealthResponse(**_check(await self._http.get(f"{self._url}/health")))
202
+
203
+ async def stats(self) -> StatsResponse:
204
+ """Database statistics."""
205
+ return StatsResponse(**_check(await self._http.get(self._path("stats"))))
206
+
207
+ async def flush(self) -> None:
208
+ """Flush write buffer."""
209
+ _check(await self._http.post(self._path("flush")))
210
+
211
+ async def close(self) -> None:
212
+ """Close the HTTP connection."""
213
+ await self._http.aclose()
214
+
215
+ async def __aenter__(self) -> AsyncAreev:
216
+ return self
217
+
218
+ async def __aexit__(self, *args: Any) -> None:
219
+ await self.close()
@@ -0,0 +1 @@
1
+ """Auto-generated code from Areev specs. Do not edit manually."""
areev/grpc.py ADDED
@@ -0,0 +1,14 @@
1
+ """gRPC transport for the Areev SDK (requires 'grpc' extra)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ try:
6
+ import grpc
7
+ from areev.generated import areev_pb2, areev_pb2_grpc
8
+ except ImportError as e:
9
+ raise ImportError(
10
+ "gRPC transport requires the 'grpc' extra: pip install areev[grpc]"
11
+ ) from e
12
+
13
+ # gRPC client implementation will be generated from proto stubs.
14
+ # This module wraps the generated stubs with the same interface as HttpClient.
areev/http.py ADDED
@@ -0,0 +1,121 @@
1
+ """HTTP transport for the Areev SDK using httpx."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import httpx
8
+
9
+ from areev.types import (
10
+ AddRequest,
11
+ AddResponse,
12
+ AreevConfig,
13
+ AreevError,
14
+ GetResponse,
15
+ HealthResponse,
16
+ RecallRequest,
17
+ RecallResponse,
18
+ RememberRequest,
19
+ RememberResponse,
20
+ StatsResponse,
21
+ SupersedeRequest,
22
+ SupersedeResponse,
23
+ )
24
+
25
+
26
+ class HttpClient:
27
+ """Async HTTP client for Areev.
28
+
29
+ Usage::
30
+
31
+ client = HttpClient(AreevConfig(url="http://localhost:4009", memory_id="default"))
32
+ resp = await client.add(AddRequest(grain_type="belief", fields={"subject": "john"}))
33
+ """
34
+
35
+ def __init__(self, config: AreevConfig) -> None:
36
+ self._base = config.url.rstrip("/")
37
+ self._memory_id = config.memory_id
38
+ headers: dict[str, str] = {}
39
+ if config.api_key:
40
+ headers["X-API-Key"] = config.api_key
41
+ self._client = httpx.AsyncClient(headers=headers)
42
+
43
+ def _url(self, path: str) -> str:
44
+ return f"{self._base}/api/memories/{self._memory_id}/{path}"
45
+
46
+ async def _handle(self, resp: httpx.Response) -> Any:
47
+ if resp.status_code >= 400:
48
+ raise AreevError(resp.status_code, resp.text)
49
+ if resp.status_code == 204 or not resp.content:
50
+ return None
51
+ return resp.json()
52
+
53
+ async def add(self, req: AddRequest) -> AddResponse:
54
+ """Add a grain to memory."""
55
+ resp = await self._client.post(
56
+ self._url("add"),
57
+ json=req.model_dump(exclude_none=True),
58
+ )
59
+ return AddResponse(**(await self._handle(resp)))
60
+
61
+ async def remember(self, req: RememberRequest) -> RememberResponse:
62
+ """Ingest natural language text as memory.
63
+
64
+ Accepts free-form text, stores it as an Observation grain, and
65
+ extracts structured Belief grains (sync or async depending on
66
+ ``req.sync``).
67
+ """
68
+ resp = await self._client.post(
69
+ self._url("remember"),
70
+ json=req.model_dump(exclude_none=True),
71
+ )
72
+ return RememberResponse(**(await self._handle(resp)))
73
+
74
+ async def recall(self, req: RecallRequest) -> RecallResponse:
75
+ """Query (recall) grains from memory."""
76
+ params = req.model_dump(exclude_none=True)
77
+ resp = await self._client.get(self._url("recall"), params=params)
78
+ return RecallResponse(**(await self._handle(resp)))
79
+
80
+ async def get(self, hash: str) -> GetResponse:
81
+ """Get a grain by its hash."""
82
+ resp = await self._client.get(self._url(f"grains/{hash}"))
83
+ return GetResponse(**(await self._handle(resp)))
84
+
85
+ async def forget(self, hash: str) -> None:
86
+ """Forget (delete) a grain."""
87
+ resp = await self._client.delete(self._url(f"grains/{hash}"))
88
+ await self._handle(resp)
89
+
90
+ async def supersede(self, req: SupersedeRequest) -> SupersedeResponse:
91
+ """Supersede (update) a grain."""
92
+ resp = await self._client.post(
93
+ self._url("supersede"),
94
+ json=req.model_dump(exclude_none=True),
95
+ )
96
+ return SupersedeResponse(**(await self._handle(resp)))
97
+
98
+ async def health(self) -> HealthResponse:
99
+ """Get health status."""
100
+ resp = await self._client.get(f"{self._base}/health")
101
+ return HealthResponse(**(await self._handle(resp)))
102
+
103
+ async def stats(self) -> StatsResponse:
104
+ """Get database statistics."""
105
+ resp = await self._client.get(self._url("stats"))
106
+ return StatsResponse(**(await self._handle(resp)))
107
+
108
+ async def flush(self) -> None:
109
+ """Flush write buffer."""
110
+ resp = await self._client.post(self._url("flush"))
111
+ await self._handle(resp)
112
+
113
+ async def close(self) -> None:
114
+ """Close the HTTP client."""
115
+ await self._client.aclose()
116
+
117
+ async def __aenter__(self) -> HttpClient:
118
+ return self
119
+
120
+ async def __aexit__(self, *args: Any) -> None:
121
+ await self.close()
areev/types.py ADDED
@@ -0,0 +1,173 @@
1
+ """Core types for the Areev SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import Enum
6
+ from typing import Any
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+
11
+ class GrainType(str, Enum):
12
+ """Grain types supported by Areev."""
13
+
14
+ BELIEF = "belief"
15
+ EVENT = "event"
16
+ STATE = "state"
17
+ WORKFLOW = "workflow"
18
+ ACTION = "action"
19
+ OBSERVATION = "observation"
20
+ GOAL = "goal"
21
+ REASONING = "reasoning"
22
+ CONSENSUS = "consensus"
23
+ CONSENT = "consent"
24
+
25
+
26
+ class AddOptions(BaseModel):
27
+ """Options for the add operation (import intelligence)."""
28
+
29
+ extract_event_date: bool | None = None
30
+ auto_relate: bool | None = None
31
+ extract_memories: bool | None = None
32
+ sync: bool | None = None
33
+
34
+
35
+ class AddRequest(BaseModel):
36
+ """Request to add a grain."""
37
+
38
+ grain_type: GrainType
39
+ fields: dict[str, Any]
40
+ options: AddOptions | None = None
41
+
42
+
43
+ class AddResponse(BaseModel):
44
+ """Response from adding a grain."""
45
+
46
+ hash: str
47
+
48
+
49
+ class RecallRequest(BaseModel):
50
+ """Request to recall (query) grains."""
51
+
52
+ query: str | None = None
53
+ subject: str | None = None
54
+ relation: str | None = None
55
+ object: str | None = None
56
+ namespace: str | None = None
57
+ user_id: str | None = None
58
+ grain_type: str | None = None
59
+ limit: int | None = None
60
+ temporal_expr: str | None = None
61
+ tags: list[str] | None = None
62
+ deduplicate: bool | None = None
63
+ rerank: bool | None = None
64
+ query_expansion: bool | None = None
65
+ explanation: bool | None = None
66
+ min_score: float | None = None
67
+ diversity: float | None = None
68
+ recency_weight: float | None = None
69
+ entity: str | None = None
70
+ multi_hop: int | None = None
71
+
72
+ model_config = {"extra": "allow"}
73
+
74
+
75
+ class SearchHit(BaseModel):
76
+ """A single search result."""
77
+
78
+ hash: str
79
+ grain_type: str
80
+ score: float
81
+ fields: dict[str, Any]
82
+ source_namespace: str | None = None
83
+ explanation: str | None = None
84
+ relative_time: str | None = None
85
+
86
+
87
+ class RecallResponse(BaseModel):
88
+ """Response from a recall query."""
89
+
90
+ count: int
91
+ results: list[SearchHit]
92
+
93
+
94
+ class SupersedeRequest(BaseModel):
95
+ """Request to supersede a grain."""
96
+
97
+ old_hash: str
98
+ grain_type: GrainType
99
+ fields: dict[str, Any]
100
+
101
+
102
+ class SupersedeResponse(BaseModel):
103
+ """Response from superseding a grain."""
104
+
105
+ new_hash: str
106
+
107
+
108
+ class RememberRequest(BaseModel):
109
+ """Request to ingest natural language text as memory."""
110
+
111
+ text: str
112
+ sync: bool = False
113
+ keep_source: bool = False
114
+ namespace: str | None = None
115
+ user_id: str | None = None
116
+ tags: list[str] | None = None
117
+ source_type: str | None = None
118
+ confidence: float | None = None
119
+ extract_event_date: bool | None = None
120
+ auto_relate: bool | None = None
121
+ created_at: int | None = None
122
+
123
+
124
+ class RememberResponse(BaseModel):
125
+ """Response from the remember endpoint."""
126
+
127
+ source_hash: str
128
+ mode: str
129
+ extracted_count: int
130
+ source_forgotten: bool
131
+ extracted_hashes: list[str] | None = None
132
+ marker_status: str | None = None
133
+ warnings: list[str] | None = None
134
+
135
+
136
+ class GetResponse(BaseModel):
137
+ """Grain detail response."""
138
+
139
+ hash: str
140
+ grain_type: str
141
+ fields: dict[str, Any]
142
+
143
+
144
+ class HealthResponse(BaseModel):
145
+ """Health check response."""
146
+
147
+ status: str
148
+ version: str
149
+
150
+
151
+ class StatsResponse(BaseModel):
152
+ """Database statistics."""
153
+
154
+ total_grains: int
155
+ disk_space_bytes: int
156
+ store_size: str
157
+ type_counts: dict[str, int] = Field(default_factory=dict)
158
+
159
+
160
+ class AreevConfig(BaseModel):
161
+ """Client configuration."""
162
+
163
+ url: str
164
+ memory_id: str
165
+ api_key: str | None = None
166
+
167
+
168
+ class AreevError(Exception):
169
+ """Error raised by the Areev client."""
170
+
171
+ def __init__(self, status: int, message: str) -> None:
172
+ self.status = status
173
+ super().__init__(f"Areev API error ({status}): {message}")
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: areev
3
+ Version: 0.0.0
4
+ Summary: Python SDK for the Areev knowledge database — HTTP, gRPC, and MCP transports
5
+ Project-URL: Repository, https://github.com/AreevAI/areev-sdk-python
6
+ Project-URL: Documentation, https://areev.ai/docs
7
+ License-Expression: BUSL-1.1
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: httpx>=0.27
11
+ Requires-Dist: pydantic>=2.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: datamodel-code-generator>=0.26; extra == 'dev'
14
+ Requires-Dist: grpcio-tools>=1.60; extra == 'dev'
15
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
16
+ Requires-Dist: pytest>=8.0; extra == 'dev'
17
+ Provides-Extra: grpc
18
+ Requires-Dist: grpcio>=1.60; extra == 'grpc'
19
+ Requires-Dist: protobuf>=5.0; extra == 'grpc'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Areev Python SDK
23
+
24
+ Python client library for the [Areev](https://areev.ai) knowledge database.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install areev
30
+ ```
31
+
32
+ For gRPC transport:
33
+ ```bash
34
+ pip install areev[grpc]
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```python
40
+ from areev import Areev
41
+
42
+ areev = Areev() # reads AREEV_API_KEY, AREEV_URL from env
43
+ areev.remember("John likes coffee")
44
+
45
+ results = areev.recall("what does John like?")
46
+ for hit in results.results:
47
+ print(f" {hit.grain_type}: {hit.fields}")
48
+ ```
49
+
50
+ ### Configuration
51
+
52
+ The client reads from environment variables by default:
53
+
54
+ | Variable | Default | Description |
55
+ |----------|---------|-------------|
56
+ | `AREEV_API_KEY` | — | API key (sent as `X-API-Key` header) |
57
+ | `AREEV_URL` | `https://app.areev.ai` | Server endpoint |
58
+ | `AREEV_MEMORY_ID` | `default` | Memory database ID |
59
+
60
+ Or pass them explicitly:
61
+
62
+ ```python
63
+ areev = Areev(api_key="ar_...", url="https://dub.areev.ai", memory_id="my-memory")
64
+ ```
65
+
66
+ ### Async
67
+
68
+ ```python
69
+ from areev import AsyncAreev
70
+
71
+ async with AsyncAreev() as areev:
72
+ await areev.remember("John likes coffee")
73
+ results = await areev.recall("what does John like?")
74
+ ```
75
+
76
+ ## API
77
+
78
+ | Method | Description |
79
+ |--------|-------------|
80
+ | `remember(text)` | Store natural-language memory (LLM extracts structure) |
81
+ | `recall(query)` | Search memories |
82
+ | `forget(hash)` | Delete a memory by hash |
83
+ | `add(grain_type, **fields)` | Add a typed grain (low-level) |
84
+ | `get(hash)` | Get a grain by hash |
85
+ | `supersede(old_hash, grain_type, **fields)` | Update a grain |
86
+ | `health()` | Health check |
87
+ | `stats()` | Database statistics |
88
+ | `flush()` | Flush write buffer |
89
+
90
+ ### Low-Level Client
91
+
92
+ For advanced use cases (custom request objects, full async control):
93
+
94
+ ```python
95
+ from areev import HttpClient, AreevConfig, AddRequest, GrainType
96
+
97
+ config = AreevConfig(url="http://localhost:4009", memory_id="default", api_key="your-key")
98
+ async with HttpClient(config) as client:
99
+ resp = await client.add(AddRequest(
100
+ grain_type=GrainType.BELIEF,
101
+ fields={"subject": "john", "relation": "likes", "object": "coffee"},
102
+ ))
103
+ ```
104
+
105
+ ## Transports
106
+
107
+ | Transport | Extra | Status |
108
+ |-----------|-------|--------|
109
+ | HTTP/REST | _(default)_ | Available |
110
+ | gRPC | `areev[grpc]` | Available |
111
+ | MCP | — | Planned |
112
+
113
+ ## Code Generation
114
+
115
+ Generate gRPC stubs and Pydantic models from the Areev spec:
116
+
117
+ ```bash
118
+ pip install areev[dev]
119
+ ./scripts/generate.sh
120
+ ```
121
+
122
+ ## License
123
+
124
+ BUSL-1.1
@@ -0,0 +1,10 @@
1
+ areev/__init__.py,sha256=1IuGtBdXYmz3tCsynmRAGDfPBDWhA51sHVWpUfp9C2M,971
2
+ areev/client.py,sha256=AtValmqMsAAyp4yGhAqxIZAqiTnQCVCVDIaoWpSUtYQ,7768
3
+ areev/grpc.py,sha256=8xhqniba-njixAgPy0N14YbGNSxqUlOsPePSrRIFcJ8,462
4
+ areev/http.py,sha256=p1aMbHKtVKorufGkOWiWwh3XL0UV6Qw1U14Vem9Qyes,3976
5
+ areev/types.py,sha256=iE-d7cYrTxK17uh37whGhUwE7J9DY5zX1-mlRwUDpsg,3862
6
+ areev/generated/__init__.py,sha256=nvnu8PEosfcYv7xT2VzI_xlgqeRc1rnXAoIdK6zLQxQ,66
7
+ areev-0.0.0.dist-info/METADATA,sha256=3RJYJ_hWCRCGFZJXHK8Gib9okmabKJnR1l-fAAPD6A4,3184
8
+ areev-0.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
9
+ areev-0.0.0.dist-info/licenses/LICENSE,sha256=pAmHakG0ptbZ0By03_Nxza9WpIpfOOYxJnC_rTB2i7E,250
10
+ areev-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,7 @@
1
+ Business Source License 1.1
2
+
3
+ Licensor: MindGryd Technologies Private Limited
4
+ Licensed Work: Areev Python SDK
5
+
6
+ The Licensed Work is provided under the terms of the Business Source License 1.1.
7
+ See https://mariadb.com/bsl11/ for the full license text.