vellum-ai 0.14.13__py3-none-any.whl → 0.14.14__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.
@@ -18,7 +18,7 @@ class BaseClientWrapper:
18
18
  headers: typing.Dict[str, str] = {
19
19
  "X-Fern-Language": "Python",
20
20
  "X-Fern-SDK-Name": "vellum-ai",
21
- "X-Fern-SDK-Version": "0.14.13",
21
+ "X-Fern-SDK-Version": "0.14.14",
22
22
  }
23
23
  headers["X_API_KEY"] = self.api_key
24
24
  return headers
vellum/plugins/utils.py CHANGED
@@ -1,11 +1,19 @@
1
- from pydantic.plugin import _loader as _pydantic_plugin_loader
2
-
3
- from vellum.plugins.pydantic import pydantic_plugin
1
+ import pydantic
4
2
 
3
+ IS_PYDANTIC_V1 = pydantic.VERSION.startswith("1.")
5
4
  _loaded = False
6
5
 
7
6
 
8
7
  def load_runtime_plugins() -> None:
8
+ if IS_PYDANTIC_V1:
9
+ # Pydantic plugins are only available in v2, so we defer the imports
10
+ # below until we confirm we are running a supported version of pydantic
11
+ return
12
+
13
+ from pydantic.plugin import _loader as _pydantic_plugin_loader
14
+
15
+ from vellum.plugins.pydantic import pydantic_plugin
16
+
9
17
  global _loaded
10
18
  if _loaded:
11
19
  return
@@ -93,6 +93,7 @@ class NodeExecutionStreamingEvent(_BaseNodeEvent):
93
93
  class NodeExecutionFulfilledBody(_BaseNodeExecutionBody, Generic[OutputsType]):
94
94
  outputs: OutputsType
95
95
  invoked_ports: InvokedPorts = None
96
+ mocked: Optional[bool] = None
96
97
 
97
98
  @field_serializer("outputs")
98
99
  def serialize_outputs(self, outputs: OutputsType, _info: Any) -> Dict[str, Any]:
@@ -117,6 +118,10 @@ class NodeExecutionFulfilledEvent(_BaseNodeEvent, Generic[OutputsType]):
117
118
  def invoked_ports(self) -> InvokedPorts:
118
119
  return self.body.invoked_ports
119
120
 
121
+ @property
122
+ def mocked(self) -> Optional[bool]:
123
+ return self.body.mocked
124
+
120
125
 
121
126
  class NodeExecutionRejectedBody(_BaseNodeExecutionBody):
122
127
  error: WorkflowError
@@ -328,6 +328,7 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__))
328
328
  "name": "default",
329
329
  }
330
330
  ],
331
+ "mocked": None,
331
332
  },
332
333
  "parent": None,
333
334
  },
@@ -365,6 +366,40 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__))
365
366
  "name": "default",
366
367
  }
367
368
  ],
369
+ "mocked": None,
370
+ },
371
+ "parent": None,
372
+ },
373
+ ),
374
+ (
375
+ NodeExecutionFulfilledEvent(
376
+ id=UUID("123e4567-e89b-12d3-a456-426614174000"),
377
+ timestamp=datetime(2024, 1, 1, 12, 0, 0),
378
+ trace_id=UUID("123e4567-e89b-12d3-a456-426614174000"),
379
+ span_id=UUID("123e4567-e89b-12d3-a456-426614174000"),
380
+ body=NodeExecutionFulfilledBody(
381
+ node_definition=MockNode,
382
+ outputs=MockNode.Outputs(
383
+ example="foo",
384
+ ),
385
+ mocked=True,
386
+ ),
387
+ ),
388
+ {
389
+ "id": "123e4567-e89b-12d3-a456-426614174000",
390
+ "api_version": "2024-10-25",
391
+ "timestamp": "2024-01-01T12:00:00",
392
+ "trace_id": "123e4567-e89b-12d3-a456-426614174000",
393
+ "span_id": "123e4567-e89b-12d3-a456-426614174000",
394
+ "name": "node.execution.fulfilled",
395
+ "body": {
396
+ "node_definition": {
397
+ "id": mock_node_uuid,
398
+ "name": "MockNode",
399
+ "module": module_root + ["events", "tests", "test_event"],
400
+ },
401
+ "outputs": {"example": "foo"},
402
+ "mocked": True,
368
403
  },
369
404
  "parent": None,
370
405
  },
@@ -379,6 +414,7 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__))
379
414
  "node.execution.streaming",
