prismlib-plus 0.7.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.
- prism/__init__.py +9 -0
- prism/api/__init__.py +83 -0
- prism/api/auth.py +127 -0
- prism/api/consumer.py +573 -0
- prism/api/integrations/__init__.py +30 -0
- prism/api/integrations/langgraph.py +382 -0
- prism/api/mcp.py +341 -0
- prism/api/multi_provider.py +315 -0
- prism/api/provider.py +496 -0
- prism/api/schema.py +296 -0
- prism/bridge/__init__.py +32 -0
- prism/bridge/vector.py +704 -0
- prism/cache/__init__.py +54 -0
- prism/cache/cache.py +637 -0
- prism/cache/embedder.py +438 -0
- prism/cache/metrics.py +273 -0
- prism/cache/store.py +370 -0
- prism/cluster/__init__.py +20 -0
- prism/cluster/alerts.py +550 -0
- prism/cluster/cache.py +480 -0
- prism/cluster/health.py +87 -0
- prism/cluster/node.py +288 -0
- prism/cluster/transport.py +81 -0
- prism/enterprise/__init__.py +5 -0
- prism/enterprise/app.py +70 -0
- prism/ffi/__init__.py +34 -0
- prism/ffi/bindings.py +1055 -0
- prism/ffi/grpc_client.py +121 -0
- prism/lib/__init__.py +17 -0
- prism/lib/fabric.py +1141 -0
- prism/lib/lang.py +531 -0
- prism/lib/resonance.py +691 -0
- prism/observability/__init__.py +110 -0
- prism/observability/otel.py +85 -0
- prism/observability/prometheus.py +11 -0
- prism/security/__init__.py +17 -0
- prism/security/audit.py +80 -0
- prism/security/rate_limit.py +74 -0
- prism/security/tls.py +48 -0
- prism/wrapper/__init__.py +49 -0
- prism/wrapper/config.py +132 -0
- prism/wrapper/daemon.py +261 -0
- prism/wrapper/grpc_server.py +248 -0
- prism/wrapper/interceptor.py +543 -0
- prism/wrapper/main.py +5 -0
- prism/wrapper/proto/__init__.py +0 -0
- prism/wrapper/proto/chorus_pb2.py +71 -0
- prism/wrapper/proto/chorus_pb2_grpc.py +454 -0
- prism/wrapper/publisher.py +255 -0
- prism/wrapper/row_events.py +129 -0
- prism/wrapper/subscribe_server.py +78 -0
- prismlib_plus-0.7.0.dist-info/METADATA +748 -0
- prismlib_plus-0.7.0.dist-info/RECORD +56 -0
- prismlib_plus-0.7.0.dist-info/WHEEL +5 -0
- prismlib_plus-0.7.0.dist-info/entry_points.txt +2 -0
- prismlib_plus-0.7.0.dist-info/top_level.txt +1 -0
prism/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prism Ecosystem — Tensor-Native Distributed Data Plane
|
|
3
|
+
=======================================================
|
|
4
|
+
PrismLib: Core mathematical primitives, wave-mechanics retrieval engine,
|
|
5
|
+
state-compression/isolation layers, and CHORUS Fabric transport interface.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.7.0"
|
|
9
|
+
__author__ = "InsightIts"
|
prism/api/__init__.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
prism.api — Vector-native API layer for AI agents
|
|
3
|
+
==================================================
|
|
4
|
+
|
|
5
|
+
PrismAPI lets an API serve content that is ALREADY embedded and projected
|
|
6
|
+
into PrismResonance space, delivered over CHORUS as raw float32 vectors.
|
|
7
|
+
The consuming agent retrieves results directly with no JSON parsing and no
|
|
8
|
+
re-embedding call.
|
|
9
|
+
|
|
10
|
+
Quick start::
|
|
11
|
+
|
|
12
|
+
# Provider side (one line to adopt)
|
|
13
|
+
from prism.api import PrismAPIProvider
|
|
14
|
+
from prism.api.schema import SentenceTransformerEmbedder
|
|
15
|
+
from prism.lib.lang import PrismProjector, ProjectionConfig
|
|
16
|
+
|
|
17
|
+
projector = PrismProjector(ProjectionConfig(tenant_id="my-tenant"))
|
|
18
|
+
embedder = SentenceTransformerEmbedder()
|
|
19
|
+
provider = PrismAPIProvider(projector, embedder,
|
|
20
|
+
semantic_fields=["title", "body"],
|
|
21
|
+
id_field="doc_id")
|
|
22
|
+
|
|
23
|
+
@provider.expose
|
|
24
|
+
def search(query: str, top_k: int = 10) -> list[dict]:
|
|
25
|
+
return my_db.search(query, top_k) # unchanged
|
|
26
|
+
|
|
27
|
+
# Consumer side
|
|
28
|
+
from prism.api import PrismAPIClient
|
|
29
|
+
|
|
30
|
+
client = PrismAPIClient(projector, embedder, loopback_provider=provider)
|
|
31
|
+
response = client.query("how does inflation affect bonds?", top_k=5)
|
|
32
|
+
# response.vectors → np.ndarray (5, 64) — ready for PrismResonance
|
|
33
|
+
# response.sidecars → list of exact metadata dicts — no re-embedding
|
|
34
|
+
|
|
35
|
+
See prism/api/README.md for full documentation and benchmark numbers.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from prism.api.provider import ASGIAdapter, ExposedHandler, PrismAPIProvider
|
|
39
|
+
from prism.api.consumer import LangGraphTool, PrismAPIClient, RetryConfig
|
|
40
|
+
from prism.api.auth import AuthConfig, AuthError, generate_api_key
|
|
41
|
+
from prism.api.multi_provider import MultiProviderClient, MultiProviderResponse
|
|
42
|
+
from prism.api.schema import (
|
|
43
|
+
APIRequest,
|
|
44
|
+
APIResponse,
|
|
45
|
+
Embedder,
|
|
46
|
+
ExactSidecar,
|
|
47
|
+
SemanticItem,
|
|
48
|
+
SentenceTransformerEmbedder,
|
|
49
|
+
)
|
|
50
|
+
from prism.api.integrations.langgraph import (
|
|
51
|
+
PrismRetrieverNode,
|
|
52
|
+
MultiProviderRetrieverNode,
|
|
53
|
+
create_retriever_node,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
# Provider
|
|
58
|
+
"PrismAPIProvider",
|
|
59
|
+
"ExposedHandler",
|
|
60
|
+
"ASGIAdapter",
|
|
61
|
+
# Consumer
|
|
62
|
+
"PrismAPIClient",
|
|
63
|
+
"RetryConfig",
|
|
64
|
+
"LangGraphTool",
|
|
65
|
+
# Multi-provider
|
|
66
|
+
"MultiProviderClient",
|
|
67
|
+
"MultiProviderResponse",
|
|
68
|
+
# LangGraph integration
|
|
69
|
+
"PrismRetrieverNode",
|
|
70
|
+
"MultiProviderRetrieverNode",
|
|
71
|
+
"create_retriever_node",
|
|
72
|
+
# Schema
|
|
73
|
+
"Embedder",
|
|
74
|
+
"SentenceTransformerEmbedder",
|
|
75
|
+
"SemanticItem",
|
|
76
|
+
"ExactSidecar",
|
|
77
|
+
"APIRequest",
|
|
78
|
+
"APIResponse",
|
|
79
|
+
# Auth
|
|
80
|
+
"AuthConfig",
|
|
81
|
+
"AuthError",
|
|
82
|
+
"generate_api_key",
|
|
83
|
+
]
|
prism/api/auth.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
prism.api.auth — API key and bearer authentication for PrismAPI endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import hmac
|
|
8
|
+
import os
|
|
9
|
+
import secrets
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Callable, Optional, TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from prism.security.audit import AuditLogger
|
|
15
|
+
from prism.security.rate_limit import RateLimiter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AuthError(Exception):
|
|
19
|
+
"""Raised when authentication fails."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class AuthConfig:
|
|
24
|
+
"""
|
|
25
|
+
Authentication configuration for PrismAPI ASGI endpoints.
|
|
26
|
+
|
|
27
|
+
api_keys:
|
|
28
|
+
Valid API keys (plain strings). Compared with timing-safe equality.
|
|
29
|
+
bearer_tokens:
|
|
30
|
+
Valid bearer tokens (without the 'Bearer ' prefix).
|
|
31
|
+
header_api_key:
|
|
32
|
+
Header name for API key auth (default X-API-Key).
|
|
33
|
+
require_auth:
|
|
34
|
+
If True, reject requests with no credentials. If False, auth is
|
|
35
|
+
optional when api_keys/bearer_tokens are configured.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
api_keys: tuple[str, ...] = field(default_factory=tuple)
|
|
39
|
+
bearer_tokens: tuple[str, ...] = field(default_factory=tuple)
|
|
40
|
+
header_api_key: str = "X-API-Key"
|
|
41
|
+
require_auth: bool = True
|
|
42
|
+
rate_limit_rpm: int = 120
|
|
43
|
+
rate_limit_burst: int = 30
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_env(cls, *, prefix: str = "PRISM_API") -> "AuthConfig":
|
|
47
|
+
keys = os.environ.get(f"{prefix}_KEYS", "")
|
|
48
|
+
tokens = os.environ.get(f"{prefix}_BEARER_TOKENS", "")
|
|
49
|
+
require = os.environ.get(f"{prefix}_REQUIRE_AUTH", "true").lower() in (
|
|
50
|
+
"1", "true", "yes",
|
|
51
|
+
)
|
|
52
|
+
rpm = int(os.environ.get(f"{prefix}_RATE_LIMIT_RPM", "120"))
|
|
53
|
+
burst = int(os.environ.get(f"{prefix}_RATE_LIMIT_BURST", "30"))
|
|
54
|
+
return cls(
|
|
55
|
+
api_keys=tuple(k.strip() for k in keys.split(",") if k.strip()),
|
|
56
|
+
bearer_tokens=tuple(t.strip() for t in tokens.split(",") if t.strip()),
|
|
57
|
+
require_auth=require,
|
|
58
|
+
rate_limit_rpm=rpm,
|
|
59
|
+
rate_limit_burst=burst,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def enabled(self) -> bool:
|
|
64
|
+
return bool(self.api_keys or self.bearer_tokens)
|
|
65
|
+
|
|
66
|
+
def validate_headers(self, headers: dict[str, str]) -> bool:
|
|
67
|
+
"""Return True if headers contain valid credentials."""
|
|
68
|
+
if not self.enabled:
|
|
69
|
+
return not self.require_auth
|
|
70
|
+
|
|
71
|
+
lowered = {k.lower(): v for k, v in headers.items()}
|
|
72
|
+
|
|
73
|
+
api_key = lowered.get(self.header_api_key.lower())
|
|
74
|
+
if api_key and any(_safe_eq(api_key, k) for k in self.api_keys):
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
auth = lowered.get("authorization", "")
|
|
78
|
+
if auth.lower().startswith("bearer "):
|
|
79
|
+
token = auth[7:].strip()
|
|
80
|
+
if any(_safe_eq(token, t) for t in self.bearer_tokens):
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _safe_eq(a: str, b: str) -> bool:
|
|
87
|
+
return hmac.compare_digest(a.encode(), b.encode())
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def generate_api_key() -> str:
|
|
91
|
+
"""Generate a URL-safe API key."""
|
|
92
|
+
return secrets.token_urlsafe(32)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def actor_from_headers(headers: dict[str, str], header_api_key: str = "X-API-Key") -> str:
|
|
96
|
+
"""Derive audit actor id from request headers (API key prefix or client IP)."""
|
|
97
|
+
lowered = {k.lower(): v for k, v in headers.items()}
|
|
98
|
+
key = lowered.get(header_api_key.lower(), "")
|
|
99
|
+
if key:
|
|
100
|
+
return f"apikey:{key[:8]}"
|
|
101
|
+
auth = lowered.get("authorization", "")
|
|
102
|
+
if auth.lower().startswith("bearer "):
|
|
103
|
+
return f"bearer:{auth[7:13]}"
|
|
104
|
+
return lowered.get("x-forwarded-for", lowered.get("x-real-ip", "anonymous"))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def auth_dependency(config: AuthConfig) -> Callable:
|
|
108
|
+
"""
|
|
109
|
+
FastAPI dependency factory for PrismAPI routes.
|
|
110
|
+
|
|
111
|
+
Usage::
|
|
112
|
+
|
|
113
|
+
from fastapi import Depends
|
|
114
|
+
from prism.api.auth import AuthConfig, auth_dependency
|
|
115
|
+
|
|
116
|
+
auth = AuthConfig.from_env()
|
|
117
|
+
app.add_api_route("/chorus/search", handler, dependencies=[Depends(auth_dependency(auth))])
|
|
118
|
+
"""
|
|
119
|
+
def _check(headers: dict[str, str]) -> None:
|
|
120
|
+
if not config.validate_headers(headers):
|
|
121
|
+
raise AuthError("Unauthorized")
|
|
122
|
+
|
|
123
|
+
async def _fastapi_dep(request: object) -> None:
|
|
124
|
+
hdrs = {k: v for k, v in getattr(request, "headers", {}).items()}
|
|
125
|
+
_check(hdrs)
|
|
126
|
+
|
|
127
|
+
return _fastapi_dep
|