Merge branch 'main' into feat/tool-oauth

pull/22338/head^2
zxhlyh 7 months ago
commit bda76080a9

@ -51,7 +51,7 @@ class File(BaseModel):
# It should be set to `ToolFile.id` when `transfer_method` is `tool_file`.
related_id: Optional[str] = None
filename: Optional[str] = None
extension: Optional[str] = Field(default=None, description="File extension, should contains dot")
extension: Optional[str] = Field(default=None, description="File extension, should contain dot")
mime_type: Optional[str] = None
size: int = -1

@ -1,67 +0,0 @@
import base64
import logging
import time
from typing import Optional
from configs import dify_config
from constants import IMAGE_EXTENSIONS
from core.helper.url_signer import UrlSigner
from extensions.ext_storage import storage
class UploadFileParser:
@classmethod
def get_image_data(cls, upload_file, force_url: bool = False) -> Optional[str]:
if not upload_file:
return None
if upload_file.extension not in IMAGE_EXTENSIONS:
return None
if dify_config.MULTIMODAL_SEND_FORMAT == "url" or force_url:
return cls.get_signed_temp_image_url(upload_file.id)
else:
# get image file base64
try:
data = storage.load(upload_file.key)
except FileNotFoundError:
logging.exception(f"File not found: {upload_file.key}")
return None
encoded_string = base64.b64encode(data).decode("utf-8")
return f"data:{upload_file.mime_type};base64,{encoded_string}"
@classmethod
def get_signed_temp_image_url(cls, upload_file_id) -> str:
"""
get signed url from upload file
:param upload_file_id: the id of UploadFile object
:return:
"""
base_url = dify_config.FILES_URL
image_preview_url = f"{base_url}/files/{upload_file_id}/image-preview"
return UrlSigner.get_signed_url(url=image_preview_url, sign_key=upload_file_id, prefix="image-preview")
@classmethod
def verify_image_file_signature(cls, upload_file_id: str, timestamp: str, nonce: str, sign: str) -> bool:
"""
verify signature
:param upload_file_id: file id
:param timestamp: timestamp
:param nonce: nonce
:param sign: signature
:return:
"""
result = UrlSigner.verify(
sign_key=upload_file_id, timestamp=timestamp, nonce=nonce, sign=sign, prefix="image-preview"
)
# verify signature
if not result:
return False
current_time = int(time.time())
return current_time - int(timestamp) <= dify_config.FILES_ACCESS_TIMEOUT

@ -1,22 +0,0 @@
from collections import OrderedDict
from typing import Any
class LRUCache:
def __init__(self, capacity: int):
self.cache: OrderedDict[Any, Any] = OrderedDict()
self.capacity = capacity
def get(self, key: Any) -> Any:
if key not in self.cache:
return None
else:
self.cache.move_to_end(key) # move the key to the end of the OrderedDict
return self.cache[key]
def put(self, key: Any, value: Any) -> None:
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False) # pop the first item

@ -372,6 +372,7 @@ class AliyunDataTrace(BaseTraceInstance):
) -> SpanData:
process_data = node_execution.process_data or {}
outputs = node_execution.outputs or {}
usage_data = process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
return SpanData(
trace_id=trace_id,
parent_span_id=workflow_span_id,
@ -385,9 +386,9 @@ class AliyunDataTrace(BaseTraceInstance):
GEN_AI_FRAMEWORK: "dify",
GEN_AI_MODEL_NAME: process_data.get("model_name", ""),
GEN_AI_SYSTEM: process_data.get("model_provider", ""),
GEN_AI_USAGE_INPUT_TOKENS: str(outputs.get("usage", {}).get("prompt_tokens", 0)),
GEN_AI_USAGE_OUTPUT_TOKENS: str(outputs.get("usage", {}).get("completion_tokens", 0)),
GEN_AI_USAGE_TOTAL_TOKENS: str(outputs.get("usage", {}).get("total_tokens", 0)),
GEN_AI_USAGE_INPUT_TOKENS: str(usage_data.get("prompt_tokens", 0)),
GEN_AI_USAGE_OUTPUT_TOKENS: str(usage_data.get("completion_tokens", 0)),
GEN_AI_USAGE_TOTAL_TOKENS: str(usage_data.get("total_tokens", 0)),
GEN_AI_PROMPT: json.dumps(process_data.get("prompts", []), ensure_ascii=False),
GEN_AI_COMPLETION: str(outputs.get("text", "")),
GEN_AI_RESPONSE_FINISH_REASON: outputs.get("finish_reason", ""),

@ -213,11 +213,12 @@ class ArizePhoenixDataTrace(BaseTraceInstance):
if model:
node_metadata["ls_model_name"] = model
usage = json.loads(node_execution.outputs).get("usage", {}) if node_execution.outputs else {}
if usage:
node_metadata["total_tokens"] = usage.get("total_tokens", 0)
node_metadata["prompt_tokens"] = usage.get("prompt_tokens", 0)
node_metadata["completion_tokens"] = usage.get("completion_tokens", 0)
outputs = json.loads(node_execution.outputs).get("usage", {})
usage_data = process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
if usage_data:
node_metadata["total_tokens"] = usage_data.get("total_tokens", 0)
node_metadata["prompt_tokens"] = usage_data.get("prompt_tokens", 0)
node_metadata["completion_tokens"] = usage_data.get("completion_tokens", 0)
elif node_execution.node_type == "dataset_retrieval":
span_kind = OpenInferenceSpanKindValues.RETRIEVER.value
elif node_execution.node_type == "tool":
@ -246,14 +247,19 @@ class ArizePhoenixDataTrace(BaseTraceInstance):
if model:
node_span.set_attribute(SpanAttributes.LLM_MODEL_NAME, model)
usage = json.loads(node_execution.outputs).get("usage", {}) if node_execution.outputs else {}
if usage:
node_span.set_attribute(SpanAttributes.LLM_TOKEN_COUNT_TOTAL, usage.get("total_tokens", 0))
outputs = json.loads(node_execution.outputs).get("usage", {})
usage_data = (
process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
)
if usage_data:
node_span.set_attribute(
SpanAttributes.LLM_TOKEN_COUNT_TOTAL, usage_data.get("total_tokens", 0)
)
node_span.set_attribute(
SpanAttributes.LLM_TOKEN_COUNT_PROMPT, usage.get("prompt_tokens", 0)
SpanAttributes.LLM_TOKEN_COUNT_PROMPT, usage_data.get("prompt_tokens", 0)
)
node_span.set_attribute(
SpanAttributes.LLM_TOKEN_COUNT_COMPLETION, usage.get("completion_tokens", 0)
SpanAttributes.LLM_TOKEN_COUNT_COMPLETION, usage_data.get("completion_tokens", 0)
)
finally:
node_span.end(end_time=datetime_to_nanos(finished_at))

@ -181,12 +181,9 @@ class LangFuseDataTrace(BaseTraceInstance):
prompt_tokens = 0
completion_tokens = 0
try:
if outputs.get("usage"):
prompt_tokens = outputs.get("usage", {}).get("prompt_tokens", 0)
completion_tokens = outputs.get("usage", {}).get("completion_tokens", 0)
else:
prompt_tokens = process_data.get("usage", {}).get("prompt_tokens", 0)
completion_tokens = process_data.get("usage", {}).get("completion_tokens", 0)
usage_data = process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
prompt_tokens = usage_data.get("prompt_tokens", 0)
completion_tokens = usage_data.get("completion_tokens", 0)
except Exception:
logger.error("Failed to extract usage", exc_info=True)

@ -206,12 +206,9 @@ class LangSmithDataTrace(BaseTraceInstance):
prompt_tokens = 0
completion_tokens = 0
try:
if outputs.get("usage"):
prompt_tokens = outputs.get("usage", {}).get("prompt_tokens", 0)
completion_tokens = outputs.get("usage", {}).get("completion_tokens", 0)
else:
prompt_tokens = process_data.get("usage", {}).get("prompt_tokens", 0)
completion_tokens = process_data.get("usage", {}).get("completion_tokens", 0)
usage_data = process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
prompt_tokens = usage_data.get("prompt_tokens", 0)
completion_tokens = usage_data.get("completion_tokens", 0)
except Exception:
logger.error("Failed to extract usage", exc_info=True)

@ -222,10 +222,10 @@ class OpikDataTrace(BaseTraceInstance):
)
try:
if outputs.get("usage"):
total_tokens = outputs["usage"].get("total_tokens", 0)
prompt_tokens = outputs["usage"].get("prompt_tokens", 0)
completion_tokens = outputs["usage"].get("completion_tokens", 0)
usage_data = process_data.get("usage", {}) if "usage" in process_data else outputs.get("usage", {})
total_tokens = usage_data.get("total_tokens", 0)
prompt_tokens = usage_data.get("prompt_tokens", 0)
completion_tokens = usage_data.get("completion_tokens", 0)
except Exception:
logger.error("Failed to extract usage", exc_info=True)

