kalibr 1.0.28__py3-none-any.whl → 1.1.3a0__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.
Files changed (61) hide show
  1. kalibr/__init__.py +129 -4
  2. kalibr/__main__.py +3 -203
  3. kalibr/capsule_middleware.py +108 -0
  4. kalibr/cli/__init__.py +5 -0
  5. kalibr/cli/capsule_cmd.py +174 -0
  6. kalibr/cli/deploy_cmd.py +114 -0
  7. kalibr/cli/main.py +67 -0
  8. kalibr/cli/run.py +203 -0
  9. kalibr/cli/serve.py +59 -0
  10. kalibr/client.py +293 -0
  11. kalibr/collector.py +173 -0
  12. kalibr/context.py +132 -0
  13. kalibr/cost_adapter.py +222 -0
  14. kalibr/decorators.py +140 -0
  15. kalibr/instrumentation/__init__.py +13 -0
  16. kalibr/instrumentation/anthropic_instr.py +282 -0
  17. kalibr/instrumentation/base.py +108 -0
  18. kalibr/instrumentation/google_instr.py +281 -0
  19. kalibr/instrumentation/openai_instr.py +265 -0
  20. kalibr/instrumentation/registry.py +153 -0
  21. kalibr/kalibr.py +144 -230
  22. kalibr/kalibr_app.py +53 -314
  23. kalibr/middleware/__init__.py +5 -0
  24. kalibr/middleware/auto_tracer.py +356 -0
  25. kalibr/models.py +41 -0
  26. kalibr/redaction.py +44 -0
  27. kalibr/schemas.py +116 -0
  28. kalibr/simple_tracer.py +258 -0
  29. kalibr/tokens.py +52 -0
  30. kalibr/trace_capsule.py +296 -0
  31. kalibr/trace_models.py +201 -0
  32. kalibr/tracer.py +354 -0
  33. kalibr/types.py +25 -93
  34. kalibr/utils.py +198 -0
  35. kalibr-1.1.3a0.dist-info/METADATA +236 -0
  36. kalibr-1.1.3a0.dist-info/RECORD +48 -0
  37. kalibr-1.1.3a0.dist-info/entry_points.txt +2 -0
  38. kalibr-1.1.3a0.dist-info/licenses/LICENSE +21 -0
  39. kalibr-1.1.3a0.dist-info/top_level.txt +4 -0
  40. kalibr_crewai/__init__.py +65 -0
  41. kalibr_crewai/callbacks.py +539 -0
  42. kalibr_crewai/instrumentor.py +513 -0
  43. kalibr_langchain/__init__.py +47 -0
  44. kalibr_langchain/async_callback.py +850 -0
  45. kalibr_langchain/callback.py +1064 -0
  46. kalibr_openai_agents/__init__.py +43 -0
  47. kalibr_openai_agents/processor.py +554 -0
  48. kalibr/deployment.py +0 -41
  49. kalibr/packager.py +0 -43
  50. kalibr/runtime_router.py +0 -138
  51. kalibr/schema_generators.py +0 -159
  52. kalibr/validator.py +0 -70
  53. kalibr-1.0.28.data/data/examples/README.md +0 -173
  54. kalibr-1.0.28.data/data/examples/basic_kalibr_example.py +0 -66
  55. kalibr-1.0.28.data/data/examples/enhanced_kalibr_example.py +0 -347
  56. kalibr-1.0.28.dist-info/METADATA +0 -175
  57. kalibr-1.0.28.dist-info/RECORD +0 -19
  58. kalibr-1.0.28.dist-info/entry_points.txt +0 -2
  59. kalibr-1.0.28.dist-info/licenses/LICENSE +0 -11
  60. kalibr-1.0.28.dist-info/top_level.txt +0 -1
  61. {kalibr-1.0.28.dist-info → kalibr-1.1.3a0.dist-info}/WHEEL +0 -0
