vellum-workflow-server 1.0.6__tar.gz → 1.0.7__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.

Files changed (33) hide show
  1. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/PKG-INFO +2 -2
  2. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/pyproject.toml +2 -2
  3. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/tests/test_workflow_view.py +79 -0
  4. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/workflow_view.py +45 -0
  5. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/README.md +0 -0
  6. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/__init__.py +0 -0
  7. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/__init__.py +0 -0
  8. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/auth_middleware.py +0 -0
  9. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/healthz_view.py +0 -0
  10. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/tests/__init__.py +0 -0
  11. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/tests/test_input_display_mapping.py +0 -0
  12. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/api/tests/test_workflow_view_stream_workflow_route.py +0 -0
  13. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/code_exec_runner.py +0 -0
  14. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/config.py +0 -0
  15. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/__init__.py +0 -0
  16. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/cancel_workflow.py +0 -0
  17. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/events.py +0 -0
  18. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/executor.py +0 -0
  19. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/utils.py +0 -0
  20. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/core/workflow_executor_context.py +0 -0
  21. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/server.py +0 -0
  22. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/start.py +0 -0
  23. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/__init__.py +0 -0
  24. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/exit_handler.py +0 -0
  25. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/log_proxy.py +0 -0
  26. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/oom_killer.py +0 -0
  27. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/sentry.py +0 -0
  28. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/system_utils.py +0 -0
  29. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/tests/__init__.py +0 -0
  30. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/tests/test_sentry_integration.py +0 -0
  31. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/tests/test_system_utils.py +0 -0
  32. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/tests/test_utils.py +0 -0
  33. {vellum_workflow_server-1.0.6 → vellum_workflow_server-1.0.7}/src/workflow_server/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-workflow-server
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary:
5
5
  License: AGPL
6
6
  Requires-Python: >=3.9.0,<4
@@ -29,7 +29,7 @@ Requires-Dist: pyjwt (==2.10.0)
29
29
  Requires-Dist: python-dotenv (==1.0.1)
30
30
  Requires-Dist: retrying (==1.3.4)
31
31
  Requires-Dist: sentry-sdk[flask] (==2.20.0)
32
- Requires-Dist: vellum-ai (==1.0.6)
32
+ Requires-Dist: vellum-ai (==1.0.7)
33
33
  Description-Content-Type: text/markdown
34
34
 
35
35
  # Vellum Workflow Runner Server
@@ -3,7 +3,7 @@ name = "vellum-workflow-server"
3
3
 
4
4
  [tool.poetry]
5
5
  name = "vellum-workflow-server"
6
- version = "1.0.6"
6
+ version = "1.0.7"
7
7
  description = ""
8
8
  readme = "README.md"
9
9
  authors = []
@@ -45,7 +45,7 @@ flask = "2.3.3"
45
45
  orderly-set = "5.2.2"
46
46
  pebble = "5.0.7"
47
47
  gunicorn = "23.0.0"
48
- vellum-ai = "1.0.6"
48
+ vellum-ai = "1.0.7"
49
49
  python-dotenv = "1.0.1"
50
50
  retrying = "1.3.4"
51
51
  sentry-sdk = {extras = ["flask"], version = "2.20.0"}
@@ -3,6 +3,8 @@ import re
3
3
  from unittest.mock import patch
4
4
  from uuid import UUID
5
5
 
6
+ from deepdiff import DeepDiff
7
+
6
8
  from workflow_server.server import create_app
7
9
 
8
10
 
@@ -376,3 +378,80 @@ class MyAdditionNode(BaseNode):
376
378
  "trigger": {"id": "a5298668-d808-4a45-a62e-790943948e8a", "merge_behavior": "AWAIT_ATTRIBUTES"},
377
379
  "type": "GENERIC",
378
380
  }
