cuemap 0.4.1__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.

Potentially problematic release.


This version of cuemap might be problematic. Click here for more details.

cuemap/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ """
2
+ CueMap: Redis for AI Agents
3
+
4
+ A high-performance, temporal-associative memory store.
5
+ You give us the cues, we give you the right memory at the right time.
6
+
7
+ Example:
8
+ >>> from cuemap import CueMap
9
+ >>>
10
+ >>> client = CueMap()
11
+ >>>
12
+ >>> # Add a memory with cues
13
+ >>> client.add("The server password is abc123", cues=["server", "password"])
14
+ >>>
15
+ >>> # Recall by cues
16
+ >>> results = client.recall(["server", "password"])
17
+ >>> print(results[0].content)
18
+ """
19
+
20
+ from .client import CueMap, AsyncCueMap
21
+ from .models import Memory, RecallResult
22
+ from .exceptions import CueMapError, ConnectionError, AuthenticationError
23
+
24
+ __version__ = "0.2.0"
25
+ __all__ = [
26
+ "CueMap",
27
+ "AsyncCueMap",
28
+ "Memory",
29
+ "RecallResult",
30
+ "CueMapError",
31
+ "ConnectionError",
32
+ "AuthenticationError",
33
+ ]
cuemap/client.py ADDED
@@ -0,0 +1,336 @@
1
+ """Pure CueMap client - no magic, just speed."""
2
+
3
+ import httpx
4
+ from typing import List, Optional, Dict, Any
5
+
6
+ from .models import Memory, RecallResult
7
+ from .exceptions import CueMapError, ConnectionError, AuthenticationError
8
+
9
+
10
+ class CueMap:
11
+ """
12
+ Pure CueMap client.
13
+
14
+ No auto-cue extraction. No semantic matching. Just fast memory storage.
15
+
16
+ Example:
17
+ >>> client = CueMap()
18
+ >>> client.add("Important note", cues=["work", "urgent"])
19
+ >>> results = client.recall(["work"])
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ url: str = "http://localhost:8080",
25
+ api_key: Optional[str] = None,
26
+ project_id: Optional[str] = None,
27
+ timeout: float = 30.0
28
+ ):
29
+ """
30
+ Initialize CueMap client.
31
+
32
+ Args:
33
+ url: CueMap server URL
34
+ api_key: Optional API key for authentication
35
+ project_id: Optional project ID for multi-tenancy
36
+ timeout: Request timeout in seconds
37
+ """
38
+ self.url = url
39
+ self.api_key = api_key
40
+ self.project_id = project_id
41
+
42
+ self.client = httpx.Client(
43
+ base_url=url,
44
+ timeout=timeout
45
+ )
46
+
47
+ def _headers(self) -> Dict[str, str]:
48
+ """Get request headers."""
49
+ headers = {}
50
+ if self.api_key:
51
+ headers["X-API-Key"] = self.api_key
52
+ if self.project_id:
53
+ headers["X-Project-ID"] = self.project_id
54
+ return headers
55
+
56
+ def add(
57
+ self,
58
+ content: str,
59
+ cues: List[str],
60
+ metadata: Optional[Dict[str, Any]] = None
61
+ ) -> str:
62
+ """
63
+ Add a memory.
64
+
65
+ Args:
66
+ content: Memory content
67
+ cues: List of cues (tags) for retrieval
68
+ metadata: Optional metadata
69
+
70
+ Returns:
71
+ Memory ID
72
+
73
+ Example:
74
+ >>> client.add(
75
+ ... "Meeting with John at 3pm",
76
+ ... cues=["meeting", "john", "calendar"]
77
+ ... )
78
+ """
79
+ response = self.client.post(
80
+ "/memories",
81
+ json={
82
+ "content": content,
83
+ "cues": cues,
84
+ "metadata": metadata or {}
85
+ },
86
+ headers=self._headers()
87
+ )
88
+
89
+ if response.status_code == 401:
90
+ raise AuthenticationError("Invalid API key")
91
+ elif response.status_code != 200:
92
+ raise CueMapError(f"Failed to add memory: {response.status_code}")
93
+
94
+ return response.json()["id"]
95
+
96
+ def recall(
97
+ self,
98
+ cues: List[str],
99
+ limit: int = 10,
100
+ auto_reinforce: bool = False,
101
+ min_intersection: Optional[int] = None,
102
+ projects: Optional[List[str]] = None
103
+ ) -> List[RecallResult]:
104
+ """
105
+ Recall memories by cues.
106
+
107
+ Args:
108
+ cues: List of cues to search for
109
+ limit: Maximum results to return
110
+ auto_reinforce: Automatically reinforce retrieved memories
111
+ min_intersection: Minimum number of cues that must match (for strict AND logic)
112
+ projects: List of project IDs for cross-domain queries (multi-tenant only)
113
+
114
+ Returns:
115
+ List of recall results
116
+
117
+ Example:
118
+ >>> # OR logic (default): matches any cue
119
+ >>> results = client.recall(["meeting", "john"])
120
+
121
+ >>> # AND logic: requires both cues
122
+ >>> results = client.recall(["meeting", "john"], min_intersection=2)
123
+
124
+ >>> # Cross-domain query (multi-tenant)
125
+ >>> results = client.recall(["urgent"], projects=["sales", "support"])
126
+ """
127
+ payload = {
128
+ "cues": cues,
129
+ "limit": limit,
130
+ "auto_reinforce": auto_reinforce
131
+ }
132
+
133
+ if min_intersection is not None:
134
+ payload["min_intersection"] = min_intersection
135
+
136
+ if projects is not None:
137
+ payload["projects"] = projects
138
+
139
+ response = self.client.post(
140
+ "/recall",
141
+ json=payload,
142
+ headers=self._headers()
143
+ )
144
+
145
+ if response.status_code != 200:
146
+ raise CueMapError(f"Failed to recall: {response.status_code}")
147
+
148
+ results = response.json()["results"]
149
+ return [RecallResult(**r) for r in results]
150
+
151
+ def reinforce(self, memory_id: str, cues: List[str]) -> bool:
152
+ """
153
+ Reinforce a memory on specific cue pathways.
154
+
155
+ Args:
156
+ memory_id: Memory ID
157
+ cues: Cues to reinforce on
158
+
159
+ Returns:
160
+ Success status
161
+ """
162
+ response = self.client.patch(
163
+ f"/memories/{memory_id}/reinforce",
164
+ json={"cues": cues},
165
+ headers=self._headers()
166
+ )
167
+
168
+ return response.status_code == 200
169
+
170
+ def get(self, memory_id: str) -> Memory:
171
+ """Get a memory by ID."""
172
+ response = self.client.get(
173
+ f"/memories/{memory_id}",
174
+ headers=self._headers()
175
+ )
176
+
177
+ if response.status_code == 404:
178
+ raise CueMapError(f"Memory not found: {memory_id}")
179
+ elif response.status_code != 200:
180
+ raise CueMapError(f"Failed to get memory: {response.status_code}")
181
+
182
+ return Memory(**response.json())
183
+
184
+ def stats(self) -> Dict[str, Any]:
185
+ """Get server statistics."""
186
+ response = self.client.get(
187
+ "/stats",
188
+ headers=self._headers()
189
+ )
190
+
191
+ return response.json()
192
+
193
+ def close(self):
194
+ """Close the client."""
195
+ self.client.close()
196
+
197
+ def __enter__(self):
198
+ return self
199
+
200
+ def __exit__(self, exc_type, exc_val, exc_tb):
201
+ self.close()
202
+
203
+
204
+ class AsyncCueMap:
205
+ """
206
+ Async CueMap client.
207
+
208
+ Example:
209
+ >>> async with AsyncCueMap() as client:
210
+ ... await client.add("Note", cues=["work"])
211
+ ... results = await client.recall(["work"])
212
+ """
213
+
214
+ def __init__(
215
+ self,
216
+ url: str = "http://localhost:8080",
217
+ api_key: Optional[str] = None,
218
+ project_id: Optional[str] = None,
219
+ timeout: float = 30.0
220
+ ):
221
+ self.url = url
222
+ self.api_key = api_key
223
+ self.project_id = project_id
224
+
225
+ self.client = httpx.AsyncClient(
226
+ base_url=url,
227
+ timeout=timeout
228
+ )
229
+
230
+ def _headers(self) -> Dict[str, str]:
231
+ headers = {}
232
+ if self.api_key:
233
+ headers["X-API-Key"] = self.api_key
234
+ if self.project_id:
235
+ headers["X-Project-ID"] = self.project_id
236
+ return headers
237
+
238
+ async def add(
239
+ self,
240
+ content: str,
241
+ cues: List[str],
242
+ metadata: Optional[Dict[str, Any]] = None
243
+ ) -> str:
244
+ """Add a memory (async)."""
245
+ response = await self.client.post(
246
+ "/memories",
247
+ json={
248
+ "content": content,
249
+ "cues": cues,
250
+ "metadata": metadata or {}
251
+ },
252
+ headers=self._headers()
253
+ )
254
+
255
+ if response.status_code == 401:
256
+ raise AuthenticationError("Invalid API key")
257
+ elif response.status_code != 200:
258
+ raise CueMapError(f"Failed to add memory: {response.status_code}")
259
+
260
+ return response.json()["id"]
261
+
262
+ async def recall(
263
+ self,
264
+ cues: List[str],
265
+ limit: int = 10,
266
+ auto_reinforce: bool = False,
267
+ min_intersection: Optional[int] = None,
268
+ projects: Optional[List[str]] = None
269
+ ) -> List[RecallResult]:
270
+ """Recall memories (async)."""
271
+ payload = {
272
+ "cues": cues,
273
+ "limit": limit,
274
+ "auto_reinforce": auto_reinforce
275
+ }
276
+
277
+ if min_intersection is not None:
278
+ payload["min_intersection"] = min_intersection
279
+
280
+ if projects is not None:
281
+ payload["projects"] = projects
282
+
283
+ response = await self.client.post(
284
+ "/recall",
285
+ json=payload,
286
+ headers=self._headers()
287
+ )
288
+
289
+ if response.status_code != 200:
290
+ raise CueMapError(f"Failed to recall: {response.status_code}")
291
+
292
+ results = response.json()["results"]
293
+ return [RecallResult(**r) for r in results]
294
+
295
+ async def reinforce(self, memory_id: str, cues: List[str]) -> bool:
296
+ """Reinforce a memory (async)."""
297
+ response = await self.client.patch(
298
+ f"/memories/{memory_id}/reinforce",
299
+ json={"cues": cues},
300
+ headers=self._headers()
301
+ )
302
+
303
+ return response.status_code == 200
304
+
305
+ async def get(self, memory_id: str) -> Memory:
306
+ """Get a memory by ID (async)."""
307
+ response = await self.client.get(
308
+ f"/memories/{memory_id}",
309
+ headers=self._headers()
310
+ )
311
+
312
+ if response.status_code == 404:
313
+ raise CueMapError(f"Memory not found: {memory_id}")
314
+ elif response.status_code != 200:
315
+ raise CueMapError(f"Failed to get memory: {response.status_code}")
316
+
317
+ return Memory(**response.json())
318
+
319
+ async def stats(self) -> Dict[str, Any]:
320
+ """Get server statistics (async)."""
321
+ response = await self.client.get(
322
+ "/stats",
323
+ headers=self._headers()
324
+ )
325
+
326
+ return response.json()
327
+
328
+ async def close(self):
329
+ """Close the client."""
330
+ await self.client.aclose()
331
+
332
+ async def __aenter__(self):
333
+ return self
334
+
335
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
336
+ await self.close()
cuemap/exceptions.py ADDED
@@ -0,0 +1,16 @@
1
+ """Exceptions."""
2
+
3
+
4
+ class CueMapError(Exception):
5
+ """Base exception."""
6
+ pass
7
+
8
+
9
+ class ConnectionError(CueMapError):
10
+ """Connection failed."""
11
+ pass
12
+
13
+
14
+ class AuthenticationError(CueMapError):
15
+ """Authentication failed."""
16
+ pass
cuemap/models.py ADDED
@@ -0,0 +1,25 @@
1
+ """Data models."""
2
+
3
+ from typing import Dict, List, Any
4
+ from pydantic import BaseModel, Field
5
+
6
+
7
+ class Memory(BaseModel):
8
+ """A memory object."""
9
+
10
+ id: str
11
+ content: str
12
+ cues: List[str] = Field(default_factory=list)
13
+ metadata: Dict[str, Any] = Field(default_factory=dict)
14
+
15
+
16
+ class RecallResult(BaseModel):
17
+ """Result from a recall operation."""
18
+
19
+ memory_id: str
20
+ content: str
21
+ score: float
22
+ intersection_count: int
23
+ recency_score: float
24
+ reinforcement_score: float
25
+ metadata: Dict[str, Any] = Field(default_factory=dict)
@@ -0,0 +1,337 @@
1
+ Metadata-Version: 2.4
2
+ Name: cuemap
3
+ Version: 0.4.1
4
+ Summary: Redis for AI Agents - High-performance temporal-associative memory
5
+ Author-email: CueMap Team <hello@cuemap.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/cuemap-dev/sdks
8
+ Project-URL: Documentation, https://github.com/cuemap-dev/sdks/blob/main/python/README.md
9
+ Project-URL: Repository, https://github.com/cuemap-dev/sdks
10
+ Project-URL: Issues, https://github.com/cuemap-dev/sdks/issues
11
+ Project-URL: Engine, https://github.com/cuemap-dev/engine
12
+ Keywords: ai,memory,agents,redis,temporal,associative,llm,rag
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: httpx>=0.25.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
32
+ Requires-Dist: build>=1.0.0; extra == "dev"
33
+ Requires-Dist: twine>=4.0.0; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # CueMap: Redis for AI Agents
37
+
38
+ **High-performance, temporal-associative memory store.**
39
+
40
+ You give us the cues, we give you the right memory at the right time.
41
+
42
+ ## Why CueMap?
43
+
44
+ Redis doesn't auto-serialize your data. It doesn't guess what you mean. It just stores keys and values **blazing fast**.
45
+
46
+ CueMap is the same philosophy for AI agent memory:
47
+ - ✅ **You control the cues** (tags)
48
+ - ✅ **We handle the speed** (sub-millisecond)
49
+ - ✅ **No magic** (predictable behavior)
50
+ - ✅ **No dependencies** (5KB SDK)
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install cuemap
56
+ ```
57
+
58
+ That's it. No ML models. No transformers. Just pure speed.
59
+
60
+ ## Quick Start
61
+
62
+ ### 1. Start the Engine
63
+
64
+ ```bash
65
+ docker run -p 8080:8080 cuemap/engine:latest
66
+ ```
67
+
68
+ ### 2. Use the SDK
69
+
70
+ ```python
71
+ from cuemap import CueMap
72
+
73
+ client = CueMap()
74
+
75
+ # Add a memory with cues
76
+ client.add(
77
+ "The server password is abc123",
78
+ cues=["server", "password", "credentials"]
79
+ )
80
+
81
+ # Recall by cues
82
+ results = client.recall(["server", "password"])
83
+ print(results[0].content)
84
+ # Output: "The server password is abc123"
85
+ ```
86
+
87
+ ## Core API
88
+
89
+ ### Add Memory
90
+
91
+ ```python
92
+ memory_id = client.add(
93
+ content="Meeting with John at 3pm",
94
+ cues=["meeting", "john", "calendar", "today"]
95
+ )
96
+ ```
97
+
98
+ ### Recall Memories
99
+
100
+ ```python
101
+ # OR logic (default): matches any cue
102
+ results = client.recall(
103
+ cues=["meeting", "john"],
104
+ limit=10
105
+ )
106
+
107
+ for result in results:
108
+ print(f"{result.content} (score: {result.score})")
109
+
110
+ # AND logic: requires all cues to match
111
+ results = client.recall(
112
+ cues=["meeting", "john"],
113
+ min_intersection=2 # Both cues must match
114
+ )
115
+
116
+ # Cross-domain query (multi-tenant mode)
117
+ results = client.recall(
118
+ cues=["urgent"],
119
+ projects=["sales", "support", "engineering"]
120
+ )
121
+ ```
122
+
123
+ ### Reinforce Memory
124
+
125
+ ```python
126
+ # Make a memory more accessible
127
+ client.reinforce(memory_id, cues=["important", "urgent"])
128
+ ```
129
+
130
+ ## How It Works
131
+
132
+ ### Temporal-Associative Retrieval
133
+
134
+ CueMap uses **Iterative Deepening Intersection**:
135
+
136
+ 1. **Intersection**: Memories matching multiple cues rank higher
137
+ 2. **Recency**: Recent memories are more accessible
138
+ 3. **Reinforcement**: Frequently accessed memories stay "front of mind"
139
+
140
+ ```python
141
+ # Add memories
142
+ client.add("Pizza recipe", cues=["food", "italian"])
143
+ client.add("Pasta recipe", cues=["food", "italian"])
144
+ client.add("Sushi recipe", cues=["food", "japanese"])
145
+
146
+ # Query with multiple cues
147
+ results = client.recall(["food", "italian"])
148
+ # Returns: Pizza and Pasta (both match 2 cues)
149
+ # Sushi is filtered out (only matches 1 cue)
150
+ ```
151
+
152
+ ### Performance (~1M memories)
153
+
154
+ - **Write P99**: 0.33ms
155
+ - **Read P99**: 0.37ms
156
+ - **Throughput**: 2,900+ ops/sec
157
+ - **Accuracy**: 100% (validated on 120 test scenarios)
158
+
159
+ ## Recipes
160
+
161
+ ### Recipe 1: Use with OpenAI
162
+
163
+ ```python
164
+ from cuemap import CueMap
165
+ import openai
166
+
167
+ client = CueMap()
168
+
169
+ def store_with_ai_tags(content: str):
170
+ # Let OpenAI extract the cues
171
+ response = openai.chat.completions.create(
172
+ model="gpt-4",
173
+ messages=[{
174
+ "role": "system",
175
+ "content": "Extract 3-5 search tags from the text. Return as JSON array."
176
+ }, {
177
+ "role": "user",
178
+ "content": content
179
+ }]
180
+ )
181
+
182
+ cues = response.choices[0].message.content # ["tag1", "tag2", ...]
183
+
184
+ # Store in CueMap
185
+ return client.add(content, cues=cues)
186
+
187
+ # Usage
188
+ store_with_ai_tags("I need to buy groceries this weekend")
189
+ # OpenAI extracts: ["shopping", "groceries", "weekend", "todo"]
190
+ ```
191
+
192
+ ### Recipe 2: Use with LangChain
193
+
194
+ ```python
195
+ from cuemap import CueMap
196
+ from langchain.memory import BaseMemory
197
+
198
+ class CueMapMemory(BaseMemory):
199
+ def __init__(self, cue_extractor):
200
+ self.client = CueMap()
201
+ self.extract_cues = cue_extractor
202
+
203
+ def save_context(self, inputs, outputs):
204
+ context = f"User: {inputs['input']}\nAI: {outputs['output']}"
205
+ cues = self.extract_cues(context)
206
+ self.client.add(context, cues=cues)
207
+
208
+ def load_memory_variables(self, inputs):
209
+ cues = self.extract_cues(inputs['input'])
210
+ results = self.client.recall(cues, limit=5)
211
+ return {"history": "\n".join([r.content for r in results])}
212
+ ```
213
+
214
+ ### Recipe 3: Manual Cues (Production)
215
+
216
+ ```python
217
+ # For production: explicit, predictable cues
218
+ client.add(
219
+ "Deploy command: kubectl apply -f deployment.yaml",
220
+ cues=["deployment", "kubernetes", "commands", "devops"]
221
+ )
222
+
223
+ client.add(
224
+ "API endpoint: https://api.example.com/v1/users",
225
+ cues=["api", "endpoint", "users", "documentation"]
226
+ )
227
+
228
+ # Query with specific cues
229
+ client.recall(["deployment", "kubernetes"])
230
+ client.recall(["api", "users"])
231
+ ```
232
+
233
+ ## Running the Engine
234
+
235
+ CueMap requires a running engine. Choose your deployment:
236
+
237
+ ### Option 1: Docker (Recommended)
238
+
239
+ ```bash
240
+ docker run -p 8080:8080 cuemap/engine:latest
241
+ ```
242
+
243
+ ### Option 2: From Source
244
+
245
+ ```bash
246
+ git clone https://github.com/cuemap-dev/engine
247
+ cd engine
248
+ cargo build --release
249
+ ./target/release/cuemap-rust --port 8080
250
+ ```
251
+
252
+ ## Configuration
253
+
254
+ ### Connect to Engine
255
+
256
+ ```python
257
+ # Default (localhost)
258
+ client = CueMap()
259
+
260
+ # Custom URL
261
+ client = CueMap(url="http://your-server:8080")
262
+
263
+ # With authentication
264
+ client = CueMap(
265
+ url="http://your-server:8080",
266
+ api_key="your-secret-key"
267
+ )
268
+ ```
269
+
270
+ ### Multi-tenancy
271
+
272
+ ```python
273
+ # Use project isolation
274
+ client = CueMap(
275
+ url="http://your-server:8080",
276
+ project_id="my-project"
277
+ )
278
+ ```
279
+
280
+ ### Async Support
281
+
282
+ ```python
283
+ from cuemap import AsyncCueMap
284
+
285
+ async with AsyncCueMap() as client:
286
+ await client.add("Note", cues=["work"])
287
+ results = await client.recall(["work"])
288
+ ```
289
+
290
+ ## Philosophy
291
+
292
+ ### What CueMap Does
293
+
294
+ ✅ **Fast storage** - Sub-millisecond retrieval
295
+ ✅ **Temporal ordering** - Recent memories prioritized
296
+ ✅ **Intersection scoring** - Multi-cue matching
297
+ ✅ **Reinforcement** - Move-to-front operation
298
+
299
+ ### What CueMap Doesn't Do
300
+
301
+ ❌ **Auto-tagging** - You provide the cues
302
+ ❌ **Semantic search** - Use your own embeddings
303
+ ❌ **LLM integration** - Bring your own model
304
+ ❌ **Magic** - Explicit and predictable
305
+
306
+ ## Why This Approach?
307
+
308
+ **Redis Philosophy**: Don't guess what the user wants. Provide primitives. Let them build.
309
+
310
+ **CueMap Philosophy**: Don't auto-extract cues. Don't auto-embed. Just store and retrieve **fast**.
311
+
312
+ **Benefits**:
313
+ - 🚀 **5KB SDK** (vs 500MB with ML models)
314
+ - ⚡ **Instant install** (1 second vs 5 minutes)
315
+ - 🎯 **Predictable** (no ML black boxes)
316
+ - 🔧 **Flexible** (works with any LLM/embedding model)
317
+
318
+ ## Comparison
319
+
320
+ | Feature | CueMap | Vector DBs |
321
+ |---------|--------|------------|
322
+ | **Speed** | 0.37ms P99 | 200-500ms |
323
+ | **SDK Size** | 5KB | 500MB+ |
324
+ | **Dependencies** | 2 | 50+ |
325
+ | **Install Time** | 1 sec | 5 min |
326
+ | **Cue Control** | Explicit | Auto (black box) |
327
+ | **Temporal** | ✅ Built-in | ❌ None |
328
+
329
+ ## Documentation
330
+
331
+ - [Engine Repository](https://github.com/cuemap-dev/engine)
332
+ - [SDKs Repository](https://github.com/cuemap-dev/sdks)
333
+ - [Examples](https://github.com/cuemap-dev/sdks/tree/main/python/examples)
334
+
335
+ ## License
336
+
337
+ MIT
@@ -0,0 +1,9 @@
1
+ cuemap/__init__.py,sha256=jy_21twtKaRLJq2AunVstNgFCIfe8QCjPpH5quxTz3c,817
2
+ cuemap/client.py,sha256=HzLzPAYjHKPVJstBIH7G3QNZ3k_D5Obt_hPLKJPQ3rw,9819
3
+ cuemap/exceptions.py,sha256=LPwk-pXDBWP-aA1m6w9BNqfM-zmT3-ZPZcyXdPDE9PE,245
4
+ cuemap/models.py,sha256=YgnKNtWJLad_s02koDhCSbqdm1MuN7cp_ih98J6gojY,566
5
+ cuemap-0.4.1.dist-info/licenses/LICENSE,sha256=XroXVr5iCchm6KhTUtnrjVAhcErBwmvhl7EwcjeI_yI,1063
6
+ cuemap-0.4.1.dist-info/METADATA,sha256=v1VekU6uNZWyIwfB2gBIFLJNtGr1UZsDo2yLuC4ShXU,8461
7
+ cuemap-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ cuemap-0.4.1.dist-info/top_level.txt,sha256=bZ0CmDM_glT73Eeo0pHCyjpEThjesQ0Zx9r3D4_N9LU,7
9
+ cuemap-0.4.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CueMap
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ cuemap