mirror of
https://github.com/langgenius/dify.git
synced 2026-11-11 05:41:09 +08:00
69 lines
2.7 KiB
Python
69 lines
2.7 KiB
Python
"""Change conversation-variable values without exposing persistence to the use case."""
|
|
|
|
from collections.abc import Callable
|
|
from functools import partial
|
|
from typing import Protocol
|
|
|
|
from pydantic import JsonValue
|
|
|
|
from factories import variable_factory
|
|
from graphon.variables import VariableBase
|
|
from graphon.variables.types import SegmentType
|
|
from services.conversation_variable_query import ConversationVariableRecord
|
|
from services.entities.conversation_entities import EndUserConversationRef
|
|
from services.errors.conversation import ConversationVariableTypeMismatchError
|
|
|
|
|
|
class ConversationVariableStore(Protocol):
|
|
def update(
|
|
self,
|
|
*,
|
|
ref: EndUserConversationRef,
|
|
variable_id: str,
|
|
transform: Callable[[VariableBase], VariableBase],
|
|
) -> ConversationVariableRecord:
|
|
"""Apply a pure value transform within the owned write transaction.
|
|
|
|
The transform must not perform I/O. Ownership, loading the current value,
|
|
transformation, and saving complete in one transaction.
|
|
"""
|
|
...
|
|
|
|
|
|
class ConversationVariableCommandService:
|
|
def __init__(self, *, variables: ConversationVariableStore) -> None:
|
|
self._variables = variables
|
|
|
|
def update_value(
|
|
self, *, ref: EndUserConversationRef, variable_id: str, new_value: JsonValue
|
|
) -> ConversationVariableRecord:
|
|
return self._variables.update(
|
|
ref=ref,
|
|
variable_id=variable_id,
|
|
transform=partial(self._replace_value, new_value=new_value),
|
|
)
|
|
|
|
@staticmethod
|
|
def _replace_value(current_variable: VariableBase, *, new_value: JsonValue) -> VariableBase:
|
|
expected_type = SegmentType(current_variable.value_type)
|
|
# The API exposes stored integers as numbers; preserve the existing check
|
|
# and let the shared factory retain its numeric reconstruction rules.
|
|
if expected_type == SegmentType.INTEGER:
|
|
expected_type = SegmentType.NUMBER
|
|
if not expected_type.is_valid(new_value):
|
|
inferred_type = SegmentType.infer_segment_type(new_value)
|
|
raise ConversationVariableTypeMismatchError(
|
|
f"Type mismatch: variable '{current_variable.name}' expects {expected_type.value}, "
|
|
f"but got {inferred_type.value if inferred_type else 'unknown'} type"
|
|
)
|
|
return variable_factory.build_conversation_variable_from_mapping(
|
|
{
|
|
"id": current_variable.id,
|
|
"name": current_variable.name,
|
|
"description": current_variable.description,
|
|
"value_type": current_variable.value_type,
|
|
"value": new_value,
|
|
"selector": current_variable.selector,
|
|
}
|
|
)
|