optimizely-opal.opal-tools-sdk 0.1.32.dev0__tar.gz → 0.1.34.dev0__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 (22) hide show
  1. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/PKG-INFO +1 -1
  2. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/decorators.py +4 -0
  3. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/models.py +5 -1
  4. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/proteus.py +30 -22
  5. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/service.py +3 -0
  6. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/optimizely_opal.opal_tools_sdk.egg-info/PKG-INFO +1 -1
  7. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/pyproject.toml +1 -1
  8. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/setup.py +1 -1
  9. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/README.md +0 -0
  10. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/__init__.py +0 -0
  11. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/_registry.py +0 -0
  12. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/auth.py +0 -0
  13. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/logging.py +0 -0
  14. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/opal_tools_sdk/ui.py +0 -0
  15. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/optimizely_opal.opal_tools_sdk.egg-info/SOURCES.txt +0 -0
  16. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/optimizely_opal.opal_tools_sdk.egg-info/dependency_links.txt +0 -0
  17. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/optimizely_opal.opal_tools_sdk.egg-info/requires.txt +0 -0
  18. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/optimizely_opal.opal_tools_sdk.egg-info/top_level.txt +0 -0
  19. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/setup.cfg +0 -0
  20. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/tests/test_integration.py +0 -0
  21. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/tests/test_nested_schema.py +0 -0
  22. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.34.dev0}/tests/test_proteus.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optimizely-opal.opal-tools-sdk
3
- Version: 0.1.32.dev0
3
+ Version: 0.1.34.dev0
4
4
  Summary: SDK for creating Opal-compatible tools services
5
5
  Home-page: https://github.com/optimizely/opal-tools-sdk
6
6
  Author: Optimizely
@@ -95,6 +95,7 @@ def tool(
95
95
  description: str,
96
96
  auth_requirements: list[dict[str, Any]] | None = None,
97
97
  ui_resource: str | None = None,
98
+ wait: bool = False,
98
99
  ):
