orbitals 0.1.0__py3-none-any.whl → 0.1.2__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.
- orbitals/scope_guard/cli/serve.py +1 -1
- orbitals/scope_guard/guards/base.py +8 -8
- orbitals/scope_guard/guards/hf.py +2 -2
- orbitals/scope_guard/guards/vllm.py +5 -5
- orbitals/scope_guard/serving/main.py +2 -14
- orbitals/types.py +14 -2
- orbitals/utils.py +34 -26
- orbitals-0.1.2.dist-info/METADATA +170 -0
- {orbitals-0.1.0.dist-info → orbitals-0.1.2.dist-info}/RECORD +12 -12
- {orbitals-0.1.0.dist-info → orbitals-0.1.2.dist-info}/licenses/LICENSE +1 -1
- orbitals-0.1.0.dist-info/METADATA +0 -103
- {orbitals-0.1.0.dist-info → orbitals-0.1.2.dist-info}/WHEEL +0 -0
- {orbitals-0.1.0.dist-info → orbitals-0.1.2.dist-info}/entry_points.txt +0 -0
|
@@ -38,7 +38,7 @@ def serve(
|
|
|
38
38
|
"0.0.0.0", "-h", "--host", help="The host to use for the server"
|
|
39
39
|
),
|
|
40
40
|
vllm_port: int = typer.Option(8001, help="The port to use for the vLLM server"),
|
|
41
|
-
vllm_max_model_len: int = typer.Option(
|
|
41
|
+
vllm_max_model_len: int = typer.Option(15000, help="Maximum model length for vLLM"),
|
|
42
42
|
vllm_max_num_seqs: int = typer.Option(
|
|
43
43
|
2, help="Maximum number of sequences for vLLM"
|
|
44
44
|
),
|
|
@@ -17,7 +17,7 @@ from ..modeling import (
|
|
|
17
17
|
ScopeGuardOutput,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
DefaultModel = Literal["
|
|
20
|
+
DefaultModel = Literal["scope-guard"]
|
|
21
21
|
|
|
22
22
|
MODEL_MAPPING = {
|
|
23
23
|
"scope-guard": "principled-intelligence/scope-guard-4B-q-2601",
|
|
@@ -137,9 +137,9 @@ class ScopeGuard(BaseScopeGuard):
|
|
|
137
137
|
def __new__(
|
|
138
138
|
cls,
|
|
139
139
|
backend: Literal["hf"] = "hf",
|
|
140
|
-
model: DefaultModel | str = "
|
|
140
|
+
model: DefaultModel | str = "scope-guard",
|
|
141
141
|
skip_evidences: bool = False,
|
|
142
|
-
max_new_tokens: int =
|
|
142
|
+
max_new_tokens: int = 3000,
|
|
143
143
|
do_sample: bool = False,
|
|
144
144
|
**kwargs,
|
|
145
145
|
) -> HuggingFaceScopeGuard: ...
|
|
@@ -148,11 +148,11 @@ class ScopeGuard(BaseScopeGuard):
|
|
|
148
148
|
def __new__(
|
|
149
149
|
cls,
|
|
150
150
|
backend: Literal["vllm"],
|
|
151
|
-
model: DefaultModel | str = "
|
|
151
|
+
model: DefaultModel | str = "scope-guard",
|
|
152
152
|
skip_evidences: bool = False,
|
|
153
153
|
temperature: float = 0.0,
|
|
154
|
-
max_tokens: int =
|
|
155
|
-
max_model_len: int =
|
|
154
|
+
max_tokens: int = 3000,
|
|
155
|
+
max_model_len: int = 15_000,
|
|
156
156
|
max_num_seqs: int = 2,
|
|
157
157
|
) -> VLLMScopeGuard: ...
|
|
158
158
|
|
|
@@ -223,11 +223,11 @@ class AsyncScopeGuard(BaseScopeGuard):
|
|
|
223
223
|
def __new__(
|
|
224
224
|
cls,
|
|
225
225
|
backend: Literal["vllm-api"],
|
|
226
|
-
model: DefaultModel | str = "
|
|
226
|
+
model: DefaultModel | str = "scope-guard",
|
|
227
227
|
skip_evidences: bool = False,
|
|
228
228
|
vllm_serving_url: str = "http://localhost:8000",
|
|
229
229
|
temperature: float = 0.0,
|
|
230
|
-
max_tokens: int =
|
|
230
|
+
max_tokens: int = 3000,
|
|
231
231
|
) -> AsyncVLLMApiScopeGuard: ...
|
|
232
232
|
|
|
233
233
|
@overload
|
|
@@ -21,9 +21,9 @@ class HuggingFaceScopeGuard(ScopeGuard):
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
23
|
backend: Literal["hf"] = "hf",
|
|
24
|
-
model: DefaultModel | str = "
|
|
24
|
+
model: DefaultModel | str = "scope-guard",
|
|
25
25
|
skip_evidences: bool = False,
|
|
26
|
-
max_new_tokens: int =
|
|
26
|
+
max_new_tokens: int = 3000,
|
|
27
27
|
do_sample: bool = False,
|
|
28
28
|
**kwargs,
|
|
29
29
|
):
|
|
@@ -23,11 +23,11 @@ class VLLMScopeGuard(ScopeGuard):
|
|
|
23
23
|
def __init__(
|
|
24
24
|
self,
|
|
25
25
|
backend: Literal["vllm"] = "vllm",
|
|
26
|
-
model: DefaultModel | str = "
|
|
26
|
+
model: DefaultModel | str = "scope-guard",
|
|
27
27
|
skip_evidences: bool = False,
|
|
28
28
|
temperature: float = 0.0,
|
|
29
|
-
max_tokens: int =
|
|
30
|
-
max_model_len: int =
|
|
29
|
+
max_tokens: int = 3000,
|
|
30
|
+
max_model_len: int = 15_000,
|
|
31
31
|
max_num_seqs: int = 2,
|
|
32
32
|
gpu_memory_utilization: float = 0.9,
|
|
33
33
|
):
|
|
@@ -127,11 +127,11 @@ class AsyncVLLMApiScopeGuard(AsyncScopeGuard):
|
|
|
127
127
|
def __init__(
|
|
128
128
|
self,
|
|
129
129
|
backend: Literal["vllm-api", "vllm-async-api"] = "vllm-api",
|
|
130
|
-
model: DefaultModel | str = "
|
|
130
|
+
model: DefaultModel | str = "scope-guard",
|
|
131
131
|
skip_evidences: bool = False,
|
|
132
132
|
vllm_serving_url: str = "http://localhost:8000",
|
|
133
133
|
temperature: float = 0.0,
|
|
134
|
-
max_tokens: int =
|
|
134
|
+
max_tokens: int = 3000,
|
|
135
135
|
):
|
|
136
136
|
import transformers
|
|
137
137
|
|
|
@@ -54,19 +54,13 @@ class ScopeGuardResponse(BaseModel):
|
|
|
54
54
|
time_taken: float
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
@app.post("/
|
|
58
|
-
@app.post("/api/in/scope-classifier/classify", response_model=ScopeGuardResponse)
|
|
57
|
+
@app.post("/orbitals/scope-guard/validate", response_model=ScopeGuardResponse)
|
|
59
58
|
async def validate(
|
|
60
59
|
request: Request,
|
|
61
60
|
conversation: ScopeGuardInput,
|
|
62
61
|
ai_service_description: Annotated[str | AIServiceDescription, Body()],
|
|
63
62
|
skip_evidences: bool | None = Body(None),
|
|
64
63
|
) -> ScopeGuardResponse:
|
|
65
|
-
if request.url.path.endswith("/api/in/scope-classifier/classify"):
|
|
66
|
-
logging.warning(
|
|
67
|
-
"The /api/in/scope-classifier/classify endpoint is deprecated. Please use /api/in/scope-guard/validate instead."
|
|
68
|
-
)
|
|
69
|
-
|
|
70
64
|
global scope_guard
|
|
71
65
|
|
|
72
66
|
start_time = time.time()
|
|
@@ -85,10 +79,9 @@ async def validate(
|
|
|
85
79
|
|
|
86
80
|
|
|
87
81
|
@app.post(
|
|
88
|
-
"/
|
|
82
|
+
"/orbitals/scope-guard/batch-validate",
|
|
89
83
|
response_model=list[ScopeGuardResponse],
|
|
90
84
|
)
|
|
91
|
-
@app.post("/api/in/scope-classifier/batch-classify", response_model=ScopeGuardResponse)
|
|
92
85
|
async def batch_validate(
|
|
93
86
|
request: Request,
|
|
94
87
|
conversations: list[ScopeGuardInput],
|
|
@@ -96,11 +89,6 @@ async def batch_validate(
|
|
|
96
89
|
ai_service_descriptions: list[str] | list[AIServiceDescription] | None = None,
|
|
97
90
|
skip_evidences: bool | None = Body(None),
|
|
98
91
|
) -> list[ScopeGuardResponse]:
|
|
99
|
-
if request.url.path.endswith("/api/in/scope-classifier/batch-classify"):
|
|
100
|
-
logging.warning(
|
|
101
|
-
"The /api/in/scope-classifier/batch-classify endpoint is deprecated. Please use /api/in/scope-guard/batch-validate instead."
|
|
102
|
-
)
|
|
103
|
-
|
|
104
92
|
global scope_guard
|
|
105
93
|
|
|
106
94
|
start_time = time.time()
|
orbitals/types.py
CHANGED
|
@@ -1,34 +1,46 @@
|
|
|
1
|
-
from typing import Literal
|
|
1
|
+
from typing import ClassVar, Literal
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel, Field
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class LLMUsage(BaseModel):
|
|
7
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
8
|
+
|
|
7
9
|
prompt_tokens: int
|
|
8
10
|
completion_tokens: int
|
|
9
11
|
total_tokens: int
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class ConversationMessage(BaseModel):
|
|
15
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
16
|
+
|
|
13
17
|
role: Literal["user", "assistant"]
|
|
14
18
|
content: str
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class Conversation(BaseModel):
|
|
22
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
23
|
+
|
|
18
24
|
messages: list[ConversationMessage]
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
class SupportingMaterial(BaseModel):
|
|
28
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
29
|
+
|
|
22
30
|
pass
|
|
23
31
|
|
|
24
32
|
|
|
25
33
|
class Principle(BaseModel):
|
|
34
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
35
|
+
|
|
26
36
|
title: str = Field(description="Title of the principle")
|
|
27
37
|
description: str = Field(description="Description of the principle")
|
|
28
38
|
supporting_materials: list[SupportingMaterial] | None
|
|
29
39
|
|
|
30
40
|
|
|
31
41
|
class AIServiceDescription(BaseModel):
|
|
42
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
|
43
|
+
|
|
32
44
|
identity_role: str = Field(
|
|
33
45
|
description="Identity, role and objectives of the AI Service. Gives a general idea of what the service is about."
|
|
34
46
|
)
|
orbitals/utils.py
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
if TYPE_CHECKING:
|
|
6
|
-
import torch
|
|
7
|
-
else:
|
|
8
|
-
try:
|
|
9
|
-
import torch # ty: ignore[unresolved-import]
|
|
10
|
-
except ModuleNotFoundError:
|
|
11
|
-
torch = None # ty: ignore[invalid-assignment]
|
|
12
3
|
|
|
13
4
|
|
|
14
5
|
def maybe_configure_gpu_usage():
|
|
@@ -16,30 +7,47 @@ def maybe_configure_gpu_usage():
|
|
|
16
7
|
If the user hasn't explicitly set CUDA_VISIBLE_DEVICES, auto-configure it for
|
|
17
8
|
optimal usage: search for the gpu with the most free memory, and
|
|
18
9
|
set CUDA_VISIBLE_DEVICES to that GPU only.
|
|
19
|
-
"""
|
|
20
|
-
if torch is None:
|
|
21
|
-
return
|
|
22
10
|
|
|
11
|
+
Uses nvidia-ml-py (pynvml) to avoid triggering CUDA initialization from torch.
|
|
12
|
+
"""
|
|
23
13
|
if "CUDA_VISIBLE_DEVICES" in os.environ:
|
|
24
14
|
logging.info(
|
|
25
15
|
"CUDA_VISIBLE_DEVICES is already set, not auto-configuring GPU usage"
|
|
26
16
|
)
|
|
27
17
|
return
|
|
28
18
|
|
|
29
|
-
|
|
19
|
+
try:
|
|
20
|
+
import pynvml # ty: ignore[unresolved-import] # provided by nvidia-ml-py
|
|
21
|
+
except ModuleNotFoundError:
|
|
22
|
+
logging.debug("nvidia-ml-py not available, skipping GPU auto-configuration")
|
|
30
23
|
return
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if free_bytes > best_free:
|
|
38
|
-
best_idx = i
|
|
39
|
-
best_free = free_bytes
|
|
25
|
+
try:
|
|
26
|
+
pynvml.nvmlInit()
|
|
27
|
+
except pynvml.NVMLError:
|
|
28
|
+
logging.error("NVML initialization failed, skipping GPU auto-configuration")
|
|
29
|
+
return
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
try:
|
|
32
|
+
device_count = pynvml.nvmlDeviceGetCount()
|
|
33
|
+
if device_count == 0:
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
best_idx = None
|
|
37
|
+
best_free = -1
|
|
38
|
+
|
|
39
|
+
for i in range(device_count):
|
|
40
|
+
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
|
|
41
|
+
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
|
42
|
+
if mem_info.free > best_free:
|
|
43
|
+
best_idx = i
|
|
44
|
+
best_free = mem_info.free
|
|
45
|
+
|
|
46
|
+
if best_idx is not None:
|
|
47
|
+
if device_count > 1:
|
|
48
|
+
logging.warning(
|
|
49
|
+
f"Auto-configuring to use GPU {best_idx} with {best_free / 1024**3:.2f} GB free"
|
|
50
|
+
)
|
|
51
|
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(best_idx)
|
|
52
|
+
finally:
|
|
53
|
+
pynvml.nvmlShutdown()
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orbitals
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: LLM Guardrails tailored to your Principles
|
|
5
|
+
Author-email: Luigi Procopio <luigi@principled-intelligence.com>, Edoardo Barba <edoardo@principled-intelligence.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: aiohttp
|
|
16
|
+
Requires-Dist: pydantic>=2.0.0
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: typer>=0.12.3
|
|
19
|
+
Provides-Extra: all
|
|
20
|
+
Requires-Dist: accelerate>=1.11.0; extra == 'all'
|
|
21
|
+
Requires-Dist: fastapi[standard]>=0.119.1; extra == 'all'
|
|
22
|
+
Requires-Dist: nvidia-ml-py; extra == 'all'
|
|
23
|
+
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'all'
|
|
24
|
+
Requires-Dist: uvicorn>=0.29.0; extra == 'all'
|
|
25
|
+
Requires-Dist: vllm>=0.11.0; extra == 'all'
|
|
26
|
+
Requires-Dist: xgrammar; extra == 'all'
|
|
27
|
+
Provides-Extra: scope-guard-all
|
|
28
|
+
Requires-Dist: accelerate>=1.11.0; extra == 'scope-guard-all'
|
|
29
|
+
Requires-Dist: fastapi[standard]>=0.119.1; extra == 'scope-guard-all'
|
|
30
|
+
Requires-Dist: nvidia-ml-py; extra == 'scope-guard-all'
|
|
31
|
+
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-all'
|
|
32
|
+
Requires-Dist: uvicorn>=0.29.0; extra == 'scope-guard-all'
|
|
33
|
+
Requires-Dist: vllm>=0.11.0; extra == 'scope-guard-all'
|
|
34
|
+
Requires-Dist: xgrammar; extra == 'scope-guard-all'
|
|
35
|
+
Provides-Extra: scope-guard-hf
|
|
36
|
+
Requires-Dist: accelerate>=1.11.0; extra == 'scope-guard-hf'
|
|
37
|
+
Requires-Dist: nvidia-ml-py; extra == 'scope-guard-hf'
|
|
38
|
+
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-hf'
|
|
39
|
+
Provides-Extra: scope-guard-serve
|
|
40
|
+
Requires-Dist: fastapi[standard]>=0.119.1; extra == 'scope-guard-serve'
|
|
41
|
+
Requires-Dist: nvidia-ml-py; extra == 'scope-guard-serve'
|
|
42
|
+
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-serve'
|
|
43
|
+
Requires-Dist: uvicorn>=0.29.0; extra == 'scope-guard-serve'
|
|
44
|
+
Requires-Dist: vllm>=0.11.0; extra == 'scope-guard-serve'
|
|
45
|
+
Requires-Dist: xgrammar; extra == 'scope-guard-serve'
|
|
46
|
+
Provides-Extra: scope-guard-vllm
|
|
47
|
+
Requires-Dist: nvidia-ml-py; extra == 'scope-guard-vllm'
|
|
48
|
+
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-vllm'
|
|
49
|
+
Requires-Dist: vllm>=0.11.0; extra == 'scope-guard-vllm'
|
|
50
|
+
Requires-Dist: xgrammar; extra == 'scope-guard-vllm'
|
|
51
|
+
Provides-Extra: serving
|
|
52
|
+
Requires-Dist: fastapi[standard]>=0.119.1; extra == 'serving'
|
|
53
|
+
Requires-Dist: uvicorn>=0.29.0; extra == 'serving'
|
|
54
|
+
Description-Content-Type: text/markdown
|
|
55
|
+
|
|
56
|
+
<div align="center">
|
|
57
|
+
<img src="https://raw.githubusercontent.com/Principled-Intelligence/orbitals/refs/heads/main/assets/orbitals-banner.png" width="70%" />
|
|
58
|
+
<h3 align="center">
|
|
59
|
+
<p>
|
|
60
|
+
<b>LLM Guardrails tailored to your Principles</b>
|
|
61
|
+
</p>
|
|
62
|
+
</h4>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
<a href="https://pypi.org/project/orbitals/">
|
|
67
|
+
<img src="https://img.shields.io/pypi/v/orbitals?color=green" alt="PyPI Version">
|
|
68
|
+
</a>
|
|
69
|
+
<!-- <img src="https://img.shields.io/badge/type%20checked-ty-blue.svg?color=green" alt="Type Checked with ty"> -->
|
|
70
|
+
<a href="https://pypi.org/project/orbitals/">
|
|
71
|
+
<img src="https://img.shields.io/pypi/pyversions/orbitals" alt="Python Versions">
|
|
72
|
+
</a>
|
|
73
|
+
<a href="https://raw.githubusercontent.com/Principled-Intelligence/orbitals/refs/heads/main/LICENSE">
|
|
74
|
+
<img src="https://img.shields.io/github/license/principled-intelligence/orbitals" alt="GitHub License">
|
|
75
|
+
</a>
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
## Overview
|
|
79
|
+
|
|
80
|
+
**Orbitals** is a lightweight Python library for adding LLM guardrails in just a few lines of code. With Orbitals, you can add a governance layer tailored to **user-specific principles**. Rather than enforcing generic notions of safety, compliance, and correctness, Orbitals validates inputs (e.g., user requests) and outputs (e.g., assistant responses) against user-defined specifications and custom policies. This makes guardrails explicit, auditable, and aligned with the user's philosophy.
|
|
81
|
+
|
|
82
|
+
### Key Features
|
|
83
|
+
|
|
84
|
+
- **User-defined specifications** — Guardrails that match your use case and your custom policies, not generic safety rules
|
|
85
|
+
- **Simple integration** — Add guardrails with minimal code changes
|
|
86
|
+
- **Open framework, open models** — Orbitals is open-source and is a simple interface for our open models
|
|
87
|
+
|
|
88
|
+
## Getting started
|
|
89
|
+
|
|
90
|
+
### Installation
|
|
91
|
+
|
|
92
|
+
You can install Orbitals via pip:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install orbitals[all]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Basic Usage
|
|
99
|
+
|
|
100
|
+
Here's a quick example to get you started with Orbitals, in which we use the ScopeGuard module to guard an AI service (for example, a customer support chatbot) from user requests that violate specified principles or fall outside of the scope of the core task of the assistant.
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from orbitals.scope_guard import ScopeGuard
|
|
104
|
+
|
|
105
|
+
ai_service_description = "You are a helpful assistant for ..."
|
|
106
|
+
user_message = "Can I buy ..."
|
|
107
|
+
|
|
108
|
+
guardrail = ScopeGuard()
|
|
109
|
+
result = guardrail.validate(user_message, ai_service_description)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The result of a guardrail validation will indicate whether the input or output passed the guardrail checks, along with details on any violations. You can then handle violations as needed, such as by rejecting the input or modifying the output. For example:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
if result.scope_class.value == "Restricted" or result.scope_class.value == "Out of Scope":
|
|
116
|
+
print("Request violates guardrail:", result.evidences)
|
|
117
|
+
else:
|
|
118
|
+
# The user request is safe!
|
|
119
|
+
# We can now pass it to the AI assistant for processing.
|
|
120
|
+
...
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Available Guardrails
|
|
124
|
+
|
|
125
|
+
Orbitals currently provides the following guardrail modules:
|
|
126
|
+
|
|
127
|
+
| Guardrail | Description | Hosting Options |
|
|
128
|
+
|:----------|:------------|:----------------|
|
|
129
|
+
| **[ScopeGuard](README.scope-guard.md)** | Classifies user queries against AI assistant specifications to detect out-of-scope requests, policy violations, and chit-chat | Self-hosted / Cloud hosting |
|
|
130
|
+
| 🚀 *Coming Soon* | More guardrails are on the way — stay tuned for updates! | — |
|
|
131
|
+
|
|
132
|
+
#### Hosting Options
|
|
133
|
+
|
|
134
|
+
- **Self-hosted**: Use open-weight models that you can deploy on your own infrastructure, ensuring data privacy and control.
|
|
135
|
+
- **Cloud hosting**: (Coming soon) Managed hosting options for ease of use and scalability
|
|
136
|
+
|
|
137
|
+
### Documentation
|
|
138
|
+
|
|
139
|
+
For detailed documentation, including installation instructions, usage guides, and API references, please visit the Orbitals Documentation.
|
|
140
|
+
|
|
141
|
+
- [ScopeGuard Documentation](README.scope-guard.md)
|
|
142
|
+
|
|
143
|
+
### FAQ
|
|
144
|
+
|
|
145
|
+
- **Can I use Orbitals for commercial applications?**
|
|
146
|
+
Yes, Orbitals is designed to be used in both research and commercial applications. It is licensed under the Apache 2.0 License, which allows for commercial use.
|
|
147
|
+
- **Other questions?**
|
|
148
|
+
Feel free to reach out to us at [orbitals@principled-intelligence.com](mailto:orbitals@principled-intelligence.com)!
|
|
149
|
+
|
|
150
|
+
### Contributing
|
|
151
|
+
|
|
152
|
+
We welcome contributions from the community! If you'd like to contribute to Orbitals, please check out our [Contributing Guide](CONTRIBUTING.md) for guidelines on how to get started.
|
|
153
|
+
|
|
154
|
+
### License
|
|
155
|
+
|
|
156
|
+
This project is licensed under the Apache 2.0 License. See the [LICENSE](LICENSE) file for details.
|
|
157
|
+
|
|
158
|
+
### Contact
|
|
159
|
+
|
|
160
|
+
For questions, feedback, or support, please reach out to us at [orbitals@principled-intelligence.com](mailto:orbitals@principled-intelligence.com).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
<div align="center">
|
|
165
|
+
<p>
|
|
166
|
+
<b>Built with ❤️ by <a href="https://principled-intelligence.com">Principled Intelligence</a></b>
|
|
167
|
+
<br />
|
|
168
|
+
Follow us on <a href="https://www.linkedin.com/company/principled-ai/">LinkedIn</a> for the latest updates.
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
orbitals/__init__.py,sha256=ED6jHcYiuYpr_0vjGz0zx2lrrmJT9sDJCzIljoDfmlM,65
|
|
2
|
-
orbitals/types.py,sha256=
|
|
3
|
-
orbitals/utils.py,sha256=
|
|
2
|
+
orbitals/types.py,sha256=4oRinWPG6kbtW4lQ8bHrDmxEotncqMIwLCmQ2yGH7PI,1988
|
|
3
|
+
orbitals/utils.py,sha256=FoCNGgPNqD4mey7_f3Rj5XBJKsp7-krcvvr5KvmnNG4,1677
|
|
4
4
|
orbitals/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
orbitals/cli/main.py,sha256=p4MEbmtJ0L8mLiyovEq7urnVc6I0mbbCNdGEtGyY60Y,197
|
|
6
6
|
orbitals/scope_guard/__init__.py,sha256=0gzzSXpfRvIcCYpu3AKQSMFYDMDJaknY9pdypt7HiuI,197
|
|
@@ -9,17 +9,17 @@ orbitals/scope_guard/prompting.py,sha256=0oV1YgklMm1bikR4anDJMP1_NFpGzfwNYk--ilu
|
|
|
9
9
|
orbitals/scope_guard/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
orbitals/scope_guard/cli/convert_default_model_name.py,sha256=f6iwEigcyoi99uqgntUx36ph7S1lXv72hA0rkrjbMM8,247
|
|
11
11
|
orbitals/scope_guard/cli/main.py,sha256=jz8fQ2e4VFZQti982feVWGpL9fT7yZeanq14pX5WAkM,219
|
|
12
|
-
orbitals/scope_guard/cli/serve.py,sha256=
|
|
12
|
+
orbitals/scope_guard/cli/serve.py,sha256=tOZbbGoashw-s0V3B5G1DTjQ_giiH6Wn4ii30dAAGrA,4611
|
|
13
13
|
orbitals/scope_guard/guards/__init__.py,sha256=B1EA9YtaTQ3ko5d2wFK2y4bXKrV8MclAELAievmZjxg,376
|
|
14
14
|
orbitals/scope_guard/guards/api.py,sha256=S8VX4_8VIhtg3_IP4Eh50l1uarcJBagGXNEEl1BZjag,8514
|
|
15
|
-
orbitals/scope_guard/guards/base.py,sha256=
|
|
16
|
-
orbitals/scope_guard/guards/hf.py,sha256=
|
|
17
|
-
orbitals/scope_guard/guards/vllm.py,sha256=
|
|
15
|
+
orbitals/scope_guard/guards/base.py,sha256=mZWAvtUq0M9s6yEzlO2r-iYj5vk-VMLe4n6nWSo5pyw,9792
|
|
16
|
+
orbitals/scope_guard/guards/hf.py,sha256=WecW157__LhFQSsMxZk-prv5kw6s_Eyn1ALrFzNNm1s,3965
|
|
17
|
+
orbitals/scope_guard/guards/vllm.py,sha256=gxMoLOtR23Ky4OQ4UnXblkBnAAxufmM1bik8tHgGAvA,8979
|
|
18
18
|
orbitals/scope_guard/serving/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
orbitals/scope_guard/serving/main.py,sha256=
|
|
19
|
+
orbitals/scope_guard/serving/main.py,sha256=ijOtsYOzsbXrgJrWKvNRjL5LmrxbHE74GbwgoXwulA8,3162
|
|
20
20
|
orbitals/scope_guard/serving/vllm_logging_config.json,sha256=Bc08X8mQWJFAAHEE6ZFVUGnRc77pMVpPvji6BhFTtSE,651
|
|
21
|
-
orbitals-0.1.
|
|
22
|
-
orbitals-0.1.
|
|
23
|
-
orbitals-0.1.
|
|
24
|
-
orbitals-0.1.
|
|
25
|
-
orbitals-0.1.
|
|
21
|
+
orbitals-0.1.2.dist-info/METADATA,sha256=3SWCRK16xMQLr8iY4KXq-QcAH0M2FK9vHP4nbcD8_Cc,7643
|
|
22
|
+
orbitals-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
23
|
+
orbitals-0.1.2.dist-info/entry_points.txt,sha256=fd6lukgEvK9UBwhA1JtcB9MLTqAtntA4H2cc7-nWkeU,51
|
|
24
|
+
orbitals-0.1.2.dist-info/licenses/LICENSE,sha256=Eeclrom-K-omYcKnMvijEMV-IMiQ7X-bdgxlZcXcImI,11360
|
|
25
|
+
orbitals-0.1.2.dist-info/RECORD,,
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Principled Intelligence s.r.l.
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: orbitals
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: LLM Guardrails tailored to your Principles
|
|
5
|
-
Author-email: Luigi Procopio <luigi@principled-intelligence.com>, Edoardo Barba <edoardo@principled-intelligence.com>
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
License-File: LICENSE
|
|
8
|
-
Requires-Python: >=3.10
|
|
9
|
-
Requires-Dist: aiohttp
|
|
10
|
-
Requires-Dist: pydantic>=2.0.0
|
|
11
|
-
Requires-Dist: requests
|
|
12
|
-
Requires-Dist: typer>=0.12.3
|
|
13
|
-
Provides-Extra: scope-guard-hf
|
|
14
|
-
Requires-Dist: accelerate>=1.11.0; extra == 'scope-guard-hf'
|
|
15
|
-
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-hf'
|
|
16
|
-
Provides-Extra: scope-guard-serve
|
|
17
|
-
Requires-Dist: fastapi[standard]>=0.119.1; extra == 'scope-guard-serve'
|
|
18
|
-
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-serve'
|
|
19
|
-
Requires-Dist: uvicorn>=0.29.0; extra == 'scope-guard-serve'
|
|
20
|
-
Requires-Dist: vllm>=0.11.0; extra == 'scope-guard-serve'
|
|
21
|
-
Requires-Dist: xgrammar; extra == 'scope-guard-serve'
|
|
22
|
-
Provides-Extra: scope-guard-vllm
|
|
23
|
-
Requires-Dist: transformers<5.0.0,>=4.47.0; extra == 'scope-guard-vllm'
|
|
24
|
-
Requires-Dist: vllm>=0.11.0; extra == 'scope-guard-vllm'
|
|
25
|
-
Requires-Dist: xgrammar; extra == 'scope-guard-vllm'
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
|
|
28
|
-
<div align="center">
|
|
29
|
-
<img src="assets/orbitals.svg" width="40%" />
|
|
30
|
-
<h3 align="center">
|
|
31
|
-
<p>
|
|
32
|
-
<b>LLM Guardrails tailored to your Principles</b>
|
|
33
|
-
</p>
|
|
34
|
-
</h4>
|
|
35
|
-
<hr/>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<p align="center">
|
|
39
|
-
<img src="https://img.shields.io/badge/type%20checked-ty-blue.svg?color=green" alt="Type Checked with ty">
|
|
40
|
-
<img src="https://img.shields.io/pypi/v/orbitals?color=green" alt="PyPI Version">
|
|
41
|
-
<img src="https://img.shields.io/github/license/principled-intelligence/orbitals" alt="GitHub License">
|
|
42
|
-
<img src="https://img.shields.io/pypi/pyversions/orbitals" alt="Python Versions">
|
|
43
|
-
<img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fprincipled-intelligence%2Forbitals%2Fmain%2Fpyproject.toml" alt="Required Python Version">
|
|
44
|
-
</p>
|
|
45
|
-
|
|
46
|
-
`orbitals` is an ecosystem of LLM guardrails, designed to provide a governance layer tailored to **user-specific principles, requirements and use cases**. Rather than enforcing generic notions of safety, correctness, etc., Orbitals evaluates inputs and outputs against *user-defined specifications*. This makes guardrails explicit, auditable, and aligned with the user's philosophy.
|
|
47
|
-
|
|
48
|
-
Orbitals guardrails fall into two typologies:
|
|
49
|
-
- **Guards** operate on the *input* of a guardrailed LLM, assessing whether a user request is legitimate under the provided specifications.
|
|
50
|
-
- **Supervisors** operate on the *output* of a guardrailed LLM, evaluating the assistant’s response before it is returned.
|
|
51
|
-
|
|
52
|
-
Guardrails may be released under different modality flavors:
|
|
53
|
-
- **Open** (open-source and open-weight), allowing users to run guardrails and underlying models on their own infrastructure.
|
|
54
|
-
- **Hosted**, accessible via simple HTTP calls (API key required).
|
|
55
|
-
|
|
56
|
-
## Available Guardrails
|
|
57
|
-
|
|
58
|
-
| Name | Flavor | Description |
|
|
59
|
-
|-------------|-------------------------|-----------------------------------------------------------------------------|
|
|
60
|
-
| [ScopeGuard](README.scope-guard.md) | Open / Hosted | Validates whether a user request falls within the intended use of an AI service. |
|
|
61
|
-
| RagSupervisor | Coming soon | Ensures LLM responses remain grounded in retrieved context for RAG setups. |
|
|
62
|
-
|
|
63
|
-
<details>
|
|
64
|
-
<summary>ScopeGuard</summary>
|
|
65
|
-
<br>
|
|
66
|
-
|
|
67
|
-
First, we need to install `orbitals` and `scope-guard`:
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
pip install orbitals[scope-guard-vllm]
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Then:
|
|
74
|
-
|
|
75
|
-
```python
|
|
76
|
-
from orbitals.scope_guard import ScopeGuard
|
|
77
|
-
|
|
78
|
-
scope_guard = ScopeGuard(
|
|
79
|
-
backend="vllm",
|
|
80
|
-
model="small"
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
ai_service_description = """
|
|
84
|
-
You are a virtual assistant for a parcel delivery service.
|
|
85
|
-
You can only answer questions about package tracking.
|
|
86
|
-
Never respond to requests for refunds.
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
user_query = "If the package hasn't arrived by tomorrow, can I get my money back?"
|
|
90
|
-
result = scope_guard.validate(user_query, ai_service_description)
|
|
91
|
-
|
|
92
|
-
print(f"Scope: {result.scope_class.value}")
|
|
93
|
-
if result.evidences:
|
|
94
|
-
print("Evidences:")
|
|
95
|
-
for evidence in result.evidences:
|
|
96
|
-
print(f" - {evidence}")
|
|
97
|
-
|
|
98
|
-
# Scope: Restricted
|
|
99
|
-
# Evidences:
|
|
100
|
-
# - Never respond to requests for refunds.
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
</details>
|
|
File without changes
|
|
File without changes
|