optimizely-opal.opal-tools-sdk 0.1.4.dev0__py3-none-any.whl → 0.1.5.dev0__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.
Potentially problematic release.
This version of optimizely-opal.opal-tools-sdk might be problematic. Click here for more details.
- opal_tools_sdk/__init__.py +14 -1
- opal_tools_sdk/models.py +70 -13
- optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info/METADATA +253 -0
- {optimizely_opal_opal_tools_sdk-0.1.4.dev0.dist-info → optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info}/RECORD +6 -6
- optimizely_opal_opal_tools_sdk-0.1.4.dev0.dist-info/METADATA +0 -138
- {optimizely_opal_opal_tools_sdk-0.1.4.dev0.dist-info → optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info}/WHEEL +0 -0
- {optimizely_opal_opal_tools_sdk-0.1.4.dev0.dist-info → optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info}/top_level.txt +0 -0
opal_tools_sdk/__init__.py
CHANGED
|
@@ -2,6 +2,19 @@ from .service import ToolsService
|
|
|
2
2
|
from .decorators import tool
|
|
3
3
|
from .auth import requires_auth
|
|
4
4
|
from .logging import register_logger_factory
|
|
5
|
+
from .models import AuthData, AuthRequirement, Credentials, Environment, IslandConfig, IslandResponse
|
|
5
6
|
|
|
6
7
|
__version__ = "0.1.0"
|
|
7
|
-
__all__ = [
|
|
8
|
+
__all__ = [
|
|
9
|
+
"ToolsService",
|
|
10
|
+
"tool",
|
|
11
|
+
"requires_auth",
|
|
12
|
+
"register_logger_factory",
|
|
13
|
+
# Models
|
|
14
|
+
"AuthData",
|
|
15
|
+
"AuthRequirement",
|
|
16
|
+
"Credentials",
|
|
17
|
+
"Environment",
|
|
18
|
+
"IslandConfig",
|
|
19
|
+
"IslandResponse",
|
|
20
|
+
]
|
opal_tools_sdk/models.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import List, Dict, Any, Optional
|
|
2
|
+
from typing import List, Dict, Any, Optional, Literal, TypedDict
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
class ParameterType(str, Enum):
|
|
6
9
|
"""Types of parameters supported by Opal tools."""
|
|
10
|
+
|
|
7
11
|
string = "string"
|
|
8
12
|
integer = "integer"
|
|
9
13
|
number = "number"
|
|
@@ -11,9 +15,11 @@ class ParameterType(str, Enum):
|
|
|
11
15
|
list = "array" # Changed to match main service expectation
|
|
12
16
|
dictionary = "object" # Standard JSON schema type
|
|
13
17
|
|
|
18
|
+
|
|
14
19
|
@dataclass
|
|
15
20
|
class Parameter:
|
|
16
21
|
"""Parameter definition for an Opal tool."""
|
|
22
|
+
|
|
17
23
|
name: str
|
|
18
24
|
param_type: ParameterType
|
|
19
25
|
description: str
|
|
@@ -21,31 +27,49 @@ class Parameter:
|
|
|
21
27
|
|
|
22
28
|
def to_dict(self) -> Dict[str, Any]:
|
|
23
29
|
"""Convert to dictionary for the discovery endpoint."""
|
|
24
|
-
return {
|
|
25
|
-
|
|
26
|
-
"type": self.param_type.value,
|
|
27
|
-
"description": self.description,
|
|
28
|
-
"required": self.required
|
|
29
|
-
}
|
|
30
|
+
return {"name": self.name, "type": self.param_type.value, "description": self.description, "required": self.required}
|
|
31
|
+
|
|
30
32
|
|
|
31
33
|
@dataclass
|
|
32
34
|
class AuthRequirement:
|
|
33
35
|
"""Authentication requirements for an Opal tool."""
|
|
36
|
+
|
|
34
37
|
provider: str # e.g., "google", "microsoft"
|
|
35
38
|
scope_bundle: str # e.g., "calendar", "drive"
|
|
36
39
|
required: bool = True
|
|
37
40
|
|
|
38
41
|
def to_dict(self) -> Dict[str, Any]:
|
|
39
42
|
"""Convert to dictionary for the discovery endpoint."""
|
|
40
|
-
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
return {"provider": self.provider, "scope_bundle": self.scope_bundle, "required": self.required}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Credentials(TypedDict):
|
|
47
|
+
"""AuthData credentials."""
|
|
48
|
+
|
|
49
|
+
access_token: str
|
|
50
|
+
org_sso_id: Optional[str]
|
|
51
|
+
customer_id: str
|
|
52
|
+
instance_id: str
|
|
53
|
+
product_sku: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class AuthData(TypedDict):
|
|
57
|
+
"""Authentication data for an Opal tool."""
|
|
58
|
+
|
|
59
|
+
provider: str
|
|
60
|
+
credentials: Credentials
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Environment(TypedDict):
|
|
64
|
+
"""Execution environment for an Opal tool. Interactive will provide interaction islands, while headless will not."""
|
|
65
|
+
|
|
66
|
+
execution_mode: Literal["headless", "interactive"]
|
|
67
|
+
|
|
45
68
|
|
|
46
69
|
@dataclass
|
|
47
70
|
class Function:
|
|
48
71
|
"""Function definition for an Opal tool."""
|
|
72
|
+
|
|
49
73
|
name: str
|
|
50
74
|
description: str
|
|
51
75
|
parameters: List[Parameter]
|
|
@@ -60,10 +84,43 @@ class Function:
|
|
|
60
84
|
"description": self.description,
|
|
61
85
|
"parameters": [p.to_dict() for p in self.parameters],
|
|
62
86
|
"endpoint": self.endpoint,
|
|
63
|
-
"http_method": self.http_method
|
|
87
|
+
"http_method": self.http_method,
|
|
64
88
|
}
|
|
65
89
|
|
|
66
90
|
if self.auth_requirements:
|
|
67
91
|
result["auth_requirements"] = [auth.to_dict() for auth in self.auth_requirements]
|
|
68
92
|
|
|
69
93
|
return result
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Interaction island related classes
|
|
97
|
+
class IslandConfig(BaseModel):
|
|
98
|
+
class Field(BaseModel):
|
|
99
|
+
name: str
|
|
100
|
+
label: str
|
|
101
|
+
type: Literal["string", "boolean", "json"]
|
|
102
|
+
value: str = Field(default="")
|
|
103
|
+
hidden: bool = Field(default=False)
|
|
104
|
+
options: list[str] = Field(default=[])
|
|
105
|
+
|
|
106
|
+
class Action(BaseModel):
|
|
107
|
+
name: str
|
|
108
|
+
label: str
|
|
109
|
+
type: str
|
|
110
|
+
endpoint: str
|
|
111
|
+
operation: str = Field(default="create")
|
|
112
|
+
|
|
113
|
+
fields: list[Field]
|
|
114
|
+
actions: list[Action]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class IslandResponse(BaseModel):
|
|
118
|
+
class ResponseConfig(BaseModel):
|
|
119
|
+
islands: list[IslandConfig]
|
|
120
|
+
|
|
121
|
+
type: Literal["island"]
|
|
122
|
+
config: ResponseConfig
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
def create(cls, islands: list[IslandConfig]):
|
|
126
|
+
return cls(type="island", config=cls.ResponseConfig(islands=islands))
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: optimizely-opal.opal-tools-sdk
|
|
3
|
+
Version: 0.1.5.dev0
|
|
4
|
+
Summary: SDK for creating Opal-compatible tools services
|
|
5
|
+
Home-page: https://github.com/optimizely/opal-tools-sdk
|
|
6
|
+
Author: Optimizely
|
|
7
|
+
Author-email: Optimizely <opal-team@optimizely.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/optimizely/opal-tools-sdk
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/optimizely/opal-tools-sdk/issues
|
|
11
|
+
Keywords: opal,tools,sdk,ai,llm
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: fastapi>=0.100.0
|
|
19
|
+
Requires-Dist: pydantic>=2.0.0
|
|
20
|
+
Requires-Dist: httpx>=0.24.1
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
|
|
25
|
+
# Opal Tools SDK for Python
|
|
26
|
+
|
|
27
|
+
This SDK simplifies the creation of tools services compatible with the Opal Tools Management Service.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Easy definition of tool functions with decorators
|
|
32
|
+
- Automatic generation of discovery endpoints
|
|
33
|
+
- Parameter validation and type checking
|
|
34
|
+
- Authentication helpers
|
|
35
|
+
- FastAPI integration
|
|
36
|
+
- Island components for interactive UI responses
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install optimizely-opal.opal-tools-sdk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Note: While the package is installed as `optimizely-opal.opal-tools-sdk`, you'll still import it in your code as `opal_tools_sdk`:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# Import using the package name
|
|
48
|
+
from opal_tools_sdk import ToolsService, tool, IslandResponse, IslandConfig
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from opal_tools_sdk import ToolsService, tool
|
|
55
|
+
from pydantic import BaseModel
|
|
56
|
+
from fastapi import FastAPI
|
|
57
|
+
|
|
58
|
+
app = FastAPI()
|
|
59
|
+
tools_service = ToolsService(app)
|
|
60
|
+
|
|
61
|
+
class WeatherParameters(BaseModel):
|
|
62
|
+
location: str
|
|
63
|
+
units: str = "metric"
|
|
64
|
+
|
|
65
|
+
@tool("get_weather", "Gets current weather for a location")
|
|
66
|
+
async def get_weather(parameters: WeatherParameters):
|
|
67
|
+
# Implementation...
|
|
68
|
+
return {"temperature": 22, "condition": "sunny"}
|
|
69
|
+
|
|
70
|
+
# Discovery endpoint is automatically created at /discovery
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Authentication
|
|
74
|
+
|
|
75
|
+
The SDK provides two ways to require authentication for your tools:
|
|
76
|
+
|
|
77
|
+
### 1. Using the `@requires_auth` decorator
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from opal_tools_sdk import ToolsService, tool, AuthData
|
|
81
|
+
from opal_tools_sdk.auth import requires_auth
|
|
82
|
+
from pydantic import BaseModel
|
|
83
|
+
from fastapi import FastAPI
|
|
84
|
+
from typing import Optional
|
|
85
|
+
|
|
86
|
+
app = FastAPI()
|
|
87
|
+
tools_service = ToolsService(app)
|
|
88
|
+
|
|
89
|
+
class CalendarParameters(BaseModel):
|
|
90
|
+
date: str
|
|
91
|
+
timezone: str = "UTC"
|
|
92
|
+
|
|
93
|
+
# Single authentication requirement
|
|
94
|
+
@requires_auth(provider="google", scope_bundle="calendar", required=True)
|
|
95
|
+
@tool("get_calendar_events", "Gets calendar events for a date")
|
|
96
|
+
async def get_calendar_events(parameters: CalendarParameters, auth_data: Optional[AuthData] = None):
|
|
97
|
+
# The auth_data parameter contains authentication information
|
|
98
|
+
if auth_data:
|
|
99
|
+
token = auth_data["credentials"]["access_token"]
|
|
100
|
+
|
|
101
|
+
# Use the token to make authenticated requests
|
|
102
|
+
# ...
|
|
103
|
+
|
|
104
|
+
return {"events": ["Meeting at 10:00", "Lunch at 12:00"]}
|
|
105
|
+
|
|
106
|
+
# Multiple authentication requirements (tool can work with either provider)
|
|
107
|
+
@requires_auth(provider="google", scope_bundle="calendar", required=True)
|
|
108
|
+
@requires_auth(provider="microsoft", scope_bundle="outlook", required=True)
|
|
109
|
+
@tool("get_calendar_availability", "Check calendar availability")
|
|
110
|
+
async def get_calendar_availability(parameters: CalendarParameters, auth_data: Optional[AuthData] = None):
|
|
111
|
+
provider = ""
|
|
112
|
+
token = ""
|
|
113
|
+
|
|
114
|
+
if auth_data:
|
|
115
|
+
provider = auth_data["provider"]
|
|
116
|
+
token = auth_data["credentials"]["access_token"]
|
|
117
|
+
|
|
118
|
+
if provider == "google":
|
|
119
|
+
# Use Google Calendar API
|
|
120
|
+
pass
|
|
121
|
+
elif provider == "microsoft":
|
|
122
|
+
# Use Microsoft Outlook API
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
return {"available": True, "provider_used": provider}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 2. Specifying auth requirements in the `@tool` decorator
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
@tool(
|
|
132
|
+
"get_email",
|
|
133
|
+
"Gets emails from the user's inbox",
|
|
134
|
+
auth_requirements=[
|
|
135
|
+
{"provider": "google", "scope_bundle": "gmail", "required": True}
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
async def get_email(parameters: EmailParameters, auth_data: Optional[AuthData] = None):
|
|
139
|
+
# Implementation...
|
|
140
|
+
return {"emails": ["Email 1", "Email 2"]}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Island Components
|
|
144
|
+
|
|
145
|
+
The SDK includes Island components for creating interactive UI responses that allow users to input data and trigger actions.
|
|
146
|
+
|
|
147
|
+
### Weather Tool with Interactive Island
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from opal_tools_sdk import ToolsService, tool, IslandResponse, IslandConfig
|
|
151
|
+
from pydantic import BaseModel
|
|
152
|
+
from fastapi import FastAPI
|
|
153
|
+
|
|
154
|
+
app = FastAPI()
|
|
155
|
+
tools_service = ToolsService(app)
|
|
156
|
+
|
|
157
|
+
class WeatherParameters(BaseModel):
|
|
158
|
+
location: str
|
|
159
|
+
units: str = "metric"
|
|
160
|
+
|
|
161
|
+
@tool("get_weather", "Gets current weather for a location")
|
|
162
|
+
async def get_weather(parameters: WeatherParameters):
|
|
163
|
+
# Get weather data (implementation details omitted)
|
|
164
|
+
weather_data = {"temperature": 22, "condition": "sunny", "humidity": 65}
|
|
165
|
+
|
|
166
|
+
# Create an interactive island for weather settings
|
|
167
|
+
island = IslandConfig(
|
|
168
|
+
fields=[
|
|
169
|
+
IslandConfig.Field(
|
|
170
|
+
name="location",
|
|
171
|
+
label="Location",
|
|
172
|
+
type="string",
|
|
173
|
+
value=parameters.location
|
|
174
|
+
),
|
|
175
|
+
IslandConfig.Field(
|
|
176
|
+
name="units",
|
|
177
|
+
label="Temperature Units",
|
|
178
|
+
type="string",
|
|
179
|
+
value=parameters.units,
|
|
180
|
+
options=["metric", "imperial", "kelvin"]
|
|
181
|
+
),
|
|
182
|
+
IslandConfig.Field(
|
|
183
|
+
name="current_temp",
|
|
184
|
+
label="Current Temperature",
|
|
185
|
+
type="string",
|
|
186
|
+
value=f"{weather_data['temperature']}°{'C' if parameters.units == 'metric' else 'F'}"
|
|
187
|
+
)
|
|
188
|
+
],
|
|
189
|
+
actions=[
|
|
190
|
+
IslandConfig.Action(
|
|
191
|
+
name="refresh_weather",
|
|
192
|
+
label="Refresh Weather",
|
|
193
|
+
type="button",
|
|
194
|
+
endpoint="/tools/get_weather",
|
|
195
|
+
operation="update"
|
|
196
|
+
)
|
|
197
|
+
]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return IslandResponse.create([island])
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Island Components
|
|
204
|
+
|
|
205
|
+
#### IslandConfig.Field
|
|
206
|
+
Fields represent data inputs in the UI:
|
|
207
|
+
- `name`: Programmatic field identifier
|
|
208
|
+
- `label`: Human-readable label
|
|
209
|
+
- `type`: Field type (`"string"`, `"boolean"`, `"json"`)
|
|
210
|
+
- `value`: Current field value (optional)
|
|
211
|
+
- `hidden`: Whether to hide from user (optional, default: False)
|
|
212
|
+
- `options`: Available options for selection (optional)
|
|
213
|
+
|
|
214
|
+
#### IslandConfig.Action
|
|
215
|
+
Actions represent buttons or operations:
|
|
216
|
+
- `name`: Programmatic action identifier
|
|
217
|
+
- `label`: Human-readable button label
|
|
218
|
+
- `type`: UI element type (typically `"button"`)
|
|
219
|
+
- `endpoint`: API endpoint to call
|
|
220
|
+
- `operation`: Operation type (default: `"create"`)
|
|
221
|
+
|
|
222
|
+
#### IslandConfig
|
|
223
|
+
Contains the complete island configuration:
|
|
224
|
+
- `fields`: List of IslandConfig.Field objects
|
|
225
|
+
- `actions`: List of IslandConfig.Action objects
|
|
226
|
+
|
|
227
|
+
#### IslandResponse
|
|
228
|
+
The response wrapper for islands:
|
|
229
|
+
- Use `IslandResponse.create([islands])` to create responses
|
|
230
|
+
- Supports multiple islands per response
|
|
231
|
+
|
|
232
|
+
## Type Definitions
|
|
233
|
+
|
|
234
|
+
The SDK provides several TypedDict and dataclass definitions for better type safety:
|
|
235
|
+
|
|
236
|
+
### Authentication Types
|
|
237
|
+
- `AuthData`: TypedDict containing provider and credentials information
|
|
238
|
+
- `Credentials`: TypedDict with access_token, org_sso_id, customer_id, instance_id, and product_sku
|
|
239
|
+
- `AuthRequirement`: Dataclass for specifying authentication requirements
|
|
240
|
+
|
|
241
|
+
### Execution Environment
|
|
242
|
+
- `Environment`: TypedDict specifying execution mode (`"headless"` or `"interactive"`)
|
|
243
|
+
|
|
244
|
+
### Parameter Types
|
|
245
|
+
- `ParameterType`: Enum for supported parameter types (string, integer, number, boolean, list, dictionary)
|
|
246
|
+
- `Parameter`: Dataclass for tool parameter definitions
|
|
247
|
+
- `Function`: Dataclass for complete tool function definitions
|
|
248
|
+
|
|
249
|
+
These types are automatically imported when you import from `opal_tools_sdk` and provide better IDE support and type checking.
|
|
250
|
+
|
|
251
|
+
## Documentation
|
|
252
|
+
|
|
253
|
+
See full documentation for more examples and configuration options.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
opal_tools_sdk/__init__.py,sha256=
|
|
1
|
+
opal_tools_sdk/__init__.py,sha256=0B0c53fyCRMuI_zOfwiePzQk5ion1BSKCqGLVsY0TVk,495
|
|
2
2
|
opal_tools_sdk/_registry.py,sha256=YE3eD4kcS09QDe4RccBYAzXPo9znEU7fblrsB-g3o-Y,67
|
|
3
3
|
opal_tools_sdk/auth.py,sha256=9aMiZv6n6_iu7hQA0sKg4hgNr5DzYFFuP0SWUoZf_Vw,1520
|
|
4
4
|
opal_tools_sdk/decorators.py,sha256=iHal7RElOSCWjqKHIK-Hc4GKOsjuGyUg0_lsQKVQShg,5315
|
|
5
5
|
opal_tools_sdk/logging.py,sha256=krvkhdql2GWh0aCWj5gfqyn5plsyLJ773WzIirK7tkU,1325
|
|
6
|
-
opal_tools_sdk/models.py,sha256=
|
|
6
|
+
opal_tools_sdk/models.py,sha256=YESFXdIPIFoVqP6OXtswXzHQ1tYMFVSnb8rFVe9cFj4,3403
|
|
7
7
|
opal_tools_sdk/service.py,sha256=wVYe40zEZc1ynIkvowD9APU8BFHQ5fdy3j8qlsdZB1U,6965
|
|
8
|
-
optimizely_opal_opal_tools_sdk-0.1.
|
|
9
|
-
optimizely_opal_opal_tools_sdk-0.1.
|
|
10
|
-
optimizely_opal_opal_tools_sdk-0.1.
|
|
11
|
-
optimizely_opal_opal_tools_sdk-0.1.
|
|
8
|
+
optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info/METADATA,sha256=KS830xd4wFliLcbfJBuWSxj49pIH_AfajJJOrm_UG0Q,8085
|
|
9
|
+
optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
+
optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info/top_level.txt,sha256=nCJ5PxF0rgoV6yNJvvuUaZPx4D3EWkl7gpu-6xafH1E,15
|
|
11
|
+
optimizely_opal_opal_tools_sdk-0.1.5.dev0.dist-info/RECORD,,
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: optimizely-opal.opal-tools-sdk
|
|
3
|
-
Version: 0.1.4.dev0
|
|
4
|
-
Summary: SDK for creating Opal-compatible tools services
|
|
5
|
-
Home-page: https://github.com/optimizely/opal-tools-sdk
|
|
6
|
-
Author: Optimizely
|
|
7
|
-
Author-email: Optimizely <opal-team@optimizely.com>
|
|
8
|
-
License: MIT
|
|
9
|
-
Project-URL: Homepage, https://github.com/optimizely/opal-tools-sdk
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/optimizely/opal-tools-sdk/issues
|
|
11
|
-
Keywords: opal,tools,sdk,ai,llm
|
|
12
|
-
Classifier: Development Status :: 3 - Alpha
|
|
13
|
-
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
-
Requires-Python: >=3.10
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: fastapi>=0.100.0
|
|
19
|
-
Requires-Dist: pydantic>=2.0.0
|
|
20
|
-
Requires-Dist: httpx>=0.24.1
|
|
21
|
-
Dynamic: author
|
|
22
|
-
Dynamic: home-page
|
|
23
|
-
Dynamic: requires-python
|
|
24
|
-
|
|
25
|
-
# Opal Tools SDK for Python
|
|
26
|
-
|
|
27
|
-
This SDK simplifies the creation of tools services compatible with the Opal Tools Management Service.
|
|
28
|
-
|
|
29
|
-
## Features
|
|
30
|
-
|
|
31
|
-
- Easy definition of tool functions with decorators
|
|
32
|
-
- Automatic generation of discovery endpoints
|
|
33
|
-
- Parameter validation and type checking
|
|
34
|
-
- Authentication helpers
|
|
35
|
-
- FastAPI integration
|
|
36
|
-
|
|
37
|
-
## Installation
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
pip install optimizely-opal.opal-tools-sdk
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Note: While the package is installed as `optimizely-opal.opal-tools-sdk`, you'll still import it in your code as `opal_tools_sdk`:
|
|
44
|
-
|
|
45
|
-
```python
|
|
46
|
-
# Import using the package name
|
|
47
|
-
from opal_tools_sdk import ToolsService, tool
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Usage
|
|
51
|
-
|
|
52
|
-
```python
|
|
53
|
-
from opal_tools_sdk import ToolsService, tool
|
|
54
|
-
from pydantic import BaseModel
|
|
55
|
-
from fastapi import FastAPI
|
|
56
|
-
|
|
57
|
-
app = FastAPI()
|
|
58
|
-
tools_service = ToolsService(app)
|
|
59
|
-
|
|
60
|
-
class WeatherParameters(BaseModel):
|
|
61
|
-
location: str
|
|
62
|
-
units: str = "metric"
|
|
63
|
-
|
|
64
|
-
@tool("get_weather", "Gets current weather for a location")
|
|
65
|
-
async def get_weather(parameters: WeatherParameters):
|
|
66
|
-
# Implementation...
|
|
67
|
-
return {"temperature": 22, "condition": "sunny"}
|
|
68
|
-
|
|
69
|
-
# Discovery endpoint is automatically created at /discovery
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Authentication
|
|
73
|
-
|
|
74
|
-
The SDK provides two ways to require authentication for your tools:
|
|
75
|
-
|
|
76
|
-
### 1. Using the `@requires_auth` decorator
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
from opal_tools_sdk import ToolsService, tool
|
|
80
|
-
from opal_tools_sdk.auth import requires_auth
|
|
81
|
-
from pydantic import BaseModel
|
|
82
|
-
from fastapi import FastAPI
|
|
83
|
-
|
|
84
|
-
app = FastAPI()
|
|
85
|
-
tools_service = ToolsService(app)
|
|
86
|
-
|
|
87
|
-
class CalendarParameters(BaseModel):
|
|
88
|
-
date: str
|
|
89
|
-
timezone: str = "UTC"
|
|
90
|
-
|
|
91
|
-
# Single authentication requirement
|
|
92
|
-
@requires_auth(provider="google", scope_bundle="calendar", required=True)
|
|
93
|
-
@tool("get_calendar_events", "Gets calendar events for a date")
|
|
94
|
-
async def get_calendar_events(parameters: CalendarParameters, auth_data=None):
|
|
95
|
-
# The auth_data parameter contains authentication information
|
|
96
|
-
token = auth_data.get("credentials", {}).get("token", "")
|
|
97
|
-
|
|
98
|
-
# Use the token to make authenticated requests
|
|
99
|
-
# ...
|
|
100
|
-
|
|
101
|
-
return {"events": ["Meeting at 10:00", "Lunch at 12:00"]}
|
|
102
|
-
|
|
103
|
-
# Multiple authentication requirements (tool can work with either provider)
|
|
104
|
-
@requires_auth(provider="google", scope_bundle="calendar", required=True)
|
|
105
|
-
@requires_auth(provider="microsoft", scope_bundle="outlook", required=True)
|
|
106
|
-
@tool("get_calendar_availability", "Check calendar availability")
|
|
107
|
-
async def get_calendar_availability(parameters: CalendarParameters, auth_data=None):
|
|
108
|
-
provider = auth_data.get("provider", "")
|
|
109
|
-
token = auth_data.get("credentials", {}).get("token", "")
|
|
110
|
-
|
|
111
|
-
if provider == "google":
|
|
112
|
-
# Use Google Calendar API
|
|
113
|
-
pass
|
|
114
|
-
elif provider == "microsoft":
|
|
115
|
-
# Use Microsoft Outlook API
|
|
116
|
-
pass
|
|
117
|
-
|
|
118
|
-
return {"available": True, "provider_used": provider}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### 2. Specifying auth requirements in the `@tool` decorator
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
@tool(
|
|
125
|
-
"get_email",
|
|
126
|
-
"Gets emails from the user's inbox",
|
|
127
|
-
auth_requirements=[
|
|
128
|
-
{"provider": "google", "scope_bundle": "gmail", "required": True}
|
|
129
|
-
]
|
|
130
|
-
)
|
|
131
|
-
async def get_email(parameters: EmailParameters, auth_data=None):
|
|
132
|
-
# Implementation...
|
|
133
|
-
return {"emails": ["Email 1", "Email 2"]}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Documentation
|
|
137
|
-
|
|
138
|
-
See full documentation for more examples and configuration options.
|
|
File without changes
|