dify-player 0.3.4__tar.gz → 0.3.6__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.
Files changed (55) hide show
  1. {dify_player-0.3.4 → dify_player-0.3.6}/PKG-INFO +1 -1
  2. {dify_player-0.3.4 → dify_player-0.3.6}/README.md +29 -3
  3. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/__init__.py +1 -1
  4. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/__init__.py +12 -7
  5. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/llm_azure_chat.py +23 -11
  6. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/llm_groq_chat.py +21 -13
  7. dify_player-0.3.6/dify_player/provider_config.py +38 -0
  8. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/runtime.py +38 -1
  9. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/workflow_engine.py +7 -0
  10. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/workflow_executor.py +7 -0
  11. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player.egg-info/PKG-INFO +1 -1
  12. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player.egg-info/SOURCES.txt +1 -0
  13. {dify_player-0.3.4 → dify_player-0.3.6}/pyproject.toml +1 -1
  14. {dify_player-0.3.4 → dify_player-0.3.6}/MANIFEST.in +0 -0
  15. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/__main__.py +0 -0
  16. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/cli.py +0 -0
  17. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/__init__.py +0 -0
  18. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/graph_parser.py +0 -0
  19. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/http_body_converter.py +0 -0
  20. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/__init__.py +0 -0
  21. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/assigner.py +0 -0
  22. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/code.py +0 -0
  23. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/end.py +0 -0
  24. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/http_request.py +0 -0
  25. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/if_else.py +0 -0
  26. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/llm.py +0 -0
  27. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/loop.py +0 -0
  28. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/start.py +0 -0
  29. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/template_transform.py +0 -0
  30. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/node_converters/variable_aggregator.py +0 -0
  31. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/plan_serializer.py +0 -0
  32. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/reference_converter.py +0 -0
  33. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/workflow_loader.py +0 -0
  34. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_importer/workflow_normalizer.py +0 -0
  35. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/dify_workflow_importer.py +0 -0
  36. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/event_logger.py +0 -0
  37. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/exceptions.py +0 -0
  38. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/input_resolver.py +0 -0
  39. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/llm_cache.py +0 -0
  40. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/models.py +0 -0
  41. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/assigner.py +0 -0
  42. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/code.py +0 -0
  43. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/end.py +0 -0
  44. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/http.py +0 -0
  45. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/if_else.py +0 -0
  46. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/llm_xai_chat.py +0 -0
  47. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/start.py +0 -0
  48. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/template.py +0 -0
  49. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/nodes/variable_aggregator.py +0 -0
  50. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/plan_loader.py +0 -0
  51. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player/value_renderer.py +0 -0
  52. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player.egg-info/dependency_links.txt +0 -0
  53. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player.egg-info/requires.txt +0 -0
  54. {dify_player-0.3.4 → dify_player-0.3.6}/dify_player.egg-info/top_level.txt +0 -0
  55. {dify_player-0.3.4 → dify_player-0.3.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dify-player
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Minimal workflow runner for hand-authored Dify-like plans.
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: Jinja2<4,>=3.1
@@ -87,9 +87,9 @@ async def run_workflow(payload: dict) -> dict:
87
87
 
88
88
  `WorkflowEngine` には次の async API があります。
89
89
 
90
- - `await engine.run_plan_data(plan_data=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None)`
91
- - `await engine.run_plan(plan=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None)`
92
- - `await engine.run_compiled_plan(compiled_plan=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None)`
90
+ - `await engine.run_plan_data(plan_data=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None, provider_config=None)`
91
+ - `await engine.run_plan(plan=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None, provider_config=None)`
92
+ - `await engine.run_compiled_plan(compiled_plan=..., inputs=..., run_id=None, logger=None, http_client=None, llm_cache=False, llm_cache_store=None, provider_config=None)`
93
93
 
94
94
  使い分けは次のとおりです。
95
95
 
@@ -97,6 +97,32 @@ async def run_workflow(payload: dict) -> dict:
97
97
  - `run_plan`: すでに `Plan` オブジェクトを組み立てている内部利用向け
98
98
  - `run_compiled_plan`: 同じ plan を何度も実行する用途向け
99
99
 
100
+ ### Provider Config
101
+
102
+ Azure OpenAI と Groq の接続設定は、実行単位で `provider_config` として渡せます。
103
+ 優先順位は `provider_config`、`DIFY_PLAYER_*` 環境変数、既存互換の環境変数の順です。
104
+
105
+ ```python
106
+ result = await engine.run_compiled_plan(
107
+ compiled_plan=compiled_plan,
108
+ inputs=inputs,
109
+ provider_config={
110
+ "azure_openai_endpoint": "https://example.openai.azure.com",
111
+ "azure_openai_api_key": "...",
112
+ "azure_openai_api_version": "2024-10-21",
113
+ "groq_api_key": "...",
114
+ "groq_api_base_url": "https://api.groq.com/openai/v1",
115
+ },
116
+ )
117
+ ```
118
+
119
+ 対応する env fallback は次のとおりです。
120
+
121
+ - Azure OpenAI: `DIFY_PLAYER_AZURE_OPENAI_ENDPOINT`, `DIFY_PLAYER_AZURE_OPENAI_API_KEY`, `DIFY_PLAYER_AZURE_OPENAI_API_VERSION`
122
+ - Azure OpenAI 既存互換: `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_API_VERSION`
123
+ - Groq: `DIFY_PLAYER_GROQ_API_KEY`, `DIFY_PLAYER_GROQ_API_BASE_URL`
124
+ - Groq 既存互換: `GROQ_API_KEY`, `GROQ_API_BASE_URL`
125
+
100
126
  ### LLM Cache Mode
101
127
 
102
128
  workflow 改善中だけ LLM 応答を再利用したい場合は、`llm_cache=True` と cache store を渡します。
@@ -5,4 +5,4 @@ from dify_player.workflow_engine import WorkflowEngine
5
5
 
6
6
  __all__ = ["__version__", "LLMCacheStore", "NullLLMCacheStore", "WorkflowEngine"]
7
7
 
8
- __version__ = "0.3.4"
8
+ __version__ = "0.3.6"
@@ -6,6 +6,7 @@ from typing import Any
6
6
  import httpx
7
7
  from dify_player.exceptions import UnsupportedNodeError
8
8
  from dify_player.models import Node
9
+ from dify_player.provider_config import ProviderConfig
9
10
 
10
11
  from dify_player.nodes.assigner import run as run_assigner
11
12
  from dify_player.nodes.code import run as run_code
@@ -43,14 +44,18 @@ async def run_node(
43
44
  node_outputs: dict[str, dict[str, Any]],
44
45
  resolved_inputs: dict[str, Any],
45
46
  http_client: httpx.AsyncClient | None = None,
47
+ provider_config: ProviderConfig | None = None,
46
48
  ) -> dict[str, Any]:
47
49
  executor = _EXECUTORS.get(node.kind)
48
50
  if executor is None:
49
51
  raise UnsupportedNodeError(f"unsupported node kind {node.kind!r}")
50
- return await executor(
51
- node=node,
52
- workflow_inputs=workflow_inputs,
53
- node_outputs=node_outputs,
54
- resolved_inputs=resolved_inputs,
55
- http_client=http_client,
56
- )
52
+ kwargs: dict[str, Any] = {
53
+ "node": node,
54
+ "workflow_inputs": workflow_inputs,
55
+ "node_outputs": node_outputs,
56
+ "resolved_inputs": resolved_inputs,
57
+ "http_client": http_client,
58
+ }
59
+ if node.kind in {"llm_azure_chat", "llm_groq_chat"}:
60
+ kwargs["provider_config"] = provider_config
61
+ return await executor(**kwargs)
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- import os
5
4
  from typing import Any
6
5
 
7
6
  import httpx
8
7
 
9
8
  from dify_player.exceptions import AzureLLMBadStatusError, AzureLLMRequestFailedError, AzureLLMStructuredOutputError
10
9
  from dify_player.models import Node
10
+ from dify_player.provider_config import ProviderConfig, resolve_provider_config_value
11
11
  from dify_player.value_renderer import render_value
12
12
 
13
13
  _STRUCTURED_OUTPUT_REPAIR_RETRIES = 1
@@ -20,11 +20,30 @@ async def run(
20
20
  node_outputs: dict[str, dict[str, Any]],
21
21
  resolved_inputs: dict[str, Any],
22
22
  http_client: httpx.AsyncClient | None = None,
23
+ provider_config: ProviderConfig | None = None,
23
24
  ) -> dict[str, Any]:
24
25
  _ = resolved_inputs
25
- endpoint = _require_env("AZURE_OPENAI_ENDPOINT", node=node)
26
- api_key = _require_env("AZURE_OPENAI_API_KEY", node=node)
27
- api_version = _require_env("AZURE_OPENAI_API_VERSION", node=node)
26
+ endpoint = resolve_provider_config_value(
27
+ provider_config=provider_config,
28
+ config_key="azure_openai_endpoint",
29
+ env_names=("DIFY_PLAYER_AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_ENDPOINT"),
30
+ node=node,
31
+ required=True,
32
+ )
33
+ api_key = resolve_provider_config_value(
34
+ provider_config=provider_config,
35
+ config_key="azure_openai_api_key",
36
+ env_names=("DIFY_PLAYER_AZURE_OPENAI_API_KEY", "AZURE_OPENAI_API_KEY"),
37
+ node=node,
38
+ required=True,
39
+ )
40
+ api_version = resolve_provider_config_value(
41
+ provider_config=provider_config,
42
+ config_key="azure_openai_api_version",
43
+ env_names=("DIFY_PLAYER_AZURE_OPENAI_API_VERSION", "AZURE_OPENAI_API_VERSION"),
44
+ node=node,
45
+ required=True,
46
+ )
28
47
 
29
48
  messages = render_value(
30
49
  node.config["messages"],
@@ -59,13 +78,6 @@ async def run(
59
78
  )
60
79
 
61
80
 
62
- def _require_env(name: str, *, node: Node) -> str:
63
- value = os.environ.get(name)
64
- if value:
65
- return value
66
- raise ValueError(f"llm node {node.label!r} requires environment variable {name}")
67
-
68
-
69
81
  def _build_request_body(*, node: Node, messages: Any) -> dict[str, Any]:
70
82
  if not isinstance(messages, list):
71
83
  raise ValueError(f"llm node {node.label!r} config.messages must render to an array")
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
- import os
5
4
  from typing import Any
6
5
 
7
6
  import httpx
@@ -19,6 +18,7 @@ from dify_player.nodes.llm_azure_chat import (
19
18
  _validate_schema,
20
19
  _zero_usage,
21
20
  )
21
+ from dify_player.provider_config import ProviderConfig, resolve_provider_config_value
22
22
  from dify_player.value_renderer import render_value
23
23
 
24
24
  _DEFAULT_BASE_URL = "https://api.groq.com/openai/v1"
@@ -32,10 +32,24 @@ async def run(
32
32
  node_outputs: dict[str, dict[str, Any]],
33
33
  resolved_inputs: dict[str, Any],
34
34
  http_client: httpx.AsyncClient | None = None,
35
+ provider_config: ProviderConfig | None = None,
35
36
  ) -> dict[str, Any]:
36
37
  _ = resolved_inputs
37
- api_key = _require_env("GROQ_API_KEY", node=node)
38
- base_url = os.environ.get("GROQ_API_BASE_URL", _DEFAULT_BASE_URL)
38
+ api_key = resolve_provider_config_value(
39
+ provider_config=provider_config,
40
+ config_key="groq_api_key",
41
+ env_names=("DIFY_PLAYER_GROQ_API_KEY", "GROQ_API_KEY"),
42
+ node=node,
43
+ required=True,
44
+ )
45
+ base_url = resolve_provider_config_value(
46
+ provider_config=provider_config,
47
+ config_key="groq_api_base_url",
48
+ env_names=("DIFY_PLAYER_GROQ_API_BASE_URL", "GROQ_API_BASE_URL"),
49
+ node=node,
50
+ required=False,
51
+ default=_DEFAULT_BASE_URL,
52
+ )
39
53
 
40
54
  messages = render_value(
41
55
  node.config["messages"],
@@ -67,13 +81,6 @@ async def run(
67
81
  )
68
82
 
69
83
 
70
- def _require_env(name: str, *, node: Node) -> str:
71
- value = os.environ.get(name)
72
- if value:
73
- return value
74
- raise ValueError(f"llm node {node.label!r} requires environment variable {name}")
75
-
76
-
77
84
  def _build_request_body(*, node: Node, messages: Any) -> dict[str, Any]:
78
85
  if not isinstance(messages, list):
79
86
  raise ValueError(f"llm node {node.label!r} config.messages must render to an array")
@@ -222,8 +229,9 @@ async def _run_structured_output_with_repair(
222
229
 
223
230
 
224
231
  # Groq may return json_validate_failed as HTTP 400 even when the failure is the
225
- # model's generated JSON, not a permanent request/schema error. Preserve that
226
- # failed output so the existing structured-output repair prompt can fix it.
232
+ # model's generated JSON, not a permanent request/schema error. Retry through the
233
+ # existing repair prompt even when Groq omits failed_generation, because the next
234
+ # attempt can still recover from provider-side structured-output validation.
227
235
  def _extract_groq_failed_generation(exc: GroqLLMBadStatusError) -> tuple[str, str] | None:
228
236
  if exc.status_code != 400 or exc.response_body is None:
229
237
  return None
@@ -242,7 +250,7 @@ def _extract_groq_failed_generation(exc: GroqLLMBadStatusError) -> tuple[str, st
242
250
  return None
243
251
 
244
252
  failed_generation = error.get("failed_generation")
245
- if not isinstance(failed_generation, str) or not failed_generation.strip():
253
+ if not isinstance(failed_generation, str):
246
254
  return None
247
255
 
248
256
  message = error.get("message")
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Mapping
5
+ from typing import Any
6
+
7
+ from dify_player.models import Node
8
+
9
+ ProviderConfig = Mapping[str, Any]
10
+
11
+
12
+ def resolve_provider_config_value(
13
+ *,
14
+ provider_config: ProviderConfig | None,
15
+ config_key: str,
16
+ env_names: tuple[str, ...],
17
+ node: Node,
18
+ required: bool,
19
+ default: str | None = None,
20
+ ) -> str:
21
+ if provider_config is not None:
22
+ value = provider_config.get(config_key)
23
+ if value:
24
+ if not isinstance(value, str):
25
+ raise ValueError(f"llm node {node.label!r} provider_config[{config_key!r}] must be a string")
26
+ return value
27
+
28
+ for env_name in env_names:
29
+ value = os.environ.get(env_name)
30
+ if value:
31
+ return value
32
+
33
+ if default is not None:
34
+ return default
35
+ if required:
36
+ sources = [f"provider_config[{config_key!r}]"] + [f"environment variable {env_name}" for env_name in env_names]
37
+ raise ValueError(f"llm node {node.label!r} requires {' or '.join(sources)}")
38
+ raise ValueError(f"llm node {node.label!r} provider config {config_key!r} is not configured")
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import time
4
5
  from copy import deepcopy
5
6
  from datetime import datetime, timezone
@@ -26,6 +27,7 @@ from dify_player.input_resolver import resolve_node_inputs
26
27
  from dify_player.llm_cache import LLMCacheStore, NullLLMCacheStore, build_llm_cache_key
27
28
  from dify_player.models import CompiledLoop, CompiledPlan, Edge, Node, NodeResult, RunResult, RunState, WorkflowError
28
29
  from dify_player.nodes import run_node
30
+ from dify_player.provider_config import ProviderConfig
29
31
  from dify_player.value_renderer import render_value
30
32
 
31
33
 
@@ -36,10 +38,12 @@ class WorkflowRuntime:
36
38
  *,
37
39
  llm_cache_enabled: bool = False,
38
40
  llm_cache_store: LLMCacheStore | None = None,
41
+ provider_config: ProviderConfig | None = None,
39
42
  ) -> None:
40
43
  self.logger = logger
41
44
  self.llm_cache_enabled = llm_cache_enabled
42
45
  self.llm_cache_store = llm_cache_store if llm_cache_store is not None else NullLLMCacheStore()
46
+ self.provider_config = provider_config
43
47
 
44
48
  async def run(
45
49
  self,
@@ -455,6 +459,7 @@ class WorkflowRuntime:
455
459
  node_outputs=node_outputs,
456
460
  resolved_inputs=resolved_inputs,
457
461
  http_client=http_client,
462
+ provider_config=self.provider_config,
458
463
  )
459
464
 
460
465
  if not self._should_use_llm_cache(node=node):
@@ -528,7 +533,8 @@ class WorkflowRuntime:
528
533
  node.config["messages"],
529
534
  {"inputs": workflow_inputs, "nodes": node_outputs},
530
535
  location=f"llm cache key for node {node.label!r} config.messages",
531
- )
536
+ ),
537
+ "provider_config": _cacheable_provider_config(self.provider_config),
532
538
  }
533
539
  return build_llm_cache_key(
534
540
  node_kind=node.kind,
@@ -772,6 +778,37 @@ def _normalize_workflow_inputs(*, compiled_plan: CompiledPlan, inputs: dict[str,
772
778
  return normalized_inputs
773
779
 
774
780
 
781
+ def _cacheable_provider_config(provider_config: ProviderConfig | None) -> dict[str, Any]:
782
+ values = {
783
+ "azure_openai_endpoint": _cacheable_provider_config_value(
784
+ provider_config=provider_config,
785
+ config_key="azure_openai_endpoint",
786
+ env_names=("DIFY_PLAYER_AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_ENDPOINT"),
787
+ ),
788
+ "azure_openai_api_version": _cacheable_provider_config_value(
789
+ provider_config=provider_config,
790
+ config_key="azure_openai_api_version",
791
+ env_names=("DIFY_PLAYER_AZURE_OPENAI_API_VERSION", "AZURE_OPENAI_API_VERSION"),
792
+ ),
793
+ }
794
+ return {key: value for key, value in values.items() if value}
795
+
796
+
797
+ def _cacheable_provider_config_value(
798
+ *,
799
+ provider_config: ProviderConfig | None,
800
+ config_key: str,
801
+ env_names: tuple[str, ...],
802
+ ) -> Any:
803
+ if provider_config is not None and provider_config.get(config_key):
804
+ return provider_config[config_key]
805
+ for env_name in env_names:
806
+ value = os.environ.get(env_name)
807
+ if value:
808
+ return value
809
+ return None
810
+
811
+
775
812
  class _LoopRuntimeError(ValueError):
776
813
  def __init__(self, error: WorkflowError) -> None:
777
814
  super().__init__(error.message)
@@ -9,6 +9,7 @@ from dify_player.event_logger import NullEventLogger, WorkflowLogger
9
9
  from dify_player.llm_cache import LLMCacheStore
10
10
  from dify_player.models import CompiledPlan, Plan, RunResult
11
11
  from dify_player.plan_loader import parse_plan
12
+ from dify_player.provider_config import ProviderConfig
12
13
  from dify_player.workflow_executor import WorkflowExecutor
13
14
 
14
15
 
@@ -26,6 +27,7 @@ class WorkflowEngine:
26
27
  http_client: httpx.AsyncClient | None = None,
27
28
  llm_cache: bool = False,
28
29
  llm_cache_store: LLMCacheStore | None = None,
30
+ provider_config: ProviderConfig | None = None,
29
31
  ) -> RunResult:
30
32
  effective_logger, owns_logger = _resolve_logger(run_id=run_id, logger=logger)
31
33
  try:
@@ -36,6 +38,7 @@ class WorkflowEngine:
36
38
  http_client=http_client,
37
39
  llm_cache=llm_cache,
38
40
  llm_cache_store=llm_cache_store,
41
+ provider_config=provider_config,
39
42
  )
40
43
  finally:
41
44
  if owns_logger:
@@ -51,6 +54,7 @@ class WorkflowEngine:
51
54
  http_client: httpx.AsyncClient | None = None,
52
55
  llm_cache: bool = False,
53
56
  llm_cache_store: LLMCacheStore | None = None,
57
+ provider_config: ProviderConfig | None = None,
54
58
  ) -> RunResult:
55
59
  effective_logger, owns_logger = _resolve_logger(run_id=run_id, logger=logger)
56
60
  try:
@@ -61,6 +65,7 @@ class WorkflowEngine:
61
65
  http_client=http_client,
62
66
  llm_cache=llm_cache,
63
67
  llm_cache_store=llm_cache_store,
68
+ provider_config=provider_config,
64
69
  )