@ -122,7 +122,6 @@ class TencentVector(BaseVector):
metric_type,
params,
)
index_text = vdb_index.FilterIndex(self.field_text, enum.FieldType.String, enum.IndexType.FILTER)
index_metadate = vdb_index.FilterIndex(self.field_metadata, enum.FieldType.Json, enum.IndexType.FILTER)
index_sparse_vector = vdb_index.SparseIndex(
name="sparse_vector",
@ -130,7 +129,7 @@ class TencentVector(BaseVector):
index_type=enum.IndexType.SPARSE_INVERTED,
metric_type=enum.MetricType.IP,
)
indexes = [index_id, index_vector, index_text, index_metadate]
indexes = [index_id, index_vector, index_metadate]
if self._enable_hybrid_search:
indexes.append(index_sparse_vector)
try:
@ -149,7 +148,7 @@ class TencentVector(BaseVector):
index_metadate = vdb_index.FilterIndex(
self.field_metadata, enum.FieldType.String, enum.IndexType.FILTER
)
indexes = [index_id, index_vector, index_text, index_metadate]
indexes = [index_id, index_vector, index_metadate]
if self._enable_hybrid_search:
indexes.append(index_sparse_vector)
self._client.create_collection(

@ -17,6 +17,7 @@ from core.workflow.entities.workflow_execution import (
)
from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository
from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter
from libs.helper import extract_tenant_id
from models import (
Account,
CreatorUserRole,
@ -67,7 +68,7 @@ class SQLAlchemyWorkflowExecutionRepository(WorkflowExecutionRepository):
)
# Extract tenant_id from user
tenant_id: str | None = user.tenant_id if isinstance(user, EndUser) else user.current_tenant_id
tenant_id = extract_tenant_id(user)
if not tenant_id:
raise ValueError("User must have a tenant_id or current_tenant_id")
self._tenant_id = tenant_id

@ -20,6 +20,7 @@ from core.workflow.entities.workflow_node_execution import (
from core.workflow.nodes.enums import NodeType
from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository
from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter
from libs.helper import extract_tenant_id
from models import (
Account,
CreatorUserRole,
@ -70,7 +71,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository)
)
# Extract tenant_id from user
tenant_id: str | None = user.tenant_id if isinstance(user, EndUser) else user.current_tenant_id
tenant_id = extract_tenant_id(user)
if not tenant_id:
raise ValueError("User must have a tenant_id or current_tenant_id")
self._tenant_id = tenant_id

@ -221,15 +221,6 @@ class LLMNode(BaseNode[LLMNodeData]):
jinja2_variables=self.node_data.prompt_config.jinja2_variables,
)
process_data = {
"model_mode": model_config.mode,
"prompts": PromptMessageUtil.prompt_messages_to_prompt_for_saving(
model_mode=model_config.mode, prompt_messages=prompt_messages
),
"model_provider": model_config.provider,
"model_name": model_config.model,
}
# handle invoke result
generator = self._invoke_llm(
node_data_model=self.node_data.model,
@ -253,6 +244,17 @@ class LLMNode(BaseNode[LLMNodeData]):
elif isinstance(event, LLMStructuredOutput):
structured_output = event
process_data = {
"model_mode": model_config.mode,
"prompts": PromptMessageUtil.prompt_messages_to_prompt_for_saving(
model_mode=model_config.mode, prompt_messages=prompt_messages
),
"usage": jsonable_encoder(usage),
"finish_reason": finish_reason,
"model_provider": model_config.provider,
"model_name": model_config.model,
}
outputs = {"text": result_text, "usage": jsonable_encoder(usage), "finish_reason": finish_reason}
if structured_output:
outputs["structured_output"] = structured_output.structured_output

@ -253,7 +253,12 @@ class ParameterExtractorNode(BaseNode):
status=WorkflowNodeExecutionStatus.SUCCEEDED,
inputs=inputs,
process_data=process_data,
outputs={"__is_success": 1 if not error else 0, "__reason": error, **result},
outputs={
"__is_success": 1 if not error else 0,
"__reason": error,
"__usage": jsonable_encoder(usage),
**result,
},
metadata={
WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: usage.total_tokens,
WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: usage.total_price,

@ -145,7 +145,11 @@ class QuestionClassifierNode(LLMNode):
"model_provider": model_config.provider,
"model_name": model_config.model,
}
outputs = {"class_name": category_name, "class_id": category_id}
outputs = {
"class_name": category_name,
"class_id": category_id,
"usage": jsonable_encoder(usage),
}
return NodeRunResult(
status=WorkflowNodeExecutionStatus.SUCCEEDED,

@ -12,6 +12,7 @@ from flask_login import user_loaded_from_request, user_logged_in # type: ignore
from configs import dify_config
from dify_app import DifyApp
from libs.helper import extract_tenant_id
from models import Account, EndUser
@ -24,11 +25,8 @@ def on_user_loaded(_sender, user: Union["Account", "EndUser"]):
if user:
try:
current_span = get_current_span()
if isinstance(user, Account) and user.current_tenant_id:
tenant_id = user.current_tenant_id
elif isinstance(user, EndUser):
tenant_id = user.tenant_id
else:
tenant_id = extract_tenant_id(user)
if not tenant_id:
return
if current_span:
current_span.set_attribute("service.tenant.id", tenant_id)

@ -17,6 +17,7 @@ class EnvironmentVariableField(fields.Raw):
"name": value.name,
"value": encrypter.obfuscated_token(value.value),
"value_type": value.value_type.value,
"description": value.description,
}
if isinstance(value, Variable):
return {
@ -24,6 +25,7 @@ class EnvironmentVariableField(fields.Raw):
"name": value.name,
"value": value.value,
"value_type": value.value_type.value,
"description": value.description,
}
if isinstance(value, dict):
value_type = value.get("value_type")

@ -25,6 +25,31 @@ from extensions.ext_redis import redis_client
if TYPE_CHECKING:
from models.account import Account
from models.model import EndUser
def extract_tenant_id(user: Union["Account", "EndUser"]) -> str | None:
"""
Extract tenant_id from Account or EndUser object.
Args:
user: Account or EndUser object
Returns:
tenant_id string if available, None otherwise
Raises:
ValueError: If user is neither Account nor EndUser
"""
from models.account import Account
from models.model import EndUser
if isinstance(user, Account):
return user.current_tenant_id
elif isinstance(user, EndUser):
return user.tenant_id
else:
raise ValueError(f"Invalid user type: {type(user)}. Expected Account or EndUser.")
def run(script):

@ -15,6 +15,7 @@ from core.variables import utils as variable_utils
from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID
from core.workflow.nodes.enums import NodeType
from factories.variable_factory import TypeMismatchError, build_segment_with_type
from libs.helper import extract_tenant_id
from ._workflow_exc import NodeNotFoundError, WorkflowDataError
@ -352,12 +353,7 @@ class Workflow(Base):
self._environment_variables = "{}"
# Get tenant_id from current_user (Account or EndUser)
if isinstance(current_user, Account):
# Account user
tenant_id = current_user.current_tenant_id
else:
# EndUser
tenant_id = current_user.tenant_id
tenant_id = extract_tenant_id(current_user)
if not tenant_id:
return []
@ -384,12 +380,7 @@ class Workflow(Base):
return
# Get tenant_id from current_user (Account or EndUser)
if isinstance(current_user, Account):
# Account user
tenant_id = current_user.current_tenant_id
else:
# EndUser
tenant_id = current_user.tenant_id
tenant_id = extract_tenant_id(current_user)
if not tenant_id:
self._environment_variables = "{}"

@ -18,6 +18,7 @@ from core.file import helpers as file_helpers
from core.rag.extractor.extract_processor import ExtractProcessor
from extensions.ext_database import db
from extensions.ext_storage import storage
from libs.helper import extract_tenant_id
from models.account import Account
from models.enums import CreatorUserRole
from models.model import EndUser, UploadFile
@ -61,11 +62,7 @@ class FileService:
# generate file key
file_uuid = str(uuid.uuid4())
if isinstance(user, Account):
current_tenant_id = user.current_tenant_id
else:
# end_user
current_tenant_id = user.tenant_id
current_tenant_id = extract_tenant_id(user)
file_key = "upload_files/" + (current_tenant_id or "") + "/" + file_uuid + "." + extension

@ -0,0 +1,194 @@
from unittest.mock import patch
from urllib.parse import parse_qs, urlparse
import pytest
from core.helper.url_signer import SignedUrlParams, UrlSigner
class TestUrlSigner:
"""Test cases for UrlSigner class"""
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_generate_signed_url_params(self):
"""Test generation of signed URL parameters with all required fields"""
sign_key = "test-sign-key"
prefix = "test-prefix"
params = UrlSigner.get_signed_url_params(sign_key, prefix)
# Verify the returned object and required fields
assert isinstance(params, SignedUrlParams)
assert params.sign_key == sign_key
assert params.timestamp is not None
assert params.nonce is not None
assert params.sign is not None
# Verify nonce format (32 character hex string)
assert len(params.nonce) == 32
assert all(c in "0123456789abcdef" for c in params.nonce)
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_generate_complete_signed_url(self):
"""Test generation of complete signed URL with query parameters"""
base_url = "https://example.com/api/test"
sign_key = "test-sign-key"
prefix = "test-prefix"
signed_url = UrlSigner.get_signed_url(base_url, sign_key, prefix)
# Parse URL and verify structure
parsed = urlparse(signed_url)
assert f"{parsed.scheme}://{parsed.netloc}{parsed.path}" == base_url
# Verify query parameters
query_params = parse_qs(parsed.query)
assert "timestamp" in query_params
assert "nonce" in query_params
assert "sign" in query_params
# Verify each parameter has exactly one value
assert len(query_params["timestamp"]) == 1
assert len(query_params["nonce"]) == 1
assert len(query_params["sign"]) == 1
# Verify parameter values are not empty
assert query_params["timestamp"][0]
assert query_params["nonce"][0]
assert query_params["sign"][0]
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_verify_valid_signature(self):
"""Test verification of valid signature"""
sign_key = "test-sign-key"
prefix = "test-prefix"
# Generate and verify signature
params = UrlSigner.get_signed_url_params(sign_key, prefix)
is_valid = UrlSigner.verify(
sign_key=sign_key, timestamp=params.timestamp, nonce=params.nonce, sign=params.sign, prefix=prefix
)
assert is_valid is True
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
@pytest.mark.parametrize(
("field", "modifier"),
[
("sign_key", lambda _: "wrong-sign-key"),
("timestamp", lambda t: str(int(t) + 1000)),
("nonce", lambda _: "different-nonce-123456789012345"),
("prefix", lambda _: "wrong-prefix"),
("sign", lambda s: s + "tampered"),
],
)
def test_should_reject_invalid_signature_params(self, field, modifier):
"""Test signature verification rejects invalid parameters"""
sign_key = "test-sign-key"
prefix = "test-prefix"
# Generate valid signed parameters
params = UrlSigner.get_signed_url_params(sign_key, prefix)
# Prepare verification parameters
verify_params = {
"sign_key": sign_key,
"timestamp": params.timestamp,
"nonce": params.nonce,
"sign": params.sign,
"prefix": prefix,
}
# Modify the specific field
verify_params[field] = modifier(verify_params[field])
# Verify should fail
is_valid = UrlSigner.verify(**verify_params)
assert is_valid is False
@patch("configs.dify_config.SECRET_KEY", None)
def test_should_raise_error_without_secret_key(self):
"""Test that signing fails when SECRET_KEY is not configured"""
with pytest.raises(Exception) as exc_info:
UrlSigner.get_signed_url_params("key", "prefix")
assert "SECRET_KEY is not set" in str(exc_info.value)
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_generate_unique_signatures(self):
"""Test that different inputs produce different signatures"""
params1 = UrlSigner.get_signed_url_params("key1", "prefix1")
params2 = UrlSigner.get_signed_url_params("key2", "prefix2")
# Different inputs should produce different signatures
assert params1.sign != params2.sign
assert params1.nonce != params2.nonce
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_handle_special_characters(self):
"""Test handling of special characters in parameters"""
special_cases = [
"test with spaces",
"test/with/slashes",
"test中文字符",
]
for sign_key in special_cases:
params = UrlSigner.get_signed_url_params(sign_key, "prefix")
# Should generate valid signature and verify correctly
is_valid = UrlSigner.verify(
sign_key=sign_key, timestamp=params.timestamp, nonce=params.nonce, sign=params.sign, prefix="prefix"
)
assert is_valid is True
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_ensure_nonce_randomness(self):
"""Test that nonce is random for each generation - critical for security"""
sign_key = "test-sign-key"
prefix = "test-prefix"
# Generate multiple nonces
nonces = set()
for _ in range(5):
params = UrlSigner.get_signed_url_params(sign_key, prefix)
nonces.add(params.nonce)
# All nonces should be unique
assert len(nonces) == 5
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
@patch("time.time", return_value=1234567890)
@patch("os.urandom", return_value=b"\xab\xcd\xef\x12\x34\x56\x78\x90\xab\xcd\xef\x12\x34\x56\x78\x90")
def test_should_produce_consistent_signatures(self, mock_urandom, mock_time):
"""Test that same inputs produce same signature - ensures deterministic behavior"""
sign_key = "test-sign-key"
prefix = "test-prefix"
# Generate signature multiple times with same inputs (time and nonce are mocked)
params1 = UrlSigner.get_signed_url_params(sign_key, prefix)
params2 = UrlSigner.get_signed_url_params(sign_key, prefix)
# With mocked time and random, should produce identical results
assert params1.timestamp == params2.timestamp
assert params1.nonce == params2.nonce
assert params1.sign == params2.sign
# Verify the signature is valid
assert UrlSigner.verify(
sign_key=sign_key, timestamp=params1.timestamp, nonce=params1.nonce, sign=params1.sign, prefix=prefix
)
@patch("configs.dify_config.SECRET_KEY", "test-secret-key-12345")
def test_should_handle_empty_strings(self):
"""Test handling of empty string parameters - common edge case"""
# Empty sign_key and prefix should still work
params = UrlSigner.get_signed_url_params("", "")
assert params.sign is not None
# Should verify correctly
is_valid = UrlSigner.verify(
sign_key="", timestamp=params.timestamp, nonce=params.nonce, sign=params.sign, prefix=""
)
assert is_valid is True

@ -0,0 +1,65 @@
import pytest
from libs.helper import extract_tenant_id
from models.account import Account
from models.model import EndUser
class TestExtractTenantId:
"""Test cases for the extract_tenant_id utility function."""
def test_extract_tenant_id_from_account_with_tenant(self):
"""Test extracting tenant_id from Account with current_tenant_id."""
# Create a mock Account object
account = Account()
# Mock the current_tenant_id property
account._current_tenant = type("MockTenant", (), {"id": "account-tenant-123"})()
tenant_id = extract_tenant_id(account)
assert tenant_id == "account-tenant-123"
def test_extract_tenant_id_from_account_without_tenant(self):
"""Test extracting tenant_id from Account without current_tenant_id."""
# Create a mock Account object
account = Account()
account._current_tenant = None
tenant_id = extract_tenant_id(account)
assert tenant_id is None
def test_extract_tenant_id_from_enduser_with_tenant(self):
"""Test extracting tenant_id from EndUser with tenant_id."""
# Create a mock EndUser object
end_user = EndUser()
end_user.tenant_id = "enduser-tenant-456"
tenant_id = extract_tenant_id(end_user)
assert tenant_id == "enduser-tenant-456"
def test_extract_tenant_id_from_enduser_without_tenant(self):
"""Test extracting tenant_id from EndUser without tenant_id."""
# Create a mock EndUser object
end_user = EndUser()
end_user.tenant_id = None
tenant_id = extract_tenant_id(end_user)
assert tenant_id is None
def test_extract_tenant_id_with_invalid_user_type(self):
"""Test extracting tenant_id with invalid user type raises ValueError."""
invalid_user = "not_a_user_object"
with pytest.raises(ValueError, match="Invalid user type.*Expected Account or EndUser"):
extract_tenant_id(invalid_user)
def test_extract_tenant_id_with_none_user(self):
"""Test extracting tenant_id with None user raises ValueError."""
with pytest.raises(ValueError, match="Invalid user type.*Expected Account or EndUser"):
extract_tenant_id(None)
def test_extract_tenant_id_with_dict_user(self):
"""Test extracting tenant_id with dict user raises ValueError."""
dict_user = {"id": "123", "tenant_id": "456"}
with pytest.raises(ValueError, match="Invalid user type.*Expected Account or EndUser"):
extract_tenant_id(dict_user)

@ -9,6 +9,7 @@ from core.file.models import File
from core.variables import FloatVariable, IntegerVariable, SecretVariable, StringVariable
from core.variables.segments import IntegerSegment, Segment
from factories.variable_factory import build_segment
from models.model import EndUser
from models.workflow import Workflow, WorkflowDraftVariable, WorkflowNodeExecutionModel, is_system_variable_editable
@ -43,7 +44,7 @@ def test_environment_variables():
)
# Mock current_user as an EndUser
mock_user = mock.Mock()
mock_user = mock.Mock(spec=EndUser)
mock_user.tenant_id = "tenant_id"
with (
@ -90,7 +91,7 @@ def test_update_environment_variables():
)
# Mock current_user as an EndUser
mock_user = mock.Mock()
mock_user = mock.Mock(spec=EndUser)
mock_user.tenant_id = "tenant_id"
with (
@ -136,7 +137,7 @@ def test_to_dict():
# Create some EnvironmentVariable instances
# Mock current_user as an EndUser
mock_user = mock.Mock()
mock_user = mock.Mock(spec=EndUser)
mock_user.tenant_id = "tenant_id"
with (

@ -826,6 +826,9 @@ MAX_ITERATIONS_NUM=99
# The timeout for the text generation in millisecond
TEXT_GENERATION_TIMEOUT_MS=60000
# Allow rendering unsafe URLs which have "data:" scheme.
ALLOW_UNSAFE_DATA_SCHEME=false
# ------------------------------
# Environment Variables for db Service
# ------------------------------

@ -67,6 +67,7 @@ services:
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}

@ -364,6 +364,7 @@ x-shared-env: &shared-api-worker-env
MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
POSTGRES_USER: ${POSTGRES_USER:-${DB_USERNAME}}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-${DB_PASSWORD}}
POSTGRES_DB: ${POSTGRES_DB:-${DB_DATABASE}}
@ -582,6 +583,7 @@ services:
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
CSP_WHITELIST: ${CSP_WHITELIST:-}
ALLOW_EMBED: ${ALLOW_EMBED:-false}
ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}