kalibr/runtime_router.py DELETED
@@ -1,138 +0,0 @@
1
- """
2
- Runtime Router
3
- --------------
4
- Abstraction over deployment targets without hosting them ourselves.
5
- Generates minimal configs and invokes the target's CLI/API where possible.
6
-
7
- Supported:
8
- - local (uvicorn)
9
- - fly (fly.io) -> generates fly.toml and basic Dockerfile
10
- - render -> generates render.yaml
11
-
12
- Note: We do not ship vendor SDKs. We shell out to their CLIs if present.
13
- """
14
-
15
- from __future__ import annotations
16
- from pathlib import Path
17
- import subprocess
18
- import shutil
19
- import os
20
- import json
21
- from typing import Dict, Any, Optional, Tuple
22
-
23
- HERE = Path(__file__).parent
24
-
25
- def which(cmd: str) -> Optional[str]:
26
- return shutil.which(cmd)
27
-
28
- def ensure_file(path: Path, content: str):
29
- path.parent.mkdir(parents=True, exist_ok=True)
30
- if not path.exists():
31
- path.write_text(content)
32
-
33
- def generate_fly_files(app_name: str) -> Tuple[Path, Path]:
34
- fly_toml = Path("fly.toml")
35
- dockerfile = Path("Dockerfile")
36
- ensure_file(fly_toml, f"""# fly.toml
37
- app = "{app_name}"
38
- primary_region = "iad"
39
-
40
- [build]
41
- dockerfile = "Dockerfile"
42
-
43
- [http_service]
44
- internal_port = 8000
45
- force_https = true
46
- auto_stop_machines = "off"
47
- auto_start_machines = true
48
- min_machines_running = 1
49
- """)
50
- ensure_file(dockerfile, """# Dockerfile
51
- FROM python:3.11-slim
52
- WORKDIR /app
53
- COPY . /app
54
- RUN pip install --no-cache-dir -U pip && \
55
- pip install --no-cache-dir fastapi uvicorn typer pydantic requests
56
- EXPOSE 8000
57
- CMD ["python", "-m", "kalibr", "serve", "kalibr_app.py", "--host", "0.0.0.0", "--port", "8000", "--base-url", "http://0.0.0.0:8000"]
58
- """)
59
- return fly_toml, dockerfile
60
-
61
- def generate_render_file(service_name: str) -> Path:
62
- render_yaml = Path("render.yaml")
63
- ensure_file(render_yaml, f"""# render.yaml
64
- services:
65
- - type: web
66
- name: {service_name}
67
- env: docker
68
- plan: free
69
- dockerfilePath: ./Dockerfile
70
- autoDeploy: true
71
- """)
72
- return render_yaml
73
-
74
- def deploy_local(app_file: str, host: str = "0.0.0.0", port: int = 8000, base_url: str = "http://localhost:8000") -> Dict[str, Any]:
75
- # Run uvicorn inline (non-blocking not handled here - CLI uses this to print guidance)
76
- cmd = ["python", "-m", "kalibr", "serve", app_file, "--host", host, "--port", str(port), "--base-url", base_url]
77
- print("▶︎", " ".join(cmd))
78
- subprocess.run(cmd, check=False)
79
- return {
80
- "status": "started",
81
- "endpoints": {
82
- "root": f"{base_url}/",
83
- "mcp": f"{base_url}/mcp.json",
84
- "openapi": f"{base_url}/openapi.json",
85
- "health": f"{base_url}/health"
86
- }
87
- }
88
-
89
- def deploy_fly(app_name: str) -> Dict[str, Any]:
90
- if not which("flyctl"):
91
- raise RuntimeError("flyctl is not installed. See https://fly.io/docs/flyctl/install/")
92
- # Ensure files exist
93
- generate_fly_files(app_name)
94
- # Launch or deploy
95
- print("▶︎ flyctl apps list")
96
- subprocess.run(["flyctl", "apps", "list"], check=False)
97
- print(f"▶︎ flyctl deploy --app {app_name}")
98
- subprocess.run(["flyctl", "deploy", "--app", app_name], check=False)
99
- url = f"https://{app_name}.fly.dev"
100
- return {
101
- "status": "success",
102
- "endpoints": {
103
- "root": f"{url}/",
104
- "mcp": f"{url}/mcp.json",
105
- "openapi": f"{url}/openapi.json",
106
- "health": f"{url}/health"
107
- }
108
- }
109
-
110
- def deploy_render(service_name: str) -> Dict[str, Any]:
111
- # We just generate render.yaml and Dockerfile. User connects repo in Render UI.
112
- generate_render_file(service_name)
113
- ensure_file(Path("Dockerfile"), """# Dockerfile for Render
114
- FROM python:3.11-slim
115
- WORKDIR /app
116
- COPY . /app
117
- RUN pip install --no-cache-dir -U pip && \
118
- pip install --no-cache-dir fastapi uvicorn typer pydantic requests
119
- EXPOSE 8000
120
- CMD ["python", "-m", "kalibr", "serve", "kalibr_app.py", "--host", "0.0.0.0", "--port", "8000", "--base-url", "https://$RENDER_EXTERNAL_URL"]
121
- """)
122
- print("📄 Generated render.yaml and Dockerfile. Connect your repo in Render.com and auto-deploy.")
123
- return {
124
- "status": "success",
125
- "endpoints": {},
126
- "note": "Connect this repository to Render; it will build from render.yaml."
127
- }
128
-
129
- def deploy(runtime: str, app_name: str, app_file: str, host: str = "0.0.0.0", port: int = 8000, base_url: str = "http://localhost:8000") -> Dict[str, Any]:
130
- runtime = runtime.lower()
131
- if runtime in ("local", "dev"):
132
- return deploy_local(app_file, host, port, base_url)
133
- if runtime in ("fly", "flyio"):
134
- return deploy_fly(app_name)
135
- if runtime == "render":
136
- return deploy_render(app_name)
137
- raise ValueError(f"Unknown runtime: {runtime}")
138
-
@@ -1,159 +0,0 @@
1
- """
2
- Multi-model schema generators for different AI platforms
3
- """
4
- from typing import Dict, Any, List
5
- from abc import ABC, abstractmethod
6
-
7
- KALIBR_TITLE = "Kalibr Enhanced API"
8
- KALIBR_VERSION = "2.0.0"
9
- MCP_SPEC_VERSION = "1.0" # bump via validator when MCP evolves
10
-
11
- class BaseSchemaGenerator(ABC):
12
- """Base class for AI model schema generators"""
13
- @abstractmethod
14
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
15
- pass
16
-
17
- class MCPSchemaGenerator(BaseSchemaGenerator):
18
- """Claude/GPT-AgentBuilder MCP schema generator"""
19
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
20
- tools = []
21
- for action_name, action_data in actions.items():
22
- properties = {}
23
- required = []
24
- for param_name, param_info in action_data["params"].items():
25
- properties[param_name] = {"type": param_info["type"]}
26
- if param_info["required"]:
27
- required.append(param_name)
28
- tools.append({
29
- "name": action_name,
30
- "description": action_data["description"],
31
- "input_schema": {
32
- "type": "object",
33
- "properties": properties,
34
- "required": required
35
- },
36
- "server": {"url": f"{base_url}/proxy/{action_name}"}
37
- })
38
- return {
39
- "mcp": MCP_SPEC_VERSION,
40
- "name": "kalibr-enhanced",
41
- "tools": tools
42
- }
43
-
44
- class OpenAPISchemaGenerator(BaseSchemaGenerator):
45
- """GPT Actions OpenAPI schema generator (legacy but still useful)"""
46
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
47
- paths = {}
48
- for action_name, action_data in actions.items():
49
- properties = {}
50
- required = []
51
- for param_name, param_info in action_data["params"].items():
52
- properties[param_name] = {"type": param_info["type"]}
53
- if param_info["required"]:
54
- required.append(param_name)
55
- paths[f"/proxy/{action_name}"] = {
56
- "post": {
57
- "summary": action_data["description"],
58
- "operationId": action_name,
59
- "requestBody": {
60
- "required": True,
61
- "content": {
62
- "application/json": {
63
- "schema": {
64
- "type": "object",
65
- "properties": properties,
66
- "required": required
67
- }
68
- }
69
- }
70
- },
71
- "responses": {
72
- "200": {
73
- "description": "Successful response",
74
- "content": {"application/json": {"schema": {"type": "object"}}}
75
- }
76
- }
77
- }
78
- }
79
- return {
80
- "openapi": "3.0.0",
81
- "info": {"title": KALIBR_TITLE, "version": KALIBR_VERSION, "description": "Enhanced Kalibr API"},
82
- "servers": [{"url": base_url}],
83
- "paths": paths
84
- }
85
-
86
- class GeminiSchemaGenerator(BaseSchemaGenerator):
87
- """Google Gemini Extensions schema generator"""
88
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
89
- functions = []
90
- for action_name, action_data in actions.items():
91
- parameters = {"type": "object", "properties": {}, "required": []}
92
- for param_name, param_info in action_data["params"].items():
93
- parameters["properties"][param_name] = {"type": param_info["type"], "description": f"Parameter {param_name}"}
94
- if param_info["required"]:
95
- parameters["required"].append(param_name)
96
- functions.append({
97
- "name": action_name,
98
- "description": action_data["description"],
99
- "parameters": parameters,
100
- "server": {"url": f"{base_url}/proxy/{action_name}"}
101
- })
102
- return {
103
- "gemini_extension": "1.0",
104
- "name": "kalibr_enhanced",
105
- "description": "Enhanced Kalibr API for Gemini integration",
106
- "functions": functions
107
- }
108
-
109
- class CopilotSchemaGenerator(BaseSchemaGenerator):
110
- """Microsoft Copilot plugin schema generator (transitional)"""
111
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
112
- apis = []
113
- for action_name, action_data in actions.items():
114
- request_schema = {"type": "object", "properties": {}, "required": []}
115
- for param_name, param_info in action_data["params"].items():
116
- request_schema["properties"][param_name] = {"type": param_info["type"]}
117
- if param_info["required"]:
118
- request_schema["required"].append(param_name)
119
- apis.append({
120
- "name": action_name,
121
- "description": action_data["description"],
122
- "url": f"{base_url}/proxy/{action_name}",
123
- "method": "POST",
124
- "request_schema": request_schema,
125
- "response_schema": {"type": "object", "description": "API response"}
126
- })
127
- return {
128
- "schema_version": "v1",
129
- "name_for_model": "kalibr_enhanced",
130
- "name_for_human": "Enhanced Kalibr API",
131
- "description_for_model": "Enhanced Kalibr API with advanced capabilities",
132
- "description_for_human": "API for advanced AI model integrations",
133
- "auth": {"type": "none"},
134
- "api": {"type": "openapi", "url": f"{base_url}/openapi.json"},
135
- "apis": apis
136
- }
137
-
138
- class CustomModelSchemaGenerator(BaseSchemaGenerator):
139
- """Extensible generator for future AI models"""
140
- def __init__(self, model_name: str, schema_format: str):
141
- self.model_name = model_name
142
- self.schema_format = schema_format
143
-
144
- def generate_schema(self, actions: Dict, base_url: str) -> Dict[str, Any]:
145
- return {
146
- "model": self.model_name,
147
- "format": self.schema_format,
148
- "version": KALIBR_VERSION,
149
- "base_url": base_url,
150
- "actions": [
151
- {
152
- "name": name,
153
- "description": data["description"],
154
- "parameters": data["params"],
155
- "endpoint": f"{base_url}/proxy/{name}"
156
- }
157
- for name, data in actions.items()
158
- ]
159
- }
kalibr/validator.py DELETED
@@ -1,70 +0,0 @@
1
- """
2
- Validator
3
- ---------
4
- - Validates MCP manifest structure (lightweight JSONSchema)
5
- - Detects spec drift (compares manifest version vs. embedded known latest)
6
- - Provides 'update-schemas' hook (stub here; can fetch from GH in future)
7
-
8
- Note: We keep it offline-safe. You can later wire network fetch if desired.
9
- """
10
-
11
- from __future__ import annotations
12
- from typing import Dict, Any
13
- import json
14
- from jsonschema import validate, Draft7Validator
15
-
16
- # Minimal MCP JSON schema (aligned with your generator shape)
17
- MCP_SCHEMA = {
18
- "type": "object",
19
- "required": ["mcp", "name", "tools"],
20
- "properties": {
21
- "mcp": {"type": "string"},
22
- "name": {"type": "string"},
23
- "tools": {
24
- "type": "array",
25
- "items": {
26
- "type": "object",
27
- "required": ["name", "description", "input_schema", "server"],
28
- "properties": {
29
- "name": {"type": "string"},
30
- "description": {"type": "string"},
31
- "input_schema": {
32
- "type": "object",
33
- "required": ["type", "properties"],
34
- "properties": {
35
- "type": {"type": "string"},
36
- "properties": {"type": "object"},
37
- "required": {"type": "array", "items": {"type": "string"}}
38
- }
39
- },
40
- "server": {
41
- "type": "object",
42
- "required": ["url"],
43
- "properties": {"url": {"type": "string"}}
44
- }
45
- }
46
- }
47
- }
48
- }
49
- }
50
-
51
- LATEST_MCP_SPEC_VERSION = "1.0" # bump here as spec evolves
52
-
53
- def validate_mcp_manifest(manifest: Dict[str, Any]) -> None:
54
- # Structural validation
55
- validate(instance=manifest, schema=MCP_SCHEMA)
56
- # Version guidance
57
- version = str(manifest.get("mcp", ""))
58
- if version != LATEST_MCP_SPEC_VERSION:
59
- print(f"⚠️ MCP spec version in manifest is '{version}'. Latest known is '{LATEST_MCP_SPEC_VERSION}'.")
60
- print(" Run `kalibr update-schemas` after updating the SDK, or regenerate the manifest.")
61
-
62
- def update_schemas() -> None:
63
- """
64
- Stub: In a connected environment, fetch updated schema templates.
65
- Here, we simply print guidance so the CLI can expose the command now.
66
- """
67
- print("🔄 Update schemas (stub):")
68
- print(" - Upgrade kalibr SDK to latest version: pip install -U kalibr")
69
- print(" - Re-run manifest generation to pick up spec changes.")
70
-
@@ -1,173 +0,0 @@
1
- # Enhanced Kalibr SDK Examples
2
-
3
- This directory contains examples demonstrating both the original function-level Kalibr capabilities and the new enhanced app-level features.
4
-
5
- ## Examples Included
6
-
7
- ### 1. Basic Kalibr Example (`basic_kalibr_example.py`)
8
- Demonstrates the original Kalibr SDK capabilities:
9
- - Simple function decoration with `@sdk.action()`
10
- - Basic parameter handling and type inference
11
- - Compatible with GPT Actions and Claude MCP
12
- - Simple API endpoints
13
-
14
- **Features shown:**
15
- - Text processing functions
16
- - Mathematical calculations
17
- - Email validation
18
- - Text statistics
19
-
20
- **To run:**
21
- ```bash
22
- kalibr serve basic_kalibr_example.py
23
- ```
24
-
25
- **Test endpoints:**
26
- - `POST /proxy/greet` - Greeting function
27
- - `POST /proxy/calculate` - Basic calculator
28
- - `POST /proxy/validate_email` - Email validation
29
- - `POST /proxy/text_stats` - Text analysis
30
-
31
- ### 2. Enhanced Kalibr Example (`enhanced_kalibr_example.py`)
32
- Demonstrates the new enhanced app-level capabilities:
33
- - File upload handling
34
- - Session management
35
- - Streaming responses
36
- - Complex workflows
37
- - Multi-model schema generation
38
-
39
- **Features shown:**
40
- - File upload and analysis
41
- - Session-based note taking
42
- - Real-time streaming data
43
- - Multi-step workflows
44
- - Advanced parameter handling
45
-
46
- **To run:**
47
- ```bash
48
- kalibr serve enhanced_kalibr_example.py --app-mode
49
- ```
50
-
51
- **Test endpoints:**
52
- - `POST /upload/analyze_document` - File upload analysis
53
- - `POST /session/save_note` - Session-based note saving
54
- - `GET /stream/count_with_progress` - Streaming counter
55
- - `POST /workflow/process_text_analysis` - Complex text workflow
56
-
57
- ## Multi-Model Integration
58
-
59
- Both examples automatically generate schemas for multiple AI models:
60
-
61
- ### Available Schema Endpoints:
62
- - **Claude MCP**: `/mcp.json`
63
- - **GPT Actions**: `/openapi.json`
64
- - **Gemini Extensions**: `/schemas/gemini`
65
- - **Microsoft Copilot**: `/schemas/copilot`
66
-
67
- ### Management Endpoints:
68
- - **Health Check**: `/health`
69
- - **Supported Models**: `/models/supported`
70
- - **API Documentation**: `/docs`
71
-
72
- ## Usage Examples
73
-
74
- ### Basic Function Call:
75
- ```bash
76
- curl -X POST http://localhost:8000/proxy/greet \
77
- -H "Content-Type: application/json" \
78
- -d '{"name": "Alice", "greeting": "Hi"}'
79
- ```
80
-
81
- ### File Upload:
82
- ```bash
83
- curl -X POST http://localhost:8000/upload/analyze_document \
84
- -F "file=@example.txt"
85
- ```
86
-
87
- ### Session Management:
88
- ```bash
89
- # Save a note (creates session)
90
- curl -X POST http://localhost:8000/session/save_note \
91
- -H "Content-Type: application/json" \
92
- -d '{"note_title": "My Note", "note_content": "This is a test note"}'
93
-
94
- # Get notes (use session ID from previous response)
95
- curl -X POST http://localhost:8000/session/get_notes \
96
- -H "Content-Type: application/json" \
97
- -H "x-session-id: <session-id-here>" \
98
- -d '{}'
99
- ```
100
-
101
- ### Streaming Data:
102
- ```bash
103
- curl http://localhost:8000/stream/count_with_progress?max_count=5&delay_seconds=1
104
- ```
105
-
106
- ### Complex Workflow:
107
- ```bash
108
- curl -X POST http://localhost:8000/workflow/process_text_analysis \
109
- -H "Content-Type: application/json" \
110
- -d '{"text": "This is a sample text for analysis. It contains multiple sentences and words for testing the workflow capabilities."}'
111
- ```
112
-
113
- ## Integration with AI Models
114
-
115
- ### GPT Actions Setup:
116
- 1. Copy the OpenAPI schema from `/openapi.json`
117
- 2. Create a new GPT Action in ChatGPT
118
- 3. Paste the schema and set the base URL
119
-
120
- ### Claude MCP Setup:
121
- 1. Add the MCP server configuration:
122
- ```json
123
- {
124
- "mcp": {
125
- "servers": {
126
- "kalibr": {
127
- "command": "curl",
128
- "args": ["http://localhost:8000/mcp.json"]
129
- }
130
- }
131
- }
132
- }
133
- ```
134
-
135
- ### Gemini Extensions:
136
- 1. Use the schema from `/schemas/gemini`
137
- 2. Configure according to Gemini's extension documentation
138
-
139
- ### Microsoft Copilot:
140
- 1. Use the schema from `/schemas/copilot`
141
- 2. Follow Microsoft's plugin development guidelines
142
-
143
- ## Advanced Features
144
-
145
- ### Authentication (Optional):
146
- Uncomment the authentication line in enhanced example:
147
- ```python
148
- app.enable_auth("your-secret-jwt-key-here")
149
- ```
150
-
151
- ### Custom Schema Generation:
152
- The framework supports extensible schema generation for future AI models through the `CustomModelSchemaGenerator` class.
153
-
154
- ### Error Handling:
155
- All endpoints include comprehensive error handling with meaningful error messages.
156
-
157
- ### Type Safety:
158
- Full support for Python type hints with automatic schema generation.
159
-
160
- ## Development Notes
161
-
162
- - The enhanced framework is backward compatible with original Kalibr apps
163
- - Session data is stored in memory (use external storage for production)
164
- - File uploads are handled in memory (implement persistent storage as needed)
165
- - Streaming uses Server-Sent Events (SSE) format
166
- - All examples include proper async/await handling where needed
167
-
168
- ## Next Steps
169
-
170
- 1. Try the examples with different AI models
171
- 2. Modify the examples to fit your specific use case
172
- 3. Explore the source code in `/app/backend/kalibr/` for advanced customization
173
- 4. Build your own enhanced Kalibr applications!
@@ -1,66 +0,0 @@
1
- """
2
- Basic Kalibr SDK Example - Function-level API integration
3
- This demonstrates the original function-level capabilities of Kalibr.
4
- """
5
-
6
- from kalibr import Kalibr
7
-
8
- # Create a basic Kalibr instance
9
- sdk = Kalibr(title="Basic Kalibr Demo", base_url="http://localhost:8000")
10
-
11
- @sdk.action("greet", "Greet someone with a personalized message")
12
- def greet_user(name: str, greeting: str = "Hello"):
13
- """Simple greeting function"""
14
- return {"message": f"{greeting}, {name}! Welcome to Kalibr SDK."}
15
-
16
- @sdk.action("calculate", "Perform basic mathematical operations")
17
- def calculate(operation: str, a: float, b: float):
18
- """Basic calculator functionality"""
19
- operations = {
20
- "add": a + b,
21
- "subtract": a - b,
22
- "multiply": a * b,
23
- "divide": a / b if b != 0 else None
24
- }
25
-
26
- result = operations.get(operation)
27
- if result is None:
28
- return {"error": f"Invalid operation '{operation}' or division by zero"}
29
-
30
- return {
31
- "operation": operation,
32
- "operands": [a, b],
33
- "result": result
34
- }
35
-
36
- @sdk.action("validate_email", "Check if an email address is valid")
37
- def validate_email(email: str):
38
- """Simple email validation"""
39
- import re
40
-
41
- pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
42
- is_valid = bool(re.match(pattern, email))
43
-
44
- return {
45
- "email": email,
46
- "is_valid": is_valid,
47
- "message": "Valid email address" if is_valid else "Invalid email format"
48
- }
49
-
50
- @sdk.action("text_stats", "Get statistics about a text string")
51
- def text_statistics(text: str):
52
- """Analyze text and return statistics"""
53
- words = text.split()
54
- sentences = text.split('.') + text.split('!') + text.split('?')
55
- sentences = [s.strip() for s in sentences if s.strip()]
56
-
57
- return {
58
- "character_count": len(text),
59
- "word_count": len(words),
60
- "sentence_count": len(sentences),
61
- "average_word_length": sum(len(word) for word in words) / len(words) if words else 0,
62
- "longest_word": max(words, key=len) if words else None
63
- }
64
-
65
- # The SDK instance is automatically discovered by the Kalibr CLI
66
- # To run this: kalibr serve basic_kalibr_example.py