vellum-ai 0.8.9__py3-none-any.whl → 0.8.10__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
vellum/client.py CHANGED
@@ -892,7 +892,9 @@ class Vellum:
892
892
  ChatMessageRequest(
893
893
  text="string",
894
894
  role="SYSTEM",
895
- content=StringChatMessageContentRequest(),
895
+ content=StringChatMessageContentRequest(
896
+ value="string",
897
+ ),
896
898
  source="string",
897
899
  )
898
900
  ],
@@ -2116,7 +2118,9 @@ class AsyncVellum:
2116
2118
  ChatMessageRequest(
2117
2119
  text="string",
2118
2120
  role="SYSTEM",
2119
- content=StringChatMessageContentRequest(),
2121
+ content=StringChatMessageContentRequest(
2122
+ value="string",
2123
+ ),
2120
2124
  source="string",
2121
2125
  )
2122
2126
  ],
@@ -17,7 +17,7 @@ class BaseClientWrapper:
17
17
  headers: typing.Dict[str, str] = {
18
18
  "X-Fern-Language": "Python",
19
19
  "X-Fern-SDK-Name": "vellum-ai",
20
- "X-Fern-SDK-Version": "0.8.9",
20
+ "X-Fern-SDK-Version": "0.8.10",
21
21
  }
22
22
  headers["X_API_KEY"] = self.api_key
23
23
  return headers
@@ -80,6 +80,8 @@ class UniversalBaseModel(pydantic.BaseModel):
80
80
  smart_union = True
81
81
  allow_population_by_field_name = True
82
82
  json_encoders = {dt.datetime: serialize_datetime}
83
+ # Allow fields begining with `model_` to be used in the model
84
+ protected_namespaces = ()
83
85
 
84
86
  def json(self, **kwargs: typing.Any) -> str:
