hebbrix 2.3.2__tar.gz → 2.4.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.
Files changed (29) hide show
  1. {hebbrix-2.3.2 → hebbrix-2.4.0}/CHANGELOG.md +14 -0
  2. hebbrix-2.4.0/PKG-INFO +139 -0
  3. hebbrix-2.4.0/README.md +98 -0
  4. hebbrix-2.4.0/hebbrix/__init__.py +42 -0
  5. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix/client.py +58 -11
  6. hebbrix-2.4.0/hebbrix/exceptions.py +76 -0
  7. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix/resources.py +157 -140
  8. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix/sync_client.py +67 -17
  9. hebbrix-2.4.0/hebbrix.egg-info/PKG-INFO +139 -0
  10. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix.egg-info/SOURCES.txt +1 -0
  11. {hebbrix-2.3.2 → hebbrix-2.4.0}/pyproject.toml +7 -6
  12. hebbrix-2.4.0/tests/test_advanced_resources.py +96 -0
  13. {hebbrix-2.3.2 → hebbrix-2.4.0}/tests/test_openapi_parity.py +76 -0
  14. hebbrix-2.3.2/PKG-INFO +0 -205
  15. hebbrix-2.3.2/README.md +0 -143
  16. hebbrix-2.3.2/hebbrix/__init__.py +0 -74
  17. hebbrix-2.3.2/hebbrix/exceptions.py +0 -48
  18. hebbrix-2.3.2/hebbrix.egg-info/PKG-INFO +0 -205
  19. {hebbrix-2.3.2 → hebbrix-2.4.0}/LICENSE +0 -0
  20. {hebbrix-2.3.2 → hebbrix-2.4.0}/MANIFEST.in +0 -0
  21. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix/chat.py +0 -0
  22. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix/models.py +0 -0
  23. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix.egg-info/dependency_links.txt +0 -0
  24. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix.egg-info/requires.txt +0 -0
  25. {hebbrix-2.3.2 → hebbrix-2.4.0}/hebbrix.egg-info/top_level.txt +0 -0
  26. {hebbrix-2.3.2 → hebbrix-2.4.0}/setup.cfg +0 -0
  27. {hebbrix-2.3.2 → hebbrix-2.4.0}/tests/test_memories_resource.py +0 -0
  28. {hebbrix-2.3.2 → hebbrix-2.4.0}/tests/test_procedural_resource.py +0 -0
  29. {hebbrix-2.3.2 → hebbrix-2.4.0}/tests/test_sync_client.py +0 -0
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.4.0 — 2026-08-27
4
+
5
+ - Reconcile every exported advanced method with the canonical public OpenAPI,
6
+ including temporal, working-memory, consolidation, memory-tool, and RL routes.
7
+ - Add a route-manifest release gate and clean-wheel installation verification.
8
+ - Treat durable-but-indexing batch results as `202`, poll them through the SDK,
9
+ and raise `IndexingTimeoutError` with the durable receipt on client deadline.
10
+ - Preserve structured entitlement metadata in `EntitlementError`.
11
+ - Keep advanced resources async-only and document the sync-client boundary.
12
+ - Withdraw the experimental World Model from the public SDK until a trained,
13
+ versioned production model artifact and serving contract exist.
14
+ - Publish compatibility through `GET /v1/release`; replace the broken public
15
+ repository link with valid artifact and support links.
16
+
3
17
  ## 2.3.2 — 2026-08-27
4
18
 
5
19
  - Align procedure create/list/get/update/execute/delete with the canonical