65
70
  finally:
66
71
  if owns_logger:
@@ -76,6 +81,7 @@ class WorkflowEngine:
76
81
  http_client: httpx.AsyncClient | None = None,
77
82
  llm_cache: bool = False,
78
83
  llm_cache_store: LLMCacheStore | None = None,
84
+ provider_config: ProviderConfig | None = None,
79
85
  ) -> RunResult:
80
86
  plan = parse_plan(plan_data)
81
87
  return await self.run_plan(
@@ -86,6 +92,7 @@ class WorkflowEngine:
86
92
  http_client=http_client,
87
93
  llm_cache=llm_cache,
88
94
  llm_cache_store=llm_cache_store,
95
+ provider_config=provider_config,
89
96
  )
90
97
 
91
98
 
@@ -13,6 +13,7 @@ from dify_player.exceptions import PlanValidationError
13
13
  from dify_player.llm_cache import LLMCacheStore
14
14
  from dify_player.models import CompiledPlan, Plan, RunResult, WorkflowError
15
15
  from dify_player.plan_loader import compile_plan, load_input_data, load_plan_definition
16
+ from dify_player.provider_config import ProviderConfig
16
17
  from dify_player.runtime import WorkflowRuntime
17
18
 
18
19
 
@@ -33,11 +34,13 @@ class WorkflowExecutor:
33
34
  http_client: httpx.AsyncClient | None = None,
