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.
Files changed (32) hide show
  1. kalibr-1.0.23/PKG-INFO +257 -0
  2. kalibr-1.0.23/README.md +208 -0
  3. kalibr-1.0.23/kalibr/__main__.py +206 -0
  4. kalibr-1.0.23/kalibr/deployment.py +41 -0
  5. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/kalibr_app.py +32 -11
  6. kalibr-1.0.23/kalibr/packager.py +43 -0
  7. kalibr-1.0.23/kalibr/runtime_router.py +138 -0
  8. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/schema_generators.py +21 -74
  9. kalibr-1.0.23/kalibr/validator.py +70 -0
  10. kalibr-1.0.23/kalibr.egg-info/PKG-INFO +257 -0
  11. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/SOURCES.txt +3 -0
  12. {kalibr-1.0.21 → kalibr-1.0.23}/pyproject.toml +1 -1
  13. {kalibr-1.0.21 → kalibr-1.0.23}/setup.py +1 -1
  14. kalibr-1.0.21/PKG-INFO +0 -302
  15. kalibr-1.0.21/README.md +0 -253
  16. kalibr-1.0.21/kalibr/__main__.py +0 -677
  17. kalibr-1.0.21/kalibr/deployment.py +0 -26
  18. kalibr-1.0.21/kalibr.egg-info/PKG-INFO +0 -302
  19. {kalibr-1.0.21 → kalibr-1.0.23}/LICENSE +0 -0
  20. {kalibr-1.0.21 → kalibr-1.0.23}/MANIFEST.in +0 -0
  21. {kalibr-1.0.21 → kalibr-1.0.23}/examples/README.md +0 -0
  22. {kalibr-1.0.21 → kalibr-1.0.23}/examples/__init__.py +0 -0
  23. {kalibr-1.0.21 → kalibr-1.0.23}/examples/basic_kalibr_example.py +0 -0
  24. {kalibr-1.0.21 → kalibr-1.0.23}/examples/enhanced_kalibr_example.py +0 -0
  25. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/__init__.py +0 -0
  26. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/kalibr.py +0 -0
  27. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr/types.py +0 -0
  28. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/dependency_links.txt +0 -0
  29. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/entry_points.txt +0 -0
  30. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/requires.txt +0 -0
  31. {kalibr-1.0.21 → kalibr-1.0.23}/kalibr.egg-info/top_level.txt +0 -0
  32. {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.
@@ -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}