vellum-workflow-server 1.3.8__py3-none-any.whl → 1.3.8.post1__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.

Potentially problematic release.


This version of vellum-workflow-server might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-workflow-server
3
- Version: 1.3.8
3
+ Version: 1.3.8.post1
4
4
  Summary:
5
5
  License: AGPL
6
6
  Requires-Python: >=3.9.0,<4
@@ -4,16 +4,16 @@ workflow_server/api/auth_middleware.py,sha256=IlZaCiwZ5nwQqk5sYQorvOFj7lt0p1ZSSE
4
4
  workflow_server/api/healthz_view.py,sha256=itiRvBDBXncrw8Kbbc73UZLwqMAhgHOR3uSre_dAfgY,404
5
5
  workflow_server/api/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  workflow_server/api/tests/test_input_display_mapping.py,sha256=drBZqMudFyB5wgiUOcMgRXz7E7ge-Qgxbstw4E4f0zE,2211
7
- workflow_server/api/tests/test_workflow_view.py,sha256=gwb53E44LBm06XHY1UwfHqKG-UfwwICh_IYPtowN_kE,19085
7
+ workflow_server/api/tests/test_workflow_view.py,sha256=aMYbHpblr9KRa4hLX87koAng3O8lfggKBe-9tVDBnLA,22538
8
8
  workflow_server/api/tests/test_workflow_view_stream_workflow_route.py,sha256=Qo8u6mPyRCmE2jamY1yIh8l44hgo4-Nwlq03z61ND5g,27031
9
- workflow_server/api/workflow_view.py,sha256=gSKqlMR2r2urSBYm_jFlcpXHOk5jQsDMSDwpSahp5A8,21144
9
+ workflow_server/api/workflow_view.py,sha256=Ufc49WJ4LON3FFxzY2MeP4q7uQyorMNMu9zLRuJvdp4,21523
10
10
  workflow_server/code_exec_runner.py,sha256=lBnMIorPZL8zZBye6TjeCIs06WTJM7P2HR07B1fjJJI,2533
11
11
  workflow_server/config.py,sha256=DyTty8NrAwvtx-esM3KthnpsNh-nKdWNlovWQOgiGpg,1417
12
12
  workflow_server/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  workflow_server/core/cancel_workflow.py,sha256=Ffkc3mzmrdMEUcD-sHfEhX4IwVrka-E--SxKA1dUfIU,2185
14
14
  workflow_server/core/events.py,sha256=24MA66DVQuaLJJcZrS8IL1Zq4Ohi9CoouKZ5VgoH3Cs,1402
15
- workflow_server/core/executor.py,sha256=TTpMifrIZuzXxOUtX3E3CgLOb8eRXul2aGPpRCfWIco,18368
16
- workflow_server/core/utils.py,sha256=cmwHbKCfXqtUutBD3akGus0Ga7a1xG3zlOw-jEMx6mI,1795
15
+ workflow_server/core/executor.py,sha256=qAAQcwN0BfNL--IVZAn9jWr_KeOYGqB8sPP7dm8cFQk,17548
16
+ workflow_server/core/utils.py,sha256=aIpSINstLGslP2PIoDLM82_1GlJ1uC_0AIrP-V7Yobo,3230
17
17
  workflow_server/core/workflow_executor_context.py,sha256=w3OhV_AXpgh7AxpjEsc0vo-IJypgJcgr5DXJCqGptOU,1587
18
18
  workflow_server/server.py,sha256=QBU12AaAfAgLqfCDBd24qIJl_mbheiq0-hfcWV7rZM4,1234
19
19
  workflow_server/start.py,sha256=qpIg0SgIgz8RNyc8Cu9LxyzXdOXZRv9qq3M3uSBbgD0,2180
@@ -28,7 +28,7 @@ workflow_server/utils/tests/test_sentry_integration.py,sha256=LGmWiaLhFrx-jslrRj
28
28
  workflow_server/utils/tests/test_system_utils.py,sha256=_4GwXvVvU5BrATxUEWwQIPg0bzQXMWBtiBmjP8MTxJM,4314
29
29
  workflow_server/utils/tests/test_utils.py,sha256=qwK5Rmy3RQyjtlUrYAuGuDlBeRzZKsf1yS-y2IpUizQ,6452
