dify-player 0.3.5__tar.gz → 0.3.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.
- {dify_player-0.3.5 → dify_player-0.3.7}/PKG-INFO +1 -1
- {dify_player-0.3.5 → dify_player-0.3.7}/README.md +29 -3
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/__init__.py +1 -1
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/if_else.py +6 -2
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/__init__.py +12 -7
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/if_else.py +2 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/llm_azure_chat.py +23 -11
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/llm_groq_chat.py +17 -10
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/plan_loader.py +4 -2
- dify_player-0.3.7/dify_player/provider_config.py +38 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/runtime.py +38 -1
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/workflow_engine.py +7 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/workflow_executor.py +7 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player.egg-info/PKG-INFO +1 -1
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player.egg-info/SOURCES.txt +1 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/pyproject.toml +1 -1
- {dify_player-0.3.5 → dify_player-0.3.7}/MANIFEST.in +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/__main__.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/cli.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/__init__.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/graph_parser.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/http_body_converter.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/__init__.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/assigner.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/code.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/end.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/http_request.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/llm.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/loop.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/start.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/template_transform.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/variable_aggregator.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/plan_serializer.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/reference_converter.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/workflow_loader.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/workflow_normalizer.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_workflow_importer.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/event_logger.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/exceptions.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/input_resolver.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/llm_cache.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/models.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/assigner.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/code.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/end.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/http.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/llm_xai_chat.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/start.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/template.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/nodes/variable_aggregator.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player/value_renderer.py +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player.egg-info/dependency_links.txt +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player.egg-info/requires.txt +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/dify_player.egg-info/top_level.txt +0 -0
- {dify_player-0.3.5 → dify_player-0.3.7}/setup.cfg +0 -0
|
@@ -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 を渡します。
|
{dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/if_else.py
RENAMED
|
@@ -42,7 +42,7 @@ def convert_if_else_node(
|
|
|
42
42
|
)
|
|
43
43
|
comparison_operator = raw_condition.get("comparison_operator")
|
|
44
44
|
operator = _convert_comparison_operator(comparison_operator, node_id=node_id)
|
|
45
|
-
value = raw_condition.get("value")
|
|
45
|
+
value = raw_condition.get("value", "" if operator in {"empty", "not_empty"} else None)
|
|
46
46
|
if not isinstance(value, str):
|
|
47
47
|
raise PlanValidationError(
|
|
48
48
|
f"Dify if-else node {node_id!r} cases[{case_index}].conditions[{condition_index}].value must be a string"
|
|
@@ -88,4 +88,8 @@ def _convert_comparison_operator(raw_value: Any, *, node_id: str) -> str:
|
|
|
88
88
|
return "equals"
|
|
89
89
|
if raw_value == "empty":
|
|
90
90
|
return "empty"
|
|
91
|
-
|
|
91
|
+
if raw_value == "not empty":
|
|
92
|
+
return "not_empty"
|
|
93
|
+
raise PlanValidationError(
|
|
94
|
+
f"Dify if-else node {node_id!r} only supports comparison_operator=contains, '=', empty, or not empty"
|
|
95
|
+
)
|
|
@@ -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
|
-
|
|
51
|
-
node
|
|
52
|
-
workflow_inputs
|
|
53
|
-
node_outputs
|
|
54
|
-
resolved_inputs
|
|
55
|
-
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)
|
|
@@ -41,6 +41,8 @@ def _matches_condition(*, condition: dict[str, Any], resolved_inputs: dict[str,
|
|
|
41
41
|
return str(condition["value"]) in str(left_value)
|
|
42
42
|
if condition["operator"] == "empty":
|
|
43
43
|
return _is_empty(left_value)
|
|
44
|
+
if condition["operator"] == "not_empty":
|
|
45
|
+
return not _is_empty(left_value)
|
|
44
46
|
if condition["operator"] == "equals":
|
|
45
47
|
return str(left_value) == str(condition["value"])
|
|
46
48
|
raise ValueError(f"unsupported if_else operator {condition['operator']!r}")
|
|
@@ -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 =
|
|
26
|
-
|
|
27
|
-
|
|
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 =
|
|
38
|
-
|
|
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")
|
|
@@ -390,8 +390,10 @@ def _validate_if_else_config(*, node_id: str, node_name: str | None, config: dic
|
|
|
390
390
|
raise PlanValidationError(
|
|
391
391
|
f"if_else node {node_label!r} config.cases[{case_index}].conditions[{condition_index}] must be an object"
|
|
392
392
|
)
|
|
393
|
-
if condition.get("operator") not in {"contains", "empty", "equals"}:
|
|
394
|
-
raise PlanValidationError(
|
|
393
|
+
if condition.get("operator") not in {"contains", "empty", "equals", "not_empty"}:
|
|
394
|
+
raise PlanValidationError(
|
|
395
|
+
f"if_else node {node_label!r} only supports operator=contains, empty, equals, or not_empty"
|
|
396
|
+
)
|
|
395
397
|
input_name = condition.get("input_name")
|
|
396
398
|
if not isinstance(input_name, str) or not input_name:
|
|
397
399
|
raise PlanValidationError(
|
|
@@ -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":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/__init__.py
RENAMED
|
File without changes
|
{dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/assigner.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dify_player-0.3.5 → dify_player-0.3.7}/dify_player/dify_importer/node_converters/http_request.py
RENAMED
|
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
|
|
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
|
|
File without changes
|