prismlang 0.1.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.
prismlang/__init__.py ADDED
@@ -0,0 +1,88 @@
1
+ """PrismLang — Deterministic Vector Language Protocol for Multi-Agent AI Orchestration.
2
+
3
+ Public API
4
+ ----------
5
+ from prismlang import (
6
+ PrismState,
7
+ PrismEnvelope,
8
+ PrismProjector,
9
+ TaxonomyConfig,
10
+ Category,
11
+ prism_node,
12
+ BoundaryTranslator,
13
+ JsonFileCheckpointer,
14
+ PostgresCheckpointer,
15
+ )
16
+ """
17
+
18
+ from .config import DEFAULT_ALPHA, DEFAULT_K, EMBED_DIM
19
+ from .envelope import PrismEnvelope
20
+ from .exceptions import (
21
+ PrismLangError,
22
+ EncoderError,
23
+ ModelDownloadError,
24
+ ModelNotFoundError,
25
+ TokenizerNotFoundError,
26
+ TaxonomyError,
27
+ DuplicateCategoryError,
28
+ UnknownCategoryError,
29
+ EmptyTaxonomyError,
30
+ ProjectionError,
31
+ ZeroVectorError,
32
+ DimensionMismatchError,
33
+ CheckpointerError,
34
+ CheckpointerConnectionError,
35
+ CheckpointerSchemaError,
36
+ TenantError,
37
+ MissingTenantError,
38
+ )
39
+ from .state import PrismState
40
+ from .taxonomy import Category, TaxonomyConfig
41
+ from .projector import PrismProjector
42
+ from .middleware import prism_node, async_prism_node
43
+ from .translator import BoundaryTranslator
44
+ from .checkpointer import (
45
+ JsonFileCheckpointer,
46
+ PostgresCheckpointer,
47
+ AsyncJsonFileCheckpointer,
48
+ AsyncPostgresCheckpointer,
49
+ )
50
+
51
+ __version__ = "0.1.0"
52
+ __author__ = "Amin Parva / Insight IT Solutions LLC"
53
+
54
+ __all__ = [
55
+ "PrismState",
56
+ "PrismEnvelope",
57
+ "PrismProjector",
58
+ "TaxonomyConfig",
59
+ "Category",
60
+ "prism_node",
61
+ "BoundaryTranslator",
62
+ "JsonFileCheckpointer",
63
+ "PostgresCheckpointer",
64
+ "AsyncJsonFileCheckpointer",
65
+ "AsyncPostgresCheckpointer",
66
+ "async_prism_node",
67
+ "DEFAULT_ALPHA",
68
+ "DEFAULT_K",
69
+ "EMBED_DIM",
70
+ # Exceptions
71
+ "PrismLangError",
72
+ "EncoderError",
73
+ "ModelDownloadError",
74
+ "ModelNotFoundError",
75
+ "TokenizerNotFoundError",
76
+ "TaxonomyError",
77
+ "DuplicateCategoryError",
78
+ "UnknownCategoryError",
79
+ "EmptyTaxonomyError",
80
+ "ProjectionError",
81
+ "ZeroVectorError",
82
+ "DimensionMismatchError",
83
+ "CheckpointerError",
84
+ "CheckpointerConnectionError",
85
+ "CheckpointerSchemaError",
86
+ "TenantError",
87
+ "MissingTenantError",
88
+ ]
@@ -0,0 +1,547 @@
1
+ """PrismLang checkpointers for persisting PrismState across graph runs.
2
+
3
+ Two backends are provided:
4
+
5
+ JsonFileCheckpointer — zero extra dependencies, writes one JSON file per
6
+ checkpoint under a local directory. Good for dev/testing.
7
+
8
+ PostgresCheckpointer — stores envelope sequences in a JSONB column. Requires
9
+ psycopg2-binary. Can share the same Postgres instance as
10
+ PrismRAG by pointing DATABASE_URL at the same DSN.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import json
16
+ import os
17
+ import uuid
18
+ from pathlib import Path
19
+ from typing import Any, Dict, Iterator, Optional, Tuple
20
+
21
+ from langgraph.checkpoint.base import BaseCheckpointSaver, Checkpoint, CheckpointMetadata
22
+ from langgraph.checkpoint.base import CheckpointTuple
23
+
24
+ from .exceptions import CheckpointerConnectionError, CheckpointerSchemaError
25
+
26
+
27
+ # ------------------------------------------------------------------ #
28
+ # JSON file backend #
29
+ # ------------------------------------------------------------------ #
30
+
31
+ class JsonFileCheckpointer(BaseCheckpointSaver):
32
+ """Persists checkpoints as JSON files under a local directory.
33
+
34
+ Directory layout:
35
+ {root}/{thread_id}/{checkpoint_id}.json
36
+ """
37
+
38
+ def __init__(self, root: str = ".prismlang_checkpoints") -> None:
39
+ super().__init__()
40
+ self.root = Path(root)
41
+ self.root.mkdir(parents=True, exist_ok=True)
42
+
43
+ def _path(self, thread_id: str, checkpoint_id: str) -> Path:
44
+ thread_dir = self.root / thread_id
45
+ thread_dir.mkdir(parents=True, exist_ok=True)
46
+ return thread_dir / f"{checkpoint_id}.json"
47
+
48
+ def get_tuple(self, config: Dict[str, Any]) -> Optional[CheckpointTuple]:
49
+ thread_id = config["configurable"]["thread_id"]
50
+ checkpoint_id = config["configurable"].get("checkpoint_id")
51
+
52
+ if checkpoint_id:
53
+ p = self._path(thread_id, checkpoint_id)
54
+ if not p.exists():
55
+ return None
56
+ data = json.loads(p.read_text())
57
+ else:
58
+ # Return the latest checkpoint for this thread
59
+ thread_dir = self.root / thread_id
60
+ if not thread_dir.exists():
61
+ return None
62
+ files = sorted(thread_dir.glob("*.json"))
63
+ if not files:
64
+ return None
65
+ data = json.loads(files[-1].read_text())
66
+
67
+ return CheckpointTuple(
68
+ config=config,
69
+ checkpoint=data["checkpoint"],
70
+ metadata=data.get("metadata", {}),
71
+ parent_config=data.get("parent_config"),
72
+ )
73
+
74
+ def list(
75
+ self,
76
+ config: Optional[Dict[str, Any]],
77
+ *,
78
+ filter: Optional[Dict[str, Any]] = None,
79
+ before: Optional[Dict[str, Any]] = None,
80
+ limit: Optional[int] = None,
81
+ ) -> Iterator[CheckpointTuple]:
82
+ thread_id = (config or {}).get("configurable", {}).get("thread_id", "")
83
+ thread_dir = self.root / thread_id
84
+ if not thread_dir.exists():
85
+ return
86
+ files = sorted(thread_dir.glob("*.json"), reverse=True)
87
+ count = 0
88
+ for f in files:
89
+ if limit and count >= limit:
90
+ break
91
+ data = json.loads(f.read_text())
92
+ yield CheckpointTuple(
93
+ config={"configurable": {"thread_id": thread_id, "checkpoint_id": f.stem}},
94
+ checkpoint=data["checkpoint"],
95
+ metadata=data.get("metadata", {}),
96
+ parent_config=data.get("parent_config"),
97
+ )
98
+ count += 1
99
+
100
+ def put(
101
+ self,
102
+ config: Dict[str, Any],
103
+ checkpoint: Checkpoint,
104
+ metadata: CheckpointMetadata,
105
+ new_versions: Dict[str, Any],
106
+ ) -> Dict[str, Any]:
107
+ thread_id = config["configurable"]["thread_id"]
108
+ checkpoint_id = checkpoint["id"]
109
+ p = self._path(thread_id, checkpoint_id)
110
+ p.write_text(
111
+ json.dumps(
112
+ {
113
+ "checkpoint": checkpoint,
114
+ "metadata": metadata,
115
+ "parent_config": config,
116
+ },
117
+ default=str,
118
+ )
119
+ )
120
+ return {**config, "configurable": {**config["configurable"], "checkpoint_id": checkpoint_id}}
121
+
122
+ def put_writes(
123
+ self,
124
+ config: Dict[str, Any],
125
+ writes: list,
126
+ task_id: str,
127
+ ) -> None:
128
+ # For this simple backend writes are committed atomically in put()
129
+ pass
130
+
131
+
132
+ # ------------------------------------------------------------------ #
133
+ # PostgreSQL backend #
134
+ # ------------------------------------------------------------------ #
135
+
136
+ _CREATE_TABLE = """
137
+ CREATE TABLE IF NOT EXISTS prismlang_checkpoint (
138
+ thread_id TEXT NOT NULL,
139
+ checkpoint_id TEXT NOT NULL,
140
+ tenant_id TEXT,
141
+ checkpoint JSONB NOT NULL,
142
+ metadata JSONB NOT NULL DEFAULT '{}',
143
+ parent_config JSONB,
144
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
145
+ PRIMARY KEY (thread_id, checkpoint_id)
146
+ );
147
+ CREATE INDEX IF NOT EXISTS ix_prismlang_cp_thread
148
+ ON prismlang_checkpoint (thread_id, created_at DESC);
149
+ """
150
+
151
+
152
+ class PostgresCheckpointer(BaseCheckpointSaver):
153
+ """Persists PrismState checkpoints in a PostgreSQL JSONB column.
154
+
155
+ Compatible with PrismRAG's database — point DATABASE_URL at the same DSN.
156
+
157
+ Args:
158
+ dsn: PostgreSQL DSN string, e.g. "postgresql://user:pass@localhost/db".
159
+ Falls back to the DATABASE_URL environment variable.
160
+ """
161
+
162
+ def __init__(self, dsn: Optional[str] = None) -> None:
163
+ super().__init__()
164
+ try:
165
+ import psycopg2
166
+ except ImportError as exc:
167
+ raise ImportError(
168
+ "psycopg2-binary is required for PostgresCheckpointer. "
169
+ "Install it with: pip install psycopg2-binary"
170
+ ) from exc
171
+
172
+ self._dsn = dsn or os.environ.get("DATABASE_URL")
173
+ if not self._dsn:
174
+ raise CheckpointerConnectionError(
175
+ "postgresql", cause=ValueError("No DSN provided. Pass dsn= or set the DATABASE_URL environment variable.")
176
+ )
177
+ self._ensure_schema()
178
+
179
+ def _connect(self):
180
+ import psycopg2
181
+ try:
182
+ return psycopg2.connect(self._dsn)
183
+ except Exception as exc:
184
+ raise CheckpointerConnectionError("postgresql", cause=exc) from exc
185
+
186
+ def _ensure_schema(self) -> None:
187
+ try:
188
+ conn = self._connect()
189
+ with conn.cursor() as cur:
190
+ cur.execute(_CREATE_TABLE)
191
+ conn.commit()
192
+ conn.close()
193
+ except CheckpointerConnectionError:
194
+ raise
195
+ except Exception as exc:
196
+ raise CheckpointerSchemaError(
197
+ f"Failed to create prismlang_checkpoint schema: {exc}"
198
+ ) from exc
199
+
200
+ def get_tuple(self, config: Dict[str, Any]) -> Optional[CheckpointTuple]:
201
+ thread_id = config["configurable"]["thread_id"]
202
+ checkpoint_id = config["configurable"].get("checkpoint_id")
203
+
204
+ conn = self._connect()
205
+ try:
206
+ with conn.cursor() as cur:
207
+ if checkpoint_id:
208
+ cur.execute(
209
+ "SELECT checkpoint, metadata, parent_config FROM prismlang_checkpoint "
210
+ "WHERE thread_id=%s AND checkpoint_id=%s",
211
+ (thread_id, checkpoint_id),
212
+ )
213
+ else:
214
+ cur.execute(
215
+ "SELECT checkpoint, metadata, parent_config FROM prismlang_checkpoint "
216
+ "WHERE thread_id=%s ORDER BY created_at DESC LIMIT 1",
217
+ (thread_id,),
218
+ )
219
+ row = cur.fetchone()
220
+ finally:
221
+ conn.close()
222
+
223
+ if not row:
224
+ return None
225
+ checkpoint, metadata, parent_config = row
226
+ return CheckpointTuple(
227
+ config=config,
228
+ checkpoint=checkpoint,
229
+ metadata=metadata or {},
230
+ parent_config=parent_config,
231
+ )
232
+
233
+ def list(
234
+ self,
235
+ config: Optional[Dict[str, Any]],
236
+ *,
237
+ filter: Optional[Dict[str, Any]] = None,
238
+ before: Optional[Dict[str, Any]] = None,
239
+ limit: Optional[int] = None,
240
+ ) -> Iterator[CheckpointTuple]:
241
+ thread_id = (config or {}).get("configurable", {}).get("thread_id", "")
242
+ q = (
243
+ "SELECT thread_id, checkpoint_id, checkpoint, metadata, parent_config "
244
+ "FROM prismlang_checkpoint WHERE thread_id=%s ORDER BY created_at DESC"
245
+ )
246
+ params = [thread_id]
247
+ if limit:
248
+ q += " LIMIT %s"
249
+ params.append(limit)
250
+ conn = self._connect()
251
+ try:
252
+ with conn.cursor() as cur:
253
+ cur.execute(q, params)
254
+ for row in cur.fetchall():
255
+ tid, cid, checkpoint, metadata, parent_config = row
256
+ yield CheckpointTuple(
257
+ config={"configurable": {"thread_id": tid, "checkpoint_id": cid}},
258
+ checkpoint=checkpoint,
259
+ metadata=metadata or {},
260
+ parent_config=parent_config,
261
+ )
262
+ finally:
263
+ conn.close()
264
+
265
+ def put(
266
+ self,
267
+ config: Dict[str, Any],
268
+ checkpoint: Checkpoint,
269
+ metadata: CheckpointMetadata,
270
+ new_versions: Dict[str, Any],
271
+ ) -> Dict[str, Any]:
272
+ thread_id = config["configurable"]["thread_id"]
273
+ checkpoint_id = checkpoint["id"]
274
+ tenant_id = checkpoint.get("channel_values", {}).get("tenant_id")
275
+ conn = self._connect()
276
+ try:
277
+ with conn.cursor() as cur:
278
+ cur.execute(
279
+ """
280
+ INSERT INTO prismlang_checkpoint
281
+ (thread_id, checkpoint_id, tenant_id, checkpoint, metadata, parent_config)
282
+ VALUES (%s, %s, %s, %s::jsonb, %s::jsonb, %s::jsonb)
283
+ ON CONFLICT (thread_id, checkpoint_id) DO UPDATE
284
+ SET checkpoint = EXCLUDED.checkpoint,
285
+ metadata = EXCLUDED.metadata
286
+ """,
287
+ (
288
+ thread_id,
289
+ checkpoint_id,
290
+ tenant_id,
291
+ json.dumps(checkpoint, default=str),
292
+ json.dumps(dict(metadata), default=str),
293
+ json.dumps(config, default=str),
294
+ ),
295
+ )
296
+ conn.commit()
297
+ finally:
298
+ conn.close()
299
+ return {**config, "configurable": {**config["configurable"], "checkpoint_id": checkpoint_id}}
300
+
301
+ def put_writes(
302
+ self,
303
+ config: Dict[str, Any],
304
+ writes: list,
305
+ task_id: str,
306
+ ) -> None:
307
+ pass
308
+
309
+
310
+ # ------------------------------------------------------------------ #
311
+ # Async JSON file backend #
312
+ # ------------------------------------------------------------------ #
313
+
314
+ class AsyncJsonFileCheckpointer(BaseCheckpointSaver):
315
+ """Async variant of JsonFileCheckpointer using aiofiles.
316
+
317
+ Requires: pip install prismlang[async-files]
318
+ """
319
+
320
+ def __init__(self, root: str = ".prismlang_checkpoints") -> None:
321
+ super().__init__()
322
+ self.root = Path(root)
323
+ self.root.mkdir(parents=True, exist_ok=True)
324
+
325
+ def _path(self, thread_id: str, checkpoint_id: str) -> Path:
326
+ thread_dir = self.root / thread_id
327
+ thread_dir.mkdir(parents=True, exist_ok=True)
328
+ return thread_dir / f"{checkpoint_id}.json"
329
+
330
+ def get_tuple(self, config: Dict[str, Any]) -> Optional[CheckpointTuple]:
331
+ import asyncio
332
+ loop = asyncio.new_event_loop()
333
+ try:
334
+ return loop.run_until_complete(self.aget_tuple(config))
335
+ finally:
336
+ loop.close()
337
+
338
+ async def aget_tuple(self, config: Dict[str, Any]) -> Optional[CheckpointTuple]:
339
+ try:
340
+ import aiofiles
341
+ except ImportError as exc:
342
+ raise ImportError(
343
+ "aiofiles is required for AsyncJsonFileCheckpointer. "
344
+ "Install with: pip install 'prismlang[async-files]'"
345
+ ) from exc
346
+
347
+ thread_id = config["configurable"]["thread_id"]
348
+ checkpoint_id = config["configurable"].get("checkpoint_id")
349
+
350
+ if checkpoint_id:
351
+ p = self._path(thread_id, checkpoint_id)
352
+ if not p.exists():
353
+ return None
354
+ async with aiofiles.open(p) as f:
355
+ data = json.loads(await f.read())
356
+ else:
357
+ thread_dir = self.root / thread_id
358
+ if not thread_dir.exists():
359
+ return None
360
+ files = sorted(thread_dir.glob("*.json"))
361
+ if not files:
362
+ return None
363
+ async with aiofiles.open(files[-1]) as f:
364
+ data = json.loads(await f.read())
365
+
366
+ return CheckpointTuple(
367
+ config=config,
368
+ checkpoint=data["checkpoint"],
369
+ metadata=data.get("metadata", {}),
370
+ parent_config=data.get("parent_config"),
371
+ )
372
+
373
+ def list(self, config, *, filter=None, before=None, limit=None):
374
+ thread_id = (config or {}).get("configurable", {}).get("thread_id", "")
375
+ thread_dir = self.root / thread_id
376
+ if not thread_dir.exists():
377
+ return
378
+ files = sorted(thread_dir.glob("*.json"), reverse=True)
379
+ count = 0
380
+ for f in files:
381
+ if limit and count >= limit:
382
+ break
383
+ data = json.loads(f.read_text())
384
+ yield CheckpointTuple(
385
+ config={"configurable": {"thread_id": thread_id, "checkpoint_id": f.stem}},
386
+ checkpoint=data["checkpoint"],
387
+ metadata=data.get("metadata", {}),
388
+ parent_config=data.get("parent_config"),
389
+ )
390
+ count += 1
391
+
392
+ async def aput(
393
+ self,
394
+ config: Dict[str, Any],
395
+ checkpoint: Checkpoint,
396
+ metadata: CheckpointMetadata,
397
+ new_versions: Dict[str, Any],
398
+ ) -> Dict[str, Any]:
399
+ try:
400
+ import aiofiles
401
+ except ImportError as exc:
402
+ raise ImportError(
403
+ "aiofiles is required for AsyncJsonFileCheckpointer. "
404
+ "Install with: pip install 'prismlang[async-files]'"
405
+ ) from exc
406
+
407
+ thread_id = config["configurable"]["thread_id"]
408
+ checkpoint_id = checkpoint["id"]
409
+ p = self._path(thread_id, checkpoint_id)
410
+ content = json.dumps(
411
+ {"checkpoint": checkpoint, "metadata": metadata, "parent_config": config},
412
+ default=str,
413
+ )
414
+ async with aiofiles.open(p, "w") as f:
415
+ await f.write(content)
416
+ return {**config, "configurable": {**config["configurable"], "checkpoint_id": checkpoint_id}}
417
+
418
+ def put(self, config, checkpoint, metadata, new_versions):
419
+ import asyncio
420
+ loop = asyncio.new_event_loop()
421
+ try:
422
+ return loop.run_until_complete(self.aput(config, checkpoint, metadata, new_versions))
423
+ finally:
424
+ loop.close()
425
+
426
+ def put_writes(self, config, writes, task_id):
427
+ pass
428
+
429
+
430
+ # ------------------------------------------------------------------ #
431
+ # Async PostgreSQL backend #
432
+ # ------------------------------------------------------------------ #
433
+
434
+ class AsyncPostgresCheckpointer(BaseCheckpointSaver):
435
+ """Async variant of PostgresCheckpointer using asyncpg.
436
+
437
+ Requires: pip install prismlang[async-postgres]
438
+ """
439
+
440
+ def __init__(self, dsn: Optional[str] = None) -> None:
441
+ super().__init__()
442
+ self._dsn = dsn or os.environ.get("DATABASE_URL")
443
+ if not self._dsn:
444
+ raise CheckpointerConnectionError(
445
+ "asyncpg", cause=ValueError("No DSN provided. Pass dsn= or set DATABASE_URL.")
446
+ )
447
+ self._pool = None
448
+
449
+ async def _get_pool(self):
450
+ if self._pool is None:
451
+ try:
452
+ import asyncpg
453
+ except ImportError as exc:
454
+ raise ImportError(
455
+ "asyncpg is required for AsyncPostgresCheckpointer. "
456
+ "Install with: pip install 'prismlang[async-postgres]'"
457
+ ) from exc
458
+ try:
459
+ import asyncpg
460
+ self._pool = await asyncpg.create_pool(self._dsn)
461
+ async with self._pool.acquire() as conn:
462
+ await conn.execute(_CREATE_TABLE)
463
+ except Exception as exc:
464
+ raise CheckpointerConnectionError("asyncpg", cause=exc) from exc
465
+ return self._pool
466
+
467
+ async def aget_tuple(self, config: Dict[str, Any]) -> Optional[CheckpointTuple]:
468
+ pool = await self._get_pool()
469
+ thread_id = config["configurable"]["thread_id"]
470
+ checkpoint_id = config["configurable"].get("checkpoint_id")
471
+
472
+ async with pool.acquire() as conn:
473
+ if checkpoint_id:
474
+ row = await conn.fetchrow(
475
+ "SELECT checkpoint, metadata, parent_config FROM prismlang_checkpoint "
476
+ "WHERE thread_id=$1 AND checkpoint_id=$2",
477
+ thread_id, checkpoint_id,
478
+ )
479
+ else:
480
+ row = await conn.fetchrow(
481
+ "SELECT checkpoint, metadata, parent_config FROM prismlang_checkpoint "
482
+ "WHERE thread_id=$1 ORDER BY created_at DESC LIMIT 1",
483
+ thread_id,
484
+ )
485
+
486
+ if not row:
487
+ return None
488
+ return CheckpointTuple(
489
+ config=config,
490
+ checkpoint=json.loads(row["checkpoint"]),
491
+ metadata=json.loads(row["metadata"] or "{}"),
492
+ parent_config=json.loads(row["parent_config"]) if row["parent_config"] else None,
493
+ )
494
+
495
+ def get_tuple(self, config):
496
+ import asyncio
497
+ loop = asyncio.new_event_loop()
498
+ try:
499
+ return loop.run_until_complete(self.aget_tuple(config))
500
+ finally:
501
+ loop.close()
502
+
503
+ def list(self, config, *, filter=None, before=None, limit=None):
504
+ return iter([]) # use alist() for async listing
505
+
506
+ async def aput(
507
+ self,
508
+ config: Dict[str, Any],
509
+ checkpoint: Checkpoint,
510
+ metadata: CheckpointMetadata,
511
+ new_versions: Dict[str, Any],
512
+ ) -> Dict[str, Any]:
513
+ pool = await self._get_pool()
514
+ thread_id = config["configurable"]["thread_id"]
515
+ checkpoint_id = checkpoint["id"]
516
+ tenant_id = checkpoint.get("channel_values", {}).get("tenant_id")
517
+
518
+ async with pool.acquire() as conn:
519
+ await conn.execute(
520
+ """
521
+ INSERT INTO prismlang_checkpoint
522
+ (thread_id, checkpoint_id, tenant_id, checkpoint, metadata, parent_config)
523
+ VALUES ($1, $2, $3, $4::jsonb, $5::jsonb, $6::jsonb)
524
+ ON CONFLICT (thread_id, checkpoint_id) DO UPDATE
525
+ SET checkpoint = EXCLUDED.checkpoint,
526
+ metadata = EXCLUDED.metadata
527
+ """,
528
+ thread_id,
529
+ checkpoint_id,
530
+ tenant_id,
531
+ json.dumps(checkpoint, default=str),
532
+ json.dumps(dict(metadata), default=str),
533
+ json.dumps(config, default=str),
534
+ )
535
+
536
+ return {**config, "configurable": {**config["configurable"], "checkpoint_id": checkpoint_id}}
537
+
538
+ def put(self, config, checkpoint, metadata, new_versions):
539
+ import asyncio
540
+ loop = asyncio.new_event_loop()
541
+ try:
542
+ return loop.run_until_complete(self.aput(config, checkpoint, metadata, new_versions))
543
+ finally:
544
+ loop.close()
545
+
546
+ def put_writes(self, config, writes, task_id):
547
+ pass
prismlang/config.py ADDED
@@ -0,0 +1,17 @@
1
+ """Global constants for PrismLang."""
2
+
3
+ # ONNX encoder output dimension (all-MiniLM-L6-v2)
4
+ EMBED_DIM: int = 384
5
+
6
+ # Default Johnson-Lindenstrauss target dimension
7
+ DEFAULT_K: int = 64
8
+
9
+ # Spherical blend weight — how strongly the category direction pulls the vector
10
+ DEFAULT_ALPHA: float = 0.3
11
+
12
+ # HuggingFace model repo for the ONNX encoder
13
+ HF_MODEL_REPO: str = "sentence-transformers/all-MiniLM-L6-v2"
14
+
15
+ # Local cache directory for downloaded models
16
+ import os
17
+ MODEL_CACHE_DIR: str = os.path.join(os.path.expanduser("~"), ".prismlang", "models")