oridio 0.1.0__tar.gz
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.
- oridio-0.1.0/.gitignore +47 -0
- oridio-0.1.0/PKG-INFO +209 -0
- oridio-0.1.0/README.md +172 -0
- oridio-0.1.0/oridio/__init__.py +99 -0
- oridio-0.1.0/oridio/bootstrap.py +45 -0
- oridio-0.1.0/oridio/client.py +1002 -0
- oridio-0.1.0/oridio/context.py +30 -0
- oridio-0.1.0/oridio/decorators.py +78 -0
- oridio-0.1.0/oridio/exceptions.py +113 -0
- oridio-0.1.0/oridio/interceptors.py +150 -0
- oridio-0.1.0/oridio/models.py +317 -0
- oridio-0.1.0/oridio/tools/__init__.py +4 -0
- oridio-0.1.0/oridio/tools/bridge.py +84 -0
- oridio-0.1.0/oridio/tools/schema.py +85 -0
- oridio-0.1.0/oridio-crewai/oridio_crewai/__init__.py +113 -0
- oridio-0.1.0/oridio-langgraph/oridio_langgraph/__init__.py +105 -0
- oridio-0.1.0/pyproject.toml +63 -0
oridio-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Rust build artifacts
|
|
2
|
+
target/
|
|
3
|
+
Cargo.lock
|
|
4
|
+
|
|
5
|
+
# Environment variables
|
|
6
|
+
.env
|
|
7
|
+
.env.local
|
|
8
|
+
.env.*.local
|
|
9
|
+
|
|
10
|
+
# IDEs and editors
|
|
11
|
+
.idea/
|
|
12
|
+
.vscode/
|
|
13
|
+
*.suo
|
|
14
|
+
*.ntvs*
|
|
15
|
+
*.njsproj
|
|
16
|
+
*.sln
|
|
17
|
+
*.sw?
|
|
18
|
+
|
|
19
|
+
# OS files
|
|
20
|
+
.DS_Store
|
|
21
|
+
Thumbs.db
|
|
22
|
+
|
|
23
|
+
# Logs
|
|
24
|
+
*.log
|
|
25
|
+
|
|
26
|
+
# Python
|
|
27
|
+
__pycache__/
|
|
28
|
+
*.py[cod]
|
|
29
|
+
*.class
|
|
30
|
+
*.egg-info/
|
|
31
|
+
.pytest_cache/
|
|
32
|
+
.venv/
|
|
33
|
+
venv/
|
|
34
|
+
|
|
35
|
+
# Node
|
|
36
|
+
node_modules/
|
|
37
|
+
dist/
|
|
38
|
+
.npm/
|
|
39
|
+
|
|
40
|
+
# Oridio specific
|
|
41
|
+
.fastembed_cache/
|
|
42
|
+
|
|
43
|
+
test_results.json
|
|
44
|
+
*.key
|
|
45
|
+
*.pem
|
|
46
|
+
.next/
|
|
47
|
+
demo/
|
oridio-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: oridio
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Oridio — AI Control Plane
|
|
5
|
+
Project-URL: Homepage, https://oridio.org
|
|
6
|
+
Project-URL: Repository, https://github.com/Oridio-org/ORIDIO
|
|
7
|
+
Project-URL: Documentation, https://oridio.org/docs
|
|
8
|
+
Author-email: Oridio <team@oridio.org>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Keywords: ai,control-plane,langchain,langgraph,llm,openai,proxy
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx>=0.27.0
|
|
22
|
+
Requires-Dist: opentelemetry-api>=1.20.0
|
|
23
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.45b0
|
|
24
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.45b0
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0
|
|
26
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
27
|
+
Requires-Dist: websockets>=12.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
33
|
+
Requires-Dist: types-requests; extra == 'dev'
|
|
34
|
+
Provides-Extra: langchain
|
|
35
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == 'langchain'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# Oridio Python SDK
|
|
39
|
+
|
|
40
|
+
[](https://badge.fury.io/py/oridio)
|
|
41
|
+
[](https://opensource.org/licenses/MIT)
|
|
42
|
+
|
|
43
|
+
The official Python SDK for [Oridio](https://oridio.org) — the Enterprise AI Control Plane.
|
|
44
|
+
|
|
45
|
+
Oridio is a high-performance, drop-in OpenAI-compatible proxy that provides:
|
|
46
|
+
- 🛡️ **Policy Enforcement:** Set cost limits, redact PII, block toxic content, and detect prompt injections before they reach the LLM.
|
|
47
|
+
- ⚡ **Semantic Caching:** Serve identical or semantically similar requests instantly from cache, saving tokens and reducing latency.
|
|
48
|
+
- 🔀 **Intelligent Routing:** Automatically route requests to fallback models when primary providers experience downtime.
|
|
49
|
+
- 📊 **Observability & Audit:** Full telemetry, usage analytics, and SOC2-compliant audit logs.
|
|
50
|
+
- 🤖 **Agent-Ready:** Native integration with LangGraph, CrewAI, and other agentic frameworks out of the box.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
Install the base package:
|
|
55
|
+
```bash
|
|
56
|
+
pip install oridio
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If you are using LangChain, you can install the optional dependencies:
|
|
60
|
+
```bash
|
|
61
|
+
pip install "oridio[langchain]"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
### 1. Drop-in OpenAI Replacement
|
|
67
|
+
|
|
68
|
+
Use the `OridioClient` exactly as you would use the `OpenAI` client. All your existing code will continue to work, but with added security and caching.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import oridio
|
|
72
|
+
|
|
73
|
+
client = oridio.OridioClient(
|
|
74
|
+
api_key="sk-or-your-key",
|
|
75
|
+
proxy_url="http://localhost:8080", # Point to your Oridio proxy
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
response = client.chat.completions.create(
|
|
79
|
+
model="gpt-4o",
|
|
80
|
+
messages=[{"role": "user", "content": "Explain quantum computing in one sentence."}],
|
|
81
|
+
)
|
|
82
|
+
print(response.choices[0].message.content)
|
|
83
|
+
print(f"Cache hit: {response.cache_hit}") # True on repeated or similar requests
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 2. LangGraph / LangChain Integration (Zero Code Change)
|
|
87
|
+
|
|
88
|
+
Because Oridio acts as an OpenAI-compatible endpoint, integrating with LangChain is as simple as overriding the `base_url`.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from langchain_openai import ChatOpenAI
|
|
92
|
+
|
|
93
|
+
llm = ChatOpenAI(
|
|
94
|
+
model="gpt-4o",
|
|
95
|
+
base_url="http://localhost:8080/v1", # Point to your Oridio proxy
|
|
96
|
+
api_key="sk-or-your-key",
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. Asynchronous Usage
|
|
101
|
+
|
|
102
|
+
For high-throughput or asynchronous applications, use the `AsyncOridioClient`.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import asyncio
|
|
106
|
+
from oridio import AsyncOridioClient
|
|
107
|
+
|
|
108
|
+
async def main():
|
|
109
|
+
async with AsyncOridioClient(api_key="sk-or-your-key") as client:
|
|
110
|
+
response = await client.chat.completions.create(
|
|
111
|
+
model="gpt-4o",
|
|
112
|
+
messages=[{"role": "user", "content": "Hello async!"}],
|
|
113
|
+
)
|
|
114
|
+
print(response.choices[0].message.content)
|
|
115
|
+
|
|
116
|
+
asyncio.run(main())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Advanced Policy Management
|
|
120
|
+
|
|
121
|
+
The SDK also allows you to interact with the **Oridio Control Plane** to manage policies programmatically.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
client = oridio.OridioClient(
|
|
125
|
+
admin_token="your-admin-token",
|
|
126
|
+
control_plane_url="http://localhost:3000",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Create an advanced policy for cost optimization and safety
|
|
130
|
+
policy = client.policies.create({
|
|
131
|
+
"name": "strict-production-guardrails",
|
|
132
|
+
"rules": [
|
|
133
|
+
{
|
|
134
|
+
"id": "cost-limit",
|
|
135
|
+
"name": "Daily Cost Limit",
|
|
136
|
+
"action": "block",
|
|
137
|
+
"conditions": {"cost_limit": {"daily_usd": 100}}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "pii-redaction",
|
|
141
|
+
"name": "Redact Sensitive Info",
|
|
142
|
+
"action": "redact",
|
|
143
|
+
"pii_types": ["EMAIL", "CREDIT_CARD", "SSN"]
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
# Deploy the policy to all active Data Planes (Proxies)
|
|
149
|
+
client.policies.deploy(policy.id)
|
|
150
|
+
print(f"Deployed policy: {policy.name}")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Error Handling
|
|
154
|
+
|
|
155
|
+
Oridio provides strongly-typed exceptions so your applications can react gracefully to policy blocks or rate limits.
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from oridio import OridioPolicyBlockedError, OridioRateLimitError, OridioAuthError
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
response = client.chat.completions.create(model="gpt-4o", messages=[...])
|
|
162
|
+
except OridioPolicyBlockedError as e:
|
|
163
|
+
# Handle requests blocked by your custom guardrails (e.g., PII detected, cost limit exceeded)
|
|
164
|
+
print(f"🚨 Request Blocked: {e.reason}")
|
|
165
|
+
print(f"Triggered Rules: {e.rules_matched}")
|
|
166
|
+
except OridioRateLimitError as e:
|
|
167
|
+
# Handle Oridio or provider rate limits
|
|
168
|
+
print(f"⏳ Rate limited. Retry after {e.retry_after} seconds.")
|
|
169
|
+
except OridioAuthError:
|
|
170
|
+
print("❌ Invalid API key.")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## API Key Management & Usage Analytics
|
|
174
|
+
|
|
175
|
+
Manage programmatic access and track spend:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# Create a scoped key
|
|
179
|
+
key = client.keys.create(name="production-backend-key", spend_limit_usd=50)
|
|
180
|
+
print(f"Secret: {key.secret}") # Store securely! Only shown once.
|
|
181
|
+
|
|
182
|
+
# Track Usage
|
|
183
|
+
records = client.usage.list(limit=100)
|
|
184
|
+
total_cost = sum(r.estimated_cost_usd for r in records)
|
|
185
|
+
cache_hits = sum(1 for r in records if r.cache_hit)
|
|
186
|
+
print(f"Total spend: ${total_cost:.4f} | Cache hits: {cache_hits}/{len(records)}")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Examples
|
|
190
|
+
|
|
191
|
+
See [`examples/`](../../examples/) for full working demos:
|
|
192
|
+
- `basic_proxy.py` — Simple script showing basic chat completion via Oridio.
|
|
193
|
+
- `advanced_policy.py` — Demonstrates catching and handling policy enforcement blocks.
|
|
194
|
+
- `langgraph_example.py` — LangGraph ReAct agent with policy enforcement.
|
|
195
|
+
- `crewai_example.py` — Multi-agent CrewAI pipeline with cost tracking.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Known Limitations & Intentional Gaps
|
|
200
|
+
|
|
201
|
+
| Feature | Status | Notes |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `keys.create()` response | Fixed in SDK | CP returns `{"status": "success", "data": {"id": ..., "key": ...}}`. The SDK unwraps this and normalises `key` → `secret`. |
|
|
204
|
+
| `keys.list()` response | Handled | CP may return a flat array or `{"data": [...]}` — both are handled. |
|
|
205
|
+
| `estimated_cost_usd` for unknown models | By design | When `estimated_cost_known=False`, cost is `0.0` (not a real zero). Do not aggregate for spend reporting without checking this flag. |
|
|
206
|
+
| `McpServer.sandbox_preference` | Documented | Default is `"process"`. Firecracker requires KVM-capable Linux hosts; will hard-deny when `require_strong_isolation=True` and Firecracker is unavailable. |
|
|
207
|
+
| Async MCP client | Not yet implemented | `AsyncOridioClient` exposes `chat.completions.create` but not the full MCP management API. Use the synchronous `OridioClient` for MCP admin operations. |
|
|
208
|
+
| Admin dashboard | Deferred | No web UI. All operations use this SDK or the REST API directly. |
|
|
209
|
+
| SSO / SAML | Not implemented | Auth is via static admin token or JWT. |
|
oridio-0.1.0/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Oridio Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/oridio)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
The official Python SDK for [Oridio](https://oridio.org) — the Enterprise AI Control Plane.
|
|
7
|
+
|
|
8
|
+
Oridio is a high-performance, drop-in OpenAI-compatible proxy that provides:
|
|
9
|
+
- 🛡️ **Policy Enforcement:** Set cost limits, redact PII, block toxic content, and detect prompt injections before they reach the LLM.
|
|
10
|
+
- ⚡ **Semantic Caching:** Serve identical or semantically similar requests instantly from cache, saving tokens and reducing latency.
|
|
11
|
+
- 🔀 **Intelligent Routing:** Automatically route requests to fallback models when primary providers experience downtime.
|
|
12
|
+
- 📊 **Observability & Audit:** Full telemetry, usage analytics, and SOC2-compliant audit logs.
|
|
13
|
+
- 🤖 **Agent-Ready:** Native integration with LangGraph, CrewAI, and other agentic frameworks out of the box.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Install the base package:
|
|
18
|
+
```bash
|
|
19
|
+
pip install oridio
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you are using LangChain, you can install the optional dependencies:
|
|
23
|
+
```bash
|
|
24
|
+
pip install "oridio[langchain]"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Drop-in OpenAI Replacement
|
|
30
|
+
|
|
31
|
+
Use the `OridioClient` exactly as you would use the `OpenAI` client. All your existing code will continue to work, but with added security and caching.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import oridio
|
|
35
|
+
|
|
36
|
+
client = oridio.OridioClient(
|
|
37
|
+
api_key="sk-or-your-key",
|
|
38
|
+
proxy_url="http://localhost:8080", # Point to your Oridio proxy
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
response = client.chat.completions.create(
|
|
42
|
+
model="gpt-4o",
|
|
43
|
+
messages=[{"role": "user", "content": "Explain quantum computing in one sentence."}],
|
|
44
|
+
)
|
|
45
|
+
print(response.choices[0].message.content)
|
|
46
|
+
print(f"Cache hit: {response.cache_hit}") # True on repeated or similar requests
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. LangGraph / LangChain Integration (Zero Code Change)
|
|
50
|
+
|
|
51
|
+
Because Oridio acts as an OpenAI-compatible endpoint, integrating with LangChain is as simple as overriding the `base_url`.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from langchain_openai import ChatOpenAI
|
|
55
|
+
|
|
56
|
+
llm = ChatOpenAI(
|
|
57
|
+
model="gpt-4o",
|
|
58
|
+
base_url="http://localhost:8080/v1", # Point to your Oridio proxy
|
|
59
|
+
api_key="sk-or-your-key",
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Asynchronous Usage
|
|
64
|
+
|
|
65
|
+
For high-throughput or asynchronous applications, use the `AsyncOridioClient`.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
import asyncio
|
|
69
|
+
from oridio import AsyncOridioClient
|
|
70
|
+
|
|
71
|
+
async def main():
|
|
72
|
+
async with AsyncOridioClient(api_key="sk-or-your-key") as client:
|
|
73
|
+
response = await client.chat.completions.create(
|
|
74
|
+
model="gpt-4o",
|
|
75
|
+
messages=[{"role": "user", "content": "Hello async!"}],
|
|
76
|
+
)
|
|
77
|
+
print(response.choices[0].message.content)
|
|
78
|
+
|
|
79
|
+
asyncio.run(main())
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Advanced Policy Management
|
|
83
|
+
|
|
84
|
+
The SDK also allows you to interact with the **Oridio Control Plane** to manage policies programmatically.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
client = oridio.OridioClient(
|
|
88
|
+
admin_token="your-admin-token",
|
|
89
|
+
control_plane_url="http://localhost:3000",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Create an advanced policy for cost optimization and safety
|
|
93
|
+
policy = client.policies.create({
|
|
94
|
+
"name": "strict-production-guardrails",
|
|
95
|
+
"rules": [
|
|
96
|
+
{
|
|
97
|
+
"id": "cost-limit",
|
|
98
|
+
"name": "Daily Cost Limit",
|
|
99
|
+
"action": "block",
|
|
100
|
+
"conditions": {"cost_limit": {"daily_usd": 100}}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"id": "pii-redaction",
|
|
104
|
+
"name": "Redact Sensitive Info",
|
|
105
|
+
"action": "redact",
|
|
106
|
+
"pii_types": ["EMAIL", "CREDIT_CARD", "SSN"]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
# Deploy the policy to all active Data Planes (Proxies)
|
|
112
|
+
client.policies.deploy(policy.id)
|
|
113
|
+
print(f"Deployed policy: {policy.name}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Error Handling
|
|
117
|
+
|
|
118
|
+
Oridio provides strongly-typed exceptions so your applications can react gracefully to policy blocks or rate limits.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from oridio import OridioPolicyBlockedError, OridioRateLimitError, OridioAuthError
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
response = client.chat.completions.create(model="gpt-4o", messages=[...])
|
|
125
|
+
except OridioPolicyBlockedError as e:
|
|
126
|
+
# Handle requests blocked by your custom guardrails (e.g., PII detected, cost limit exceeded)
|
|
127
|
+
print(f"🚨 Request Blocked: {e.reason}")
|
|
128
|
+
print(f"Triggered Rules: {e.rules_matched}")
|
|
129
|
+
except OridioRateLimitError as e:
|
|
130
|
+
# Handle Oridio or provider rate limits
|
|
131
|
+
print(f"⏳ Rate limited. Retry after {e.retry_after} seconds.")
|
|
132
|
+
except OridioAuthError:
|
|
133
|
+
print("❌ Invalid API key.")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## API Key Management & Usage Analytics
|
|
137
|
+
|
|
138
|
+
Manage programmatic access and track spend:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
# Create a scoped key
|
|
142
|
+
key = client.keys.create(name="production-backend-key", spend_limit_usd=50)
|
|
143
|
+
print(f"Secret: {key.secret}") # Store securely! Only shown once.
|
|
144
|
+
|
|
145
|
+
# Track Usage
|
|
146
|
+
records = client.usage.list(limit=100)
|
|
147
|
+
total_cost = sum(r.estimated_cost_usd for r in records)
|
|
148
|
+
cache_hits = sum(1 for r in records if r.cache_hit)
|
|
149
|
+
print(f"Total spend: ${total_cost:.4f} | Cache hits: {cache_hits}/{len(records)}")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
See [`examples/`](../../examples/) for full working demos:
|
|
155
|
+
- `basic_proxy.py` — Simple script showing basic chat completion via Oridio.
|
|
156
|
+
- `advanced_policy.py` — Demonstrates catching and handling policy enforcement blocks.
|
|
157
|
+
- `langgraph_example.py` — LangGraph ReAct agent with policy enforcement.
|
|
158
|
+
- `crewai_example.py` — Multi-agent CrewAI pipeline with cost tracking.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Known Limitations & Intentional Gaps
|
|
163
|
+
|
|
164
|
+
| Feature | Status | Notes |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| `keys.create()` response | Fixed in SDK | CP returns `{"status": "success", "data": {"id": ..., "key": ...}}`. The SDK unwraps this and normalises `key` → `secret`. |
|
|
167
|
+
| `keys.list()` response | Handled | CP may return a flat array or `{"data": [...]}` — both are handled. |
|
|
168
|
+
| `estimated_cost_usd` for unknown models | By design | When `estimated_cost_known=False`, cost is `0.0` (not a real zero). Do not aggregate for spend reporting without checking this flag. |
|
|
169
|
+
| `McpServer.sandbox_preference` | Documented | Default is `"process"`. Firecracker requires KVM-capable Linux hosts; will hard-deny when `require_strong_isolation=True` and Firecracker is unavailable. |
|
|
170
|
+
| Async MCP client | Not yet implemented | `AsyncOridioClient` exposes `chat.completions.create` but not the full MCP management API. Use the synchronous `OridioClient` for MCP admin operations. |
|
|
171
|
+
| Admin dashboard | Deferred | No web UI. All operations use this SDK or the REST API directly. |
|
|
172
|
+
| SSO / SAML | Not implemented | Auth is via static admin token or JWT. |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Oridio Python SDK — AI Control Plane
|
|
3
|
+
|
|
4
|
+
Drop-in OpenAI-compatible proxy with policy enforcement,
|
|
5
|
+
semantic caching, cost controls, and observability.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
|
|
10
|
+
from .client import OridioClient, AsyncOridioClient
|
|
11
|
+
from .decorators import oridio_protected
|
|
12
|
+
from .context import (
|
|
13
|
+
set_agent_id, get_agent_id,
|
|
14
|
+
set_session_id, get_session_id,
|
|
15
|
+
set_run_id, get_run_id
|
|
16
|
+
)
|
|
17
|
+
from .bootstrap import init
|
|
18
|
+
from .tools.bridge import wrap_tool, register_autogen_tool
|
|
19
|
+
from .tools.schema import extract_mcp_schema
|
|
20
|
+
from .interceptors import (
|
|
21
|
+
create_openai_client,
|
|
22
|
+
create_async_openai_client,
|
|
23
|
+
create_anthropic_client,
|
|
24
|
+
create_async_anthropic_client,
|
|
25
|
+
spawn_child,
|
|
26
|
+
)
|
|
27
|
+
from .exceptions import (
|
|
28
|
+
OridioError,
|
|
29
|
+
OridioAPIError,
|
|
30
|
+
OridioAuthError,
|
|
31
|
+
OridioRateLimitError,
|
|
32
|
+
OridioPolicyBlockedError,
|
|
33
|
+
OridioTimeoutError,
|
|
34
|
+
OridioHITLPendingError,
|
|
35
|
+
OridioHITLTimeoutError,
|
|
36
|
+
OridioHITLDeniedError,
|
|
37
|
+
)
|
|
38
|
+
from .models import (
|
|
39
|
+
ChatMessage,
|
|
40
|
+
ChatCompletionRequest,
|
|
41
|
+
ChatCompletionResponse,
|
|
42
|
+
McpGrant,
|
|
43
|
+
McpServer,
|
|
44
|
+
McpTool,
|
|
45
|
+
Policy,
|
|
46
|
+
PolicyRule,
|
|
47
|
+
ApiKey,
|
|
48
|
+
UsageRecord,
|
|
49
|
+
AgentStatus,
|
|
50
|
+
AgentIdentity,
|
|
51
|
+
MCPMeta,
|
|
52
|
+
MCPParams,
|
|
53
|
+
MCPPayload,
|
|
54
|
+
FirewallVerdict,
|
|
55
|
+
OridioResponse,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
"__version__",
|
|
60
|
+
# Client
|
|
61
|
+
"OridioClient",
|
|
62
|
+
"AsyncOridioClient",
|
|
63
|
+
"oridio_protected",
|
|
64
|
+
"create_openai_client",
|
|
65
|
+
"create_async_openai_client",
|
|
66
|
+
"create_anthropic_client",
|
|
67
|
+
"create_async_anthropic_client",
|
|
68
|
+
"spawn_child",
|
|
69
|
+
# Exceptions
|
|
70
|
+
"OridioError",
|
|
71
|
+
"OridioAPIError",
|
|
72
|
+
"OridioAuthError",
|
|
73
|
+
"OridioRateLimitError",
|
|
74
|
+
"OridioPolicyBlockedError",
|
|
75
|
+
"OridioTimeoutError",
|
|
76
|
+
"OridioHITLPendingError",
|
|
77
|
+
"OridioHITLTimeoutError",
|
|
78
|
+
"OridioHITLDeniedError",
|
|
79
|
+
"extract_mcp_schema",
|
|
80
|
+
# Models
|
|
81
|
+
"ChatMessage",
|
|
82
|
+
"ChatCompletionRequest",
|
|
83
|
+
"ChatCompletionResponse",
|
|
84
|
+
"McpGrant",
|
|
85
|
+
"McpServer",
|
|
86
|
+
"McpTool",
|
|
87
|
+
"Policy",
|
|
88
|
+
"PolicyRule",
|
|
89
|
+
"ApiKey",
|
|
90
|
+
"UsageRecord",
|
|
91
|
+
"AgentStatus",
|
|
92
|
+
"AgentIdentity",
|
|
93
|
+
"MCPMeta",
|
|
94
|
+
"MCPParams",
|
|
95
|
+
"MCPPayload",
|
|
96
|
+
"FirewallVerdict",
|
|
97
|
+
"OridioResponse",
|
|
98
|
+
]
|
|
99
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
|
|
4
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
5
|
+
from .context import get_agent_id
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
def _request_hook(span, request):
|
|
10
|
+
"""Inject Oridio headers into outbound HTTP requests."""
|
|
11
|
+
agent_id = get_agent_id()
|
|
12
|
+
if agent_id:
|
|
13
|
+
request.headers["X-Oridio-Agent-Id"] = agent_id
|
|
14
|
+
|
|
15
|
+
# The JWT is typically already in the environment or set by the user,
|
|
16
|
+
# but if we wanted to auto-inject a known key here we could.
|
|
17
|
+
oridio_api_key = os.environ.get("ORIDIO_API_KEY")
|
|
18
|
+
if oridio_api_key and "Authorization" not in request.headers:
|
|
19
|
+
request.headers["Authorization"] = f"Bearer {oridio_api_key}"
|
|
20
|
+
|
|
21
|
+
def init():
|
|
22
|
+
"""
|
|
23
|
+
Initialize global Oridio interception for Python.
|
|
24
|
+
|
|
25
|
+
1. Sets OPENAI_BASE_URL and ANTHROPIC_BASE_URL to point to the proxy.
|
|
26
|
+
2. Hooks httpx and requests via OpenTelemetry to inject identity headers.
|
|
27
|
+
"""
|
|
28
|
+
proxy_url = os.environ.get("ORIDIO_PROXY_URL", "http://localhost:8080")
|
|
29
|
+
|
|
30
|
+
# Force OpenAI and Anthropic SDKs to use the Oridio proxy
|
|
31
|
+
os.environ.setdefault("OPENAI_BASE_URL", f"{proxy_url}/v1")
|
|
32
|
+
os.environ.setdefault("ANTHROPIC_BASE_URL", f"{proxy_url}/v1")
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
HTTPXClientInstrumentor().instrument(request_hook=_request_hook)
|
|
36
|
+
logger.info("Successfully instrumented httpx.")
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logger.warning(f"Failed to instrument httpx: {e}")
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
RequestsInstrumentor().instrument(request_hook=_request_hook)
|
|
42
|
+
logger.info("Successfully instrumented requests.")
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logger.warning(f"Failed to instrument requests: {e}")
|
|
45
|
+
|