380
415
  "node.execution.fulfilled",
381
416
  "fulfilled_node_with_undefined_outputs",
417
+ "mocked_node",
382
418
  ],
383
419
  )
384
420
  def test_event_serialization(event, expected_json):
@@ -283,3 +283,19 @@ def test_templating_node__function_call_as_json():
283
283
  # AND we can access fields directly
284
284
  assert outputs.result["arguments"] == {"key": "value"}
285
285
  assert outputs.result["name"] == "test_function"
286
+
287
+
288
+ def test_templating_node__empty_string_to_list():
289
+ """Test that an empty string output with list output type casts to an empty array."""
290
+
291
+ # GIVEN a templating node that outputs an empty string but has List output type
292
+ class EmptyStringToListTemplateNode(TemplatingNode[BaseState, List[str]]):
293
+ template = """{{ "" }}"""
294
+ inputs = {}
295
+
296
+ # WHEN the node is run
297
+ node = EmptyStringToListTemplateNode()
298
+ outputs = node.run()
299
+
300
+ # THEN the output should be an empty list, not raise an exception
301
+ assert outputs.result == []
@@ -0,0 +1,133 @@
1
+ import pytest
2
+ from typing import List, Union
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from vellum.workflows.errors.types import WorkflowErrorCode
7
+ from vellum.workflows.exceptions import NodeException
8
+ from vellum.workflows.nodes.utils import parse_type_from_str
9
+ from vellum.workflows.types.core import Json
10
+
11
+
12
+ class Person(BaseModel):
13
+ name: str
14
+ age: int
15
+
16
+
17
+ class FunctionCall(BaseModel):
18
+ name: str
19
+ args: List[int]
20
+
21
+
22
+ @pytest.mark.parametrize(
23
+ "input_str, output_type, expected_result",
24
+ [
25
+ ("hello", str, "hello"),
26
+ ("3.14", float, 3.14),
27
+ ("42", int, 42),
28
+ ("True", bool, True),
29
+ ("", List[str], []), # Empty string should return an empty list
30
+ ("[1, 2, 3]", List[int], [1, 2, 3]),
31
+ ('["a", "b", "c"]', List[str], ["a", "b", "c"]),
32
+ ('{"name": "Alice", "age": 30}', Json, {"name": "Alice", "age": 30}),
33
+ (
34
+ '{"type": "FUNCTION_CALL", "value": {"name": "test", "args": [1, 2]}}',
35
+ Json,
36
+ {"name": "test", "args": [1, 2]},
37
+ ),
38
+ ("42", Union[int, str], 42),
39
+ ("hello", Union[int, str], "hello"),
40
+ ],
41
+ ids=[
42
+ "str",
43
+ "float",
44
+ "int",
45
+ "bool",
46
+ "empty_list",
47
+ "list_of_int",
48
+ "list_of_str",
49
+ "simple_json",
50
+ "function_call_json",
51
+ "union_int",
52
+ "union_str",
53
+ ],
54
+ )
55
+ def test_parse_type_from_str_basic_cases(input_str, output_type, expected_result):
56
+ result = parse_type_from_str(input_str, output_type)
57
+ assert result == expected_result
58
+
59
+
60
+ def test_parse_type_from_str_pydantic_models():
61
+ person_json = '{"name": "Alice", "age": 30}'
62
+ person = parse_type_from_str(person_json, Person)
63
+ assert isinstance(person, Person)
64
+ assert person.name == "Alice"
65
+ assert person.age == 30
66
+
67
+ function_json = '{"name": "test", "args": [1, 2]}'
68
+ function = parse_type_from_str(function_json, FunctionCall)
69
+ assert isinstance(function, FunctionCall)
70
+ assert function.name == "test"
71
+ assert function.args == [1, 2]
72
+
73
+ function_call_json = '{"value": {"name": "test", "args": [1, 2]}}'
74
+ function = parse_type_from_str(function_call_json, FunctionCall)
75
+ assert isinstance(function, FunctionCall)
76
+ assert function.name == "test"
77
+ assert function.args == [1, 2]
78
+
79
+
80
+ def test_parse_type_from_str_list_of_models():
81
+ person_list_json = '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]'
82
+ persons = parse_type_from_str(person_list_json, List[Person])
83
+ assert len(persons) == 2
84
+ assert all(isinstance(p, Person) for p in persons)
85
+ assert persons[0].name == "Alice"
86
+ assert persons[0].age == 30
87
+ assert persons[1].name == "Bob"
88
+ assert persons[1].age == 25
89
+
90
+
91
+ @pytest.mark.parametrize(
92
+ "input_str, output_type, expected_exception, expected_code, expected_message",
93
+ [
94
+ (
95
+ "{invalid json}",
96
+ List[str],
97
+ NodeException,
98
+ WorkflowErrorCode.INVALID_OUTPUTS,
99
+ "Invalid JSON Array format for result_as_str",
100
+ ),
101
+ (
102
+ "{invalid json}",
103
+ Person,
104
+ NodeException,
105
+ WorkflowErrorCode.INVALID_OUTPUTS,
106
+ "Invalid JSON format for result_as_str",
107
+ ),
108
+ (
109
+ "{invalid json}",
110
+ Json,
111
+ NodeException,
112
+ WorkflowErrorCode.INVALID_OUTPUTS,
113
+ "Invalid JSON format for result_as_str",
114
+ ),
115
+ ('{"name": "Alice"}', List[str], ValueError, None, "Expected a list of items for result_as_str, received dict"),
116
+ ("data", object, ValueError, None, "Unsupported output type: <class 'object'>"),
117
+ ],
118
+ ids=[
119
+ "invalid_json_list",
120
+ "invalid_json_model",
121
+ "invalid_json_json_type",
122
+ "non_list_for_list",
123
+ "unsupported_type",
124
+ ],
125
+ )
126
+ def test_parse_type_from_str_error_cases(input_str, output_type, expected_exception, expected_code, expected_message):
127
+ with pytest.raises(expected_exception) as excinfo:
128
+ parse_type_from_str(input_str, output_type)
129
+
130
+ if expected_code:
131
+ assert excinfo.value.code == expected_code
132
+
133
+ assert expected_message in str(excinfo.value)
@@ -95,10 +95,18 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any:
95
95
  return bool(result_as_str)
