chore(workflow): migrate legacy system file variable

Add compatibility migration for deprecated workflow system file references, persist upgraded workflow graphs, provide a batch migration command, and remove new frontend selection paths for the legacy variable.
This commit is contained in:
-LAN-
2026-05-11 13:22:25 +08:00
parent 59dab7deac
commit af004a88c3
49 changed files with 1364 additions and 235 deletions

View File

@ -19,6 +19,10 @@ from controllers.service_api.app.error import (
ProviderNotInitializeError,
ProviderQuotaExceededError,
)
from controllers.service_api.app.legacy_system_files import (
attach_legacy_system_file_warning_for_service_api,
normalize_legacy_system_file_args_for_service_api,
)
from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token
from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError
from core.app.entities.app_invoke_entities import InvokeFrom
@ -205,11 +209,20 @@ class ChatApi(Resource):
args["external_trace_id"] = external_trace_id
streaming = payload.response_mode == "streaming"
legacy_system_file_compat = None
if app_mode == AppMode.ADVANCED_CHAT:
args, legacy_system_file_compat = normalize_legacy_system_file_args_for_service_api(
app_model=app_model,
args=args,
raw_payload=service_api_ns.payload,
workflow_id=args.get("workflow_id"),
)
try:
response = AppGenerateService.generate(
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
)
response = attach_legacy_system_file_warning_for_service_api(response, legacy_system_file_compat)
return helper.compact_generate_response(response)
except WorkflowNotFoundError as ex:

View File

@ -0,0 +1,57 @@
from collections.abc import Mapping
from typing import Any
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.legacy_system_files import (
LegacySysFilesCompatVariable,
attach_legacy_sys_files_warning,
normalize_legacy_sys_files_args,
)
from models.model import App
from services.app_generate_service import AppGenerateService
def normalize_legacy_system_file_args_for_service_api(
*,
app_model: App,
args: Mapping[str, Any],
raw_payload: Mapping[str, Any] | None,
workflow_id: str | None = None,
) -> tuple[Mapping[str, Any], LegacySysFilesCompatVariable | None]:
# TODO: Remove this hidden Service API compatibility path after all persisted workflows are migrated.
args_with_hidden_system = _copy_hidden_system_files_arg(args=args, raw_payload=raw_payload)
if not _has_legacy_file_arg(args_with_hidden_system):
return args, None
workflow = AppGenerateService._get_workflow(app_model, InvokeFrom.SERVICE_API, workflow_id)
return normalize_legacy_sys_files_args(graph=workflow.graph_dict, args=args_with_hidden_system)
def attach_legacy_system_file_warning_for_service_api(
response: Mapping[str, Any] | Any,
compat_variable: LegacySysFilesCompatVariable | None,
) -> Mapping[str, Any] | Any:
# TODO: Remove this warning once Service API clients no longer need the legacy migration notice.
return attach_legacy_sys_files_warning(response, compat_variable)
def _copy_hidden_system_files_arg(
*,
args: Mapping[str, Any],
raw_payload: Mapping[str, Any] | None,
) -> Mapping[str, Any]:
system = raw_payload.get("system") if isinstance(raw_payload, Mapping) else None
if not isinstance(system, Mapping) or "files" not in system or system["files"] is None:
return args
copied_args = dict(args)
copied_args["system"] = {"files": system["files"]}
return copied_args
def _has_legacy_file_arg(args: Mapping[str, Any]) -> bool:
if args.get("files") is not None:
return True
system = args.get("system")
return isinstance(system, Mapping) and system.get("files") is not None

View File

@ -20,6 +20,10 @@ from controllers.service_api.app.error import (
ProviderNotInitializeError,
ProviderQuotaExceededError,
)
from controllers.service_api.app.legacy_system_files import (
attach_legacy_system_file_warning_for_service_api,
normalize_legacy_system_file_args_for_service_api,
)
from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token
from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError
from core.app.apps.base_app_queue_manager import AppQueueManager
@ -279,11 +283,17 @@ class WorkflowRunApi(Resource):
if external_trace_id:
args["external_trace_id"] = external_trace_id
streaming = payload.response_mode == "streaming"
args, legacy_system_file_compat = normalize_legacy_system_file_args_for_service_api(
app_model=app_model,
args=args,
raw_payload=service_api_ns.payload,
)
try:
response = AppGenerateService.generate(
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
)
response = attach_legacy_system_file_warning_for_service_api(response, legacy_system_file_compat)
return helper.compact_generate_response(response)
except ProviderTokenNotInitError as ex:
@ -339,11 +349,18 @@ class WorkflowRunByIdApi(Resource):
if external_trace_id:
args["external_trace_id"] = external_trace_id
streaming = payload.response_mode == "streaming"
args, legacy_system_file_compat = normalize_legacy_system_file_args_for_service_api(
app_model=app_model,
args=args,
raw_payload=service_api_ns.payload,
workflow_id=workflow_id,
)
try:
response = AppGenerateService.generate(
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
)
response = attach_legacy_system_file_warning_for_service_api(response, legacy_system_file_compat)
return helper.compact_generate_response(response)
except WorkflowNotFoundError as ex: