mirror of
https://github.com/langgenius/dify.git
synced 2026-06-26 06:41:10 +08:00
Merge c3bb3bf702 into a246dc8b17
This commit is contained in:
commit
8d7eaa4129
@ -167,12 +167,16 @@ register_schema_models(
|
||||
ChatMessagesQuery,
|
||||
MessageFeedbackPayload,
|
||||
FeedbackExportQuery,
|
||||
)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
AnnotationCountResponse,
|
||||
SuggestedQuestionsResponse,
|
||||
MessageDetailResponse,
|
||||
MessageInfiniteScrollPaginationResponse,
|
||||
SimpleResultResponse,
|
||||
TextFileResponse,
|
||||
)
|
||||
register_response_schema_models(console_ns, SimpleResultResponse, TextFileResponse)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/chat-messages")
|
||||
|
||||
@ -12,8 +12,13 @@ from controllers.service_api import service_api_ns
|
||||
from controllers.service_api.wraps import validate_app_token
|
||||
from extensions.ext_database import db
|
||||
from extensions.ext_redis import redis_client
|
||||
from fields.annotation_fields import Annotation, AnnotationList
|
||||
from fields.base import ResponseModel
|
||||
from fields.annotation_fields import (
|
||||
Annotation,
|
||||
AnnotationJobStatusDetailResponse,
|
||||
AnnotationJobStatusResponse,
|
||||
AnnotationList,
|
||||
)
|
||||
from libs.helper import dump_response
|
||||
from models.model import App
|
||||
from services.annotation_service import (
|
||||
AppAnnotationService,
|
||||
@ -45,12 +50,6 @@ class AnnotationListQuery(BaseModel):
|
||||
keyword: str = Field(default="", description="Keyword to filter annotations by question or answer content.")
|
||||
|
||||
|
||||
class AnnotationJobStatusResponse(ResponseModel):
|
||||
job_id: str
|
||||
job_status: str
|
||||
error_msg: str | None = None
|
||||
|
||||
|
||||
ANNOTATION_REPLY_ACTION_PARAM = {
|
||||
"description": "Action to perform: `enable` or `disable`.",
|
||||
"enum": ["enable", "disable"],
|
||||
@ -66,7 +65,13 @@ register_schema_models(
|
||||
Annotation,
|
||||
AnnotationList,
|
||||
)
|
||||
register_response_schema_models(service_api_ns, AnnotationJobStatusResponse)
|
||||
register_response_schema_models(
|
||||
service_api_ns,
|
||||
Annotation,
|
||||
AnnotationList,
|
||||
AnnotationJobStatusResponse,
|
||||
AnnotationJobStatusDetailResponse,
|
||||
)
|
||||
|
||||
|
||||
@service_api_ns.route("/apps/annotation-reply/<string:action>")
|
||||
@ -112,7 +117,7 @@ class AnnotationReplyActionApi(Resource):
|
||||
result = AppAnnotationService.enable_app_annotation(enable_args, app_model.id)
|
||||
case "disable":
|
||||
result = AppAnnotationService.disable_app_annotation(app_model.id)
|
||||
return result, 200
|
||||
return dump_response(AnnotationJobStatusResponse, result), 200
|
||||
|
||||
|
||||
@service_api_ns.route("/apps/annotation-reply/<string:action>/status/<uuid:job_id>")
|
||||
@ -150,7 +155,7 @@ class AnnotationReplyActionStatusApi(Resource):
|
||||
@service_api_ns.response(
|
||||
200,
|
||||
"Job status retrieved successfully",
|
||||
service_api_ns.models[AnnotationJobStatusResponse.__name__],
|
||||
service_api_ns.models[AnnotationJobStatusDetailResponse.__name__],
|
||||
)
|
||||
@validate_app_token
|
||||
def get(self, app_model: App, job_id: UUID, action: str):
|
||||
@ -167,7 +172,9 @@ class AnnotationReplyActionStatusApi(Resource):
|
||||
app_annotation_error_key = f"{action}_app_annotation_error_{job_id_str}"
|
||||
error_msg = redis_client.get(app_annotation_error_key).decode()
|
||||
|
||||
return {"job_id": job_id_str, "job_status": job_status, "error_msg": error_msg}, 200
|
||||
return AnnotationJobStatusDetailResponse(
|
||||
job_id=job_id_str, job_status=job_status, error_msg=error_msg
|
||||
).model_dump(mode="json"), 200
|
||||
|
||||
|
||||
@service_api_ns.route("/apps/annotations")
|
||||
@ -203,14 +210,13 @@ class AnnotationListApi(Resource):
|
||||
app_model.id, query.page, query.limit, query.keyword
|
||||
)
|
||||
annotation_models = TypeAdapter(list[Annotation]).validate_python(annotation_list, from_attributes=True)
|
||||
response = AnnotationList(
|
||||
return AnnotationList(
|
||||
data=annotation_models,
|
||||
has_more=len(annotation_list) == query.limit,
|
||||
limit=query.limit,
|
||||
total=total,
|
||||
page=query.page,
|
||||
)
|
||||
return response.model_dump(mode="json")
|
||||
).model_dump(mode="json")
|
||||
|
||||
@service_api_ns.doc(
|
||||
summary="Create Annotation",
|
||||
@ -243,8 +249,7 @@ class AnnotationListApi(Resource):
|
||||
payload = AnnotationCreatePayload.model_validate(service_api_ns.payload or {})
|
||||
insert_args: InsertAnnotationArgs = {"question": payload.question, "answer": payload.answer}
|
||||
annotation = AppAnnotationService.insert_app_annotation_directly(insert_args, app_model.id)
|
||||
response = Annotation.model_validate(annotation, from_attributes=True)
|
||||
return response.model_dump(mode="json"), HTTPStatus.CREATED
|
||||
return dump_response(Annotation, annotation), HTTPStatus.CREATED
|
||||
|
||||
|
||||
@service_api_ns.route("/apps/annotations/<uuid:annotation_id>")
|
||||
@ -285,8 +290,7 @@ class AnnotationUpdateDeleteApi(Resource):
|
||||
annotation = AppAnnotationService.update_app_annotation_directly(
|
||||
update_args, app_model.id, str(annotation_id), db.session
|
||||
)
|
||||
response = Annotation.model_validate(annotation, from_attributes=True)
|
||||
return response.model_dump(mode="json")
|
||||
return dump_response(Annotation, annotation)
|
||||
|
||||
@service_api_ns.doc(
|
||||
summary="Delete Annotation",
|
||||
|
||||
@ -25,6 +25,7 @@ from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate
|
||||
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
|
||||
from extensions.ext_database import db
|
||||
from graphon.model_runtime.errors.invoke import InvokeError
|
||||
from libs.helper import dump_response
|
||||
from models.model import App, EndUser
|
||||
from services.audio_service import AudioService
|
||||
from services.errors.audio import (
|
||||
@ -101,7 +102,7 @@ class AudioApi(Resource):
|
||||
try:
|
||||
response = AudioService.transcript_asr(app_model=app_model, file=file, end_user=end_user.id)
|
||||
|
||||
return response
|
||||
return dump_response(AudioTranscriptResponse, response)
|
||||
except services.errors.app_model_config.AppModelConfigBrokenError:
|
||||
logger.exception("App model config broken.")
|
||||
raise AppUnavailableError()
|
||||
@ -164,6 +165,7 @@ class TextApi(Resource):
|
||||
500: "Internal server error",
|
||||
}
|
||||
)
|
||||
# TTS returns provider audio bytes, so the success response is intentionally schema-less.
|
||||
@service_api_ns.response(200, "Text successfully converted to audio")
|
||||
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON))
|
||||
def post(self, app_model: App, end_user: EndUser):
|
||||
@ -177,7 +179,7 @@ class TextApi(Resource):
|
||||
message_id = payload.message_id
|
||||
text = payload.text
|
||||
voice = payload.voice
|
||||
response = AudioService.transcript_tts(
|
||||
return AudioService.transcript_tts(
|
||||
app_model=app_model,
|
||||
session=db.session,
|
||||
text=text,
|
||||
@ -185,8 +187,6 @@ class TextApi(Resource):
|
||||
end_user=end_user.external_user_id,
|
||||
message_id=message_id,
|
||||
)
|
||||
|
||||
return response
|
||||
except services.errors.app_model_config.AppModelConfigBrokenError:
|
||||
logger.exception("App model config broken.")
|
||||
raise AppUnavailableError()
|
||||
|
||||
@ -9,7 +9,7 @@ from pydantic.json_schema import SkipJsonSchema
|
||||
from werkzeug.exceptions import BadRequest, InternalServerError, NotFound
|
||||
|
||||
import services
|
||||
from controllers.common.fields import GeneratedAppResponse, SimpleResultResponse
|
||||
from controllers.common.fields import SimpleResultResponse
|
||||
from controllers.common.schema import register_response_schema_models, register_schema_models
|
||||
from controllers.service_api import service_api_ns
|
||||
from controllers.service_api.app.error import (
|
||||
@ -154,7 +154,7 @@ class ChatRequestPayload(BaseModel):
|
||||
|
||||
|
||||
register_schema_models(service_api_ns, CompletionRequestPayload, ChatRequestPayload)
|
||||
register_response_schema_models(service_api_ns, GeneratedAppResponse, SimpleResultResponse)
|
||||
register_response_schema_models(service_api_ns, SimpleResultResponse)
|
||||
|
||||
|
||||
@service_api_ns.route("/completion-messages")
|
||||
@ -197,11 +197,7 @@ class CompletionApi(Resource):
|
||||
500: "Internal server error",
|
||||
}
|
||||
)
|
||||
@service_api_ns.response(
|
||||
200,
|
||||
"Completion created successfully",
|
||||
service_api_ns.models[GeneratedAppResponse.__name__],
|
||||
)
|
||||
@service_api_ns.response(200, "Completion created successfully")
|
||||
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
|
||||
def post(self, app_model: App, end_user: EndUser):
|
||||
"""Create a completion for the given prompt.
|
||||
@ -236,6 +232,7 @@ class CompletionApi(Resource):
|
||||
streaming=streaming,
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
@ -296,7 +293,7 @@ class CompletionStopApi(Resource):
|
||||
app_mode=AppMode.value_of(app_model.mode),
|
||||
)
|
||||
|
||||
return {"result": "success"}, 200
|
||||
return SimpleResultResponse(result="success").model_dump(mode="json"), 200
|
||||
|
||||
|
||||
@service_api_ns.route("/chat-messages")
|
||||
@ -346,11 +343,7 @@ class ChatApi(Resource):
|
||||
500: "Internal server error",
|
||||
}
|
||||
)
|
||||
@service_api_ns.response(
|
||||
200,
|
||||
"Message sent successfully",
|
||||
service_api_ns.models[GeneratedAppResponse.__name__],
|
||||
)
|
||||
@service_api_ns.response(200, "Message sent successfully")
|
||||
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
|
||||
def post(self, app_model: App, end_user: EndUser):
|
||||
"""Send a message in a chat conversation.
|
||||
@ -379,6 +372,7 @@ class ChatApi(Resource):
|
||||
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except WorkflowNotFoundError as ex:
|
||||
raise NotFound(str(ex))
|
||||
@ -448,4 +442,4 @@ class ChatStopApi(Resource):
|
||||
app_mode=app_mode,
|
||||
)
|
||||
|
||||
return {"result": "success"}, 200
|
||||
return SimpleResultResponse(result="success").model_dump(mode="json"), 200
|
||||
|
||||
@ -24,7 +24,7 @@ from fields.conversation_fields import (
|
||||
SimpleConversation,
|
||||
)
|
||||
from graphon.variables.types import SegmentType
|
||||
from libs.helper import UUIDStrOrEmpty, to_timestamp
|
||||
from libs.helper import UUIDStrOrEmpty, dump_response, to_timestamp
|
||||
from models.model import App, AppMode, EndUser
|
||||
from services.conversation_service import ConversationService
|
||||
|
||||
@ -142,15 +142,13 @@ register_schema_models(
|
||||
ConversationRenamePayload,
|
||||
ConversationVariablesQuery,
|
||||
ConversationVariableUpdatePayload,
|
||||
ConversationVariableResponse,
|
||||
ConversationVariableInfiniteScrollPaginationResponse,
|
||||
)
|
||||
register_response_schema_models(
|
||||
service_api_ns,
|
||||
ConversationInfiniteScrollPagination,
|
||||
SimpleConversation,
|
||||
ConversationVariableResponse,
|
||||
ConversationVariableInfiniteScrollPaginationResponse,
|
||||
ConversationInfiniteScrollPagination,
|
||||
SimpleConversation,
|
||||
)
|
||||
|
||||
|
||||
@ -166,9 +164,9 @@ class ConversationApi(Resource):
|
||||
404: "`not_found` : Last conversation does not exist (invalid `last_id`).",
|
||||
},
|
||||
)
|
||||
@service_api_ns.doc(params=query_params_from_model(ConversationListQuery))
|
||||
@service_api_ns.doc("list_conversations")
|
||||
@service_api_ns.doc(description="List all conversations for the current user")
|
||||
@service_api_ns.doc(params=query_params_from_model(ConversationListQuery))
|
||||
@service_api_ns.doc(
|
||||
responses={
|
||||
200: "Conversations retrieved successfully",
|
||||
@ -192,7 +190,7 @@ class ConversationApi(Resource):
|
||||
raise NotChatAppError()
|
||||
|
||||
query_args = ConversationListQuery.model_validate(request.args.to_dict())
|
||||
last_id = str(query_args.last_id) if query_args.last_id else None
|
||||
last_id = query_args.last_id or None
|
||||
|
||||
try:
|
||||
with sessionmaker(db.engine).begin() as session:
|
||||
@ -208,9 +206,7 @@ class ConversationApi(Resource):
|
||||
adapter = TypeAdapter(SimpleConversation)
|
||||
conversations = [adapter.validate_python(item, from_attributes=True) for item in pagination.data]
|
||||
return ConversationInfiniteScrollPagination(
|
||||
limit=pagination.limit,
|
||||
has_more=pagination.has_more,
|
||||
data=conversations,
|
||||
limit=pagination.limit, has_more=pagination.has_more, data=conversations
|
||||
).model_dump(mode="json")
|
||||
except services.errors.conversation.LastConversationNotExistsError:
|
||||
raise NotFound("Last Conversation Not Exists.")
|
||||
@ -301,11 +297,7 @@ class ConversationRenameApi(Resource):
|
||||
conversation = ConversationService.rename(
|
||||
app_model, conversation_id, end_user, payload.name, payload.auto_generate
|
||||
)
|
||||
return (
|
||||
TypeAdapter(SimpleConversation)
|
||||
.validate_python(conversation, from_attributes=True)
|
||||
.model_dump(mode="json")
|
||||
)
|
||||
return dump_response(SimpleConversation, conversation)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
|
||||
@ -322,10 +314,9 @@ class ConversationVariablesApi(Resource):
|
||||
404: "`not_found` : Conversation does not exist.",
|
||||
},
|
||||
)
|
||||
@service_api_ns.doc(params=query_params_from_model(ConversationVariablesQuery))
|
||||
@service_api_ns.doc("list_conversation_variables")
|
||||
@service_api_ns.doc(description="List all variables for a conversation")
|
||||
@service_api_ns.doc(params={"c_id": "Conversation ID."})
|
||||
@service_api_ns.doc(params={"c_id": "Conversation ID.", **query_params_from_model(ConversationVariablesQuery)})
|
||||
@service_api_ns.doc(
|
||||
responses={
|
||||
200: "Variables retrieved successfully",
|
||||
@ -352,15 +343,13 @@ class ConversationVariablesApi(Resource):
|
||||
conversation_id = str(c_id)
|
||||
|
||||
query_args = ConversationVariablesQuery.model_validate(request.args.to_dict())
|
||||
last_id = str(query_args.last_id) if query_args.last_id else None
|
||||
last_id = query_args.last_id or None
|
||||
|
||||
try:
|
||||
pagination = ConversationService.get_conversational_variable(
|
||||
app_model, conversation_id, end_user, query_args.limit, last_id, query_args.variable_name
|
||||
)
|
||||
return ConversationVariableInfiniteScrollPaginationResponse.model_validate(
|
||||
pagination, from_attributes=True
|
||||
).model_dump(mode="json")
|
||||
return dump_response(ConversationVariableInfiniteScrollPaginationResponse, pagination)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
|
||||
@ -419,7 +408,7 @@ class ConversationVariableDetailApi(Resource):
|
||||
variable = ConversationService.update_conversation_variable(
|
||||
app_model, conversation_id, variable_id_str, end_user, payload.value
|
||||
)
|
||||
return ConversationVariableResponse.model_validate(variable, from_attributes=True).model_dump(mode="json")
|
||||
return dump_response(ConversationVariableResponse, variable)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
except services.errors.conversation.ConversationVariableNotExistsError:
|
||||
|
||||
@ -16,6 +16,7 @@ from controllers.service_api.schema import multipart_file_params
|
||||
from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token
|
||||
from extensions.ext_database import db
|
||||
from fields.file_fields import FileResponse
|
||||
from libs.helper import dump_response
|
||||
from models import App, EndUser
|
||||
from services.file_service import FileService
|
||||
|
||||
@ -87,5 +88,4 @@ class FileApi(Resource):
|
||||
except services.errors.file.UnsupportedFileTypeError:
|
||||
raise UnsupportedFileTypeError()
|
||||
|
||||
response = FileResponse.model_validate(upload_file, from_attributes=True)
|
||||
return response.model_dump(mode="json"), 201
|
||||
return dump_response(FileResponse, upload_file), 201
|
||||
|
||||
@ -59,12 +59,14 @@ register_response_schema_models(
|
||||
ResultResponse,
|
||||
SimpleResultStringListResponse,
|
||||
MessageInfiniteScrollPagination,
|
||||
MessageListItem,
|
||||
AppFeedbackListResponse,
|
||||
)
|
||||
|
||||
|
||||
@service_api_ns.route("/messages")
|
||||
class MessageListApi(Resource):
|
||||
@service_api_ns.doc("list_messages")
|
||||
@service_api_ns.doc(
|
||||
summary="List Conversation Messages",
|
||||
description=(
|
||||
@ -75,15 +77,15 @@ class MessageListApi(Resource):
|
||||
responses={
|
||||
200: "Successfully retrieved conversation history.",
|
||||
400: "`not_chat_app` : App mode does not match the API route.",
|
||||
404: ("- `not_found` : Conversation does not exist.\n- `not_found` : First message does not exist."),
|
||||
404: "- `not_found` : Conversation does not exist.\n- `not_found` : First message does not exist.",
|
||||
},
|
||||
)
|
||||
@service_api_ns.doc(params=query_params_from_model(MessageListQuery))
|
||||
@service_api_ns.doc("list_messages")
|
||||
@service_api_ns.doc(description="List messages in a conversation")
|
||||
@service_api_ns.doc(
|
||||
responses={
|
||||
200: "Messages retrieved successfully",
|
||||
400: "`not_chat_app` : App mode does not match the API route.",
|
||||
401: "Unauthorized - invalid API token",
|
||||
404: "Conversation or first message not found",
|
||||
}
|
||||
@ -104,8 +106,8 @@ class MessageListApi(Resource):
|
||||
raise NotChatAppError()
|
||||
|
||||
query_args = MessageListQuery.model_validate(request.args.to_dict())
|
||||
conversation_id = str(query_args.conversation_id)
|
||||
first_id = str(query_args.first_id) if query_args.first_id else None
|
||||
conversation_id = query_args.conversation_id
|
||||
first_id = query_args.first_id or None
|
||||
|
||||
try:
|
||||
pagination = MessageService.pagination_by_first_id(
|
||||
@ -114,9 +116,7 @@ class MessageListApi(Resource):
|
||||
adapter = TypeAdapter(MessageListItem)
|
||||
items = [adapter.validate_python(message, from_attributes=True) for message in pagination.data]
|
||||
return MessageInfiniteScrollPagination(
|
||||
limit=pagination.limit,
|
||||
has_more=pagination.has_more,
|
||||
data=items,
|
||||
limit=pagination.limit, has_more=pagination.has_more, data=items
|
||||
).model_dump(mode="json")
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
@ -126,21 +126,20 @@ class MessageListApi(Resource):
|
||||
|
||||
@service_api_ns.route("/messages/<uuid:message_id>/feedbacks")
|
||||
class MessageFeedbackApi(Resource):
|
||||
@expect_with_user(service_api_ns, MessageFeedbackPayload)
|
||||
@service_api_ns.response(200, "Feedback submitted successfully", service_api_ns.models[ResultResponse.__name__])
|
||||
@service_api_ns.doc("create_message_feedback")
|
||||
@service_api_ns.doc(
|
||||
summary="Submit Message Feedback",
|
||||
description=(
|
||||
"Submit feedback for a message. End users can rate messages as `like` or `dislike`, and "
|
||||
"optionally provide text feedback. Pass `null` for `rating` to revoke previously submitted "
|
||||
"feedback."
|
||||
"optionally provide text feedback. Pass `null` for `rating` to revoke previously submitted feedback."
|
||||
),
|
||||
tags=["Feedback"],
|
||||
responses={
|
||||
404: "`not_found` : Message does not exist.",
|
||||
},
|
||||
)
|
||||
@expect_with_user(service_api_ns, MessageFeedbackPayload)
|
||||
@service_api_ns.response(200, "Feedback submitted successfully", service_api_ns.models[ResultResponse.__name__])
|
||||
@service_api_ns.doc("create_message_feedback")
|
||||
@service_api_ns.doc(description="Submit feedback for a message")
|
||||
@service_api_ns.doc(params={"message_id": "Message ID."})
|
||||
@service_api_ns.doc(
|
||||
@ -176,11 +175,12 @@ class MessageFeedbackApi(Resource):
|
||||
|
||||
@service_api_ns.route("/app/feedbacks")
|
||||
class AppGetFeedbacksApi(Resource):
|
||||
@service_api_ns.doc("get_app_feedbacks")
|
||||
@service_api_ns.doc(
|
||||
summary="List App Feedbacks",
|
||||
description=(
|
||||
"Retrieve a paginated list of all feedback submitted for messages in this application, "
|
||||
"including both end-user and admin feedback."
|
||||
"Retrieve a paginated list of all feedback submitted for messages in this application, including both "
|
||||
"end-user and admin feedback."
|
||||
),
|
||||
tags=["Feedback"],
|
||||
responses={
|
||||
@ -188,7 +188,6 @@ class AppGetFeedbacksApi(Resource):
|
||||
},
|
||||
)
|
||||
@service_api_ns.doc(params=query_params_from_model(FeedbackListQuery))
|
||||
@service_api_ns.doc("get_app_feedbacks")
|
||||
@service_api_ns.doc(description="Get all feedbacks for the application")
|
||||
@service_api_ns.doc(
|
||||
responses={
|
||||
@ -209,11 +208,12 @@ class AppGetFeedbacksApi(Resource):
|
||||
"""
|
||||
query_args = FeedbackListQuery.model_validate(request.args.to_dict())
|
||||
feedbacks = MessageService.get_all_messages_feedbacks(app_model, page=query_args.page, limit=query_args.limit)
|
||||
return {"data": feedbacks}
|
||||
return AppFeedbackListResponse(data=feedbacks).model_dump(mode="json")
|
||||
|
||||
|
||||
@service_api_ns.route("/messages/<uuid:message_id>/suggested")
|
||||
class MessageSuggestedApi(Resource):
|
||||
@service_api_ns.doc("get_suggested_questions")
|
||||
@service_api_ns.doc(
|
||||
summary="Get Next Suggested Questions",
|
||||
description="Get next questions suggestions for the current message.",
|
||||
@ -233,7 +233,6 @@ class MessageSuggestedApi(Resource):
|
||||
"Suggested questions retrieved successfully",
|
||||
service_api_ns.models[SimpleResultStringListResponse.__name__],
|
||||
)
|
||||
@service_api_ns.doc("get_suggested_questions")
|
||||
@service_api_ns.doc(description="Get suggested follow-up questions for a message")
|
||||
@service_api_ns.doc(params={"message_id": "Message ID"})
|
||||
@service_api_ns.doc(
|
||||
@ -268,4 +267,4 @@ class MessageSuggestedApi(Resource):
|
||||
logger.exception("internal server error.")
|
||||
raise InternalServerError()
|
||||
|
||||
return {"result": "success", "data": questions}
|
||||
return SimpleResultStringListResponse(result="success", data=questions).model_dump(mode="json")
|
||||
|
||||
@ -1,19 +1,24 @@
|
||||
import logging
|
||||
from collections.abc import Mapping
|
||||
from datetime import datetime
|
||||
from typing import Literal, override
|
||||
from typing import Literal
|
||||
|
||||
from dateutil.parser import isoparse
|
||||
from flask import request
|
||||
from flask_restx import Resource, fields
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from flask_restx import Resource
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
from pydantic.json_schema import SkipJsonSchema
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from werkzeug.exceptions import BadRequest, InternalServerError, NotFound
|
||||
|
||||
from controllers.common.controller_schemas import WorkflowRunPayload as WorkflowRunPayloadBase
|
||||
from controllers.common.fields import GeneratedAppResponse, SimpleResultResponse
|
||||
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
|
||||
from controllers.common.fields import SimpleResultResponse
|
||||
from controllers.common.schema import (
|
||||
query_params_from_model,
|
||||
query_params_from_request,
|
||||
register_response_schema_models,
|
||||
register_schema_models,
|
||||
)
|
||||
from controllers.service_api import service_api_ns
|
||||
from controllers.service_api.app.error import (
|
||||
CompletionRequestError,
|
||||
@ -41,14 +46,13 @@ from extensions.ext_database import db
|
||||
from extensions.ext_redis import redis_client
|
||||
from fields.base import ResponseModel
|
||||
from fields.end_user_fields import SimpleEndUser
|
||||
from fields.member_fields import SimpleAccount
|
||||
from fields.member_fields import SimpleAccountResponse
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from graphon.graph_engine.manager import GraphEngineManager
|
||||
from graphon.model_runtime.errors.invoke import InvokeError
|
||||
from libs import helper
|
||||
from libs.helper import to_timestamp
|
||||
from libs.helper import dump_response, to_timestamp
|
||||
from models.model import App, AppMode, EndUser
|
||||
from models.workflow import WorkflowRun
|
||||
from repositories.factory import DifyAPIRepositoryFactory
|
||||
from services.app_generate_service import AppGenerateService
|
||||
from services.errors.app import IsDraftWorkflowError, WorkflowIdFormatError, WorkflowNotFoundError
|
||||
@ -97,36 +101,19 @@ class WorkflowLogQuery(BaseModel):
|
||||
|
||||
|
||||
register_schema_models(service_api_ns, WorkflowRunPayload, WorkflowLogQuery)
|
||||
register_response_schema_models(service_api_ns, GeneratedAppResponse, SimpleResultResponse)
|
||||
register_response_schema_models(service_api_ns, SimpleResultResponse)
|
||||
|
||||
|
||||
def _enum_value(value):
|
||||
return getattr(value, "value", value)
|
||||
|
||||
|
||||
class WorkflowRunStatusField(fields.Raw):
|
||||
@override
|
||||
def output(self, key, obj: WorkflowRun, **kwargs):
|
||||
return _enum_value(obj.status)
|
||||
|
||||
|
||||
class WorkflowRunOutputsField(fields.Raw):
|
||||
@override
|
||||
def output(self, key, obj: WorkflowRun, **kwargs):
|
||||
status = _enum_value(obj.status)
|
||||
if status == WorkflowExecutionStatus.PAUSED.value:
|
||||
return {}
|
||||
|
||||
outputs = obj.outputs_dict
|
||||
return outputs or {}
|
||||
|
||||
|
||||
class WorkflowRunResponse(ResponseModel):
|
||||
id: str
|
||||
workflow_id: str
|
||||
status: str
|
||||
inputs: dict | list | str | int | float | bool | None = Field(default=None)
|
||||
outputs: dict = Field(default_factory=dict)
|
||||
outputs: dict = Field(default_factory=dict, validation_alias="outputs_dict")
|
||||
error: str | None = None
|
||||
total_steps: int | None = None
|
||||
total_tokens: int | None = None
|
||||
@ -134,11 +121,33 @@ class WorkflowRunResponse(ResponseModel):
|
||||
finished_at: int | None = None
|
||||
elapsed_time: float | int | None = None
|
||||
|
||||
@field_validator("status", mode="before")
|
||||
@classmethod
|
||||
def _normalize_enum(cls, value):
|
||||
return _enum_value(value)
|
||||
|
||||
@field_validator("outputs", mode="before")
|
||||
@classmethod
|
||||
def _normalize_outputs(cls, value):
|
||||
if value is None:
|
||||
return {}
|
||||
if isinstance(value, dict):
|
||||
return value
|
||||
if isinstance(value, Mapping):
|
||||
return dict(value)
|
||||
return {}
|
||||
|
||||
@field_validator("created_at", "finished_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _clear_paused_outputs(self):
|
||||
if self.status == WorkflowExecutionStatus.PAUSED.value:
|
||||
self.outputs = {}
|
||||
return self
|
||||
|
||||
|
||||
class WorkflowRunForLogResponse(ResponseModel):
|
||||
id: str
|
||||
@ -170,7 +179,7 @@ class WorkflowAppLogPartialResponse(ResponseModel):
|
||||
details: dict | list | str | int | float | bool | None = Field(default=None)
|
||||
created_from: str | None = None
|
||||
created_by_role: str | None = None
|
||||
created_by_account: SimpleAccount | None = None
|
||||
created_by_account: SimpleAccountResponse | None = None
|
||||
created_by_end_user: SimpleEndUser | None = None
|
||||
created_at: int | None = None
|
||||
|
||||
@ -202,39 +211,6 @@ register_response_schema_models(
|
||||
)
|
||||
|
||||
|
||||
def _serialize_workflow_run(workflow_run: WorkflowRun) -> dict:
|
||||
status = _enum_value(workflow_run.status)
|
||||
raw_outputs = workflow_run.outputs_dict
|
||||
match raw_outputs:
|
||||
case _ if status == WorkflowExecutionStatus.PAUSED.value or raw_outputs is None:
|
||||
outputs: dict = {}
|
||||
case dict():
|
||||
outputs = raw_outputs
|
||||
case _ if isinstance(raw_outputs, Mapping):
|
||||
outputs = dict(raw_outputs)
|
||||
case _:
|
||||
outputs = {}
|
||||
return WorkflowRunResponse.model_validate(
|
||||
{
|
||||
"id": workflow_run.id,
|
||||
"workflow_id": workflow_run.workflow_id,
|
||||
"status": status,
|
||||
"inputs": workflow_run.inputs,
|
||||
"outputs": outputs,
|
||||
"error": workflow_run.error,
|
||||
"total_steps": workflow_run.total_steps,
|
||||
"total_tokens": workflow_run.total_tokens,
|
||||
"created_at": workflow_run.created_at,
|
||||
"finished_at": workflow_run.finished_at,
|
||||
"elapsed_time": workflow_run.elapsed_time,
|
||||
}
|
||||
).model_dump(mode="json")
|
||||
|
||||
|
||||
def _serialize_workflow_log_pagination(pagination) -> dict:
|
||||
return WorkflowAppLogPaginationResponse.model_validate(pagination, from_attributes=True).model_dump(mode="json")
|
||||
|
||||
|
||||
@service_api_ns.route("/workflows/run/<string:workflow_run_id>")
|
||||
class WorkflowRunDetailApi(Resource):
|
||||
@service_api_ns.doc(
|
||||
@ -287,7 +263,7 @@ class WorkflowRunDetailApi(Resource):
|
||||
)
|
||||
if not workflow_run:
|
||||
raise NotFound("Workflow run not found.")
|
||||
return _serialize_workflow_run(workflow_run)
|
||||
return dump_response(WorkflowRunResponse, workflow_run)
|
||||
|
||||
|
||||
@service_api_ns.route("/workflows/run")
|
||||
@ -338,7 +314,6 @@ class WorkflowRunApi(Resource):
|
||||
@service_api_ns.response(
|
||||
200,
|
||||
"Workflow executed successfully",
|
||||
service_api_ns.models[GeneratedAppResponse.__name__],
|
||||
)
|
||||
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
|
||||
def post(self, app_model: App, end_user: EndUser):
|
||||
@ -366,6 +341,7 @@ class WorkflowRunApi(Resource):
|
||||
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except ProviderTokenNotInitError as ex:
|
||||
raise ProviderNotInitializeError(ex.description)
|
||||
@ -445,7 +421,6 @@ class WorkflowRunByIdApi(Resource):
|
||||
@service_api_ns.response(
|
||||
200,
|
||||
"Workflow executed successfully",
|
||||
service_api_ns.models[GeneratedAppResponse.__name__],
|
||||
)
|
||||
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
|
||||
def post(self, app_model: App, end_user: EndUser, workflow_id: str):
|
||||
@ -476,6 +451,7 @@ class WorkflowRunByIdApi(Resource):
|
||||
app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except WorkflowNotFoundError as ex:
|
||||
raise NotFound(str(ex))
|
||||
@ -541,7 +517,7 @@ class WorkflowTaskStopApi(Resource):
|
||||
# New graph engine command channel mechanism
|
||||
GraphEngineManager(redis_client).send_stop_command(task_id)
|
||||
|
||||
return {"result": "success"}
|
||||
return SimpleResultResponse(result="success").model_dump()
|
||||
|
||||
|
||||
@service_api_ns.route("/workflows/logs")
|
||||
@ -574,7 +550,7 @@ class WorkflowAppLogApi(Resource):
|
||||
|
||||
Returns paginated workflow execution logs with filtering options.
|
||||
"""
|
||||
args = WorkflowLogQuery.model_validate(request.args.to_dict())
|
||||
args = query_params_from_request(WorkflowLogQuery)
|
||||
|
||||
status = WorkflowExecutionStatus(args.status) if args.status else None
|
||||
created_at_before = isoparse(args.created_at__before) if args.created_at__before else None
|
||||
@ -596,4 +572,4 @@ class WorkflowAppLogApi(Resource):
|
||||
created_by_account=args.created_by_account,
|
||||
)
|
||||
|
||||
return _serialize_workflow_log_pagination(workflow_app_log_pagination)
|
||||
return dump_response(WorkflowAppLogPaginationResponse, workflow_app_log_pagination)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
@ -29,6 +30,15 @@ class AnnotationList(ResponseModel):
|
||||
page: int
|
||||
|
||||
|
||||
class AnnotationJobStatusResponse(ResponseModel):
|
||||
job_id: str
|
||||
job_status: Literal["waiting", "processing", "completed", "error"] | str
|
||||
|
||||
|
||||
class AnnotationJobStatusDetailResponse(AnnotationJobStatusResponse):
|
||||
error_msg: str = ""
|
||||
|
||||
|
||||
class AnnotationExportList(ResponseModel):
|
||||
data: list[Annotation]
|
||||
|
||||
|
||||
@ -15,13 +15,13 @@ simple_account_fields = {
|
||||
}
|
||||
|
||||
|
||||
class SimpleAccount(ResponseModel):
|
||||
class SimpleAccountResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
email: str
|
||||
|
||||
|
||||
class _AccountAvatar(ResponseModel):
|
||||
class _AccountAvatarResponseMixin(ResponseModel):
|
||||
avatar: str | None = None
|
||||
|
||||
@computed_field(return_type=str | None) # type: ignore[prop-decorator]
|
||||
@ -30,7 +30,7 @@ class _AccountAvatar(ResponseModel):
|
||||
return build_avatar_url(self.avatar)
|
||||
|
||||
|
||||
class Account(_AccountAvatar):
|
||||
class AccountResponse(_AccountAvatarResponseMixin):
|
||||
id: str
|
||||
name: str
|
||||
email: str
|
||||
@ -48,7 +48,7 @@ class Account(_AccountAvatar):
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class AccountWithRole(_AccountAvatar):
|
||||
class AccountWithRoleResponse(_AccountAvatarResponseMixin):
|
||||
id: str
|
||||
name: str
|
||||
email: str
|
||||
@ -65,5 +65,11 @@ class AccountWithRole(_AccountAvatar):
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class AccountWithRoleList(ResponseModel):
|
||||
accounts: list[AccountWithRole]
|
||||
class AccountWithRoleListResponse(ResponseModel):
|
||||
accounts: list[AccountWithRoleResponse]
|
||||
|
||||
|
||||
SimpleAccount = SimpleAccountResponse
|
||||
Account = AccountResponse
|
||||
AccountWithRole = AccountWithRoleResponse
|
||||
AccountWithRoleList = AccountWithRoleListResponse
|
||||
|
||||
@ -38,7 +38,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/change-email
|
||||
#### Request Body
|
||||
@ -77,7 +77,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/change-email/validity
|
||||
#### Request Body
|
||||
@ -198,7 +198,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/interface-theme
|
||||
#### Request Body
|
||||
@ -211,7 +211,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/name
|
||||
#### Request Body
|
||||
@ -224,7 +224,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/password
|
||||
#### Request Body
|
||||
@ -237,14 +237,14 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [GET] /account/profile
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /account/timezone
|
||||
#### Request Body
|
||||
@ -257,7 +257,7 @@ Get account avatar url
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [Account](#account)<br> |
|
||||
| 200 | Success | **application/json**: [AccountResponse](#accountresponse)<br> |
|
||||
|
||||
### [POST] /activate
|
||||
Activate account with invitation token
|
||||
@ -9268,7 +9268,7 @@ Increment snippet use count by 1
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [AccountWithRoleList](#accountwithrolelist)<br> |
|
||||
| 200 | Success | **application/json**: [AccountWithRoleListResponse](#accountwithrolelistresponse)<br> |
|
||||
|
||||
### [GET] /workspaces/current/default-model
|
||||
#### Parameters
|
||||
@ -9477,7 +9477,7 @@ Update a plugin endpoint
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [AccountWithRoleList](#accountwithrolelist)<br> |
|
||||
| 200 | Success | **application/json**: [AccountWithRoleListResponse](#accountwithrolelistresponse)<br> |
|
||||
|
||||
### [POST] /workspaces/current/members/invite-email
|
||||
#### Request Body
|
||||
@ -11928,23 +11928,6 @@ Default namespace
|
||||
| role_name | string | | No |
|
||||
| tenant_id | string | | No |
|
||||
|
||||
#### Account
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| avatar | string | | No |
|
||||
| avatar_url | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
| email | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| interface_language | string | | No |
|
||||
| interface_theme | string | | No |
|
||||
| is_password_set | boolean | | Yes |
|
||||
| last_login_at | integer | | No |
|
||||
| last_login_ip | string | | No |
|
||||
| name | string | | Yes |
|
||||
| timezone | string | | No |
|
||||
|
||||
#### AccountAvatarPayload
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -12020,13 +12003,36 @@ Default namespace
|
||||
| password | string | | No |
|
||||
| repeat_new_password | string | | Yes |
|
||||
|
||||
#### AccountResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| avatar | string | | No |
|
||||
| avatar_url | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
| email | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| interface_language | string | | No |
|
||||
| interface_theme | string | | No |
|
||||
| is_password_set | boolean | | Yes |
|
||||
| last_login_at | integer | | No |
|
||||
| last_login_ip | string | | No |
|
||||
| name | string | | Yes |
|
||||
| timezone | string | | No |
|
||||
|
||||
#### AccountTimezonePayload
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| timezone | string | | Yes |
|
||||
|
||||
#### AccountWithRole
|
||||
#### AccountWithRoleListResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| accounts | [ [AccountWithRoleResponse](#accountwithroleresponse) ] | | Yes |
|
||||
|
||||
#### AccountWithRoleResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
@ -12041,12 +12047,6 @@ Default namespace
|
||||
| roles | [ object ] | | No |
|
||||
| status | string | | Yes |
|
||||
|
||||
#### AccountWithRoleList
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| accounts | [ [AccountWithRole](#accountwithrole) ] | | Yes |
|
||||
|
||||
#### ActivateCheckQuery
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -12095,7 +12095,7 @@ Default namespace
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| conversation_id | string | | No |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| elapsed_time | number | | No |
|
||||
| exceptions_count | integer | | No |
|
||||
| finished_at | integer | | No |
|
||||
@ -13429,7 +13429,6 @@ Soft lifecycle state for Agent records.
|
||||
| created_at | integer | | No |
|
||||
| files | [ string ] | | Yes |
|
||||
| id | string | | Yes |
|
||||
| message_chain_id | string | | No |
|
||||
| message_id | string | | Yes |
|
||||
| observation | string | | No |
|
||||
| position | integer | | Yes |
|
||||
@ -14540,8 +14539,8 @@ Enum class for configurate method of provider model.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| annotation_create_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| annotation_id | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
| id | string | | Yes |
|
||||
|
||||
#### ConversationDetail
|
||||
|
||||
@ -17079,6 +17078,7 @@ Enum class for large language model mode.
|
||||
| agent_thoughts | [ [AgentThought](#agentthought) ] | | No |
|
||||
| annotation | [ConversationAnnotation](#conversationannotation) | | No |
|
||||
| annotation_hit_history | [ConversationAnnotationHitHistory](#conversationannotationhithistory) | | No |
|
||||
| answer | string | | Yes |
|
||||
| answer_tokens | integer | | No |
|
||||
| conversation_id | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
@ -17092,12 +17092,11 @@ Enum class for large language model mode.
|
||||
| inputs | object | | Yes |
|
||||
| message | [JSONValue](#jsonvalue) | | No |
|
||||
| message_files | [ [MessageFile](#messagefile) ] | | No |
|
||||
| message_metadata_dict | [JSONValue](#jsonvalue) | | No |
|
||||
| message_tokens | integer | | No |
|
||||
| metadata | [JSONValue](#jsonvalue) | | No |
|
||||
| parent_message_id | string | | No |
|
||||
| provider_response_latency | number | | No |
|
||||
| query | string | | Yes |
|
||||
| re_sign_file_url_answer | string | | Yes |
|
||||
| status | string | | Yes |
|
||||
| workflow_run_id | string | | No |
|
||||
|
||||
@ -19151,6 +19150,14 @@ Model class for provider quota configuration.
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
|
||||
#### SimpleAccountResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| email | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
|
||||
#### SimpleConversation
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -19458,7 +19465,7 @@ Query parameters for listing snippet published workflows.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| conversation_variables | [ [WorkflowConversationVariableResponse](#workflowconversationvariableresponse) ] | | Yes |
|
||||
| created_at | integer | | Yes |
|
||||
| created_by | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| environment_variables | [ [WorkflowEnvironmentVariableResponse](#workflowenvironmentvariableresponse) ] | | Yes |
|
||||
| features | object | | Yes |
|
||||
| graph | object | | Yes |
|
||||
@ -19470,7 +19477,7 @@ Query parameters for listing snippet published workflows.
|
||||
| rag_pipeline_variables | [ [PipelineVariableResponse](#pipelinevariableresponse) ] | | Yes |
|
||||
| tool_published | boolean | | Yes |
|
||||
| updated_at | integer | | Yes |
|
||||
| updated_by | [SimpleAccount](#simpleaccount) | | No |
|
||||
| updated_by | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| version | string | | Yes |
|
||||
|
||||
#### StarredAppListQuery
|
||||
@ -20390,7 +20397,7 @@ How a workflow node is bound to an Agent.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| created_by_end_user | [SimpleEndUser](#simpleenduser) | | No |
|
||||
| created_by_role | string | | No |
|
||||
| created_from | string | | No |
|
||||
@ -20427,7 +20434,7 @@ How a workflow node is bound to an Agent.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| created_by_end_user | [SimpleEndUser](#simpleenduser) | | No |
|
||||
| id | string | | Yes |
|
||||
| trigger_metadata | | | No |
|
||||
@ -20528,7 +20535,7 @@ How a workflow node is bound to an Agent.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| users | [ [AccountWithRole](#accountwithrole) ] | | Yes |
|
||||
| users | [ [AccountWithRoleResponse](#accountwithroleresponse) ] | | Yes |
|
||||
|
||||
#### WorkflowCommentReply
|
||||
|
||||
@ -20877,7 +20884,7 @@ can reuse its existing handler.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| conversation_variables | [ [WorkflowConversationVariableResponse](#workflowconversationvariableresponse) ] | | Yes |
|
||||
| created_at | integer | | Yes |
|
||||
| created_by | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| environment_variables | [ [WorkflowEnvironmentVariableResponse](#workflowenvironmentvariableresponse) ] | | Yes |
|
||||
| features | object | | Yes |
|
||||
| graph | object | | Yes |
|
||||
@ -20888,7 +20895,7 @@ can reuse its existing handler.
|
||||
| rag_pipeline_variables | [ [PipelineVariableResponse](#pipelinevariableresponse) ] | | Yes |
|
||||
| tool_published | boolean | | Yes |
|
||||
| updated_at | integer | | Yes |
|
||||
| updated_by | [SimpleAccount](#simpleaccount) | | No |
|
||||
| updated_by | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| version | string | | Yes |
|
||||
|
||||
#### WorkflowRestoreResponse
|
||||
@ -20923,7 +20930,7 @@ can reuse its existing handler.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| created_by_end_user | [SimpleEndUser](#simpleenduser) | | No |
|
||||
| created_by_role | string | | No |
|
||||
| elapsed_time | number | | No |
|
||||
@ -20962,7 +20969,7 @@ can reuse its existing handler.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| elapsed_time | number | | No |
|
||||
| exceptions_count | integer | | No |
|
||||
| finished_at | integer | | No |
|
||||
@ -21009,7 +21016,7 @@ can reuse its existing handler.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| created_by_end_user | [SimpleEndUser](#simpleenduser) | | No |
|
||||
| created_by_role | string | | No |
|
||||
| elapsed_time | number | | No |
|
||||
|
||||
@ -237,7 +237,7 @@ Retrieves the status of an asynchronous annotation reply configuration job start
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successfully retrieved task status. | **application/json**: [AnnotationJobStatusResponse](#annotationjobstatusresponse)<br> |
|
||||
| 200 | Successfully retrieved task status. | **application/json**: [AnnotationJobStatusDetailResponse](#annotationjobstatusdetailresponse)<br> |
|
||||
| 400 | `invalid_param` : The specified job does not exist. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
@ -392,15 +392,15 @@ Send a request to the chat application.
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `ChatCompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of Server-Sent Events. | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br>**text/event-stream**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `not_chat_app` : App mode does not match the API route. - `conversation_completed` : The conversation has ended. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
| 404 | `not_found` : Conversation does not exist. | |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. | |
|
||||
| 500 | `internal_server_error` : Internal server error. | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `ChatCompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of Server-Sent Events. |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `not_chat_app` : App mode does not match the API route. - `conversation_completed` : The conversation has ended. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. |
|
||||
| 401 | Unauthorized - invalid API token |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied |
|
||||
| 404 | `not_found` : Conversation does not exist. |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. |
|
||||
| 500 | `internal_server_error` : Internal server error. |
|
||||
|
||||
### [POST] /chat-messages/{task_id}/stop
|
||||
**Stop Chat Message Generation**
|
||||
@ -539,15 +539,15 @@ Send a request to the chat application.
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `ChatCompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of Server-Sent Events. | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br>**text/event-stream**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `not_chat_app` : App mode does not match the API route. - `conversation_completed` : The conversation has ended. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
| 404 | `not_found` : Conversation does not exist. | |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. | |
|
||||
| 500 | `internal_server_error` : Internal server error. | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `ChatCompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of Server-Sent Events. |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `not_chat_app` : App mode does not match the API route. - `conversation_completed` : The conversation has ended. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. |
|
||||
| 401 | Unauthorized - invalid API token |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied |
|
||||
| 404 | `not_found` : Conversation does not exist. |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. |
|
||||
| 500 | `internal_server_error` : Internal server error. |
|
||||
|
||||
### [POST] /chat-messages/{task_id}/stop
|
||||
**Stop Chat Message Generation**
|
||||
@ -615,15 +615,15 @@ Send a request to the text generation application.
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `CompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkCompletionEvent` objects. | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br>**text/event-stream**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
| 404 | Conversation not found | |
|
||||
| 429 | `too_many_requests` : Too many concurrent requests for this app. | |
|
||||
| 500 | `internal_server_error` : Internal server error. | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `CompletionResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkCompletionEvent` objects. |
|
||||
| 400 | - `app_unavailable` : App unavailable or misconfigured. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Text generation failed. |
|
||||
| 401 | Unauthorized - invalid API token |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied |
|
||||
| 404 | Conversation not found |
|
||||
| 429 | `too_many_requests` : Too many concurrent requests for this app. |
|
||||
| 500 | `internal_server_error` : Internal server error. |
|
||||
|
||||
### [POST] /completion-messages/{task_id}/stop
|
||||
**Stop Completion Message Generation**
|
||||
@ -2220,15 +2220,15 @@ Execute a workflow. Cannot be executed without a published workflow.
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects. | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br>**text/event-stream**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | - `not_workflow_app` : App mode does not match the API route. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Workflow execution request failed. - `invalid_param` : Invalid parameter value. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
| 404 | Workflow not found | |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. | |
|
||||
| 500 | `internal_server_error` : Internal server error. | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects. |
|
||||
| 400 | - `not_workflow_app` : App mode does not match the API route. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Workflow execution request failed. - `invalid_param` : Invalid parameter value. |
|
||||
| 401 | Unauthorized - invalid API token |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied |
|
||||
| 404 | Workflow not found |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. |
|
||||
| 500 | `internal_server_error` : Internal server error. |
|
||||
|
||||
### [GET] /workflows/run/{workflow_run_id}
|
||||
**Get Workflow Run Detail**
|
||||
@ -2297,15 +2297,15 @@ Execute a specific workflow version identified by its ID. Useful for running a p
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects. | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br>**text/event-stream**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | - `not_workflow_app` : App mode does not match the API route. - `bad_request` : Workflow is a draft or has an invalid ID format. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Workflow execution request failed. - `invalid_param` : Required parameter missing or invalid. | |
|
||||
| 401 | Unauthorized - invalid API token | |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied | |
|
||||
| 404 | `not_found` : Workflow not found. | |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. | |
|
||||
| 500 | `internal_server_error` : Internal server error. | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Successful response. The content type and structure depend on the `response_mode` parameter in the request. - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object. - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects. |
|
||||
| 400 | - `not_workflow_app` : App mode does not match the API route. - `bad_request` : Workflow is a draft or has an invalid ID format. - `provider_not_initialize` : No valid model provider credentials found. - `provider_quota_exceeded` : Model provider quota exhausted. - `model_currently_not_support` : Current model unavailable. - `completion_request_error` : Workflow execution request failed. - `invalid_param` : Required parameter missing or invalid. |
|
||||
| 401 | Unauthorized - invalid API token |
|
||||
| 403 | Forbidden - token scope, app, dataset, or workspace access denied |
|
||||
| 404 | `not_found` : Workflow not found. |
|
||||
| 429 | - `too_many_requests` : Too many concurrent requests for this app. - `rate_limit_error` : The upstream model provider rate limit was exceeded. |
|
||||
| 500 | `internal_server_error` : Internal server error. |
|
||||
|
||||
---
|
||||
## default
|
||||
@ -2351,7 +2351,7 @@ Retrieve the list of available models by type. Primarily used to query `text-emb
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| content | string | | No |
|
||||
| answer | string | | No |
|
||||
| created_at | integer | | No |
|
||||
| hit_count | integer | | No |
|
||||
| id | string | | Yes |
|
||||
@ -2364,13 +2364,20 @@ Retrieve the list of available models by type. Primarily used to query `text-emb
|
||||
| answer | string | Annotation answer. | Yes |
|
||||
| question | string | Annotation question. | Yes |
|
||||
|
||||
#### AnnotationJobStatusResponse
|
||||
#### AnnotationJobStatusDetailResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| error_msg | string | | No |
|
||||
| job_id | string | | Yes |
|
||||
| job_status | string | | Yes |
|
||||
| job_status | string<br>string | | Yes |
|
||||
|
||||
#### AnnotationJobStatusResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| job_id | string | | Yes |
|
||||
| job_status | string<br>string | | Yes |
|
||||
|
||||
#### AnnotationList
|
||||
|
||||
@ -3937,7 +3944,7 @@ Model class for provider with models response.
|
||||
| output_variable_name | string | | Yes |
|
||||
| type | string | | No |
|
||||
|
||||
#### SimpleAccount
|
||||
#### SimpleAccountResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
@ -4147,7 +4154,7 @@ in form definiton, or a variable while the workflow is running.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| created_by_account | [SimpleAccountResponse](#simpleaccountresponse) | | No |
|
||||
| created_by_end_user | [SimpleEndUser](#simpleenduser) | | No |
|
||||
| created_by_role | string | | No |
|
||||
| created_from | string | | No |
|
||||
|
||||
@ -141,14 +141,14 @@ class TestAppModelPatterns:
|
||||
|
||||
assert app.id is not None
|
||||
assert app.status == "normal"
|
||||
assert app.enable_api is True
|
||||
assert app.enable_api
|
||||
|
||||
def test_app_model_disabled_api(self):
|
||||
"""Test app with disabled API access."""
|
||||
app = Mock(spec=App)
|
||||
app.enable_api = False
|
||||
|
||||
assert app.enable_api is False
|
||||
assert not app.enable_api
|
||||
|
||||
def test_app_model_archived_status(self):
|
||||
"""Test app with archived status."""
|
||||
@ -183,7 +183,7 @@ class TestAnnotationErrorPatterns:
|
||||
|
||||
class TestAnnotationReplyActionApi:
|
||||
def test_enable(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
enable_mock = Mock()
|
||||
enable_mock = Mock(return_value={"job_id": "job-1", "job_status": "waiting"})
|
||||
monkeypatch.setattr(AppAnnotationService, "enable_app_annotation", enable_mock)
|
||||
|
||||
api = AnnotationReplyActionApi()
|
||||
@ -198,10 +198,11 @@ class TestAnnotationReplyActionApi:
|
||||
response, status = handler(api, app_model=app_model, action="enable")
|
||||
|
||||
assert status == 200
|
||||
assert response == {"job_id": "job-1", "job_status": "waiting"}
|
||||
enable_mock.assert_called_once()
|
||||
|
||||
def test_disable(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
disable_mock = Mock()
|
||||
disable_mock = Mock(return_value={"job_id": "job-1", "job_status": "waiting"})
|
||||
monkeypatch.setattr(AppAnnotationService, "disable_app_annotation", disable_mock)
|
||||
|
||||
api = AnnotationReplyActionApi()
|
||||
@ -216,6 +217,7 @@ class TestAnnotationReplyActionApi:
|
||||
response, status = handler(api, app_model=app_model, action="disable")
|
||||
|
||||
assert status == 200
|
||||
assert response == {"job_id": "job-1", "job_status": "waiting"}
|
||||
disable_mock.assert_called_once()
|
||||
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ class TestMessageListQuery:
|
||||
"""Test conversation_id is required."""
|
||||
conversation_id = str(uuid.uuid4())
|
||||
query = MessageListQuery(conversation_id=conversation_id)
|
||||
assert str(query.conversation_id) == conversation_id
|
||||
assert query.conversation_id == conversation_id
|
||||
|
||||
def test_query_with_defaults(self):
|
||||
"""Test query with default values."""
|
||||
@ -87,13 +87,13 @@ class TestMessageListQuery:
|
||||
"""Test query rejects limit < 1."""
|
||||
conversation_id = str(uuid.uuid4())
|
||||
with pytest.raises(ValueError):
|
||||
MessageListQuery(conversation_id=conversation_id, limit=0)
|
||||
MessageListQuery(conversation_id=conversation_id, limit=0) # pyrefly: ignore[bad-argument-type]
|
||||
|
||||
def test_query_rejects_limit_above_maximum(self):
|
||||
"""Test query rejects limit > 100."""
|
||||
conversation_id = str(uuid.uuid4())
|
||||
with pytest.raises(ValueError):
|
||||
MessageListQuery(conversation_id=conversation_id, limit=101)
|
||||
MessageListQuery(conversation_id=conversation_id, limit=101) # pyrefly: ignore[bad-argument-type]
|
||||
|
||||
|
||||
class TestMessageFeedbackPayload:
|
||||
@ -131,6 +131,7 @@ class TestMessageFeedbackPayload:
|
||||
"""Test payload with long feedback content."""
|
||||
long_content = "A" * 1000
|
||||
payload = MessageFeedbackPayload(content=long_content)
|
||||
assert payload.content is not None
|
||||
assert len(payload.content) == 1000
|
||||
|
||||
def test_payload_with_unicode_content(self):
|
||||
@ -163,7 +164,7 @@ class TestFeedbackListQuery:
|
||||
def test_query_rejects_page_below_minimum(self):
|
||||
"""Test query rejects page < 1."""
|
||||
with pytest.raises(ValueError):
|
||||
FeedbackListQuery(page=0)
|
||||
FeedbackListQuery(page=0) # pyrefly: ignore[bad-argument-type]
|
||||
|
||||
def test_query_limit_boundaries(self):
|
||||
"""Test query limit boundaries."""
|
||||
@ -176,12 +177,12 @@ class TestFeedbackListQuery:
|
||||
def test_query_rejects_limit_below_minimum(self):
|
||||
"""Test query rejects limit < 1."""
|
||||
with pytest.raises(ValueError):
|
||||
FeedbackListQuery(limit=0)
|
||||
FeedbackListQuery(limit=0) # pyrefly: ignore[bad-argument-type]
|
||||
|
||||
def test_query_rejects_limit_above_maximum(self):
|
||||
"""Test query rejects limit > 101."""
|
||||
with pytest.raises(ValueError):
|
||||
FeedbackListQuery(limit=102)
|
||||
FeedbackListQuery(limit=102) # pyrefly: ignore[bad-argument-type]
|
||||
|
||||
|
||||
class TestMessageAppModeValidation:
|
||||
@ -449,7 +450,20 @@ class TestMessageFeedbackApi:
|
||||
|
||||
class TestAppGetFeedbacksApi:
|
||||
def test_success(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(MessageService, "get_all_messages_feedbacks", lambda *_args, **_kwargs: ["f1"])
|
||||
feedback = {
|
||||
"id": "feedback-1",
|
||||
"app_id": "app-1",
|
||||
"conversation_id": "conversation-1",
|
||||
"message_id": "message-1",
|
||||
"rating": "like",
|
||||
"content": "helpful answer",
|
||||
"from_source": "user",
|
||||
"from_end_user_id": "end-user-1",
|
||||
"from_account_id": None,
|
||||
"created_at": "2024-01-02T03:04:05",
|
||||
"updated_at": "2024-01-02T03:04:06",
|
||||
}
|
||||
monkeypatch.setattr(MessageService, "get_all_messages_feedbacks", lambda *_args, **_kwargs: [feedback])
|
||||
|
||||
api = AppGetFeedbacksApi()
|
||||
handler = unwrap(api.get)
|
||||
@ -458,7 +472,7 @@ class TestAppGetFeedbacksApi:
|
||||
with app.test_request_context("/app/feedbacks?page=1&limit=20", method="GET"):
|
||||
response = handler(api, app_model=app_model)
|
||||
|
||||
assert response == {"data": ["f1"]}
|
||||
assert response == {"data": [feedback]}
|
||||
|
||||
|
||||
class TestMessageSuggestedApi:
|
||||
|
||||
@ -13,15 +13,17 @@ Focus on:
|
||||
- Service method interfaces
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import UTC, datetime
|
||||
from inspect import unwrap
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from werkzeug.exceptions import BadRequest, NotFound
|
||||
|
||||
from controllers.service_api.app.error import NotWorkflowAppError
|
||||
@ -35,31 +37,175 @@ from controllers.service_api.app.workflow import (
|
||||
WorkflowRunByIdApi,
|
||||
WorkflowRunDetailApi,
|
||||
WorkflowRunPayload,
|
||||
WorkflowRunResponse,
|
||||
WorkflowTaskStopApi,
|
||||
)
|
||||
from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from models.model import App, AppMode
|
||||
from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom
|
||||
from models.model import App, AppMode, EndUser
|
||||
from models.workflow import WorkflowAppLog, WorkflowAppLogCreatedFrom, WorkflowRun, WorkflowType
|
||||
from services.app_generate_service import AppGenerateService
|
||||
from services.errors.app import IsDraftWorkflowError, WorkflowNotFoundError
|
||||
from services.errors.llm import InvokeRateLimitError
|
||||
from services.workflow_app_service import WorkflowAppService
|
||||
from services.workflow_app_service import LogView, LogViewDetails, WorkflowAppService
|
||||
|
||||
|
||||
def _make_mock_workflow_run(run_id: str = "run-1"):
|
||||
run = Mock()
|
||||
run.id = run_id
|
||||
run.workflow_id = "wf-1"
|
||||
run.status = WorkflowExecutionStatus.SUCCEEDED
|
||||
run.inputs = {"input": "value"}
|
||||
run.outputs_dict = {"output": "value"}
|
||||
run.error = None
|
||||
run.total_steps = 1
|
||||
run.total_tokens = 10
|
||||
run.created_at = datetime(2026, 1, 1, tzinfo=UTC)
|
||||
run.finished_at = datetime(2026, 1, 1, tzinfo=UTC)
|
||||
run.elapsed_time = 0.1
|
||||
return run
|
||||
def _default_workflow_inputs() -> dict[str, object]:
|
||||
return {"input": "value"}
|
||||
|
||||
|
||||
def _default_log_details() -> LogViewDetails:
|
||||
return {"trigger_metadata": {"node": "answer", "latency": 1.25}}
|
||||
|
||||
|
||||
class _DbSessionStub:
|
||||
def get(self, *args: object, **kwargs: object) -> None:
|
||||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
class _DbStub:
|
||||
engine: object = field(default_factory=object)
|
||||
session: _DbSessionStub = field(default_factory=_DbSessionStub)
|
||||
|
||||
|
||||
@dataclass
|
||||
class _WorkflowRunRepositoryStub:
|
||||
run: WorkflowRun | None
|
||||
|
||||
def get_workflow_run_by_id(self, *, tenant_id: str, app_id: str, run_id: str) -> WorkflowRun | None:
|
||||
return self.run if tenant_id and app_id and run_id else None
|
||||
|
||||
def get_workflow_run_by_id_without_tenant(self, *, run_id: str) -> WorkflowRun | None:
|
||||
return self.run if run_id else None
|
||||
|
||||
|
||||
class _BeginStub:
|
||||
def __enter__(self) -> object:
|
||||
return object()
|
||||
|
||||
def __exit__(self, exc_type: object, exc: object, tb: object) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class _SessionMakerStub:
|
||||
def __init__(self, *args: object, **kwargs: object) -> None:
|
||||
pass
|
||||
|
||||
def begin(self) -> _BeginStub:
|
||||
return _BeginStub()
|
||||
|
||||
|
||||
def _make_workflow_run(
|
||||
run_id: str = "run-1",
|
||||
*,
|
||||
workflow_id: str = "wf-1",
|
||||
inputs: dict[str, object] | None = None,
|
||||
outputs: dict[str, object] | None = None,
|
||||
created_at: datetime | None = None,
|
||||
finished_at: datetime | None = None,
|
||||
) -> WorkflowRun:
|
||||
return WorkflowRun(
|
||||
id=run_id,
|
||||
tenant_id="tenant-1",
|
||||
app_id="app-1",
|
||||
workflow_id=workflow_id,
|
||||
type=WorkflowType.WORKFLOW,
|
||||
triggered_from=WorkflowRunTriggeredFrom.APP_RUN,
|
||||
version="2026-01-01",
|
||||
graph=json.dumps({"nodes": [], "edges": []}),
|
||||
inputs=json.dumps(inputs if inputs is not None else _default_workflow_inputs()),
|
||||
outputs=json.dumps(outputs if outputs is not None else {"output": "value"}),
|
||||
status=WorkflowExecutionStatus.SUCCEEDED,
|
||||
error=None,
|
||||
elapsed_time=0.1,
|
||||
total_tokens=10,
|
||||
total_steps=1,
|
||||
created_by_role=CreatorUserRole.END_USER,
|
||||
created_by="end-user-1",
|
||||
created_at=created_at or datetime(2026, 1, 1, tzinfo=UTC),
|
||||
finished_at=finished_at or datetime(2026, 1, 1, tzinfo=UTC),
|
||||
exceptions_count=0,
|
||||
)
|
||||
|
||||
|
||||
def _make_workflow_app_log() -> WorkflowAppLog:
|
||||
log = WorkflowAppLog(
|
||||
tenant_id="tenant-1",
|
||||
app_id="app-1",
|
||||
workflow_id="wf-1",
|
||||
workflow_run_id="log-run-1",
|
||||
created_from=WorkflowAppLogCreatedFrom.SERVICE_API,
|
||||
created_by_role=CreatorUserRole.ACCOUNT,
|
||||
created_by="account-1",
|
||||
)
|
||||
log.id = "app-log-1"
|
||||
log.created_at = datetime(2026, 1, 1, 1, 0, 3, tzinfo=UTC)
|
||||
return log
|
||||
|
||||
|
||||
def _make_workflow_log_page() -> dict[str, object]:
|
||||
return {
|
||||
"page": 1,
|
||||
"limit": 20,
|
||||
"total": 1,
|
||||
"has_more": False,
|
||||
"data": [LogView(_make_workflow_app_log(), _default_log_details())],
|
||||
}
|
||||
|
||||
|
||||
def _make_app_model(
|
||||
*,
|
||||
app_id: str = "app-1",
|
||||
tenant_id: str = "tenant-1",
|
||||
mode: AppMode = AppMode.WORKFLOW,
|
||||
) -> App:
|
||||
app = App()
|
||||
app.id = app_id
|
||||
app.tenant_id = tenant_id
|
||||
app.mode = mode
|
||||
return app
|
||||
|
||||
|
||||
def _make_end_user(user_id: str = "end-user-1") -> EndUser:
|
||||
end_user = EndUser()
|
||||
end_user.id = user_id
|
||||
return end_user
|
||||
|
||||
|
||||
def _expected_workflow_log_pagination_payload() -> dict[str, object]:
|
||||
return {
|
||||
"page": 1,
|
||||
"limit": 20,
|
||||
"total": 1,
|
||||
"has_more": False,
|
||||
"data": [
|
||||
{
|
||||
"id": "app-log-1",
|
||||
"workflow_run": {
|
||||
"id": "log-run-1",
|
||||
"version": "2026-01-01",
|
||||
"status": "succeeded",
|
||||
"triggered_from": "app-run",
|
||||
"error": None,
|
||||
"elapsed_time": 0.1,
|
||||
"total_tokens": 10,
|
||||
"total_steps": 1,
|
||||
"created_at": 1767229200,
|
||||
"finished_at": 1767229202,
|
||||
"exceptions_count": 0,
|
||||
},
|
||||
"details": {"trigger_metadata": {"node": "answer", "latency": 1.25}},
|
||||
"created_from": "service-api",
|
||||
"created_by_role": "account",
|
||||
"created_by_account": None,
|
||||
"created_by_end_user": None,
|
||||
"created_at": 1767229203,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class TestWorkflowRunPayload:
|
||||
@ -108,6 +254,7 @@ class TestWorkflowRunPayload:
|
||||
{"type": "audio", "url": "http://example.com/audio.mp3"},
|
||||
]
|
||||
payload = WorkflowRunPayload(inputs={}, files=files)
|
||||
assert payload.files is not None
|
||||
assert len(payload.files) == 3
|
||||
|
||||
|
||||
@ -170,22 +317,22 @@ class TestWorkflowLogQuery:
|
||||
def test_query_rejects_page_below_minimum(self):
|
||||
"""Test query rejects page < 1."""
|
||||
with pytest.raises(ValueError):
|
||||
WorkflowLogQuery(page=0)
|
||||
WorkflowLogQuery.model_validate({"page": 0})
|
||||
|
||||
def test_query_rejects_page_above_maximum(self):
|
||||
"""Test query rejects page > 99999."""
|
||||
with pytest.raises(ValueError):
|
||||
WorkflowLogQuery(page=100000)
|
||||
WorkflowLogQuery.model_validate({"page": 100000})
|
||||
|
||||
def test_query_rejects_limit_below_minimum(self):
|
||||
"""Test query rejects limit < 1."""
|
||||
with pytest.raises(ValueError):
|
||||
WorkflowLogQuery(limit=0)
|
||||
WorkflowLogQuery.model_validate({"limit": 0})
|
||||
|
||||
def test_query_rejects_limit_above_maximum(self):
|
||||
"""Test query rejects limit > 100."""
|
||||
with pytest.raises(ValueError):
|
||||
WorkflowLogQuery(limit=101)
|
||||
WorkflowLogQuery.model_validate({"limit": 101})
|
||||
|
||||
def test_query_with_keyword_search(self):
|
||||
"""Test query with keyword filter."""
|
||||
@ -199,6 +346,29 @@ class TestWorkflowLogQuery:
|
||||
assert query.created_at__after == "2024-01-01T00:00:00Z"
|
||||
|
||||
|
||||
class TestWorkflowRunResponse:
|
||||
def test_validates_workflow_run_object_shape_and_clears_paused_outputs(self):
|
||||
run = _make_workflow_run(run_id="run-paused")
|
||||
run.status = WorkflowExecutionStatus.PAUSED
|
||||
run.outputs = json.dumps({"should": "not leak"})
|
||||
|
||||
result = WorkflowRunResponse.model_validate(run, from_attributes=True).model_dump(mode="json")
|
||||
|
||||
assert result == {
|
||||
"id": "run-paused",
|
||||
"workflow_id": "wf-1",
|
||||
"status": "paused",
|
||||
"inputs": '{"input": "value"}',
|
||||
"outputs": {},
|
||||
"error": None,
|
||||
"total_steps": 1,
|
||||
"total_tokens": 10,
|
||||
"created_at": 1767225600,
|
||||
"finished_at": 1767225600,
|
||||
"elapsed_time": 0.1,
|
||||
}
|
||||
|
||||
|
||||
class TestWorkflowAppService:
|
||||
"""Test WorkflowAppService interface."""
|
||||
|
||||
@ -215,17 +385,13 @@ class TestWorkflowAppService:
|
||||
@patch.object(WorkflowAppService, "get_paginate_workflow_app_logs")
|
||||
def test_get_paginate_workflow_app_logs_returns_pagination(self, mock_get_logs):
|
||||
"""Test get_paginate_workflow_app_logs returns paginated result."""
|
||||
mock_pagination = Mock()
|
||||
mock_pagination.data = []
|
||||
mock_pagination.page = 1
|
||||
mock_pagination.limit = 20
|
||||
mock_pagination.total = 0
|
||||
mock_get_logs.return_value = mock_pagination
|
||||
pagination = _make_workflow_log_page()
|
||||
mock_get_logs.return_value = pagination
|
||||
|
||||
service = WorkflowAppService()
|
||||
result = service.get_paginate_workflow_app_logs(
|
||||
session=Mock(),
|
||||
app_model=Mock(spec=App),
|
||||
app_model=_make_app_model(),
|
||||
keyword=None,
|
||||
status=None,
|
||||
created_at_before=None,
|
||||
@ -236,8 +402,7 @@ class TestWorkflowAppService:
|
||||
created_by_account=None,
|
||||
)
|
||||
|
||||
assert result.page == 1
|
||||
assert result.limit == 20
|
||||
assert result == pagination
|
||||
|
||||
|
||||
class TestWorkflowExecutionStatus:
|
||||
@ -268,10 +433,10 @@ class TestAppGenerateServiceWorkflow:
|
||||
mock_generate.return_value = {"result": "success"}
|
||||
|
||||
result = AppGenerateService.generate(
|
||||
app_model=Mock(spec=App),
|
||||
user=Mock(),
|
||||
app_model=_make_app_model(),
|
||||
user=_make_end_user(),
|
||||
args={"inputs": {"key": "value"}, "workflow_id": "workflow_123"},
|
||||
invoke_from=Mock(),
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
streaming=False,
|
||||
)
|
||||
|
||||
@ -285,10 +450,10 @@ class TestAppGenerateServiceWorkflow:
|
||||
|
||||
with pytest.raises(WorkflowNotFoundError):
|
||||
AppGenerateService.generate(
|
||||
app_model=Mock(spec=App),
|
||||
user=Mock(),
|
||||
app_model=_make_app_model(),
|
||||
user=_make_end_user(),
|
||||
args={"workflow_id": "invalid_id"},
|
||||
invoke_from=Mock(),
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
streaming=False,
|
||||
)
|
||||
|
||||
@ -299,10 +464,10 @@ class TestAppGenerateServiceWorkflow:
|
||||
|
||||
with pytest.raises(IsDraftWorkflowError):
|
||||
AppGenerateService.generate(
|
||||
app_model=Mock(spec=App),
|
||||
user=Mock(),
|
||||
app_model=_make_app_model(),
|
||||
user=_make_end_user(),
|
||||
args={"workflow_id": "draft_workflow"},
|
||||
invoke_from=Mock(),
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
streaming=False,
|
||||
)
|
||||
|
||||
@ -313,10 +478,10 @@ class TestAppGenerateServiceWorkflow:
|
||||
mock_generate.return_value = mock_stream
|
||||
|
||||
result = AppGenerateService.generate(
|
||||
app_model=Mock(spec=App),
|
||||
user=Mock(),
|
||||
app_model=_make_app_model(),
|
||||
user=_make_end_user(),
|
||||
args={"inputs": {}, "response_mode": "streaming"},
|
||||
invoke_from=Mock(),
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
streaming=True,
|
||||
)
|
||||
|
||||
@ -351,37 +516,33 @@ class TestWorkflowRunRepository:
|
||||
@patch("repositories.factory.DifyAPIRepositoryFactory.create_api_workflow_run_repository")
|
||||
def test_workflow_run_repository_get_by_id(self, mock_factory):
|
||||
"""Test workflow run repository get_workflow_run_by_id method."""
|
||||
mock_repo = Mock()
|
||||
mock_run = Mock()
|
||||
mock_run.id = str(uuid.uuid4())
|
||||
mock_run.status = "succeeded"
|
||||
mock_repo.get_workflow_run_by_id.return_value = mock_run
|
||||
mock_factory.return_value = mock_repo
|
||||
run = _make_workflow_run(run_id=str(uuid.uuid4()))
|
||||
mock_factory.return_value = _WorkflowRunRepositoryStub(run=run)
|
||||
|
||||
from repositories.factory import DifyAPIRepositoryFactory
|
||||
|
||||
repo = DifyAPIRepositoryFactory.create_api_workflow_run_repository(Mock())
|
||||
repo = DifyAPIRepositoryFactory.create_api_workflow_run_repository(sessionmaker())
|
||||
|
||||
result = repo.get_workflow_run_by_id(tenant_id="tenant_123", app_id="app_456", run_id="run_789")
|
||||
|
||||
assert result.status == "succeeded"
|
||||
assert result == run
|
||||
|
||||
|
||||
class TestWorkflowRunDetailApi:
|
||||
def test_not_workflow_app(self, app: Flask) -> None:
|
||||
api = WorkflowRunDetailApi()
|
||||
handler = unwrap(api.get)
|
||||
app_model = SimpleNamespace(mode=AppMode.CHAT.value)
|
||||
app_model = _make_app_model(mode=AppMode.CHAT)
|
||||
|
||||
with app.test_request_context("/workflows/run/1", method="GET"):
|
||||
with pytest.raises(NotWorkflowAppError):
|
||||
handler(api, app_model=app_model, workflow_run_id="run")
|
||||
|
||||
def test_success(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
run = _make_mock_workflow_run(run_id="run")
|
||||
repo = SimpleNamespace(get_workflow_run_by_id=lambda **_kwargs: run)
|
||||
run = _make_workflow_run(run_id="run")
|
||||
repo = _WorkflowRunRepositoryStub(run=run)
|
||||
workflow_module = sys.modules["controllers.service_api.app.workflow"]
|
||||
monkeypatch.setattr(workflow_module, "db", SimpleNamespace(engine=object()))
|
||||
monkeypatch.setattr(workflow_module, "db", _DbStub())
|
||||
monkeypatch.setattr(
|
||||
DifyAPIRepositoryFactory,
|
||||
"create_api_workflow_run_repository",
|
||||
@ -390,7 +551,7 @@ class TestWorkflowRunDetailApi:
|
||||
|
||||
api = WorkflowRunDetailApi()
|
||||
handler = unwrap(api.get)
|
||||
app_model = SimpleNamespace(mode=AppMode.WORKFLOW, tenant_id="t1", id="a1")
|
||||
app_model = _make_app_model(app_id="a1", tenant_id="t1")
|
||||
|
||||
result = handler(api, app_model=app_model, workflow_run_id="run")
|
||||
assert result["id"] == "run"
|
||||
@ -402,8 +563,8 @@ class TestWorkflowRunApi:
|
||||
def test_not_workflow_app(self, app: Flask) -> None:
|
||||
api = WorkflowRunApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.CHAT.value)
|
||||
end_user = SimpleNamespace()
|
||||
app_model = _make_app_model(mode=AppMode.CHAT)
|
||||
end_user = _make_end_user()
|
||||
|
||||
with app.test_request_context("/workflows/run", method="POST", json={"inputs": {}}):
|
||||
with pytest.raises(NotWorkflowAppError):
|
||||
@ -418,8 +579,8 @@ class TestWorkflowRunApi:
|
||||
|
||||
api = WorkflowRunApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.WORKFLOW)
|
||||
end_user = SimpleNamespace()
|
||||
app_model = _make_app_model()
|
||||
end_user = _make_end_user()
|
||||
|
||||
with app.test_request_context("/workflows/run", method="POST", json={"inputs": {}}):
|
||||
with pytest.raises(InvokeRateLimitHttpError):
|
||||
@ -436,8 +597,8 @@ class TestWorkflowRunByIdApi:
|
||||
|
||||
api = WorkflowRunByIdApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.WORKFLOW)
|
||||
end_user = SimpleNamespace()
|
||||
app_model = _make_app_model()
|
||||
end_user = _make_end_user()
|
||||
|
||||
with app.test_request_context("/workflows/1/run", method="POST", json={"inputs": {}}):
|
||||
with pytest.raises(NotFound):
|
||||
@ -452,8 +613,8 @@ class TestWorkflowRunByIdApi:
|
||||
|
||||
api = WorkflowRunByIdApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.WORKFLOW)
|
||||
end_user = SimpleNamespace()
|
||||
app_model = _make_app_model()
|
||||
end_user = _make_end_user()
|
||||
|
||||
with app.test_request_context("/workflows/1/run", method="POST", json={"inputs": {}}):
|
||||
with pytest.raises(BadRequest):
|
||||
@ -464,8 +625,8 @@ class TestWorkflowTaskStopApi:
|
||||
def test_wrong_mode(self, app: Flask) -> None:
|
||||
api = WorkflowTaskStopApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.CHAT.value)
|
||||
end_user = SimpleNamespace()
|
||||
app_model = _make_app_model(mode=AppMode.CHAT)
|
||||
end_user = _make_end_user()
|
||||
|
||||
with app.test_request_context("/workflows/tasks/1/stop", method="POST"):
|
||||
with pytest.raises(NotWorkflowAppError):
|
||||
@ -479,8 +640,8 @@ class TestWorkflowTaskStopApi:
|
||||
|
||||
api = WorkflowTaskStopApi()
|
||||
handler = unwrap(api.post)
|
||||
app_model = SimpleNamespace(mode=AppMode.WORKFLOW)
|
||||
end_user = SimpleNamespace(id="u1")
|
||||
app_model = _make_app_model()
|
||||
end_user = _make_end_user(user_id="u1")
|
||||
|
||||
with app.test_request_context("/workflows/tasks/1/stop", method="POST"):
|
||||
response = handler(api, app_model=app_model, end_user=end_user, task_id="t1")
|
||||
@ -492,37 +653,36 @@ class TestWorkflowTaskStopApi:
|
||||
|
||||
class TestWorkflowAppLogApi:
|
||||
def test_success(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
class _BeginStub:
|
||||
def __enter__(self):
|
||||
return SimpleNamespace()
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return False
|
||||
|
||||
class _SessionMakerStub:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def begin(self):
|
||||
return _BeginStub()
|
||||
|
||||
workflow_module = sys.modules["controllers.service_api.app.workflow"]
|
||||
monkeypatch.setattr(workflow_module, "db", SimpleNamespace(engine=object()))
|
||||
workflow_model_module = sys.modules["models.workflow"]
|
||||
monkeypatch.setattr(workflow_module, "db", _DbStub())
|
||||
monkeypatch.setattr(workflow_model_module, "db", _DbStub())
|
||||
monkeypatch.setattr(workflow_module, "sessionmaker", _SessionMakerStub)
|
||||
monkeypatch.setattr(
|
||||
WorkflowAppService,
|
||||
"get_paginate_workflow_app_logs",
|
||||
lambda *_args, **_kwargs: {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []},
|
||||
lambda *_args, **_kwargs: _make_workflow_log_page(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
DifyAPIRepositoryFactory,
|
||||
"create_api_workflow_run_repository",
|
||||
lambda *_args, **_kwargs: _WorkflowRunRepositoryStub(
|
||||
run=_make_workflow_run(
|
||||
run_id="log-run-1",
|
||||
created_at=datetime(2026, 1, 1, 1, tzinfo=UTC),
|
||||
finished_at=datetime(2026, 1, 1, 1, 0, 2, tzinfo=UTC),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
api = WorkflowAppLogApi()
|
||||
handler = unwrap(api.get)
|
||||
app_model = SimpleNamespace(id="a1")
|
||||
app_model = _make_app_model(app_id="a1")
|
||||
|
||||
with app.test_request_context("/workflows/logs", method="GET"):
|
||||
response = handler(api, app_model=app_model)
|
||||
|
||||
assert response == {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []}
|
||||
assert response == _expected_workflow_log_pagination_payload()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@ -536,12 +696,8 @@ class TestWorkflowAppLogApi:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_workflow_app():
|
||||
app = Mock(spec=App)
|
||||
app.id = str(uuid.uuid4())
|
||||
app.tenant_id = str(uuid.uuid4())
|
||||
app.mode = AppMode.WORKFLOW
|
||||
return app
|
||||
def workflow_app() -> App:
|
||||
return _make_app_model(app_id=str(uuid.uuid4()), tenant_id=str(uuid.uuid4()))
|
||||
|
||||
|
||||
class TestWorkflowRunDetailApiGet:
|
||||
@ -558,38 +714,46 @@ class TestWorkflowRunDetailApiGet:
|
||||
mock_db,
|
||||
mock_repo_factory,
|
||||
app: Flask,
|
||||
mock_workflow_app,
|
||||
workflow_app: App,
|
||||
):
|
||||
"""Test successful workflow run detail retrieval."""
|
||||
mock_run = _make_mock_workflow_run(run_id="run-1")
|
||||
mock_repo = Mock()
|
||||
mock_repo.get_workflow_run_by_id.return_value = mock_run
|
||||
mock_repo_factory.create_api_workflow_run_repository.return_value = mock_repo
|
||||
run = _make_workflow_run(run_id="run-1")
|
||||
mock_repo_factory.create_api_workflow_run_repository.return_value = _WorkflowRunRepositoryStub(run=run)
|
||||
|
||||
from controllers.service_api.app.workflow import WorkflowRunDetailApi
|
||||
|
||||
with app.test_request_context(
|
||||
f"/workflows/run/{mock_run.id}",
|
||||
f"/workflows/run/{run.id}",
|
||||
method="GET",
|
||||
):
|
||||
api = WorkflowRunDetailApi()
|
||||
result = unwrap(api.get)(api, app_model=mock_workflow_app, workflow_run_id=mock_run.id)
|
||||
result = unwrap(api.get)(api, app_model=workflow_app, workflow_run_id=run.id)
|
||||
|
||||
assert result["id"] == mock_run.id
|
||||
assert result["status"] == "succeeded"
|
||||
assert result == {
|
||||
"id": "run-1",
|
||||
"workflow_id": "wf-1",
|
||||
"status": "succeeded",
|
||||
"inputs": '{"input": "value"}',
|
||||
"outputs": {"output": "value"},
|
||||
"error": None,
|
||||
"total_steps": 1,
|
||||
"total_tokens": 10,
|
||||
"created_at": 1767225600,
|
||||
"finished_at": 1767225600,
|
||||
"elapsed_time": 0.1,
|
||||
}
|
||||
|
||||
@patch("controllers.service_api.app.workflow.db")
|
||||
def test_get_workflow_run_wrong_app_mode(self, mock_db, app: Flask):
|
||||
"""Test NotWorkflowAppError when app mode is not workflow or advanced_chat."""
|
||||
from controllers.service_api.app.workflow import WorkflowRunDetailApi
|
||||
|
||||
mock_app = Mock(spec=App)
|
||||
mock_app.mode = AppMode.CHAT.value
|
||||
app_model = _make_app_model(mode=AppMode.CHAT)
|
||||
|
||||
with app.test_request_context("/workflows/run/run-1", method="GET"):
|
||||
api = WorkflowRunDetailApi()
|
||||
with pytest.raises(NotWorkflowAppError):
|
||||
unwrap(api.get)(api, app_model=mock_app, workflow_run_id="run-1")
|
||||
unwrap(api.get)(api, app_model=app_model, workflow_run_id="run-1")
|
||||
|
||||
|
||||
class TestWorkflowTaskStopApiPost:
|
||||
@ -605,7 +769,7 @@ class TestWorkflowTaskStopApiPost:
|
||||
mock_queue_mgr,
|
||||
mock_graph_mgr,
|
||||
app: Flask,
|
||||
mock_workflow_app,
|
||||
workflow_app: App,
|
||||
):
|
||||
"""Test successful workflow task stop."""
|
||||
from controllers.service_api.app.workflow import WorkflowTaskStopApi
|
||||
@ -614,8 +778,8 @@ class TestWorkflowTaskStopApiPost:
|
||||
api = WorkflowTaskStopApi()
|
||||
result = unwrap(api.post)(
|
||||
api,
|
||||
app_model=mock_workflow_app,
|
||||
end_user=Mock(),
|
||||
app_model=workflow_app,
|
||||
end_user=_make_end_user(),
|
||||
task_id="task-1",
|
||||
)
|
||||
|
||||
@ -628,13 +792,12 @@ class TestWorkflowTaskStopApiPost:
|
||||
"""Test NotWorkflowAppError when app mode is not workflow."""
|
||||
from controllers.service_api.app.workflow import WorkflowTaskStopApi
|
||||
|
||||
mock_app = Mock(spec=App)
|
||||
mock_app.mode = AppMode.COMPLETION.value
|
||||
app_model = _make_app_model(mode=AppMode.COMPLETION)
|
||||
|
||||
with app.test_request_context("/workflows/tasks/task-1/stop", method="POST"):
|
||||
api = WorkflowTaskStopApi()
|
||||
with pytest.raises(NotWorkflowAppError):
|
||||
unwrap(api.post)(api, app_model=mock_app, end_user=Mock(), task_id="task-1")
|
||||
unwrap(api.post)(api, app_model=app_model, end_user=_make_end_user(), task_id="task-1")
|
||||
|
||||
|
||||
class TestWorkflowAppLogApiGet:
|
||||
@ -650,27 +813,23 @@ class TestWorkflowAppLogApiGet:
|
||||
mock_db,
|
||||
mock_wf_svc_cls,
|
||||
app: Flask,
|
||||
mock_workflow_app,
|
||||
workflow_app: App,
|
||||
):
|
||||
"""Test successful workflow log retrieval."""
|
||||
mock_pagination = Mock()
|
||||
mock_pagination.page = 1
|
||||
mock_pagination.limit = 20
|
||||
mock_pagination.total = 0
|
||||
mock_pagination.has_more = False
|
||||
mock_pagination.data = []
|
||||
mock_svc_instance = Mock()
|
||||
mock_svc_instance.get_paginate_workflow_app_logs.return_value = mock_pagination
|
||||
mock_svc_instance.get_paginate_workflow_app_logs.return_value = _make_workflow_log_page()
|
||||
mock_wf_svc_cls.return_value = mock_svc_instance
|
||||
mock_repo = _WorkflowRunRepositoryStub(
|
||||
run=_make_workflow_run(
|
||||
run_id="log-run-1",
|
||||
created_at=datetime(2026, 1, 1, 1, tzinfo=UTC),
|
||||
finished_at=datetime(2026, 1, 1, 1, 0, 2, tzinfo=UTC),
|
||||
)
|
||||
)
|
||||
|
||||
# Mock sessionmaker(...).begin() context manager
|
||||
mock_session = Mock()
|
||||
mock_db.engine = Mock()
|
||||
mock_begin = Mock()
|
||||
mock_begin.__enter__ = Mock(return_value=mock_session)
|
||||
mock_begin.__exit__ = Mock(return_value=False)
|
||||
mock_session_factory = Mock()
|
||||
mock_session_factory.begin.return_value = mock_begin
|
||||
mock_db.engine = object()
|
||||
mock_db.session.get.return_value = None
|
||||
|
||||
from controllers.service_api.app.workflow import WorkflowAppLogApi
|
||||
|
||||
@ -678,8 +837,15 @@ class TestWorkflowAppLogApiGet:
|
||||
"/workflows/logs?page=1&limit=20",
|
||||
method="GET",
|
||||
):
|
||||
with patch("controllers.service_api.app.workflow.sessionmaker", return_value=mock_session_factory):
|
||||
with (
|
||||
patch("controllers.service_api.app.workflow.sessionmaker", _SessionMakerStub),
|
||||
patch("models.workflow.db", _DbStub()),
|
||||
patch(
|
||||
"repositories.factory.DifyAPIRepositoryFactory.create_api_workflow_run_repository",
|
||||
return_value=mock_repo,
|
||||
),
|
||||
):
|
||||
api = WorkflowAppLogApi()
|
||||
result = unwrap(api.get)(api, app_model=mock_workflow_app)
|
||||
result = unwrap(api.get)(api, app_model=workflow_app)
|
||||
|
||||
assert result == {"page": 1, "limit": 20, "total": 0, "has_more": False, "data": []}
|
||||
assert result == _expected_workflow_log_pagination_payload()
|
||||
|
||||
@ -1,25 +1,36 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from controllers.service_api.app.workflow import WorkflowRunOutputsField, WorkflowRunStatusField
|
||||
from controllers.service_api.app.workflow import WorkflowRunResponse
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from libs.helper import dump_response
|
||||
from models.workflow import WorkflowRun
|
||||
|
||||
|
||||
def test_workflow_run_status_field_with_enum() -> None:
|
||||
field = WorkflowRunStatusField()
|
||||
obj = SimpleNamespace(status=WorkflowExecutionStatus.PAUSED)
|
||||
|
||||
assert field.output("status", obj) == "paused"
|
||||
def _workflow_run(status: WorkflowExecutionStatus, outputs: str | None = '{"foo": "bar"}') -> WorkflowRun:
|
||||
return WorkflowRun(
|
||||
id="run-id",
|
||||
workflow_id="workflow-id",
|
||||
status=status,
|
||||
inputs="{}",
|
||||
outputs=outputs,
|
||||
error=None,
|
||||
total_steps=1,
|
||||
total_tokens=2,
|
||||
elapsed_time=3.5,
|
||||
)
|
||||
|
||||
|
||||
def test_workflow_run_outputs_field_paused_returns_empty() -> None:
|
||||
field = WorkflowRunOutputsField()
|
||||
obj = SimpleNamespace(status=WorkflowExecutionStatus.PAUSED, outputs_dict={"foo": "bar"})
|
||||
def test_workflow_run_serializer_normalizes_status_enum() -> None:
|
||||
response = dump_response(WorkflowRunResponse, _workflow_run(WorkflowExecutionStatus.PAUSED))
|
||||
|
||||
assert field.output("outputs", obj) == {}
|
||||
assert response["status"] == "paused"
|
||||
|
||||
|
||||
def test_workflow_run_outputs_field_running_returns_outputs() -> None:
|
||||
field = WorkflowRunOutputsField()
|
||||
obj = SimpleNamespace(status=WorkflowExecutionStatus.RUNNING, outputs_dict={"foo": "bar"})
|
||||
def test_workflow_run_serializer_paused_returns_empty_outputs() -> None:
|
||||
response = dump_response(WorkflowRunResponse, _workflow_run(WorkflowExecutionStatus.PAUSED))
|
||||
|
||||
assert field.output("outputs", obj) == {"foo": "bar"}
|
||||
assert response["outputs"] == {}
|
||||
|
||||
|
||||
def test_workflow_run_serializer_running_returns_outputs() -> None:
|
||||
response = dump_response(WorkflowRunResponse, _workflow_run(WorkflowExecutionStatus.RUNNING))
|
||||
|
||||
assert response["outputs"] == {"foo": "bar"}
|
||||
|
||||
@ -12,7 +12,7 @@ export type AccountAvatarPayload = {
|
||||
avatar: string
|
||||
}
|
||||
|
||||
export type Account = {
|
||||
export type AccountResponse = {
|
||||
avatar?: string | null
|
||||
readonly avatar_url: string | null
|
||||
created_at?: number | null
|
||||
@ -140,7 +140,7 @@ export type AccountIntegrateResponse = {
|
||||
provider: string
|
||||
}
|
||||
|
||||
export type AccountWritable = {
|
||||
export type AccountResponseWritable = {
|
||||
avatar?: string | null
|
||||
created_at?: number | null
|
||||
email: string
|
||||
@ -177,7 +177,7 @@ export type PostAccountAvatarData = {
|
||||
}
|
||||
|
||||
export type PostAccountAvatarResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountAvatarResponse = PostAccountAvatarResponses[keyof PostAccountAvatarResponses]
|
||||
@ -218,7 +218,7 @@ export type PostAccountChangeEmailResetData = {
|
||||
}
|
||||
|
||||
export type PostAccountChangeEmailResetResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountChangeEmailResetResponse
|
||||
@ -374,7 +374,7 @@ export type PostAccountInterfaceLanguageData = {
|
||||
}
|
||||
|
||||
export type PostAccountInterfaceLanguageResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountInterfaceLanguageResponse
|
||||
@ -388,7 +388,7 @@ export type PostAccountInterfaceThemeData = {
|
||||
}
|
||||
|
||||
export type PostAccountInterfaceThemeResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountInterfaceThemeResponse
|
||||
@ -402,7 +402,7 @@ export type PostAccountNameData = {
|
||||
}
|
||||
|
||||
export type PostAccountNameResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountNameResponse = PostAccountNameResponses[keyof PostAccountNameResponses]
|
||||
@ -415,7 +415,7 @@ export type PostAccountPasswordData = {
|
||||
}
|
||||
|
||||
export type PostAccountPasswordResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountPasswordResponse
|
||||
@ -429,7 +429,7 @@ export type GetAccountProfileData = {
|
||||
}
|
||||
|
||||
export type GetAccountProfileResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type GetAccountProfileResponse = GetAccountProfileResponses[keyof GetAccountProfileResponses]
|
||||
@ -442,7 +442,7 @@ export type PostAccountTimezoneData = {
|
||||
}
|
||||
|
||||
export type PostAccountTimezoneResponses = {
|
||||
200: Account
|
||||
200: AccountResponse
|
||||
}
|
||||
|
||||
export type PostAccountTimezoneResponse
|
||||
|
||||
@ -17,9 +17,9 @@ export const zAccountAvatarPayload = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Account
|
||||
* AccountResponse
|
||||
*/
|
||||
export const zAccount = z.object({
|
||||
export const zAccountResponse = z.object({
|
||||
avatar: z.string().nullish(),
|
||||
avatar_url: z.string().nullable(),
|
||||
created_at: z.int().nullish(),
|
||||
@ -212,9 +212,9 @@ export const zAccountIntegrateListResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* Account
|
||||
* AccountResponse
|
||||
*/
|
||||
export const zAccountWritable = z.object({
|
||||
export const zAccountResponseWritable = z.object({
|
||||
avatar: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
email: z.string(),
|
||||
@ -242,7 +242,7 @@ export const zPostAccountAvatarBody = zAccountAvatarPayload
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountAvatarResponse = zAccount
|
||||
export const zPostAccountAvatarResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountChangeEmailBody = zChangeEmailSendPayload
|
||||
|
||||
@ -263,7 +263,7 @@ export const zPostAccountChangeEmailResetBody = zChangeEmailResetPayload
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountChangeEmailResetResponse = zAccount
|
||||
export const zPostAccountChangeEmailResetResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountChangeEmailValidityBody = zChangeEmailValidityPayload
|
||||
|
||||
@ -336,37 +336,37 @@ export const zPostAccountInterfaceLanguageBody = zAccountInterfaceLanguagePayloa
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountInterfaceLanguageResponse = zAccount
|
||||
export const zPostAccountInterfaceLanguageResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountInterfaceThemeBody = zAccountInterfaceThemePayload
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountInterfaceThemeResponse = zAccount
|
||||
export const zPostAccountInterfaceThemeResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountNameBody = zAccountNamePayload
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountNameResponse = zAccount
|
||||
export const zPostAccountNameResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountPasswordBody = zAccountPasswordPayload
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountPasswordResponse = zAccount
|
||||
export const zPostAccountPasswordResponse = zAccountResponse
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetAccountProfileResponse = zAccount
|
||||
export const zGetAccountProfileResponse = zAccountResponse
|
||||
|
||||
export const zPostAccountTimezoneBody = zAccountTimezonePayload
|
||||
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zPostAccountTimezoneResponse = zAccount
|
||||
export const zPostAccountTimezoneResponse = zAccountResponse
|
||||
|
||||
@ -269,6 +269,7 @@ export type MessageDetailResponse = {
|
||||
agent_thoughts?: Array<AgentThought>
|
||||
annotation?: ConversationAnnotation | null
|
||||
annotation_hit_history?: ConversationAnnotationHitHistory | null
|
||||
answer: string
|
||||
answer_tokens?: number | null
|
||||
conversation_id: string
|
||||
created_at?: number | null
|
||||
@ -284,12 +285,11 @@ export type MessageDetailResponse = {
|
||||
}
|
||||
message?: JsonValue | null
|
||||
message_files?: Array<MessageFile>
|
||||
message_metadata_dict?: JsonValue | null
|
||||
message_tokens?: number | null
|
||||
metadata?: JsonValue | null
|
||||
parent_message_id?: string | null
|
||||
provider_response_latency?: number | null
|
||||
query: string
|
||||
re_sign_file_url_answer: string
|
||||
status: string
|
||||
workflow_run_id?: string | null
|
||||
}
|
||||
@ -723,7 +723,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
@ -743,8 +742,8 @@ export type ConversationAnnotation = {
|
||||
|
||||
export type ConversationAnnotationHitHistory = {
|
||||
annotation_create_account?: SimpleAccount | null
|
||||
annotation_id: string
|
||||
created_at?: number | null
|
||||
id: string
|
||||
}
|
||||
|
||||
export type HumanInputContent = {
|
||||
|
||||
@ -570,7 +570,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
@ -1056,8 +1055,8 @@ export const zConversationAnnotation = z.object({
|
||||
*/
|
||||
export const zConversationAnnotationHitHistory = z.object({
|
||||
annotation_create_account: zSimpleAccount.nullish(),
|
||||
annotation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -2035,6 +2034,7 @@ export const zMessageDetailResponse = z.object({
|
||||
agent_thoughts: z.array(zAgentThought).optional(),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer: z.string(),
|
||||
answer_tokens: z.int().nullish(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
@ -2048,12 +2048,11 @@ export const zMessageDetailResponse = z.object({
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue.nullish(),
|
||||
message_files: z.array(zMessageFile).optional(),
|
||||
message_metadata_dict: zJsonValue.nullish(),
|
||||
message_tokens: z.int().nullish(),
|
||||
metadata: zJsonValue.nullish(),
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number().nullish(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
@ -472,6 +472,7 @@ export type MessageDetailResponse = {
|
||||
agent_thoughts?: Array<AgentThought>
|
||||
annotation?: ConversationAnnotation | null
|
||||
annotation_hit_history?: ConversationAnnotationHitHistory | null
|
||||
answer: string
|
||||
answer_tokens?: number | null
|
||||
conversation_id: string
|
||||
created_at?: number | null
|
||||
@ -487,12 +488,11 @@ export type MessageDetailResponse = {
|
||||
}
|
||||
message?: JsonValue | null
|
||||
message_files?: Array<MessageFile>
|
||||
message_metadata_dict?: JsonValue | null
|
||||
message_tokens?: number | null
|
||||
metadata?: JsonValue | null
|
||||
parent_message_id?: string | null
|
||||
provider_response_latency?: number | null
|
||||
query: string
|
||||
re_sign_file_url_answer: string
|
||||
status: string
|
||||
workflow_run_id?: string | null
|
||||
}
|
||||
@ -731,7 +731,7 @@ export type WorkflowRunPaginationResponse = {
|
||||
|
||||
export type WorkflowRunDetailResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -799,7 +799,7 @@ export type WorkflowCommentCreate = {
|
||||
}
|
||||
|
||||
export type WorkflowCommentMentionUsersPayload = {
|
||||
users: Array<AccountWithRole>
|
||||
users: Array<AccountWithRoleResponse>
|
||||
}
|
||||
|
||||
export type WorkflowCommentDetail = {
|
||||
@ -887,7 +887,7 @@ export type DefaultBlockConfigResponse = {
|
||||
export type WorkflowResponse = {
|
||||
conversation_variables: Array<WorkflowConversationVariableResponse>
|
||||
created_at: number
|
||||
created_by?: SimpleAccount | null
|
||||
created_by?: SimpleAccountResponse | null
|
||||
environment_variables: Array<WorkflowEnvironmentVariableResponse>
|
||||
features: {
|
||||
[key: string]: unknown
|
||||
@ -902,7 +902,7 @@ export type WorkflowResponse = {
|
||||
rag_pipeline_variables: Array<PipelineVariableResponse>
|
||||
tool_published: boolean
|
||||
updated_at: number
|
||||
updated_by?: SimpleAccount | null
|
||||
updated_by?: SimpleAccountResponse | null
|
||||
version: string
|
||||
}
|
||||
|
||||
@ -1029,7 +1029,7 @@ export type AgentComposerValidateResponse = {
|
||||
|
||||
export type WorkflowRunNodeExecutionResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -1289,7 +1289,7 @@ export type WorkflowOnlineUsersByApp = {
|
||||
export type AdvancedChatWorkflowRunForListResponse = {
|
||||
conversation_id?: string | null
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
elapsed_time?: number | null
|
||||
exceptions_count?: number | null
|
||||
finished_at?: number | null
|
||||
@ -1498,7 +1498,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
@ -1518,8 +1517,8 @@ export type ConversationAnnotation = {
|
||||
|
||||
export type ConversationAnnotationHitHistory = {
|
||||
annotation_create_account?: SimpleAccount | null
|
||||
annotation_id: string
|
||||
created_at?: number | null
|
||||
id: string
|
||||
}
|
||||
|
||||
export type HumanInputContent = {
|
||||
@ -1596,7 +1595,7 @@ export type UserSatisfactionRateStatisticItem = {
|
||||
|
||||
export type WorkflowAppLogPartialResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
created_from?: string | null
|
||||
@ -1607,7 +1606,7 @@ export type WorkflowAppLogPartialResponse = {
|
||||
|
||||
export type WorkflowArchivedLogPartialResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
id: string
|
||||
trigger_metadata?: unknown
|
||||
@ -1616,7 +1615,7 @@ export type WorkflowArchivedLogPartialResponse = {
|
||||
|
||||
export type WorkflowRunForListResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
elapsed_time?: number | null
|
||||
exceptions_count?: number | null
|
||||
finished_at?: number | null
|
||||
@ -1628,7 +1627,7 @@ export type WorkflowRunForListResponse = {
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type SimpleAccount = {
|
||||
export type SimpleAccountResponse = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
@ -1671,7 +1670,7 @@ export type WorkflowCommentBasic = {
|
||||
updated_at?: number | null
|
||||
}
|
||||
|
||||
export type AccountWithRole = {
|
||||
export type AccountWithRoleResponse = {
|
||||
avatar?: string | null
|
||||
created_at?: number | null
|
||||
email: string
|
||||
@ -2054,6 +2053,12 @@ export type SimpleMessageDetail = {
|
||||
query: string
|
||||
}
|
||||
|
||||
export type SimpleAccount = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export type HumanInputFormDefinition = {
|
||||
actions?: Array<UserActionConfig>
|
||||
display_in_ui?: boolean
|
||||
|
||||
@ -1150,7 +1150,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
@ -1319,9 +1318,9 @@ export const zUserSatisfactionRateStatisticResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
* SimpleAccountResponse
|
||||
*/
|
||||
export const zSimpleAccount = z.object({
|
||||
export const zSimpleAccountResponse = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
@ -1333,7 +1332,7 @@ export const zSimpleAccount = z.object({
|
||||
export const zAdvancedChatWorkflowRunForListResponse = z.object({
|
||||
conversation_id: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
exceptions_count: z.int().nullish(),
|
||||
finished_at: z.int().nullish(),
|
||||
@ -1355,72 +1354,12 @@ export const zAdvancedChatWorkflowRunPaginationResponse = z.object({
|
||||
limit: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationAnnotation
|
||||
*/
|
||||
export const zConversationAnnotation = z.object({
|
||||
account: zSimpleAccount.nullish(),
|
||||
content: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
question: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationAnnotationHitHistory
|
||||
*/
|
||||
export const zConversationAnnotationHitHistory = z.object({
|
||||
annotation_create_account: zSimpleAccount.nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Feedback
|
||||
*/
|
||||
export const zFeedback = z.object({
|
||||
content: z.string().nullish(),
|
||||
from_account: zSimpleAccount.nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
rating: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* MessageDetail
|
||||
*/
|
||||
export const zMessageDetail = z.object({
|
||||
agent_thoughts: z.array(zAgentThought),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer_tokens: z.int(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
error: z.string().nullish(),
|
||||
feedbacks: z.array(zFeedback),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue,
|
||||
message_files: z.array(zMessageFile),
|
||||
message_metadata_dict: zJsonValue,
|
||||
message_tokens: z.int(),
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* WorkflowRunForListResponse
|
||||
*/
|
||||
export const zWorkflowRunForListResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
exceptions_count: z.int().nullish(),
|
||||
finished_at: z.int().nullish(),
|
||||
@ -1456,7 +1395,7 @@ export const zSimpleEndUser = z.object({
|
||||
*/
|
||||
export const zWorkflowRunDetailResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -1478,7 +1417,7 @@ export const zWorkflowRunDetailResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowRunNodeExecutionResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -1544,9 +1483,9 @@ export const zSandboxUploadResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* AccountWithRole
|
||||
* AccountWithRoleResponse
|
||||
*/
|
||||
export const zAccountWithRole = z.object({
|
||||
export const zAccountWithRoleResponse = z.object({
|
||||
avatar: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
email: z.string(),
|
||||
@ -1563,7 +1502,7 @@ export const zAccountWithRole = z.object({
|
||||
* WorkflowCommentMentionUsersPayload
|
||||
*/
|
||||
export const zWorkflowCommentMentionUsersPayload = z.object({
|
||||
users: z.array(zAccountWithRole),
|
||||
users: z.array(zAccountWithRoleResponse),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -1752,7 +1691,7 @@ export const zPipelineVariableResponse = z.object({
|
||||
export const zWorkflowResponse = z.object({
|
||||
conversation_variables: z.array(zWorkflowConversationVariableResponse),
|
||||
created_at: z.int(),
|
||||
created_by: zSimpleAccount.nullish(),
|
||||
created_by: zSimpleAccountResponse.nullish(),
|
||||
environment_variables: z.array(zWorkflowEnvironmentVariableResponse),
|
||||
features: z.record(z.string(), z.unknown()),
|
||||
graph: z.record(z.string(), z.unknown()),
|
||||
@ -1763,7 +1702,7 @@ export const zWorkflowResponse = z.object({
|
||||
rag_pipeline_variables: z.array(zPipelineVariableResponse),
|
||||
tool_published: z.boolean(),
|
||||
updated_at: z.int(),
|
||||
updated_by: zSimpleAccount.nullish(),
|
||||
updated_by: zSimpleAccountResponse.nullish(),
|
||||
version: z.string(),
|
||||
})
|
||||
|
||||
@ -2152,20 +2091,6 @@ export const zConversationDetail = z.object({
|
||||
user_feedback_stats: zFeedbackStat.nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationMessageDetail
|
||||
*/
|
||||
export const zConversationMessageDetail = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
first_message: zMessageDetail.nullish(),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
model_config: zModelConfig.nullish(),
|
||||
status: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Type
|
||||
*/
|
||||
@ -2366,6 +2291,26 @@ export const zSimpleMessageDetail = z.object({
|
||||
query: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
*/
|
||||
export const zSimpleAccount = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationAnnotation
|
||||
*/
|
||||
export const zConversationAnnotation = z.object({
|
||||
account: zSimpleAccount.nullish(),
|
||||
content: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
question: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Conversation
|
||||
*/
|
||||
@ -2398,6 +2343,69 @@ export const zConversationPagination = z.object({
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationAnnotationHitHistory
|
||||
*/
|
||||
export const zConversationAnnotationHitHistory = z.object({
|
||||
annotation_create_account: zSimpleAccount.nullish(),
|
||||
annotation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Feedback
|
||||
*/
|
||||
export const zFeedback = z.object({
|
||||
content: z.string().nullish(),
|
||||
from_account: zSimpleAccount.nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
rating: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* MessageDetail
|
||||
*/
|
||||
export const zMessageDetail = z.object({
|
||||
agent_thoughts: z.array(zAgentThought),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer_tokens: z.int(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
error: z.string().nullish(),
|
||||
feedbacks: z.array(zFeedback),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue,
|
||||
message_files: z.array(zMessageFile),
|
||||
message_metadata_dict: zJsonValue,
|
||||
message_tokens: z.int(),
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConversationMessageDetail
|
||||
*/
|
||||
export const zConversationMessageDetail = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
first_message: zMessageDetail.nullish(),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
model_config: zModelConfig.nullish(),
|
||||
status: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* ExecutionContentType
|
||||
*/
|
||||
@ -2425,7 +2433,7 @@ export const zWorkflowRunForLogResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowAppLogPartialResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
created_from: z.string().nullish(),
|
||||
@ -2461,7 +2469,7 @@ export const zWorkflowRunForArchivedLogResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowArchivedLogPartialResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
id: z.string(),
|
||||
trigger_metadata: z.unknown().optional(),
|
||||
@ -3455,6 +3463,7 @@ export const zMessageDetailResponse = z.object({
|
||||
agent_thoughts: z.array(zAgentThought).optional(),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer: z.string(),
|
||||
answer_tokens: z.int().nullish(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
@ -3468,12 +3477,11 @@ export const zMessageDetailResponse = z.object({
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue.nullish(),
|
||||
message_files: z.array(zMessageFile).optional(),
|
||||
message_metadata_dict: zJsonValue.nullish(),
|
||||
message_tokens: z.int().nullish(),
|
||||
metadata: zJsonValue.nullish(),
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number().nullish(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
@ -246,7 +246,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
|
||||
@ -266,7 +266,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
|
||||
@ -119,7 +119,7 @@ export type SimpleResultResponse = {
|
||||
|
||||
export type WorkflowRunDetailResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -158,7 +158,7 @@ export type DefaultBlockConfigResponse = {
|
||||
export type WorkflowResponse = {
|
||||
conversation_variables: Array<WorkflowConversationVariableResponse>
|
||||
created_at: number
|
||||
created_by?: SimpleAccount | null
|
||||
created_by?: SimpleAccountResponse | null
|
||||
environment_variables: Array<WorkflowEnvironmentVariableResponse>
|
||||
features: {
|
||||
[key: string]: unknown
|
||||
@ -173,7 +173,7 @@ export type WorkflowResponse = {
|
||||
rag_pipeline_variables: Array<PipelineVariableResponse>
|
||||
tool_published: boolean
|
||||
updated_at: number
|
||||
updated_by?: SimpleAccount | null
|
||||
updated_by?: SimpleAccountResponse | null
|
||||
version: string
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ export type DatasourceVariablesPayload = {
|
||||
|
||||
export type WorkflowRunNodeExecutionResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -421,7 +421,7 @@ export type PluginDependency = {
|
||||
|
||||
export type WorkflowRunForListResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
elapsed_time?: number | null
|
||||
exceptions_count?: number | null
|
||||
finished_at?: number | null
|
||||
@ -433,7 +433,7 @@ export type WorkflowRunForListResponse = {
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type SimpleAccount = {
|
||||
export type SimpleAccountResponse = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
|
||||
@ -322,9 +322,9 @@ export const zPipelineTemplateListResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
* SimpleAccountResponse
|
||||
*/
|
||||
export const zSimpleAccount = z.object({
|
||||
export const zSimpleAccountResponse = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
@ -335,7 +335,7 @@ export const zSimpleAccount = z.object({
|
||||
*/
|
||||
export const zWorkflowRunForListResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
exceptions_count: z.int().nullish(),
|
||||
finished_at: z.int().nullish(),
|
||||
@ -371,7 +371,7 @@ export const zSimpleEndUser = z.object({
|
||||
*/
|
||||
export const zWorkflowRunDetailResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -393,7 +393,7 @@ export const zWorkflowRunDetailResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowRunNodeExecutionResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -471,7 +471,7 @@ export const zPipelineVariableResponse = z.object({
|
||||
export const zWorkflowResponse = z.object({
|
||||
conversation_variables: z.array(zWorkflowConversationVariableResponse),
|
||||
created_at: z.int(),
|
||||
created_by: zSimpleAccount.nullish(),
|
||||
created_by: zSimpleAccountResponse.nullish(),
|
||||
environment_variables: z.array(zWorkflowEnvironmentVariableResponse),
|
||||
features: z.record(z.string(), z.unknown()),
|
||||
graph: z.record(z.string(), z.unknown()),
|
||||
@ -482,7 +482,7 @@ export const zWorkflowResponse = z.object({
|
||||
rag_pipeline_variables: z.array(zPipelineVariableResponse),
|
||||
tool_published: z.boolean(),
|
||||
updated_at: z.int(),
|
||||
updated_by: zSimpleAccount.nullish(),
|
||||
updated_by: zSimpleAccountResponse.nullish(),
|
||||
version: z.string(),
|
||||
})
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ export type SimpleResultResponse = {
|
||||
|
||||
export type WorkflowRunDetailResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -51,7 +51,7 @@ export type DefaultBlockConfigsResponse = Array<{
|
||||
export type SnippetWorkflowResponse = {
|
||||
conversation_variables: Array<WorkflowConversationVariableResponse>
|
||||
created_at: number
|
||||
created_by?: SimpleAccount | null
|
||||
created_by?: SimpleAccountResponse | null
|
||||
environment_variables: Array<WorkflowEnvironmentVariableResponse>
|
||||
features: {
|
||||
[key: string]: unknown
|
||||
@ -69,7 +69,7 @@ export type SnippetWorkflowResponse = {
|
||||
rag_pipeline_variables: Array<PipelineVariableResponse>
|
||||
tool_published: boolean
|
||||
updated_at: number
|
||||
updated_by?: SimpleAccount | null
|
||||
updated_by?: SimpleAccountResponse | null
|
||||
version: string
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ export type SnippetLoopNodeRunPayload = {
|
||||
|
||||
export type WorkflowRunNodeExecutionResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
elapsed_time?: number | null
|
||||
@ -210,7 +210,7 @@ export type WorkflowPublishResponse = {
|
||||
|
||||
export type WorkflowRunForListResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
elapsed_time?: number | null
|
||||
exceptions_count?: number | null
|
||||
finished_at?: number | null
|
||||
@ -222,7 +222,7 @@ export type WorkflowRunForListResponse = {
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type SimpleAccount = {
|
||||
export type SimpleAccountResponse = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
|
||||
@ -134,9 +134,9 @@ export const zWorkflowPublishResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
* SimpleAccountResponse
|
||||
*/
|
||||
export const zSimpleAccount = z.object({
|
||||
export const zSimpleAccountResponse = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
@ -147,7 +147,7 @@ export const zSimpleAccount = z.object({
|
||||
*/
|
||||
export const zWorkflowRunForListResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
exceptions_count: z.int().nullish(),
|
||||
finished_at: z.int().nullish(),
|
||||
@ -183,7 +183,7 @@ export const zSimpleEndUser = z.object({
|
||||
*/
|
||||
export const zWorkflowRunDetailResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -205,7 +205,7 @@ export const zWorkflowRunDetailResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowRunNodeExecutionResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
elapsed_time: z.number().nullish(),
|
||||
@ -283,7 +283,7 @@ export const zPipelineVariableResponse = z.object({
|
||||
export const zSnippetWorkflowResponse = z.object({
|
||||
conversation_variables: z.array(zWorkflowConversationVariableResponse),
|
||||
created_at: z.int(),
|
||||
created_by: zSimpleAccount.nullish(),
|
||||
created_by: zSimpleAccountResponse.nullish(),
|
||||
environment_variables: z.array(zWorkflowEnvironmentVariableResponse),
|
||||
features: z.record(z.string(), z.unknown()),
|
||||
graph: z.record(z.string(), z.unknown()),
|
||||
@ -295,7 +295,7 @@ export const zSnippetWorkflowResponse = z.object({
|
||||
rag_pipeline_variables: z.array(zPipelineVariableResponse),
|
||||
tool_published: z.boolean(),
|
||||
updated_at: z.int(),
|
||||
updated_by: zSimpleAccount.nullish(),
|
||||
updated_by: zSimpleAccountResponse.nullish(),
|
||||
version: z.string(),
|
||||
})
|
||||
|
||||
|
||||
@ -104,8 +104,8 @@ export type SnippetUseCountResponse = {
|
||||
use_count: number
|
||||
}
|
||||
|
||||
export type AccountWithRoleList = {
|
||||
accounts: Array<AccountWithRole>
|
||||
export type AccountWithRoleListResponse = {
|
||||
accounts: Array<AccountWithRoleResponse>
|
||||
}
|
||||
|
||||
export type DefaultModelDataResponse = {
|
||||
@ -921,7 +921,7 @@ export type AnonymousInlineModel7B8B49Ca164e = {
|
||||
type?: string
|
||||
}
|
||||
|
||||
export type AccountWithRole = {
|
||||
export type AccountWithRoleResponse = {
|
||||
avatar?: string | null
|
||||
created_at?: number | null
|
||||
email: string
|
||||
@ -1777,7 +1777,7 @@ export type GetWorkspacesCurrentDatasetOperatorsData = {
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentDatasetOperatorsResponses = {
|
||||
200: AccountWithRoleList
|
||||
200: AccountWithRoleListResponse
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentDatasetOperatorsResponse
|
||||
@ -2004,7 +2004,7 @@ export type GetWorkspacesCurrentMembersData = {
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentMembersResponses = {
|
||||
200: AccountWithRoleList
|
||||
200: AccountWithRoleListResponse
|
||||
}
|
||||
|
||||
export type GetWorkspacesCurrentMembersResponse
|
||||
|
||||
@ -889,9 +889,9 @@ export const zSnippetPagination = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* AccountWithRole
|
||||
* AccountWithRoleResponse
|
||||
*/
|
||||
export const zAccountWithRole = z.object({
|
||||
export const zAccountWithRoleResponse = z.object({
|
||||
avatar: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
email: z.string(),
|
||||
@ -905,10 +905,10 @@ export const zAccountWithRole = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* AccountWithRoleList
|
||||
* AccountWithRoleListResponse
|
||||
*/
|
||||
export const zAccountWithRoleList = z.object({
|
||||
accounts: z.array(zAccountWithRole),
|
||||
export const zAccountWithRoleListResponse = z.object({
|
||||
accounts: z.array(zAccountWithRoleResponse),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -2274,7 +2274,7 @@ export const zPostWorkspacesCurrentCustomizedSnippetsBySnippetIdUseCountIncremen
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetWorkspacesCurrentDatasetOperatorsResponse = zAccountWithRoleList
|
||||
export const zGetWorkspacesCurrentDatasetOperatorsResponse = zAccountWithRoleListResponse
|
||||
|
||||
export const zGetWorkspacesCurrentDefaultModelQuery = z.object({
|
||||
model_type: z.enum(['llm', 'moderation', 'rerank', 'speech2text', 'text-embedding', 'tts']),
|
||||
@ -2378,7 +2378,7 @@ export const zPatchWorkspacesCurrentEndpointsByIdResponse = zEndpointUpdateRespo
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetWorkspacesCurrentMembersResponse = zAccountWithRoleList
|
||||
export const zGetWorkspacesCurrentMembersResponse = zAccountWithRoleListResponse
|
||||
|
||||
export const zPostWorkspacesCurrentMembersInviteEmailBody = zMemberInvitePayload
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ export type AgentThought = {
|
||||
}
|
||||
|
||||
export type Annotation = {
|
||||
content?: string | null
|
||||
answer?: string | null
|
||||
created_at?: number | null
|
||||
hit_count?: number | null
|
||||
id: string
|
||||
@ -31,10 +31,15 @@ export type AnnotationCreatePayload = {
|
||||
question: string
|
||||
}
|
||||
|
||||
export type AnnotationJobStatusResponse = {
|
||||
error_msg?: string | null
|
||||
export type AnnotationJobStatusDetailResponse = {
|
||||
error_msg?: string
|
||||
job_id: string
|
||||
job_status: string
|
||||
job_status: 'completed' | 'error' | 'processing' | 'waiting' | string
|
||||
}
|
||||
|
||||
export type AnnotationJobStatusResponse = {
|
||||
job_id: string
|
||||
job_status: 'completed' | 'error' | 'processing' | 'waiting' | string
|
||||
}
|
||||
|
||||
export type AnnotationList = {
|
||||
@ -1414,7 +1419,7 @@ export type SelectInputConfig = {
|
||||
type?: 'select'
|
||||
}
|
||||
|
||||
export type SimpleAccount = {
|
||||
export type SimpleAccountResponse = {
|
||||
email: string
|
||||
id: string
|
||||
name: string
|
||||
@ -1572,7 +1577,7 @@ export type WorkflowAppLogPaginationResponse = {
|
||||
|
||||
export type WorkflowAppLogPartialResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
created_by_account?: SimpleAccountResponse | null
|
||||
created_by_end_user?: SimpleEndUser | null
|
||||
created_by_role?: string | null
|
||||
created_from?: string | null
|
||||
@ -1768,7 +1773,7 @@ export type GetAppsAnnotationReplyByActionStatusByJobIdErrors = {
|
||||
}
|
||||
|
||||
export type GetAppsAnnotationReplyByActionStatusByJobIdResponses = {
|
||||
200: AnnotationJobStatusResponse
|
||||
200: AnnotationJobStatusDetailResponse
|
||||
}
|
||||
|
||||
export type GetAppsAnnotationReplyByActionStatusByJobIdResponse
|
||||
@ -1893,16 +1898,32 @@ export type PostChatMessagesData = {
|
||||
}
|
||||
|
||||
export type PostChatMessagesErrors = {
|
||||
400: unknown
|
||||
401: unknown
|
||||
403: unknown
|
||||
404: unknown
|
||||
429: unknown
|
||||
500: unknown
|
||||
400: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
401: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
403: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
404: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
429: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
500: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostChatMessagesError = PostChatMessagesErrors[keyof PostChatMessagesErrors]
|
||||
|
||||
export type PostChatMessagesResponses = {
|
||||
200: GeneratedAppResponse
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostChatMessagesResponse = PostChatMessagesResponses[keyof PostChatMessagesResponses]
|
||||
@ -1938,16 +1959,33 @@ export type PostCompletionMessagesData = {
|
||||
}
|
||||
|
||||
export type PostCompletionMessagesErrors = {
|
||||
400: unknown
|
||||
401: unknown
|
||||
403: unknown
|
||||
404: unknown
|
||||
429: unknown
|
||||
500: unknown
|
||||
400: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
401: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
403: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
404: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
429: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
500: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostCompletionMessagesError
|
||||
= PostCompletionMessagesErrors[keyof PostCompletionMessagesErrors]
|
||||
|
||||
export type PostCompletionMessagesResponses = {
|
||||
200: GeneratedAppResponse
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostCompletionMessagesResponse
|
||||
@ -3622,16 +3660,32 @@ export type PostWorkflowsRunData = {
|
||||
}
|
||||
|
||||
export type PostWorkflowsRunErrors = {
|
||||
400: unknown
|
||||
401: unknown
|
||||
403: unknown
|
||||
404: unknown
|
||||
429: unknown
|
||||
500: unknown
|
||||
400: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
401: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
403: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
404: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
429: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
500: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostWorkflowsRunError = PostWorkflowsRunErrors[keyof PostWorkflowsRunErrors]
|
||||
|
||||
export type PostWorkflowsRunResponses = {
|
||||
200: GeneratedAppResponse
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostWorkflowsRunResponse = PostWorkflowsRunResponses[keyof PostWorkflowsRunResponses]
|
||||
@ -3692,16 +3746,33 @@ export type PostWorkflowsByWorkflowIdRunData = {
|
||||
}
|
||||
|
||||
export type PostWorkflowsByWorkflowIdRunErrors = {
|
||||
400: unknown
|
||||
401: unknown
|
||||
403: unknown
|
||||
404: unknown
|
||||
429: unknown
|
||||
500: unknown
|
||||
400: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
401: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
403: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
404: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
429: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
500: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostWorkflowsByWorkflowIdRunError
|
||||
= PostWorkflowsByWorkflowIdRunErrors[keyof PostWorkflowsByWorkflowIdRunErrors]
|
||||
|
||||
export type PostWorkflowsByWorkflowIdRunResponses = {
|
||||
200: GeneratedAppResponse
|
||||
200: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type PostWorkflowsByWorkflowIdRunResponse
|
||||
|
||||
@ -6,7 +6,7 @@ import * as z from 'zod'
|
||||
* Annotation
|
||||
*/
|
||||
export const zAnnotation = z.object({
|
||||
content: z.string().nullish(),
|
||||
answer: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
hit_count: z.int().nullish(),
|
||||
id: z.string(),
|
||||
@ -21,13 +21,21 @@ export const zAnnotationCreatePayload = z.object({
|
||||
question: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationJobStatusDetailResponse
|
||||
*/
|
||||
export const zAnnotationJobStatusDetailResponse = z.object({
|
||||
error_msg: z.string().optional().default(''),
|
||||
job_id: z.string(),
|
||||
job_status: z.union([z.enum(['completed', 'error', 'processing', 'waiting']), z.string()]),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationJobStatusResponse
|
||||
*/
|
||||
export const zAnnotationJobStatusResponse = z.object({
|
||||
error_msg: z.string().nullish(),
|
||||
job_id: z.string(),
|
||||
job_status: z.string(),
|
||||
job_status: z.union([z.enum(['completed', 'error', 'processing', 'waiting']), z.string()]),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -1676,9 +1684,9 @@ export const zProcessRule = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
* SimpleAccountResponse
|
||||
*/
|
||||
export const zSimpleAccount = z.object({
|
||||
export const zSimpleAccountResponse = z.object({
|
||||
email: z.string(),
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
@ -2196,7 +2204,7 @@ export const zWorkflowRunForLogResponse = z.object({
|
||||
*/
|
||||
export const zWorkflowAppLogPartialResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by_account: zSimpleAccount.nullish(),
|
||||
created_by_account: zSimpleAccountResponse.nullish(),
|
||||
created_by_end_user: zSimpleEndUser.nullish(),
|
||||
created_by_role: z.string().nullish(),
|
||||
created_from: z.string().nullish(),
|
||||
@ -2351,7 +2359,8 @@ export const zGetAppsAnnotationReplyByActionStatusByJobIdPath = z.object({
|
||||
/**
|
||||
* Successfully retrieved task status.
|
||||
*/
|
||||
export const zGetAppsAnnotationReplyByActionStatusByJobIdResponse = zAnnotationJobStatusResponse
|
||||
export const zGetAppsAnnotationReplyByActionStatusByJobIdResponse
|
||||
= zAnnotationJobStatusDetailResponse
|
||||
|
||||
export const zGetAppsAnnotationsQuery = z.object({
|
||||
keyword: z.string().optional().default(''),
|
||||
@ -2409,7 +2418,7 @@ export const zPostChatMessagesBody = zChatRequestPayloadWithUser
|
||||
* - If `response_mode` is `blocking`, returns `application/json` with a `ChatCompletionResponse` object.
|
||||
* - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of Server-Sent Events.
|
||||
*/
|
||||
export const zPostChatMessagesResponse = zGeneratedAppResponse
|
||||
export const zPostChatMessagesResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
export const zPostChatMessagesByTaskIdStopBody = zRequiredServiceApiUserPayload
|
||||
|
||||
@ -2430,7 +2439,7 @@ export const zPostCompletionMessagesBody = zCompletionRequestPayloadWithUser
|
||||
* - If `response_mode` is `blocking`, returns `application/json` with a `CompletionResponse` object.
|
||||
* - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkCompletionEvent` objects.
|
||||
*/
|
||||
export const zPostCompletionMessagesResponse = zGeneratedAppResponse
|
||||
export const zPostCompletionMessagesResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
export const zPostCompletionMessagesByTaskIdStopBody = zRequiredServiceApiUserPayload
|
||||
|
||||
@ -3250,7 +3259,7 @@ export const zPostWorkflowsRunBody = zWorkflowRunPayloadWithUser
|
||||
* - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object.
|
||||
* - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects.
|
||||
*/
|
||||
export const zPostWorkflowsRunResponse = zGeneratedAppResponse
|
||||
export const zPostWorkflowsRunResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
export const zGetWorkflowsRunByWorkflowRunIdPath = z.object({
|
||||
workflow_run_id: z.string(),
|
||||
@ -3284,7 +3293,7 @@ export const zPostWorkflowsByWorkflowIdRunPath = z.object({
|
||||
* - If `response_mode` is `blocking`, returns `application/json` with a `WorkflowBlockingResponse` object.
|
||||
* - If `response_mode` is `streaming`, returns `text/event-stream` with a stream of `ChunkWorkflowEvent` objects.
|
||||
*/
|
||||
export const zPostWorkflowsByWorkflowIdRunResponse = zGeneratedAppResponse
|
||||
export const zPostWorkflowsByWorkflowIdRunResponse = z.record(z.string(), z.unknown())
|
||||
|
||||
export const zGetWorkspacesCurrentModelsModelTypesByModelTypePath = z.object({
|
||||
model_type: z.enum(['llm', 'moderation', 'rerank', 'speech2text', 'text-embedding', 'tts']),
|
||||
|
||||
@ -10,13 +10,21 @@ type SwaggerSchema = JsonObject & {
|
||||
$ref?: string
|
||||
}
|
||||
|
||||
type OpenApiMediaType = JsonObject & {
|
||||
schema?: SwaggerSchema
|
||||
}
|
||||
|
||||
type OpenApiResponse = JsonObject & {
|
||||
content?: Record<string, OpenApiMediaType>
|
||||
}
|
||||
|
||||
type OpenApiComponents = JsonObject & {
|
||||
schemas?: Record<string, SwaggerSchema>
|
||||
}
|
||||
|
||||
type SwaggerOperation = JsonObject & {
|
||||
operationId?: string
|
||||
responses?: Record<string, unknown>
|
||||
responses?: Record<string, OpenApiResponse>
|
||||
}
|
||||
|
||||
type SwaggerDocument = JsonObject & {
|
||||
@ -52,6 +60,17 @@ const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
const apiOpenApiDir = path.resolve(currentDir, 'openapi')
|
||||
|
||||
const operationMethods = new Set(['delete', 'get', 'patch', 'post', 'put'])
|
||||
const pydanticDecimalStringPattern = '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$'
|
||||
const codegenSafeDecimalStringPattern = '^(?![-+.]*$)[+-]?0*\\d*\\.?\\d*$'
|
||||
|
||||
const opaqueJsonContent = (): Record<string, OpenApiMediaType> => ({
|
||||
'application/json': {
|
||||
schema: {
|
||||
additionalProperties: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const apiSpecs: ApiSpec[] = [
|
||||
{ filename: 'console-openapi.json', name: 'console' },
|
||||
@ -182,6 +201,46 @@ const addOperationIds = (document: SwaggerDocument) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isOpaqueContractResponse = (response: OpenApiResponse) => {
|
||||
const content = response.content
|
||||
if (!isObject(content))
|
||||
return false
|
||||
|
||||
return Object.entries(content).some(([mediaType, media]) => {
|
||||
if (!isObject(media))
|
||||
return false
|
||||
|
||||
return (mediaType === 'application/json' || mediaType === 'text/event-stream') && !('schema' in media)
|
||||
})
|
||||
}
|
||||
|
||||
const hasOpaqueContractSuccessResponse = (operation: SwaggerOperation) => {
|
||||
return Object.entries(operation.responses ?? {}).some(([status, response]) => {
|
||||
return /^2\d\d$/.test(status) && isObject(response) && isOpaqueContractResponse(response)
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeOpaqueContractResponses = (document: SwaggerDocument) => {
|
||||
// Some backend endpoints has no schema (e.g. external) and will trap heyapi here
|
||||
// So we forge an opaque schema here
|
||||
for (const pathItem of Object.values(document.paths ?? {})) {
|
||||
for (const [method, operation] of Object.entries(pathItem)) {
|
||||
if (!operationMethods.has(method) || !isObject(operation))
|
||||
continue
|
||||
|
||||
const swaggerOperation = operation as SwaggerOperation
|
||||
if (!hasOpaqueContractSuccessResponse(swaggerOperation))
|
||||
continue
|
||||
|
||||
Object.values(swaggerOperation.responses ?? {})
|
||||
.filter(response => isObject(response) && isOpaqueContractResponse(response))
|
||||
.forEach((response) => {
|
||||
response.content = opaqueJsonContent()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hasSuccessResponse = (operation: SwaggerOperation) => {
|
||||
return Object.entries(operation.responses ?? {}).some(([status, response]) => {
|
||||
if (!/^2\d\d$/.test(status))
|
||||
@ -215,6 +274,7 @@ const filterContractOperations = (document: SwaggerDocument) => {
|
||||
}
|
||||
|
||||
const normalizeApiSwagger = (document: SwaggerDocument) => {
|
||||
normalizeOpaqueContractResponses(document)
|
||||
filterContractOperations(document)
|
||||
addOperationIds(document)
|
||||
|
||||
@ -380,10 +440,20 @@ const createApiConfig = (job: ApiJob): UserConfig => ({
|
||||
'name': 'zod',
|
||||
'~resolvers': {
|
||||
string: (ctx) => {
|
||||
if (ctx.schema.format !== 'binary')
|
||||
return undefined
|
||||
if (ctx.schema.format === 'binary')
|
||||
return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File')))
|
||||
|
||||
return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File')))
|
||||
if (ctx.schema.pattern === pydanticDecimalStringPattern) {
|
||||
// the pydantic generated regex will emit error like
|
||||
// regexp/no-useless-assertions, so patch the regex here
|
||||
return $(ctx.symbols.z)
|
||||
.attr('string')
|
||||
.call()
|
||||
.attr('regex')
|
||||
.call($.regexp(codegenSafeDecimalStringPattern))
|
||||
}
|
||||
|
||||
return undefined
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -217,14 +217,8 @@ const toFeedback = (feedback: NonNullable<MessageDetailResponse['feedbacks']>[nu
|
||||
}
|
||||
}
|
||||
|
||||
type AgentDebugMessageWithLegacyAnswer = MessageDetailResponse & {
|
||||
answer?: string | null
|
||||
}
|
||||
|
||||
const getAgentDebugMessageAnswer = (message: MessageDetailResponse) => {
|
||||
const legacyAnswer = (message as AgentDebugMessageWithLegacyAnswer).answer
|
||||
|
||||
return message.re_sign_file_url_answer ?? legacyAnswer ?? ''
|
||||
return message.answer ?? ''
|
||||
}
|
||||
|
||||
function getFormattedAgentDebugChatTree(messages: MessageDetailResponse[]): ChatItemInTree[] {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user