96
96
 
97
97
  if get_origin(output_type) is list:
98
+ # Handle empty string case for list types by returning an empty list
99
+ if not result_as_str.strip():
100
+ return []
101
+
98
102
  try:
99
103
  data = json.loads(result_as_str)
100
104
  except json.JSONDecodeError:
101
- raise ValueError("Invalid JSON Array format for result_as_str")
105
+ # raise ValueError("Invalid JSON Array format for result_as_str")
106
+ raise NodeException(
107
+ code=WorkflowErrorCode.INVALID_OUTPUTS,
108
+ message="Invalid JSON Array format for result_as_str",
109
+ )
102
110
 
103
111
  if not isinstance(data, list):
104
112
  raise ValueError(f"Expected a list of items for result_as_str, received {data.__class__.__name__}")
@@ -117,7 +125,10 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any:
117
125
  return data["value"]
118
126
  return data
119
127
  except json.JSONDecodeError:
120
- raise ValueError("Invalid JSON format for result_as_str")
128
+ raise NodeException(
129
+ code=WorkflowErrorCode.INVALID_OUTPUTS,
130
+ message="Invalid JSON format for result_as_str",
131
+ )
121
132
 
122
133
  if get_origin(output_type) is Union:
123
134
  for inner_type in get_args(output_type):