@ -32,6 +32,9 @@ NEXT_PUBLIC_CSP_WHITELIST=
# Default is not allow to embed into iframe to prevent Clickjacking: https://owasp.org/www-community/attacks/Clickjacking
NEXT_PUBLIC_ALLOW_EMBED=
# Allow rendering unsafe URLs which have "data:" scheme.
NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME=false
# Github Access Token, used for invoking Github API
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN=
# The maximum number of top-k value for RAG.

@ -1,3 +1,7 @@
import { ALLOW_UNSAFE_DATA_SCHEME } from '@/config'
export const isValidUrl = (url: string): boolean => {
return ['http:', 'https:', '//', 'mailto:'].some(prefix => url.startsWith(prefix))
const validPrefixes = ['http:', 'https:', '//', 'mailto:']
if (ALLOW_UNSAFE_DATA_SCHEME) validPrefixes.push('data:')
return validPrefixes.some(prefix => url.startsWith(prefix))
}

@ -4,6 +4,7 @@
* Includes preprocessing for LaTeX and custom "think" tags.
*/
import { flow } from 'lodash-es'
import { ALLOW_UNSAFE_DATA_SCHEME } from '@/config'
export const preprocessLaTeX = (content: string) => {
if (typeof content !== 'string')
@ -86,5 +87,8 @@ export const customUrlTransform = (uri: string): string | undefined => {
if (PERMITTED_SCHEME_REGEX.test(scheme))
return uri
if (ALLOW_UNSAFE_DATA_SCHEME && scheme === 'data:')
return uri
return undefined
}

@ -101,7 +101,7 @@ const Tooltip: FC<TooltipProps> = ({
>
{popupContent && (<div
className={cn(
!noDecoration && 'system-xs-regular relative break-words rounded-md bg-components-panel-bg px-3 py-2 text-text-tertiary shadow-lg',
!noDecoration && 'system-xs-regular relative max-w-[300px] break-words rounded-md bg-components-panel-bg px-3 py-2 text-left text-text-tertiary shadow-lg',
popupClassName,
)}
onMouseEnter={() => triggerMethod === 'hover' && setHoverPopup()}

@ -480,6 +480,10 @@ export const LLM_OUTPUT_STRUCT: Var[] = [
variable: 'text',
type: VarType.string,
},
{
variable: 'usage',
type: VarType.object,
},
]
export const KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT: Var[] = [
@ -501,6 +505,10 @@ export const QUESTION_CLASSIFIER_OUTPUT_STRUCT = [
variable: 'class_name',
type: VarType.string,
},
{
variable: 'usage',
type: VarType.object,
},
]
export const HTTP_REQUEST_OUTPUT_STRUCT: Var[] = [
@ -546,6 +554,10 @@ export const PARAMETER_EXTRACTOR_COMMON_STRUCT: Var[] = [
variable: '__reason',
type: VarType.string,
},
{
variable: '__usage',
type: VarType.object,
},
]
export const FILE_STRUCT: Var[] = [

@ -462,6 +462,7 @@ const formatItem = (
return {
variable: `env.${env.name}`,
type: env.value_type,
description: env.description,
}
}) as Var[]
break
@ -472,7 +473,7 @@ const formatItem = (
return {
variable: `conversation.${chatVar.name}`,
type: chatVar.value_type,
des: chatVar.description,
description: chatVar.description,
}
}) as Var[]
break

@ -22,6 +22,7 @@ const nodeDefault: NodeDefault<HttpNodeType> = {
type: BodyType.none,
data: [],
},
ssl_verify: true,
timeout: {
max_connect_timeout: 0,
max_read_timeout: 0,

@ -10,6 +10,7 @@ import type { HttpNodeType } from './types'
import Timeout from './components/timeout'
import CurlPanel from './components/curl-panel'
import cn from '@/utils/classnames'
import Switch from '@/app/components/base/switch'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import Split from '@/app/components/workflow/nodes/_base/components/split'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
@ -47,6 +48,7 @@ const Panel: FC<NodePanelProps<HttpNodeType>> = ({
showCurlPanel,
hideCurlPanel,
handleCurlImport,
handleSSLVerifyChange,
} = useConfig(id, data)
// To prevent prompt editor in body not update data.
if (!isDataReady)
@ -124,6 +126,18 @@ const Panel: FC<NodePanelProps<HttpNodeType>> = ({
onChange={setBody}
/>
</Field>
<Field
title={t(`${i18nPrefix}.verifySSL.title`)}
tooltip={t(`${i18nPrefix}.verifySSL.warningTooltip`)}
operations={
<Switch
defaultValue={!!inputs.ssl_verify}
onChange={handleSSLVerifyChange}
size='md'
disabled={readOnly}
/>
}>
</Field>
</div>
<Split />
<Timeout

@ -81,4 +81,5 @@ export type HttpNodeType = CommonNodeType & {
body: Body
authorization: Authorization
timeout: Timeout
ssl_verify?: boolean
}

@ -141,6 +141,13 @@ const useConfig = (id: string, payload: HttpNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
const handleSSLVerifyChange = useCallback((checked: boolean) => {
const newInputs = produce(inputs, (draft: HttpNodeType) => {
draft.ssl_verify = checked
})
setInputs(newInputs)
}, [inputs, setInputs])
return {
readOnly,
isDataReady,
@ -164,6 +171,8 @@ const useConfig = (id: string, payload: HttpNodeType) => {
toggleIsParamKeyValueEdit,
// body
setBody,
// ssl verify
handleSSLVerifyChange,
// authorization
isShowAuthorization,
showAuthorization,

@ -282,6 +282,11 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
type='string'
description={t(`${i18nPrefix}.outputVars.output`)}
/>
<VarItem
name='usage'
type='object'
description={t(`${i18nPrefix}.outputVars.usage`)}
/>
{inputs.structured_output_enabled && (
<>
<Split className='mt-3' />

@ -190,12 +190,17 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
<VarItem
name='__is_success'
type={VarType.number}
description={t(`${i18nPrefix}.isSuccess`)}
description={t(`${i18nPrefix}.outputVars.isSuccess`)}
/>
<VarItem
name='__reason'
type={VarType.string}
description={t(`${i18nPrefix}.errorReason`)}
description={t(`${i18nPrefix}.outputVars.errorReason`)}
/>
<VarItem
name='__usage'
type='object'
description={t(`${i18nPrefix}.outputVars.usage`)}
/>
</>
</OutputVars>

@ -129,6 +129,11 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
type='string'
description={t(`${i18nPrefix}.outputVars.className`)}
/>
<VarItem
name='usage'
type='object'
description={t(`${i18nPrefix}.outputVars.usage`)}
/>
</>
</OutputVars>
</div>

@ -80,7 +80,7 @@ const ChatVariableModal = ({
const [objectValue, setObjectValue] = React.useState<ObjectValueItem[]>([DEFAULT_OBJECT_VALUE])
const [editorContent, setEditorContent] = React.useState<string>()
const [editInJSON, setEditInJSON] = React.useState(false)
const [des, setDes] = React.useState<string>('')
const [description, setDescription] = React.useState<string>('')
const editorMinHeight = useMemo(() => {
if (type === ChatVarType.ArrayObject)
@ -237,7 +237,7 @@ const ChatVariableModal = ({
name,
value_type: type,
value: formatValue(value),
description: des,
description,
})
onClose()
}
@ -247,7 +247,7 @@ const ChatVariableModal = ({
setName(chatVar.name)
setType(chatVar.value_type)
setValue(chatVar.value)
setDes(chatVar.description)
setDescription(chatVar.description)
setObjectValue(getObjectValue())
if (chatVar.value_type === ChatVarType.ArrayObject) {
setEditorContent(JSON.stringify(chatVar.value))
@ -385,9 +385,9 @@ const ChatVariableModal = ({
<div className='flex'>
<textarea
className='system-sm-regular placeholder:system-sm-regular block h-20 w-full resize-none appearance-none rounded-lg border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'
value={des}
value={description}
placeholder={t('workflow.chatVariable.modal.descriptionPlaceholder') || ''}
onChange={e => setDes(e.target.value)}
onChange={e => setDescription(e.target.value)}
/>
</div>
</div>

@ -22,30 +22,42 @@ const EnvItem = ({
return (
<div className={cn(
'radius-md mb-1 border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg px-2.5 py-2 shadow-xs hover:bg-components-panel-on-panel-item-bg-hover',
'radius-md group mb-1 border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-xs hover:bg-components-panel-on-panel-item-bg-hover',
destructive && 'border-state-destructive-border hover:bg-state-destructive-hover',
)}>
<div className='flex items-center justify-between'>
<div className='flex grow items-center gap-1'>
<Env className='h-4 w-4 text-util-colors-violet-violet-600' />
<div className='system-sm-medium text-text-primary'>{env.name}</div>
<div className='system-xs-medium text-text-tertiary'>{capitalize(env.value_type)}</div>
{env.value_type === 'secret' && <RiLock2Line className='h-3 w-3 text-text-tertiary' />}
</div>
<div className='flex shrink-0 items-center gap-1 text-text-tertiary'>
<div className='radius-md cursor-pointer p-1 hover:bg-state-base-hover hover:text-text-secondary'>
<RiEditLine className='h-4 w-4' onClick={() => onEdit(env)}/>
<div className='px-2.5 py-2'>
<div className='flex items-center justify-between'>
<div className='flex grow items-center gap-1'>
<Env className='h-4 w-4 text-util-colors-violet-violet-600' />
<div className='system-sm-medium text-text-primary'>{env.name}</div>
<div className='system-xs-medium text-text-tertiary'>{capitalize(env.value_type)}</div>
{env.value_type === 'secret' && <RiLock2Line className='h-3 w-3 text-text-tertiary' />}
</div>
<div
className='radius-md cursor-pointer p-1 hover:bg-state-destructive-hover hover:text-text-destructive'
onMouseOver={() => setDestructive(true)}
onMouseOut={() => setDestructive(false)}
>
<RiDeleteBinLine className='h-4 w-4' onClick={() => onDelete(env)} />
<div className='flex shrink-0 items-center gap-1 text-text-tertiary'>
<div className='radius-md cursor-pointer p-1 hover:bg-state-base-hover hover:text-text-secondary'>
<RiEditLine className='h-4 w-4' onClick={() => onEdit(env)}/>
</div>
<div
className='radius-md cursor-pointer p-1 hover:bg-state-destructive-hover hover:text-text-destructive'
onMouseOver={() => setDestructive(true)}
onMouseOut={() => setDestructive(false)}
>
<RiDeleteBinLine className='h-4 w-4' onClick={() => onDelete(env)} />
</div>
</div>
</div>
<div className='system-xs-regular truncate text-text-tertiary'>{env.value_type === 'secret' ? envSecrets[env.id] : env.value}</div>
</div>
<div className='system-xs-regular truncate text-text-tertiary'>{env.value_type === 'secret' ? envSecrets[env.id] : env.value}</div>
{env.description && (
<>
<div className={'h-[0.5px] bg-divider-subtle'} />
<div className={cn('rounded-bl-[8px] rounded-br-[8px] bg-background-default-subtle px-2.5 py-2 group-hover:bg-transparent',
destructive && 'bg-state-destructive-hover hover:bg-state-destructive-hover',
)}>
<div className='system-xs-regular truncate text-text-tertiary'>{env.description}</div>
</div>
</>
)}
</div>
)
}

@ -29,6 +29,7 @@ const VariableModal = ({
const [type, setType] = React.useState<'string' | 'number' | 'secret'>('string')
const [name, setName] = React.useState('')
const [value, setValue] = React.useState<any>()
const [description, setDescription] = React.useState<string>('')
const checkVariableName = (value: string) => {
const { isValid, errorMessageKey } = checkKeys([value], false)
@ -67,6 +68,7 @@ const VariableModal = ({
value_type: type,
name,
value: type === 'number' ? Number(value) : value,
description,
})
onClose()
}
@ -76,6 +78,7 @@ const VariableModal = ({
setType(env.value_type)
setName(env.name)
setValue(env.value_type === 'secret' ? envSecrets[env.id] : env.value)
setDescription(env.description)
}
}, [env, envSecrets])
@ -141,7 +144,7 @@ const VariableModal = ({
</div>
</div>
{/* value */}
<div className=''>
<div className='mb-4'>
<div className='system-sm-semibold mb-1 flex h-6 items-center text-text-secondary'>{t('workflow.env.modal.value')}</div>
<div className='flex'>
{
@ -160,6 +163,18 @@ const VariableModal = ({
}
</div>
</div>
{/* description */}
<div className=''>
<div className='system-sm-semibold mb-1 flex h-6 items-center text-text-secondary'>{t('workflow.env.modal.description')}</div>
<div className='flex'>
<textarea
className='system-sm-regular placeholder:system-sm-regular block h-20 w-full resize-none appearance-none rounded-lg border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'
value={description}
placeholder={t('workflow.env.modal.descriptionPlaceholder') || ''}
onChange={e => setDescription(e.target.value)}
/>
</div>
</div>
</div>
<div className='flex flex-row-reverse rounded-b-2xl p-4 pt-2'>
<div className='flex gap-2'>

@ -149,6 +149,7 @@ export type EnvironmentVariable = {
name: string
value: any
value_type: 'string' | 'number' | 'secret'
description: string
}
export type ConversationVariable = {

@ -44,6 +44,7 @@ const LocaleLayout = async ({
[DatasetAttr.DATA_PUBLIC_LOOP_NODE_MAX_COUNT]: process.env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT,
[DatasetAttr.DATA_PUBLIC_MAX_ITERATIONS_NUM]: process.env.NEXT_PUBLIC_MAX_ITERATIONS_NUM,
[DatasetAttr.DATA_PUBLIC_MAX_TREE_DEPTH]: process.env.NEXT_PUBLIC_MAX_TREE_DEPTH,
[DatasetAttr.DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME]: process.env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME,
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER,
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL,
[DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL]: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL,

@ -270,6 +270,7 @@ export const LOOP_NODE_MAX_COUNT = getNumberConfig(process.env.NEXT_PUBLIC_LOOP_
export const MAX_ITERATIONS_NUM = getNumberConfig(process.env.NEXT_PUBLIC_MAX_ITERATIONS_NUM, DatasetAttr.DATA_PUBLIC_MAX_ITERATIONS_NUM, 99)
export const MAX_TREE_DEPTH = getNumberConfig(process.env.NEXT_PUBLIC_MAX_TREE_DEPTH, DatasetAttr.DATA_PUBLIC_MAX_TREE_DEPTH, 50)
export const ALLOW_UNSAFE_DATA_SCHEME = getBooleanConfig(process.env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, DatasetAttr.DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, false)
export const ENABLE_WEBSITE_JINAREADER = getBooleanConfig(process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER, DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER, true)
export const ENABLE_WEBSITE_FIRECRAWL = getBooleanConfig(process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, true)
export const ENABLE_WEBSITE_WATERCRAWL = getBooleanConfig(process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, false)

@ -26,6 +26,7 @@ export NEXT_TELEMETRY_DISABLED=${NEXT_TELEMETRY_DISABLED}
export NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=${TEXT_GENERATION_TIMEOUT_MS}
export NEXT_PUBLIC_CSP_WHITELIST=${CSP_WHITELIST}
export NEXT_PUBLIC_ALLOW_EMBED=${ALLOW_EMBED}
export NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME=${ALLOW_UNSAFE_DATA_SCHEME:-false}
export NEXT_PUBLIC_TOP_K_MAX_VALUE=${TOP_K_MAX_VALUE}
export NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH}
export NEXT_PUBLIC_MAX_TOOLS_NUM=${MAX_TOOLS_NUM}

@ -129,6 +129,8 @@ const translation = {
value: 'Wert',
valuePlaceholder: 'Umgebungswert',
secretTip: 'Wird verwendet, um sensible Informationen oder Daten zu definieren, wobei DSL-Einstellungen zur Verhinderung von Lecks konfiguriert sind.',
description: 'Beschreibung',
descriptionPlaceholder: 'Beschreiben Sie die Variable',
},
export: {
title: 'Geheime Umgebungsvariablen exportieren?',
@ -537,6 +539,10 @@ const translation = {
title: 'Importieren von cURL',
placeholder: 'Fügen Sie hier die cURL-Zeichenfolge ein',
},
verifySSL: {
title: 'SSL-Zertifikat überprüfen',
warningTooltip: 'Das Deaktivieren der SSL-Überprüfung wird für Produktionsumgebungen nicht empfohlen. Dies sollte nur in der Entwicklung oder im Test verwendet werden, da es die Verbindung anfällig für Sicherheitsbedrohungen wie Man-in-the-Middle-Angriffe macht.',
},
},
code: {
inputVars: 'Eingabevariablen',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Eingabevariablen',
outputVars: {
className: 'Klassennamen',
usage: 'Nutzungsinformationen des Modells',
},
class: 'Klasse',
classNamePlaceholder: 'Geben Sie Ihren Klassennamen ein',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Eingabevariable',
outputVars: {
isSuccess: 'Ist Erfolg. Bei Erfolg beträgt der Wert 1, bei Misserfolg beträgt der Wert 0.',
errorReason: 'Fehlergrund',
usage: 'Nutzungsinformationen des Modells',
},
extractParameters: 'Parameter extrahieren',
importFromTool: 'Aus Tools importieren',
addExtractParameter: 'Extraktionsparameter hinzufügen',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Erweiterte Einstellung',
reasoningMode: 'Schlussfolgerungsmodus',
reasoningModeTip: 'Sie können den entsprechenden Schlussfolgerungsmodus basierend auf der Fähigkeit des Modells wählen, auf Anweisungen zur Funktionsaufruf- oder Eingabeaufforderungen zu reagieren.',
isSuccess: 'Ist Erfolg. Bei Erfolg beträgt der Wert 1, bei Misserfolg beträgt der Wert 0.',
errorReason: 'Fehlergrund',
},
iteration: {
deleteTitle: 'Iterationsknoten löschen?',

@ -127,6 +127,8 @@ const translation = {
value: 'Value',
valuePlaceholder: 'env value',
secretTip: 'Used to define sensitive information or data, with DSL settings configured for leak prevention.',
description: 'Description',
descriptionPlaceholder: 'Describe the variable',
},
export: {
title: 'Export Secret environment variables?',
@ -542,6 +544,10 @@ const translation = {
title: 'Import from cURL',
placeholder: 'Paste cURL string here',
},
verifySSL: {
title: 'Verify SSL Certificate',
warningTooltip: 'Disabling SSL verification is not recommended for production environments. This should only be used in development or testing, as it makes the connection vulnerable to security threats like man-in-the-middle attacks.',
},
},
code: {
inputVars: 'Input Variables',
@ -673,6 +679,7 @@ const translation = {
inputVars: 'Input Variables',
outputVars: {
className: 'Class Name',
usage: 'Model Usage Information',
},
class: 'Class',
classNamePlaceholder: 'Write your class name',
@ -686,6 +693,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Input Variable',
outputVars: {
isSuccess: 'Is Success.On success the value is 1, on failure the value is 0.',
errorReason: 'Error Reason',
usage: 'Model Usage Information',
},
extractParameters: 'Extract Parameters',
importFromTool: 'Import from tools',
addExtractParameter: 'Add Extract Parameter',
@ -705,8 +717,6 @@ const translation = {
advancedSetting: 'Advanced Setting',
reasoningMode: 'Reasoning Mode',
reasoningModeTip: 'You can choose the appropriate reasoning mode based on the model\'s ability to respond to instructions for function calling or prompts.',
isSuccess: 'Is Success.On success the value is 1, on failure the value is 0.',
errorReason: 'Error Reason',
},
iteration: {
deleteTitle: 'Delete Iteration Node?',

@ -129,6 +129,8 @@ const translation = {
value: 'Valor',
valuePlaceholder: 'valor de env',
secretTip: 'Se utiliza para definir información o datos sensibles, con configuraciones DSL configuradas para prevenir fugas.',
description: 'Descripción',
descriptionPlaceholder: 'Describa la variable',
},
export: {
title: '¿Exportar variables de entorno secretas?',
@ -535,6 +537,10 @@ const translation = {
title: 'Importar desde cURL',
placeholder: 'Pegar la cadena cURL aquí',
},
verifySSL: {
title: 'Verificar el certificado SSL',
warningTooltip: 'Deshabilitar la verificación SSL no se recomienda para entornos de producción. Esto solo debe utilizarse en desarrollo o pruebas, ya que hace que la conexión sea vulnerable a amenazas de seguridad como ataques de intermediario.',
},
},
code: {
inputVars: 'Variables de entrada',
@ -667,6 +673,7 @@ const translation = {
inputVars: 'Variables de entrada',
outputVars: {
className: 'Nombre de la clase',
usage: 'Información de uso del modelo',
},
class: 'Clase',
classNamePlaceholder: 'Escribe el nombre de tu clase',
@ -680,6 +687,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Variable de entrada',
outputVars: {
isSuccess: 'Es éxito. En caso de éxito el valor es 1, en caso de fallo el valor es 0.',
errorReason: 'Motivo del error',
usage: 'Información de uso del modelo',
},
extractParameters: 'Extraer parámetros',
importFromTool: 'Importar desde herramientas',
addExtractParameter: 'Agregar parámetro de extracción',
@ -699,8 +711,6 @@ const translation = {
advancedSetting: 'Configuración avanzada',
reasoningMode: 'Modo de razonamiento',
reasoningModeTip: 'Puede elegir el modo de razonamiento apropiado basado en la capacidad del modelo para responder a instrucciones para llamadas de funciones o indicaciones.',
isSuccess: 'Es éxito. En caso de éxito el valor es 1, en caso de fallo el valor es 0.',
errorReason: 'Motivo del error',
},
iteration: {
deleteTitle: '¿Eliminar nodo de iteración?',

@ -129,6 +129,8 @@ const translation = {
value: 'مقدار',
valuePlaceholder: 'مقدار متغیر',
secretTip: 'برای تعریف اطلاعات حساس یا داده‌ها، با تنظیمات DSL برای جلوگیری از نشت پیکربندی شده است.',
description: 'توضیحات',
descriptionPlaceholder: 'متغیر را توصیف کنید',
},
export: {
title: 'آیا متغیرهای محیطی مخفی را صادر کنید؟',
@ -537,6 +539,10 @@ const translation = {
title: 'وارد کردن از cURL',
placeholder: 'رشته cURL را اینجا بچسبانید',
},
verifySSL: {
title: 'گواهی SSL را تأیید کنید',
warningTooltip: 'غیرفعال کردن تأیید SSL برای محیط‌های تولید توصیه نمی‌شود. این فقط باید در توسعه یا آزمایش استفاده شود، زیرا این کار اتصال را در معرض تهدیدات امنیتی مانند حملات میانی قرار می‌دهد.',
},
},
code: {
inputVars: 'متغیرهای ورودی',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'متغیرهای ورودی',
outputVars: {
className: 'نام کلاس',
usage: 'اطلاعات استفاده از مدل',
},
class: 'کلاس',
classNamePlaceholder: 'نام کلاس خود را بنویسید',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'متغیر ورودی',
outputVars: {
isSuccess: 'موفقیت‌آمیز است. در صورت موفقیت مقدار 1 و در صورت شکست مقدار 0 است.',
errorReason: 'دلیل خطا',
usage: 'اطلاعات استفاده از مدل',
},
extractParameters: 'استخراج پارامترها',
importFromTool: 'وارد کردن از ابزارها',
addExtractParameter: 'افزودن پارامتر استخراج شده',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'تنظیمات پیشرفته',
reasoningMode: 'حالت استدلال',
reasoningModeTip: 'می‌توانید حالت استدلال مناسب را بر اساس توانایی مدل برای پاسخ به دستورات برای فراخوانی عملکردها یا پیشنهادات انتخاب کنید.',
isSuccess: 'موفقیت‌آمیز است. در صورت موفقیت مقدار 1 و در صورت شکست مقدار 0 است.',
errorReason: 'دلیل خطا',
},
iteration: {
deleteTitle: 'حذف نود تکرار؟',

@ -129,6 +129,8 @@ const translation = {
value: 'valeur',
valuePlaceholder: 'Valeur de l\'env',
secretTip: 'Utilisé pour définir des informations ou des données sensibles, avec des paramètres DSL configurés pour la prévention des fuites.',
description: 'Description',
descriptionPlaceholder: 'Décrivez la variable',
},
export: {
title: 'Exporter des variables d\'environnement secrètes?',
@ -537,6 +539,10 @@ const translation = {
placeholder: 'Collez la chaîne cURL ici',
title: 'Importer à partir de cURL',
},
verifySSL: {
title: 'Vérifier le certificat SSL',
warningTooltip: 'Désactiver la vérification SSL n\'est pas recommandé pour les environnements de production. Cela ne devrait être utilisé que dans le développement ou les tests, car cela rend la connexion vulnérable aux menaces de sécurité telles que les attaques de type \'man-in-the-middle\'.',
},
},
code: {
inputVars: 'Variables de saisie',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Variables de saisie',
outputVars: {
className: 'Nom de la classe',
usage: 'Informations sur l\'utilisation du modèle',
},
class: 'Classe',
classNamePlaceholder: 'Écrivez le nom de votre classe',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Variable de saisie',
outputVars: {
isSuccess: 'Est réussi. En cas de succès, la valeur est 1, en cas d\'échec, la valeur est 0.',
errorReason: 'Raison de l\'erreur',
usage: 'Informations sur l\'utilisation du modèle',
},
extractParameters: 'Extraire des paramètres',
importFromTool: 'Importer des outils',
addExtractParameter: 'Ajouter un paramètre d\'extraction',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Paramètre avancé',
reasoningMode: 'Mode de raisonnement',
reasoningModeTip: 'Vous pouvez choisir le mode de raisonnement approprié en fonction de la capacité du modèle à répondre aux instructions pour les appels de fonction ou les invites.',
isSuccess: 'Est réussi. En cas de succès, la valeur est 1, en cas d\'échec, la valeur est 0.',
errorReason: 'Raison de l\'erreur',
},
iteration: {
deleteTitle: 'Supprimer le nœud d\'itération?',

@ -132,6 +132,8 @@ const translation = {
value: 'मान',
valuePlaceholder: 'पर्यावरण मान',
secretTip: 'संवेदनशील जानकारी या डेटा को परिभाषित करने के लिए उपयोग किया जाता है, DSL सेटिंग्स लीक रोकथाम के लिए कॉन्फ़िगर की गई हैं।',
description: 'विवरण',
descriptionPlaceholder: 'चर का वर्णन करें',
},
export: {
title: 'गुप्त पर्यावरण चर निर्यात करें?',
@ -550,6 +552,10 @@ const translation = {
placeholder: 'यहां cURL स्ट्रिंग पेस्ट करें',
title: 'cURL से आयात करें',
},
verifySSL: {
title: 'SSL प्रमाणपत्र की पुष्टि करें',
warningTooltip: 'SSL सत्यापन को अक्षम करना उत्पादन वातावरण के लिए अनुशंसित नहीं है। इसका उपयोग केवल विकास या परीक्षण में किया जाना चाहिए, क्योंकि यह कनेक्शन को मिडल-मैन हमलों जैसे सुरक्षा खतरों के लिए कमजोर बना देता है।',
},
},
code: {
inputVars: 'इनपुट वेरिएबल्स',
@ -685,6 +691,7 @@ const translation = {
inputVars: 'इनपुट वेरिएबल्स',
outputVars: {
className: 'क्लास नाम',
usage: 'मॉडल उपयोग जानकारी',
},
class: 'क्लास',
classNamePlaceholder: 'अपना क्लास नाम लिखें',
@ -699,6 +706,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'इनपुट वेरिएबल',
outputVars: {
isSuccess: 'सफलता है। सफलता पर मान 1 है, असफलता पर मान 0 है।',
errorReason: 'त्रुटि का कारण',
usage: 'मॉडल उपयोग जानकारी',
},
extractParameters: 'पैरामीटर्स निकालें',
importFromTool: 'उपकरणों से आयात करें',
addExtractParameter: 'एक्सट्रेक्ट पैरामीटर जोड़ें',
@ -721,8 +733,6 @@ const translation = {
reasoningMode: 'रीज़निंग मोड',
reasoningModeTip:
'फ़ंक्शन कॉलिंग या प्रॉम्प्ट्स के लिए निर्देशों का जवाब देने की मॉडल की क्षमता के आधार पर उपयुक्त रीज़निंग मोड चुन सकते हैं।',
isSuccess: 'सफलता है। सफलता पर मान 1 है, असफलता पर मान 0 है।',
errorReason: 'त्रुटि का कारण',
},
iteration: {
deleteTitle: 'इटरेशन नोड हटाएं?',

@ -133,6 +133,8 @@ const translation = {
value: 'Valore',
valuePlaceholder: 'valore env',
secretTip: 'Utilizzato per definire informazioni o dati sensibili, con impostazioni DSL configurate per la prevenzione delle fughe.',
description: 'Descrizione',
descriptionPlaceholder: 'Descrivi la variabile',
},
export: {
title: 'Esportare variabili d\'ambiente segrete?',
@ -553,6 +555,10 @@ const translation = {
placeholder: 'Incolla qui la stringa cURL',
title: 'Importazione da cURL',
},
verifySSL: {
title: 'Verifica il certificato SSL',
warningTooltip: 'Disabilitare la verifica SSL non è raccomandato per gli ambienti di produzione. Questo dovrebbe essere utilizzato solo in sviluppo o test, poiché rende la connessione vulnerabile a minacce alla sicurezza come gli attacchi man-in-the-middle.',
},
},
code: {
inputVars: 'Variabili di Input',
@ -688,6 +694,7 @@ const translation = {
inputVars: 'Variabili di Input',
outputVars: {
className: 'Nome Classe',
usage: 'Informazioni sull\'utilizzo del modello',
},
class: 'Classe',
classNamePlaceholder: 'Scrivi il nome della tua classe',
@ -702,6 +709,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Variabile di Input',
outputVars: {
isSuccess: 'È successo. In caso di successo il valore è 1, in caso di fallimento il valore è 0.',
errorReason: 'Motivo dell\'errore',
usage: 'Informazioni sull\'utilizzo del modello',
},
extractParameters: 'Estrai Parametri',
importFromTool: 'Importa dagli strumenti',
addExtractParameter: 'Aggiungi Parametro Estratto',
@ -724,9 +736,6 @@ const translation = {
reasoningMode: 'Modalità di ragionamento',
reasoningModeTip:
'Puoi scegliere la modalità di ragionamento appropriata in base alla capacità del modello di rispondere alle istruzioni per la chiamata delle funzioni o i prompt.',
isSuccess:
'È successo. In caso di successo il valore è 1, in caso di fallimento il valore è 0.',
errorReason: 'Motivo dell\'errore',
},
iteration: {
deleteTitle: 'Eliminare Nodo Iterazione?',

@ -127,6 +127,8 @@ const translation = {
value: '値',
valuePlaceholder: '変数値を入力',
secretTip: 'この変数は機密情報やデータを定義するために使用されます。DSL をエクスポートするときに漏洩防止メカニズムを設定されます。',
description: '説明',
descriptionPlaceholder: '変数の説明を入力',
},
export: {
title: 'シークレット環境変数をエクスポートしますか?',
@ -543,6 +545,10 @@ const translation = {
title: 'cURL からインポート',
placeholder: 'ここに cURL 文字列を貼り付けます',
},
verifySSL: {
title: 'SSL証明書を確認する',
warningTooltip: 'SSL検証を無効にすることは、本番環境では推奨されません。これは開発またはテストのみに使用すべきであり、中間者攻撃などのセキュリティ脅威に対して接続を脆弱にするためです。',
},
},
code: {
inputVars: '入力変数',
@ -676,6 +682,7 @@ const translation = {
inputVars: '入力変数',
outputVars: {
className: 'クラス名',
usage: 'モデル使用量',
},
class: 'クラス',
classNamePlaceholder: 'クラス名を入力してください',
@ -689,6 +696,11 @@ const translation = {
},
parameterExtractor: {
inputVar: '入力変数',
outputVars: {
isSuccess: '成功。成功した場合の値は 1、失敗した場合の値は 0 です。',
errorReason: 'エラーの理由',
usage: 'モデル使用量',
},
extractParameters: 'パラメーターを抽出',
importFromTool: 'ツールからインポート',
addExtractParameter: '抽出パラメーターを追加',
@ -708,8 +720,6 @@ const translation = {
advancedSetting: '高度な設定',
reasoningMode: '推論モード',
reasoningModeTip: '関数呼び出しやプロンプトの指示に応答するモデルの能力に基づいて、適切な推論モードを選択できます。',
isSuccess: '成功。成功した場合の値は 1、失敗した場合の値は 0 です。',
errorReason: 'エラーの理由',
},
iteration: {
deleteTitle: 'イテレーションノードを削除しますか?',

@ -135,6 +135,8 @@ const translation = {
valuePlaceholder: '환경 값',
secretTip:
'민감한 정보나 데이터를 정의하는 데 사용되며, DSL 설정은 유출 방지를 위해 구성됩니다.',
description: '설명',
descriptionPlaceholder: '변수에 대해 설명하세요',
},
export: {
title: '비밀 환경 변수를 내보내시겠습니까?',
@ -565,6 +567,10 @@ const translation = {
title: 'cURL 에서 가져오기',
placeholder: '여기에 cURL 문자열 붙여 넣기',
},
verifySSL: {
title: 'SSL 인증서 확인',
warningTooltip: 'SSL 검증을 비활성화하는 것은 프로덕션 환경에서는 권장되지 않습니다. 이는 연결이 중간자 공격과 같은 보안 위협에 취약하게 만들므로 개발 또는 테스트에서만 사용해야 합니다.',
},
},
code: {
inputVars: '입력 변수',
@ -701,6 +707,7 @@ const translation = {
inputVars: '입력 변수',
outputVars: {
className: '클래스 이름',
usage: '모델 사용 정보',
},
class: '클래스',
classNamePlaceholder: '클래스 이름을 작성하세요',
@ -715,6 +722,11 @@ const translation = {
},
parameterExtractor: {
inputVar: '입력 변수',
outputVars: {
isSuccess: '성공 여부. 성공 시 값은 1 이고, 실패 시 값은 0 입니다.',
errorReason: '오류 원인',
usage: '모델 사용 정보',
},
extractParameters: '매개변수 추출',
importFromTool: '도구에서 가져오기',
addExtractParameter: '추출 매개변수 추가',

@ -129,6 +129,8 @@ const translation = {
value: 'Wartość',
valuePlaceholder: 'wartość środowiska',
secretTip: 'Używane do definiowania wrażliwych informacji lub danych, z ustawieniami DSL skonfigurowanymi do zapobiegania wyciekom.',
description: 'Opis',
descriptionPlaceholder: 'Opisz zmienną',
},
export: {
title: 'Eksportować tajne zmienne środowiskowe?',
@ -537,6 +539,10 @@ const translation = {
placeholder: 'Wklej tutaj ciąg cURL',
title: 'Importowanie z cURL',
},
verifySSL: {
title: 'Zweryfikuj certyfikat SSL',
warningTooltip: 'Wyłączenie weryfikacji SSL nie jest zalecane w środowiskach produkcyjnych. Powinno to być używane tylko w rozwoju lub testowaniu, ponieważ naraża połączenie na zagrożenia bezpieczeństwa, takie jak ataki typu man-in-the-middle.',
},
},
code: {
inputVars: 'Zmienne wejściowe',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Zmienne wejściowe',
outputVars: {
className: 'Nazwa klasy',
usage: 'Informacje o użyciu modelu',
},
class: 'Klasa',
classNamePlaceholder: 'Napisz nazwę swojej klasy',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Zmienna wejściowa',
outputVars: {
isSuccess: 'Czy się udało. W przypadku sukcesu wartość wynosi 1, w przypadku niepowodzenia wartość wynosi 0.',
errorReason: 'Powód błędu',
usage: 'Informacje o użyciu modelu',
},
extractParameters: 'Wyodrębnij parametry',
importFromTool: 'Importuj z narzędzi',
addExtractParameter: 'Dodaj parametr wyodrębniania',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Zaawansowane ustawienia',
reasoningMode: 'Tryb wnioskowania',
reasoningModeTip: 'Możesz wybrać odpowiedni tryb wnioskowania w zależności od zdolności modelu do reagowania na instrukcje dotyczące wywoływania funkcji lub zapytań.',
isSuccess: 'Czy się udało. W przypadku sukcesu wartość wynosi 1, w przypadku niepowodzenia wartość wynosi 0.',
errorReason: 'Powód błędu',
},
iteration: {
deleteTitle: 'Usunąć węzeł iteracji?',

@ -129,6 +129,8 @@ const translation = {
value: 'Valor',
valuePlaceholder: 'valor da env',
secretTip: 'Usado para definir informações ou dados sensíveis, com configurações DSL configuradas para prevenção de vazamentos.',
description: 'Descrição',
descriptionPlaceholder: 'Descreva a variável',
},
export: {
title: 'Exportar variáveis de ambiente secretas?',
@ -537,6 +539,10 @@ const translation = {
placeholder: 'Cole a string cURL aqui',
title: 'Importar do cURL',
},
verifySSL: {
title: 'Verificar o certificado SSL',
warningTooltip: 'Desabilitar a verificação SSL não é recomendado para ambientes de produção. Isso deve ser usado apenas em desenvolvimento ou teste, pois torna a conexão vulnerável a ameaças de segurança, como ataques man-in-the-middle.',
},
},
code: {
inputVars: 'Variáveis de entrada',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Variáveis de entrada',
outputVars: {
className: 'Nome da classe',
usage: 'Informações de uso do modelo',
},
class: 'Classe',
classNamePlaceholder: 'Escreva o nome da sua classe',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Variável de entrada',
outputVars: {
isSuccess: 'É sucesso. Em caso de sucesso, o valor é 1, em caso de falha, o valor é 0.',
errorReason: 'Motivo do erro',
usage: 'Informações de uso do modelo',
},
extractParameters: 'Extrair parâmetros',
importFromTool: 'Importar das ferramentas',
addExtractParameter: 'Adicionar parâmetro de extração',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Configuração avançada',
reasoningMode: 'Modo de raciocínio',
reasoningModeTip: 'Você pode escolher o modo de raciocínio apropriado com base na capacidade do modelo de responder a instruções para chamadas de função ou prompts.',
isSuccess: 'É sucesso. Em caso de sucesso, o valor é 1, em caso de falha, o valor é 0.',
errorReason: 'Motivo do erro',
},
iteration: {
deleteTitle: 'Excluir nó de iteração?',

@ -129,6 +129,8 @@ const translation = {
value: 'Valoare',
valuePlaceholder: 'valoare mediu',
secretTip: 'Utilizat pentru a defini informații sau date sensibile, cu setări DSL configurate pentru prevenirea scurgerilor.',
description: 'Descriere',
descriptionPlaceholder: 'Descrieți variabila',
},
export: {
title: 'Exportă variabile de mediu secrete?',
@ -537,6 +539,10 @@ const translation = {
placeholder: 'Lipiți șirul cURL aici',
title: 'Importați din cURL',
},
verifySSL: {
title: 'Verifică certificatul SSL',
warningTooltip: 'Dezactivarea verificării SSL nu este recomandată pentru medii de producție. Acest lucru ar trebui să fie folosit doar în dezvoltare sau testare, deoarece face conexiunea vulnerabilă la amenințări de securitate, cum ar fi atacurile man-in-the-middle.',
},
},
code: {
inputVars: 'Variabile de intrare',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Variabile de intrare',
outputVars: {
className: 'Nume clasă',
usage: 'Informații de utilizare a modelului',
},
class: 'Clasă',
classNamePlaceholder: 'Scrieți numele clasei',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Variabilă de intrare',
outputVars: {
isSuccess: 'Este succes. În caz de succes valoarea este 1, în caz de eșec valoarea este 0.',
errorReason: 'Motivul erorii',
usage: 'Informații de utilizare a modelului',
},
extractParameters: 'Extrageți parametrii',
importFromTool: 'Importă din instrumente',
addExtractParameter: 'Adăugați parametru de extragere',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Setare avansată',
reasoningMode: 'Mod de raționament',
reasoningModeTip: 'Puteți alege modul de raționament potrivit în funcție de capacitatea modelului de a răspunde la instrucțiuni pentru apelarea funcțiilor sau prompturi.',
isSuccess: 'Este succes. În caz de succes valoarea este 1, în caz de eșec valoarea este 0.',
errorReason: 'Motivul erorii',
},
iteration: {
deleteTitle: 'Ștergeți nodul de iterație?',

@ -129,6 +129,8 @@ const translation = {
value: 'Значение',
valuePlaceholder: 'Значение переменной среды',
secretTip: 'Используется для определения конфиденциальной информации или данных, с настройками DSL, настроенными для предотвращения утечки.',
description: 'Описание',
descriptionPlaceholder: 'Опишите переменную',
},
export: {
title: 'Экспортировать секретные переменные среды?',
@ -537,6 +539,10 @@ const translation = {
placeholder: 'Вставьте сюда строку cURL',
title: 'Импорт из cURL',
},
verifySSL: {
title: 'Проверить SSL-сертификат',
warningTooltip: 'Отключение проверки SSL не рекомендуется для производственных сред. Это следует использовать только в разработке или тестировании, так как это делает соединение уязвимым для угроз безопасности, таких как атаки «человек посередине».',
},
},
code: {
inputVars: 'Входные переменные',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Входные переменные',
outputVars: {
className: 'Имя класса',
usage: 'Информация об использовании модели',
},
class: 'Класс',
classNamePlaceholder: 'Введите имя вашего класса',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Входная переменная',
outputVars: {
isSuccess: 'Успешно. В случае успеха значение равно 1, в случае сбоя - 0.',
errorReason: 'Причина ошибки',
usage: 'Информация об использовании модели',
},
extractParameters: 'Извлечь параметры',
importFromTool: 'Импортировать из инструментов',
addExtractParameter: 'Добавить параметр для извлечения',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Расширенные настройки',
reasoningMode: 'Режим рассуждения',
reasoningModeTip: 'Вы можете выбрать соответствующий режим рассуждения, основываясь на способности модели реагировать на инструкции для вызова функций или подсказки.',
isSuccess: 'Успешно. В случае успеха значение равно 1, в случае сбоя - 0.',
errorReason: 'Причина ошибки',
},
iteration: {
deleteTitle: 'Удалить узел итерации?',

@ -124,6 +124,8 @@ const translation = {
type: 'Tip',
editTitle: 'Uredi okoljsko spremenljivko',
secretTip: 'Uporablja se za opredelitev občutljivih informacij ali podatkov, s konfiguriranimi nastavitvami DSL za preprečevanje puščanja.',
description: 'Opis',
descriptionPlaceholder: 'Opisujte spremenljivko',
},
export: {
export: 'Izvozi DSL z skrivnimi vrednostmi',
@ -143,6 +145,7 @@ const translation = {
objectKey: 'Ključ',
valuePlaceholder: 'Privzeta vrednost, pustite prazno, da je ne nastavite',
description: 'Opis',
descriptionPlaceholder: 'Opisujte spremenljivko',
type: 'Tip',
value: 'Privzeta vrednost',
name: 'Ime',
@ -153,7 +156,6 @@ const translation = {
objectType: 'Tip',
oneByOne: 'Dodaj eno po eno',
objectValue: 'Privzeta vrednost',
descriptionPlaceholder: 'Opisujte spremenljivko',
},
updatedAt: 'Posodobljeno ob',
docLink: 'Obiščite našo dokumentacijo, da se naučite več.',
@ -539,6 +541,10 @@ const translation = {
value: 'Vrednost',
params: 'Parametri',
insertVarPlaceholder: 'vnesite \'/\' za vstavljanje spremenljivke',
verifySSL: {
title: 'Preverite SSL certifikat',
warningTooltip: 'Onemogočanje preverjanja SSL ni priporočljivo za proizvodna okolja. To bi se moralo uporabljati le pri razvoju ali testiranju, saj povezavo izpostavi varnostnim grožnjam, kot so napadi človek-v-sredini.',
},
},
code: {
searchDependencies: 'Išči odvisnosti',
@ -667,6 +673,7 @@ const translation = {
questionClassifiers: {
outputVars: {
className: 'Ime razreda',
usage: 'Informacije o uporabi modela',
},
instruction: 'Navodilo',
addClass: 'Dodaj razred',
@ -692,16 +699,19 @@ const translation = {
requiredContent: 'Zahtevano se uporablja le kot referenca za sklepanje modela in ne kot obvezno validacijo izhodnih parametrov.',
},
extractParameters: 'Izvleči parametre',
errorReason: 'Razlog za napako',
instruction: 'Navodilo',
instructionTip: 'Vnesite dodatna navodila, da pomagate izvleku parametrov razumeti, kako izvleči parametre.',
reasoningMode: 'Način razmišljanja',
isSuccess: 'Ali je uspeh. Na uspehu je vrednost 1, na neuspehu je vrednost 0.',
importFromTool: 'Uvoz iz orodij',
advancedSetting: 'Napredno nastavitev',
addExtractParameter: 'Dodaj parameter za ekstrakcijo',
extractParametersNotSet: 'Parameterji za ekstrakcijo niso nastavljeni',
inputVar: 'Vhodna spremenljivka',
outputVars: {
isSuccess: 'Ali je uspeh. Na uspehu je vrednost 1, na neuspehu je vrednost 0.',
errorReason: 'Razlog za napako',
usage: 'Informacije o uporabi modela',
},
reasoningModeTip: 'Lahko izberete ustrezen način razmišljanja glede na sposobnost modela, da se odzove na navodila za klic funkcij ali pozive.',
},
iteration: {

@ -129,6 +129,8 @@ const translation = {
value: 'ค่า',
valuePlaceholder: 'ค่า env',
secretTip: 'ใช้เพื่อกําหนดข้อมูลหรือข้อมูลที่ละเอียดอ่อน โดยมีการตั้งค่า DSL ที่กําหนดค่าไว้เพื่อป้องกันการรั่วไหล',
description: 'คำอธิบาย',
descriptionPlaceholder: 'อธิบายตัวแปร',
},
export: {
title: 'ส่งออกตัวแปรสภาพแวดล้อม Secret หรือไม่',
@ -537,6 +539,10 @@ const translation = {
title: 'นําเข้าจาก cURL',
placeholder: 'วางสตริง cURL ที่นี่',
},
verifySSL: {
title: 'ตรวจสอบใบรับรอง SSL',
warningTooltip: 'การปิดการตรวจสอบ SSL ไม่แนะนำให้ใช้ในสภาพแวดล้อมการผลิต ควรใช้เฉพาะในระหว่างการพัฒนาหรือการทดสอบเท่านั้น เนื่องจากจะทำให้การเชื่อมต่อมีความเสี่ยงต่อภัยคุกคามด้านความปลอดภัย เช่น การโจมตีแบบ Man-in-the-middle.',
},
},
code: {
inputVars: 'ตัวแปรอินพุต',
@ -668,6 +674,7 @@ const translation = {
inputVars: 'ตัวแปรอินพุต',
outputVars: {
className: 'ชื่อคลาส',
usage: 'ข้อมูลการใช้งานรุ่น',
},
class: 'ประเภท',
classNamePlaceholder: 'เขียนชื่อชั้นเรียนของคุณ',
@ -681,6 +688,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'ตัวแปรอินพุต',
outputVars: {
isSuccess: 'คือ Success เมื่อสําเร็จค่าคือ 1 เมื่อล้มเหลวค่าเป็น 0',
errorReason: 'สาเหตุข้อผิดพลาด',
usage: 'ข้อมูลการใช้งานรุ่น',
},
extractParameters: 'แยกพารามิเตอร์',
importFromTool: 'นําเข้าจากเครื่องมือ',
addExtractParameter: 'เพิ่มพารามิเตอร์การแยกข้อมูล',
@ -700,8 +712,6 @@ const translation = {
advancedSetting: 'การตั้งค่าขั้นสูง',
reasoningMode: 'โหมดการให้เหตุผล',
reasoningModeTip: 'คุณสามารถเลือกโหมดการให้เหตุผลที่เหมาะสมตามความสามารถของโมเดลในการตอบสนองต่อคําแนะนําสําหรับการเรียกใช้ฟังก์ชันหรือข้อความแจ้ง',
isSuccess: 'คือ Success เมื่อสําเร็จค่าคือ 1 เมื่อล้มเหลวค่าเป็น 0',
errorReason: 'สาเหตุข้อผิดพลาด',
},
iteration: {
deleteTitle: 'ลบโหนดการทําซ้ํา?',

@ -129,6 +129,8 @@ const translation = {
value: 'Değer',
valuePlaceholder: 'env değeri',
secretTip: 'Hassas bilgileri veya verileri tanımlamak için kullanılır, bilgi sızıntısını önlemek için DSL ayarları yapılandırılmıştır.',
description: 'Açıklama',
descriptionPlaceholder: 'Değişkeni açıklayın',
},
export: {
title: 'Gizli çevre değişkenleri dışa aktarılsın mı?',
@ -538,6 +540,10 @@ const translation = {
placeholder: 'cURL dizesini buraya yapıştırın',
title: 'cURL\'den içe aktar',
},
verifySSL: {
title: 'SSL Sertifikasını Doğrula',
warningTooltip: 'SSL doğrulamasını devre dışı bırakmak, üretim ortamları için önerilmez. Bu yalnızca geliştirme veya test aşamalarında kullanılmalıdır, çünkü bağlantıyı adam ortada saldırıları gibi güvenlik tehditlerine karşı savunmasız hale getirir.',
},
},
code: {
inputVars: 'Giriş Değişkenleri',
@ -670,6 +676,7 @@ const translation = {
inputVars: 'Giriş Değişkenleri',
outputVars: {
className: 'Sınıf Adı',
usage: 'Model Kullanım Bilgileri',
},
class: 'Sınıf',
classNamePlaceholder: 'Sınıf adınızı yazın',
@ -683,6 +690,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Giriş Değişkeni',
outputVars: {
isSuccess: 'Başarılı mı. Başarılı olduğunda değer 1, başarısız olduğunda değer 0\'dır.',
errorReason: 'Hata Nedeni',
usage: 'Model Kullanım Bilgileri',
},
extractParameters: 'Parametreleri Çıkar',
importFromTool: 'Araçlardan içe aktar',
addExtractParameter: ıkarma Parametresi Ekle',
@ -702,8 +714,6 @@ const translation = {
advancedSetting: 'Gelişmiş Ayarlar',
reasoningMode: 'Akıl Yürütme Modu',
reasoningModeTip: 'Modelin fonksiyon çağırma veya istemler için talimatlara yanıt verme yeteneğine bağlı olarak uygun akıl yürütme modunu seçebilirsiniz.',
isSuccess: 'Başarılı mı. Başarılı olduğunda değer 1, başarısız olduğunda değer 0\'dır.',
errorReason: 'Hata Nedeni',
},
iteration: {
deleteTitle: 'Yineleme Düğümünü Sil?',

@ -129,6 +129,8 @@ const translation = {
value: 'Значення',
valuePlaceholder: 'значення середовища',
secretTip: 'Використовується для визначення конфіденційної інформації або даних, з налаштуваннями DSL, сконфігурованими для запобігання витоку.',
description: 'Опис',
descriptionPlaceholder: 'Опишіть змінну',
},
export: {
title: 'Експортувати секретні змінні середовища?',
@ -537,6 +539,10 @@ const translation = {
title: 'Імпорт з cURL',
placeholder: 'Вставте сюди рядок cURL',
},
verifySSL: {
title: 'Перевірити SSL сертифікат',
warningTooltip: 'Вимкнення перевірки SSL не рекомендується для виробничих середовищ. Це слід використовувати лише в розробці або тестуванні, оскільки це робить з\'єднання вразливим до загроз безпеці, таких як атаки «людина посередині».',
},
},
code: {
inputVars: 'Вхідні змінні',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Вхідні змінні',
outputVars: {
className: 'Назва класу',
usage: 'Інформація про використання моделі',
},
class: 'Клас',
classNamePlaceholder: 'Напишіть назву вашого класу',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Вхідна змінна',
outputVars: {
isSuccess: 'Є успіх. У разі успіху значення 1, у разі невдачі значення 0.',
errorReason: 'Причина помилки',
usage: 'Інформація про використання моделі',
},
extractParameters: 'Витягти параметри',
importFromTool: 'Імпорт з інструментів',
addExtractParameter: 'Додати параметр витягування',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Розширене налаштування',
reasoningMode: 'Режим інференції',
reasoningModeTip: 'Ви можете вибрати відповідний режим інференції залежно від здатності моделі реагувати на інструкції щодо викликів функцій або запитів.',
isSuccess: 'Є успіх. У разі успіху значення 1, у разі невдачі значення 0.',
errorReason: 'Причина помилки',
},
iteration: {
deleteTitle: 'Видалити вузол ітерації?',

@ -129,6 +129,8 @@ const translation = {
value: 'Giá trị',
valuePlaceholder: 'giá trị môi trường',
secretTip: 'Được sử dụng để xác định thông tin hoặc dữ liệu nhạy cảm, với cài đặt DSL được cấu hình để ngăn chặn rò rỉ.',
description: 'Mô tả',
descriptionPlaceholder: 'Mô tả biến',
},
export: {
title: 'Xuất biến môi trường bí mật?',
@ -537,6 +539,10 @@ const translation = {
title: 'Nhập từ cURL',
placeholder: 'Dán chuỗi cURL vào đây',
},
verifySSL: {
title: 'Xác thực chứng chỉ SSL',
warningTooltip: 'Việc vô hiệu hóa xác minh SSL không được khuyến khích cho các môi trường sản xuất. Điều này chỉ nên được sử dụng trong phát triển hoặc thử nghiệm, vì nó làm cho kết nối dễ bị tổn thương trước các mối đe dọa an ninh như cuộc tấn công man-in-the-middle.',
},
},
code: {
inputVars: 'Biến đầu vào',
@ -669,6 +675,7 @@ const translation = {
inputVars: 'Biến đầu vào',
outputVars: {
className: 'Tên lớp',
usage: 'Thông tin sử dụng mô hình',
},
class: 'Lớp',
classNamePlaceholder: 'Viết tên lớp của bạn',
@ -682,6 +689,11 @@ const translation = {
},
parameterExtractor: {
inputVar: 'Biến đầu vào',
outputVars: {
isSuccess: 'Thành công. Khi thành công giá trị là 1, khi thất bại giá trị là 0.',
errorReason: 'Lý do lỗi',
usage: 'Thông tin sử dụng mô hình',
},
extractParameters: 'Trích xuất tham số',
importFromTool: 'Nhập từ công cụ',
addExtractParameter: 'Thêm tham số trích xuất',
@ -701,8 +713,6 @@ const translation = {
advancedSetting: 'Cài đặt nâng cao',
reasoningMode: 'Chế độ suy luận',
reasoningModeTip: 'Bạn có thể chọn chế độ suy luận phù hợp dựa trên khả năng của mô hình để phản hồi các hướng dẫn về việc gọi hàm hoặc prompt.',
isSuccess: 'Thành công. Khi thành công giá trị là 1, khi thất bại giá trị là 0.',
errorReason: 'Lý do lỗi',
},
iteration: {
deleteTitle: 'Xóa nút lặp?',

@ -127,6 +127,8 @@ const translation = {
value: '值',
valuePlaceholder: '变量值',
secretTip: '用于定义敏感信息或数据,导出 DSL 时设置了防泄露机制。',
description: '描述',
descriptionPlaceholder: '变量的描述',
},
export: {
title: '导出 Secret 类型环境变量?',
@ -543,6 +545,10 @@ const translation = {
title: '导入 cURL',
placeholder: '粘贴 cURL 字符串',
},
verifySSL: {
title: '验证 SSL 证书',
warningTooltip: '不建议在生产环境中禁用 SSL 验证。这仅应在开发或测试中使用,因为它会使连接容易受到诸如中间人攻击等安全威胁。',
},
},
code: {
inputVars: '输入变量',
@ -674,6 +680,7 @@ const translation = {
inputVars: '输入变量',
outputVars: {
className: '分类名称',
usage: '模型用量信息',
},
class: '分类',
classNamePlaceholder: '输入你的分类名称',
@ -687,6 +694,11 @@ const translation = {
},
parameterExtractor: {
inputVar: '输入变量',
outputVars: {
isSuccess: '是否成功。成功时值为 1失败时值为 0。',
errorReason: '错误原因',
usage: '模型用量信息',
},
extractParameters: '提取参数',
importFromTool: '从工具导入',
addExtractParameter: '添加提取参数',
@ -706,8 +718,6 @@ const translation = {
advancedSetting: '高级设置',
reasoningMode: '推理模式',
reasoningModeTip: '你可以根据模型对于 Function calling 或 Prompt 的指令响应能力选择合适的推理模式',
isSuccess: '是否成功。成功时值为 1失败时值为 0。',
errorReason: '错误原因',
},
iteration: {
deleteTitle: '删除迭代节点?',

@ -129,6 +129,8 @@ const translation = {
value: '值',
valuePlaceholder: '環境值',
secretTip: '用於定義敏感信息或數據DSL 設置配置為防止洩露。',
description: '描述',
descriptionPlaceholder: '描述此變數',
},
export: {
title: '導出機密環境變數?',
@ -537,6 +539,10 @@ const translation = {
placeholder: '在此處粘貼 cURL 字串',
title: '從 cURL 導入',
},
verifySSL: {
title: '驗證 SSL 證書',
warningTooltip: '不建議在生產環境中禁用SSL驗證。這僅應用於開發或測試因為這樣會使連接容易受到中間人攻擊等安全威脅的威脅。',
},
},
code: {
inputVars: '輸入變量',
@ -670,6 +676,7 @@ const translation = {
inputVars: '輸入變量',
outputVars: {
className: '分類名稱',
usage: '模型用量信息',
},
class: '分類',
classNamePlaceholder: '輸入你的分類名稱',
@ -683,6 +690,11 @@ const translation = {
},
parameterExtractor: {
inputVar: '輸入變量',
outputVars: {
isSuccess: '是否成功。成功時值為 1失敗時值為 0。',
errorReason: '錯誤原因',
usage: '模型用量信息',
},
extractParameters: '提取參數',
importFromTool: '從工具導入',
addExtractParameter: '添加提取參數',
@ -702,8 +714,6 @@ const translation = {
advancedSetting: '高級設置',
reasoningMode: '推理模式',
reasoningModeTip: '你可以根據模型對於 Function calling 或 Prompt 的指令響應能力選擇合適的推理模式',
isSuccess: '是否成功。成功時值為 1失敗時值為 0。',
errorReason: '錯誤原因',
},
iteration: {
deleteTitle: '刪除迭代節點?',

@ -116,6 +116,7 @@ export enum DatasetAttr {
DATA_PUBLIC_LOOP_NODE_MAX_COUNT = 'data-public-loop-node-max-count',
DATA_PUBLIC_MAX_ITERATIONS_NUM = 'data-public-max-iterations-num',
DATA_PUBLIC_MAX_TREE_DEPTH = 'data-public-max-tree-depth',
DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME = 'data-public-allow-unsafe-data-scheme',
DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER = 'data-public-enable-website-jinareader',
DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL = 'data-public-enable-website-firecrawl',
DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL = 'data-public-enable-website-watercrawl',

Loading…
Cancel
Save