381
+
382
+
383
+ def test_serialize_route__with_no_files():
384
+ # GIVEN a Flask application
385
+ flask_app = create_app()
386
+
387
+ # WHEN we make a request with no files
388
+ with flask_app.test_client() as test_client:
389
+ response = test_client.post("/workflow/serialize", json={"files": {}})
390
+
391
+ # THEN we should get a bad request response
392
+ assert response.status_code == 400
393
+
394
+ # AND the response should contain an error message
395
+ assert "detail" in response.json
396
+ assert "No files received" in response.json["detail"]
397
+
398
+
399
+ def test_serialize_route__with_invalid_python_syntax():
400
+ # GIVEN a Flask application
401
+ flask_app = create_app()
402
+
403
+ # AND a file with invalid Python syntax
404
+ invalid_content = """
405
+ from vellum.workflows.nodes import BaseNode
406
+
407
+ class BrokenNode(BaseNode) # Missing colon
408
+ \"\"\"This node has a syntax error.\"\"\"
409
+ """
410
+
411
+ # WHEN we make a request to the serialize route
412
+ with flask_app.test_client() as test_client:
413
+ response = test_client.post("/workflow/serialize", json={"files": {"broken_node.py": invalid_content}})
414
+
415
+ # THEN we should get a server error response
416
+ assert response.status_code == 500
417
+
418
+ # AND the response should contain an error message
419
+ assert "detail" in response.json
420
+ assert "Serialization failed" in response.json["detail"]
421
+
422
+
423
+ def test_serialize_route__with__workflow():
424
+ # GIVEN a Flask application
425
+ flask_app = create_app()
426
+
427
+ # AND a complete workflow with multiple files
428
+ workflow_files = {
429
+ "__init__.py": "# flake8: noqa: F401, F403\n\n",
430
+ "inputs.py": "from typing import Any, Optional\n\nfrom vellum.workflows.inputs import BaseInputs\n\n\nclass Inputs(BaseInputs):\n text: str\n var_1: Optional[Any]\n", # noqa: E501
431
+ "workflow.py": "from vellum.workflows import BaseWorkflow\nfrom vellum.workflows.state import BaseState\n\nfrom .inputs import Inputs\nfrom .nodes.final_output import FinalOutput\nfrom .nodes.templating_node import TemplatingNode\n\n\nclass Workflow(BaseWorkflow[Inputs, BaseState]):\n graph = TemplatingNode >> FinalOutput\n\n class Outputs(BaseWorkflow.Outputs):\n final_output = FinalOutput.Outputs.value\n", # noqa: E501
432
+ "nodes/__init__.py": 'from .final_output import FinalOutput\nfrom .templating_node import TemplatingNode\n\n__all__ = [\n "FinalOutput",\n "TemplatingNode",\n]\n', # noqa: E501
433
+ "nodes/templating_node.py": 'from vellum.workflows.nodes.displayable import TemplatingNode as BaseTemplatingNode\nfrom vellum.workflows.state import BaseState\n\nfrom ..inputs import Inputs\n\n\nclass TemplatingNode(BaseTemplatingNode[BaseState, str]):\n template = """{{ text }}"""\n inputs = {\n "text": Inputs.text,\n }\n', # noqa: E501
434
+ "nodes/final_output.py": "from vellum.workflows.nodes.displayable import FinalOutputNode\nfrom vellum.workflows.state import BaseState\n\nfrom .templating_node import TemplatingNode\n\n\nclass FinalOutput(FinalOutputNode[BaseState, str]):\n class Outputs(FinalOutputNode.Outputs):\n value = TemplatingNode.Outputs.result\n", # noqa: E501
435
+ }
436
+
437
+ # WHEN we make a request to the serialize route
438
+ with flask_app.test_client() as test_client:
439
+ response = test_client.post("/workflow/serialize", json={"files": workflow_files})
440
+
441
+ # THEN we should get a successful response
442
+ assert response.status_code == 200
443
+
444
+ # AND the response should contain exec_config
445
+ assert "exec_config" in response.json
446
+ exec_config = response.json["exec_config"]
447
+
448
+ # AND the exec_config should have workflow_raw_data
449
+ assert "workflow_raw_data" in exec_config
450
+ nodes = exec_config["workflow_raw_data"]["nodes"]
451
+
452
+ # AND we should find the workflow nodes
453
+ node_labels = {node["data"]["label"] for node in nodes}
454
+ expected_nodes = {"Templating Node", "Final Output", "Entrypoint Node"}
455
+
456
+ # AND at least some of the expected nodes should be present
457
+ assert not DeepDiff(node_labels, expected_nodes, ignore_order=True)
@@ -7,6 +7,8 @@ from multiprocessing import Process, Queue, set_start_method
7
7
  import os
8
8
  import pkgutil
9
9
  from queue import Empty
10
+ import random
11
+ import string
10
12
  import sys
11
13
  from threading import Event as ThreadingEvent
12
14
  import time
@@ -18,6 +20,8 @@ from flask import Blueprint, Response, current_app as app, has_request_context,
18
20
  from pydantic import ValidationError
19
21
  from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
20
22
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
23
+ from vellum_ee.workflows.display.workflows import BaseWorkflowDisplay
24
+ from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
21
25
 
22
26
  from vellum.workflows.exceptions import WorkflowInitializationException
23
27
  from vellum.workflows.nodes import BaseNode
@@ -410,6 +414,47 @@ def stream_node_route() -> Response:
410
414
  return resp
411
415
 
412
416
 
417
+ @bp.route("/serialize", methods=["POST"])
418
+ def serialize_route() -> Response:
419
+ data = request.get_json()
420
+
421
+ files = data.get("files", {})
422
+
423
+ if not files:
424
+ return Response(
425
+ json.dumps({"detail": "No files received"}),
426
+ status=400,
427
+ content_type="application/json",
428
+ )
429
+
430
+ try:
431
+ # Generate a unique namespace for this serialization request
432
+ namespace = "".join(random.choice(string.ascii_letters + string.digits) for i in range(14))
433
+ virtual_finder = VirtualFileFinder(files, namespace)
434
+
435
+ try:
436
+ sys.meta_path.append(virtual_finder)
437
+ exec_config = BaseWorkflowDisplay.serialize_module(namespace).exec_config
438
+
439
+ return Response(
440
+ json.dumps({"exec_config": exec_config}),
441
+ status=200,
442
+ content_type="application/json",
443
+ )
444
+
445
+ finally:
446
+ if virtual_finder in sys.meta_path:
447
+ sys.meta_path.remove(virtual_finder)
448
+
449
+ except Exception as e:
450
+ logger.exception(f"Error during serialization: {str(e)}")
451
+ return Response(
452
+ json.dumps({"detail": f"Serialization failed: {str(e)}"}),
453
+ status=500,
454
+ content_type="application/json",
455
+ )
456
+
457
+
413
458
  @bp.route("/version", methods=["GET"])
414
459
  def get_version_route() -> tuple[dict, int]:
415
460
  resp = get_version()