99
100
  """Decorator to register a function as an Opal tool.
100
101
 
@@ -108,6 +109,8 @@ def tool(
108
109
  "scope_bundle": "calendar", "required": True}]
109
110
  ui_resource: URI of associated UI resource for dynamic rendering (optional)
110
111
  Example: "ui://my-app/create-form"
112
+ wait: When True, invoking this tool pauses the agent execution until the caller
113
+ signals completion.
111
114
 
112
115
  Returns:
113
116
  Decorator function
@@ -294,6 +297,7 @@ def tool(
294
297
  endpoint=endpoint,
295
298
  auth_requirements=auth_req_list,
296
299
  ui_resource=ui_resource,
300
+ wait=wait,
297
301
  )
298
302
 
299
303
  return func
@@ -102,10 +102,11 @@ class Function:
102
102
  auth_requirements: list[AuthRequirement] | None = None
103
103
  http_method: str = "POST"
104
104
  ui_resource: str | None = None # UI resource URI for dynamic UI rendering
105
+ wait: bool = False # When True, pauses the agent until the caller signals completion
105
106
 
106
107
  def to_dict(self) -> dict[str, Any]:
107
108
  """Convert to dictionary for the discovery endpoint."""
108
- result = {
109
+ result: dict[str, Any] = {
109
110
  "name": self.name,
110
111
  "description": self.description,
111
112
  "parameters": [p.to_dict() for p in self.parameters],
@@ -119,6 +120,9 @@ class Function:
119
120
  if self.ui_resource:
120
121
  result["ui_resource"] = self.ui_resource
121
122
 
123
+ if self.wait:
124
+ result["wait"] = self.wait
125
+
122
126
  return result
123
127
 
124
128
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: proteus-document-spec.json
3
- # timestamp: 2026-05-11T14:40:18+00:00
3
+ # timestamp: 2026-05-11T17:24:58+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -27,6 +27,11 @@ class ProteusEventHandler1(BaseModel):
27
27
  )
28
28
 
29
29
 
30
+ class File(BaseModel):
31
+ link: str
32
+ name: str
33
+
34
+
30
35
  class Series(BaseModel):
31
36
  model_config = ConfigDict(
32
37
  extra="forbid",
@@ -130,7 +135,7 @@ class ProteusCondition1(BaseModel):
130
135
  extra="forbid",
131
136
  )
132
137
  field__: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
133
- ..., alias="!=", description="Inequality comparison", max_length=2, min_length=2
138
+ ..., alias="!=", description="Inequality comparison"
134
139
  )
135
140
 
136
141
 
@@ -143,7 +148,7 @@ class ProteusCondition2(BaseModel):
143
148
  extra="forbid",
144
149
  )
145
150
  field_: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
146
- ..., alias="<", description="Less than comparison", max_length=2, min_length=2
151
+ ..., alias="<", description="Less than comparison"
147
152
  )
148
153
 
149
154
 
@@ -156,7 +161,7 @@ class ProteusCondition3(BaseModel):
156
161
  extra="forbid",
157
162
  )
158
163
  field__: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
159
- ..., alias="<=", description="Less than or equal comparison", max_length=2, min_length=2
164
+ ..., alias="<=", description="Less than or equal comparison"
160
165
  )
161
166
 
162
167
 
@@ -169,7 +174,7 @@ class ProteusCondition4(BaseModel):
169
174
  extra="forbid",
170
175
  )
171
176
  field__: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
172
- ..., alias="==", description="Equality comparison", max_length=2, min_length=2
177
+ ..., alias="==", description="Equality comparison"
173
178
  )
174
179
 
175
180
 
@@ -182,7 +187,7 @@ class ProteusCondition5(BaseModel):
182
187
  extra="forbid",
183
188
  )
184
189
  field_: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
185
- ..., alias=">", description="Greater than comparison", max_length=2, min_length=2
190
+ ..., alias=">", description="Greater than comparison"
186
191
  )
187
192
 
188
193
 
@@ -195,7 +200,7 @@ class ProteusCondition6(BaseModel):
195
200
  extra="forbid",
196
201
  )
197
202
  field__: list[str | float | bool | ProteusMapIndex | ProteusValue | None] = Field(
198
- ..., alias=">=", description="Greater than or equal comparison", max_length=2, min_length=2
203
+ ..., alias=">=", description="Greater than or equal comparison"
199
204
  )
200
205
 
201
206
 
@@ -238,10 +243,7 @@ class ProteusCondition9(BaseModel):
238
243
  extra="forbid",
239
244
  )
240
245
  and_: list[ProteusCondition] = Field(
241
- ...,
242
- alias="and",
243
- description="Logical AND - returns true if all conditions are true",
244
- min_length=1,
246
+ ..., alias="and", description="Logical AND - returns true if all conditions are true"
245
247
  )
246
248
 
247
249
 
@@ -254,10 +256,7 @@ class ProteusCondition10(BaseModel):
254
256
  extra="forbid",
255
257
  )
256
258
  or_: list[ProteusCondition] = Field(
257
- ...,
258
- alias="or",
259
- description="Logical OR - returns true if any condition is true",
260
- min_length=1,
259
+ ..., alias="or", description="Logical OR - returns true if any condition is true"
261
260
  )
262
261
 
263
262
 
@@ -355,14 +354,15 @@ class Part(BaseModel):
355
354
 
356
355
  class ProteusStructuredMessage(BaseModel):
357
356
  """
