vellum-workflow-server 0.14.69__tar.gz → 0.14.70.post1__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.
Potentially problematic release.
This version of vellum-workflow-server might be problematic. Click here for more details.
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/PKG-INFO +2 -2
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/pyproject.toml +2 -2
- vellum_workflow_server-0.14.70.post1/src/workflow_server/api/tests/test_input_display_mapping.py +61 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/tests/test_workflow_view_stream_workflow_route.py +41 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/core/executor.py +3 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/core/workflow_executor_context.py +1 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/tests/test_utils.py +53 -2
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/utils.py +18 -2
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/README.md +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/__init__.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/__init__.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/auth_middleware.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/healthz_view.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/tests/__init__.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/tests/test_workflow_view.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/api/workflow_view.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/code_exec_runner.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/config.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/core/__init__.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/core/cancel_workflow.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/core/events.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/server.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/start.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/__init__.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/exit_handler.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/log_proxy.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/oom_killer.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/sentry.py +0 -0
- {vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/utils/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vellum-workflow-server
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.70.post1
|
|
4
4
|
Summary:
|
|
5
5
|
License: AGPL
|
|
6
6
|
Requires-Python: >=3.9.0,<4
|
|
@@ -28,7 +28,7 @@ Requires-Dist: pebble (==5.0.7)
|
|
|
28
28
|
Requires-Dist: pyjwt (==2.10.0)
|
|
29
29
|
Requires-Dist: python-dotenv (==1.0.1)
|
|
30
30
|
Requires-Dist: sentry-sdk[flask] (==2.20.0)
|
|
31
|
-
Requires-Dist: vellum-ai (==0.14.
|
|
31
|
+
Requires-Dist: vellum-ai (==0.14.70)
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
|
|
34
34
|
# Vellum Workflow Runner Server
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "vellum-workflow-server"
|
|
3
|
-
version = "0.14.
|
|
3
|
+
version = "0.14.70.post1"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = []
|
|
@@ -41,7 +41,7 @@ flask = "2.3.3"
|
|
|
41
41
|
orderly-set = "5.2.2"
|
|
42
42
|
pebble = "5.0.7"
|
|
43
43
|
gunicorn = "23.0.0"
|
|
44
|
-
vellum-ai = "0.14.
|
|
44
|
+
vellum-ai = "0.14.70"
|
|
45
45
|
python-dotenv = "1.0.1"
|
|
46
46
|
sentry-sdk = {extras = ["flask"], version = "2.20.0"}
|
|
47
47
|
|
vellum_workflow_server-0.14.70.post1/src/workflow_server/api/tests/test_input_display_mapping.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from uuid import uuid4
|
|
2
|
+
|
|
3
|
+
from workflow_server.server import create_app
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_input_conversion_with_display_mapping():
|
|
7
|
+
"""
|
|
8
|
+
Test that validates input conversion behavior for future WorkflowDisplay refactor.
|
|
9
|
+
|
|
10
|
+
This test demonstrates the expected behavior when inputs are converted from UI names
|
|
11
|
+
to SDK attribute names using WorkflowDisplay's inputs_display mapping, rather than
|
|
12
|
+
the current snake_case conversion approach.
|
|
13
|
+
|
|
14
|
+
The test passes on main branch by using the current conversion logic, but establishes
|
|
15
|
+
the expected input/output patterns for the future refactor.
|
|
16
|
+
"""
|
|
17
|
+
span_id = uuid4()
|
|
18
|
+
request_body = {
|
|
19
|
+
"execution_id": str(span_id),
|
|
20
|
+
"inputs": [
|
|
21
|
+
{"name": "User Message", "type": "STRING", "value": "Hello world"},
|
|
22
|
+
{"name": "123-config", "type": "STRING", "value": "config-value"},
|
|
23
|
+
{"name": "API-Key", "type": "STRING", "value": "test-key"},
|
|
24
|
+
],
|
|
25
|
+
"environment_api_key": "test",
|
|
26
|
+
"module": "workflow",
|
|
27
|
+
"timeout": 360,
|
|
28
|
+
"files": {
|
|
29
|
+
"__init__.py": "",
|
|
30
|
+
"workflow.py": """
|
|
31
|
+
from vellum.workflows import BaseWorkflow
|
|
32
|
+
from vellum.workflows.state import BaseState
|
|
33
|
+
from .inputs import Inputs
|
|
34
|
+
|
|
35
|
+
class Workflow(BaseWorkflow[Inputs, BaseState]):
|
|
36
|
+
class Outputs(BaseWorkflow.Outputs):
|
|
37
|
+
result = "success"
|
|
38
|
+
""",
|
|
39
|
+
"inputs.py": """
|
|
40
|
+
from vellum.workflows.inputs import BaseInputs
|
|
41
|
+
|
|
42
|
+
class Inputs(BaseInputs):
|
|
43
|
+
user_message: str
|
|
44
|
+
input_123_config: str
|
|
45
|
+
api_key: str
|
|
46
|
+
""",
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
flask_app = create_app()
|
|
51
|
+
with flask_app.test_client() as test_client:
|
|
52
|
+
response = test_client.post("/workflow/stream", json=request_body)
|
|
53
|
+
status_code = response.status_code
|
|
54
|
+
|
|
55
|
+
assert status_code == 200, f"Request failed with status {status_code}: {response.data}"
|
|
56
|
+
|
|
57
|
+
response_lines = [line for line in response.data.decode().split("\n") if line and line not in ["WAITING", "END"]]
|
|
58
|
+
assert len(response_lines) > 0, "No response events received"
|
|
59
|
+
|
|
60
|
+
fulfilled_events = [line for line in response_lines if "workflow.execution.fulfilled" in line]
|
|
61
|
+
assert len(fulfilled_events) > 0, "No workflow.execution.fulfilled event received"
|
|
@@ -743,3 +743,44 @@ class EndNodeDisplay(BaseNodeDisplay[EndNode]):
|
|
|
743
743
|
assert len(events) > 3, json.dumps(events[-1])
|
|
744
744
|
assert events[2]["name"] == "node.execution.initiated", json.dumps(events[-1])
|
|
745
745
|
assert events[2]["body"]["inputs"] == {"fruit": "cherry"}
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
def test_stream_workflow_route__with_environment_variables(both_stream_types):
|
|
749
|
+
# GIVEN a valid request body with environment variables
|
|
750
|
+
span_id = uuid4()
|
|
751
|
+
request_body = {
|
|
752
|
+
"execution_id": str(span_id),
|
|
753
|
+
"inputs": [],
|
|
754
|
+
"environment_api_key": "test",
|
|
755
|
+
"module": "workflow",
|
|
756
|
+
"timeout": 360,
|
|
757
|
+
"environment_variables": {"TEST_ENV_VAR": "test_value", "ANOTHER_VAR": "another_value"},
|
|
758
|
+
"files": {
|
|
759
|
+
"__init__.py": "",
|
|
760
|
+
"workflow.py": """\
|
|
761
|
+
from vellum.workflows import BaseWorkflow
|
|
762
|
+
from vellum.workflows.references import EnvironmentVariableReference
|
|
763
|
+
|
|
764
|
+
class Workflow(BaseWorkflow):
|
|
765
|
+
class Outputs(BaseWorkflow.Outputs):
|
|
766
|
+
env_var_value = EnvironmentVariableReference(name="TEST_ENV_VAR", default="not_found")
|
|
767
|
+
another_var_value = EnvironmentVariableReference(name="ANOTHER_VAR", default="not_found")
|
|
768
|
+
""",
|
|
769
|
+
},
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
# WHEN we call the stream route
|
|
773
|
+
status_code, events = both_stream_types(request_body)
|
|
774
|
+
|
|
775
|
+
# THEN we get a 200 response
|
|
776
|
+
assert status_code == 200, events
|
|
777
|
+
|
|
778
|
+
# THEN we get the expected events
|
|
779
|
+
assert events[0]["name"] == "vembda.execution.initiated"
|
|
780
|
+
assert events[1]["name"] == "workflow.execution.initiated"
|
|
781
|
+
assert events[2]["name"] == "workflow.execution.fulfilled"
|
|
782
|
+
|
|
783
|
+
# AND the environment variables are accessible in the workflow
|
|
784
|
+
outputs = events[2]["body"]["outputs"]
|
|
785
|
+
assert outputs["env_var_value"] == "test_value"
|
|
786
|
+
assert outputs["another_var_value"] == "another_value"
|
|
@@ -342,6 +342,9 @@ def _create_workflow_context(executor_context: BaseExecutorContext) -> WorkflowC
|
|
|
342
342
|
else:
|
|
343
343
|
environment = VellumEnvironment.PRODUCTION
|
|
344
344
|
|
|
345
|
+
if executor_context.environment_variables:
|
|
346
|
+
os.environ.update(executor_context.environment_variables)
|
|
347
|
+
|
|
345
348
|
return WorkflowContext(
|
|
346
349
|
vellum_client=Vellum(
|
|
347
350
|
api_key=executor_context.environment_api_key,
|
|
@@ -22,6 +22,7 @@ class BaseExecutorContext(UniversalBaseModel):
|
|
|
22
22
|
stream_start_time: int = 0
|
|
23
23
|
vembda_public_url: Optional[str] = None
|
|
24
24
|
node_output_mocks: Optional[list[Any]] = None
|
|
25
|
+
environment_variables: Optional[dict[str, str]] = None
|
|
25
26
|
|
|
26
27
|
@property
|
|
27
28
|
def container_overhead_latency(self) -> int:
|
|
@@ -10,7 +10,11 @@ from vellum import (
|
|
|
10
10
|
VellumError,
|
|
11
11
|
VellumImage,
|
|
12
12
|
)
|
|
13
|
-
from workflow_server.utils.utils import
|
|
13
|
+
from workflow_server.utils.utils import (
|
|
14
|
+
convert_json_inputs_to_vellum,
|
|
15
|
+
to_python_safe_snake_case,
|
|
16
|
+
to_valid_python_identifier,
|
|
17
|
+
)
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
@pytest.mark.parametrize(
|
|
@@ -134,10 +138,57 @@ def test_input_variables_with_uppercase_gets_sanitized():
|
|
|
134
138
|
]
|
|
135
139
|
|
|
136
140
|
expected = {
|
|
137
|
-
"
|
|
141
|
+
"Foo": "<example-string-value>",
|
|
138
142
|
"foo_var": "<another-example-string-value>",
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
actual = convert_json_inputs_to_vellum(inputs)
|
|
142
146
|
|
|
143
147
|
assert expected == actual
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@pytest.mark.parametrize(
|
|
151
|
+
["input_string", "safety_prefix", "expected"],
|
|
152
|
+
[
|
|
153
|
+
("Foo", "input", "Foo"),
|
|
154
|
+
("test", "input", "test"),
|
|
155
|
+
("myVariable", "input", "myVariable"),
|
|
156
|
+
("validName123", "input", "validName123"),
|
|
157
|
+
("Foo-Var", "input", "foo_var"),
|
|
158
|
+
("My Variable", "input", "my_variable"),
|
|
159
|
+
("test-case", "input", "test_case"),
|
|
160
|
+
("CamelCase", "input", "CamelCase"),
|
|
161
|
+
("123", "input", "input_123"),
|
|
162
|
+
("_a", "input", "input_a"),
|
|
163
|
+
("_123", "input", "input_123"),
|
|
164
|
+
("test@#$", "input", "test"),
|
|
165
|
+
("@#$test", "input", "test"),
|
|
166
|
+
("123", "_", "_123"),
|
|
167
|
+
("123", "var", "var_123"),
|
|
168
|
+
("123", "var_", "var_123"),
|
|
169
|
+
],
|
|
170
|
+
)
|
|
171
|
+
def test_to_valid_python_identifier(input_string, safety_prefix, expected):
|
|
172
|
+
actual = to_valid_python_identifier(input_string, safety_prefix)
|
|
173
|
+
assert expected == actual
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize(
|
|
177
|
+
["input_string", "safety_prefix", "expected"],
|
|
178
|
+
[
|
|
179
|
+
("Foo", "input", "foo"),
|
|
180
|
+
("Foo-Var", "input", "foo_var"),
|
|
181
|
+
("CamelCase", "input", "camel_case"),
|
|
182
|
+
("test", "input", "test"),
|
|
183
|
+
("My Variable", "input", "my_variable"),
|
|
184
|
+
("123", "input", "input_123"),
|
|
185
|
+
("_a", "input", "input_a"),
|
|
186
|
+
("_123", "input", "input_123"),
|
|
187
|
+
("123", "_", "_123"),
|
|
188
|
+
("123", "var", "var_123"),
|
|
189
|
+
("123", "var_", "var_123"),
|
|
190
|
+
],
|
|
191
|
+
)
|
|
192
|
+
def test_to_python_safe_snake_case(input_string, safety_prefix, expected):
|
|
193
|
+
actual = to_python_safe_snake_case(input_string, safety_prefix)
|
|
194
|
+
assert expected == actual
|
|
@@ -22,7 +22,7 @@ def convert_json_inputs_to_vellum(inputs: List[dict]) -> dict:
|
|
|
22
22
|
for input in inputs:
|
|
23
23
|
value = input["value"]
|
|
24
24
|
# sync with vellum-python-sdks/ee/codegen/src/context/input-variable-context.ts
|
|
25
|
-
name =
|
|
25
|
+
name = to_valid_python_identifier(input["name"], "input")
|
|
26
26
|
type = input["type"]
|
|
27
27
|
|
|
28
28
|
if type == "CHAT_HISTORY":
|
|
@@ -58,7 +58,7 @@ def to_python_safe_snake_case(string: str, safety_prefix: str = "_") -> str:
|
|
|
58
58
|
# Strip special characters from start of string
|
|
59
59
|
cleaned_str = re.sub(r"^[^a-zA-Z0-9_]+", "", string)
|
|
60
60
|
|
|
61
|
-
# Check if cleaned string starts with a number or underscore
|
|
61
|
+
# Check if cleaned string starts with a number or an underscore
|
|
62
62
|
starts_with_unsafe = bool(re.match(r"^[\d_]", cleaned_str))
|
|
63
63
|
|
|
64
64
|
# Convert to snake case
|
|
@@ -74,6 +74,22 @@ def to_python_safe_snake_case(string: str, safety_prefix: str = "_") -> str:
|
|
|
74
74
|
return f"{cleaned_safety_prefix}{snake_case}" if starts_with_unsafe else snake_case
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
def to_valid_python_identifier(string: str, safety_prefix: str = "_") -> str:
|
|
78
|
+
# Strip special characters from start of string
|
|
79
|
+
cleaned_str = re.sub(r"^[^a-zA-Z0-9_]+", "", string)
|
|
80
|
+
|
|
81
|
+
# Check if cleaned string starts with a number or an underscore
|
|
82
|
+
starts_with_unsafe = bool(re.match(r"^[\d_]", cleaned_str))
|
|
83
|
+
|
|
84
|
+
# Check if the string is already a valid Python identifier (preserve case)
|
|
85
|
+
is_valid_python_identifier = bool(re.match(r"^[a-zA-Z][a-zA-Z0-9]*$", cleaned_str))
|
|
86
|
+
|
|
87
|
+
if is_valid_python_identifier and not starts_with_unsafe:
|
|
88
|
+
return cleaned_str
|
|
89
|
+
|
|
90
|
+
return to_python_safe_snake_case(string, safety_prefix)
|
|
91
|
+
|
|
92
|
+
|
|
77
93
|
def get_obj_size(obj: Any) -> int:
|
|
78
94
|
marked = {id(obj)}
|
|
79
95
|
obj_q = [obj]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vellum_workflow_server-0.14.69 → vellum_workflow_server-0.14.70.post1}/src/workflow_server/start.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|