30
30
  workflow_server/utils/utils.py,sha256=zcjnY6tSPf90VZOBm8w0NfxYWPQYAL9TCNlza231Odg,4535
31
- vellum_workflow_server-1.3.8.dist-info/METADATA,sha256=XpStc7y5oUXAvWcPnz60GZCzjgXjbMITkuIUfFhfdSM,2267
32
- vellum_workflow_server-1.3.8.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
33
- vellum_workflow_server-1.3.8.dist-info/entry_points.txt,sha256=uB_0yPkr7YV6RhEXzvFReUM8P4OQBlVXD6TN6eb9-oc,277
34
- vellum_workflow_server-1.3.8.dist-info/RECORD,,
31
+ vellum_workflow_server-1.3.8.post1.dist-info/METADATA,sha256=XXsdPKaXM25l8UINX9PGIx4YyxpC21TJnX1bp0Do_Pg,2273
32
+ vellum_workflow_server-1.3.8.post1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
33
+ vellum_workflow_server-1.3.8.post1.dist-info/entry_points.txt,sha256=uB_0yPkr7YV6RhEXzvFReUM8P4OQBlVXD6TN6eb9-oc,277
34
+ vellum_workflow_server-1.3.8.post1.dist-info/RECORD,,
@@ -472,3 +472,64 @@ def test_serialize_route__with__workflow():
472
472
 
473
473
  # AND at least some of the expected nodes should be present
474
474
  assert not DeepDiff(node_labels, expected_nodes, ignore_order=True)
475
+
476
+
477
+ def test_serialize_route__with_workspace_api_key():
478
+ """
479
+ Tests that the serialize route accepts workspace_api_key and passes it through serialization.
480
+ """
481
+ # GIVEN a Flask application
482
+ flask_app = create_app()
483
+
484
+ # AND a complete workflow with multiple files
485
+ workflow_files = {
486
+ "__init__.py": "# flake8: noqa: F401, F403\n\n",
487
+ "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
488
+ "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
489
+ "nodes/__init__.py": 'from .final_output import FinalOutput\nfrom .templating_node import TemplatingNode\n\n__all__ = [\n "FinalOutput",\n "TemplatingNode",\n]\n', # noqa: E501
490
+ "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
491
+ "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
492
+ }
493
+
494
+ # WHEN we make a request to the serialize route with workspace_api_key
495
+ with flask_app.test_client() as test_client:
496
+ response = test_client.post(
497
+ "/workflow/serialize", json={"files": workflow_files, "workspace_api_key": "test_workspace_key"}
498
+ )
499
+
500
+ # THEN we should get a successful response
501
+ assert response.status_code == 200
502
+
503
+ # AND the response should contain the full WorkflowSerializationResult
504
+ assert "exec_config" in response.json
505
+ assert "errors" in response.json
506
+
507
+
508
+ def test_serialize_route__with_invalid_workspace_api_key():
509
+ """
510
+ Tests that the serialize route handles invalid workspace_api_key gracefully.
511
+ """
512
+ # GIVEN a Flask application
513
+ flask_app = create_app()
514
+
515
+ workflow_files = {
516
+ "__init__.py": "",
517
+ "workflow.py": (
518
+ "from vellum.workflows import BaseWorkflow\n\n"
519
+ "class Workflow(BaseWorkflow):\n"
520
+ " class Outputs(BaseWorkflow.Outputs):\n"
521
+ " foo = 'hello'\n"
522
+ ),
523
+ }
524
+
525
+ # WHEN we make a request with an invalid workspace_api_key
526
+ with flask_app.test_client() as test_client:
527
+ response = test_client.post(
528
+ "/workflow/serialize", json={"files": workflow_files, "workspace_api_key": ""} # Invalid empty key
529
+ )
530
+
531
+ # THEN we should still get a successful response (graceful degradation)
532
+ assert response.status_code == 200
533
+
534
+ # AND the response should contain the serialization result
535
+ assert "exec_config" in response.json
@@ -37,6 +37,7 @@ from workflow_server.core.events import (
37
37
  )
38
38
  from workflow_server.core.executor import stream_node_pebble_timeout, stream_workflow, stream_workflow_process_timeout