358
- Structured message payload that lets file URLs travel as a typed list alongside the text parts, instead of being joined into the text.
357
+ Structured message payload that lets file metadata travel as a typed list alongside the text parts, instead of being joined into the text.
359
358
  """
360
359
 
361
360
  model_config = ConfigDict(
362
361
  extra="forbid",
363
362
  )
364
- files: list[str] | ProteusExpression | None = Field(
365
- default=None, description="List of file URLs (typically signed URLs from a host upload)."
363
+ files: list[File] | ProteusExpression | None = Field(
364
+ default=None,
365
+ description="List of uploaded file metadata objects (typically the host's onUpload return value). Hosts may attach additional fields beyond `name` and `link`.",
366
366
  )
367
367
  parts: list[Part]
368
368
 
@@ -1088,12 +1088,16 @@ class ProteusFileUpload(BaseModel):
1088
1088
  accept: list[str] | None = Field(
1089
1089
  default=None, description="File types to accept; array of MIME types or extensions."
1090
1090
  )
1091
- name: str | ProteusExpression | None = Field(
1091
+ maxFiles: float | ProteusExpression | None = Field(
1092
1092
  default=None,
1093
- description="The name of the form control element. The resolved URL is written at parentPath/name in form data.",
1093
+ description="Maximum number of files allowed. When set to 1 the field is in single-file mode; any other value (or omitted) allows multiple uploads.",
1094
1094
  )
1095
- required: bool | ProteusExpression | None = Field(
1096
- default=None, description="Whether a file is required."
1095
+ minFiles: float | ProteusExpression | None = Field(
1096
+ default=None, description="Minimum number of files required."
1097
+ )
1098
+ name: str | ProteusExpression | None = Field(
1099
+ default=None,
1100
+ description="The name of the form control element. The resolved metadata array is written at parentPath/name in form data.",
1097
1101
  )
1098
1102
 
1099
1103
 
@@ -1591,6 +1595,10 @@ class ProteusMap(BaseModel):
1591
1595
  default=None,
1592
1596
  description="Template object to render for each item in the array. Value paths inside this template are relative to the current item (e.g., path='title' resolves to each item's 'title' field). Use a leading '/' to reference top-level data (e.g., path='/title' resolves to the root data's 'title').",
1593
1597
  )
1598
+ flat: bool | None = Field(
1599
+ default=None,
1600
+ description="When true, flattens the result array by one level. Useful when each mapped item resolves to an array and you want a single flat list.",
1601
+ )
1594
1602
  path: str = Field(
1595
1603
  ..., description="JSON pointer path to the source array in the data (e.g., '/results')"
1596
1604
  )
@@ -213,6 +213,7 @@ class ToolsService:
213
213
  endpoint: str,
214
214
  auth_requirements: list[AuthRequirement] | None = None,
215
215
  ui_resource: str | None = None,
216
+ wait: bool = False,
216
217
  ) -> None:
217
218
  """Register a tool function.
218
219
 
@@ -224,6 +225,7 @@ class ToolsService:
224
225
  endpoint: API endpoint for the tool
225
226
  auth_requirements: List of authentication requirements (optional)
226
227
  ui_resource: URI of associated UI resource for dynamic rendering (optional)
228
+ wait: When True, invoking this tool pauses the agent until the caller signals completion
227
229
  """
228
230
  logger.info(f"Registering tool: {name} with endpoint: {endpoint}")
229
231
 
@@ -250,6 +252,7 @@ class ToolsService:
250
252
  endpoint=endpoint,
251
253
  auth_requirements=final_auth_requirements,
252
254
  ui_resource=ui_resource,
255
+ wait=wait,
253
256
  )
254
257
 
255
258
  self.functions.append(function)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optimizely-opal.opal-tools-sdk
3
- Version: 0.1.32.dev0
3
+ Version: 0.1.34.dev0
4
4
  Summary: SDK for creating Opal-compatible tools services
5
5
  Home-page: https://github.com/optimizely/opal-tools-sdk
6
6
  Author: Optimizely
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "optimizely-opal.opal-tools-sdk"
7
- version = "0.1.32-dev"
7
+ version = "0.1.34-dev"
8
8
  description = "SDK for creating Opal-compatible tools services"
9
9
  authors = [{ name = "Optimizely", email = "opal-team@optimizely.com" }]
10
10
  readme = "README.md"
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="optimizely-opal.opal-tools-sdk",
5
- version="0.1.32-dev",
5
+ version="0.1.34-dev",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "fastapi>=0.100.0",