Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>tags/1.7.0
| @@ -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: | |||
| @@ -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: | |||
| @@ -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 | |||
| @@ -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, | |||
| @@ -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({}) | |||
| @@ -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 | |||
| @@ -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 {} | |||
| @@ -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) | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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 = ( | |||
| @@ -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 = { | |||
| @@ -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, | |||
| @@ -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() | |||
| @@ -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, | |||
| ) | |||
| ) | |||
| @@ -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 | |||
| @@ -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`. | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (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:<br/> | |||
| - Header: via HTTP Header <code>X-Trace-Id</code>, highest priority.<br/> | |||
| - Query parameter: via URL query parameter <code>trace_id</code>.<br/> | |||
| - Request Body: via request body field <code>trace_id</code> (i.e., this field).<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### Response | |||
| @@ -80,6 +80,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| タイトルを自動生成、デフォルトは`true`。 | |||
| `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。 | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:<br/> | |||
| - Header:HTTPヘッダー <code>X-Trace-Id</code> で渡す(最優先)。<br/> | |||
| - クエリパラメータ:URLクエリパラメータ <code>trace_id</code> で渡す。<br/> | |||
| - リクエストボディ:リクエストボディの <code>trace_id</code> フィールドで渡す(本フィールド)。<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### 応答 | |||
| @@ -78,6 +78,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| <Property name='auto_generate_name' type='bool' key='auto_generate_name'> | |||
| (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成<code>trace_id</code>。支持以下三种方式传递,具体优先级依次为:<br/> | |||
| - Header:通过 HTTP Header <code>X-Trace-Id</code> 传递,优先级最高。<br/> | |||
| - Query 参数:通过 URL 查询参数 <code>trace_id</code> 传递。<br/> | |||
| - Request Body:通过请求体字段 <code>trace_id</code> 传递(即本字段)。<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### Response | |||
| @@ -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`. | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (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:<br/> | |||
| - Header: via HTTP Header <code>X-Trace-Id</code>, highest priority.<br/> | |||
| - Query parameter: via URL query parameter <code>trace_id</code>.<br/> | |||
| - Request Body: via request body field <code>trace_id</code> (i.e., this field).<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### Response | |||
| @@ -74,6 +74,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| タイトルを自動生成します。デフォルトは`true`です。 | |||
| `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。 | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:<br/> | |||
| - Header:HTTPヘッダー <code>X-Trace-Id</code> で渡す(最優先)。<br/> | |||
| - クエリパラメータ:URLクエリパラメータ <code>trace_id</code> で渡す。<br/> | |||
| - リクエストボディ:リクエストボディの <code>trace_id</code> フィールドで渡す(本フィールド)。<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### 応答 | |||
| @@ -73,6 +73,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| <Property name='auto_generate_name' type='bool' key='auto_generate_name'> | |||
| (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 | |||
| </Property> | |||
| <Property name='trace_id' type='string' key='trace_id'> | |||
| (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成<code>trace_id</code>。支持以下三种方式传递,具体优先级依次为:<br/> | |||
| - Header:通过 HTTP Header <code>X-Trace-Id</code> 传递,优先级最高。<br/> | |||
| - Query 参数:通过 URL 查询参数 <code>trace_id</code> 传递。<br/> | |||
| - Request Body:通过请求体字段 <code>trace_id</code> 传递(即本字段)。<br/> | |||
| </Property> | |||
| </Properties> | |||
| ### Response | |||
| @@ -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. | |||
| <br/> | |||
| <i>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.</i> | |||
| - `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. | |||
| @@ -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` フィールドで渡す(本フィールド)。 | |||
| ### 応答 | |||
| @@ -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。 | |||