diff --git a/api/controllers/service_api/app/completion.py b/api/controllers/service_api/app/completion.py index 1d9890199d..7762672494 100644 --- a/api/controllers/service_api/app/completion.py +++ b/api/controllers/service_api/app/completion.py @@ -1,5 +1,6 @@ import logging +from flask import request from flask_restful import Resource, reqparse from werkzeug.exceptions import InternalServerError, NotFound @@ -23,6 +24,7 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) +from core.helper.trace_id_helper import get_external_trace_id from core.model_runtime.errors.invoke import InvokeError from libs import helper from libs.helper import uuid_value @@ -111,6 +113,10 @@ class ChatApi(Resource): args = parser.parse_args() + external_trace_id = get_external_trace_id(request) + if external_trace_id: + args["external_trace_id"] = external_trace_id + streaming = args["response_mode"] == "streaming" try: diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index ac2ebf2b09..370ff911b4 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -1,6 +1,7 @@ import logging from dateutil.parser import isoparse +from flask import request from flask_restful import Resource, fields, marshal_with, reqparse from flask_restful.inputs import int_range from sqlalchemy.orm import Session, sessionmaker @@ -23,6 +24,7 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) +from core.helper.trace_id_helper import get_external_trace_id from core.model_runtime.errors.invoke import InvokeError from core.workflow.entities.workflow_execution import WorkflowExecutionStatus from extensions.ext_database import db @@ -90,7 +92,9 @@ class WorkflowRunApi(Resource): parser.add_argument("files", type=list, required=False, location="json") parser.add_argument("response_mode", type=str, choices=["blocking", "streaming"], location="json") args = parser.parse_args() - + external_trace_id = get_external_trace_id(request) + if external_trace_id: + args["external_trace_id"] = external_trace_id streaming = args.get("response_mode") == "streaming" try: diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index bd5ad9c51b..fc6556dfb5 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -23,6 +23,7 @@ from core.app.apps.message_based_app_generator import MessageBasedAppGenerator from core.app.apps.message_based_app_queue_manager import MessageBasedAppQueueManager from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, InvokeFrom from core.app.entities.task_entities import ChatbotAppBlockingResponse, ChatbotAppStreamResponse +from core.helper.trace_id_helper import extract_external_trace_id_from_args from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.prompt.utils.get_thread_messages_length import get_thread_messages_length @@ -112,7 +113,10 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator): query = query.replace("\x00", "") inputs = args["inputs"] - extras = {"auto_generate_conversation_name": args.get("auto_generate_name", False)} + extras = { + "auto_generate_conversation_name": args.get("auto_generate_name", False), + **extract_external_trace_id_from_args(args), + } # get conversation conversation = None diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index 337b779b50..dc27076a4d 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -559,6 +559,7 @@ class AdvancedChatAppGenerateTaskPipeline: outputs=event.outputs, conversation_id=self._conversation_id, trace_manager=trace_manager, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( session=session, @@ -590,6 +591,7 @@ class AdvancedChatAppGenerateTaskPipeline: exceptions_count=event.exceptions_count, conversation_id=None, trace_manager=trace_manager, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( session=session, @@ -622,6 +624,7 @@ class AdvancedChatAppGenerateTaskPipeline: conversation_id=self._conversation_id, trace_manager=trace_manager, exceptions_count=event.exceptions_count, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( session=session, @@ -653,6 +656,7 @@ class AdvancedChatAppGenerateTaskPipeline: error_message=event.get_stop_reason(), conversation_id=self._conversation_id, trace_manager=trace_manager, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( session=session, diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index 6f560b3253..eeca9bb503 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -22,6 +22,7 @@ from core.app.apps.workflow.generate_response_converter import WorkflowAppGenera from core.app.apps.workflow.generate_task_pipeline import WorkflowAppGenerateTaskPipeline from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity from core.app.entities.task_entities import WorkflowAppBlockingResponse, WorkflowAppStreamResponse +from core.helper.trace_id_helper import extract_external_trace_id_from_args from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.repositories import DifyCoreRepositoryFactory @@ -123,6 +124,10 @@ class WorkflowAppGenerator(BaseAppGenerator): ) inputs: Mapping[str, Any] = args["inputs"] + + extras = { + **extract_external_trace_id_from_args(args), + } workflow_run_id = str(uuid.uuid4()) # init application generate entity application_generate_entity = WorkflowAppGenerateEntity( @@ -142,6 +147,7 @@ class WorkflowAppGenerator(BaseAppGenerator): call_depth=call_depth, trace_manager=trace_manager, workflow_execution_id=workflow_run_id, + extras=extras, ) contexts.plugin_tool_providers.set({}) diff --git a/api/core/app/apps/workflow/generate_task_pipeline.py b/api/core/app/apps/workflow/generate_task_pipeline.py index 9a39b2e01e..e31a316c56 100644 --- a/api/core/app/apps/workflow/generate_task_pipeline.py +++ b/api/core/app/apps/workflow/generate_task_pipeline.py @@ -490,6 +490,7 @@ class WorkflowAppGenerateTaskPipeline: outputs=event.outputs, conversation_id=None, trace_manager=trace_manager, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) # save workflow app log @@ -524,6 +525,7 @@ class WorkflowAppGenerateTaskPipeline: exceptions_count=event.exceptions_count, conversation_id=None, trace_manager=trace_manager, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) # save workflow app log @@ -561,6 +563,7 @@ class WorkflowAppGenerateTaskPipeline: conversation_id=None, trace_manager=trace_manager, exceptions_count=event.exceptions_count if isinstance(event, QueueWorkflowFailedEvent) else 0, + external_trace_id=self._application_generate_entity.extras.get("external_trace_id"), ) # save workflow app log diff --git a/api/core/helper/trace_id_helper.py b/api/core/helper/trace_id_helper.py new file mode 100644 index 0000000000..e90c3194f2 --- /dev/null +++ b/api/core/helper/trace_id_helper.py @@ -0,0 +1,42 @@ +import re +from collections.abc import Mapping +from typing import Any, Optional + + +def is_valid_trace_id(trace_id: str) -> bool: + """ + Check if the trace_id is valid. + + Requirements: 1-128 characters, only letters, numbers, '-', and '_'. + """ + return bool(re.match(r"^[a-zA-Z0-9\-_]{1,128}$", trace_id)) + + +def get_external_trace_id(request: Any) -> Optional[str]: + """ + Retrieve the trace_id from the request. + + Priority: header ('X-Trace-Id'), then parameters, then JSON body. Returns None if not provided or invalid. + """ + trace_id = request.headers.get("X-Trace-Id") + if not trace_id: + trace_id = request.args.get("trace_id") + if not trace_id and getattr(request, "is_json", False): + json_data = getattr(request, "json", None) + if json_data: + trace_id = json_data.get("trace_id") + if isinstance(trace_id, str) and is_valid_trace_id(trace_id): + return trace_id + return None + + +def extract_external_trace_id_from_args(args: Mapping[str, Any]) -> dict: + """ + Extract 'external_trace_id' from args. + + Returns a dict suitable for use in extras. Returns an empty dict if not found. + """ + trace_id = args.get("external_trace_id") + if trace_id: + return {"external_trace_id": trace_id} + return {} diff --git a/api/core/ops/aliyun_trace/aliyun_trace.py b/api/core/ops/aliyun_trace/aliyun_trace.py index db8fec4ee9..bbbc12a2c8 100644 --- a/api/core/ops/aliyun_trace/aliyun_trace.py +++ b/api/core/ops/aliyun_trace/aliyun_trace.py @@ -101,7 +101,8 @@ class AliyunDataTrace(BaseTraceInstance): raise ValueError(f"Aliyun get run url failed: {str(e)}") def workflow_trace(self, trace_info: WorkflowTraceInfo): - trace_id = convert_to_trace_id(trace_info.workflow_run_id) + external_trace_id = trace_info.metadata.get("external_trace_id") + trace_id = external_trace_id or convert_to_trace_id(trace_info.workflow_run_id) workflow_span_id = convert_to_span_id(trace_info.workflow_run_id, "workflow") self.add_workflow_span(trace_id, workflow_span_id, trace_info) diff --git a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py index 8b3ce0c448..14dba44237 100644 --- a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py +++ b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py @@ -153,7 +153,8 @@ class ArizePhoenixDataTrace(BaseTraceInstance): } workflow_metadata.update(trace_info.metadata) - trace_id = uuid_to_trace_id(trace_info.workflow_run_id) + external_trace_id = trace_info.metadata.get("external_trace_id") + trace_id = external_trace_id or uuid_to_trace_id(trace_info.workflow_run_id) span_id = RandomIdGenerator().generate_span_id() context = SpanContext( trace_id=trace_id, diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 4a7e66d27c..6dadb2897e 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -67,13 +67,14 @@ class LangFuseDataTrace(BaseTraceInstance): self.generate_name_trace(trace_info) def workflow_trace(self, trace_info: WorkflowTraceInfo): - trace_id = trace_info.workflow_run_id + external_trace_id = trace_info.metadata.get("external_trace_id") + trace_id = external_trace_id or trace_info.workflow_run_id user_id = trace_info.metadata.get("user_id") metadata = trace_info.metadata metadata["workflow_app_log_id"] = trace_info.workflow_app_log_id if trace_info.message_id: - trace_id = trace_info.message_id + trace_id = external_trace_id or trace_info.message_id name = TraceTaskName.MESSAGE_TRACE.value trace_data = LangfuseTrace( id=trace_id, diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index 8a559c4929..3246782278 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -65,7 +65,8 @@ class LangSmithDataTrace(BaseTraceInstance): self.generate_name_trace(trace_info) def workflow_trace(self, trace_info: WorkflowTraceInfo): - trace_id = trace_info.message_id or trace_info.workflow_run_id + external_trace_id = trace_info.metadata.get("external_trace_id") + trace_id = external_trace_id or trace_info.message_id or trace_info.workflow_run_id if trace_info.start_time is None: trace_info.start_time = datetime.now() message_dotted_order = ( diff --git a/api/core/ops/opik_trace/opik_trace.py b/api/core/ops/opik_trace/opik_trace.py index be4997a5bf..dfa7052c36 100644 --- a/api/core/ops/opik_trace/opik_trace.py +++ b/api/core/ops/opik_trace/opik_trace.py @@ -96,7 +96,8 @@ class OpikDataTrace(BaseTraceInstance): self.generate_name_trace(trace_info) def workflow_trace(self, trace_info: WorkflowTraceInfo): - dify_trace_id = trace_info.workflow_run_id + external_trace_id = trace_info.metadata.get("external_trace_id") + dify_trace_id = external_trace_id or trace_info.workflow_run_id opik_trace_id = prepare_opik_uuid(trace_info.start_time, dify_trace_id) workflow_metadata = wrap_metadata( trace_info.metadata, message_id=trace_info.message_id, workflow_app_log_id=trace_info.workflow_app_log_id @@ -104,7 +105,7 @@ class OpikDataTrace(BaseTraceInstance): root_span_id = None if trace_info.message_id: - dify_trace_id = trace_info.message_id + dify_trace_id = external_trace_id or trace_info.message_id opik_trace_id = prepare_opik_uuid(trace_info.start_time, dify_trace_id) trace_data = { diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index 5c9b9d27b7..34963efab3 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -520,6 +520,10 @@ class TraceTask: "app_id": workflow_run.app_id, } + external_trace_id = self.kwargs.get("external_trace_id") + if external_trace_id: + metadata["external_trace_id"] = external_trace_id + workflow_trace_info = WorkflowTraceInfo( workflow_data=workflow_run.to_dict(), conversation_id=conversation_id, diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index 445c6a8741..4bd41ce4a6 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -87,7 +87,8 @@ class WeaveDataTrace(BaseTraceInstance): self.generate_name_trace(trace_info) def workflow_trace(self, trace_info: WorkflowTraceInfo): - trace_id = trace_info.message_id or trace_info.workflow_run_id + external_trace_id = trace_info.metadata.get("external_trace_id") + trace_id = external_trace_id or trace_info.message_id or trace_info.workflow_run_id if trace_info.start_time is None: trace_info.start_time = datetime.now() diff --git a/api/core/rag/datasource/vdb/tablestore/tablestore_vector.py b/api/core/rag/datasource/vdb/tablestore/tablestore_vector.py index 552068c99e..55326fd60f 100644 --- a/api/core/rag/datasource/vdb/tablestore/tablestore_vector.py +++ b/api/core/rag/datasource/vdb/tablestore/tablestore_vector.py @@ -118,10 +118,21 @@ class TableStoreVector(BaseVector): def search_by_vector(self, query_vector: list[float], **kwargs: Any) -> list[Document]: top_k = kwargs.get("top_k", 4) - return self._search_by_vector(query_vector, top_k) + document_ids_filter = kwargs.get("document_ids_filter") + filtered_list = None + if document_ids_filter: + filtered_list = ["document_id=" + item for item in document_ids_filter] + score_threshold = float(kwargs.get("score_threshold") or 0.0) + return self._search_by_vector(query_vector, filtered_list, top_k, score_threshold) def search_by_full_text(self, query: str, **kwargs: Any) -> list[Document]: - return self._search_by_full_text(query) + top_k = kwargs.get("top_k", 4) + document_ids_filter = kwargs.get("document_ids_filter") + filtered_list = None + if document_ids_filter: + filtered_list = ["document_id=" + item for item in document_ids_filter] + + return self._search_by_full_text(query, filtered_list, top_k) def delete(self) -> None: self._delete_table_if_exist() @@ -230,32 +241,51 @@ class TableStoreVector(BaseVector): primary_key = [("id", id)] row = tablestore.Row(primary_key) self._tablestore_client.delete_row(self._table_name, row, None) - logging.info("Tablestore delete row successfully. id:%s", id) def _search_by_metadata(self, key: str, value: str) -> list[str]: query = tablestore.SearchQuery( tablestore.TermQuery(self._tags_field, str(key) + "=" + str(value)), - limit=100, + limit=1000, get_total_count=False, ) + rows: list[str] = [] + next_token = None + while True: + if next_token is not None: + query.next_token = next_token + + search_response = self._tablestore_client.search( + table_name=self._table_name, + index_name=self._index_name, + search_query=query, + columns_to_get=tablestore.ColumnsToGet( + column_names=[Field.PRIMARY_KEY.value], return_type=tablestore.ColumnReturnType.SPECIFIED + ), + ) - search_response = self._tablestore_client.search( - table_name=self._table_name, - index_name=self._index_name, - search_query=query, - columns_to_get=tablestore.ColumnsToGet(return_type=tablestore.ColumnReturnType.ALL_FROM_INDEX), - ) + if search_response is not None: + rows.extend([row[0][0][1] for row in search_response.rows]) - return [row[0][0][1] for row in search_response.rows] + if search_response is None or search_response.next_token == b"": + break + else: + next_token = search_response.next_token - def _search_by_vector(self, query_vector: list[float], top_k: int) -> list[Document]: - ots_query = tablestore.KnnVectorQuery( + return rows + + def _search_by_vector( + self, query_vector: list[float], document_ids_filter: list[str] | None, top_k: int, score_threshold: float + ) -> list[Document]: + knn_vector_query = tablestore.KnnVectorQuery( field_name=Field.VECTOR.value, top_k=top_k, float32_query_vector=query_vector, ) + if document_ids_filter: + knn_vector_query.filter = tablestore.TermsQuery(self._tags_field, document_ids_filter) + sort = tablestore.Sort(sorters=[tablestore.ScoreSort(sort_order=tablestore.SortOrder.DESC)]) - search_query = tablestore.SearchQuery(ots_query, limit=top_k, get_total_count=False, sort=sort) + search_query = tablestore.SearchQuery(knn_vector_query, limit=top_k, get_total_count=False, sort=sort) search_response = self._tablestore_client.search( table_name=self._table_name, @@ -263,30 +293,32 @@ class TableStoreVector(BaseVector): search_query=search_query, columns_to_get=tablestore.ColumnsToGet(return_type=tablestore.ColumnReturnType.ALL_FROM_INDEX), ) - logging.info( - "Tablestore search successfully. request_id:%s", - search_response.request_id, - ) - return self._to_query_result(search_response) - - def _to_query_result(self, search_response: tablestore.SearchResponse) -> list[Document]: documents = [] - for row in search_response.rows: - documents.append( - Document( - page_content=row[1][2][1], - vector=json.loads(row[1][3][1]), - metadata=json.loads(row[1][0][1]), + for search_hit in search_response.search_hits: + if search_hit.score > score_threshold: + metadata = json.loads(search_hit.row[1][0][1]) + metadata["score"] = search_hit.score + documents.append( + Document( + page_content=search_hit.row[1][2][1], + vector=json.loads(search_hit.row[1][3][1]), + metadata=metadata, + ) ) - ) - + documents = sorted(documents, key=lambda x: x.metadata["score"] if x.metadata else 0, reverse=True) return documents - def _search_by_full_text(self, query: str) -> list[Document]: + def _search_by_full_text(self, query: str, document_ids_filter: list[str] | None, top_k: int) -> list[Document]: + bool_query = tablestore.BoolQuery() + bool_query.must_queries.append(tablestore.MatchQuery(text=query, field_name=Field.CONTENT_KEY.value)) + + if document_ids_filter: + bool_query.filter_queries.append(tablestore.TermsQuery(self._tags_field, document_ids_filter)) + search_query = tablestore.SearchQuery( - query=tablestore.MatchQuery(text=query, field_name=Field.CONTENT_KEY.value), + query=bool_query, sort=tablestore.Sort(sorters=[tablestore.ScoreSort(sort_order=tablestore.SortOrder.DESC)]), - limit=100, + limit=top_k, ) search_response = self._tablestore_client.search( table_name=self._table_name, @@ -295,7 +327,16 @@ class TableStoreVector(BaseVector): columns_to_get=tablestore.ColumnsToGet(return_type=tablestore.ColumnReturnType.ALL_FROM_INDEX), ) - return self._to_query_result(search_response) + documents = [] + for search_hit in search_response.search_hits: + documents.append( + Document( + page_content=search_hit.row[1][2][1], + vector=json.loads(search_hit.row[1][3][1]), + metadata=json.loads(search_hit.row[1][0][1]), + ) + ) + return documents class TableStoreVectorFactory(AbstractVectorFactory): diff --git a/api/core/workflow/workflow_cycle_manager.py b/api/core/workflow/workflow_cycle_manager.py index f844aada95..03f670707e 100644 --- a/api/core/workflow/workflow_cycle_manager.py +++ b/api/core/workflow/workflow_cycle_manager.py @@ -85,6 +85,7 @@ class WorkflowCycleManager: outputs: Mapping[str, Any] | None = None, conversation_id: Optional[str] = None, trace_manager: Optional[TraceQueueManager] = None, + external_trace_id: Optional[str] = None, ) -> WorkflowExecution: workflow_execution = self._get_workflow_execution_or_raise_error(workflow_run_id) @@ -96,7 +97,7 @@ class WorkflowCycleManager: total_steps=total_steps, ) - self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id) + self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id, external_trace_id) self._workflow_execution_repository.save(workflow_execution) return workflow_execution @@ -111,6 +112,7 @@ class WorkflowCycleManager: exceptions_count: int = 0, conversation_id: Optional[str] = None, trace_manager: Optional[TraceQueueManager] = None, + external_trace_id: Optional[str] = None, ) -> WorkflowExecution: execution = self._get_workflow_execution_or_raise_error(workflow_run_id) @@ -123,7 +125,7 @@ class WorkflowCycleManager: exceptions_count=exceptions_count, ) - self._add_trace_task_if_needed(trace_manager, execution, conversation_id) + self._add_trace_task_if_needed(trace_manager, execution, conversation_id, external_trace_id) self._workflow_execution_repository.save(execution) return execution @@ -139,6 +141,7 @@ class WorkflowCycleManager: conversation_id: Optional[str] = None, trace_manager: Optional[TraceQueueManager] = None, exceptions_count: int = 0, + external_trace_id: Optional[str] = None, ) -> WorkflowExecution: workflow_execution = self._get_workflow_execution_or_raise_error(workflow_run_id) now = naive_utc_now() @@ -154,7 +157,7 @@ class WorkflowCycleManager: ) self._fail_running_node_executions(workflow_execution.id_, error_message, now) - self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id) + self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id, external_trace_id) self._workflow_execution_repository.save(workflow_execution) return workflow_execution @@ -312,6 +315,7 @@ class WorkflowCycleManager: trace_manager: Optional[TraceQueueManager], workflow_execution: WorkflowExecution, conversation_id: Optional[str], + external_trace_id: Optional[str], ) -> None: """Add trace task if trace manager is provided.""" if trace_manager: @@ -321,6 +325,7 @@ class WorkflowCycleManager: workflow_execution=workflow_execution, conversation_id=conversation_id, user_id=trace_manager.user_id, + external_trace_id=external_trace_id, ) ) diff --git a/api/templates/clean_document_job_mail_template-US.html b/api/templates/clean_document_job_mail_template-US.html index b26e494f80..97f3997c93 100644 --- a/api/templates/clean_document_job_mail_template-US.html +++ b/api/templates/clean_document_job_mail_template-US.html @@ -45,8 +45,7 @@ line-height: 120%; /* 28.8px */ } .button { - display: inline-block; - width: 480px; + display: block; padding: 8px 12px; color: white; text-decoration: none; diff --git a/api/templates/invite_member_mail_template_en-US.html b/api/templates/invite_member_mail_template_en-US.html index da29242869..a07c5f4b16 100644 --- a/api/templates/invite_member_mail_template_en-US.html +++ b/api/templates/invite_member_mail_template_en-US.html @@ -12,7 +12,7 @@ } .container { width: 504px; - height: 444px; + min-height: 444px; margin: 40px auto; padding: 0 48px; background-color: #fcfcfd; @@ -31,8 +31,7 @@ height: auto; } .button { - display: inline-block; - width: 480px; + display: block; padding: 8px 12px; color: white; text-decoration: none; diff --git a/api/templates/invite_member_mail_template_zh-CN.html b/api/templates/invite_member_mail_template_zh-CN.html index c7c321bf6f..27709a3c6d 100644 --- a/api/templates/invite_member_mail_template_zh-CN.html +++ b/api/templates/invite_member_mail_template_zh-CN.html @@ -28,11 +28,10 @@ .header img { max-width: 63px; - height: auto; + min-height: auto; } .button { - display: inline-block; - width: 480px; + display: block; padding: 8px 12px; color: white; text-decoration: none; diff --git a/api/templates/without-brand/invite_member_mail_template_en-US.html b/api/templates/without-brand/invite_member_mail_template_en-US.html index f6b1966c52..fc7f3679ba 100644 --- a/api/templates/without-brand/invite_member_mail_template_en-US.html +++ b/api/templates/without-brand/invite_member_mail_template_en-US.html @@ -12,7 +12,7 @@ } .container { width: 504px; - height: 444px; + min-height: 444px; margin: 40px auto; padding: 0 48px; background-color: #fcfcfd; @@ -31,8 +31,7 @@ height: auto; } .button { - display: inline-block; - width: 480px; + display: block; padding: 8px 12px; color: white; text-decoration: none; diff --git a/api/templates/without-brand/invite_member_mail_template_zh-CN.html b/api/templates/without-brand/invite_member_mail_template_zh-CN.html index fd2d6b873f..e787c90914 100644 --- a/api/templates/without-brand/invite_member_mail_template_zh-CN.html +++ b/api/templates/without-brand/invite_member_mail_template_zh-CN.html @@ -12,7 +12,7 @@ } .container { width: 504px; - height: 444px; + min-height: 444px; margin: 40px auto; padding: 0 48px; background-color: #fcfcfd; @@ -31,8 +31,7 @@ height: auto; } .button { - display: inline-block; - width: 480px; + display: block; padding: 8px 12px; color: white; text-decoration: none; diff --git a/api/tests/integration_tests/vdb/tablestore/test_tablestore.py b/api/tests/integration_tests/vdb/tablestore/test_tablestore.py index da890d0b7c..da549af1b6 100644 --- a/api/tests/integration_tests/vdb/tablestore/test_tablestore.py +++ b/api/tests/integration_tests/vdb/tablestore/test_tablestore.py @@ -1,4 +1,7 @@ import os +import uuid + +import tablestore from core.rag.datasource.vdb.tablestore.tablestore_vector import ( TableStoreConfig, @@ -6,6 +9,8 @@ from core.rag.datasource.vdb.tablestore.tablestore_vector import ( ) from tests.integration_tests.vdb.test_vector_store import ( AbstractVectorTest, + get_example_document, + get_example_text, setup_mock_redis, ) @@ -29,6 +34,49 @@ class TableStoreVectorTest(AbstractVectorTest): assert len(ids) == 1 assert ids[0] == self.example_doc_id + def create_vector(self): + self.vector.create( + texts=[get_example_document(doc_id=self.example_doc_id)], + embeddings=[self.example_embedding], + ) + while True: + search_response = self.vector._tablestore_client.search( + table_name=self.vector._table_name, + index_name=self.vector._index_name, + search_query=tablestore.SearchQuery(query=tablestore.MatchAllQuery(), get_total_count=True, limit=0), + columns_to_get=tablestore.ColumnsToGet(return_type=tablestore.ColumnReturnType.ALL_FROM_INDEX), + ) + if search_response.total_count == 1: + break + + def search_by_vector(self): + super().search_by_vector() + docs = self.vector.search_by_vector(self.example_embedding, document_ids_filter=[self.example_doc_id]) + assert len(docs) == 1 + assert docs[0].metadata["doc_id"] == self.example_doc_id + assert docs[0].metadata["score"] > 0 + + docs = self.vector.search_by_vector(self.example_embedding, document_ids_filter=[str(uuid.uuid4())]) + assert len(docs) == 0 + + def search_by_full_text(self): + super().search_by_full_text() + docs = self.vector.search_by_full_text(get_example_text(), document_ids_filter=[self.example_doc_id]) + assert len(docs) == 1 + assert docs[0].metadata["doc_id"] == self.example_doc_id + assert not hasattr(docs[0], "score") + + docs = self.vector.search_by_full_text(get_example_text(), document_ids_filter=[str(uuid.uuid4())]) + assert len(docs) == 0 + + def run_all_tests(self): + try: + self.vector.delete() + except Exception: + pass + + return super().run_all_tests() + def test_tablestore_vector(setup_mock_redis): TableStoreVectorTest().run_all_tests() diff --git a/api/tests/unit_tests/core/helper/test_trace_id_helper.py b/api/tests/unit_tests/core/helper/test_trace_id_helper.py new file mode 100644 index 0000000000..27bfe1af05 --- /dev/null +++ b/api/tests/unit_tests/core/helper/test_trace_id_helper.py @@ -0,0 +1,86 @@ +import pytest + +from core.helper.trace_id_helper import extract_external_trace_id_from_args, get_external_trace_id, is_valid_trace_id + + +class DummyRequest: + def __init__(self, headers=None, args=None, json=None, is_json=False): + self.headers = headers or {} + self.args = args or {} + self.json = json + self.is_json = is_json + + +class TestTraceIdHelper: + """Test cases for trace_id_helper.py""" + + @pytest.mark.parametrize( + ("trace_id", "expected"), + [ + ("abc123", True), + ("A-B_C-123", True), + ("a" * 128, True), + ("", False), + ("a" * 129, False), + ("abc!@#", False), + ("空格", False), + ("with space", False), + ], + ) + def test_is_valid_trace_id(self, trace_id, expected): + """Test trace_id validation for various cases""" + assert is_valid_trace_id(trace_id) is expected + + def test_get_external_trace_id_from_header(self): + """Should extract valid trace_id from header""" + req = DummyRequest(headers={"X-Trace-Id": "abc123"}) + assert get_external_trace_id(req) == "abc123" + + def test_get_external_trace_id_from_args(self): + """Should extract valid trace_id from args if header missing""" + req = DummyRequest(args={"trace_id": "abc123"}) + assert get_external_trace_id(req) == "abc123" + + def test_get_external_trace_id_from_json(self): + """Should extract valid trace_id from JSON body if header and args missing""" + req = DummyRequest(is_json=True, json={"trace_id": "abc123"}) + assert get_external_trace_id(req) == "abc123" + + def test_get_external_trace_id_priority(self): + """Header > args > json priority""" + req = DummyRequest( + headers={"X-Trace-Id": "header_id"}, + args={"trace_id": "args_id"}, + is_json=True, + json={"trace_id": "json_id"}, + ) + assert get_external_trace_id(req) == "header_id" + req2 = DummyRequest(args={"trace_id": "args_id"}, is_json=True, json={"trace_id": "json_id"}) + assert get_external_trace_id(req2) == "args_id" + req3 = DummyRequest(is_json=True, json={"trace_id": "json_id"}) + assert get_external_trace_id(req3) == "json_id" + + @pytest.mark.parametrize( + "req", + [ + DummyRequest(headers={"X-Trace-Id": "!!!"}), + DummyRequest(args={"trace_id": "!!!"}), + DummyRequest(is_json=True, json={"trace_id": "!!!"}), + DummyRequest(), + ], + ) + def test_get_external_trace_id_invalid(self, req): + """Should return None for invalid or missing trace_id""" + assert get_external_trace_id(req) is None + + @pytest.mark.parametrize( + ("args", "expected"), + [ + ({"external_trace_id": "abc123"}, {"external_trace_id": "abc123"}), + ({"other": "value"}, {}), + ({}, {}), + ], + ) + def test_extract_external_trace_id_from_args(self, args, expected): + """Test extraction of external_trace_id from args mapping""" + assert extract_external_trace_id_from_args(args) == expected diff --git a/web/app/components/base/markdown/index.tsx b/web/app/components/base/markdown/index.tsx index 1e50e6745b..bab5ac8eba 100644 --- a/web/app/components/base/markdown/index.tsx +++ b/web/app/components/base/markdown/index.tsx @@ -28,8 +28,15 @@ import { * Further refactoring candidates (custom block components not fitting general categories) * are noted in their respective files if applicable. */ +export type MarkdownProps = { + content: string + className?: string + customDisallowedElements?: string[] + customComponents?: Record> +} -export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) { +export const Markdown = (props: MarkdownProps) => { + const { customComponents = {} } = props const latexContent = flow([ preprocessThinkTag, preprocessLaTeX, @@ -78,6 +85,7 @@ export function Markdown(props: { content: string; className?: string; customDis form: MarkdownForm, script: ScriptBlock as any, details: ThinkBlock, + ...customComponents, }} > {/* Markdown detect has problem. */} diff --git a/web/app/components/develop/template/template_advanced_chat.en.mdx b/web/app/components/develop/template/template_advanced_chat.en.mdx index adba404a64..bafcb1f99a 100644 --- a/web/app/components/develop/template/template_advanced_chat.en.mdx +++ b/web/app/components/develop/template/template_advanced_chat.en.mdx @@ -80,6 +80,12 @@ Chat applications support session persistence, allowing previous chat history to Auto-generate title, default is `true`. If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`. + + (Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:
+ - Header: via HTTP Header X-Trace-Id, highest priority.
+ - Query parameter: via URL query parameter trace_id.
+ - Request Body: via request body field trace_id (i.e., this field).
+
### Response diff --git a/web/app/components/develop/template/template_advanced_chat.ja.mdx b/web/app/components/develop/template/template_advanced_chat.ja.mdx index 2e57d5e20c..d8c5464ed5 100644 --- a/web/app/components/develop/template/template_advanced_chat.ja.mdx +++ b/web/app/components/develop/template/template_advanced_chat.ja.mdx @@ -80,6 +80,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from タイトルを自動生成、デフォルトは`true`。 `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。 + + (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:
+ - Header:HTTPヘッダー X-Trace-Id で渡す(最優先)。
+ - クエリパラメータ:URLクエリパラメータ trace_id で渡す。
+ - リクエストボディ:リクエストボディの trace_id フィールドで渡す(本フィールド)。
+
### 応答 diff --git a/web/app/components/develop/template/template_advanced_chat.zh.mdx b/web/app/components/develop/template/template_advanced_chat.zh.mdx index 8955396ad9..30068d93a2 100755 --- a/web/app/components/develop/template/template_advanced_chat.zh.mdx +++ b/web/app/components/develop/template/template_advanced_chat.zh.mdx @@ -78,6 +78,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 + + (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成trace_id。支持以下三种方式传递,具体优先级依次为:
+ - Header:通过 HTTP Header X-Trace-Id 传递,优先级最高。
+ - Query 参数:通过 URL 查询参数 trace_id 传递。
+ - Request Body:通过请求体字段 trace_id 传递(即本字段)。
+
### Response diff --git a/web/app/components/develop/template/template_chat.en.mdx b/web/app/components/develop/template/template_chat.en.mdx index 73d1fa1b41..f1bb1de206 100644 --- a/web/app/components/develop/template/template_chat.en.mdx +++ b/web/app/components/develop/template/template_chat.en.mdx @@ -74,6 +74,12 @@ Chat applications support session persistence, allowing previous chat history to Auto-generate title, default is `true`. If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`. + + (Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:
+ - Header: via HTTP Header X-Trace-Id, highest priority.
+ - Query parameter: via URL query parameter trace_id.
+ - Request Body: via request body field trace_id (i.e., this field).
+
### Response diff --git a/web/app/components/develop/template/template_chat.ja.mdx b/web/app/components/develop/template/template_chat.ja.mdx index 45c970a9f2..06e88782d9 100644 --- a/web/app/components/develop/template/template_chat.ja.mdx +++ b/web/app/components/develop/template/template_chat.ja.mdx @@ -74,6 +74,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from タイトルを自動生成します。デフォルトは`true`です。 `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。 + + (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:
+ - Header:HTTPヘッダー X-Trace-Id で渡す(最優先)。
+ - クエリパラメータ:URLクエリパラメータ trace_id で渡す。
+ - リクエストボディ:リクエストボディの trace_id フィールドで渡す(本フィールド)。
+
### 応答 diff --git a/web/app/components/develop/template/template_chat.zh.mdx b/web/app/components/develop/template/template_chat.zh.mdx index 8573408c36..a7127d614b 100644 --- a/web/app/components/develop/template/template_chat.zh.mdx +++ b/web/app/components/develop/template/template_chat.zh.mdx @@ -73,6 +73,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 + + (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成trace_id。支持以下三种方式传递,具体优先级依次为:
+ - Header:通过 HTTP Header X-Trace-Id 传递,优先级最高。
+ - Query 参数:通过 URL 查询参数 trace_id 传递。
+ - Request Body:通过请求体字段 trace_id 传递(即本字段)。
+
### Response diff --git a/web/app/components/develop/template/template_workflow.en.mdx b/web/app/components/develop/template/template_workflow.en.mdx index 23ff2bbb55..8ac1db3287 100644 --- a/web/app/components/develop/template/template_workflow.en.mdx +++ b/web/app/components/develop/template/template_workflow.en.mdx @@ -66,6 +66,12 @@ Workflow applications offers non-session support and is ideal for translation, a Should be uniquely defined by the developer within the application.
The user identifier should be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. + - `files` (array[object]) Optional + - `trace_id` (string) Optional + Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority: + 1. Header: via HTTP Header `X-Trace-Id`, highest priority. + 2. Query parameter: via URL query parameter `trace_id`. + 3. Request Body: via request body field `trace_id` (i.e., this field). ### Response When `response_mode` is `blocking`, return a CompletionResponse object. diff --git a/web/app/components/develop/template/template_workflow.ja.mdx b/web/app/components/develop/template/template_workflow.ja.mdx index 287eb87f45..0c32467ce8 100644 --- a/web/app/components/develop/template/template_workflow.ja.mdx +++ b/web/app/components/develop/template/template_workflow.ja.mdx @@ -66,6 +66,11 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用されます。 アプリケーション内で開発者によって一意に定義される必要があります。 - `files` (array[object]) オプション + - `trace_id` (string) オプション + トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです: + 1. Header:HTTPヘッダー `X-Trace-Id` で渡す(最優先)。 + 2. クエリパラメータ:URLクエリパラメータ `trace_id` で渡す。 + 3. リクエストボディ:リクエストボディの `trace_id` フィールドで渡す(本フィールド)。 ### 応答 diff --git a/web/app/components/develop/template/template_workflow.zh.mdx b/web/app/components/develop/template/template_workflow.zh.mdx index 105eca0700..236da62e88 100644 --- a/web/app/components/develop/template/template_workflow.zh.mdx +++ b/web/app/components/develop/template/template_workflow.zh.mdx @@ -60,7 +60,12 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 - `user` (string) Required 用户标识,用于定义终端用户的身份,方便检索、统计。 由开发者定义规则,需保证用户标识在应用内唯一。API 无法访问 WebApp 创建的会话。 - + - `files` (array[object]) 可选 + - `trace_id` (string) Optional + 链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统将自动生成 `trace_id`。支持以下三种方式传递,具体优先级依次为: + 1. Header:推荐通过 HTTP Header `X-Trace-Id` 传递,优先级最高。 + 2. Query 参数:通过 URL 查询参数 `trace_id` 传递。 + 3. Request Body:通过请求体字段 `trace_id` 传递(即本字段)。 ### Response 当 `response_mode` 为 `blocking` 时,返回 CompletionResponse object。 diff --git a/web/app/components/tools/mcp/hooks.ts b/web/app/components/tools/mcp/hooks.ts index b2b521557f..562be6f079 100644 --- a/web/app/components/tools/mcp/hooks.ts +++ b/web/app/components/tools/mcp/hooks.ts @@ -1,7 +1,10 @@ import dayjs from 'dayjs' +import relativeTime from 'dayjs/plugin/relativeTime' import { useCallback } from 'react' import { useI18N } from '@/context/i18n' +dayjs.extend(relativeTime) + export const useFormatTimeFromNow = () => { const { locale } = useI18N() const formatTimeFromNow = useCallback((time: number) => { diff --git a/web/i18n/de-DE/plugin.ts b/web/i18n/de-DE/plugin.ts index 2a79241d00..e416e4c9cb 100644 --- a/web/i18n/de-DE/plugin.ts +++ b/web/i18n/de-DE/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointDeleteTip: 'Endpunkt entfernen', serviceOk: 'Service in Ordnung', switchVersion: 'Version wechseln', + deprecation: { + reason: { + noMaintainer: 'kein Wartender', + ownershipTransferred: 'Eigentum übertragen', + businessAdjustments: 'Geschäftsanpassungen', + }, + onlyReason: 'Dieses Plugin wurde aufgrund von {{deprecatedReason}} abgelehnt und wird nicht länger aktualisiert.', + fullMessage: 'Dieses Plugin wurde aufgrund von {{deprecatedReason}} eingestellt und wird nicht mehr aktualisiert. Bitte verwenden Sie stattdessen {{-alternativePluginId}}.', + noReason: 'Dieses Plugin wurde eingestellt und wird nicht mehr aktualisiert.', + }, }, debugInfo: { title: 'Debuggen', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'Nachdem die Anmeldeinformationen konfiguriert wurden, können alle Mitglieder des Arbeitsbereichs dieses Tool beim Orchestrieren von Anwendungen verwenden.', authRemoved: 'Die Authentifizierung wurde entfernt.', }, + deprecated: 'Abgelehnt', } export default translation diff --git a/web/i18n/es-ES/common.ts b/web/i18n/es-ES/common.ts index 337232bea0..eba82dd384 100644 --- a/web/i18n/es-ES/common.ts +++ b/web/i18n/es-ES/common.ts @@ -690,6 +690,7 @@ const translation = { license: { expiring: 'Caduca en un día', expiring_plural: 'Caducando en {{count}} días', + unlimited: 'Ilimitado', }, pagination: { perPage: 'Elementos por página', diff --git a/web/i18n/es-ES/dataset.ts b/web/i18n/es-ES/dataset.ts index 16745b56d7..e27fe0cbf9 100644 --- a/web/i18n/es-ES/dataset.ts +++ b/web/i18n/es-ES/dataset.ts @@ -204,6 +204,7 @@ const translation = { name: 'Nombre', description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.', disabled: 'desactivar', + builtIn: 'Integrado', }, documentMetadata: { technicalParameters: 'Parámetros técnicos', diff --git a/web/i18n/es-ES/plugin.ts b/web/i18n/es-ES/plugin.ts index 630ff3e405..e4506e09e2 100644 --- a/web/i18n/es-ES/plugin.ts +++ b/web/i18n/es-ES/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointsDocLink: 'Ver el documento', endpointsEmpty: 'Haga clic en el botón \'+\' para agregar un punto de conexión', configureApp: 'Configurar la aplicación', + deprecation: { + reason: { + ownershipTransferred: 'propiedad transferida', + noMaintainer: 'sin mantenedor', + businessAdjustments: 'ajustes comerciales', + }, + noReason: 'Este complemento ha sido descontinuado y ya no se actualizará.', + onlyReason: 'Este complemento ha sido desaprobado debido a {{deprecatedReason}} y ya no se actualizará.', + fullMessage: 'Este complemento ha sido descontinuado debido a {{deprecatedReason}}, y ya no será actualizado. Por favor, utilice {{-alternativePluginId}} en su lugar.', + }, }, debugInfo: { title: 'Depuración', @@ -235,7 +245,9 @@ const translation = { saveOnly: 'Guardar solo', clientInfo: 'Como no se encontraron secretos de cliente del sistema para este proveedor de herramientas, se requiere configurarlo manualmente. Para redirect_uri, por favor utiliza', oauthClientSettings: 'Configuración del cliente OAuth', + default: 'Predeterminado', }, + deprecated: 'Obsoleto', } export default translation diff --git a/web/i18n/es-ES/workflow.ts b/web/i18n/es-ES/workflow.ts index 535f92b0b1..3c509934df 100644 --- a/web/i18n/es-ES/workflow.ts +++ b/web/i18n/es-ES/workflow.ts @@ -475,10 +475,12 @@ const translation = { options: { disabled: { subTitle: 'No habilitar el filtrado de metadatos', + title: 'Deshabilitado', }, automatic: { subTitle: 'Generar automáticamente condiciones de filtrado de metadatos basadas en la consulta del usuario', desc: 'Generar automáticamente condiciones de filtrado de metadatos basadas en la variable de consulta', + title: 'Automático', }, manual: { title: 'Manual', @@ -898,6 +900,7 @@ const translation = { error_other: '{{count}} Errores', loopVariables: 'Variables de bucle', variableName: 'Nombre de Variable', + input: 'Entrada', }, }, tracing: { @@ -916,6 +919,7 @@ const translation = { onlyShowNamedVersions: 'Solo muestra versiones nombradas', empty: 'No se encontró un historial de versiones coincidente.', reset: 'Restablecer filtro', + all: 'Todo', }, editField: { titleLengthLimit: 'El título no puede exceder {{limit}} caracteres', @@ -939,6 +943,7 @@ const translation = { deletionTip: 'La eliminación es irreversible, por favor confirma.', currentDraft: 'Borrador Actual', editVersionInfo: 'Editar información de la versión', + latest: 'Último', }, debug: { noData: { @@ -951,6 +956,7 @@ const translation = { stop: 'Detén la carrera', normal: 'Inspeccionar Variable', cached: 'Ver variables en caché', + clear: 'Claro', }, envNode: 'Medio ambiente', chatNode: 'Conversación', @@ -963,6 +969,7 @@ const translation = { resetConversationVar: 'Restablecer la variable de conversación al valor predeterminado', clearNode: 'Limpiar variable en caché', emptyTip: 'Después de recorrer un nodo en el lienzo o ejecutar un nodo paso a paso, puedes ver el valor actual de la variable del nodo en Inspección de Variables.', + edited: 'Editado', }, lastRunTab: 'Última ejecución', settingsTab: 'Ajustes', diff --git a/web/i18n/fa-IR/plugin.ts b/web/i18n/fa-IR/plugin.ts index aebe39d508..a9fba512e6 100644 --- a/web/i18n/fa-IR/plugin.ts +++ b/web/i18n/fa-IR/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointModalDesc: 'پس از پیکربندی، می توان از ویژگی های ارائه شده توسط افزونه از طریق نقاط پایانی API استفاده کرد.', switchVersion: 'نسخه سوئیچ', endpointDeleteContent: 'آیا می خواهید {{name}} را حذف کنید؟', + deprecation: { + reason: { + ownershipTransferred: 'مالکیت منتقل شد', + businessAdjustments: 'تنظیمات کسب و کار', + noMaintainer: 'بدون نگهدارنده', + }, + noReason: 'این افزونه منسوخ شده است و دیگر به روز رسانی نخواهد شد.', + onlyReason: 'این افزونه به دلیل {{deprecatedReason}} منسوخ شده و دیگر به‌روزرسانی نخواهد شد.', + fullMessage: 'این افزونه به دلیل {{deprecatedReason}} منسوخ شده است و دیگر به‌روزرسانی نخواهد شد. لطفا به‌جای آن از {{-alternativePluginId}} استفاده کنید.', + }, }, debugInfo: { title: 'اشکال زدایی', @@ -237,6 +247,7 @@ const translation = { clientInfo: 'از آنجایی که هیچ راز مشتری سیستم برای این ارائه‌دهنده ابزار پیدا نشد، تنظیم دستی آن ضروری است، لطفاً برای redirect_uri از', useApiAuthDesc: 'پس از پیکربندی اعتبارنامه‌ها، تمامی اعضای درون فضای کاری می‌توانند از این ابزار هنگام نظم‌دهی به برنامه‌ها استفاده کنند.', }, + deprecated: 'منسوخ شده', } export default translation diff --git a/web/i18n/fr-FR/plugin.ts b/web/i18n/fr-FR/plugin.ts index dcab0a1ead..2f85e26244 100644 --- a/web/i18n/fr-FR/plugin.ts +++ b/web/i18n/fr-FR/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointModalTitle: 'Configurer le point de terminaison', serviceOk: 'Service OK', endpointModalDesc: 'Une fois configuré, les fonctionnalités fournies par le plugin via les points de terminaison de l’API peuvent être utilisées.', + deprecation: { + reason: { + ownershipTransferred: 'propriété transférée', + businessAdjustments: 'ajustements commerciaux', + noMaintainer: 'aucun mainteneur', + }, + noReason: 'Ce plugin a été abandonné et ne sera plus mis à jour.', + onlyReason: 'Ce plugin a été déprécié en raison de {{deprecatedReason}} et ne sera plus mis à jour.', + fullMessage: 'Ce plugin a été déprécié en raison de {{deprecatedReason}}, et ne sera plus mis à jour. Veuillez utiliser {{-alternativePluginId}} à la place.', + }, }, debugInfo: { title: 'Débogage', @@ -237,6 +247,7 @@ const translation = { authorization: 'Autorisation', useApi: 'Utilisez la clé API', }, + deprecated: 'Obsolète', } export default translation diff --git a/web/i18n/hi-IN/plugin.ts b/web/i18n/hi-IN/plugin.ts index cd5540d5a9..b1349b149b 100644 --- a/web/i18n/hi-IN/plugin.ts +++ b/web/i18n/hi-IN/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointModalTitle: 'एंडपॉइंट सेटअप करें', strategyNum: '{{num}} {{रणनीति}} शामिल', endpointsTip: 'यह प्लगइन एंडपॉइंट्स के माध्यम से विशिष्ट कार्यक्षमताएँ प्रदान करता है, और आप वर्तमान कार्यक्षेत्र के लिए कई एंडपॉइंट सेट कॉन्फ़िगर कर सकते हैं।', + deprecation: { + reason: { + noMaintainer: 'कोई देखभाल करने वाला नहीं', + ownershipTransferred: 'स्वामित्व स्थानांतरित किया गया', + businessAdjustments: 'व्यवसाय समायोजन', + }, + noReason: 'यह प्लगइन अप्रचलित हो गया है और इसे अब अपडेट नहीं किया जाएगा।', + onlyReason: 'इस प्लगइन को {{deprecatedReason}} के कारण अमान्य कर दिया गया है और इसे अब अपडेट नहीं किया जाएगा।', + fullMessage: 'इस प्लगइन को {{deprecatedReason}} के कारण अमान्य कर दिया गया है, और इसे अब अपडेट नहीं किया जाएगा। कृपया इसके बजाय {{-alternativePluginId}} का उपयोग करें।', + }, }, debugInfo: { viewDocs: 'दस्तावेज़ देखें', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'क्रेडेंशियल्स कॉन्फ़िगर करने के बाद, कार्यक्षेत्र के सभी सदस्यों को एप्लिकेशन को व्यवस्थित करते समय इस उपकरण का उपयोग करने की अनुमति होती है।', clientInfo: 'चूंकि इस टूल प्रदाता के लिए कोई सिस्टम क्लाइंट रहस्य नहीं पाए गए हैं, इसलिए इसे मैन्युअल रूप से सेटअप करना आवश्यक है, कृपया redirect_uri का उपयोग करें', }, + deprecated: 'अनुशंसित नहीं', } export default translation diff --git a/web/i18n/it-IT/app.ts b/web/i18n/it-IT/app.ts index a874d2b71f..63a25dccc6 100644 --- a/web/i18n/it-IT/app.ts +++ b/web/i18n/it-IT/app.ts @@ -232,6 +232,7 @@ const translation = { structuredTip: 'Le Uscite Strutturate sono una funzione che garantisce che il modello generi sempre risposte che aderiscano al tuo Schema JSON fornito.', notConfiguredTip: 'L\'output strutturato non è stato ancora configurato.', modelNotSupportedTip: 'Il modello attuale non supporta questa funzione e viene automaticamente downgradato a iniezione di prompt.', + required: 'Necessario', }, accessItemsDescription: { anyone: 'Chiunque può accedere all\'app web', diff --git a/web/i18n/it-IT/dataset.ts b/web/i18n/it-IT/dataset.ts index 9f66ee8e43..c8d5482a4d 100644 --- a/web/i18n/it-IT/dataset.ts +++ b/web/i18n/it-IT/dataset.ts @@ -211,6 +211,7 @@ const translation = { deleteContent: 'Sei sicuro di voler eliminare i metadati "{{name}}"?', builtInDescription: 'I metadati incorporati vengono estratti e generati automaticamente. Devono essere abilitati prima dell\'uso e non possono essere modificati.', description: 'Puoi gestire tutti i metadati in questa conoscenza qui. Le modifiche saranno sincronizzate con ogni documento.', + builtIn: 'Integrato', }, documentMetadata: { documentInformation: 'Informazioni sul documento', diff --git a/web/i18n/it-IT/plugin.ts b/web/i18n/it-IT/plugin.ts index f2aa0977f0..52c05ae40c 100644 --- a/web/i18n/it-IT/plugin.ts +++ b/web/i18n/it-IT/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointDeleteTip: 'Rimuovi punto finale', endpointsEmpty: 'Fare clic sul pulsante \'+\' per aggiungere un punto finale', actionNum: '{{num}} {{azione}} INCLUSO', + deprecation: { + reason: { + noMaintainer: 'nessun manutentore', + ownershipTransferred: 'proprietà trasferita', + businessAdjustments: 'adeguamenti aziendali', + }, + onlyReason: 'Questo plugin è stato deprecato a causa di {{deprecatedReason}} e non verrà più aggiornato.', + fullMessage: 'Questo plugin è stato deprecato a causa di {{deprecatedReason}} e non verrà più aggiornato. Si prega di utilizzare {{-alternativePluginId}} invece.', + noReason: 'Questo plugin è stato deprecato e non sarà più aggiornato.', + }, }, debugInfo: { title: 'Debug', @@ -237,6 +247,7 @@ const translation = { useApiAuth: 'Configurazione dell\'autorizzazione della chiave API', clientInfo: 'Poiché non sono stati trovati segreti client di sistema per questo fornitore di strumenti, è necessario configurarlo manualmente. Per redirect_uri, si prega di utilizzare', }, + deprecated: 'Deprecato', } export default translation diff --git a/web/i18n/it-IT/workflow.ts b/web/i18n/it-IT/workflow.ts index 024ee8b90c..97e4bc14f2 100644 --- a/web/i18n/it-IT/workflow.ts +++ b/web/i18n/it-IT/workflow.ts @@ -497,6 +497,7 @@ const translation = { automatic: { subTitle: 'Genera automaticamente condizioni di filtraggio dei metadati in base alla query dell\'utente', desc: 'Genera automaticamente condizioni di filtraggio dei metadati basate sulla variabile di query', + title: 'Automatico', }, manual: { title: 'Manuale', @@ -611,6 +612,7 @@ const translation = { 'exists': 'Esiste', 'not exists': 'non esiste', 'after': 'dopo', + 'before': 'prima', }, enterValue: 'Inserisci valore', addCondition: 'Aggiungi Condizione', diff --git a/web/i18n/ko-KR/plugin.ts b/web/i18n/ko-KR/plugin.ts index 6050448fbf..5ed122c3f1 100644 --- a/web/i18n/ko-KR/plugin.ts +++ b/web/i18n/ko-KR/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpoints: '끝점', serviceOk: '서비스 정상', endpointDisableTip: '엔드포인트 비활성화', + deprecation: { + reason: { + ownershipTransferred: '소유권 이전', + businessAdjustments: '사업 조정', + noMaintainer: '유지보수자 없음', + }, + noReason: '이 플러그인은 더 이상 지원되지 않으며 업데이트되지 않을 것입니다.', + onlyReason: '이 플러그인은 {{deprecatedReason}}로 인해 사용 중단되었으며 더 이상 업데이트되지 않습니다.', + fullMessage: '이 플러그인은 {{deprecatedReason}}로 인해 사용 중단되었으며 더 이상 업데이트되지 않습니다. 대신 {{-alternativePluginId}}를 사용하십시오.', + }, }, debugInfo: { title: '디버깅', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: '자격증명을 구성한 후에는 작업 공간 내의 모든 구성원이 애플리케이션을 조정할 때 이 도구를 사용할 수 있습니다.', clientInfo: '이 도구 공급자에 대한 시스템 클라이언트 비밀이 발견되지 않았으므로 수동으로 설정해야 하며, redirect_uri는 다음을 사용하십시오.', }, + deprecated: '사용 중단됨', } export default translation diff --git a/web/i18n/pl-PL/plugin.ts b/web/i18n/pl-PL/plugin.ts index a4b194b757..3349fac4da 100644 --- a/web/i18n/pl-PL/plugin.ts +++ b/web/i18n/pl-PL/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointDeleteContent: 'Czy chcesz usunąć {{name}}?', endpointsTip: 'Ta wtyczka zapewnia określone funkcje za pośrednictwem punktów końcowych i można skonfigurować wiele zestawów punktów końcowych dla bieżącego obszaru roboczego.', modelNum: '{{liczba}} MODELE W ZESTAWIE', + deprecation: { + reason: { + businessAdjustments: 'dostosowania biznesowe', + ownershipTransferred: 'własność przekazana', + noMaintainer: 'brak opiekuna', + }, + onlyReason: 'Ten plugin został wycofany z użycia z powodu {{deprecatedReason}} i nie będzie już aktualizowany.', + noReason: 'Ten wtyczka została przestarzała i nie będzie dłużej aktualizowana.', + fullMessage: 'Ten plugin został wycofany z użycia z powodu {{deprecatedReason}} i nie będzie już aktualizowany. Proszę użyć zamiast tego {{-alternativePluginId}}.', + }, }, debugInfo: { viewDocs: 'Wyświetlanie dokumentów', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'Po skonfigurowaniu poświadczeń wszyscy członkowie w przestrzeni roboczej mogą korzystać z tego narzędzia podczas orkiestracji aplikacji.', clientInfo: 'Ponieważ nie znaleziono tajemnic klientów systemu dla tego dostawcy narzędzi, wymagane jest ręczne skonfigurowanie, dla redirect_uri proszę użyć', }, + deprecated: 'Nieaktualny', } export default translation diff --git a/web/i18n/pt-BR/plugin.ts b/web/i18n/pt-BR/plugin.ts index c03acac2ec..4527f5ff03 100644 --- a/web/i18n/pt-BR/plugin.ts +++ b/web/i18n/pt-BR/plugin.ts @@ -84,6 +84,16 @@ const translation = { configureTool: 'Ferramenta de configuração', endpointsDocLink: 'Veja o documento', endpointModalTitle: 'Ponto de extremidade de configuração', + deprecation: { + reason: { + businessAdjustments: 'ajustes de negócios', + ownershipTransferred: 'propriedade transferida', + noMaintainer: 'sem mantenedor', + }, + onlyReason: 'Este plugin foi descontinuado devido a {{deprecatedReason}} e não será mais atualizado.', + noReason: 'Este plugin foi descontinuado e não será mais atualizado.', + fullMessage: 'Este plugin foi descontinuado devido a {{deprecatedReason}}, e não receberá mais atualizações. Por favor, use {{-alternativePluginId}} em vez disso.', + }, }, debugInfo: { title: 'Depuração', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'Após configurar as credenciais, todos os membros dentro do espaço de trabalho podem usar esta ferramenta ao orquestrar aplicações.', clientInfo: 'Como não foram encontrados segredos de cliente do sistema para este provedor de ferramentas, é necessário configurá-lo manualmente. Para redirect_uri, use', }, + deprecated: 'Obsoleto', } export default translation diff --git a/web/i18n/ro-RO/plugin.ts b/web/i18n/ro-RO/plugin.ts index b866f1de01..3b5e4da843 100644 --- a/web/i18n/ro-RO/plugin.ts +++ b/web/i18n/ro-RO/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointModalDesc: 'Odată configurate, pot fi utilizate funcțiile furnizate de plugin prin intermediul punctelor finale API.', modelNum: '{{num}} MODELE INCLUSE', configureModel: 'Configurarea modelului', + deprecation: { + reason: { + businessAdjustments: 'ajustări de afaceri', + noMaintainer: 'fără întreținător', + ownershipTransferred: 'proprietatea transferată', + }, + noReason: 'Acest plugin a fost declarat învechit și nu va mai fi actualizat.', + onlyReason: 'Acest plugin a fost depreciat din cauza {{deprecatedReason}} și nu va mai fi actualizat.', + fullMessage: 'Acest plugin a fost declarat învechit din cauza {{deprecatedReason}}, și nu va mai fi actualizat. Vă rugăm să folosiți în schimb {{-alternativePluginId}}.', + }, }, debugInfo: { viewDocs: 'Vizualizați documentele', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'După configurarea acreditivelor, toți membrii din spațiul de lucru pot folosi acest instrument atunci când orchestran aplicații.', clientInfo: 'Deoarece nu s-au găsit secretele clientului sistemului pentru acest furnizor de instrumente, este necesară configurarea manuală; pentru redirect_uri, vă rugăm să folosiți', }, + deprecated: 'Încetat de a mai fi utilizat', } export default translation diff --git a/web/i18n/ru-RU/plugin.ts b/web/i18n/ru-RU/plugin.ts index 5c96520ed9..e82963c3f1 100644 --- a/web/i18n/ru-RU/plugin.ts +++ b/web/i18n/ru-RU/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointsEmpty: 'Нажмите кнопку «+», чтобы добавить конечную точку', switchVersion: 'Версия для переключателя', endpointsDocLink: 'Посмотреть документ', + deprecation: { + reason: { + businessAdjustments: 'бизнес-правки', + ownershipTransferred: 'передача права собственности', + noMaintainer: 'нет сопровождающего', + }, + noReason: 'Этот плагин был устаревшим и больше не будет обновляться.', + onlyReason: 'Этот плагин был устаревшим из-за {{deprecatedReason}} и больше не будет обновляться.', + fullMessage: 'Этот плагин больше не поддерживается по причине {{deprecatedReason}} и больше не будет обновляться. Пожалуйста, используйте {{-alternativePluginId}} вместо этого.', + }, }, debugInfo: { title: 'Отладка', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'После настройки учетных данных все члены рабочей области могут использовать этот инструмент при оркестрации приложений.', clientInfo: 'Поскольку не найдены секреты клиентской системы для этого поставщика инструментов, необходимо настроить его вручную, для redirect_uri, пожалуйста, используйте', }, + deprecated: 'Устаревший', } export default translation diff --git a/web/i18n/sl-SI/plugin.ts b/web/i18n/sl-SI/plugin.ts index cecb8e9a62..5ed6d9c0a7 100644 --- a/web/i18n/sl-SI/plugin.ts +++ b/web/i18n/sl-SI/plugin.ts @@ -87,6 +87,16 @@ const translation = { endpointsTip: 'Ta vtičnik zagotavlja specifične funkcionalnosti preko končnih točk, prav tako pa lahko konfigurirate več nizov končnih točk za trenutno delovno okolje.', endpointModalDesc: 'Ko je konfiguriran, se lahko uporabljajo funkcije, ki jih vtičnik zagotavlja prek API končnih točk.', endpointsEmpty: 'Kliknite gumb \' \' za dodajanje končne točke', + deprecation: { + reason: { + businessAdjustments: 'poslovne prilagoditve', + noMaintainer: 'brez vzdrževalca', + ownershipTransferred: 'lastništvo preneseno', + }, + onlyReason: 'Ta vtičnik je bil opuščen zaradi {{deprecatedReason}} in ne bo več posodobljen.', + noReason: 'Ta vtičnik je bil ukinjen in ne bo več posodabljan.', + fullMessage: 'Ta vtičnik je bil ukinjen zaradi {{deprecatedReason}}, in ne bo več posodobljen. Namesto tega uporabite {{-alternativePluginId}}.', + }, }, debugInfo: { viewDocs: 'Oglejte si dokumente', @@ -237,6 +247,7 @@ const translation = { clientInfo: 'Ker za tega ponudnika orodij niso bili najdeni klientski skrivnosti sistema, je potrebna ročna nastavitev, za redirect_uri prosimo uporabite', useApiAuthDesc: 'Po konfiguraciji poverilnic lahko vsi člani v delovnem prostoru uporabljajo to orodje pri orkestraciji aplikacij.', }, + deprecated: 'Zastaran', } export default translation diff --git a/web/i18n/th-TH/plugin.ts b/web/i18n/th-TH/plugin.ts index de1201396d..b152f5848f 100644 --- a/web/i18n/th-TH/plugin.ts +++ b/web/i18n/th-TH/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointsTip: 'ปลั๊กอินนี้มีฟังก์ชันเฉพาะผ่านปลายทาง และคุณสามารถกําหนดค่าชุดปลายทางหลายชุดสําหรับพื้นที่ทํางานปัจจุบันได้', endpointsEmpty: 'คลิกปุ่ม \'+\' เพื่อเพิ่มปลายทาง', serviceOk: 'บริการตกลง', + deprecation: { + reason: { + ownershipTransferred: 'การโอนความเป็นเจ้าของ', + businessAdjustments: 'การปรับเปลี่ยนธุรกิจ', + noMaintainer: 'ไม่มีผู้ดูแล', + }, + onlyReason: 'ปลั๊กอินนี้ถูกเลิกใช้เนื่องจาก {{deprecatedReason}} และจะไม่มีการอัปเดตอีกต่อไป.', + noReason: 'ปลั๊กอินนี้ได้ถูกยกเลิกใช้งานและจะไม่มีการอัปเดตอีกต่อไป.', + fullMessage: 'ปลั๊กอินนี้ถูกยกเลิกการใช้งานเนื่องจาก {{เหตุผลที่ถูกยกเลิก}} และจะไม่มีการอัปเดตอีกต่อไป กรุณาใช้ {{-alternativePluginId}} แทน.', + }, }, debugInfo: { viewDocs: 'ดูเอกสาร', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'หลังจากตั้งค่าข้อมูลประจำตัวแล้ว สมาชิกทุกคนภายในพื้นที่ทำงานสามารถใช้เครื่องมือนี้เมื่อจัดการแอปพลิเคชันได้', clientInfo: 'เนื่องจากไม่พบความลับของลูกค้าสำหรับผู้ให้บริการเครื่องมือนี้ จำเป็นต้องตั้งค่าแบบแมนนวล สำหรับ redirect_uri กรุณาใช้', }, + deprecated: 'เลิกใช้', } export default translation diff --git a/web/i18n/tr-TR/plugin.ts b/web/i18n/tr-TR/plugin.ts index 80237131e7..40799328e6 100644 --- a/web/i18n/tr-TR/plugin.ts +++ b/web/i18n/tr-TR/plugin.ts @@ -84,6 +84,16 @@ const translation = { modelNum: '{{sayı}} DAHİL OLAN MODELLER', endpointDisableTip: 'Uç Noktayı Devre Dışı Bırak', serviceOk: 'Servis Tamam', + deprecation: { + reason: { + noMaintainer: 'bakımcı yok', + ownershipTransferred: 'mülkiyet devredildi', + businessAdjustments: 'iş ayarlamaları', + }, + noReason: 'Bu eklenti kullanımdan kaldırıldı ve artık güncellenmeyecek.', + onlyReason: 'Bu eklenti {{deprecatedReason}} nedeniyle kullanımdan kaldırılmıştır ve artık güncellenmeyecektir.', + fullMessage: 'Bu eklenti {{deprecatedReason}} nedeniyle kullanım dışı bırakılmıştır ve artık güncellenmeyecek. Lütfen bunun yerine {{-alternativePluginId}}\'i kullanın.', + }, }, debugInfo: { title: 'Hata ayıklama', @@ -237,6 +247,7 @@ const translation = { saveAndAuth: 'Kaydet ve Yetkilendir', clientInfo: 'Bu araç sağlayıcı için sistem istemci gizlilikleri bulunmadığından, manuel olarak ayar yapılması gerekmektedir. redirect_uri için lütfen şu adresi kullanın', }, + deprecated: 'Kaldırılmış', } export default translation diff --git a/web/i18n/uk-UA/plugin.ts b/web/i18n/uk-UA/plugin.ts index 7273f1174e..76c717cd47 100644 --- a/web/i18n/uk-UA/plugin.ts +++ b/web/i18n/uk-UA/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointModalDesc: 'Після налаштування можна використовувати функції, що надаються плагіном через кінцеві точки API.', configureTool: 'Інструмент налаштування', serviceOk: 'Сервіс працює', + deprecation: { + reason: { + ownershipTransferred: 'право власності передано', + businessAdjustments: 'бізнесові корективи', + noMaintainer: 'немає супроводжувача', + }, + noReason: 'Цей плагін було застаріло, і він більше не буде оновлюватися.', + onlyReason: 'Цей плагін було знято з підтримки через {{deprecatedReason}} і більше не буде оновлюватися.', + fullMessage: 'Цей плагін був застарілий через {{deprecatedReason}}, і більше не буде оновлюватися. Будь ласка, використовуйте {{-alternativePluginId}} замість цього.', + }, }, debugInfo: { title: 'Налагодження', @@ -237,6 +247,7 @@ const translation = { clientInfo: 'Оскільки не знайдено жодних секретів клієнта системи для цього постачальника інструментів, потрібно налаштувати його вручну; для redirect_uri, будь ласка, використовуйте', useApiAuthDesc: 'Після налаштування облікових даних усі учасники робочого простору можуть використовувати цей інструмент під час оркестрації додатків.', }, + deprecated: 'Застарілий', } export default translation diff --git a/web/i18n/vi-VN/plugin.ts b/web/i18n/vi-VN/plugin.ts index 143cd71a66..9760eafd0c 100644 --- a/web/i18n/vi-VN/plugin.ts +++ b/web/i18n/vi-VN/plugin.ts @@ -84,6 +84,16 @@ const translation = { endpointDeleteContent: 'Bạn có muốn xóa {{name}} không?', endpointModalTitle: 'Điểm cuối thiết lập', disabled: 'Tàn tật', + deprecation: { + reason: { + noMaintainer: 'không có người bảo trì', + ownershipTransferred: 'quyền sở hữu được chuyển nhượng', + businessAdjustments: 'điều chỉnh kinh doanh', + }, + noReason: 'Plugin này đã bị loại bỏ và sẽ không còn được cập nhật.', + onlyReason: 'Plugin này đã bị ngừng hỗ trợ do {{deprecatedReason}} và sẽ không còn được cập nhật nữa.', + fullMessage: 'Plugin này đã bị ngừng sử dụng do {{deprecatedReason}}, và sẽ không còn được cập nhật nữa. Vui lòng sử dụng {{-alternativePluginId}} thay thế.', + }, }, debugInfo: { title: 'Gỡ lỗi', @@ -237,6 +247,7 @@ const translation = { useApiAuthDesc: 'Sau khi cấu hình thông tin xác thực, tất cả các thành viên trong không gian làm việc có thể sử dụng công cụ này khi điều phối các ứng dụng.', clientInfo: 'Vì không tìm thấy bí mật khách hàng hệ thống cho nhà cung cấp công cụ này, cần thiết lập thủ công, đối với redirect_uri, vui lòng sử dụng', }, + deprecated: 'Đã bị ngưng sử dụng', } export default translation diff --git a/web/i18n/zh-Hant/plugin.ts b/web/i18n/zh-Hant/plugin.ts index 938c754394..24b0ef997e 100644 --- a/web/i18n/zh-Hant/plugin.ts +++ b/web/i18n/zh-Hant/plugin.ts @@ -84,6 +84,16 @@ const translation = { configureModel: '配置模型', endpointModalTitle: '設置終端節點', endpointsDocLink: '查看文件', + deprecation: { + reason: { + businessAdjustments: '業務調整', + ownershipTransferred: '所有權轉移', + noMaintainer: '沒有維護者', + }, + noReason: '此插件已被廢棄,將不再進行更新。', + onlyReason: '此插件因為 {{deprecatedReason}} 而被棄用,將不再更新。', + fullMessage: '由於 {{deprecatedReason}},此插件已被棄用,將不再更新。請改用 {{-alternativePluginId}}。', + }, }, debugInfo: { viewDocs: '查看文件', @@ -237,6 +247,7 @@ const translation = { clientInfo: '由於未找到此工具提供者的系統客戶端秘密,因此需要手動設置,對於 redirect_uri,請使用', useApiAuthDesc: '配置完憑證後,工作區內的所有成員在協調應用程式時都可以使用此工具。', }, + deprecated: '不推薦使用的', } export default translation