@@ -140,7 +151,10 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any:
140
151
  data = data["value"]
141
152
  return output_type.model_validate(data)
142
153
  except json.JSONDecodeError:
143
- raise ValueError("Invalid JSON format for result_as_str")
154
+ raise NodeException(
155
+ code=WorkflowErrorCode.INVALID_OUTPUTS,
156
+ message="Invalid JSON format for result_as_str",
157
+ )
144
158
 
145
159
  raise ValueError(f"Unsupported output type: {output_type}")
146
160
 
@@ -200,7 +200,7 @@ class WorkflowRunner(Generic[StateType]):
200
200
  parent=parent_context,
201
201
  )
202
202
  node_run_response: NodeRunResponse
203
- was_mocked = False
203
+ was_mocked: Optional[bool] = None
204
204
  mock_candidates = self.workflow.context.node_output_mocks_map.get(node.Outputs) or []
205
205
  for mock_candidate in mock_candidates:
206
206
  if mock_candidate.when_condition.resolve(node.state):
@@ -315,6 +315,7 @@ class WorkflowRunner(Generic[StateType]):
315
315
  node_definition=node.__class__,
316
316
  outputs=outputs,
317
317
  invoked_ports=invoked_ports,
318
+ mocked=was_mocked,
318
319
  ),
319
320
  parent=parent_context,
320
321
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.13
3
+ Version: 0.14.14
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -123,7 +123,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
123
123
  vellum/client/__init__.py,sha256=tKtdM1_GqmGq1gpi9ydWD_T-MM7fPn8QdHh8ww19cNI,117564
124
124
  vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
125
125
  vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
126
- vellum/client/core/client_wrapper.py,sha256=rm58d4E5Lrfg-SwnN1AtE5vFfVb1Qy6a5GyVyEmNWvU,1869
126
+ vellum/client/core/client_wrapper.py,sha256=F65g9wG6SXfGPkAao7k0GN7doBs1E434iyOswOpG3iE,1869
127
127
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
128
128
  vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
129
129
  vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
@@ -720,7 +720,7 @@ vellum/evaluations/utils/exceptions.py,sha256=dXMAkzqbHV_AP5FjjbegPlfUE0zQDlpA3q
720
720
  vellum/evaluations/utils/paginator.py,sha256=rEED_BJAXAM6tM1yMwHePNzszjq_tTq4NbQvi1jWQ_Q,697
721
721
  vellum/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
722
722
  vellum/plugins/pydantic.py,sha256=BMUwC4OkxtNf6hpLwb0T4MBUKgkGy55T_5Ww7GHpHYo,3068
723
- vellum/plugins/utils.py,sha256=U9ZY9KdE3RRvbcG01hXxu9CvfJD6Fo7nJDgcHjQn0FI,606
723
+ vellum/plugins/utils.py,sha256=cPmxE9R2CK1bki2jKE8rB-G9zMf2pzHjSPDHFPXwd3Q,878
724
724
  vellum/plugins/vellum_mypy.py,sha256=QTuMSq6PiZW1dyTUZ5Bf1d4XkgFj0TKAgZLP8f4UgL4,27914
725
725
  vellum/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
726
726
  vellum/prompts/blocks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1312,9 +1312,9 @@ vellum/workflows/environment/environment.py,sha256=0XhJPBs8YASWmvPx8bkSdCvcbDmzp
1312
1312
  vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
1313
1313
  vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7n5Q,3640
1314
1314
  vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
1315
- vellum/workflows/events/node.py,sha256=uHT6If0esgZ3nLjrjmUPTKf3qbjGhoV_x5YKpjDBDcU,5280
1315
+ vellum/workflows/events/node.py,sha256=jbmNHjdp331Q1IRK-AWtAxwF6Lidb9R7__N5rQuilE8,5401
1316
1316
  vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1317