hebbrix-2.4.0/PKG-INFO ADDED
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: hebbrix
3
+ Version: 2.4.0
4
+ Summary: Typed Python client for Hebbrix memory, retrieval, and outcome-learning APIs
5
+ Author-email: Hebbrix Team <support@hebbrix.com>
6
+ Maintainer-email: Hebbrix Team <support@hebbrix.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://hebbrix.com
9
+ Project-URL: Documentation, https://docs.hebbrix.com
10
+ Project-URL: Source, https://pypi.org/project/hebbrix/#files
11
+ Project-URL: Support, https://www.hebbrix.com/contact
12
+ Project-URL: API Reference, https://api.hebbrix.com/docs
13
+ Keywords: ai,memory,agents,llm,chatbot,assistant,ml,reinforcement-learning,knowledge-graph,vector-search,rag,temporal,procedural-memory,working-memory
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Database
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Operating System :: OS Independent
26
+ Classifier: Framework :: AsyncIO
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: httpx>=0.25.0
31
+ Requires-Dist: requests>=2.31.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: black>=23.0.0; extra == "dev"
36
+ Requires-Dist: flake8<6.0.0,>=5.0.4; python_full_version < "3.8.1" and extra == "dev"
37
+ Requires-Dist: flake8>=6.0.0; python_full_version >= "3.8.1" and extra == "dev"
38
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
39
+ Requires-Dist: cryptography>=42.0.0; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # Hebbrix Python SDK
43
+
44
+ Typed Python client for Hebbrix memory, retrieval, and outcome-learning APIs.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install hebbrix==2.4.0
50
+ ```
51
+
52
+ Python 3.8+ is supported. `MemoryClient` is asynchronous. `SyncMemoryClient`
53
+ supports the core collection, memory, search, correction, procedure, and
54
+ ProofLoop workflows; advanced temporal, working-memory, consolidation,
55
+ memory-tool, and RL resources are currently async-only.
56
+
57
+ ## Quick start
58
+
59
+ ```python
60
+ import asyncio
61
+ from hebbrix import MemoryClient
62
+
63
+ async def main():
64
+ async with MemoryClient(api_key="hbx_your_api_key") as client:
65
+ collection = await client.collections.create(name="Support memory")
66
+ memory = await client.memories.create(
67
+ collection_id=collection["id"],
68
+ content="Customer prefers concise replies",
69
+ wait_for_index=True,
70
+ idempotency_key="customer-42-preference-v1",
71
+ )
72
+ results = await client.search(
73
+ "How should replies be formatted?",
74
+ collection_id=collection["id"],
75
+ )
76
+ print(memory, results)
77
+
78
+ asyncio.run(main())
79
+ ```
80
+
81
+ ## Durable readiness
82
+
83
+ Memory writes return either a searchable completion or a durable `202` receipt.
84
+ A durable receipt means the database commit succeeded while indexing is still
85
+ converging; it is not a failure and does not justify a duplicate write.
86
+
87
+ When `wait_for_index=True`, the SDK accepts that receipt and polls the documented
88
+ status URL. It returns only after `searchable=true`. If the caller's deadline
89
+ expires, it raises `IndexingTimeoutError`; the exception retains the original
90
+ receipt, durable memory IDs, and status URL. Reuse the same idempotency key with
91
+ the same body to recover the same logical resources.
92
+
93
+ For an asynchronous batch receipt:
94
+
95
+ ```python
96
+ receipt = await client.memories.create_batch(
97
+ [{"content": "First fact"}, {"content": "Second fact"}],
98
+ collection_id="collection-42",
99
+ wait_for_index=False,
100
+ idempotency_key="import-42",
101
+ )
102
+ completed = await client.memories.wait_batch_until_searchable(receipt)
103
+ ```
104
+
105
+ ## Pagination
106
+
107
+ `collections.list()` returns the current page's collection items for backward
108
+ compatibility. Use `collections.list_page()` when cursor metadata is required.
109
+ Memory resources provide the same `list()`/`list_page()` distinction.
110
+
111
+ ## Advanced capabilities and entitlements
112
+
113
+ The async client exposes the canonical `/v1` temporal, working-memory,
114
+ consolidation, memory-tool, and RL contracts. RL metrics and evaluation require
115
+ the Pro plan. Process-wide RL training and checkpoint mutation require an admin
116
+ role. Entitlement failures raise `EntitlementError` and preserve the stable
117
+ error code, current/required plan, request ID, and support action.
118
+
119
+ The experimental World Model is intentionally not exported by this public SDK.
120
+ It remains withdrawn until a trained, versioned production model artifact and
121
+ an end-to-end public serving contract are available.
122
+
123
+ The authoritative account capability matrix is available from
124
+ `GET /v1/users/me/capabilities`.
125
+
126
+ ## Release compatibility
127
+
128
+ The production API publishes exact build and artifact compatibility at
129
+ [`GET /v1/release`](https://api.hebbrix.com/v1/release). The public OpenAPI is
130
+ [`/openapi.json`](https://api.hebbrix.com/openapi.json).
131
+
132
+ - [Documentation](https://docs.hebbrix.com)
133
+ - [API reference](https://api.hebbrix.com/docs)
134
+ - [PyPI files](https://pypi.org/project/hebbrix/#files)
135
+ - [Support](https://www.hebbrix.com/contact)
136
+
137
+ ## License
138
+
139
+ MIT. See `LICENSE` in the distribution.
@@ -0,0 +1,98 @@
1
+ # Hebbrix Python SDK
2
+
3
+ Typed Python client for Hebbrix memory, retrieval, and outcome-learning APIs.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install hebbrix==2.4.0
9
+ ```
10
+
11
+ Python 3.8+ is supported. `MemoryClient` is asynchronous. `SyncMemoryClient`
12
+ supports the core collection, memory, search, correction, procedure, and
13
+ ProofLoop workflows; advanced temporal, working-memory, consolidation,
14
+ memory-tool, and RL resources are currently async-only.
15
+
16
+ ## Quick start
17
+
18
+ ```python
19
+ import asyncio
20
+ from hebbrix import MemoryClient
21
+
22
+ async def main():
23
+ async with MemoryClient(api_key="hbx_your_api_key") as client:
24
+ collection = await client.collections.create(name="Support memory")
25
+ memory = await client.memories.create(
26
+ collection_id=collection["id"],
27
+ content="Customer prefers concise replies",
28
+ wait_for_index=True,
29
+ idempotency_key="customer-42-preference-v1",
30
+ )
31
+ results = await client.search(
32
+ "How should replies be formatted?",
33
+ collection_id=collection["id"],
34
+ )
35
+ print(memory, results)
36
+
37
+ asyncio.run(main())
38
+ ```
39
+
40
+ ## Durable readiness
41
+
42
+ Memory writes return either a searchable completion or a durable `202` receipt.
43
+ A durable receipt means the database commit succeeded while indexing is still
44
+ converging; it is not a failure and does not justify a duplicate write.
45
+
46
+ When `wait_for_index=True`, the SDK accepts that receipt and polls the documented
47
+ status URL. It returns only after `searchable=true`. If the caller's deadline
48
+ expires, it raises `IndexingTimeoutError`; the exception retains the original
49
+ receipt, durable memory IDs, and status URL. Reuse the same idempotency key with
50
+ the same body to recover the same logical resources.
51
+
52
+ For an asynchronous batch receipt:
53
+
54
+ ```python
55
+ receipt = await client.memories.create_batch(
56
+ [{"content": "First fact"}, {"content": "Second fact"}],
57
+ collection_id="collection-42",
58
+ wait_for_index=False,
59
+ idempotency_key="import-42",
60
+ )
61
+ completed = await client.memories.wait_batch_until_searchable(receipt)
62
+ ```
63
+
64
+ ## Pagination
65
+
66
+ `collections.list()` returns the current page's collection items for backward
67
+ compatibility. Use `collections.list_page()` when cursor metadata is required.
68
+ Memory resources provide the same `list()`/`list_page()` distinction.
69
+
70
+ ## Advanced capabilities and entitlements
71
+
72
+ The async client exposes the canonical `/v1` temporal, working-memory,
73
+ consolidation, memory-tool, and RL contracts. RL metrics and evaluation require
74
+ the Pro plan. Process-wide RL training and checkpoint mutation require an admin
75
+ role. Entitlement failures raise `EntitlementError` and preserve the stable
76
+ error code, current/required plan, request ID, and support action.
77
+
78
+ The experimental World Model is intentionally not exported by this public SDK.
79
+ It remains withdrawn until a trained, versioned production model artifact and
80
+ an end-to-end public serving contract are available.
81
+
82
+ The authoritative account capability matrix is available from
83
+ `GET /v1/users/me/capabilities`.
84
+
85
+ ## Release compatibility
86
+
87
+ The production API publishes exact build and artifact compatibility at
88
+ [`GET /v1/release`](https://api.hebbrix.com/v1/release). The public OpenAPI is
89
+ [`/openapi.json`](https://api.hebbrix.com/openapi.json).
90
+
91
+ - [Documentation](https://docs.hebbrix.com)
92
+ - [API reference](https://api.hebbrix.com/docs)
93
+ - [PyPI files](https://pypi.org/project/hebbrix/#files)
94
+ - [Support](https://www.hebbrix.com/contact)
95
+
96
+ ## License
97
+
98
+ MIT. See `LICENSE` in the distribution.
@@ -0,0 +1,42 @@
1
+ """Typed async-first client for Hebbrix memory and outcome-learning APIs.
2
+
3
+ The public surface and its plan/role restrictions are documented by the
4
+ production OpenAPI and ``GET /v1/users/me/capabilities``. The experimental
5
+ World Model is intentionally absent from this release.
6
+ """
7
+
8
+ __version__ = "2.4.0"
9
+ __author__ = "Hebbrix Team"
10
+ __license__ = "MIT"
11
+
12
+ from hebbrix.chat import MemoryChat
13
+ from hebbrix.client import MemoryClient
14
+ from hebbrix.exceptions import (
15
+ AuthenticationError,
16
+ EntitlementError,
17
+ HebbrixError,
18
+ IndexingTimeoutError,
19
+ NotFoundError,
20
+ RateLimitError,
21
+ ServerError,
22
+ ValidationError,
23
+ )
24
+ from hebbrix.models import EvidenceClaim, GroundingReceipt, SearchSafetyEnvelope
25
+ from hebbrix.sync_client import SyncMemoryClient
26
+
27
+ __all__ = [
28
+ "MemoryClient",
29
+ "SyncMemoryClient",
30
+ "MemoryChat",
31
+ "HebbrixError",
32
+ "AuthenticationError",
33
+ "EntitlementError",
34
+ "IndexingTimeoutError",
35
+ "ValidationError",
36
+ "NotFoundError",
37
+ "RateLimitError",
38
+ "ServerError",
39
+ "GroundingReceipt",
40
+ "EvidenceClaim",
41
+ "SearchSafetyEnvelope",
42
+ ]
@@ -10,6 +10,7 @@ from typing import Any, Dict, List, Optional
10
10
  import httpx
11
11
  from hebbrix.exceptions import (
12
12
  AuthenticationError,
13
+ EntitlementError,
13
14
  HebbrixError,
14
15
  NotFoundError,
15
16
  RateLimitError,
@@ -30,7 +31,6 @@ from hebbrix.resources import (
30
31
  SearchResource,
31
32
  TemporalResource,
32
33
  WorkingMemoryResource,
33
- WorldModelResource,
34
34
  )
35
35
 
36
36
 
@@ -85,13 +85,12 @@ class MemoryClient:
85
85
  self.working_memory = WorkingMemoryResource(self)
86
86
  self.consolidation = ConsolidationResource(self)
87
87
  self.memory_tools = MemoryToolsResource(self)
88
- self.world_model = WorldModelResource(self)
89
88
 
90
89
  def _get_headers(self) -> Dict[str, str]:
91
90
  """Get request headers."""
92
91
  headers = {
93
92
  "Content-Type": "application/json",
94
- "User-Agent": "hebbrix-python/2.3.2",
93
+ "User-Agent": "hebbrix-python/2.4.0",
95
94
  }
96
95
 
97
96
  if self.api_key:
@@ -108,23 +107,71 @@ class MemoryClient:
108
107
 
109
108
  try:
110
109
  error_data = response.json()
111
- message = error_data.get("error", {}).get("message", response.text)
112
110
  except Exception:
113
- message = response.text
111
+ error_data = {}
112
+
113
+ envelope = error_data.get("error") or error_data.get("detail") or {}
114
+ if not isinstance(envelope, dict):
115
+ envelope = {"message": str(envelope)}
116
+ nested = envelope.get("message")
117
+ details = nested if isinstance(nested, dict) else envelope
118
+ message = (
119
+ (details.get("message") if isinstance(details, dict) else None)
120
+ or (nested if isinstance(nested, str) else None)
121
+ or response.text
122
+ )
123
+ code = str(details.get("code") or envelope.get("code") or "") or None
124
+ request_id = (
125
+ details.get("request_id")
126
+ or envelope.get("request_id")
127
+ or response.headers.get("X-Request-ID")
128
+ )
114
129
 
115
130
  if status_code == 401:
116
- raise AuthenticationError(message)
131
+ raise AuthenticationError(
132
+ message, code=code, request_id=request_id, details=details
133
+ )
117
134
  elif status_code == 404:
118
- raise NotFoundError(message)
135
+ raise NotFoundError(
136
+ message, code=code, request_id=request_id, details=details
137
+ )
119
138
  elif status_code == 422:
120
139
  errors = error_data.get("error", {}).get("details", [])
121
- raise ValidationError(message, errors=errors)
140
+ raise ValidationError(
141
+ message,
142
+ errors=errors,
143
+ code=code,
144
+ request_id=request_id,
145
+ details=details,
146
+ )
122
147
  elif status_code == 429:
123
- raise RateLimitError(message)
148
+ raise RateLimitError(
149
+ message, code=code, request_id=request_id, details=details
150
+ )
124
151
  elif status_code >= 500:
125
- raise ServerError(message)
152
+ raise ServerError(
153
+ message, code=code, request_id=request_id, details=details
154
+ )
155
+ elif status_code in {402, 403} and (
156
+ "ENTITLEMENT" in str(code or "")
157
+ or details.get("error")
158
+ in {"feature_not_available", "tier_upgrade_required"}
159
+ ):
160
+ raise EntitlementError(
161
+ message,
162
+ status_code=status_code,
163
+ code=code,
164
+ request_id=request_id,
165
+ details=details,
166
+ )
126
167
  else:
127
- raise HebbrixError(message, status_code=status_code)
168
+ raise HebbrixError(
169
+ message,
170
+ status_code=status_code,
171
+ code=code,
172
+ request_id=request_id,
173
+ details=details,
174
+ )
128
175
 
129
176
  async def request(
130
177
  self,
@@ -0,0 +1,76 @@
1
+ """
2
+ Hebbrix SDK Exceptions
3
+ """
4
+
5
+
6
+ class HebbrixError(Exception):
7
+ """Base exception for Hebbrix SDK."""
8
+
9
+ def __init__(
10
+ self,
11
+ message: str,
12
+ status_code: int = None,
13
+ *,
14
+ code: str = None,
15
+ request_id: str = None,
16
+ details: dict = None,
17
+ ):
18
+ self.message = message
19
+ self.status_code = status_code
20
+ self.code = code
21
+ self.request_id = request_id
22
+ self.details = details or {}
23
+ super().__init__(self.message)
24
+
25
+
26
+ class EntitlementError(HebbrixError):
27
+ """The authenticated account lacks the plan or role for an operation."""
28
+
29
+ def __init__(self, message: str, *, status_code: int, **kwargs):
30
+ super().__init__(message, status_code=status_code, **kwargs)
31
+
32
+
33
+ class IndexingTimeoutError(TimeoutError):
34
+ """A durable write did not become searchable before the client deadline."""
35
+
36
+ def __init__(self, message: str, receipt: dict):
37
+ self.receipt = dict(receipt)
38
+ self.memory_ids = list(receipt.get("memory_ids") or [])
39
+ self.status_url = receipt.get("status_url")
40
+ super().__init__(message)
41
+
42
+
43
+ class AuthenticationError(HebbrixError):
44
+ """Raised when authentication fails."""
45
+
46
+ def __init__(self, message: str = "Authentication failed", **kwargs):
47
+ super().__init__(message, status_code=401, **kwargs)
48
+
49
+
50
+ class ValidationError(HebbrixError):
51
+ """Raised when request validation fails."""
52
+
53
+ def __init__(self, message: str, errors: list = None, **kwargs):
54
+ self.errors = errors or []
55
+ super().__init__(message, status_code=422, **kwargs)
56
+
57
+
58
+ class NotFoundError(HebbrixError):
59
+ """Raised when a resource is not found."""
60
+
61
+ def __init__(self, message: str = "Resource not found", **kwargs):
62
+ super().__init__(message, status_code=404, **kwargs)
63
+
64
+
65
+ class RateLimitError(HebbrixError):
66
+ """Raised when rate limit is exceeded."""
67
+
68
+ def __init__(self, message: str = "Rate limit exceeded", **kwargs):
69
+ super().__init__(message, status_code=429, **kwargs)
70
+
71
+
72
+ class ServerError(HebbrixError):
73
+ """Raised when server returns 5xx error."""
74
+
75
+ def __init__(self, message: str = "Internal server error", **kwargs):
76
+ super().__init__(message, status_code=500, **kwargs)