kalibr 1.0.18__py3-none-any.whl → 1.0.20__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.
kalibr/__init__.py CHANGED
@@ -1,8 +1,7 @@
1
1
  """Kalibr SDK - Multi-Model AI Integration Framework"""
2
2
 
3
3
  from kalibr.kalibr import Kalibr
4
- # KalibrApp will be imported once it's properly implemented
5
- # from kalibr.kalibr_app import KalibrApp
4
+ from kalibr.kalibr_app import KalibrApp
6
5
 
7
- __version__ = "1.0.18"
8
- __all__ = ["Kalibr"] # "KalibrApp" will be added once implemented
6
+ __version__ = "1.0.20"
7
+ __all__ = ["Kalibr", "KalibrApp"]
kalibr/__main__.py CHANGED
@@ -48,10 +48,7 @@ def serve(
48
48
  raise typer.Exit(1)
49
49
 
50
50
  # Import Kalibr classes
51
- from kalibr import Kalibr
52
- # KalibrApp import will be enabled once it's properly implemented
53
- # from kalibr import KalibrApp
54
- KalibrApp = None # Placeholder until implemented
51
+ from kalibr import Kalibr, KalibrApp
55
52
  kalibr_instance = None
56
53
 
57
54
  # Iterate through the attributes of the loaded module
@@ -69,8 +66,14 @@ def serve(
69
66
  print(f"❌ Error: No Kalibr/KalibrApp instance found in {file}")
70
67
  raise typer.Exit(1)
71
68
 
72
- # Get the FastAPI application from the Kalibr instance
73
- fastapi_app = kalibr_instance.get_app()
69
+ # Get the FastAPI application from the Kalibr/KalibrApp instance
70
+ if hasattr(kalibr_instance, 'get_app'):
71
+ fastapi_app = kalibr_instance.get_app()
72
+ elif hasattr(kalibr_instance, 'app'):
73
+ fastapi_app = kalibr_instance.app
74
+ else:
75
+ print(f"❌ Error: Kalibr instance has no get_app() method or app attribute")
76
+ raise typer.Exit(1)
74
77
 
75
78
  # Print server information
76
79
  is_enhanced = KalibrApp is not None and isinstance(kalibr_instance, KalibrApp)
@@ -589,6 +592,60 @@ def test(
589
592
  print(f"❌ Could not connect to {url}")
590
593
  print("Make sure the Kalibr server is running")
591
594
 
595
+ @app.command()
596
+ def examples():
597
+ """Copy example files to current directory."""
598
+ import shutil
599
+ from pathlib import Path
600
+ import sys
601
+ import kalibr
602
+
603
+ # Find examples directory - check multiple possible locations
604
+ kalibr_path = Path(kalibr.__file__).parent
605
+
606
+ # Location 1: Sibling to kalibr package (development install)
607
+ examples_src = kalibr_path.parent / "examples"
608
+
609
+ # Location 2: In site-packages parent (wheel install with data_files)
610
+ if not examples_src.exists():
611
+ site_packages = Path(kalibr.__file__).parent.parent
612
+ examples_src = site_packages.parent / "examples"
613
+
614
+ # Location 3: Check sys.prefix/examples
615
+ if not examples_src.exists():
616
+ examples_src = Path(sys.prefix) / "examples"
617
+
618
+ if not examples_src.exists():
619
+ print(f"❌ Examples directory not found.")
620
+ print(f" Checked locations:")
621
+ print(f" - {kalibr_path.parent / 'examples'}")
622
+ print(f" - {Path(kalibr.__file__).parent.parent.parent / 'examples'}")
623
+ print(f" - {Path(sys.prefix) / 'examples'}")
624
+ print("This might happen if kalibr was installed without examples.")
625
+ raise typer.Exit(1)
626
+
627
+ # Copy to current directory
628
+ examples_dest = Path.cwd() / "kalibr_examples"
629
+
630
+ if examples_dest.exists():
631
+ print(f"⚠️ Directory 'kalibr_examples' already exists")
632
+ overwrite = typer.confirm("Do you want to overwrite it?")
633
+ if not overwrite:
634
+ print("Cancelled.")
635
+ raise typer.Exit(0)
636
+ shutil.rmtree(examples_dest)
637
+
638
+ shutil.copytree(examples_src, examples_dest)
639
+
640
+ print(f"✅ Examples copied to: {examples_dest}")
641
+ print(f"\n📚 Available examples:")
642
+ for example in examples_dest.glob("*.py"):
643
+ print(f" - {example.name}")
644
+
645
+ print(f"\n🚀 Try running:")
646
+ print(f" kalibr-connect serve kalibr_examples/basic_kalibr_example.py")
647
+ print(f" kalibr-connect serve kalibr_examples/enhanced_kalibr_example.py")
648
+
592
649
  @app.command()
593
650
  def version():
594
651
  """Show Kalibr version information."""
kalibr/kalibr.py CHANGED
@@ -153,65 +153,75 @@ class Kalibr:
153
153
 
154
154
  This includes:
155
155
  - A root endpoint ("/") for basic API status and available actions.
156
- - An MCP (Model Communication Protocol) manifest endpoint ("/mcp.json")
157
- for AI model integrations.
158
- - Customizes OpenAPI schema generation to include server URLs.
156
+ - Multi-model schema endpoints for all major AI platforms:
157
+ - /openapi.json (GPT Actions)
158
+ - /mcp.json (Claude MCP)
159
+ - /schemas/gemini (Google Gemini)
160
+ - /schemas/copilot (Microsoft Copilot)
159
161
  """
162
+ from kalibr.schema_generators import (
163
+ OpenAPISchemaGenerator,
164
+ MCPSchemaGenerator,
165
+ GeminiSchemaGenerator,
166
+ CopilotSchemaGenerator
167
+ )
160
168
 
161
169
  @self.app.get("/")
162
170
  def root():
163
171
  """
164
172
  Root endpoint providing API status and a list of available actions.
165
173
  """
166
- return {"message": "Kalibr API is running", "actions": list(self.actions.keys())}
174
+ return {
175
+ "message": "Kalibr API is running",
176
+ "actions": list(self.actions.keys()),
177
+ "schemas": {
178
+ "gpt_actions": f"{self.base_url}/gpt-actions.json",
179
+ "openapi_swagger": f"{self.base_url}/openapi.json",
180
+ "claude_mcp": f"{self.base_url}/mcp.json",
181
+ "gemini": f"{self.base_url}/schemas/gemini",
182
+ "copilot": f"{self.base_url}/schemas/copilot"
183
+ }
184
+ }
185
+
186
+ # Initialize schema generators
187
+ openapi_gen = OpenAPISchemaGenerator()
188
+ mcp_gen = MCPSchemaGenerator()
189
+ gemini_gen = GeminiSchemaGenerator()
190
+ copilot_gen = CopilotSchemaGenerator()
191
+
192
+ @self.app.get("/gpt-actions.json")
193
+ def gpt_actions_schema():
194
+ """
195
+ Generates OpenAPI 3.0 schema for GPT Actions integration.
196
+ (Alternative endpoint since /openapi.json is used by FastAPI)
197
+ """
198
+ return openapi_gen.generate_schema(self.actions, self.base_url)
167
199
 
168
200
  @self.app.get("/mcp.json")
169
201
  def mcp_manifest():
170
202
  """
171
- Generates the MCP manifest (Claude specific) for registered actions.
172
-
173
- This manifest describes the available tools (actions) and their input schemas
174
- in a format consumable by Claude.
203
+ Generates Claude MCP manifest for AI model integration.
175
204
  """
176
- tools = []
177
- for action_name, action_data in self.actions.items():
178
- properties = {}
179
- required = []
180
-
181
- # Construct the input schema for the tool
182
- for param_name, param_info in action_data["params"].items():
183
- properties[param_name] = {"type": param_info["type"]}
184
- if param_info["required"]:
185
- required.append(param_name)
186
-
187
- tools.append({
188
- "name": action_name,
189
- "description": action_data["description"],
190
- "input_schema": {
191
- "type": "object",
192
- "properties": properties,
193
- "required": required
194
- },
195
- # The server URL points to the proxy endpoint for this action
196
- "server": {
197
- "url": f"{self.base_url}/proxy/{action_name}"
198
- }
199
- })
200
-
201
- # Return the MCP manifest structure
202
- return {
203
- "mcp": "1.0",
204
- "name": "kalibr", # Name of the AI agent or toolset
205
- "tools": tools
206
- }
205
+ return mcp_gen.generate_schema(self.actions, self.base_url)
206
+
207
+ @self.app.get("/schemas/gemini")
208
+ def gemini_schema():
209
+ """
210
+ Generates Google Gemini Extensions schema.
211
+ """
212
+ return gemini_gen.generate_schema(self.actions, self.base_url)
213
+
214
+ @self.app.get("/schemas/copilot")
215
+ def copilot_schema():
216
+ """
217
+ Generates Microsoft Copilot plugin schema.
218
+ """
219
+ return copilot_gen.generate_schema(self.actions, self.base_url)
207
220
 
208
221
  # Override FastAPI's default OpenAPI generation to include servers configuration
209
222
  def custom_openapi():
210
223
  """
211
- Customizes the OpenAPI schema generation.
212
-
213
- Adds a 'servers' block to the OpenAPI schema, which is often required
214
- by AI model integrations (e.g., OpenAI function calling).
224
+ Customizes the OpenAPI schema generation for Swagger UI.
215
225
  """
216
226
  if self.app.openapi_schema:
217
227
  return self.app.openapi_schema