kalibr 1.0.21__tar.gz → 1.0.23__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.
- kalibr-1.0.23/PKG-INFO +257 -0
- kalibr-1.0.23/README.md +208 -0
- kalibr-1.0.23/kalibr/__main__.py +206 -0
- kalibr-1.0.23/kalibr/deployment.py +41 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/kalibr_app.py +32 -11
- kalibr-1.0.23/kalibr/packager.py +43 -0
- kalibr-1.0.23/kalibr/runtime_router.py +138 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/schema_generators.py +21 -74
- kalibr-1.0.23/kalibr/validator.py +70 -0
- kalibr-1.0.23/kalibr.egg-info/PKG-INFO +257 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/SOURCES.txt +3 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/pyproject.toml +1 -1
- {kalibr-1.0.21 → kalibr-1.0.23}/setup.py +1 -1
- kalibr-1.0.21/PKG-INFO +0 -302
- kalibr-1.0.21/README.md +0 -253
- kalibr-1.0.21/kalibr/__main__.py +0 -677
- kalibr-1.0.21/kalibr/deployment.py +0 -26
- kalibr-1.0.21/kalibr.egg-info/PKG-INFO +0 -302
- {kalibr-1.0.21 → kalibr-1.0.23}/LICENSE +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/MANIFEST.in +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/examples/README.md +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/examples/__init__.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/examples/basic_kalibr_example.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/examples/enhanced_kalibr_example.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/__init__.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/kalibr.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/types.py +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/dependency_links.txt +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/entry_points.txt +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/requires.txt +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/top_level.txt +0 -0
- {kalibr-1.0.21 → kalibr-1.0.23}/setup.cfg +0 -0
kalibr-1.0.23/PKG-INFO
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kalibr
|
|
3
|
+
Version: 1.0.23
|
|
4
|
+
Summary: Multi-Model AI Integration Framework
|
|
5
|
+
Home-page: https://github.com/devonakelley/kalibr-sdk
|
|
6
|
+
Author: Kalibr Team
|
|
7
|
+
Author-email: Kalibr Team <team@kalibr.dev>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://kalibr.dev
|
|
10
|
+
Project-URL: Documentation, https://kalibr.dev/docs
|
|
11
|
+
Project-URL: Repository, https://github.com/devonakelley/kalibr-sdk
|
|
12
|
+
Project-URL: Bug Reports, https://github.com/devonakelley/kalibr-sdk/issues
|
|
13
|
+
Keywords: ai,api,framework,gpt,claude,gemini,copilot,multi-model,sdk
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: fastapi>=0.110.1
|
|
28
|
+
Requires-Dist: uvicorn>=0.25.0
|
|
29
|
+
Requires-Dist: pydantic>=2.6.4
|
|
30
|
+
Requires-Dist: typer>=0.9.0
|
|
31
|
+
Requires-Dist: requests>=2.31.0
|
|
32
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
33
|
+
Requires-Dist: passlib[bcrypt]>=1.7.4
|
|
34
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
35
|
+
Requires-Dist: motor>=3.3.1
|
|
36
|
+
Requires-Dist: pymongo>=4.5.0
|
|
37
|
+
Requires-Dist: boto3>=1.34.129
|
|
38
|
+
Requires-Dist: aiofiles>=23.2.1
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: black>=24.1.1; extra == "dev"
|
|
42
|
+
Requires-Dist: isort>=5.13.2; extra == "dev"
|
|
43
|
+
Requires-Dist: flake8>=7.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: mypy>=1.8.0; extra == "dev"
|
|
45
|
+
Dynamic: author
|
|
46
|
+
Dynamic: home-page
|
|
47
|
+
Dynamic: license-file
|
|
48
|
+
Dynamic: requires-python
|
|
49
|
+
|
|
50
|
+
# Kalibr SDK
|
|
51
|
+
### Multi-Model AI Integration Framework
|
|
52
|
+
|
|
53
|
+
**Write once. Deploy anywhere. Connect to any AI model.**
|
|
54
|
+
|
|
55
|
+
Kalibr turns Python functions into APIs that work seamlessly with GPT, Claude, Gemini, and Copilot — automatically generating model-specific schemas and endpoints.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 🚀 Quick Start (2 minutes)
|
|
60
|
+
|
|
61
|
+
### 1. Install
|
|
62
|
+
```bash
|
|
63
|
+
pip install kalibr
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. Get Examples
|
|
67
|
+
```bash
|
|
68
|
+
kalibr-connect examples
|
|
69
|
+
```
|
|
70
|
+
This copies example files to `./kalibr_examples/` in your current directory.
|
|
71
|
+
|
|
72
|
+
### 3. Run Demo
|
|
73
|
+
```bash
|
|
74
|
+
kalibr-connect serve kalibr_examples/basic_kalibr_example.py
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 4. See All Schemas
|
|
78
|
+
Kalibr now **auto-detects your environment** and generates the correct base URLs.
|
|
79
|
+
|
|
80
|
+
| Environment | Example Base URL |
|
|
81
|
+
|--------------|------------------|
|
|
82
|
+
| Local Dev | `http://localhost:8000` |
|
|
83
|
+
| Fly.io | `https://<app-name>.fly.dev` |
|
|
84
|
+
| Custom Host | Use `KALIBR_BASE_URL` env var |
|
|
85
|
+
|
|
86
|
+
Then open:
|
|
87
|
+
```
|
|
88
|
+
<your-base-url>/gpt-actions.json # ChatGPT
|
|
89
|
+
<your-base-url>/mcp.json # Claude
|
|
90
|
+
<your-base-url>/schemas/gemini # Gemini
|
|
91
|
+
<your-base-url>/schemas/copilot # Copilot
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🧠 What Kalibr Does
|
|
97
|
+
|
|
98
|
+
Kalibr turns your Python functions into production-ready multi-model APIs.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from kalibr import Kalibr
|
|
102
|
+
|
|
103
|
+
app = Kalibr(title="Inventory API")
|
|
104
|
+
|
|
105
|
+
@app.action("get_inventory", "Fetch inventory data")
|
|
106
|
+
def get_inventory(product_id: str):
|
|
107
|
+
return {"product_id": product_id, "stock": 42}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Result:
|
|
111
|
+
ChatGPT, Claude, Gemini, and Copilot can all call `get_inventory()` using their native protocols — no schema work required.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 💪 Two Modes
|
|
116
|
+
|
|
117
|
+
### **Function-Level (Simple)**
|
|
118
|
+
Ideal for one-off APIs or scripts.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from kalibr import Kalibr
|
|
122
|
+
|
|
123
|
+
app = Kalibr(title="My API")
|
|
124
|
+
|
|
125
|
+
@app.action("calculate_price", "Calculate price total")
|
|
126
|
+
def calculate_price(product_id: str, quantity: int):
|
|
127
|
+
return {"total": quantity * 19.99}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### **App-Level (Advanced)**
|
|
131
|
+
Use `KalibrApp` for complete control — file uploads, sessions, streaming, and workflows.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from kalibr import KalibrApp
|
|
135
|
+
from kalibr.types import FileUpload, Session
|
|
136
|
+
|
|
137
|
+
app = KalibrApp(title="Advanced API")
|
|
138
|
+
|
|
139
|
+
@app.file_handler("analyze_doc", [".pdf", ".docx"])
|
|
140
|
+
async def analyze_doc(file: FileUpload):
|
|
141
|
+
return {"filename": file.filename, "analysis": "..."}
|
|
142
|
+
|
|
143
|
+
@app.session_action("save_data", "Save session data")
|
|
144
|
+
async def save_data(session: Session, data: dict):
|
|
145
|
+
session.set("my_data", data)
|
|
146
|
+
return {"saved": True}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 📚 Examples Included
|
|
152
|
+
|
|
153
|
+
After running `kalibr-connect examples`, you’ll get:
|
|
154
|
+
|
|
155
|
+
- `basic_kalibr_example.py` – simple function-level demo
|
|
156
|
+
- `enhanced_kalibr_example.py` – full app with sessions, uploads, and streaming
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 🤖 AI Platform Integration
|
|
161
|
+
|
|
162
|
+
### ChatGPT (GPT Actions)
|
|
163
|
+
1. Copy schema URL:
|
|
164
|
+
`https://<your-domain>/gpt-actions.json`
|
|
165
|
+
2. In GPT Builder → *Actions* → *Import from URL*
|
|
166
|
+
3. Done — ChatGPT can call your endpoints.
|
|
167
|
+
|
|
168
|
+
### Claude (MCP)
|
|
169
|
+
Add to Claude Desktop config:
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"mcp": {
|
|
173
|
+
"servers": {
|
|
174
|
+
"my-api": {
|
|
175
|
+
"url": "https://<your-domain>/mcp.json"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Gemini / Copilot
|
|
183
|
+
Use:
|
|
184
|
+
```
|
|
185
|
+
https://<your-domain>/schemas/gemini
|
|
186
|
+
https://<your-domain>/schemas/copilot
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 🎯 Common Use Cases
|
|
192
|
+
|
|
193
|
+
- **Customer Service APIs** — let AI handle orders or refunds
|
|
194
|
+
- **Data Analysis** — query your analytics through AI
|
|
195
|
+
- **Document Processing** — parse or summarize uploaded docs
|
|
196
|
+
- **Business Automation** — trigger internal workflows
|
|
197
|
+
- **Internal Tools** — expose secure internal logic to assistants
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🔧 CLI Reference
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
kalibr-connect examples # Copy examples
|
|
205
|
+
kalibr-connect serve my_app.py # Run locally
|
|
206
|
+
kalibr-connect version # Show version
|
|
207
|
+
kalibr-connect --help # Full CLI
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## ⚡ Key Features
|
|
213
|
+
|
|
214
|
+
✅ Multi-Model Support — GPT, Claude, Gemini, Copilot
|
|
215
|
+
✅ Automatic Schema Generation
|
|
216
|
+
✅ Environment-Aware Base URLs (v1.0.21+)
|
|
217
|
+
✅ File Uploads
|
|
218
|
+
✅ Session Management
|
|
219
|
+
✅ Streaming Responses
|
|
220
|
+
✅ Workflow Support
|
|
221
|
+
✅ Type-Safe API Generation
|
|
222
|
+
✅ Async / Await Ready
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 🔥 Why Kalibr?
|
|
227
|
+
|
|
228
|
+
Without Kalibr:
|
|
229
|
+
- Learn 4 model specs
|
|
230
|
+
- Maintain 4 codebases
|
|
231
|
+
- Duplicate effort
|
|
232
|
+
|
|
233
|
+
With Kalibr:
|
|
234
|
+
- One Python function
|
|
235
|
+
- Four schemas generated automatically
|
|
236
|
+
- Deploy anywhere
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 🆕 Version 1.0.21+
|
|
241
|
+
|
|
242
|
+
- **Automatic Base-URL Detection**
|
|
243
|
+
- Works with `KALIBR_BASE_URL` or `FLY_APP_NAME`
|
|
244
|
+
- Fixes all localhost references in deployed schemas
|
|
245
|
+
- Ready for **MCP ecosystem production use**
|
|
246
|
+
- Drop-in backwards compatibility
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 🧩 License
|
|
251
|
+
|
|
252
|
+
MIT License — see `LICENSE` file for details.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
**Kalibr SDK — the unified layer between AI models and the real world.**
|
|
257
|
+
Write once. Deploy anywhere. Integrate everything.
|
kalibr-1.0.23/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Kalibr SDK
|
|
2
|
+
### Multi-Model AI Integration Framework
|
|
3
|
+
|
|
4
|
+
**Write once. Deploy anywhere. Connect to any AI model.**
|
|
5
|
+
|
|
6
|
+
Kalibr turns Python functions into APIs that work seamlessly with GPT, Claude, Gemini, and Copilot — automatically generating model-specific schemas and endpoints.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🚀 Quick Start (2 minutes)
|
|
11
|
+
|
|
12
|
+
### 1. Install
|
|
13
|
+
```bash
|
|
14
|
+
pip install kalibr
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. Get Examples
|
|
18
|
+
```bash
|
|
19
|
+
kalibr-connect examples
|
|
20
|
+
```
|
|
21
|
+
This copies example files to `./kalibr_examples/` in your current directory.
|
|
22
|
+
|
|
23
|
+
### 3. Run Demo
|
|
24
|
+
```bash
|
|
25
|
+
kalibr-connect serve kalibr_examples/basic_kalibr_example.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 4. See All Schemas
|
|
29
|
+
Kalibr now **auto-detects your environment** and generates the correct base URLs.
|
|
30
|
+
|
|
31
|
+
| Environment | Example Base URL |
|
|
32
|
+
|--------------|------------------|
|
|
33
|
+
| Local Dev | `http://localhost:8000` |
|
|
34
|
+
| Fly.io | `https://<app-name>.fly.dev` |
|
|
35
|
+
| Custom Host | Use `KALIBR_BASE_URL` env var |
|
|
36
|
+
|
|
37
|
+
Then open:
|
|
38
|
+
```
|
|
39
|
+
<your-base-url>/gpt-actions.json # ChatGPT
|
|
40
|
+
<your-base-url>/mcp.json # Claude
|
|
41
|
+
<your-base-url>/schemas/gemini # Gemini
|
|
42
|
+
<your-base-url>/schemas/copilot # Copilot
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 🧠 What Kalibr Does
|
|
48
|
+
|
|
49
|
+
Kalibr turns your Python functions into production-ready multi-model APIs.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from kalibr import Kalibr
|
|
53
|
+
|
|
54
|
+
app = Kalibr(title="Inventory API")
|
|
55
|
+
|
|
56
|
+
@app.action("get_inventory", "Fetch inventory data")
|
|
57
|
+
def get_inventory(product_id: str):
|
|
58
|
+
return {"product_id": product_id, "stock": 42}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Result:
|
|
62
|
+
ChatGPT, Claude, Gemini, and Copilot can all call `get_inventory()` using their native protocols — no schema work required.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 💪 Two Modes
|
|
67
|
+
|
|
68
|
+
### **Function-Level (Simple)**
|
|
69
|
+
Ideal for one-off APIs or scripts.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from kalibr import Kalibr
|
|
73
|
+
|
|
74
|
+
app = Kalibr(title="My API")
|
|
75
|
+
|
|
76
|
+
@app.action("calculate_price", "Calculate price total")
|
|
77
|
+
def calculate_price(product_id: str, quantity: int):
|
|
78
|
+
return {"total": quantity * 19.99}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### **App-Level (Advanced)**
|
|
82
|
+
Use `KalibrApp` for complete control — file uploads, sessions, streaming, and workflows.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from kalibr import KalibrApp
|
|
86
|
+
from kalibr.types import FileUpload, Session
|
|
87
|
+
|
|
88
|
+
app = KalibrApp(title="Advanced API")
|
|
89
|
+
|
|
90
|
+
@app.file_handler("analyze_doc", [".pdf", ".docx"])
|
|
91
|
+
async def analyze_doc(file: FileUpload):
|
|
92
|
+
return {"filename": file.filename, "analysis": "..."}
|
|
93
|
+
|
|
94
|
+
@app.session_action("save_data", "Save session data")
|
|
95
|
+
async def save_data(session: Session, data: dict):
|
|
96
|
+
session.set("my_data", data)
|
|
97
|
+
return {"saved": True}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 📚 Examples Included
|
|
103
|
+
|
|
104
|
+
After running `kalibr-connect examples`, you’ll get:
|
|
105
|
+
|
|
106
|
+
- `basic_kalibr_example.py` – simple function-level demo
|
|
107
|
+
- `enhanced_kalibr_example.py` – full app with sessions, uploads, and streaming
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🤖 AI Platform Integration
|
|
112
|
+
|
|
113
|
+
### ChatGPT (GPT Actions)
|
|
114
|
+
1. Copy schema URL:
|
|
115
|
+
`https://<your-domain>/gpt-actions.json`
|
|
116
|
+
2. In GPT Builder → *Actions* → *Import from URL*
|
|
117
|
+
3. Done — ChatGPT can call your endpoints.
|
|
118
|
+
|
|
119
|
+
### Claude (MCP)
|
|
120
|
+
Add to Claude Desktop config:
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"mcp": {
|
|
124
|
+
"servers": {
|
|
125
|
+
"my-api": {
|
|
126
|
+
"url": "https://<your-domain>/mcp.json"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Gemini / Copilot
|
|
134
|
+
Use:
|
|
135
|
+
```
|
|
136
|
+
https://<your-domain>/schemas/gemini
|
|
137
|
+
https://<your-domain>/schemas/copilot
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 🎯 Common Use Cases
|
|
143
|
+
|
|
144
|
+
- **Customer Service APIs** — let AI handle orders or refunds
|
|
145
|
+
- **Data Analysis** — query your analytics through AI
|
|
146
|
+
- **Document Processing** — parse or summarize uploaded docs
|
|
147
|
+
- **Business Automation** — trigger internal workflows
|
|
148
|
+
- **Internal Tools** — expose secure internal logic to assistants
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 🔧 CLI Reference
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
kalibr-connect examples # Copy examples
|
|
156
|
+
kalibr-connect serve my_app.py # Run locally
|
|
157
|
+
kalibr-connect version # Show version
|
|
158
|
+
kalibr-connect --help # Full CLI
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## ⚡ Key Features
|
|
164
|
+
|
|
165
|
+
✅ Multi-Model Support — GPT, Claude, Gemini, Copilot
|
|
166
|
+
✅ Automatic Schema Generation
|
|
167
|
+
✅ Environment-Aware Base URLs (v1.0.21+)
|
|
168
|
+
✅ File Uploads
|
|
169
|
+
✅ Session Management
|
|
170
|
+
✅ Streaming Responses
|
|
171
|
+
✅ Workflow Support
|
|
172
|
+
✅ Type-Safe API Generation
|
|
173
|
+
✅ Async / Await Ready
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🔥 Why Kalibr?
|
|
178
|
+
|
|
179
|
+
Without Kalibr:
|
|
180
|
+
- Learn 4 model specs
|
|
181
|
+
- Maintain 4 codebases
|
|
182
|
+
- Duplicate effort
|
|
183
|
+
|
|
184
|
+
With Kalibr:
|
|
185
|
+
- One Python function
|
|
186
|
+
- Four schemas generated automatically
|
|
187
|
+
- Deploy anywhere
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 🆕 Version 1.0.21+
|
|
192
|
+
|
|
193
|
+
- **Automatic Base-URL Detection**
|
|
194
|
+
- Works with `KALIBR_BASE_URL` or `FLY_APP_NAME`
|
|
195
|
+
- Fixes all localhost references in deployed schemas
|
|
196
|
+
- Ready for **MCP ecosystem production use**
|
|
197
|
+
- Drop-in backwards compatibility
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 🧩 License
|
|
202
|
+
|
|
203
|
+
MIT License — see `LICENSE` file for details.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
**Kalibr SDK — the unified layer between AI models and the real world.**
|
|
208
|
+
Write once. Deploy anywhere. Integrate everything.
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
import uvicorn
|
|
3
|
+
import sys
|
|
4
|
+
import importlib.util
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import os
|
|
7
|
+
import requests
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
app = typer.Typer()
|
|
11
|
+
|
|
12
|
+
def _load_user_module(file: str):
|
|
13
|
+
file_path = Path(file).resolve()
|
|
14
|
+
if not file_path.exists():
|
|
15
|
+
print(f"❌ Error: {file} not found")
|
|
16
|
+
raise typer.Exit(1)
|
|
17
|
+
spec = importlib.util.spec_from_file_location("user_app", file_path)
|
|
18
|
+
if not spec or not spec.loader:
|
|
19
|
+
print(f"❌ Error: Could not load {file}")
|
|
20
|
+
raise typer.Exit(1)
|
|
21
|
+
module = importlib.util.module_from_spec(spec)
|
|
22
|
+
sys.modules["user_app"] = module
|
|
23
|
+
try:
|
|
24
|
+
spec.loader.exec_module(module)
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(f"❌ Error loading {file}: {e}")
|
|
27
|
+
raise typer.Exit(1)
|
|
28
|
+
return module
|
|
29
|
+
|
|
30
|
+
@app.command()
|
|
31
|
+
def serve(
|
|
32
|
+
file: str = typer.Argument("kalibr_app.py", help="Python file with Kalibr app"),
|
|
33
|
+
host: str = typer.Option("0.0.0.0", "--host", "-h"),
|
|
34
|
+
port: int = typer.Option(8000, "--port", "-p"),
|
|
35
|
+
base_url: str = typer.Option("http://localhost:8000", "--base-url", "-b"),
|
|
36
|
+
):
|
|
37
|
+
"""Serve a Kalibr-powered API locally."""
|
|
38
|
+
module = _load_user_module(file)
|
|
39
|
+
|
|
40
|
+
# Import Kalibr classes
|
|
41
|
+
from kalibr import Kalibr, KalibrApp
|
|
42
|
+
kalibr_instance = None
|
|
43
|
+
for attr_name in dir(module):
|
|
44
|
+
attr = getattr(module, attr_name)
|
|
45
|
+
if isinstance(attr, Kalibr) or (KalibrApp and isinstance(attr, KalibrApp)):
|
|
46
|
+
kalibr_instance = attr
|
|
47
|
+
kalibr_instance.base_url = base_url
|
|
48
|
+
break
|
|
49
|
+
if not kalibr_instance:
|
|
50
|
+
print(f"❌ Error: No Kalibr/KalibrApp instance found in {file}")
|
|
51
|
+
raise typer.Exit(1)
|
|
52
|
+
|
|
53
|
+
if hasattr(kalibr_instance, 'get_app'):
|
|
54
|
+
fastapi_app = kalibr_instance.get_app()
|
|
55
|
+
elif hasattr(kalibr_instance, 'app'):
|
|
56
|
+
fastapi_app = kalibr_instance.app
|
|
57
|
+
else:
|
|
58
|
+
print(f"❌ Error: Kalibr instance has no get_app() method or app attribute")
|
|
59
|
+
raise typer.Exit(1)
|
|
60
|
+
|
|
61
|
+
is_enhanced = 'KalibrApp' in str(type(kalibr_instance))
|
|
62
|
+
print(f"🚀 Starting {'Enhanced ' if is_enhanced else ''}Kalibr server from {file}")
|
|
63
|
+
print(f"📍 GPT (OpenAPI): {base_url}/openapi.json")
|
|
64
|
+
print(f"📍 Claude (MCP): {base_url}/mcp.json")
|
|
65
|
+
if is_enhanced:
|
|
66
|
+
print(f"📍 Gemini: {base_url}/schemas/gemini")
|
|
67
|
+
print(f"📍 Copilot: {base_url}/schemas/copilot")
|
|
68
|
+
print(f"📍 Supported Models: {base_url}/models/supported")
|
|
69
|
+
print(f"📍 Health Check: {base_url}/health")
|
|
70
|
+
print(f"📍 Swagger UI: {base_url}/docs")
|
|
71
|
+
print(f"🔌 Actions registered: {list(kalibr_instance.actions.keys())}")
|
|
72
|
+
|
|
73
|
+
uvicorn.run(fastapi_app, host=host, port=port)
|
|
74
|
+
|
|
75
|
+
@app.command()
|
|
76
|
+
def package(
|
|
77
|
+
app_dir: str = typer.Option(".", "--app-dir", "-d", help="Directory containing your app"),
|
|
78
|
+
output: str = typer.Option("kalibr_bundle.zip", "--output", "-o", help="Bundle file"),
|
|
79
|
+
models: str = typer.Option("mcp,gpt-actions,gemini,copilot", "--models", "-m", help="Comma-separated models supported")
|
|
80
|
+
):
|
|
81
|
+
"""Create a deployable MCP bundle (code + schemas + metadata)."""
|
|
82
|
+
from kalibr.packager import package_app
|
|
83
|
+
try:
|
|
84
|
+
models_supported = [x.strip() for x in models.split(",") if x.strip()]
|
|
85
|
+
# Version best-effort
|
|
86
|
+
try:
|
|
87
|
+
from kalibr import __version__ as kalibr_version
|
|
88
|
+
except Exception:
|
|
89
|
+
kalibr_version = "unknown"
|
|
90
|
+
bundle_path = package_app(app_dir=app_dir, output=output, models_supported=models_supported, kalibr_version=kalibr_version)
|
|
91
|
+
print(f"📦 Bundle created: {bundle_path}")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"❌ Packaging error: {e}")
|
|
94
|
+
raise typer.Exit(1)
|
|
95
|
+
|
|
96
|
+
@app.command()
|
|
97
|
+
def deploy(
|
|
98
|
+
file: str = typer.Argument(..., help="Python file to serve/deploy (e.g., kalibr_app.py)"),
|
|
99
|
+
name: str = typer.Option("", "--name", "-n", help="App name (defaults to filename)"),
|
|
100
|
+
runtime: str = typer.Option("local", "--runtime", "-r", help="Runtime: local|fly|render"),
|
|
101
|
+
host: str = typer.Option("0.0.0.0", "--host"),
|
|
102
|
+
port: int = typer.Option(8000, "--port"),
|
|
103
|
+
base_url: str = typer.Option("http://localhost:8000", "--base-url"),
|
|
104
|
+
):
|
|
105
|
+
"""Deploy via runtime router (no hosting burden on Kalibr)."""
|
|
106
|
+
from kalibr.runtime_router import deploy as router_deploy
|
|
107
|
+
file_path = Path(file)
|
|
108
|
+
if not file_path.exists():
|
|
109
|
+
print(f"❌ Error: {file} not found")
|
|
110
|
+
raise typer.Exit(1)
|
|
111
|
+
if not name:
|
|
112
|
+
name = file_path.stem.replace('_', '-').replace('.', '-')
|
|
113
|
+
try:
|
|
114
|
+
result = router_deploy(runtime=runtime, app_name=name, app_file=str(file_path), host=host, port=port, base_url=base_url)
|
|
115
|
+
if result.get("status") in ("success", "started"):
|
|
116
|
+
print("🎉 Deploy OK")
|
|
117
|
+
eps = result.get("endpoints", {})
|
|
118
|
+
if eps:
|
|
119
|
+
print("📍 Endpoints:")
|
|
120
|
+
for k, v in eps.items():
|
|
121
|
+
print(f" - {k}: {v}")
|
|
122
|
+
else:
|
|
123
|
+
print("⚠️ Deploy finished with unknown status:", result)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
print(f"❌ Deployment error: {e}")
|
|
126
|
+
raise typer.Exit(1)
|
|
127
|
+
|
|
128
|
+
@app.command()
|
|
129
|
+
def validate(
|
|
130
|
+
url: str = typer.Option("http://localhost:8000/mcp.json", "--mcp-url", help="URL to MCP manifest"),
|
|
131
|
+
):
|
|
132
|
+
"""Validate MCP manifest against minimal JSON schema & version hint."""
|
|
133
|
+
from kalibr.validator import validate_mcp_manifest
|
|
134
|
+
try:
|
|
135
|
+
resp = requests.get(url, timeout=10)
|
|
136
|
+
resp.raise_for_status()
|
|
137
|
+
manifest = resp.json()
|
|
138
|
+
validate_mcp_manifest(manifest)
|
|
139
|
+
print("✅ MCP manifest looks structurally valid.")
|
|
140
|
+
except Exception as e:
|
|
141
|
+
print(f"❌ Validation failed: {e}")
|
|
142
|
+
raise typer.Exit(1)
|
|
143
|
+
|
|
144
|
+
@app.command()
|
|
145
|
+
def update_schemas():
|
|
146
|
+
"""Stub: instruct users to upgrade SDK and regenerate manifests."""
|
|
147
|
+
from kalibr.validator import update_schemas as _upd
|
|
148
|
+
_upd()
|
|
149
|
+
|
|
150
|
+
@app.command()
|
|
151
|
+
def status(
|
|
152
|
+
app_url: str = typer.Argument(..., help="URL of deployed Kalibr app"),
|
|
153
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed information")
|
|
154
|
+
):
|
|
155
|
+
"""Check status of a deployed Kalibr app."""
|
|
156
|
+
try:
|
|
157
|
+
health_url = f"{app_url.rstrip('/')}/health"
|
|
158
|
+
response = requests.get(health_url, timeout=10)
|
|
159
|
+
if response.status_code == 200:
|
|
160
|
+
health_data = response.json()
|
|
161
|
+
print(f"✅ App is healthy at {app_url}")
|
|
162
|
+
print(f" Version: {health_data.get('version', 'unknown')}")
|
|
163
|
+
print(f" Features: {health_data.get('features', {})}")
|
|
164
|
+
if verbose:
|
|
165
|
+
schemas = ["mcp.json", "openapi.json", "schemas/gemini", "schemas/copilot"]
|
|
166
|
+
print(f"\n📊 Available AI model schemas:")
|
|
167
|
+
for schema in schemas:
|
|
168
|
+
schema_url = f"{app_url.rstrip('/')}/{schema}"
|
|
169
|
+
try:
|
|
170
|
+
schema_response = requests.get(schema_url, timeout=5)
|
|
171
|
+
status_emoji = "✅" if schema_response.status_code == 200 else "❌"
|
|
172
|
+
model_name = schema.replace(".json", "").replace("schemas/", "")
|
|
173
|
+
print(f" {status_emoji} {model_name.upper()}: {schema_url}")
|
|
174
|
+
except:
|
|
175
|
+
print(f" ❌ {schema}: Connection failed")
|
|
176
|
+
else:
|
|
177
|
+
print(f"❌ App at {app_url} is not responding (HTTP {response.status_code})")
|
|
178
|
+
raise typer.Exit(1)
|
|
179
|
+
except requests.exceptions.RequestException as e:
|
|
180
|
+
print(f"❌ Cannot connect to {app_url}: {e}")
|
|
181
|
+
raise typer.Exit(1)
|
|
182
|
+
|
|
183
|
+
@app.command()
|
|
184
|
+
def version():
|
|
185
|
+
try:
|
|
186
|
+
from kalibr import __version__
|
|
187
|
+
except (ImportError, AttributeError):
|
|
188
|
+
__version__ = "unknown"
|
|
189
|
+
print(f"Kalibr SDK version: {__version__}")
|
|
190
|
+
print("Enhanced multi-model AI integration framework")
|
|
191
|
+
print("Supports: GPT Actions, Claude MCP, Gemini Extensions, Copilot Plugins")
|
|
192
|
+
print("GitHub: https://github.com/devonakelley/kalibr-sdk")
|
|
193
|
+
|
|
194
|
+
def main():
|
|
195
|
+
config_file = Path.home() / ".kalibr" / "config.json"
|
|
196
|
+
if config_file.exists():
|
|
197
|
+
try:
|
|
198
|
+
config = json.loads(config_file.read_text())
|
|
199
|
+
if "api_token" in config and not os.environ.get("KALIBR_TOKEN"):
|
|
200
|
+
os.environ["KALIBR_TOKEN"] = config["api_token"]
|
|
201
|
+
except:
|
|
202
|
+
pass
|
|
203
|
+
app()
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Kalibr Deployment
|
|
3
|
+
-----------------
|
|
4
|
+
Thin wrapper that forwards to the runtime router.
|
|
5
|
+
Keeps a simple API surface for backwards-compat commands.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
from kalibr.runtime_router import deploy as router_deploy
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class DeploymentConfig:
|
|
15
|
+
app_name: str
|
|
16
|
+
memory_mb: int = 512
|
|
17
|
+
timeout_seconds: int = 30
|
|
18
|
+
environment_vars: Dict[str, str] = field(default_factory=dict)
|
|
19
|
+
|
|
20
|
+
def deploy_app(file_path: str, config: DeploymentConfig, platform: str = "local") -> Dict[str, Any]:
|
|
21
|
+
# Map older "platform" to runtime names used by router
|
|
22
|
+
runtime = {
|
|
23
|
+
"local": "local",
|
|
24
|
+
"fly": "fly",
|
|
25
|
+
"aws-lambda": "local", # not supported; punt to local
|
|
26
|
+
"render": "render",
|
|
27
|
+
}.get(platform, platform)
|
|
28
|
+
|
|
29
|
+
result = router_deploy(runtime=runtime, app_name=config.app_name, app_file=file_path)
|
|
30
|
+
if result.get("status") in ("success", "started"):
|
|
31
|
+
eps = result.get("endpoints", {})
|
|
32
|
+
return {
|
|
33
|
+
"status": "success",
|
|
34
|
+
"endpoints": {
|
|
35
|
+
"root": eps.get("root", ""),
|
|
36
|
+
"mcp": eps.get("mcp", ""),
|
|
37
|
+
"openapi": eps.get("openapi", ""),
|
|
38
|
+
"health": eps.get("health", ""),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {"status": "error", "error": "unknown deploy outcome", "raw": result}
|