34
35
  llm_cache: bool = False,
35
36
  llm_cache_store: LLMCacheStore | None = None,
37
+ provider_config: ProviderConfig | None = None,
36
38
  ) -> RunResult:
37
39
  runtime = WorkflowRuntime(
38
40
  logger=logger,
39
41
  llm_cache_enabled=llm_cache,
40
42
  llm_cache_store=llm_cache_store,
43
+ provider_config=provider_config,
41
44
  )
42
45
  return await runtime.run(
43
46
  compiled_plan=compiled_plan,
@@ -58,6 +61,7 @@ class WorkflowExecutor:
58
61
  http_client: httpx.AsyncClient | None = None,
59
62
  llm_cache: bool = False,
60
63
  llm_cache_store: LLMCacheStore | None = None,
64
+ provider_config: ProviderConfig | None = None,
61
65
  ) -> RunResult:
62
66
  try:
63
67
  compiled_plan = compile_plan(plan)
@@ -79,6 +83,7 @@ class WorkflowExecutor:
79
83
  http_client=http_client,
80
84
  llm_cache=llm_cache,
81
85
  llm_cache_store=llm_cache_store,
86
+ provider_config=provider_config,
82
87
  )
83
88
 
84
89
  async def run_plan_path(
@@ -90,6 +95,7 @@ class WorkflowExecutor:
90
95
  http_client: httpx.AsyncClient | None = None,
91
96
  llm_cache: bool = False,
92
97
  llm_cache_store: LLMCacheStore | None = None,
98
+ provider_config: ProviderConfig | None = None,
93
99
  ) -> RunResult:
94
100
  run_id = uuid.uuid4().hex
95
101
  resolved_log_path = log_path if log_path is not None else build_default_log_path(run_id)
@@ -142,6 +148,7 @@ class WorkflowExecutor:
142
148
  http_client=http_client,
143
149
  llm_cache=llm_cache,
144
150
  llm_cache_store=llm_cache_store,
151
+ provider_config=provider_config,
145
152
  )
146
153
 
147
154
  if result.status == "failed":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dify-player
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Minimal workflow runner for hand-authored Dify-like plans.
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: Jinja2<4,>=3.1
@@ -11,6 +11,7 @@ dify_player/input_resolver.py
11
11
  dify_player/llm_cache.py
12
12
  dify_player/models.py
13
13
  dify_player/plan_loader.py
14
+ dify_player/provider_config.py
14
15
  dify_player/runtime.py
15
16
  dify_player/value_renderer.py
16
17
  dify_player/workflow_engine.py
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "dify-player"
10
- version = "0.3.4"
10
+ version = "0.3.6"
11
11
  description = "Minimal workflow runner for hand-authored Dify-like plans."
12
12
  requires-python = ">=3.11"
13
13
  dependencies = [
File without changes
File without changes