cortexdbai 0.2.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.
cortexdb/exceptions.py ADDED
@@ -0,0 +1,69 @@
1
+ """Exception hierarchy for the CortexDB Python SDK."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ class CortexError(Exception):
7
+ """Base exception for all CortexDB SDK errors."""
8
+
9
+ def __init__(self, message: str = "") -> None:
10
+ self.message = message
11
+ super().__init__(message)
12
+
13
+
14
+ class CortexAPIError(CortexError):
15
+ """Raised when the CortexDB API returns an error response.
16
+
17
+ Attributes:
18
+ status_code: HTTP status code from the server.
19
+ error_code: Application-level error code returned by the API, if any.
20
+ message: Human-readable error description.
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ message: str,
26
+ status_code: int,
27
+ error_code: str | None = None,
28
+ ) -> None:
29
+ self.status_code = status_code
30
+ self.error_code = error_code
31
+ super().__init__(message)
32
+
33
+ def __str__(self) -> str:
34
+ parts = [f"[HTTP {self.status_code}]"]
35
+ if self.error_code:
36
+ parts.append(f"[{self.error_code}]")
37
+ parts.append(self.message)
38
+ return " ".join(parts)
39
+
40
+
41
+ class CortexConnectionError(CortexError):
42
+ """Raised when the SDK cannot connect to the CortexDB server."""
43
+
44
+
45
+ class CortexTimeoutError(CortexConnectionError):
46
+ """Raised when a request to the CortexDB server times out."""
47
+
48
+
49
+ class CortexAuthError(CortexAPIError):
50
+ """Raised when authentication fails (HTTP 401 or 403)."""
51
+
52
+
53
+ class CortexRateLimitError(CortexAPIError):
54
+ """Raised when the API returns HTTP 429 Too Many Requests.
55
+
56
+ Attributes:
57
+ retry_after: Number of seconds to wait before retrying, parsed from
58
+ the Retry-After header. None if the header was absent.
59
+ """
60
+
61
+ def __init__(
62
+ self,
63
+ message: str,
64
+ status_code: int = 429,
65
+ error_code: str | None = None,
66
+ retry_after: float | None = None,
67
+ ) -> None:
68
+ self.retry_after = retry_after
69
+ super().__init__(message=message, status_code=status_code, error_code=error_code)
cortexdb/models.py ADDED
@@ -0,0 +1,390 @@
1
+ """Pydantic models for the CortexDB Python SDK.
2
+
3
+ These models mirror the Rust-side Episode schema and API request/response types.
4
+ All models use snake_case field names with camelCase JSON serialization for
5
+ wire compatibility.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import enum
11
+ from datetime import datetime
12
+ from typing import Any
13
+ from uuid import UUID
14
+
15
+ from pydantic import BaseModel, ConfigDict, Field
16
+
17
+
18
+ def _to_camel(name: str) -> str:
19
+ """Convert snake_case to camelCase for JSON serialization."""
20
+ parts = name.split("_")
21
+ return parts[0] + "".join(word.capitalize() for word in parts[1:])
22
+
23
+
24
+ _SHARED_CONFIG = ConfigDict(
25
+ populate_by_name=True,
26
+ alias_generator=_to_camel,
27
+ use_enum_values=True,
28
+ )
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Enums
33
+ # ---------------------------------------------------------------------------
34
+
35
+
36
+ class EpisodeType(str, enum.Enum):
37
+ """Classification of an episode's content type."""
38
+
39
+ MESSAGE = "message"
40
+ CODE_CHANGE = "code_change"
41
+ INCIDENT = "incident"
42
+ DEPLOYMENT = "deployment"
43
+ ISSUE = "issue"
44
+ DOCUMENT = "document"
45
+ REVIEW = "review"
46
+ MEETING = "meeting"
47
+ ALERT = "alert"
48
+ DECISION = "decision"
49
+ CUSTOM = "custom"
50
+
51
+
52
+ class ActorType(str, enum.Enum):
53
+ """The kind of actor that produced an episode."""
54
+
55
+ PERSON = "person"
56
+ BOT = "bot"
57
+ SYSTEM = "system"
58
+ SERVICE = "service"
59
+
60
+
61
+ class VisibilityLevel(str, enum.Enum):
62
+ """Access level for an episode."""
63
+
64
+ ORGANIZATION = "organization"
65
+ RESTRICTED = "restricted"
66
+ PRIVATE = "private"
67
+ PUBLIC = "public"
68
+
69
+
70
+ # ---------------------------------------------------------------------------
71
+ # Core domain models
72
+ # ---------------------------------------------------------------------------
73
+
74
+
75
+ class Actor(BaseModel):
76
+ """Represents the entity that produced an episode."""
77
+
78
+ model_config = _SHARED_CONFIG
79
+
80
+ id: str
81
+ name: str = ""
82
+ actor_type: ActorType = ActorType.PERSON
83
+ email: str | None = None
84
+
85
+
86
+ class Source(BaseModel):
87
+ """Provenance information for an episode."""
88
+
89
+ model_config = _SHARED_CONFIG
90
+
91
+ connector: str
92
+ external_id: str = ""
93
+ url: str | None = None
94
+ channel: str | None = None
95
+
96
+
97
+ class Visibility(BaseModel):
98
+ """Access control specification for an episode."""
99
+
100
+ model_config = _SHARED_CONFIG
101
+
102
+ level: VisibilityLevel = VisibilityLevel.ORGANIZATION
103
+ allowed_groups: list[str] = Field(default_factory=list)
104
+ allowed_users: list[str] = Field(default_factory=list)
105
+
106
+
107
+ class EntityRef(BaseModel):
108
+ """A reference to a named entity mentioned in an episode."""
109
+
110
+ model_config = _SHARED_CONFIG
111
+
112
+ name: str
113
+ entity_type: str = ""
114
+ role: str | None = None
115
+
116
+
117
+ class Episode(BaseModel):
118
+ """A single episode of memory stored in CortexDB.
119
+
120
+ An episode represents a discrete unit of information — a message,
121
+ document, code snippet, decision, or any other event worth remembering.
122
+ """
123
+
124
+ model_config = _SHARED_CONFIG
125
+
126
+ id: UUID | None = None
127
+ tenant_id: str = "default"
128
+ episode_type: EpisodeType = EpisodeType.MESSAGE
129
+ content: str
130
+ actor: Actor | None = None
131
+ source: Source | None = None
132
+ visibility: Visibility | None = None
133
+ entities: list[EntityRef] | None = None
134
+ metadata: dict[str, Any] | None = None
135
+ created_at: datetime | None = None
136
+ updated_at: datetime | None = None
137
+
138
+
139
+ # ---------------------------------------------------------------------------
140
+ # API request / response models
141
+ # ---------------------------------------------------------------------------
142
+
143
+
144
+ class IngestEpisodeRequest(BaseModel):
145
+ """Request body for POST /v1/episodes."""
146
+
147
+ model_config = _SHARED_CONFIG
148
+
149
+ content: str
150
+ tenant_id: str = "default"
151
+ episode_type: EpisodeType = EpisodeType.MESSAGE
152
+ actor: Actor | None = None
153
+ source: Source | None = None
154
+ visibility: Visibility | None = None
155
+ entities: list[EntityRef] | None = None
156
+ metadata: dict[str, Any] | None = None
157
+
158
+ @classmethod
159
+ def from_dict(cls, data: dict[str, Any]) -> IngestEpisodeRequest:
160
+ """Create an IngestEpisodeRequest from a plain dictionary.
161
+
162
+ Accepts a simplified dict with the following keys:
163
+
164
+ - ``content`` (str, required): The episode text content.
165
+ - ``type`` (str, optional): Episode type name (default ``"message"``).
166
+ - ``source`` (str, optional): Connector/system name (default ``"sdk"``).
167
+ - ``actor`` (str, optional): Actor name (default ``"sdk"``).
168
+ - ``tenant_id`` (str, optional): Tenant namespace (default ``"default"``).
169
+ - ``metadata`` (dict, optional): Arbitrary key-value metadata.
170
+
171
+ Any other keys are folded into the ``metadata`` dict so that callers
172
+ can pass domain-specific fields without worrying about the schema.
173
+
174
+ Returns:
175
+ A fully-formed ``IngestEpisodeRequest`` ready for ingestion.
176
+
177
+ Raises:
178
+ ValueError: If ``content`` is missing from the dict.
179
+ """
180
+ data = dict(data) # shallow copy to avoid mutating caller's dict
181
+
182
+ content = data.pop("content", None)
183
+ if content is None:
184
+ raise ValueError(
185
+ "The 'content' key is required when constructing an "
186
+ "IngestEpisodeRequest from a dict."
187
+ )
188
+
189
+ episode_type_raw = data.pop("type", "message")
190
+ try:
191
+ episode_type = EpisodeType(episode_type_raw)
192
+ except ValueError:
193
+ episode_type = EpisodeType.MESSAGE
194
+
195
+ source_name = data.pop("source", "sdk")
196
+ actor_name = data.pop("actor", "sdk")
197
+ tenant_id = data.pop("tenant_id", "default")
198
+ metadata = data.pop("metadata", None)
199
+
200
+ # Remaining unknown keys get merged into metadata so nothing is lost.
201
+ if data:
202
+ if metadata is None:
203
+ metadata = {}
204
+ metadata.update(data)
205
+
206
+ return cls(
207
+ content=content,
208
+ episode_type=episode_type,
209
+ tenant_id=tenant_id,
210
+ actor=Actor(id=actor_name, name=actor_name, actor_type=ActorType.SERVICE),
211
+ source=Source(connector=source_name, external_id="sdk"),
212
+ metadata=metadata if metadata else None,
213
+ )
214
+
215
+
216
+ class IngestEpisodeResponse(BaseModel):
217
+ """Response from POST /v1/episodes."""
218
+
219
+ model_config = _SHARED_CONFIG
220
+
221
+ episode_id: str
222
+ event_id: str
223
+ ingested_at: str
224
+
225
+
226
+ class RememberRequest(BaseModel):
227
+ """Request body for POST /v1/remember."""
228
+
229
+ model_config = _SHARED_CONFIG
230
+
231
+ content: str
232
+ tenant_id: str = "default"
233
+ scope: str | None = None
234
+ metadata: dict[str, Any] | None = None
235
+
236
+
237
+ class RememberResponse(BaseModel):
238
+ """Response from POST /v1/remember."""
239
+
240
+ model_config = _SHARED_CONFIG
241
+
242
+ event_id: str
243
+
244
+
245
+ class RecallRequest(BaseModel):
246
+ """Request body for POST /v1/recall."""
247
+
248
+ model_config = _SHARED_CONFIG
249
+
250
+ query: str
251
+ tenant_id: str = "default"
252
+ max_tokens: int = 4096
253
+ min_confidence: float = 0.0
254
+
255
+
256
+ class RecallResponse(BaseModel):
257
+ """Response from POST /v1/recall."""
258
+
259
+ model_config = _SHARED_CONFIG
260
+
261
+ context: str
262
+ confidence: float
263
+ latency_ms: int = 0
264
+
265
+
266
+ class ForgetRequest(BaseModel):
267
+ """Request body for POST /v1/forget."""
268
+
269
+ model_config = _SHARED_CONFIG
270
+
271
+ query: str | None = None
272
+ reason: str = ""
273
+ tenant_id: str = "default"
274
+
275
+
276
+ class ForgetResponse(BaseModel):
277
+ """Response from POST /v1/forget."""
278
+
279
+ model_config = _SHARED_CONFIG
280
+
281
+ forgotten_entities: int = 0
282
+ forgotten_edges: int = 0
283
+ audit_id: str = ""
284
+
285
+
286
+ class EpisodeBrief(BaseModel):
287
+ """Summary of an episode returned by GET /v1/episodes.
288
+
289
+ This matches the ``EpisodeSummary`` struct in the Rust API which returns
290
+ a lightweight representation without the full content body.
291
+ """
292
+
293
+ model_config = _SHARED_CONFIG
294
+
295
+ id: str
296
+ actor_name: str = ""
297
+ source_connector: str = ""
298
+ episode_type: EpisodeType = EpisodeType.MESSAGE
299
+ content_preview: str = ""
300
+ occurred_at: str = ""
301
+ entity_count: int = 0
302
+
303
+
304
+ class ListEpisodesResponse(BaseModel):
305
+ """Response from GET /v1/episodes."""
306
+
307
+ model_config = _SHARED_CONFIG
308
+
309
+ episodes: list[EpisodeBrief] = Field(default_factory=list)
310
+ total: int = 0
311
+ has_more: bool = False
312
+
313
+
314
+ class HealthResponse(BaseModel):
315
+ """Response from GET /v1/admin/health."""
316
+
317
+ model_config = _SHARED_CONFIG
318
+
319
+ status: str
320
+ storage: str | None = None
321
+ version: str | None = None
322
+
323
+
324
+ class MetricsResponse(BaseModel):
325
+ """Response from GET /v1/admin/metrics."""
326
+
327
+ model_config = _SHARED_CONFIG
328
+
329
+ requests_total: int = 0
330
+ requests_active: int = 0
331
+ errors_total: int = 0
332
+ rate_limited_total: int = 0
333
+
334
+
335
+ # ---------------------------------------------------------------------------
336
+ # Entity / Link / Search models
337
+ # ---------------------------------------------------------------------------
338
+
339
+
340
+ class EntityRelationship(BaseModel):
341
+ """A relationship edge associated with an entity."""
342
+
343
+ id: str
344
+ source_entity_id: str
345
+ target_entity_id: str
346
+ relationship: str
347
+ fact: str
348
+ confidence: float
349
+ created_at: str
350
+
351
+
352
+ class EpisodeBrief(BaseModel):
353
+ """A lightweight summary of an episode."""
354
+
355
+ id: str
356
+ actor_name: str
357
+ source_connector: str
358
+ episode_type: str
359
+ content_preview: str
360
+ occurred_at: str
361
+
362
+
363
+ class EntityResponse(BaseModel):
364
+ """Response from GET /v1/entities/{entity_id}."""
365
+
366
+ id: str
367
+ name: str
368
+ entity_type: str
369
+ first_seen: str
370
+ last_seen: str
371
+ episode_count: int
372
+ relationships: list[EntityRelationship] = []
373
+ recent_episodes: list[EpisodeBrief] = []
374
+
375
+
376
+ class LinkResponse(BaseModel):
377
+ """Response from POST /v1/link."""
378
+
379
+ id: str
380
+ created_at: str
381
+
382
+
383
+ class SearchResponse(BaseModel):
384
+ """Response from POST /v1/search."""
385
+
386
+ context: str
387
+ confidence: float
388
+ latency_ms: int
389
+ episodes: list[EpisodeBrief] = []
390
+ total_episodes: int = 0
cortexdb/py.typed ADDED
File without changes
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: cortexdbai
3
+ Version: 0.2.0
4
+ Summary: The Long-Term Memory Layer for AI Systems
5
+ Project-URL: Homepage, https://cortexdb.io
6
+ Project-URL: Documentation, https://docs.cortexdb.io
7
+ Project-URL: Repository, https://github.com/cortexdb/cortexdb
8
+ Project-URL: Issues, https://github.com/cortexdb/cortexdb/issues
9
+ Project-URL: Changelog, https://github.com/cortexdb/cortexdb/blob/main/CHANGELOG.md
10
+ Author-email: Prashant Malik <prashant@cortexdb.io>
11
+ License-Expression: Apache-2.0
12
+ Keywords: ai,cortexdb,event-sourcing,knowledge-graph,llm,memory
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Database
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: httpx>=0.24
27
+ Requires-Dist: pydantic>=2.0
28
+ Requires-Dist: tenacity>=8.0
29
+ Provides-Extra: async
30
+ Requires-Dist: httpx[http2]; extra == 'async'
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.4; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # CortexDB Python SDK
38
+
39
+ **The Long-Term Memory Layer for AI Systems.**
40
+
41
+ CortexDB gives your AI agents persistent, searchable memory. Store conversations, decisions, incidents, and domain knowledge as structured episodes. Retrieve relevant context with a single call.
42
+
43
+ [![PyPI version](https://img.shields.io/pypi/v/cortexdb.svg)](https://pypi.org/project/cortexdb/)
44
+ [![Python](https://img.shields.io/pypi/pyversions/cortexdb.svg)](https://pypi.org/project/cortexdb/)
45
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/cortexdb/cortexdb/blob/main/LICENSE)
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install cortexdb
51
+ ```
52
+
53
+ For HTTP/2 support (recommended for async workloads):
54
+
55
+ ```bash
56
+ pip install cortexdb[async]
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ```python
62
+ from cortexdb import Cortex
63
+
64
+ # Connect to CortexDB
65
+ cortex = Cortex("http://localhost:3141", api_key="your-api-key")
66
+
67
+ # Remember something
68
+ cortex.remember("The payments service was migrated to Kubernetes on March 15th.")
69
+
70
+ # Recall relevant memories
71
+ result = cortex.recall("When did we migrate payments?")
72
+ for match in result.matches:
73
+ print(f"[{match.confidence:.0%}] {match.content}")
74
+
75
+ # Forget when needed (GDPR, cleanup, etc.)
76
+ cortex.forget(query="old deploy logs", reason="quarterly cleanup")
77
+
78
+ # Search with filters
79
+ results = cortex.search(
80
+ "deploy failure",
81
+ source="github",
82
+ time_range="7d",
83
+ limit=10,
84
+ )
85
+ print(results.context)
86
+ ```
87
+
88
+ ## Async Usage
89
+
90
+ Every method has an async counterpart via `AsyncCortex`:
91
+
92
+ ```python
93
+ import asyncio
94
+ from cortexdb import AsyncCortex
95
+
96
+ async def main():
97
+ async with AsyncCortex("http://localhost:3141", api_key="your-api-key") as cortex:
98
+ await cortex.remember("Async memory storage works great.")
99
+
100
+ result = await cortex.recall("How does async work?")
101
+ for match in result.matches:
102
+ print(match.content)
103
+
104
+ asyncio.run(main())
105
+ ```
106
+
107
+ ## Episode Ingestion
108
+
109
+ For structured data, use episodes with full metadata:
110
+
111
+ ```python
112
+ from cortexdb import Cortex, IngestEpisodeRequest, Actor, Source, ActorType, EpisodeType
113
+
114
+ cortex = Cortex("http://localhost:3141")
115
+
116
+ # Ingest a structured episode
117
+ episode = IngestEpisodeRequest(
118
+ content="PR #412: Add retry logic to payment processor",
119
+ episode_type=EpisodeType.CODE_CHANGE,
120
+ actor=Actor(id="ci-bot", name="CI Bot", actor_type=ActorType.SERVICE),
121
+ source=Source(connector="github", external_id="pr-412", url="https://github.com/org/repo/pull/412"),
122
+ metadata={"branch": "main", "files_changed": 3},
123
+ )
124
+ response = cortex.ingest_episode(episode)
125
+ print(f"Episode {response.episode_id} ingested.")
126
+
127
+ # Or use the smart store shorthand
128
+ cortex.store("Plain text goes through remember().")
129
+ cortex.store({
130
+ "content": "Dict data goes through ingest_episode().",
131
+ "type": "deployment",
132
+ "source": "slack",
133
+ })
134
+ ```
135
+
136
+ ## Entity Lookup
137
+
138
+ Explore entities and their relationships in the knowledge graph:
139
+
140
+ ```python
141
+ cortex = Cortex("http://localhost:3141")
142
+
143
+ # Look up an entity
144
+ entity = cortex.entity("payments-service")
145
+ print(f"{entity.name} ({entity.entity_type})")
146
+ print(f" Episodes: {entity.episode_count}")
147
+ print(f" First seen: {entity.first_seen}")
148
+
149
+ # Browse relationships
150
+ for rel in entity.relationships:
151
+ print(f" {rel.relationship} -> {rel.target_entity_id} ({rel.confidence:.0%})")
152
+
153
+ # Create explicit relationships
154
+ cortex.link(
155
+ source_entity_id="payments-service",
156
+ target_entity_id="auth-service",
157
+ relationship="DEPENDS_ON",
158
+ fact="Payments calls auth for token validation",
159
+ confidence=0.95,
160
+ )
161
+ ```
162
+
163
+ ## Error Handling
164
+
165
+ The SDK provides a structured exception hierarchy:
166
+
167
+ ```python
168
+ from cortexdb import Cortex
169
+ from cortexdb.exceptions import (
170
+ CortexError, # Base exception
171
+ CortexAPIError, # HTTP 4xx/5xx errors
172
+ CortexAuthError, # HTTP 401/403
173
+ CortexRateLimitError, # HTTP 429 (includes retry_after)
174
+ CortexConnectionError,# Network failures
175
+ CortexTimeoutError, # Request timeouts
176
+ )
177
+
178
+ cortex = Cortex("http://localhost:3141")
179
+
180
+ try:
181
+ cortex.remember("important data")
182
+ except CortexRateLimitError as e:
183
+ print(f"Rate limited. Retry after {e.retry_after}s")
184
+ except CortexAuthError as e:
185
+ print(f"Authentication failed: {e.message}")
186
+ except CortexConnectionError:
187
+ print("Cannot reach CortexDB server")
188
+ except CortexAPIError as e:
189
+ print(f"API error [{e.status_code}]: {e.message}")
190
+ ```
191
+
192
+ Transient errors (429, 502, 503, 504) and connection failures are automatically retried with exponential backoff. Configure retry behavior at client initialization:
193
+
194
+ ```python
195
+ cortex = Cortex(
196
+ "http://localhost:3141",
197
+ max_retries=5, # default: 3
198
+ timeout=60.0, # default: 30.0 seconds
199
+ )
200
+ ```
201
+
202
+ ## Configuration
203
+
204
+ ### Constructor Parameters
205
+
206
+ | Parameter | Type | Default | Description |
207
+ |----------------|---------|--------------------------|------------------------------------|
208
+ | `base_url` | `str` | `http://localhost:3141` | CortexDB server URL |
209
+ | `api_key` | `str` | `None` | Bearer token for authentication |
210
+ | `timeout` | `float` | `30.0` | Request timeout in seconds |
211
+ | `max_retries` | `int` | `3` | Max retries for transient failures |
212
+
213
+ ### Environment Variables
214
+
215
+ | Variable | Description |
216
+ |---------------------|----------------------------------------------|
217
+ | `CORTEXDB_API_KEY` | Fallback API key when none is passed directly |
218
+
219
+ ## Convenience Methods
220
+
221
+ | Method | Description |
222
+ |-----------------------|-------------------------------------------------------|
223
+ | `cortex.memory(q)` | Alias for `recall()` -- the GTM one-liner |
224
+ | `cortex.store(data)` | Smart dispatch: `str` -> `remember()`, `dict` -> `ingest_episode()` |
225
+ | `cortex.context(q)` | Recall with higher token budget (8192) for LLM agents |
226
+
227
+ ## Links
228
+
229
+ - [Documentation](https://docs.cortexdb.io)
230
+ - [GitHub Repository](https://github.com/cortexdb/cortexdb)
231
+ - [Issue Tracker](https://github.com/cortexdb/cortexdb/issues)
232
+ - [Changelog](https://github.com/cortexdb/cortexdb/blob/main/CHANGELOG.md)
233
+
234
+ ## License
235
+
236
+ Apache-2.0
@@ -0,0 +1,8 @@
1
+ cortexdb/__init__.py,sha256=LSlY8w1BUUlJsHxFly1AfnpQG_KplWZ08B11wh-kgHo,1616
2
+ cortexdb/client.py,sha256=2wPZmzwyTgIN6indk2v2HHdrtjKTY0ZmZOgDTAqtzh8,32045
3
+ cortexdb/exceptions.py,sha256=2ldGt_y3K2zx299VvNUVG_b9ZN0CXPbgOdJTaVnhScc,1991
4
+ cortexdb/models.py,sha256=kG-us0qZSKBGZ0Oq8DXVXhq6y-sYvEWw8FdBlPDpTtY,9965
5
+ cortexdb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ cortexdbai-0.2.0.dist-info/METADATA,sha256=mYOFUmx_WBp1yhERLac-QA4TJ4ycx8NrMcvyDm9CjaA,7763
7
+ cortexdbai-0.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
8
+ cortexdbai-0.2.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