39
39
  from workflow_server.core.utils import (
40
+ create_vellum_client,
40
41
  create_vembda_rejected_event,
41
42
  is_events_emitting_enabled,
42
43
  serialize_vembda_rejected_event,
@@ -55,11 +56,10 @@ from workflow_server.utils.system_utils import (
55
56
  from workflow_server.utils.utils import convert_json_inputs_to_vellum, get_version
56
57
 
57
58
  bp = Blueprint("exec", __name__)
59
+ logger = logging.getLogger(__name__)
58
60
 
59
61
  set_start_method("fork", force=True)
60
62
 
61
- logger = logging.getLogger(__name__)
62
-
63
63
  CUSTOM_NODES_DIRECTORY = "vellum_custom_nodes"
64
64
  WORKFLOW_INITIATION_TIMEOUT_SECONDS = 60
65
65
 
@@ -425,6 +425,7 @@ def serialize_route() -> Response:
425
425
  data = request.get_json()
426
426
 
427
427
  files = data.get("files", {})
428
+ workspace_api_key = data.get("workspace_api_key")
428
429
 
429
430
  if not files:
430
431
  return Response(
@@ -434,6 +435,13 @@ def serialize_route() -> Response:
434
435
  )
435
436
 
436
437
  try:
438
+ client = None
439
+ if workspace_api_key:
440
+ try:
441
+ client = create_vellum_client(api_key=workspace_api_key)
442
+ except Exception as e:
443
+ logger.warning(f"Failed to create VellumClient with provided workspace_api_key: {str(e)}")
444
+
437
445
  # Generate a unique namespace for this serialization request
438
446
  namespace = "".join(random.choice(string.ascii_letters + string.digits) for i in range(14))
439
447
  virtual_finder = VirtualFileFinder(files, namespace)
@@ -441,7 +449,7 @@ def serialize_route() -> Response:
441
449
  try:
442
450
  sys.meta_path.append(virtual_finder)
443
451
  try:
444
- result = BaseWorkflowDisplay.serialize_module(namespace)
452
+ result = BaseWorkflowDisplay.serialize_module(namespace, client=client)
445
453
  except Exception as e:
446
454
  raise WorkflowInitializationException(str(e)) from e
447
455
 
@@ -20,7 +20,6 @@ from vellum_ee.workflows.display.utils.events import event_enricher
20
20
  from vellum_ee.workflows.display.workflows import BaseWorkflowDisplay
21
21
  from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
22
22
 
23
- from vellum import Vellum, VellumEnvironment
24
23
  from vellum.workflows import BaseWorkflow
25
24
  from vellum.workflows.emitters.base import BaseWorkflowEmitter
26
25
  from vellum.workflows.emitters.vellum_emitter import VellumEmitter
@@ -36,7 +35,6 @@ from vellum.workflows.state.base import BaseState, StateMeta
36
35
  from vellum.workflows.state.context import WorkflowContext
37
36
  from vellum.workflows.state.store import EmptyStore
38
37
  from vellum.workflows.workflows.event_filters import all_workflow_event_filter
39
- from workflow_server.config import IS_VPC, VELLUM_API_URL_HOST, VELLUM_API_URL_PORT
40
38
  from workflow_server.core.cancel_workflow import CancelWorkflowWatcherThread
41
39
  from workflow_server.core.events import (
42
40
  SPAN_ID_EVENT,
@@ -44,7 +42,7 @@ from workflow_server.core.events import (
44
42
  VembdaExecutionFulfilledBody,
45
43
  VembdaExecutionFulfilledEvent,
46
44
  )
47
- from workflow_server.core.utils import is_events_emitting_enabled, serialize_vembda_rejected_event
45
+ from workflow_server.core.utils import create_vellum_client, is_events_emitting_enabled, serialize_vembda_rejected_event
48
46
  from workflow_server.core.workflow_executor_context import (
49
47
  DEFAULT_TIMEOUT_SECONDS,
50
48
  BaseExecutorContext,
@@ -374,21 +372,10 @@ def _create_workflow(executor_context: WorkflowExecutorContext, namespace: str)
374
372
 
375
373
 
376
374
  def _create_workflow_context(executor_context: BaseExecutorContext) -> WorkflowContext:
377
- if IS_VPC:
378
- environment = VellumEnvironment(
379
- default=os.getenv("VELLUM_DEFAULT_API_URL", VellumEnvironment.PRODUCTION.default),
380
- documents=os.getenv("VELLUM_DOCUMENTS_API_URL", VellumEnvironment.PRODUCTION.documents),
381
- predict=os.getenv("VELLUM_PREDICT_API_URL", VellumEnvironment.PRODUCTION.predict),
382
- )
383
- elif os.getenv("USE_LOCAL_VELLUM_API") == "true":
384
- VELLUM_API_URL = f"http://{VELLUM_API_URL_HOST}:{VELLUM_API_URL_PORT}"
385
- environment = VellumEnvironment(
386
- default=VELLUM_API_URL,
387
- documents=VELLUM_API_URL,
388
- predict=VELLUM_API_URL,
389
- )
390
- else:
391
- environment = VellumEnvironment.PRODUCTION
375
+ vellum_client = create_vellum_client(
376
+ api_key=executor_context.environment_api_key,
377
+ api_version=executor_context.api_version,
378
+ )
392
379
 
393
380
  if executor_context.environment_variables:
394
381
  os.environ.update(executor_context.environment_variables)
@@ -396,11 +383,7 @@ def _create_workflow_context(executor_context: BaseExecutorContext) -> WorkflowC
396
383
  namespace = _get_file_namespace(executor_context)
397
384
 
398
385
  return WorkflowContext(
399
- vellum_client=Vellum(
400
- api_key=executor_context.environment_api_key,
401
- environment=environment,
402
- api_version=executor_context.api_version,
403
- ),
386
+ vellum_client=vellum_client,
404
387
  execution_context=executor_context.execution_context,
405
388
  generated_files=executor_context.files,
406
389
  namespace=namespace,
@@ -1,7 +1,10 @@
1
1
  from datetime import datetime
2
+ import os
2
3
  from uuid import uuid4
3
4
  from typing import Optional
4
5
 
6
+ from vellum import ApiVersionEnum, Vellum, VellumEnvironment
7
+ from workflow_server.config import IS_VPC, VELLUM_API_URL_HOST, VELLUM_API_URL_PORT
5
8
  from workflow_server.core.events import VembdaExecutionFulfilledBody, VembdaExecutionFulfilledEvent
6
9
  from workflow_server.core.workflow_executor_context import BaseExecutorContext
7
10
 
@@ -48,3 +51,42 @@ def is_events_emitting_enabled(executor_context: Optional[BaseExecutorContext])
48
51
  return False
49
52
 
50
53
  return executor_context.feature_flags.get("vembda-event-emitting-enabled") or False
54
+
55
+
56
+ def create_vellum_client(
57
+ api_key: str,
58
+ api_version: Optional[ApiVersionEnum] = None,
59
+ ) -> Vellum:
60
+ """
61
+ Create a VellumClient with proper environment configuration.
62
+
63
+ Args:
64
+ api_key: The API key for the Vellum client
65
+ api_version: Optional API version to use
66
+
67
+ Returns:
68
+ Configured Vellum client instance
69
+
70
+ Note: Ideally we replace this with `vellum.workflows.vellum_client.create_vellum_client`
71
+ """
72
+ if IS_VPC:
73
+ environment = VellumEnvironment(
74
+ default=os.getenv("VELLUM_DEFAULT_API_URL", VellumEnvironment.PRODUCTION.default),
75
+ documents=os.getenv("VELLUM_DOCUMENTS_API_URL", VellumEnvironment.PRODUCTION.documents),
76
+ predict=os.getenv("VELLUM_PREDICT_API_URL", VellumEnvironment.PRODUCTION.predict),
77
+ )
78
+ elif os.getenv("USE_LOCAL_VELLUM_API") == "true":
79
+ VELLUM_API_URL = f"http://{VELLUM_API_URL_HOST}:{VELLUM_API_URL_PORT}"
80
+ environment = VellumEnvironment(
81
+ default=VELLUM_API_URL,
82
+ documents=VELLUM_API_URL,
83
+ predict=VELLUM_API_URL,
84
+ )
85
+ else:
86
+ environment = VellumEnvironment.PRODUCTION
87
+
88
+ return Vellum(
89
+ api_key=api_key,
90
+ environment=environment,
91
+ api_version=api_version,
92
+ )