- vellum/workflows/events/tests/test_event.py,sha256=uRfMwSOqU-ROeZKCEngGvvJYlOZuxBhnC3qH5AGi3fM,15399
1317
+ vellum/workflows/events/tests/test_event.py,sha256=sHcKhZPDPtzZfTmehL4NORA_StR4M6nZDcx9kz3Avo0,16866
1318
1318
  vellum/workflows/events/types.py,sha256=AeTJaQt_fNHDLI4nyBzo7XrW9QQybRC09AKzu3kEYEE,3575
1319
1319
  vellum/workflows/events/workflow.py,sha256=QoSHyIOpuVacbR7POf7h104miTOhCjtO2udnYximJGs,6851
1320
1320
  vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
@@ -1383,7 +1383,7 @@ vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TI
1383
1383
  vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
1384
1384
  vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
1385
1385
  vellum/workflows/nodes/core/templating_node/node.py,sha256=-JIqLUv6Xpx_LTVZt7whQ2X2VatgHDdTxjMrz64luEs,3721
1386
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=ldnmSASx0TfAnT3ZvU0AXtN0diZGrfySiXipuJIIzWU,9055
1386
+ vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=MHofz-BwAgt7EXkab8VIyacYznDEIJ7Er7MJUaxNQQo,9614
1387
1387
  vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
1388
1388
  vellum/workflows/nodes/core/try_node/node.py,sha256=5ux1l2HO12FBFFyhz6j-4yfBYVrqgT2maTAne_GnNDk,4434
1389
1389
  vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1453,7 +1453,8 @@ vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1
1453
1453
  vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
1454
1454
  vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1455
1455
  vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
1456
- vellum/workflows/nodes/utils.py,sha256=uaTPGYp4utenz_QDghqQ23Q1iCsGHQ40nNZh1g9H9WI,7117
1456
+ vellum/workflows/nodes/tests/test_utils.py,sha256=7PtdV_fzl56agx0IDitdqOmqUO9cQZmJww-3ToxzSqA,4174
1457
+ vellum/workflows/nodes/utils.py,sha256=b-U8xjUpGswaoEiav5tU_OFKB26GkYFzuko9XCMU_Fo,7627
1457
1458
  vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
1458
1459
  vellum/workflows/outputs/base.py,sha256=b4Dnha1miKu3uFJYptKKflIHNuajPF2BNKy0BTt8Tjc,8622
1459
1460
  vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
@@ -1475,7 +1476,7 @@ vellum/workflows/references/workflow_input.py,sha256=86IuhlBz-9cGxeUzizyjdp482aj
1475
1476
  vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
1476
1477
  vellum/workflows/resolvers/base.py,sha256=WHra9LRtlTuB1jmuNqkfVE2JUgB61Cyntn8f0b0WZg4,411
1477
1478
  vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
1478
- vellum/workflows/runner/runner.py,sha256=_p19T1woplSxZGabZuSUFBKSYBrXADrM7b_1YnWVN3g,31013
1479
+ vellum/workflows/runner/runner.py,sha256=fS21u0LIyhxT4T6YQPgonVuH8X8TgD5BrsbVxPUWfuM,31071
1479
1480
  vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
1480
1481
  vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
1481
1482
  vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
@@ -1511,8 +1512,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
1511
1512
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1512
1513
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=NRteiICyJvDM5zrtUfq2fZoXcGQVaWC9xmNlLLVW0cU,7979
1513
1514
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
1514
- vellum_ai-0.14.13.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1515
- vellum_ai-0.14.13.dist-info/METADATA,sha256=y44fYKH3DaYDbx8hhtZFAtWbGESUBWDUV-2W_JL-XiI,5408
1516
- vellum_ai-0.14.13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1517
- vellum_ai-0.14.13.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1518
- vellum_ai-0.14.13.dist-info/RECORD,,
1515
+ vellum_ai-0.14.14.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1516
+ vellum_ai-0.14.14.dist-info/METADATA,sha256=UKCcEJ4XtYH1PteNKqVZjzrWn3-WMYYFFEl9SLs_lF4,5408
1517
+ vellum_ai-0.14.14.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1518
+ vellum_ai-0.14.14.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1519
+ vellum_ai-0.14.14.dist-info/RECORD,,