optimizely-opal.opal-tools-sdk 0.1.32.dev0__tar.gz → 0.1.35.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.35.dev0}/PKG-INFO +1 -1
  2. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.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.35.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.35.dev0}/opal_tools_sdk/proteus.py +130 -24
  5. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.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.35.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.35.dev0}/pyproject.toml +1 -1
  8. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.dev0}/setup.py +1 -1
  9. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.dev0}/README.md +0 -0
  10. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.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.35.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.35.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.35.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.35.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.35.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.35.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.35.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.35.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.35.dev0}/setup.cfg +0 -0
  20. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.dev0}/tests/test_integration.py +0 -0
  21. {optimizely_opal_opal_tools_sdk-0.1.32.dev0 → optimizely_opal_opal_tools_sdk-0.1.35.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.35.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.35.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-18T18:51:08+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
 
@@ -345,6 +344,20 @@ class ProteusEventHandler4(BaseModel):
345
344
  url: ProteusExpression | str = Field(..., description="URL to open in a new tab")
346
345
 
347
346
 
347
+ class ProteusEventHandler5(BaseModel):
348
+ """
349
+ Client-side component action - for previewing a file inline
350
+ """
351
+
352
+ model_config = ConfigDict(
353
+ extra="forbid",
354
+ )
355
+ action: Literal["preview"] = Field(default="preview", description="The action type")
356
+ file: ProteusExpression | dict[str, Any] | str = Field(
357
+ ..., description="The file object to preview"
358
+ )
359
+
360
+
348
361
  class Part(BaseModel):
349
362
  model_config = ConfigDict(
350
363
  extra="forbid",
@@ -355,14 +368,15 @@ class Part(BaseModel):
355
368
 
356
369
  class ProteusStructuredMessage(BaseModel):
357
370
  """
358
- Structured message payload that lets file URLs travel as a typed list alongside the text parts, instead of being joined into the text.
371
+ Structured message payload that lets file metadata travel as a typed list alongside the text parts, instead of being joined into the text.
359
372
  """
360
373
 
361
374
  model_config = ConfigDict(
362
375
  extra="forbid",
363
376
  )
364
- files: list[str] | ProteusExpression | None = Field(
365
- default=None, description="List of file URLs (typically signed URLs from a host upload)."
377
+ files: list[File] | ProteusExpression | None = Field(
378
+ default=None,
379
+ description="List of uploaded file metadata objects (typically the host's onUpload return value). Hosts may attach additional fields beyond `name` and `link`.",
366
380
  )
367
381
  parts: list[Part]
368
382
 
@@ -927,6 +941,9 @@ class ProteusCardLink(BaseModel):
927
941
  mx: SprinklePropMx | None = None
928
942
  my: SprinklePropMy | None = None
929
943
  objectFit: SprinklePropObjectFit | None = None
944
+ onClick: ProteusEventHandler | None = Field(
945
+ default=None, description="Action triggered when link is clicked"
946
+ )
930
947
  overflow: SprinklePropOverflow | None = None
931
948
  overflowX: SprinklePropOverflowX | None = None
932
949
  overflowY: SprinklePropOverflowY | None = None
@@ -1080,6 +1097,74 @@ class ProteusField(BaseModel):
1080
1097
  z: SprinklePropZ | None = None
1081
1098
 
1082
1099
 
1100
+ class ProteusFileIcon(BaseModel):
1101
+ model_config = ConfigDict(
1102
+ extra="forbid",
1103
+ )
1104
+ field_type: Literal["FileIcon"] = Field(default="FileIcon", alias="$type")
1105
+ alignItems: SprinklePropAlignItems | None = None
1106
+ alignSelf: SprinklePropAlignSelf | None = None
1107
+ animation: SprinklePropAnimation | None = None
1108
+ backgroundImage: SprinklePropBackgroundImage | None = None
1109
+ bg: SprinklePropBg | None = None
1110
+ border: SprinklePropBorder | None = None
1111
+ borderB: SprinklePropBorderB | None = None
1112
+ borderColor: SprinklePropBorderColor | None = None
1113
+ borderL: SprinklePropBorderL | None = None
1114
+ borderR: SprinklePropBorderR | None = None
1115
+ borderT: SprinklePropBorderT | None = None
1116
+ color: SprinklePropColor | None = None
1117
+ cursor: SprinklePropCursor | None = None
1118
+ display: SprinklePropDisplay | None = None
1119
+ flex: SprinklePropFlex | None = None
1120
+ flexDirection: SprinklePropFlexDirection | None = None
1121
+ flexWrap: SprinklePropFlexWrap | None = None
1122
+ fontFamily: SprinklePropFontFamily | None = None
1123
+ fontSize: SprinklePropFontSize | None = None
1124
+ fontWeight: SprinklePropFontWeight | None = None
1125
+ gap: SprinklePropGap | None = None
1126
+ gridAutoRows: SprinklePropGridAutoRows | None = None
1127
+ gridColumn: SprinklePropGridColumn | None = None
1128
+ gridTemplateColumns: SprinklePropGridTemplateColumns | None = None
1129
+ h: SprinklePropH | None = None
1130
+ justifyContent: SprinklePropJustifyContent | None = None
1131
+ justifyItems: SprinklePropJustifyItems | None = None
1132
+ m: SprinklePropM | None = None
1133
+ maxH: SprinklePropMaxH | None = None
1134
+ maxW: SprinklePropMaxW | None = None
1135
+ mb: SprinklePropMb | None = None
1136
+ ml: SprinklePropMl | None = None
1137
+ mr: SprinklePropMr | None = None
1138
+ mt: SprinklePropMt | None = None
1139
+ mx: SprinklePropMx | None = None
1140
+ my: SprinklePropMy | None = None
1141
+ objectFit: SprinklePropObjectFit | None = None
1142
+ overflow: SprinklePropOverflow | None = None
1143
+ overflowX: SprinklePropOverflowX | None = None
1144
+ overflowY: SprinklePropOverflowY | None = None
1145
+ p: SprinklePropP | None = None
1146
+ pb: SprinklePropPb | None = None
1147
+ pl: SprinklePropPl | None = None
1148
+ placeItems: SprinklePropPlaceItems | None = None
1149
+ pointerEvents: SprinklePropPointerEvents | None = None
1150
+ pr: SprinklePropPr | None = None
1151
+ pt: SprinklePropPt | None = None
1152
+ px: SprinklePropPx | None = None
1153
+ py: SprinklePropPy | None = None
1154
+ rounded: SprinklePropRounded | None = None
1155
+ shadow: SprinklePropShadow | None = None
1156
+ size: SprinklePropSize | None = None
1157
+ textAlign: SprinklePropTextAlign | None = None
1158
+ textTransform: SprinklePropTextTransform | None = None
1159
+ transition: SprinklePropTransition | None = None
1160
+ w: SprinklePropW | None = None
1161
+ whiteSpace: SprinklePropWhiteSpace | None = None
1162
+ z: SprinklePropZ | None = None
1163
+ mimeType: str | ProteusExpression | None = Field(
1164
+ default=None, description="MIME type of the file to determine which icon to display"
1165
+ )
1166
+
1167
+
1083
1168
  class ProteusFileUpload(BaseModel):
1084
1169
  model_config = ConfigDict(
1085
1170
  extra="forbid",
@@ -1088,12 +1173,16 @@ class ProteusFileUpload(BaseModel):
1088
1173
  accept: list[str] | None = Field(
1089
1174
  default=None, description="File types to accept; array of MIME types or extensions."
1090
1175
  )
1091
- name: str | ProteusExpression | None = Field(
1176
+ maxFiles: float | ProteusExpression | None = Field(
1092
1177
  default=None,
1093
- description="The name of the form control element. The resolved URL is written at parentPath/name in form data.",
1178
+ 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
1179
  )
1095
- required: bool | ProteusExpression | None = Field(
1096
- default=None, description="Whether a file is required."
1180
+ minFiles: float | ProteusExpression | None = Field(
1181
+ default=None, description="Minimum number of files required."
1182
+ )
1183
+ name: str | ProteusExpression | None = Field(
1184
+ default=None,
1185
+ description="The name of the form control element. The resolved metadata array is written at parentPath/name in form data.",
1097
1186
  )
1098
1187
 
1099
1188
 
@@ -1591,6 +1680,10 @@ class ProteusMap(BaseModel):
1591
1680
  default=None,
1592
1681
  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
1682
  )
1683
+ flat: bool | None = Field(
1684
+ default=None,
1685
+ 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.",
1686
+ )
1594
1687
  path: str = Field(
1595
1688
  ..., description="JSON pointer path to the source array in the data (e.g., '/results')"
1596
1689
  )
@@ -2247,11 +2340,19 @@ class ProteusCondition(
2247
2340
 
2248
2341
  class ProteusEventHandler(
2249
2342
  RootModel[
2250
- ProteusEventHandler1 | ProteusEventHandler2 | ProteusEventHandler3 | ProteusEventHandler4
2343
+ ProteusEventHandler1
2344
+ | ProteusEventHandler2
2345
+ | ProteusEventHandler3
2346
+ | ProteusEventHandler4
2347
+ | ProteusEventHandler5
2251
2348
  ]
2252
2349
  ):
2253
2350
  root: (
2254
- ProteusEventHandler1 | ProteusEventHandler2 | ProteusEventHandler3 | ProteusEventHandler4
2351
+ ProteusEventHandler1
2352
+ | ProteusEventHandler2
2353
+ | ProteusEventHandler3
2354
+ | ProteusEventHandler4
2355
+ | ProteusEventHandler5
2255
2356
  ) = Field(
2256
2357
  ...,
2257
2358
  description="Handler for user interactions - a server-side interaction call, client-side message, or client-side component action",
@@ -2279,6 +2380,7 @@ class ProteusElement(
2279
2380
  | ProteusDataTable
2280
2381
  | ProteusFederated
2281
2382
  | ProteusField
2383
+ | ProteusFileIcon
2282
2384
  | ProteusFileUpload
2283
2385
  | ProteusGroup
2284
2386
  | ProteusHeading
@@ -2317,6 +2419,7 @@ class ProteusElement(
2317
2419
  | ProteusDataTable
2318
2420
  | ProteusFederated
2319
2421
  | ProteusField
2422
+ | ProteusFileIcon
2320
2423
  | ProteusFileUpload
2321
2424
  | ProteusGroup
2322
2425
  | ProteusHeading
@@ -3983,6 +4086,7 @@ ProteusDocument.model_rebuild()
3983
4086
  ProteusEventHandler2.model_rebuild()
3984
4087
  ProteusEventHandler3.model_rebuild()
3985
4088
  ProteusEventHandler4.model_rebuild()
4089
+ ProteusEventHandler5.model_rebuild()
3986
4090
  Part.model_rebuild()
3987
4091
  ProteusStructuredMessage.model_rebuild()
3988
4092
  ProteusZip.model_rebuild()
@@ -3999,6 +4103,7 @@ ProteusConcat.model_rebuild()
3999
4103
  ProteusDataTable.model_rebuild()
4000
4104
  ProteusFederated.model_rebuild()
4001
4105
  ProteusField.model_rebuild()
4106
+ ProteusFileIcon.model_rebuild()
4002
4107
  ProteusFileUpload.model_rebuild()
4003
4108
  ProteusGroup.model_rebuild()
4004
4109
  ProteusHeading.model_rebuild()
@@ -4047,6 +4152,7 @@ class UI:
4047
4152
  Document = ProteusDocument
4048
4153
  Federated = ProteusFederated
4049
4154
  Field = ProteusField
4155
+ FileIcon = ProteusFileIcon
4050
4156
  FileUpload = ProteusFileUpload
4051
4157
  Group = ProteusGroup
4052
4158
  Heading = ProteusHeading
@@ -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.35.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.35-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.35-dev",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "fastapi>=0.100.0",