85
87
  kwargs_with_defaults: typing.Any = {
@@ -97,30 +99,64 @@ class UniversalBaseModel(pydantic.BaseModel):
97
99
  Override the default dict method to `exclude_unset` by default. This function patches
98
100
  `exclude_unset` to work include fields within non-None default values.
99
101
  """
100
- _fields_set = self.__fields_set__
101
-
102
- fields = _get_model_fields(self.__class__)
103
- for name, field in fields.items():
104
- if name not in _fields_set:
105
- default = _get_field_default(field)
106
-
107
- # If the default values are non-null act like they've been set
108
- # This effectively allows exclude_unset to work like exclude_none where
109
- # the latter passes through intentionally set none values.
110
- if default != None:
111
- _fields_set.add(name)
112
-
113
- kwargs_with_defaults_exclude_unset: typing.Any = {
114
- "by_alias": True,
115
- "exclude_unset": True,
116
- "include": _fields_set,
117
- **kwargs,
118
- }
119
-
102
+ # Note: the logic here is multi-plexed given the levers exposed in Pydantic V1 vs V2
103
+ # Pydantic V1's .dict can be extremely slow, so we do not want to call it twice.
104
+ #
105
+ # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models
106
+ # that we have less control over, and this is less intrusive than custom serializers for now.
120
107
  if IS_PYDANTIC_V2:
121
- return super().model_dump(**kwargs_with_defaults_exclude_unset) # type: ignore # Pydantic v2
108
+ kwargs_with_defaults_exclude_unset: typing.Any = {
109
+ **kwargs,
110
+ "by_alias": True,
111
+ "exclude_unset": True,
112
+ "exclude_none": False,
113
+ }
114
+ kwargs_with_defaults_exclude_none: typing.Any = {
115
+ **kwargs,
116
+ "by_alias": True,
117
+ "exclude_none": True,
118
+ "exclude_unset": False,
119
+ }
120
+ return deep_union_pydantic_dicts(
121
+ super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore # Pydantic v2
122
+ super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore # Pydantic v2
123
+ )
124
+
122
125
  else:
123
- return super().dict(**kwargs_with_defaults_exclude_unset)
126
+ _fields_set = self.__fields_set__
127
+
128
+ fields = _get_model_fields(self.__class__)
129
+ for name, field in fields.items():
130
+ if name not in _fields_set:
131
+ default = _get_field_default(field)
132
+
133
+ # If the default values are non-null act like they've been set
134
+ # This effectively allows exclude_unset to work like exclude_none where
135
+ # the latter passes through intentionally set none values.
136
+ if default != None:
137
+ _fields_set.add(name)
138
+
139
+ kwargs_with_defaults_exclude_unset_include_fields: typing.Any = {
140
+ "by_alias": True,
141
+ "exclude_unset": True,
142
+ "include": _fields_set,
143
+ **kwargs,
144
+ }
145
+
146
+ return super().dict(**kwargs_with_defaults_exclude_unset_include_fields)
147
+
148
+
149
+ def deep_union_pydantic_dicts(
150
+ source: typing.Dict[str, typing.Any], destination: typing.Dict[str, typing.Any]
151
+ ) -> typing.Dict[str, typing.Any]:
152
+ for key, value in source.items():
153
+ if isinstance(value, dict):
154
+ node = destination.setdefault(key, {})
155
+ deep_union_pydantic_dicts(value, node)
156
+ else:
157
+ destination[key] = value
158
+
159
+ return destination
124
160
 
125
161
 
126
162
  if IS_PYDANTIC_V2:
@@ -1,10 +1,13 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
3
  import collections
4
+ import inspect
4
5
  import typing
5
6
 
6
7
  import typing_extensions
7
8
 
9
+ import pydantic
10
+
8
11
 
9
12
  class FieldMetadata:
10
13
  """
@@ -29,6 +32,7 @@ def convert_and_respect_annotation_metadata(
29
32
  object_: typing.Any,
30
33
  annotation: typing.Any,
31
34
  inner_type: typing.Optional[typing.Any] = None,
35
+ direction: typing.Literal["read", "write"],
32
36
  ) -> typing.Any:
33
37
  """
34
38
  Respect the metadata annotations on a field, such as aliasing. This function effectively
@@ -56,44 +60,59 @@ def convert_and_respect_annotation_metadata(
56
60
  inner_type = annotation
57
61
 
58
62
  clean_type = _remove_annotations(inner_type)
59
- if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
60
- return _convert_typeddict(object_, clean_type)
61
-
63
+ # Pydantic models
62
64
  if (
63
- # If you're iterating on a string, do not bother to coerce it to a sequence.
64
- (not isinstance(object_, str))
65
- and (
66
- (
67
- (
68
- typing_extensions.get_origin(clean_type) == typing.List
69
- or typing_extensions.get_origin(clean_type) == list
70
- or clean_type == typing.List
65
+ inspect.isclass(clean_type)
66
+ and issubclass(clean_type, pydantic.BaseModel)
67
+ and isinstance(object_, typing.Mapping)
68
+ ):
69
+ return _convert_mapping(object_, clean_type, direction)
70
+ # TypedDicts
71
+ if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
72
+ return _convert_mapping(object_, clean_type, direction)
73
+
74
+ # If you're iterating on a string, do not bother to coerce it to a sequence.
75
+ if not isinstance(object_, str):
76
+ if (
77
+ typing_extensions.get_origin(clean_type) == typing.Set
78
+ or typing_extensions.get_origin(clean_type) == set
79
+ or clean_type == typing.Set
80
+ ) and isinstance(object_, typing.Set):
81
+ inner_type = typing_extensions.get_args(clean_type)[0]
82
+ return {
83
+ convert_and_respect_annotation_metadata(
84
+ object_=item,
85
+ annotation=annotation,
86
+ inner_type=inner_type,
87
+ direction=direction,
71
88
  )
72
- and isinstance(object_, typing.List)
89
+ for item in object_
90
+ }
91
+ elif (
92
+ (
93
+ typing_extensions.get_origin(clean_type) == typing.List
94
+ or typing_extensions.get_origin(clean_type) == list
95
+ or clean_type == typing.List
73
96
  )
74
- or (
75
- (
76
- typing_extensions.get_origin(clean_type) == typing.Set
77
- or typing_extensions.get_origin(clean_type) == set
78
- or clean_type == typing.Set
79
- )
80
- and isinstance(object_, typing.Set)
97
+ and isinstance(object_, typing.List)
98
+ ) or (
99
+ (
100
+ typing_extensions.get_origin(clean_type) == typing.Sequence
101
+ or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
102
+ or clean_type == typing.Sequence
81
103
  )
82
- or (
83
- (
84
- typing_extensions.get_origin(clean_type) == typing.Sequence
85
- or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
86
- or clean_type == typing.Sequence
104
+ and isinstance(object_, typing.Sequence)
105
+ ):
106
+ inner_type = typing_extensions.get_args(clean_type)[0]
107
+ return [
108
+ convert_and_respect_annotation_metadata(
109
+ object_=item,
110
+ annotation=annotation,
111
+ inner_type=inner_type,
112
+ direction=direction,
87
113
  )
88
- and isinstance(object_, typing.Sequence)
89
- )
90
- )
91
- ):
92
- inner_type = typing_extensions.get_args(clean_type)[0]
93
- return [
94
- convert_and_respect_annotation_metadata(object_=item, annotation=annotation, inner_type=inner_type)
95
- for item in object_
96
- ]
114
+ for item in object_
115
+ ]
97
116
 
98
117
  if typing_extensions.get_origin(clean_type) == typing.Union:
99
118
  # We should be able to ~relatively~ safely try to convert keys against all
@@ -101,7 +120,12 @@ def convert_and_respect_annotation_metadata(
101
120
  # of the same name to a different name from another member
102
121
  # Or if another member aliases a field of the same name that another member does not.
103
122
  for member in typing_extensions.get_args(clean_type):
104
- object_ = convert_and_respect_annotation_metadata(object_=object_, annotation=annotation, inner_type=member)
123
+ object_ = convert_and_respect_annotation_metadata(
124
+ object_=object_,
125
+ annotation=annotation,
126
+ inner_type=member,
127
+ direction=direction,
128
+ )
105
129
  return object_
106
130
 
107
131
  annotated_type = _get_annotation(annotation)
@@ -113,16 +137,34 @@ def convert_and_respect_annotation_metadata(
113
137
  return object_
114
138
 
115
139
 
116
- def _convert_typeddict(object_: typing.Mapping[str, object], expected_type: typing.Any) -> typing.Mapping[str, object]:
140
+ def _convert_mapping(
141
+ object_: typing.Mapping[str, object],
142
+ expected_type: typing.Any,
143
+ direction: typing.Literal["read", "write"],
144
+ ) -> typing.Mapping[str, object]:
117
145
  converted_object: typing.Dict[str, object] = {}
118
146
  annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
147
+ aliases_to_field_names = _get_alias_to_field_name(annotations)
119
148
  for key, value in object_.items():
120
- type_ = annotations.get(key)
149
+ if direction == "read" and key in aliases_to_field_names:
150
+ dealiased_key = aliases_to_field_names.get(key)
151
+ if dealiased_key is not None:
152
+ type_ = annotations.get(dealiased_key)
153
+ else:
154
+ type_ = annotations.get(key)
155
+ # Note you can't get the annotation by the field name if you're in read mode, so you must check the aliases map
156
+ #
157
+ # So this is effectively saying if we're in write mode, and we don't have a type, or if we're in read mode and we don't have an alias
158
+ # then we can just pass the value through as is
121
159
  if type_ is None:
122
160
  converted_object[key] = value
161
+ elif direction == "read" and key not in aliases_to_field_names:
162
+ converted_object[key] = convert_and_respect_annotation_metadata(
163
+ object_=value, annotation=type_, direction=direction
164
+ )
123
165
  else:
124
- converted_object[_alias_key(key, type_)] = convert_and_respect_annotation_metadata(
125
- object_=value, annotation=type_
166
+ converted_object[_alias_key(key, type_, direction, aliases_to_field_names)] = (
167
+ convert_and_respect_annotation_metadata(object_=value, annotation=type_, direction=direction)
126
168
  )
127
169
  return converted_object
128
170
 
@@ -156,7 +198,39 @@ def _remove_annotations(type_: typing.Any) -> typing.Any:
156
198
  return type_
157
199
 
158
200
 
159
- def _alias_key(key: str, type_: typing.Any) -> str:
201
+ def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]:
202
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
203
+ return _get_alias_to_field_name(annotations)
204
+
205
+
206
+ def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]:
207
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
208
+ return _get_field_to_alias_name(annotations)
209
+
210
+
211
+ def _get_alias_to_field_name(
212
+ field_to_hint: typing.Dict[str, typing.Any],
213
+ ) -> typing.Dict[str, str]:
214
+ aliases = {}
215
+ for field, hint in field_to_hint.items():
216
+ maybe_alias = _get_alias_from_type(hint)
217
+ if maybe_alias is not None:
218
+ aliases[maybe_alias] = field
219
+ return aliases
220
+
221
+
222
+ def _get_field_to_alias_name(
223
+ field_to_hint: typing.Dict[str, typing.Any],
224
+ ) -> typing.Dict[str, str]:
225
+ aliases = {}
226
+ for field, hint in field_to_hint.items():
227
+ maybe_alias = _get_alias_from_type(hint)
228
+ if maybe_alias is not None:
229
+ aliases[field] = maybe_alias
230
+ return aliases
231
+
232
+
233
+ def _get_alias_from_type(type_: typing.Any) -> typing.Optional[str]:
160
234
  maybe_annotated_type = _get_annotation(type_)
161
235
 
162
236
  if maybe_annotated_type is not None:
@@ -166,5 +240,15 @@ def _alias_key(key: str, type_: typing.Any) -> str:
166
240
  for annotation in annotations:
167
241
  if isinstance(annotation, FieldMetadata) and annotation.alias is not None:
168
242
  return annotation.alias
243
+ return None
244
+
169
245
 
170
- return key
246
+ def _alias_key(
247
+ key: str,
248
+ type_: typing.Any,
249
+ direction: typing.Literal["read", "write"],
250
+ aliases_to_field_names: typing.Dict[str, str],
251
+ ) -> str:
252
+ if direction == "read":
253
+ return aliases_to_field_names.get(key, key)
254
+ return _get_alias_from_type(type_=type_) or key
@@ -112,7 +112,9 @@ class AdHocClient:
112
112
  ),
113
113
  id="string",
114
114
  state="ENABLED",
115
- cache_config=EphemeralPromptCacheConfigRequest(),
115
+ cache_config=EphemeralPromptCacheConfigRequest(
116
+ type={"key": "value"},
117
+ ),
116
118
  )
117
119
  ],
118
120
  expand_meta=AdHocExpandMetaRequest(
@@ -288,7 +290,9 @@ class AsyncAdHocClient:
288
290
  ),
289
291
  id="string",
290
292
  state="ENABLED",
291
- cache_config=EphemeralPromptCacheConfigRequest(),
293
+ cache_config=EphemeralPromptCacheConfigRequest(
294
+ type={"key": "value"},
295
+ ),
292
296
  )
293
297
  ],
294
298
  expand_meta=AdHocExpandMetaRequest(
@@ -229,8 +229,18 @@ class TestSuitesClient:
229
229
  id="string",
230
230
  data=CreateTestSuiteTestCaseRequest(
231
231
  label="string",
232
- input_values=[NamedTestCaseStringVariableValueRequest()],
233
- evaluation_values=[NamedTestCaseStringVariableValueRequest()],
232
+ input_values=[
233
+ NamedTestCaseStringVariableValueRequest(
234
+ value="string",
235
+ name="string",
236
+ )
237
+ ],
238
+ evaluation_values=[
239
+ NamedTestCaseStringVariableValueRequest(
240
+ value="string",
241
+ name="string",
242
+ )
243
+ ],
234
244
  external_id="string",
235
245
  ),
236
246
  )
@@ -548,9 +558,17 @@ class AsyncTestSuitesClient:
548
558
  id="string",
549
559
  data=CreateTestSuiteTestCaseRequest(
550
560
  label="string",
551
- input_values=[NamedTestCaseStringVariableValueRequest()],
561
+ input_values=[
562
+ NamedTestCaseStringVariableValueRequest(
563
+ value="string",
564
+ name="string",
565
+ )
566
+ ],
552
567
  evaluation_values=[
553
- NamedTestCaseStringVariableValueRequest()
568
+ NamedTestCaseStringVariableValueRequest(
569
+ value="string",
570
+ name="string",
571
+ )
554
572
  ],
555
573
  external_id="string",
556
574
  ),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.8.9
3
+ Version: 0.8.10
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.8,<4.0
@@ -1,17 +1,17 @@
1
1
  vellum/__init__.py,sha256=ZjILSZ1gKX9YUZjjOzr0wngRMV7aYaCvuCXgoxt7n2o,30148
2
- vellum/client.py,sha256=FzaKpt5tvigJpdckmhhtIZemZnt_qM-50WfXENgyA74,101094
2
+ vellum/client.py,sha256=tsLLtZbwPASP8Cdh1RF19pOuNmZbBKFkUiplU9X190Q,101256
3
3
  vellum/core/__init__.py,sha256=FzSvKbXjuM18Hdk3iGK-jsGY_DfouyRS659thZV5c1Y,1394
4
4
  vellum/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
5
- vellum/core/client_wrapper.py,sha256=ufeiagHJMhTy-ivorHYOOgDbHND76t2jMmfgX9VcJN8,1897
5
+ vellum/core/client_wrapper.py,sha256=M-BpiKCvswDs5lRLcJdm1cAw-R1gKHfMTOJcWjskwVk,1898
6
6
  vellum/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
7
7
  vellum/core/file.py,sha256=vliNmlB7PbDfi4EKiVPNq5QaGXJ4zlDBGupv7Qciy7g,1520
8
8
  vellum/core/http_client.py,sha256=rZSidd9LazCjduvdBhZ7GDs4iGfn-OAfRGsDXB1z8f4,18882
9
9
  vellum/core/jsonable_encoder.py,sha256=qaF1gtgH-kQZb4kJskETwcCsOPUof-NnYVdszHkb-dM,3656
10
- vellum/core/pydantic_utilities.py,sha256=F91xFonOmTu3AdWJtQduQoS8Gn_K7y8ln9IT8LU6WPM,7549
10
+ vellum/core/pydantic_utilities.py,sha256=h_XylfOhkKxX6ZxL5CVfXylOzR4oc5AjCVC5yTsR4aU,9138
11
11
  vellum/core/query_encoder.py,sha256=ekulqNd0j8TgD7ox-Qbz7liqX8-KP9blvT9DsRCenYM,2144
12
12
  vellum/core/remove_none_from_dict.py,sha256=EU9SGgYidWq7SexuJbNs4-PZ-5Bl3Vppd864mS6vQZw,342
13
13
  vellum/core/request_options.py,sha256=5cCGt5AEGgtP5xifDl4oVQUmSjlIA8FmRItAlJawM18,1417
14
- vellum/core/serialization.py,sha256=X1W2KRWxKwOL7k4EatJMas1e2CCLfUOI77qrj8AvLGc,5862
14
+ vellum/core/serialization.py,sha256=5evS9ZBT8F0_GUAfzb6FQvdgw4JKuHFBlEoqZ8Y8-DU,8970
15
15
  vellum/environment.py,sha256=bcAFjoE9XXd7tiysYS90Os669IJmUMZS2JZ_ZQn0Dpg,498
16
16
  vellum/errors/__init__.py,sha256=HZB8vVqzDNx0M2uFJ05S5RcGTH95iVDl4v3rQ4xRqSw,343
17
17
  vellum/errors/bad_request_error.py,sha256=_EbO8mWqN9kFZPvIap8qa1lL_EWkRcsZe1HKV9GDWJY,264
@@ -30,7 +30,7 @@ vellum/lib/utils/paginator.py,sha256=yDvgehocYBDclLt5SewZH4hCIyq0yLHdBzkyPCoYPjs
30
30
  vellum/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  vellum/resources/__init__.py,sha256=iaTrngunVag3wUnyP3TlA8lG55RUCYw4qgdlZXzhi2Q,806
32
32
  vellum/resources/ad_hoc/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
33
- vellum/resources/ad_hoc/client.py,sha256=cXVuw1ETy_oQkBtiiU8NVljB-Xp0iVZ6GrpfXv8m5pA,13862
33
+ vellum/resources/ad_hoc/client.py,sha256=7WwFing-VwbfZJbwBRJCkJ3ypXJ7jMSt4kaCVSTW3gk,14006
34
34
  vellum/resources/deployments/__init__.py,sha256=AE0TcFwLrLBljM0ZDX-pPw4Kqt-1f5JDpIok2HS80QI,157
35
35
  vellum/resources/deployments/client.py,sha256=A_x9lFFFNiiwggPcrMfP88vv5F0FuLo39Ek36WEfJpE,28516
36
36
  vellum/resources/deployments/types/__init__.py,sha256=IhwnmoXJ0r_QEhh1b2tBcaAm_x3fWMVuIhYmAapp_ZA,183
@@ -48,7 +48,7 @@ vellum/resources/sandboxes/client.py,sha256=RDFDge2gkI6Kpo3VhlRISKS8wHDp7MYh83XV
48
48
  vellum/resources/test_suite_runs/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
49
49
  vellum/resources/test_suite_runs/client.py,sha256=laE40piDiurzmO1mwStY0ebsxQpTuETgiCAewtSrNk8,14192
50
50
  vellum/resources/test_suites/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
51
- vellum/resources/test_suites/client.py,sha256=NxlaHkupz_i3JqxgqV5LmNl_LVkyFSFSebTPH1hd6SU,23105
51
+ vellum/resources/test_suites/client.py,sha256=Sy_mXyAwObTwRSPH9gOO8gNZRfx4MlQVV3TxaAdnVx0,23795
52
52
  vellum/resources/workflow_deployments/__init__.py,sha256=-5BCA0kSmW6WUh4gqLuQtHv4zFdt9lccuDwMU5YvEu4,173
53
53
  vellum/resources/workflow_deployments/client.py,sha256=ezSg3EDA5UszvrT15jx7-RoSO8pXRwAIDlqMCJXkNOY,17393
54
54
  vellum/resources/workflow_deployments/types/__init__.py,sha256=rmS_4dtbgLHGNQJ_pOloygrjl4sNbKZjTEKBxbMyz6E,208
@@ -484,7 +484,7 @@ vellum/types/workflow_result_event_output_data_search_results.py,sha256=U34IK7Zv
484
484
  vellum/types/workflow_result_event_output_data_string.py,sha256=tM3kgh6tEhD0dFEb_7UU0-UspeN4pUdINCcCrD64W74,1228
485
485
  vellum/types/workflow_stream_event.py,sha256=Wn3Yzuy9MqWAeo8tEaXDTKDEbJoA8DdYdMVq8EKuhu8,361
486
486
  vellum/version.py,sha256=jq-1PlAYxN9AXuaZqbYk9ak27SgE2lw9Ia5gx1b1gVI,76
487
- vellum_ai-0.8.9.dist-info/LICENSE,sha256=CcaljEIoOBaU-wItPH4PmM_mDCGpyuUY0Er1BGu5Ti8,1073
488
- vellum_ai-0.8.9.dist-info/METADATA,sha256=ApCmRTG3GYNsYwkGWltiBbBqNx03p4HsJzr9ikoVJtA,4394
489
- vellum_ai-0.8.9.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
490
- vellum_ai-0.8.9.dist-info/RECORD,,
487
+ vellum_ai-0.8.10.dist-info/LICENSE,sha256=CcaljEIoOBaU-wItPH4PmM_mDCGpyuUY0Er1BGu5Ti8,1073
488
+ vellum_ai-0.8.10.dist-info/METADATA,sha256=QHpzDwJPFH8HiKsH-zgInPuvI39uSU4MtqDrQpIJzwI,4395
489
+ vellum_ai-0.8.10.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
490
+ vellum_ai-0.8.10.dist-info/RECORD,,