This commit is contained in:
chariri 2026-06-25 18:39:22 +00:00 committed by GitHub
commit 500677f98b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 4206 additions and 4173 deletions

View File

@ -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")

View File

@ -1,19 +1,19 @@
import json
import logging
from collections.abc import Sequence
from collections.abc import Mapping, Sequence
from datetime import datetime
from typing import Any, NotRequired, TypedDict, cast
from typing import Any, Literal, NotRequired, TypedDict, cast
from flask import abort, request
from flask_restx import Resource, fields
from pydantic import AliasChoices, BaseModel, Field, RootModel, ValidationError, field_validator
from flask_restx import Resource
from pydantic import AliasChoices, BaseModel, Field, ValidationError, field_validator
from sqlalchemy.orm import Session, sessionmaker
from werkzeug.exceptions import BadRequest, Forbidden, InternalServerError, NotFound
import services
from controllers.common.controller_schemas import DefaultBlockConfigQuery, WorkflowListQuery, WorkflowUpdatePayload
from controllers.common.errors import InvalidArgumentError
from controllers.common.fields import GeneratedAppResponse, NewAppResponse, SimpleResultResponse
from controllers.common.fields import NewAppResponse, SimpleResultResponse
from controllers.common.schema import (
query_params_from_model,
register_response_schema_model,
@ -21,11 +21,7 @@ from controllers.common.schema import (
register_schema_models,
)
from controllers.console import console_ns
from controllers.console.app.error import (
ConversationCompletedError,
DraftWorkflowNotExist,
DraftWorkflowNotSync,
)
from controllers.console.app.error import ConversationCompletedError, DraftWorkflowNotExist, DraftWorkflowNotSync
from controllers.console.app.permission_keys import get_app_permission_keys
from controllers.console.app.wraps import get_app_model
from controllers.console.wraps import (
@ -58,7 +54,7 @@ from extensions.ext_database import db
from extensions.ext_redis import redis_client
from factories import file_factory, variable_factory
from fields.base import ResponseModel
from fields.member_fields import SimpleAccount
from fields.member_fields import SimpleAccountResponse
from fields.workflow_run_fields import WorkflowRunNodeExecutionResponse
from graphon.enums import NodeType
from graphon.file import File
@ -69,7 +65,7 @@ from graphon.variables import SecretVariable, SegmentType, VariableBase
from graphon.variables.exc import VariableError
from libs import helper
from libs.datetime_utils import naive_utc_now
from libs.helper import TimestampField, dump_response, to_timestamp, uuid_value
from libs.helper import dump_response, to_timestamp, uuid_value
from libs.login import login_required
from models import Account, App
from models.model import AppMode
@ -103,20 +99,16 @@ class SyncDraftWorkflowPayload(BaseModel):
graph: dict[str, Any]
features: dict[str, Any]
hash: str | None = None
environment_variables: list[dict[str, Any]] = Field(
default_factory=list,
)
conversation_variables: list[dict[str, Any]] = Field(
default_factory=list,
)
environment_variables: list[dict[str, Any]] = Field(default_factory=list)
conversation_variables: list[dict[str, Any]] = Field(default_factory=list)
class BaseWorkflowRunPayload(BaseModel):
files: list[dict[str, Any]] | None = Field(default=None)
files: list[dict[str, Any]] | None = None
class AdvancedChatWorkflowRunPayload(BaseWorkflowRunPayload):
inputs: dict[str, Any] | None = Field(default=None)
inputs: dict[str, Any] | None = None
query: str = ""
conversation_id: str | None = None
parent_message_id: str | None = None
@ -130,11 +122,11 @@ class AdvancedChatWorkflowRunPayload(BaseWorkflowRunPayload):
class IterationNodeRunPayload(BaseModel):
inputs: dict[str, Any] | None = Field(default=None)
inputs: dict[str, Any] | None = None
class LoopNodeRunPayload(BaseModel):
inputs: dict[str, Any] | None = Field(default=None)
inputs: dict[str, Any] | None = None
class DraftWorkflowRunPayload(BaseWorkflowRunPayload):
@ -159,10 +151,7 @@ class ConvertToWorkflowPayload(BaseModel):
class WorkflowFeaturesPayload(BaseModel):
features: dict[str, Any] = Field(
...,
description="Workflow feature configuration",
)
features: dict[str, Any] = Field(..., description="Workflow feature configuration")
class WorkflowOnlineUsersPayload(BaseModel):
@ -197,7 +186,7 @@ class PipelineVariableResponse(ResponseModel):
max_length: int | None = None
required: bool
unit: str | None = None
default_value: Any = Field(default=None)
default_value: Any = None
options: list[str] | None = None
placeholder: str | None = None
tooltips: str | None = None
@ -220,21 +209,17 @@ class WorkflowEnvironmentVariableResponse(ResponseModel):
class WorkflowResponse(ResponseModel):
id: str
graph: dict[str, Any] = Field(
validation_alias=AliasChoices("graph_dict", "graph"),
)
features: dict[str, Any] = Field(
validation_alias=AliasChoices("features_dict", "features"),
)
graph: dict[str, Any] = Field(validation_alias=AliasChoices("graph_dict", "graph"))
features: dict[str, Any] = Field(validation_alias=AliasChoices("features_dict", "features"))
hash: str = Field(validation_alias=AliasChoices("unique_hash", "hash"))
version: str
marked_name: str
marked_comment: str
created_by: SimpleAccount | None = Field(
created_by: SimpleAccountResponse | None = Field(
default=None, validation_alias=AliasChoices("created_by_account", "created_by")
)
created_at: int
updated_by: SimpleAccount | None = Field(
updated_by: SimpleAccountResponse | None = Field(
default=None, validation_alias=AliasChoices("updated_by_account", "updated_by")
)
updated_at: int
@ -267,6 +252,53 @@ class WorkflowPaginationResponse(ResponseModel):
has_more: bool
class SyncDraftWorkflowResponse(ResponseModel):
result: str
hash: str
updated_at: int
class PublishWorkflowResponse(ResponseModel):
result: str
created_at: int
class HumanInputUserActionResponse(ResponseModel):
id: str
title: str
button_style: str = "default"
class HumanInputFormPreviewResponse(ResponseModel):
# Draft previews are shape-compatible with live human_input_required events,
# but they do not persist a form or mint recipient tokens (no expiration_time)
type_: Literal["human_input_required"] = Field(default="human_input_required", alias="TYPE")
form_id: str
form_content: str
inputs: list[Mapping[str, Any]] = Field(default_factory=list)
actions: list[HumanInputUserActionResponse] = Field(default_factory=list)
node_id: str
node_title: str
resolved_default_values: Mapping[str, Any] = Field(default_factory=dict)
display_in_ui: bool = Field(default=False, description="Always false for draft preview responses.")
form_token: str | None = Field(default=None, description="Always null for draft preview responses.")
expiration_time: int | None = Field(default=None, description="Always null for draft preview responses.")
class HumanInputDeliveryTestResponse(ResponseModel):
pass
class TriggerDebugWaitingResponse(ResponseModel):
status: Literal["waiting"]
retry_in: int
class TriggerDebugErrorResponse(ResponseModel):
status: Literal["error"]
error: str | None = None
class WorkflowOnlineUser(ResponseModel):
user_id: str
username: str
@ -282,46 +314,6 @@ class WorkflowOnlineUsersResponse(ResponseModel):
data: list[WorkflowOnlineUsersByApp]
class WorkflowPublishResponse(ResponseModel):
result: str
created_at: int
class WorkflowRestoreResponse(ResponseModel):
result: str
hash: str
updated_at: int
class DefaultBlockConfigsResponse(RootModel[list[dict[str, Any]]]):
root: list[dict[str, Any]]
class DefaultBlockConfigResponse(RootModel[dict[str, Any]]):
root: dict[str, Any]
class HumanInputFormPreviewResponse(ResponseModel):
form_id: str
node_id: str
node_title: str
form_content: str
inputs: list[dict[str, Any]] = Field(default_factory=list)
actions: list[dict[str, Any]] = Field(default_factory=list)
display_in_ui: bool | None = None
form_token: str | None = None
resolved_default_values: dict[str, Any] = Field(default_factory=dict)
expiration_time: int | None = None
class HumanInputFormSubmitResponse(RootModel[dict[str, Any]]):
root: dict[str, Any]
class EmptyObjectResponse(RootModel[dict[str, Any]]):
root: dict[str, Any]
class DraftWorkflowTriggerRunPayload(BaseModel):
node_id: str
@ -356,19 +348,19 @@ register_response_schema_models(
WorkflowEnvironmentVariableResponse,
WorkflowResponse,
WorkflowPaginationResponse,
SyncDraftWorkflowResponse,
PublishWorkflowResponse,
HumanInputUserActionResponse,
HumanInputFormPreviewResponse,
HumanInputDeliveryTestResponse,
TriggerDebugWaitingResponse,
TriggerDebugErrorResponse,
WorkflowOnlineUser,
WorkflowOnlineUsersByApp,
WorkflowOnlineUsersResponse,
WorkflowPublishResponse,
WorkflowRestoreResponse,
DefaultBlockConfigsResponse,
DefaultBlockConfigResponse,
HumanInputFormPreviewResponse,
HumanInputFormSubmitResponse,
EmptyObjectResponse,
GeneratedAppResponse,
NewAppResponse,
SimpleResultResponse,
WorkflowRunNodeExecutionResponse,
)
@ -426,6 +418,14 @@ def _serialize_environment_variable(value: Any) -> EnvironmentVariableResponseDi
return value
def _trigger_debug_waiting_response() -> dict[str, int | str]:
return TriggerDebugWaitingResponse(status="waiting", retry_in=LISTENING_RETRY_IN).model_dump(mode="json")
def _trigger_debug_error_response(error: str | None = None) -> dict[str, str]:
return TriggerDebugErrorResponse(status="error", error=error).model_dump(mode="json", exclude_none=True)
@console_ns.route("/apps/<uuid:app_id>/workflows/draft")
class DraftWorkflowApi(Resource):
@console_ns.doc("get_draft_workflow")
@ -475,14 +475,7 @@ class DraftWorkflowApi(Resource):
@console_ns.response(
200,
"Draft workflow synced successfully",
console_ns.model(
"SyncDraftWorkflowResponse",
{
"result": fields.String,
"hash": fields.String,
"updated_at": fields.String,
},
),
console_ns.models[SyncDraftWorkflowResponse.__name__],
)
@console_ns.response(400, "Invalid workflow configuration")
@console_ns.response(403, "Permission denied")
@ -535,11 +528,11 @@ class DraftWorkflowApi(Resource):
except VariableError as e:
raise InvalidArgumentError(description=str(e))
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return SyncDraftWorkflowResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/advanced-chat/workflows/draft/run")
@ -548,7 +541,7 @@ class AdvancedChatDraftWorkflowRunApi(Resource):
@console_ns.doc(description="Run draft workflow for advanced chat application")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.expect(console_ns.models[AdvancedChatWorkflowRunPayload.__name__])
@console_ns.response(200, "Workflow run started successfully", console_ns.models[GeneratedAppResponse.__name__])
@console_ns.response(200, "Workflow run started successfully")
@console_ns.response(400, "Invalid request parameters")
@console_ns.response(403, "Permission denied")
@setup_required
@ -574,6 +567,7 @@ class AdvancedChatDraftWorkflowRunApi(Resource):
app_model=app_model, user=current_user, args=args, invoke_from=InvokeFrom.DEBUGGER, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -594,11 +588,7 @@ class AdvancedChatDraftRunIterationNodeApi(Resource):
@console_ns.doc(description="Run draft workflow iteration node for advanced chat")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[IterationNodeRunPayload.__name__])
@console_ns.response(
200,
"Iteration node run started successfully",
console_ns.models[GeneratedAppResponse.__name__],
)
@console_ns.response(200, "Iteration node run started successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(404, "Node not found")
@setup_required
@ -619,6 +609,7 @@ class AdvancedChatDraftRunIterationNodeApi(Resource):
app_model=app_model, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -637,11 +628,7 @@ class WorkflowDraftRunIterationNodeApi(Resource):
@console_ns.doc(description="Run draft workflow iteration node")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[IterationNodeRunPayload.__name__])
@console_ns.response(
200,
"Workflow iteration node run started successfully",
console_ns.models[GeneratedAppResponse.__name__],
)
@console_ns.response(200, "Workflow iteration node run started successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(404, "Node not found")
@setup_required
@ -662,6 +649,7 @@ class WorkflowDraftRunIterationNodeApi(Resource):
app_model=app_model, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -680,7 +668,7 @@ class AdvancedChatDraftRunLoopNodeApi(Resource):
@console_ns.doc(description="Run draft workflow loop node for advanced chat")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[LoopNodeRunPayload.__name__])
@console_ns.response(200, "Loop node run started successfully", console_ns.models[GeneratedAppResponse.__name__])
@console_ns.response(200, "Loop node run started successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(404, "Node not found")
@setup_required
@ -701,6 +689,7 @@ class AdvancedChatDraftRunLoopNodeApi(Resource):
app_model=app_model, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -719,11 +708,7 @@ class WorkflowDraftRunLoopNodeApi(Resource):
@console_ns.doc(description="Run draft workflow loop node")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[LoopNodeRunPayload.__name__])
@console_ns.response(
200,
"Workflow loop node run started successfully",
console_ns.models[GeneratedAppResponse.__name__],
)
@console_ns.response(200, "Workflow loop node run started successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(404, "Node not found")
@setup_required
@ -744,6 +729,7 @@ class WorkflowDraftRunLoopNodeApi(Resource):
app_model=app_model, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -764,10 +750,7 @@ class HumanInputFormPreviewPayload(BaseModel):
class HumanInputFormSubmitPayload(BaseModel):
form_inputs: dict[str, Any] = Field(
...,
description="Values the user provides for the form's own fields",
)
form_inputs: dict[str, Any] = Field(..., description="Values the user provides for the form's own fields")
inputs: dict[str, Any] = Field(
...,
description="Values used to fill missing upstream variables referenced in form_content",
@ -797,7 +780,11 @@ class AdvancedChatDraftHumanInputFormPreviewApi(Resource):
@console_ns.doc(description="Get human input form preview for advanced chat workflow")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[HumanInputFormPreviewPayload.__name__])
@console_ns.response(200, "Human input form preview", console_ns.models[HumanInputFormPreviewResponse.__name__])
@console_ns.response(
200,
"Human input form preview retrieved",
console_ns.models[HumanInputFormPreviewResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -819,7 +806,7 @@ class AdvancedChatDraftHumanInputFormPreviewApi(Resource):
node_id=node_id,
inputs=inputs,
)
return jsonable_encoder(preview)
return dump_response(HumanInputFormPreviewResponse, preview)
@console_ns.route("/apps/<uuid:app_id>/advanced-chat/workflows/draft/human-input/nodes/<string:node_id>/form/run")
@ -830,8 +817,7 @@ class AdvancedChatDraftHumanInputFormRunApi(Resource):
@console_ns.expect(console_ns.models[HumanInputFormSubmitPayload.__name__])
@console_ns.response(
200,
"Human input form submission result",
console_ns.models[HumanInputFormSubmitResponse.__name__],
"Human input form submitted",
)
@setup_required
@login_required
@ -854,6 +840,7 @@ class AdvancedChatDraftHumanInputFormRunApi(Resource):
inputs=args.inputs,
action=args.action,
)
# TODO: typing here for result
return jsonable_encoder(result)
@ -863,7 +850,11 @@ class WorkflowDraftHumanInputFormPreviewApi(Resource):
@console_ns.doc(description="Get human input form preview for workflow")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[HumanInputFormPreviewPayload.__name__])
@console_ns.response(200, "Human input form preview", console_ns.models[HumanInputFormPreviewResponse.__name__])
@console_ns.response(
200,
"Human input form preview retrieved",
console_ns.models[HumanInputFormPreviewResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -885,7 +876,7 @@ class WorkflowDraftHumanInputFormPreviewApi(Resource):
node_id=node_id,
inputs=inputs,
)
return jsonable_encoder(preview)
return dump_response(HumanInputFormPreviewResponse, preview)
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/human-input/nodes/<string:node_id>/form/run")
@ -896,8 +887,7 @@ class WorkflowDraftHumanInputFormRunApi(Resource):
@console_ns.expect(console_ns.models[HumanInputFormSubmitPayload.__name__])
@console_ns.response(
200,
"Human input form submission result",
console_ns.models[HumanInputFormSubmitResponse.__name__],
"Human input form submitted",
)
@setup_required
@login_required
@ -920,6 +910,7 @@ class WorkflowDraftHumanInputFormRunApi(Resource):
inputs=args.inputs,
action=args.action,
)
# TODO: typing here
return jsonable_encoder(result)
@ -929,7 +920,11 @@ class WorkflowDraftHumanInputDeliveryTestApi(Resource):
@console_ns.doc(description="Test human input delivery for workflow")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.expect(console_ns.models[HumanInputDeliveryTestPayload.__name__])
@console_ns.response(200, "Human input delivery test result", console_ns.models[EmptyObjectResponse.__name__])
@console_ns.response(
200,
"Human input delivery tested",
console_ns.models[HumanInputDeliveryTestResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -950,7 +945,7 @@ class WorkflowDraftHumanInputDeliveryTestApi(Resource):
delivery_method_id=args.delivery_method_id,
inputs=args.inputs,
)
return jsonable_encoder({})
return HumanInputDeliveryTestResponse().model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/run")
@ -959,11 +954,7 @@ class DraftWorkflowRunApi(Resource):
@console_ns.doc(description="Run draft workflow")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.expect(console_ns.models[DraftWorkflowRunPayload.__name__])
@console_ns.response(
200,
"Draft workflow run started successfully",
console_ns.models[GeneratedAppResponse.__name__],
)
@console_ns.response(200, "Draft workflow run started successfully")
@console_ns.response(403, "Permission denied")
@setup_required
@login_required
@ -991,6 +982,7 @@ class DraftWorkflowRunApi(Resource):
streaming=True,
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except InvokeRateLimitError as ex:
raise InvokeRateLimitHttpError(ex.description)
@ -1021,7 +1013,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(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/run")
@ -1109,7 +1101,7 @@ class PublishedWorkflowApi(Resource):
return dump_response(WorkflowResponse, workflow)
@console_ns.expect(console_ns.models[PublishWorkflowPayload.__name__])
@console_ns.response(200, "Workflow published successfully", console_ns.models[WorkflowPublishResponse.__name__])
@console_ns.response(200, "Workflow published successfully", console_ns.models[PublishWorkflowResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -1141,12 +1133,9 @@ class PublishedWorkflowApi(Resource):
app_model_in_session.updated_by = current_user.id
app_model_in_session.updated_at = naive_utc_now()
workflow_created_at = TimestampField().format(workflow.created_at)
workflow_created_at = to_timestamp(workflow.created_at)
return {
"result": "success",
"created_at": workflow_created_at,
}
return PublishWorkflowResponse(result="success", created_at=workflow_created_at).model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/default-workflow-block-configs")
@ -1157,7 +1146,6 @@ class DefaultBlockConfigsApi(Resource):
@console_ns.response(
200,
"Default block configurations retrieved successfully",
console_ns.models[DefaultBlockConfigsResponse.__name__],
)
@setup_required
@login_required
@ -1179,13 +1167,12 @@ class DefaultBlockConfigApi(Resource):
@console_ns.doc("get_default_block_config")
@console_ns.doc(description="Get default block configuration by type")
@console_ns.doc(params={"app_id": "Application ID", "block_type": "Block type"})
@console_ns.doc(params=query_params_from_model(DefaultBlockConfigQuery))
@console_ns.response(
200,
"Default block configuration retrieved successfully",
console_ns.models[DefaultBlockConfigResponse.__name__],
)
@console_ns.response(404, "Block type not found")
@console_ns.doc(params=query_params_from_model(DefaultBlockConfigQuery))
@setup_required
@login_required
@account_initialization_required
@ -1279,15 +1266,14 @@ class WorkflowFeaturesApi(Resource):
workflow_service = WorkflowService()
workflow_service.update_draft_workflow_features(app_model=app_model, features=features, account=current_user)
return {"result": "success"}
return SimpleResultResponse(result="success").model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows")
class PublishedAllWorkflowApi(Resource):
@console_ns.doc(params=query_params_from_model(WorkflowListQuery))
@console_ns.doc("get_all_published_workflows")
@console_ns.doc(description="Get all published workflows for an application")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(WorkflowListQuery)})
@console_ns.response(
200,
"Published workflows retrieved successfully",
@ -1340,7 +1326,11 @@ class DraftWorkflowRestoreApi(Resource):
@console_ns.doc("restore_workflow_to_draft")
@console_ns.doc(description="Restore a published workflow version into the draft workflow")
@console_ns.doc(params={"app_id": "Application ID", "workflow_id": "Published workflow ID"})
@console_ns.response(200, "Workflow restored successfully", console_ns.models[WorkflowRestoreResponse.__name__])
@console_ns.response(
200,
"Workflow restored successfully",
console_ns.models[SyncDraftWorkflowResponse.__name__],
)
@console_ns.response(400, "Source workflow must be published")
@console_ns.response(404, "Workflow not found")
@setup_required
@ -1366,11 +1356,11 @@ class DraftWorkflowRestoreApi(Resource):
except ValueError as exc:
raise BadRequest(str(exc)) from exc
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return SyncDraftWorkflowResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/<string:workflow_id>")
@ -1422,6 +1412,7 @@ class WorkflowByIdApi(Resource):
return dump_response(WorkflowResponse, workflow)
@console_ns.response(204, "Workflow deleted successfully")
@setup_required
@login_required
@account_initialization_required
@ -1480,7 +1471,7 @@ class DraftWorkflowNodeLastRunApi(Resource):
)
if node_exec is None:
raise NotFound("last run not found")
return WorkflowRunNodeExecutionResponse.model_validate(node_exec, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, node_exec)
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/trigger/run")
@ -1493,19 +1484,8 @@ class DraftWorkflowTriggerRunApi(Resource):
@console_ns.doc("poll_draft_workflow_trigger_run")
@console_ns.doc(description="Poll for trigger events and execute full workflow when event arrives")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.expect(
console_ns.model(
"DraftWorkflowTriggerRunRequest",
{
"node_id": fields.String(required=True, description="Node ID"),
},
)
)
@console_ns.response(
200,
"Trigger event received and workflow executed successfully",
console_ns.models[GeneratedAppResponse.__name__],
)
@console_ns.expect(console_ns.models[DraftWorkflowTriggerRunPayload.__name__])
@console_ns.response(200, "Trigger event received and workflow executed successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(500, "Internal server error")
@setup_required
@ -1537,10 +1517,11 @@ class DraftWorkflowTriggerRunApi(Resource):
try:
event = poller.poll()
if not event:
return jsonable_encoder({"status": "waiting", "retry_in": LISTENING_RETRY_IN})
return _trigger_debug_waiting_response()
workflow_args = dict(event.workflow_args)
workflow_args[SKIP_PREPARE_USER_INPUTS_KEY] = True
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(
AppGenerateService.generate(
app_model=app_model,
@ -1554,7 +1535,7 @@ class DraftWorkflowTriggerRunApi(Resource):
except InvokeRateLimitError as ex:
raise InvokeRateLimitHttpError(ex.description)
except PluginInvokeError as e:
return jsonable_encoder({"status": "error", "error": e.to_user_friendly_error()}), 400
return _trigger_debug_error_response(e.to_user_friendly_error()), 400
except Exception as e:
logger.exception("Error polling trigger debug event")
raise e
@ -1573,7 +1554,7 @@ class DraftWorkflowTriggerNodeApi(Resource):
@console_ns.response(
200,
"Trigger event received and node executed successfully",
console_ns.models[GeneratedAppResponse.__name__],
console_ns.models[WorkflowRunNodeExecutionResponse.__name__],
)
@console_ns.response(403, "Permission denied")
@console_ns.response(500, "Internal server error")
@ -1617,12 +1598,12 @@ class DraftWorkflowTriggerNodeApi(Resource):
)
event = poller.poll()
except PluginInvokeError as e:
return jsonable_encoder({"status": "error", "error": e.to_user_friendly_error()}), 400
return _trigger_debug_error_response(e.to_user_friendly_error()), 400
except Exception as e:
logger.exception("Error polling trigger debug event")
raise e
if not event:
return jsonable_encoder({"status": "waiting", "retry_in": LISTENING_RETRY_IN})
return _trigger_debug_waiting_response()
raw_files = event.workflow_args.get("files")
files = _parse_file(draft_workflow, raw_files if isinstance(raw_files, list) else None)
@ -1636,12 +1617,10 @@ class DraftWorkflowTriggerNodeApi(Resource):
query="",
files=files,
)
return jsonable_encoder(node_execution)
return dump_response(WorkflowRunNodeExecutionResponse, node_execution)
except Exception as e:
logger.exception("Error running draft workflow trigger node")
return jsonable_encoder(
{"status": "error", "error": "An unexpected error occurred while running the node."}
), 400
return _trigger_debug_error_response("An unexpected error occurred while running the node."), 400
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/trigger/run-all")
@ -1655,7 +1634,7 @@ class DraftWorkflowTriggerRunAllApi(Resource):
@console_ns.doc(description="Full workflow debug when the start node is a trigger")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.expect(console_ns.models[DraftWorkflowTriggerRunAllPayload.__name__])
@console_ns.response(200, "Workflow executed successfully", console_ns.models[GeneratedAppResponse.__name__])
@console_ns.response(200, "Workflow executed successfully")
@console_ns.response(403, "Permission denied")
@console_ns.response(500, "Internal server error")
@setup_required
@ -1685,12 +1664,12 @@ class DraftWorkflowTriggerRunAllApi(Resource):
node_ids=node_ids,
)
except PluginInvokeError as e:
return jsonable_encoder({"status": "error", "error": e.to_user_friendly_error()}), 400
return _trigger_debug_error_response(e.to_user_friendly_error()), 400
except Exception as e:
logger.exception("Error polling trigger debug event")
raise e
if trigger_debug_event is None:
return jsonable_encoder({"status": "waiting", "retry_in": LISTENING_RETRY_IN})
return _trigger_debug_waiting_response()
try:
workflow_args = dict(trigger_debug_event.workflow_args)
@ -1704,16 +1683,13 @@ class DraftWorkflowTriggerRunAllApi(Resource):
streaming=True,
root_node_id=trigger_debug_event.node_id,
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except InvokeRateLimitError as ex:
raise InvokeRateLimitHttpError(ex.description)
except Exception:
logger.exception("Error running draft workflow trigger run-all")
return jsonable_encoder(
{
"status": "error",
}
), 400
return _trigger_debug_error_response(), 400
@console_ns.route("/apps/workflows/online-users")
@ -1738,7 +1714,7 @@ class WorkflowOnlineUsersApi(Resource):
raise BadRequest(f"Maximum {MAX_WORKFLOW_ONLINE_USERS_REQUEST_IDS} app_ids are allowed per request.")
if not app_ids:
return {"data": []}
return WorkflowOnlineUsersResponse(data=[]).model_dump(mode="json")
workflow_service = WorkflowService()
accessible_app_ids = workflow_service.get_accessible_app_ids(app_ids, current_tenant_id)

View File

@ -20,7 +20,7 @@ from controllers.console.wraps import (
from extensions.ext_database import db
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 libs.helper import to_timestamp
from libs.login import login_required
@ -115,7 +115,7 @@ class WorkflowAppLogPartialResponse(ResponseModel):
details: Any = 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
@ -129,7 +129,7 @@ class WorkflowArchivedLogPartialResponse(ResponseModel):
id: str
workflow_run: WorkflowRunForArchivedLogResponse | None = None
trigger_metadata: Any = 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

View File

@ -2,7 +2,7 @@ import logging
from datetime import datetime
from flask_restx import Resource
from pydantic import BaseModel, Field, TypeAdapter, computed_field, field_validator
from pydantic import BaseModel, Field, computed_field, field_validator
from controllers.common.schema import register_response_schema_models, register_schema_models
from controllers.console import console_ns
@ -19,7 +19,7 @@ from controllers.console.wraps import (
)
from extensions.ext_database import db
from fields.base import ResponseModel
from fields.member_fields import AccountWithRole
from fields.member_fields import AccountWithRoleResponse
from libs.helper import build_avatar_url, dump_response, to_timestamp
from libs.login import login_required
from models import Account, App
@ -52,7 +52,7 @@ class WorkflowCommentReplyPayload(BaseModel):
class WorkflowCommentMentionUsersPayload(BaseModel):
users: list[AccountWithRole]
users: list[AccountWithRoleResponse]
class WorkflowCommentAccount(ResponseModel):
@ -189,7 +189,7 @@ class WorkflowCommentReplyUpdate(ResponseModel):
register_schema_models(
console_ns,
AccountWithRole,
AccountWithRoleResponse,
WorkflowCommentMentionUsersPayload,
WorkflowCommentCreatePayload,
WorkflowCommentUpdatePayload,
@ -491,6 +491,4 @@ class WorkflowCommentMentionUsersApi(Resource):
if current_tenant is None:
raise ValueError("current tenant is required")
members = TenantService.get_tenant_members(current_tenant, session=db.session)
users = TypeAdapter(list[AccountWithRole]).validate_python(members, from_attributes=True)
response = WorkflowCommentMentionUsersPayload(users=users)
return response.model_dump(mode="json"), 200
return dump_response(WorkflowCommentMentionUsersPayload, {"users": members}), 200

View File

@ -1,11 +1,11 @@
import logging
from collections.abc import Callable
from functools import wraps
from typing import Any, Concatenate, TypedDict, override
from typing import Any, Concatenate, Self, override
from uuid import UUID
from flask import Response, request
from flask_restx import Resource, fields, marshal, marshal_with
from flask_restx import Resource
from pydantic import BaseModel, Field
from sqlalchemy.orm import sessionmaker
@ -47,28 +47,6 @@ logger = logging.getLogger(__name__)
_file_access_controller = DatabaseFileAccessController()
class OpaqueRawField(fields.Raw):
@override
def schema(self) -> dict[str, object]:
return {"type": "object"}
class JsonValueRawField(fields.Raw):
@override
def schema(self) -> dict[str, object]:
return {
"anyOf": [
{"type": "string"},
{"type": "integer"},
{"type": "number"},
{"type": "boolean"},
{"type": "object", "additionalProperties": True},
{"type": "array", "items": {}},
{"type": "null"},
]
}
class WorkflowDraftVariableListQuery(BaseModel):
page: int = Field(default=1, ge=1, le=100_000, description="Page number")
limit: int = Field(default=20, ge=1, le=100, description="Items per page")
@ -76,24 +54,111 @@ class WorkflowDraftVariableListQuery(BaseModel):
class WorkflowDraftVariableUpdatePayload(BaseModel):
name: str | None = Field(default=None, description="Variable name")
value: Any | None = Field(default=None, description="Variable value")
value: Any = Field(default=None, description="Variable value")
class ConversationVariableUpdatePayload(BaseModel):
conversation_variables: list[dict[str, Any]] = Field(
...,
description="Conversation variables for the draft workflow",
..., description="Conversation variables for the draft workflow"
)
class EnvironmentVariableUpdatePayload(BaseModel):
environment_variables: list[dict[str, Any]] = Field(
...,
description="Environment variables for the draft workflow",
)
environment_variables: list[dict[str, Any]] = Field(..., description="Environment variables for the draft workflow")
class EnvironmentVariableItemResponse(ResponseModel):
class WorkflowDraftVariableFullContentResponse(ResponseModel):
size_bytes: int | None
value_type: str
length: int | None
download_url: str
@classmethod
def from_workflow_draft_variable(cls, variable: WorkflowDraftVariable) -> Self | None:
if not variable.is_truncated():
return None
variable_file = variable.variable_file
assert variable_file is not None
return cls(
size_bytes=variable_file.size,
value_type=str(variable_file.value_type.exposed_type()),
length=variable_file.length,
download_url=file_helpers.get_signed_file_url(variable_file.upload_file_id, as_attachment=True),
)
class WorkflowDraftVariableWithoutValueResponse(ResponseModel):
id: str
type: str
name: str
description: str
selector: list[str]
value_type: str
edited: bool
visible: bool
is_truncated: bool
@classmethod
def from_workflow_draft_variable(cls, variable: WorkflowDraftVariable) -> Self:
return cls(
id=variable.id,
type=variable.get_variable_type().value,
name=variable.name,
description=variable.description,
selector=variable.get_selector(),
value_type=_serialize_variable_type(variable),
edited=variable.edited,
visible=variable.visible,
is_truncated=variable.file_id is not None,
)
class WorkflowDraftVariableResponse(WorkflowDraftVariableWithoutValueResponse):
value: Any
full_content: WorkflowDraftVariableFullContentResponse | None
@classmethod
@override
def from_workflow_draft_variable(cls, variable: WorkflowDraftVariable) -> Self:
without_value = WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(variable)
return cls(
**without_value.model_dump(),
value=_serialize_var_value(variable),
full_content=WorkflowDraftVariableFullContentResponse.from_workflow_draft_variable(variable),
)
class WorkflowDraftVariableListWithoutValueResponse(ResponseModel):
items: list[WorkflowDraftVariableWithoutValueResponse]
total: int | None
@classmethod
def from_workflow_draft_variable_list(cls, variable_list: WorkflowDraftVariableList) -> Self:
return cls(
items=[
WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(variable)
for variable in variable_list.variables
],
total=variable_list.total,
)
class WorkflowDraftVariableListResponse(ResponseModel):
items: list[WorkflowDraftVariableResponse]
@classmethod
def from_workflow_draft_variable_list(cls, variable_list: WorkflowDraftVariableList) -> Self:
return cls(
items=[
WorkflowDraftVariableResponse.from_workflow_draft_variable(variable)
for variable in variable_list.variables
],
)
class WorkflowDraftEnvironmentVariableResponse(ResponseModel):
id: str
type: str
name: str
@ -106,8 +171,8 @@ class EnvironmentVariableItemResponse(ResponseModel):
editable: bool
class EnvironmentVariableListResponse(ResponseModel):
items: list[EnvironmentVariableItemResponse]
class WorkflowDraftEnvironmentVariableListResponse(ResponseModel):
items: list[WorkflowDraftEnvironmentVariableResponse]
register_schema_models(
@ -117,22 +182,33 @@ register_schema_models(
ConversationVariableUpdatePayload,
EnvironmentVariableUpdatePayload,
)
register_response_schema_models(console_ns, SimpleResultResponse, EnvironmentVariableListResponse)
register_response_schema_models(
console_ns,
WorkflowDraftVariableFullContentResponse,
WorkflowDraftVariableWithoutValueResponse,
WorkflowDraftVariableResponse,
WorkflowDraftVariableListWithoutValueResponse,
WorkflowDraftVariableListResponse,
WorkflowDraftEnvironmentVariableResponse,
WorkflowDraftEnvironmentVariableListResponse,
SimpleResultResponse,
)
def _convert_values_to_json_serializable_object(value: Segment):
def _convert_values_to_json_serializable_object(value: Segment) -> Any:
match value:
case FileSegment():
return value.value.model_dump()
case ArrayFileSegment():
return [i.model_dump() for i in value.value]
return [file.model_dump() for file in value.value]
case SegmentGroup():
return [_convert_values_to_json_serializable_object(i) for i in value.value]
case _:
return value.value
def _serialize_var_value(variable: WorkflowDraftVariable):
def _serialize_var_value(variable: WorkflowDraftVariable) -> Any:
value = variable.get_value()
# create a copy of the value to avoid affecting the model cache.
value = value.model_copy(deep=True)
@ -153,30 +229,6 @@ def _serialize_variable_type(workflow_draft_var: WorkflowDraftVariable) -> str:
return str(value_type.exposed_type())
class FullContentDict(TypedDict):
size_bytes: int | None
value_type: str
length: int | None
download_url: str
def _serialize_full_content(variable: WorkflowDraftVariable) -> FullContentDict | None:
"""Serialize full_content information for large variables."""
if not variable.is_truncated():
return None
variable_file = variable.variable_file
assert variable_file is not None
result: FullContentDict = {
"size_bytes": variable_file.size,
"value_type": str(variable_file.value_type.exposed_type()),
"length": variable_file.length,
"download_url": file_helpers.get_signed_file_url(variable_file.upload_file_id, as_attachment=True),
}
return result
def ensure_variable_access(
variable: WorkflowDraftVariable | None,
app_id: str,
@ -190,83 +242,21 @@ def ensure_variable_access(
return variable
_WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS = {
"id": fields.String,
"type": fields.String(attribute=lambda model: model.get_variable_type()),
"name": fields.String,
"description": fields.String,
"selector": fields.List(fields.String, attribute=lambda model: model.get_selector()),
"value_type": fields.String(attribute=_serialize_variable_type),
"edited": fields.Boolean(attribute=lambda model: model.edited),
"visible": fields.Boolean,
"is_truncated": fields.Boolean(attribute=lambda model: model.file_id is not None),
}
def validate_node_id(node_id: str) -> None:
if node_id in [
CONVERSATION_VARIABLE_NODE_ID,
SYSTEM_VARIABLE_NODE_ID,
]:
# NOTE(QuantumGhost): While we store the system and conversation variables as node variables
# with specific `node_id` in database, we still want to make the API separated. By disallowing
# accessing system and conversation variables in `WorkflowDraftNodeVariableListApi`,
# we mitigate the risk that user of the API depending on the implementation detail of the API.
#
# ref: [Hyrum's Law](https://www.hyrumslaw.com/)
_WORKFLOW_DRAFT_VARIABLE_FIELDS = {
**_WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS,
"value": JsonValueRawField(attribute=_serialize_var_value),
"full_content": OpaqueRawField(attribute=_serialize_full_content),
}
_WORKFLOW_DRAFT_ENV_VARIABLE_FIELDS = {
"id": fields.String,
"type": fields.String(attribute=lambda _: "env"),
"name": fields.String,
"description": fields.String,
"selector": fields.List(fields.String, attribute=lambda model: model.get_selector()),
"value_type": fields.String(attribute=_serialize_variable_type),
"edited": fields.Boolean(attribute=lambda model: model.edited),
"visible": fields.Boolean,
}
_WORKFLOW_DRAFT_ENV_VARIABLE_LIST_FIELDS = {
"items": fields.List(fields.Nested(_WORKFLOW_DRAFT_ENV_VARIABLE_FIELDS)),
}
def _get_items(var_list: WorkflowDraftVariableList) -> list[WorkflowDraftVariable]:
return var_list.variables
_WORKFLOW_DRAFT_VARIABLE_LIST_WITHOUT_VALUE_FIELDS = {
"items": fields.List(fields.Nested(_WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS), attribute=_get_items),
"total": fields.Integer,
}
_WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS = {
"items": fields.List(fields.Nested(_WORKFLOW_DRAFT_VARIABLE_FIELDS), attribute=_get_items),
}
# Register models for flask_restx to avoid dict type issues in Swagger
workflow_draft_variable_without_value_model = console_ns.model(
"WorkflowDraftVariableWithoutValue", _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS
)
workflow_draft_variable_model = console_ns.model("WorkflowDraftVariable", _WORKFLOW_DRAFT_VARIABLE_FIELDS)
workflow_draft_env_variable_model = console_ns.model("WorkflowDraftEnvVariable", _WORKFLOW_DRAFT_ENV_VARIABLE_FIELDS)
workflow_draft_env_variable_list_fields_copy = _WORKFLOW_DRAFT_ENV_VARIABLE_LIST_FIELDS.copy()
workflow_draft_env_variable_list_fields_copy["items"] = fields.List(fields.Nested(workflow_draft_env_variable_model))
workflow_draft_env_variable_list_model = console_ns.model(
"WorkflowDraftEnvVariableList", workflow_draft_env_variable_list_fields_copy
)
workflow_draft_variable_list_without_value_fields_copy = _WORKFLOW_DRAFT_VARIABLE_LIST_WITHOUT_VALUE_FIELDS.copy()
workflow_draft_variable_list_without_value_fields_copy["items"] = fields.List(
fields.Nested(workflow_draft_variable_without_value_model), attribute=_get_items
)
workflow_draft_variable_list_without_value_model = console_ns.model(
"WorkflowDraftVariableListWithoutValue", workflow_draft_variable_list_without_value_fields_copy
)
workflow_draft_variable_list_fields_copy = _WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS.copy()
workflow_draft_variable_list_fields_copy["items"] = fields.List(
fields.Nested(workflow_draft_variable_model), attribute=_get_items
)
workflow_draft_variable_list_model = console_ns.model(
"WorkflowDraftVariableList", workflow_draft_variable_list_fields_copy
)
raise InvalidArgumentError(
f"invalid node_id, please use correspond api for conversation and system variables, node_id={node_id}",
)
def _api_prerequisite[T, **P, R](
@ -296,23 +286,42 @@ def _api_prerequisite[T, **P, R](
return wrapper
def _get_variable_list(app_model: App, node_id: str, current_user_id: str) -> WorkflowDraftVariableList:
with sessionmaker(bind=db.engine, expire_on_commit=False).begin() as session:
draft_var_srv = WorkflowDraftVariableService(
session=session,
)
if node_id == CONVERSATION_VARIABLE_NODE_ID:
draft_vars = draft_var_srv.list_conversation_variables(app_model.id, user_id=current_user_id)
elif node_id == SYSTEM_VARIABLE_NODE_ID:
draft_vars = draft_var_srv.list_system_variables(app_model.id, user_id=current_user_id)
else:
draft_vars = draft_var_srv.list_node_variables(
app_id=app_model.id,
node_id=node_id,
user_id=current_user_id,
)
return draft_vars
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/variables")
class WorkflowVariableCollectionApi(Resource):
@console_ns.doc(params=query_params_from_model(WorkflowDraftVariableListQuery))
@console_ns.doc("get_workflow_variables")
@console_ns.doc(description="Get draft workflow variables")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.doc(params={"page": "Page number (1-100000)", "limit": "Number of items per page (1-100)"})
@console_ns.doc(params=query_params_from_model(WorkflowDraftVariableListQuery))
@console_ns.response(
200, "Workflow variables retrieved successfully", workflow_draft_variable_list_without_value_model
200,
"Workflow variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListWithoutValueResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_without_value_model)
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
def get(self, current_user: Account, app_model: App):
"""
Get draft workflow
"""
# response-contract:ignore constructed Pydantic response
args = WorkflowDraftVariableListQuery.model_validate(request.args.to_dict(flat=True))
# fetch draft workflow by app_model
@ -333,7 +342,9 @@ class WorkflowVariableCollectionApi(Resource):
user_id=current_user.id,
)
return workflow_vars
return WorkflowDraftVariableListWithoutValueResponse.from_workflow_draft_variable_list(
workflow_vars
).model_dump(mode="json")
@console_ns.doc("delete_workflow_variables")
@console_ns.doc(description="Delete all draft workflow variables")
@ -345,24 +356,7 @@ class WorkflowVariableCollectionApi(Resource):
)
draft_var_srv.delete_user_workflow_variables(app_model.id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
def validate_node_id(node_id: str) -> None:
if node_id in [
CONVERSATION_VARIABLE_NODE_ID,
SYSTEM_VARIABLE_NODE_ID,
]:
# NOTE(QuantumGhost): While we store the system and conversation variables as node variables
# with specific `node_id` in database, we still want to make the API separated. By disallowing
# accessing system and conversation variables in `WorkflowDraftNodeVariableListApi`,
# we mitigate the risk that user of the API depending on the implementation detail of the API.
#
# ref: [Hyrum's Law](https://www.hyrumslaw.com/)
raise InvalidArgumentError(
f"invalid node_id, please use correspond api for conversation and system variables, node_id={node_id}",
)
return "", 204
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/variables")
@ -370,11 +364,15 @@ class NodeVariableCollectionApi(Resource):
@console_ns.doc("get_node_variables")
@console_ns.doc(description="Get variables for a specific node")
@console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
@console_ns.response(200, "Node variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"Node variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_model)
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
def get(self, current_user: Account, app_model: App, node_id: str):
# response-contract:ignore constructed Pydantic response
validate_node_id(node_id)
with sessionmaker(bind=db.engine, expire_on_commit=False).begin() as session:
draft_var_srv = WorkflowDraftVariableService(
@ -382,7 +380,7 @@ class NodeVariableCollectionApi(Resource):
)
node_vars = draft_var_srv.list_node_variables(app_model.id, node_id, user_id=current_user.id)
return node_vars
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(node_vars).model_dump(mode="json")
@console_ns.doc("delete_node_variables")
@console_ns.doc(description="Delete all variables for a specific node")
@ -393,7 +391,7 @@ class NodeVariableCollectionApi(Resource):
srv = WorkflowDraftVariableService(db.session())
srv.delete_node_variables(app_model.id, node_id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/variables/<uuid:variable_id>")
@ -404,12 +402,14 @@ class VariableApi(Resource):
@console_ns.doc("get_variable")
@console_ns.doc(description="Get a specific workflow variable")
@console_ns.doc(params={"app_id": "Application ID", "variable_id": "Variable ID"})
@console_ns.response(200, "Variable retrieved successfully", workflow_draft_variable_model)
@console_ns.response(
200, "Variable retrieved successfully", console_ns.models[WorkflowDraftVariableResponse.__name__]
)
@console_ns.response(404, "Variable not found")
@_api_prerequisite
@marshal_with(workflow_draft_variable_model)
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
def get(self, current_user: Account, app_model: App, variable_id: UUID):
# response-contract:ignore constructed Pydantic response
draft_var_srv = WorkflowDraftVariableService(
session=db.session(),
)
@ -420,16 +420,18 @@ class VariableApi(Resource):
variable_id=variable_id_str,
current_user_id=current_user.id,
)
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.doc("update_variable")
@console_ns.doc(description="Update a workflow variable")
@console_ns.expect(console_ns.models[WorkflowDraftVariableUpdatePayload.__name__])
@console_ns.response(200, "Variable updated successfully", workflow_draft_variable_model)
@console_ns.response(
200, "Variable updated successfully", console_ns.models[WorkflowDraftVariableResponse.__name__]
)
@console_ns.response(404, "Variable not found")
@_api_prerequisite
@marshal_with(workflow_draft_variable_model)
def patch(self, current_user: Account, app_model: App, variable_id: UUID):
# response-contract:ignore constructed Pydantic response
# Request payload for file types:
#
# Local File:
@ -467,15 +469,16 @@ class VariableApi(Resource):
new_name = args_model.name
raw_value = args_model.value
if new_name is None and raw_value is None:
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
new_value = None
if raw_value is not None:
new_value_input: Any
match variable.value_type:
case SegmentType.FILE:
if not isinstance(raw_value, dict):
raise InvalidArgumentError(description=f"expected dict for file, got {type(raw_value)}")
raw_value = build_from_mapping(
new_value_input = build_from_mapping(
mapping=raw_value,
tenant_id=app_model.tenant_id,
access_controller=_file_access_controller,
@ -483,19 +486,22 @@ class VariableApi(Resource):
case SegmentType.ARRAY_FILE:
if not isinstance(raw_value, list):
raise InvalidArgumentError(description=f"expected list for files, got {type(raw_value)}")
if len(raw_value) > 0 and not isinstance(raw_value[0], dict):
raise InvalidArgumentError(description=f"expected dict for files[0], got {type(raw_value)}")
raw_value = build_from_mappings(
for index, item in enumerate(raw_value):
if not isinstance(item, dict):
raise InvalidArgumentError(
description=f"expected dict for files[{index}], got {type(item)}"
)
new_value_input = build_from_mappings(
mappings=raw_value,
tenant_id=app_model.tenant_id,
access_controller=_file_access_controller,
)
case _:
pass
new_value = build_segment_with_type(variable.value_type, raw_value)
new_value_input = raw_value
new_value = build_segment_with_type(variable.value_type, new_value_input)
draft_var_srv.update_variable(variable, name=new_name, value=new_value)
db.session.commit()
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.doc("delete_variable")
@console_ns.doc(description="Delete a workflow variable")
@ -515,7 +521,7 @@ class VariableApi(Resource):
)
draft_var_srv.delete_variable(variable)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/variables/<uuid:variable_id>/reset")
@ -523,11 +529,12 @@ class VariableResetApi(Resource):
@console_ns.doc("reset_variable")
@console_ns.doc(description="Reset a workflow variable to its default value")
@console_ns.doc(params={"app_id": "Application ID", "variable_id": "Variable ID"})
@console_ns.response(200, "Variable reset successfully", workflow_draft_variable_model)
@console_ns.response(200, "Variable reset successfully", console_ns.models[WorkflowDraftVariableResponse.__name__])
@console_ns.response(204, "Variable reset (no content)")
@console_ns.response(404, "Variable not found")
@_api_prerequisite
def put(self, current_user: Account, app_model: App, variable_id: UUID):
# response-contract:ignore constructed Pydantic response
draft_var_srv = WorkflowDraftVariableService(
session=db.session(),
)
@ -549,27 +556,8 @@ class VariableResetApi(Resource):
resetted = draft_var_srv.reset_variable(draft_workflow, variable)
db.session.commit()
if resetted is None:
return Response("", 204)
else:
return marshal(resetted, workflow_draft_variable_model)
def _get_variable_list(app_model: App, node_id: str, current_user_id: str) -> WorkflowDraftVariableList:
with sessionmaker(bind=db.engine, expire_on_commit=False).begin() as session:
draft_var_srv = WorkflowDraftVariableService(
session=session,
)
if node_id == CONVERSATION_VARIABLE_NODE_ID:
draft_vars = draft_var_srv.list_conversation_variables(app_model.id, user_id=current_user_id)
elif node_id == SYSTEM_VARIABLE_NODE_ID:
draft_vars = draft_var_srv.list_system_variables(app_model.id, user_id=current_user_id)
else:
draft_vars = draft_var_srv.list_node_variables(
app_id=app_model.id,
node_id=node_id,
user_id=current_user_id,
)
return draft_vars
return "", 204
return WorkflowDraftVariableResponse.from_workflow_draft_variable(resetted).model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/conversation-variables")
@ -577,12 +565,16 @@ class ConversationVariableCollectionApi(Resource):
@console_ns.doc("get_conversation_variables")
@console_ns.doc(description="Get conversation variables for workflow")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.response(200, "Conversation variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"Conversation variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@console_ns.response(404, "Draft workflow not found")
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_model)
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
def get(self, current_user: Account, app_model: App):
# response-contract:ignore constructed Pydantic response
# NOTE(QuantumGhost): Prefill conversation variables into the draft variables table
# so their IDs can be returned to the caller.
workflow_srv = WorkflowService()
@ -592,7 +584,9 @@ class ConversationVariableCollectionApi(Resource):
draft_var_srv = WorkflowDraftVariableService(db.session())
draft_var_srv.prefill_conversation_variable_default_values(draft_workflow, user_id=current_user.id)
db.session.commit()
return _get_variable_list(app_model, CONVERSATION_VARIABLE_NODE_ID, current_user.id)
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
_get_variable_list(app_model, CONVERSATION_VARIABLE_NODE_ID, current_user.id)
).model_dump(mode="json")
@console_ns.expect(console_ns.models[ConversationVariableUpdatePayload.__name__])
@console_ns.doc("update_conversation_variables")
@ -626,7 +620,7 @@ class ConversationVariableCollectionApi(Resource):
conversation_variables=conversation_variables,
)
return {"result": "success"}
return SimpleResultResponse(result="success").model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/system-variables")
@ -634,12 +628,18 @@ class SystemVariableCollectionApi(Resource):
@console_ns.doc("get_system_variables")
@console_ns.doc(description="Get system variables for workflow")
@console_ns.doc(params={"app_id": "Application ID"})
@console_ns.response(200, "System variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"System variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_model)
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
def get(self, current_user: Account, app_model: App):
return _get_variable_list(app_model, SYSTEM_VARIABLE_NODE_ID, current_user.id)
# response-contract:ignore constructed Pydantic response
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
_get_variable_list(app_model, SYSTEM_VARIABLE_NODE_ID, current_user.id)
).model_dump(mode="json")
@console_ns.route("/apps/<uuid:app_id>/workflows/draft/environment-variables")
@ -650,7 +650,7 @@ class EnvironmentVariableCollectionApi(Resource):
@console_ns.response(
200,
"Environment variables retrieved successfully",
console_ns.models[EnvironmentVariableListResponse.__name__],
console_ns.models[WorkflowDraftEnvironmentVariableListResponse.__name__],
)
@console_ns.response(404, "Draft workflow not found")
@_api_prerequisite
@ -669,22 +669,22 @@ class EnvironmentVariableCollectionApi(Resource):
env_vars_list = []
for v in env_vars:
env_vars_list.append(
{
"id": v.id,
"type": "env",
"name": v.name,
"description": v.description,
"selector": v.selector,
"value_type": str(v.value_type.exposed_type()),
"value": v.value,
WorkflowDraftEnvironmentVariableResponse(
id=v.id,
type="env",
name=v.name,
description=v.description,
selector=list(v.selector),
value_type=str(v.value_type.exposed_type()),
value=v.value,
# Do not track edited for env vars.
"edited": False,
"visible": True,
"editable": True,
}
edited=False,
visible=True,
editable=True,
)
)
return {"items": env_vars_list}
return WorkflowDraftEnvironmentVariableListResponse(items=env_vars_list).model_dump(mode="json")
@console_ns.expect(console_ns.models[EnvironmentVariableUpdatePayload.__name__])
@console_ns.doc("update_environment_variables")
@ -718,4 +718,4 @@ class EnvironmentVariableCollectionApi(Resource):
environment_variables=environment_variables,
)
return {"result": "success"}
return SimpleResultResponse(result="success").model_dump(mode="json")

View File

@ -37,7 +37,7 @@ from graphon.entities.pause_reason import HumanInputRequired
from graphon.enums import WorkflowExecutionStatus
from libs.archive_storage import ArchiveStorageNotConfiguredError, get_archive_storage
from libs.custom_inputs import time_duration
from libs.helper import uuid_value
from libs.helper import dump_response, uuid_value
from libs.login import login_required
from models import Account, App, AppMode, WorkflowArchiveLog, WorkflowRunTriggeredFrom
from models.workflow import WorkflowRun
@ -183,9 +183,7 @@ class AdvancedChatAppWorkflowRunListApi(Resource):
app_model=app_model, args=args, triggered_from=triggered_from
)
return AdvancedChatWorkflowRunPaginationResponse.model_validate(result, from_attributes=True).model_dump(
mode="json"
)
return dump_response(AdvancedChatWorkflowRunPaginationResponse, result)
@console_ns.route("/apps/<uuid:app_id>/workflow-runs/<uuid:run_id>/export")
@ -232,14 +230,9 @@ class WorkflowRunExportApi(Resource):
expires_in=EXPORT_SIGNED_URL_EXPIRE_SECONDS,
)
expires_at = datetime.now(UTC) + timedelta(seconds=EXPORT_SIGNED_URL_EXPIRE_SECONDS)
response = WorkflowRunExportResponse.model_validate(
{
"status": "success",
"presigned_url": presigned_url,
"presigned_url_expires_at": expires_at.isoformat(),
}
)
return response.model_dump(mode="json"), 200
return WorkflowRunExportResponse(
status="success", presigned_url=presigned_url, presigned_url_expires_at=expires_at.isoformat()
).model_dump(mode="json"), 200
@console_ns.route("/apps/<uuid:app_id>/advanced-chat/workflow-runs/count")
@ -322,7 +315,7 @@ class WorkflowRunListApi(Resource):
app_model=app_model, args=args, triggered_from=triggered_from
)
return WorkflowRunPaginationResponse.model_validate(result, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunPaginationResponse, result)
@console_ns.route("/apps/<uuid:app_id>/workflow-runs/count")
@ -393,7 +386,7 @@ class WorkflowRunDetailApi(Resource):
if workflow_run is None:
raise NotFoundError("Workflow run not found")
return WorkflowRunDetailResponse.model_validate(workflow_run, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunDetailResponse, workflow_run)
@console_ns.route("/apps/<uuid:app_id>/workflow-runs/<uuid:run_id>/node-executions")
@ -471,8 +464,7 @@ class ConsoleWorkflowPauseDetailsApi(Resource):
# Check if workflow is suspended
is_paused = workflow_run.status == WorkflowExecutionStatus.PAUSED
if not is_paused:
empty_response = WorkflowPauseDetailsResponse(paused_at=None, paused_nodes=[])
return empty_response.model_dump(mode="json"), 200
return WorkflowPauseDetailsResponse(paused_at=None, paused_nodes=[]).model_dump(mode="json"), 200
pause_entity = workflow_run_repo.get_workflow_pause(workflow_run_id)
pause_reasons = pause_entity.get_pause_reasons() if pause_entity else []
@ -500,8 +492,6 @@ class ConsoleWorkflowPauseDetailsApi(Resource):
else:
raise AssertionError("unimplemented.")
response = WorkflowPauseDetailsResponse(
paused_at=paused_at.isoformat() + "Z" if paused_at else None,
paused_nodes=paused_nodes,
)
return response.model_dump(mode="json"), 200
return WorkflowPauseDetailsResponse(
paused_at=paused_at.isoformat() + "Z" if paused_at else None, paused_nodes=paused_nodes
).model_dump(mode="json"), 200

View File

@ -1,27 +1,27 @@
import logging
from collections.abc import Callable
from functools import wraps
from typing import Any, Concatenate, NoReturn
from typing import Any, Concatenate
from uuid import UUID
from flask import Response, request
from flask_restx import Resource, marshal, marshal_with
from flask_restx import Resource
from pydantic import BaseModel, Field
from sqlalchemy.orm import sessionmaker
from werkzeug.exceptions import Forbidden
from controllers.common.errors import InvalidArgumentError, NotFoundError
from controllers.common.schema import query_params_from_model, register_schema_models
from controllers.common.schema import register_response_schema_models, register_schema_models
from controllers.console import console_ns
from controllers.console.app.error import (
DraftWorkflowNotExist,
)
from controllers.console.app.workflow_draft_variable import (
_WORKFLOW_DRAFT_VARIABLE_FIELDS, # type: ignore[private-usage]
EnvironmentVariableListResponse,
workflow_draft_variable_list_model,
workflow_draft_variable_list_without_value_model,
workflow_draft_variable_model,
WorkflowDraftVariableListResponse,
WorkflowDraftVariableListWithoutValueResponse,
WorkflowDraftVariableResponse,
WorkflowDraftVariableUpdatePayload,
validate_node_id,
)
from controllers.console.datasets.wraps import get_rag_pipeline
from controllers.console.wraps import account_initialization_required, setup_required, with_current_user
@ -30,6 +30,7 @@ from core.workflow.variable_prefixes import CONVERSATION_VARIABLE_NODE_ID, SYSTE
from extensions.ext_database import db
from factories.file_factory import build_from_mapping, build_from_mappings
from factories.variable_factory import build_segment_with_type
from fields.base import ResponseModel
from graphon.variables.types import SegmentType
from libs.login import login_required
from models import Account
@ -46,12 +47,36 @@ class PaginationQuery(BaseModel):
limit: int = Field(default=20, ge=1, le=100)
class WorkflowDraftVariablePatchPayload(BaseModel):
name: str | None = None
value: Any | None = None
class WorkflowDraftVariablePatchPayload(WorkflowDraftVariableUpdatePayload):
value: Any = None
class RagPipelineEnvironmentVariableResponse(ResponseModel):
id: str
type: str
name: str
description: str
selector: list[str]
value_type: str
value: Any
edited: bool
visible: bool
editable: bool
class RagPipelineEnvironmentVariableListResponse(ResponseModel):
items: list[RagPipelineEnvironmentVariableResponse]
register_schema_models(console_ns, PaginationQuery, WorkflowDraftVariablePatchPayload)
register_response_schema_models(
console_ns,
WorkflowDraftVariableResponse,
WorkflowDraftVariableListResponse,
WorkflowDraftVariableListWithoutValueResponse,
RagPipelineEnvironmentVariableResponse,
RagPipelineEnvironmentVariableListResponse,
)
def _api_prerequisite[T, **P, R](
@ -83,14 +108,12 @@ def _api_prerequisite[T, **P, R](
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/variables")
class RagPipelineVariableCollectionApi(Resource):
@console_ns.doc(params=query_params_from_model(PaginationQuery))
@console_ns.response(
200,
"Workflow variables retrieved successfully",
workflow_draft_variable_list_without_value_model,
"Variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListWithoutValueResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_without_value_model)
def get(self, current_user: Account, pipeline: Pipeline):
"""
Get draft workflow
@ -115,9 +138,11 @@ class RagPipelineVariableCollectionApi(Resource):
user_id=current_user.id,
)
return workflow_vars
return WorkflowDraftVariableListWithoutValueResponse.from_workflow_draft_variable_list(
workflow_vars
).model_dump(mode="json")
@console_ns.response(204, "Workflow variables deleted successfully")
@console_ns.response(204, "Variables deleted successfully")
@_api_prerequisite
def delete(self, current_user: Account, pipeline: Pipeline):
draft_var_srv = WorkflowDraftVariableService(
@ -125,32 +150,17 @@ class RagPipelineVariableCollectionApi(Resource):
)
draft_var_srv.delete_user_workflow_variables(pipeline.id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
def validate_node_id(node_id: str) -> NoReturn | None:
if node_id in [
CONVERSATION_VARIABLE_NODE_ID,
SYSTEM_VARIABLE_NODE_ID,
]:
# NOTE(QuantumGhost): While we store the system and conversation variables as node variables
# with specific `node_id` in database, we still want to make the API separated. By disallowing
# accessing system and conversation variables in `WorkflowDraftNodeVariableListApi`,
# we mitigate the risk that user of the API depending on the implementation detail of the API.
#
# ref: [Hyrum's Law](https://www.hyrumslaw.com/)
raise InvalidArgumentError(
f"invalid node_id, please use correspond api for conversation and system variables, node_id={node_id}",
)
return None
return "", 204
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/nodes/<string:node_id>/variables")
class RagPipelineNodeVariableCollectionApi(Resource):
@console_ns.response(200, "Node variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"Node variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_model)
def get(self, current_user: Account, pipeline: Pipeline, node_id: str):
validate_node_id(node_id)
with sessionmaker(bind=db.engine, expire_on_commit=False).begin() as session:
@ -159,7 +169,7 @@ class RagPipelineNodeVariableCollectionApi(Resource):
)
node_vars = draft_var_srv.list_node_variables(pipeline.id, node_id, user_id=current_user.id)
return node_vars
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(node_vars).model_dump(mode="json")
@console_ns.response(204, "Node variables deleted successfully")
@_api_prerequisite
@ -168,17 +178,17 @@ class RagPipelineNodeVariableCollectionApi(Resource):
srv = WorkflowDraftVariableService(db.session())
srv.delete_node_variables(pipeline.id, node_id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/variables/<uuid:variable_id>")
class RagPipelineVariableApi(Resource):
_PATCH_NAME_FIELD = "name"
_PATCH_VALUE_FIELD = "value"
@console_ns.response(200, "Variable retrieved successfully", workflow_draft_variable_model)
@console_ns.response(
200,
"Variable retrieved successfully",
console_ns.models[WorkflowDraftVariableResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_model)
def get(self, _current_user: Account, pipeline: Pipeline, variable_id: UUID):
draft_var_srv = WorkflowDraftVariableService(
session=db.session(),
@ -189,11 +199,14 @@ class RagPipelineVariableApi(Resource):
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
if variable.app_id != pipeline.id:
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.response(200, "Variable updated successfully", workflow_draft_variable_model)
@console_ns.response(
200,
"Variable updated successfully",
console_ns.models[WorkflowDraftVariableResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_model)
@console_ns.expect(console_ns.models[WorkflowDraftVariablePatchPayload.__name__])
def patch(self, _current_user: Account, pipeline: Pipeline, variable_id: UUID):
# Request payload for file types:
@ -221,7 +234,6 @@ class RagPipelineVariableApi(Resource):
session=db.session(),
)
payload = WorkflowDraftVariablePatchPayload.model_validate(console_ns.payload or {})
args = payload.model_dump(exclude_none=True)
variable_id_str = str(variable_id)
variable = draft_var_srv.get_variable(variable_id=variable_id_str)
@ -230,18 +242,22 @@ class RagPipelineVariableApi(Resource):
if variable.app_id != pipeline.id:
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
new_name = args.get(self._PATCH_NAME_FIELD, None)
raw_value = args.get(self._PATCH_VALUE_FIELD, None)
new_name = payload.name
raw_value = payload.value
if new_name is None and raw_value is None:
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
# TODO: duplication w/ controllers/console/app/workflow_draft_variable.py(L462)
# extract if proper (need to find a better location to prevent accident
# behavioral change)
new_value = None
if raw_value is not None:
new_value_input: Any
match variable.value_type:
case SegmentType.FILE:
if not isinstance(raw_value, dict):
raise InvalidArgumentError(description=f"expected dict for file, got {type(raw_value)}")
raw_value = build_from_mapping(
new_value_input = build_from_mapping(
mapping=raw_value,
tenant_id=pipeline.tenant_id,
access_controller=_file_access_controller,
@ -249,19 +265,22 @@ class RagPipelineVariableApi(Resource):
case SegmentType.ARRAY_FILE:
if not isinstance(raw_value, list):
raise InvalidArgumentError(description=f"expected list for files, got {type(raw_value)}")
if len(raw_value) > 0 and not isinstance(raw_value[0], dict):
raise InvalidArgumentError(description=f"expected dict for files[0], got {type(raw_value)}")
raw_value = build_from_mappings(
for index, item in enumerate(raw_value):
if not isinstance(item, dict):
raise InvalidArgumentError(
description=f"expected dict for files[{index}], got {type(item)}"
)
new_value_input = build_from_mappings(
mappings=raw_value,
tenant_id=pipeline.tenant_id,
access_controller=_file_access_controller,
)
case _:
pass
new_value = build_segment_with_type(variable.value_type, raw_value)
new_value_input = raw_value
new_value = build_segment_with_type(variable.value_type, new_value_input)
draft_var_srv.update_variable(variable, name=new_name, value=new_value)
db.session.commit()
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.response(204, "Variable deleted successfully")
@_api_prerequisite
@ -277,13 +296,17 @@ class RagPipelineVariableApi(Resource):
raise NotFoundError(description=f"variable not found, id={variable_id_str}")
draft_var_srv.delete_variable(variable)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/variables/<uuid:variable_id>/reset")
class RagPipelineVariableResetApi(Resource):
@console_ns.response(200, "Variable reset successfully", workflow_draft_variable_model)
@console_ns.response(204, "Variable reset (no content)")
@console_ns.response(
200,
"Variable reset successfully",
console_ns.models[WorkflowDraftVariableResponse.__name__],
)
@console_ns.response(204, "Variable reset to empty state")
@_api_prerequisite
def put(self, _current_user: Account, pipeline: Pipeline, variable_id: UUID):
draft_var_srv = WorkflowDraftVariableService(
@ -306,9 +329,8 @@ class RagPipelineVariableResetApi(Resource):
resetted = draft_var_srv.reset_variable(draft_workflow, variable)
db.session.commit()
if resetted is None:
return Response("", 204)
else:
return marshal(resetted, _WORKFLOW_DRAFT_VARIABLE_FIELDS)
return "", 204
return WorkflowDraftVariableResponse.from_workflow_draft_variable(resetted).model_dump(mode="json")
def _get_variable_list(pipeline: Pipeline, node_id: str, current_user_id: str) -> WorkflowDraftVariableList:
@ -327,11 +349,16 @@ def _get_variable_list(pipeline: Pipeline, node_id: str, current_user_id: str) -
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/system-variables")
class RagPipelineSystemVariableCollectionApi(Resource):
@console_ns.response(200, "System variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"System variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_api_prerequisite
@marshal_with(workflow_draft_variable_list_model)
def get(self, current_user: Account, pipeline: Pipeline):
return _get_variable_list(pipeline, SYSTEM_VARIABLE_NODE_ID, current_user.id)
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
_get_variable_list(pipeline, SYSTEM_VARIABLE_NODE_ID, current_user.id)
).model_dump(mode="json")
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/environment-variables")
@ -339,7 +366,7 @@ class RagPipelineEnvironmentVariableCollectionApi(Resource):
@console_ns.response(
200,
"Environment variables retrieved successfully",
console_ns.models[EnvironmentVariableListResponse.__name__],
console_ns.models[RagPipelineEnvironmentVariableListResponse.__name__],
)
@_api_prerequisite
def get(self, _current_user: Account, pipeline: Pipeline):
@ -353,22 +380,22 @@ class RagPipelineEnvironmentVariableCollectionApi(Resource):
raise DraftWorkflowNotExist()
env_vars = workflow.environment_variables
env_vars_list = []
env_vars_list: list[RagPipelineEnvironmentVariableResponse] = []
for v in env_vars:
env_vars_list.append(
{
"id": v.id,
"type": "env",
"name": v.name,
"description": v.description,
"selector": v.selector,
"value_type": v.value_type.value,
"value": v.value,
RagPipelineEnvironmentVariableResponse(
id=v.id,
type="env",
name=v.name,
description=v.description,
selector=list(v.selector),
value_type=v.value_type.value,
value=v.value,
# Do not track edited for env vars.
"edited": False,
"visible": True,
"editable": True,
}
edited=False,
visible=True,
editable=True,
)
)
return {"items": env_vars_list}
return RagPipelineEnvironmentVariableListResponse(items=env_vars_list).model_dump(mode="json")

View File

@ -1,5 +1,6 @@
import json
import logging
from collections.abc import Mapping
from typing import Any, Literal, cast
from uuid import UUID
@ -21,8 +22,6 @@ from controllers.console.app.error import (
)
from controllers.console.app.workflow import (
RESTORE_SOURCE_WORKFLOW_MUST_BE_PUBLISHED_MESSAGE,
DefaultBlockConfigResponse,
DefaultBlockConfigsResponse,
WorkflowPaginationResponse,
WorkflowResponse,
)
@ -41,6 +40,7 @@ from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpErr
from core.app.apps.base_app_queue_manager import AppQueueManager
from core.app.apps.pipeline.pipeline_generator import PipelineGenerator
from core.app.entities.app_invoke_entities import InvokeFrom
from core.plugin.entities.plugin_daemon import PluginDatasourceProviderEntity
from extensions.ext_database import db
from factories import variable_factory
from fields.base import ResponseModel
@ -50,9 +50,8 @@ from fields.workflow_run_fields import (
WorkflowRunNodeExecutionResponse,
WorkflowRunPaginationResponse,
)
from graphon.model_runtime.utils.encoders import jsonable_encoder
from libs import helper
from libs.helper import TimestampField, UUIDStrOrEmpty, dump_response
from libs.helper import UUIDStrOrEmpty, dump_response, to_timestamp
from libs.login import login_required
from models import Account
from models.dataset import Pipeline
@ -72,14 +71,14 @@ logger = logging.getLogger(__name__)
class DraftWorkflowSyncPayload(BaseModel):
graph: dict[str, Any]
hash: str | None = None
environment_variables: list[dict[str, Any]] | None = Field(default=None)
conversation_variables: list[dict[str, Any]] | None = Field(default=None)
rag_pipeline_variables: list[dict[str, Any]] | None = Field(default=None)
features: dict[str, Any] | None = Field(default=None)
environment_variables: list[dict[str, Any]] | None = None
conversation_variables: list[dict[str, Any]] | None = None
rag_pipeline_variables: list[dict[str, Any]] | None = None
features: dict[str, Any] | None = None
class NodeRunPayload(BaseModel):
inputs: dict[str, Any] | None = Field(default=None)
inputs: dict[str, Any] | None = None
class NodeRunRequiredPayload(BaseModel):
@ -136,14 +135,30 @@ class RagPipelineWorkflowPublishResponse(ResponseModel):
created_at: int
class RagPipelineOpaqueResponse(RootModel[Any]):
root: Any
class RagPipelineStepParametersResponse(ResponseModel):
class RagPipelineVariablesResponse(ResponseModel):
# TODO: Replace Any with a response model that mirrors graphon.variables.variables.RAGPipelineVariable.
variables: Any
class DatasourcePluginListResponse(RootModel[list[PluginDatasourceProviderEntity]]):
pass
class RagPipelineRecommendedPluginResponse(ResponseModel):
installed_recommended_plugins: list[Mapping[str, object]] = Field(
description="Installed tool provider payloads. Shape follows the tool provider serializer."
)
uninstalled_recommended_plugins: list[Mapping[str, object]] = Field(
description="Marketplace plugin manifest payloads returned by the marketplace service."
)
class RagPipelineTransformResponse(ResponseModel):
pipeline_id: str
dataset_id: str
status: str
register_schema_models(
console_ns,
DraftWorkflowSyncPayload,
@ -162,10 +177,10 @@ register_schema_models(
)
register_response_schema_models(
console_ns,
DefaultBlockConfigResponse,
DefaultBlockConfigsResponse,
RagPipelineOpaqueResponse,
RagPipelineStepParametersResponse,
DatasourcePluginListResponse,
RagPipelineRecommendedPluginResponse,
RagPipelineTransformResponse,
RagPipelineVariablesResponse,
RagPipelineWorkflowPublishResponse,
RagPipelineWorkflowSyncResponse,
SimpleResultResponse,
@ -254,17 +269,16 @@ class DraftRagPipelineApi(Resource):
except WorkflowHashNotEqualError:
raise DraftWorkflowNotSync()
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return RagPipelineWorkflowSyncResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/iteration/nodes/<string:node_id>/run")
class RagPipelineDraftRunIterationNodeApi(Resource):
@console_ns.expect(console_ns.models[NodeRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -284,6 +298,7 @@ class RagPipelineDraftRunIterationNodeApi(Resource):
pipeline=pipeline, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -299,7 +314,6 @@ class RagPipelineDraftRunIterationNodeApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/loop/nodes/<string:node_id>/run")
class RagPipelineDraftRunLoopNodeApi(Resource):
@console_ns.expect(console_ns.models[NodeRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -319,6 +333,7 @@ class RagPipelineDraftRunLoopNodeApi(Resource):
pipeline=pipeline, user=current_user, node_id=node_id, args=args, streaming=True
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
@ -334,7 +349,6 @@ class RagPipelineDraftRunLoopNodeApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/run")
class DraftRagPipelineRunApi(Resource):
@console_ns.expect(console_ns.models[DraftWorkflowRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -358,6 +372,7 @@ class DraftRagPipelineRunApi(Resource):
streaming=True,
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except InvokeRateLimitError as ex:
raise InvokeRateLimitHttpError(ex.description)
@ -366,7 +381,6 @@ class DraftRagPipelineRunApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/published/run")
class PublishedRagPipelineRunApi(Resource):
@console_ns.expect(console_ns.models[PublishedWorkflowRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -391,6 +405,7 @@ class PublishedRagPipelineRunApi(Resource):
streaming=streaming,
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except InvokeRateLimitError as ex:
raise InvokeRateLimitHttpError(ex.description)
@ -399,7 +414,6 @@ class PublishedRagPipelineRunApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/published/datasource/nodes/<string:node_id>/run")
class RagPipelinePublishedDatasourceNodeRunApi(Resource):
@console_ns.expect(console_ns.models[DatasourceNodeRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@account_initialization_required
@ -414,6 +428,7 @@ class RagPipelinePublishedDatasourceNodeRunApi(Resource):
payload = DatasourceNodeRunPayload.model_validate(console_ns.payload or {})
rag_pipeline_service = RagPipelineService()
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(
PipelineGenerator.convert_to_event_stream(
rag_pipeline_service.run_datasource_workflow_node(
@ -432,7 +447,6 @@ class RagPipelinePublishedDatasourceNodeRunApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/datasource/nodes/<string:node_id>/run")
class RagPipelineDraftDatasourceNodeRunApi(Resource):
@console_ns.expect(console_ns.models[DatasourceNodeRunPayload.__name__])
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@setup_required
@login_required
@edit_permission_required
@ -447,6 +461,7 @@ class RagPipelineDraftDatasourceNodeRunApi(Resource):
payload = DatasourceNodeRunPayload.model_validate(console_ns.payload or {})
rag_pipeline_service = RagPipelineService()
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(
PipelineGenerator.convert_to_event_stream(
rag_pipeline_service.run_datasource_workflow_node(
@ -492,9 +507,7 @@ class RagPipelineDraftNodeRunApi(Resource):
if workflow_node_execution is None:
raise ValueError("Workflow node execution not found")
return WorkflowRunNodeExecutionResponse.model_validate(
workflow_node_execution, from_attributes=True
).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, workflow_node_execution)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflow-runs/tasks/<string:task_id>/stop")
@ -513,7 +526,7 @@ class RagPipelineTaskStopApi(Resource):
"""
AppQueueManager.set_stop_flag(task_id, InvokeFrom.DEBUGGER, current_user.id)
return {"result": "success"}
return SimpleResultResponse(result="success").model_dump(mode="json")
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/publish")
@ -567,20 +580,18 @@ class PublishedRagPipelineApi(Resource):
pipeline.is_published = True
pipeline.workflow_id = workflow.id
db.session.commit()
workflow_created_at = TimestampField().format(workflow.created_at)
workflow_created_at = to_timestamp(workflow.created_at)
return {
"result": "success",
"created_at": workflow_created_at,
}
return RagPipelineWorkflowPublishResponse(result="success", created_at=workflow_created_at).model_dump(
mode="json"
)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/default-workflow-block-configs")
class DefaultRagPipelineBlockConfigsApi(Resource):
@console_ns.response(
200,
"Default block configs retrieved successfully",
console_ns.models[DefaultBlockConfigsResponse.__name__],
"Default workflow block configurations retrieved successfully",
)
@setup_required
@login_required
@ -602,8 +613,7 @@ class DefaultRagPipelineBlockConfigApi(Resource):
@console_ns.doc(params=query_params_from_model(DefaultBlockConfigQuery))
@console_ns.response(
200,
"Default block config retrieved successfully",
console_ns.models[DefaultBlockConfigResponse.__name__],
"Default workflow block configuration retrieved successfully",
)
@setup_required
@login_required
@ -631,13 +641,13 @@ class DefaultRagPipelineBlockConfigApi(Resource):
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows")
class PublishedAllRagPipelineApi(Resource):
@console_ns.doc(params=query_params_from_model(WorkflowListQuery))
@console_ns.response(
200,
"Published workflows retrieved successfully",
console_ns.models[WorkflowPaginationResponse.__name__],
)
@console_ns.response(403, "Permission denied")
@console_ns.doc(params=query_params_from_model(WorkflowListQuery))
@setup_required
@login_required
@account_initialization_required
@ -671,14 +681,15 @@ class PublishedAllRagPipelineApi(Resource):
named_only=named_only,
)
return WorkflowPaginationResponse.model_validate(
return dump_response(
WorkflowPaginationResponse,
{
"items": workflows,
"page": page,
"limit": limit,
"has_more": has_more,
}
).model_dump(mode="json")
},
)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/<string:workflow_id>/restore")
@ -706,11 +717,11 @@ class RagPipelineDraftWorkflowRestoreApi(Resource):
except WorkflowNotFoundError as exc:
raise NotFound(str(exc)) from exc
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return RagPipelineWorkflowSyncResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/<string:workflow_id>")
@ -784,13 +795,17 @@ class RagPipelineByIdApi(Resource):
except ValueError as e:
raise NotFound(str(e))
return None, 204
return "", 204
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/published/processing/parameters")
class PublishedRagPipelineSecondStepApi(Resource):
@console_ns.doc(params=query_params_from_model(NodeIdQuery))
@console_ns.response(200, "Success", console_ns.models[RagPipelineStepParametersResponse.__name__])
@console_ns.response(
200,
"Second step parameters retrieved successfully",
console_ns.models[RagPipelineVariablesResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -805,15 +820,17 @@ class PublishedRagPipelineSecondStepApi(Resource):
node_id = query.node_id
rag_pipeline_service = RagPipelineService()
variables = rag_pipeline_service.get_second_step_parameters(pipeline=pipeline, node_id=node_id, is_draft=False)
return {
"variables": variables,
}
return dump_response(RagPipelineVariablesResponse, {"variables": variables})
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/published/pre-processing/parameters")
class PublishedRagPipelineFirstStepApi(Resource):
@console_ns.doc(params=query_params_from_model(NodeIdQuery))
@console_ns.response(200, "Success", console_ns.models[RagPipelineStepParametersResponse.__name__])
@console_ns.response(
200,
"First step parameters retrieved successfully",
console_ns.models[RagPipelineVariablesResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -828,15 +845,17 @@ class PublishedRagPipelineFirstStepApi(Resource):
node_id = query.node_id
rag_pipeline_service = RagPipelineService()
variables = rag_pipeline_service.get_first_step_parameters(pipeline=pipeline, node_id=node_id, is_draft=False)
return {
"variables": variables,
}
return dump_response(RagPipelineVariablesResponse, {"variables": variables})
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/pre-processing/parameters")
class DraftRagPipelineFirstStepApi(Resource):
@console_ns.doc(params=query_params_from_model(NodeIdQuery))
@console_ns.response(200, "Success", console_ns.models[RagPipelineStepParametersResponse.__name__])
@console_ns.response(
200,
"First step parameters retrieved successfully",
console_ns.models[RagPipelineVariablesResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -851,15 +870,17 @@ class DraftRagPipelineFirstStepApi(Resource):
node_id = query.node_id
rag_pipeline_service = RagPipelineService()
variables = rag_pipeline_service.get_first_step_parameters(pipeline=pipeline, node_id=node_id, is_draft=True)
return {
"variables": variables,
}
return dump_response(RagPipelineVariablesResponse, {"variables": variables})
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/processing/parameters")
class DraftRagPipelineSecondStepApi(Resource):
@console_ns.doc(params=query_params_from_model(NodeIdQuery))
@console_ns.response(200, "Success", console_ns.models[RagPipelineStepParametersResponse.__name__])
@console_ns.response(
200,
"Second step parameters retrieved successfully",
console_ns.models[RagPipelineVariablesResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -875,9 +896,7 @@ class DraftRagPipelineSecondStepApi(Resource):
rag_pipeline_service = RagPipelineService()
variables = rag_pipeline_service.get_second_step_parameters(pipeline=pipeline, node_id=node_id, is_draft=True)
return {
"variables": variables,
}
return dump_response(RagPipelineVariablesResponse, {"variables": variables})
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflow-runs")
@ -910,7 +929,7 @@ class RagPipelineWorkflowRunListApi(Resource):
rag_pipeline_service = RagPipelineService()
result = rag_pipeline_service.get_rag_pipeline_paginate_workflow_runs(pipeline=pipeline, args=args)
return WorkflowRunPaginationResponse.model_validate(result, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunPaginationResponse, result)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflow-runs/<uuid:run_id>")
@ -935,7 +954,7 @@ class RagPipelineWorkflowRunDetailApi(Resource):
if workflow_run is None:
raise NotFound("Workflow run not found")
return WorkflowRunDetailResponse.model_validate(workflow_run, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunDetailResponse, workflow_run)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflow-runs/<uuid:run_id>/node-executions")
@ -964,20 +983,25 @@ class RagPipelineWorkflowRunNodeExecutionListApi(Resource):
user=user,
)
return WorkflowRunNodeExecutionListResponse.model_validate(
{"data": node_executions}, from_attributes=True
).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionListResponse, {"data": node_executions})
@console_ns.route("/rag/pipelines/datasource-plugins")
class DatasourceListApi(Resource):
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@console_ns.response(
200,
"Datasource plugins retrieved successfully",
console_ns.models[DatasourcePluginListResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@with_current_tenant_id
def get(self, current_tenant_id: str):
return jsonable_encoder(RagPipelineManageService.list_rag_pipeline_datasources(current_tenant_id))
return dump_response(
DatasourcePluginListResponse,
RagPipelineManageService.list_rag_pipeline_datasources(current_tenant_id),
)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/nodes/<string:node_id>/last-run")
@ -1003,12 +1027,16 @@ class RagPipelineWorkflowLastRunApi(Resource):
)
if node_exec is None:
raise NotFound("last run not found")
return WorkflowRunNodeExecutionResponse.model_validate(node_exec, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, node_exec)
@console_ns.route("/rag/pipelines/transform/datasets/<uuid:dataset_id>")
class RagPipelineTransformApi(Resource):
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@console_ns.response(
200,
"Dataset transformed successfully",
console_ns.models[RagPipelineTransformResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -1020,7 +1048,7 @@ class RagPipelineTransformApi(Resource):
dataset_id_str = str(dataset_id)
rag_pipeline_transform_service = RagPipelineTransformService()
result = rag_pipeline_transform_service.transform_dataset(dataset_id_str, db.session)
return result
return dump_response(RagPipelineTransformResponse, result)
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/draft/datasource/variables-inspect")
@ -1050,15 +1078,17 @@ class RagPipelineDatasourceVariableApi(Resource):
args=args,
current_user=current_user,
)
return WorkflowRunNodeExecutionResponse.model_validate(
workflow_node_execution, from_attributes=True
).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, workflow_node_execution)
@console_ns.route("/rag/pipelines/recommended-plugins")
class RagPipelineRecommendedPluginApi(Resource):
@console_ns.doc(params=query_params_from_model(RagPipelineRecommendedPluginQuery))
@console_ns.response(200, "Success", console_ns.models[RagPipelineOpaqueResponse.__name__])
@console_ns.response(
200,
"Recommended plugins retrieved successfully",
console_ns.models[RagPipelineRecommendedPluginResponse.__name__],
)
@setup_required
@login_required
@account_initialization_required
@ -1069,4 +1099,4 @@ class RagPipelineRecommendedPluginApi(Resource):
rag_pipeline_service = RagPipelineService()
recommended_plugins = rag_pipeline_service.get_recommended_plugins(query.type, current_user, current_tenant_id)
return recommended_plugins
return dump_response(RagPipelineRecommendedPluginResponse, recommended_plugins)

View File

@ -8,20 +8,18 @@ from pydantic import BaseModel, Field
from sqlalchemy.orm import Session, sessionmaker
from werkzeug.exceptions import BadRequest, InternalServerError, NotFound
from controllers.common.fields import GeneratedAppResponse, SimpleResultResponse
from controllers.common.fields import EventStreamResponse, SimpleResultResponse
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.console import console_ns
from controllers.console.app.error import DraftWorkflowNotExist, DraftWorkflowNotSync
from controllers.console.app.workflow import (
RESTORE_SOURCE_WORKFLOW_MUST_BE_PUBLISHED_MESSAGE,
DefaultBlockConfigsResponse,
PublishWorkflowResponse,
SyncDraftWorkflowResponse,
WorkflowPaginationResponse,
WorkflowPublishResponse,
WorkflowResponse,
WorkflowRestoreResponse,
)
from controllers.console.snippets.payloads import (
PublishWorkflowPayload,
SnippetDraftNodeRunPayload,
SnippetDraftRunPayload,
SnippetDraftSyncPayload,
@ -43,6 +41,7 @@ from core.app.apps.base_app_queue_manager import AppQueueManager
from core.app.entities.app_invoke_entities import InvokeFrom
from extensions.ext_database import db
from extensions.ext_redis import redis_client
from fields.base import ResponseModel
from fields.workflow_run_fields import (
WorkflowRunDetailResponse,
WorkflowRunNodeExecutionListResponse,
@ -51,7 +50,7 @@ from fields.workflow_run_fields import (
)
from graphon.graph_engine.manager import GraphEngineManager
from libs import helper
from libs.helper import TimestampField
from libs.helper import dump_response, to_timestamp
from libs.login import current_account_with_tenant, login_required
from models import Account
from models.snippet import CustomizedSnippet
@ -76,7 +75,7 @@ class SnippetWorkflowResponse(WorkflowResponse):
input_fields: list[dict] = Field(default_factory=list)
class SnippetDraftConfigResponse(BaseModel):
class SnippetDraftConfigResponse(ResponseModel):
parallel_depth_limit: int
@ -96,19 +95,17 @@ register_schema_models(
SnippetLoopNodeRunPayload,
SnippetWorkflowListQuery,
WorkflowRunQuery,
PublishWorkflowPayload,
)
register_response_schema_models(
console_ns,
DefaultBlockConfigsResponse,
GeneratedAppResponse,
EventStreamResponse,
SimpleResultResponse,
SnippetDraftConfigResponse,
SnippetWorkflowResponse,
SnippetWorkflowPaginationResponse,
WorkflowPublishResponse,
PublishWorkflowResponse,
WorkflowPaginationResponse,
WorkflowRestoreResponse,
SyncDraftWorkflowResponse,
WorkflowRunPaginationResponse,
WorkflowRunDetailResponse,
WorkflowRunNodeExecutionListResponse,
@ -175,7 +172,7 @@ class SnippetDraftWorkflowApi(Resource):
raise DraftWorkflowNotExist()
workflow.conversation_variables = []
response = SnippetWorkflowResponse.model_validate(workflow, from_attributes=True).model_dump(mode="json")
response = dump_response(SnippetWorkflowResponse, workflow)
response["input_fields"] = snippet.input_fields_list
return response
@ -184,7 +181,7 @@ class SnippetDraftWorkflowApi(Resource):
@console_ns.response(
200,
"Draft workflow synced successfully",
console_ns.models[WorkflowRestoreResponse.__name__],
console_ns.models[SyncDraftWorkflowResponse.__name__],
)
@console_ns.response(400, "Hash mismatch")
@setup_required
@ -214,11 +211,11 @@ class SnippetDraftWorkflowApi(Resource):
except ValueError as e:
return {"message": str(e)}, 400
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return SyncDraftWorkflowResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/config")
@ -237,9 +234,7 @@ class SnippetDraftConfigApi(Resource):
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_MANAGE, resource_required=False)
def get(self, snippet: CustomizedSnippet):
"""Get snippet draft workflow configuration limits."""
return {
"parallel_depth_limit": 3,
}
return SnippetDraftConfigResponse(parallel_depth_limit=3).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/publish")
@ -268,13 +263,12 @@ class SnippetPublishedWorkflowApi(Resource):
if not workflow:
return None
response = SnippetWorkflowResponse.model_validate(workflow, from_attributes=True).model_dump(mode="json")
response = dump_response(SnippetWorkflowResponse, workflow)
response["input_fields"] = snippet.input_fields_list
return response
@console_ns.doc("publish_snippet_workflow")
@console_ns.expect(console_ns.models.get(PublishWorkflowPayload.__name__))
@console_ns.response(200, "Workflow published successfully", console_ns.models[WorkflowPublishResponse.__name__])
@console_ns.response(200, "Workflow published successfully", console_ns.models[PublishWorkflowResponse.__name__])
@console_ns.response(400, "No draft workflow found")
@setup_required
@login_required
@ -297,25 +291,18 @@ class SnippetPublishedWorkflowApi(Resource):
snippet=snippet,
account=current_user,
)
workflow_created_at = TimestampField().format(workflow.created_at)
workflow_created_at = to_timestamp(workflow.created_at)
session.commit()
except ValueError as e:
return {"message": str(e)}, 400
return {
"result": "success",
"created_at": workflow_created_at,
}
return PublishWorkflowResponse(result="success", created_at=workflow_created_at).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/default-workflow-block-configs")
class SnippetDefaultBlockConfigsApi(Resource):
@console_ns.doc("get_snippet_default_block_configs")
@console_ns.response(
200,
"Default block configs retrieved successfully",
console_ns.models[DefaultBlockConfigsResponse.__name__],
)
@console_ns.response(200, "Default block configs retrieved successfully")
@setup_required
@login_required
@account_initialization_required
@ -377,7 +364,7 @@ class SnippetDraftWorkflowRestoreApi(Resource):
@console_ns.doc("restore_snippet_workflow_to_draft")
@console_ns.doc(description="Restore a published snippet workflow version into the draft workflow")
@console_ns.doc(params={"snippet_id": "Snippet ID", "workflow_id": "Published workflow ID"})
@console_ns.response(200, "Workflow restored successfully", console_ns.models[WorkflowRestoreResponse.__name__])
@console_ns.response(200, "Workflow restored successfully", console_ns.models[SyncDraftWorkflowResponse.__name__])
@console_ns.response(400, "Source workflow must be published")
@console_ns.response(404, "Workflow not found")
@setup_required
@ -406,11 +393,11 @@ class SnippetDraftWorkflowRestoreApi(Resource):
except ValueError as exc:
raise BadRequest(str(exc)) from exc
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
return SyncDraftWorkflowResponse(
result="success",
hash=workflow.unique_hash,
updated_at=to_timestamp(workflow.updated_at or workflow.created_at),
).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflow-runs")
@ -442,7 +429,7 @@ class SnippetWorkflowRunsApi(Resource):
snippet_service = _snippet_service()
result = snippet_service.get_snippet_workflow_runs(snippet=snippet, args=args)
return WorkflowRunPaginationResponse.model_validate(result, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunPaginationResponse, result)
@console_ns.route("/snippets/<uuid:snippet_id>/workflow-runs/<uuid:run_id>")
@ -468,7 +455,7 @@ class SnippetWorkflowRunDetailApi(Resource):
if not workflow_run:
raise NotFound("Workflow run not found")
return WorkflowRunDetailResponse.model_validate(workflow_run, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunDetailResponse, workflow_run)
@console_ns.route("/snippets/<uuid:snippet_id>/workflow-runs/<uuid:run_id>/node-executions")
@ -493,9 +480,7 @@ class SnippetWorkflowRunNodeExecutionsApi(Resource):
run_id=run_id,
)
return WorkflowRunNodeExecutionListResponse.model_validate(
{"data": node_executions}, from_attributes=True
).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionListResponse, {"data": node_executions})
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/nodes/<string:node_id>/run")
@ -546,9 +531,7 @@ class SnippetDraftNodeRunApi(Resource):
session_maker=_snippet_session_maker(),
)
return WorkflowRunNodeExecutionResponse.model_validate(
workflow_node_execution, from_attributes=True
).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, workflow_node_execution)
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/nodes/<string:node_id>/last-run")
@ -584,7 +567,7 @@ class SnippetDraftNodeLastRunApi(Resource):
if node_exec is None:
raise NotFound("Node last run not found")
return WorkflowRunNodeExecutionResponse.model_validate(node_exec, from_attributes=True).model_dump(mode="json")
return dump_response(WorkflowRunNodeExecutionResponse, node_exec)
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/iteration/nodes/<string:node_id>/run")
@ -596,7 +579,7 @@ class SnippetDraftRunIterationNodeApi(Resource):
@console_ns.response(
200,
"Iteration node run started successfully (SSE stream)",
console_ns.models[GeneratedAppResponse.__name__],
console_ns.models[EventStreamResponse.__name__],
)
@console_ns.response(404, "Snippet or draft workflow not found")
@setup_required
@ -627,6 +610,7 @@ class SnippetDraftRunIterationNodeApi(Resource):
session_maker=_snippet_session_maker(),
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except ValueError as e:
raise e
@ -644,7 +628,7 @@ class SnippetDraftRunLoopNodeApi(Resource):
@console_ns.response(
200,
"Loop node run started successfully (SSE stream)",
console_ns.models[GeneratedAppResponse.__name__],
console_ns.models[EventStreamResponse.__name__],
)
@console_ns.response(404, "Snippet or draft workflow not found")
@setup_required
@ -675,6 +659,7 @@ class SnippetDraftRunLoopNodeApi(Resource):
session_maker=_snippet_session_maker(),
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except ValueError as e:
raise e
@ -690,7 +675,7 @@ class SnippetDraftWorkflowRunApi(Resource):
@console_ns.response(
200,
"Draft workflow run started successfully (SSE stream)",
console_ns.models[GeneratedAppResponse.__name__],
console_ns.models[EventStreamResponse.__name__],
)
@console_ns.response(404, "Snippet or draft workflow not found")
@setup_required
@ -722,6 +707,7 @@ class SnippetDraftWorkflowRunApi(Resource):
session_maker=_snippet_session_maker(),
)
# response-contract:ignore compact_generate_response
return helper.compact_generate_response(response)
except ValueError as e:
raise e
@ -757,4 +743,4 @@ class SnippetWorkflowTaskStopApi(Resource):
# New graph engine command channel mechanism
GraphEngineManager(redis_client).send_stop_command(task_id)
return {"result": "success"}
return SimpleResultResponse(result="success").model_dump(mode="json")

View File

@ -15,7 +15,7 @@ from functools import wraps
from typing import Any, Concatenate
from flask import Response, request
from flask_restx import Resource, marshal, marshal_with
from flask_restx import Resource
from sqlalchemy.orm import Session, sessionmaker
from controllers.common.errors import InvalidArgumentError, NotFoundError
@ -23,14 +23,15 @@ from controllers.common.schema import query_params_from_model
from controllers.console import console_ns
from controllers.console.app.error import DraftWorkflowNotExist
from controllers.console.app.workflow_draft_variable import (
EnvironmentVariableListResponse,
WorkflowDraftEnvironmentVariableListResponse,
WorkflowDraftEnvironmentVariableResponse,
WorkflowDraftVariableListQuery,
WorkflowDraftVariableListResponse,
WorkflowDraftVariableListWithoutValueResponse,
WorkflowDraftVariableResponse,
WorkflowDraftVariableUpdatePayload,
ensure_variable_access,
validate_node_id,
workflow_draft_variable_list_model,
workflow_draft_variable_list_without_value_model,
workflow_draft_variable_model,
)
from controllers.console.snippets.snippet_workflow import get_snippet
from controllers.console.wraps import (
@ -101,12 +102,11 @@ class SnippetWorkflowVariableCollectionApi(Resource):
@console_ns.response(
200,
"Workflow variables retrieved successfully",
workflow_draft_variable_list_without_value_model,
console_ns.models[WorkflowDraftVariableListWithoutValueResponse.__name__],
)
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_list_without_value_model)
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_MANAGE, resource_required=False)
def get(self, current_user: Account, snippet: CustomizedSnippet) -> WorkflowDraftVariableList:
def get(self, current_user: Account, snippet: CustomizedSnippet) -> dict[str, Any]:
args = WorkflowDraftVariableListQuery.model_validate(request.args.to_dict(flat=True)) # type: ignore
snippet_service = _snippet_service()
@ -123,7 +123,9 @@ class SnippetWorkflowVariableCollectionApi(Resource):
exclude_node_ids=_SNIPPET_EXCLUDED_DRAFT_VARIABLE_NODE_IDS,
)
return workflow_vars
return WorkflowDraftVariableListWithoutValueResponse.from_workflow_draft_variable_list(
workflow_vars
).model_dump(mode="json")
@console_ns.doc("delete_snippet_workflow_variables")
@console_ns.doc(description="Delete all draft workflow variables for the current user (snippet scope)")
@ -132,49 +134,53 @@ class SnippetWorkflowVariableCollectionApi(Resource):
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
def delete(self, current_user: Account, snippet: CustomizedSnippet) -> Response:
def delete(self, current_user: Account, snippet: CustomizedSnippet) -> tuple[str, int]:
draft_var_srv = WorkflowDraftVariableService(session=db.session())
draft_var_srv.delete_user_workflow_variables(snippet.id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/nodes/<string:node_id>/variables")
class SnippetNodeVariableCollectionApi(Resource):
@console_ns.doc("get_snippet_node_variables")
@console_ns.doc(description="Get variables for a specific node (snippet draft workflow)")
@console_ns.response(200, "Node variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"Node variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_list_model)
def get(self, current_user: Account, snippet: CustomizedSnippet, node_id: str) -> WorkflowDraftVariableList:
def get(self, current_user: Account, snippet: CustomizedSnippet, node_id: str) -> dict[str, Any]:
validate_node_id(node_id)
with Session(bind=db.engine, expire_on_commit=False) as session:
draft_var_srv = WorkflowDraftVariableService(session=session)
node_vars = draft_var_srv.list_node_variables(snippet.id, node_id, user_id=current_user.id)
return node_vars
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(node_vars).model_dump(mode="json")
@console_ns.doc("delete_snippet_node_variables")
@console_ns.doc(description="Delete all variables for a specific node (snippet draft workflow)")
@console_ns.response(204, "Node variables deleted successfully")
@_snippet_draft_var_prerequisite
def delete(self, current_user: Account, snippet: CustomizedSnippet, node_id: str) -> Response:
def delete(self, current_user: Account, snippet: CustomizedSnippet, node_id: str):
validate_node_id(node_id)
srv = WorkflowDraftVariableService(db.session())
srv.delete_node_variables(snippet.id, node_id, user_id=current_user.id)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/variables/<uuid:variable_id>")
class SnippetVariableApi(Resource):
@console_ns.doc("get_snippet_workflow_variable")
@console_ns.doc(description="Get a specific draft workflow variable (snippet scope)")
@console_ns.response(200, "Variable retrieved successfully", workflow_draft_variable_model)
@console_ns.response(
200, "Variable retrieved successfully", console_ns.models[WorkflowDraftVariableResponse.__name__]
)
@console_ns.response(404, "Variable not found")
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_model)
def get(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str) -> WorkflowDraftVariable:
def get(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str) -> dict[str, Any]:
draft_var_srv = WorkflowDraftVariableService(session=db.session())
variable = ensure_variable_access(
variable=draft_var_srv.get_variable(variable_id=variable_id),
@ -183,16 +189,17 @@ class SnippetVariableApi(Resource):
current_user_id=current_user.id,
)
_ensure_snippet_draft_variable_row_allowed(variable=variable, variable_id=variable_id)
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.doc("update_snippet_workflow_variable")
@console_ns.doc(description="Update a draft workflow variable (snippet scope)")
@console_ns.expect(console_ns.models[WorkflowDraftVariableUpdatePayload.__name__])
@console_ns.response(200, "Variable updated successfully", workflow_draft_variable_model)
@console_ns.response(
200, "Variable updated successfully", console_ns.models[WorkflowDraftVariableResponse.__name__]
)
@console_ns.response(404, "Variable not found")
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_model)
def patch(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str) -> WorkflowDraftVariable:
def patch(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str) -> dict[str, Any]:
draft_var_srv = WorkflowDraftVariableService(session=db.session())
args_model = WorkflowDraftVariableUpdatePayload.model_validate(console_ns.payload or {})
@ -207,39 +214,46 @@ class SnippetVariableApi(Resource):
new_name = args_model.name
raw_value = args_model.value
if new_name is None and raw_value is None:
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
new_value = None
if raw_value is not None:
if variable.value_type == SegmentType.FILE:
if not isinstance(raw_value, dict):
raise InvalidArgumentError(description=f"expected dict for file, got {type(raw_value)}")
raw_value = build_from_mapping(
new_value_input: Any
match variable.value_type:
case SegmentType.FILE:
if not isinstance(raw_value, dict):
raise InvalidArgumentError(description=f"expected dict for file, got {type(raw_value)}")
new_value_input = build_from_mapping(
mapping=raw_value,
tenant_id=snippet.tenant_id,
access_controller=_file_access_controller,
)
elif variable.value_type == SegmentType.ARRAY_FILE:
if not isinstance(raw_value, list):
raise InvalidArgumentError(description=f"expected list for files, got {type(raw_value)}")
if len(raw_value) > 0 and not isinstance(raw_value[0], dict):
raise InvalidArgumentError(description=f"expected dict for files[0], got {type(raw_value)}")
raw_value = build_from_mappings(
case SegmentType.ARRAY_FILE:
if not isinstance(raw_value, list):
raise InvalidArgumentError(description=f"expected list for files, got {type(raw_value)}")
for index, item in enumerate(raw_value):
if not isinstance(item, dict):
raise InvalidArgumentError(
description=f"expected dict for files[{index}], got {type(item)}"
)
new_value_input = build_from_mappings(
mappings=raw_value,
tenant_id=snippet.tenant_id,
access_controller=_file_access_controller,
)
new_value = build_segment_with_type(variable.value_type, raw_value)
case _:
new_value_input = raw_value
new_value = build_segment_with_type(variable.value_type, new_value_input)
draft_var_srv.update_variable(variable, name=new_name, value=new_value)
db.session.commit()
return variable
return WorkflowDraftVariableResponse.from_workflow_draft_variable(variable).model_dump(mode="json")
@console_ns.doc("delete_snippet_workflow_variable")
@console_ns.doc(description="Delete a draft workflow variable (snippet scope)")
@console_ns.response(204, "Variable deleted successfully")
@console_ns.response(404, "Variable not found")
@_snippet_draft_var_prerequisite
def delete(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str) -> Response:
def delete(self, current_user: Account, snippet: CustomizedSnippet, variable_id: str):
draft_var_srv = WorkflowDraftVariableService(session=db.session())
variable = ensure_variable_access(
variable=draft_var_srv.get_variable(variable_id=variable_id),
@ -250,14 +264,14 @@ class SnippetVariableApi(Resource):
_ensure_snippet_draft_variable_row_allowed(variable=variable, variable_id=variable_id)
draft_var_srv.delete_variable(variable)
db.session.commit()
return Response("", 204)
return "", 204
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/variables/<uuid:variable_id>/reset")
class SnippetVariableResetApi(Resource):
@console_ns.doc("reset_snippet_workflow_variable")
@console_ns.doc(description="Reset a draft workflow variable to its default value (snippet scope)")
@console_ns.response(200, "Variable reset successfully", workflow_draft_variable_model)
@console_ns.response(200, "Variable reset successfully", console_ns.models[WorkflowDraftVariableResponse.__name__])
@console_ns.response(204, "Variable reset (no content)")
@console_ns.response(404, "Variable not found")
@_snippet_draft_var_prerequisite
@ -281,7 +295,7 @@ class SnippetVariableResetApi(Resource):
db.session.commit()
if resetted is None:
return Response("", 204)
return marshal(resetted, workflow_draft_variable_model)
return WorkflowDraftVariableResponse.from_workflow_draft_variable(resetted).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/conversation-variables")
@ -290,11 +304,16 @@ class SnippetConversationVariableCollectionApi(Resource):
@console_ns.doc(
description="Conversation variables are not used in snippet workflows; returns an empty list for API parity"
)
@console_ns.response(200, "Conversation variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"Conversation variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_list_model)
def get(self, _current_user: Account, snippet: CustomizedSnippet) -> WorkflowDraftVariableList:
return WorkflowDraftVariableList(variables=[])
def get(self, _current_user: Account, snippet: CustomizedSnippet) -> dict[str, Any]:
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
WorkflowDraftVariableList(variables=[])
).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/system-variables")
@ -303,11 +322,16 @@ class SnippetSystemVariableCollectionApi(Resource):
@console_ns.doc(
description="System variables are not used in snippet workflows; returns an empty list for API parity"
)
@console_ns.response(200, "System variables retrieved successfully", workflow_draft_variable_list_model)
@console_ns.response(
200,
"System variables retrieved successfully",
console_ns.models[WorkflowDraftVariableListResponse.__name__],
)
@_snippet_draft_var_prerequisite
@marshal_with(workflow_draft_variable_list_model)
def get(self, _current_user: Account, snippet: CustomizedSnippet) -> WorkflowDraftVariableList:
return WorkflowDraftVariableList(variables=[])
def get(self, _current_user: Account, snippet: CustomizedSnippet) -> dict[str, Any]:
return WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
WorkflowDraftVariableList(variables=[])
).model_dump(mode="json")
@console_ns.route("/snippets/<uuid:snippet_id>/workflows/draft/environment-variables")
@ -317,7 +341,7 @@ class SnippetEnvironmentVariableCollectionApi(Resource):
@console_ns.response(
200,
"Environment variables retrieved successfully",
console_ns.models[EnvironmentVariableListResponse.__name__],
console_ns.models[WorkflowDraftEnvironmentVariableListResponse.__name__],
)
@console_ns.response(404, "Draft workflow not found")
@_snippet_draft_var_prerequisite
@ -327,21 +351,21 @@ class SnippetEnvironmentVariableCollectionApi(Resource):
if workflow is None:
raise DraftWorkflowNotExist()
env_vars_list: list[dict[str, Any]] = []
env_vars_list: list[WorkflowDraftEnvironmentVariableResponse] = []
for v in workflow.environment_variables:
env_vars_list.append(
{
"id": v.id,
"type": "env",
"name": v.name,
"description": v.description,
"selector": v.selector,
"value_type": v.value_type.exposed_type().value,
"value": v.value,
"edited": False,
"visible": True,
"editable": True,
}
WorkflowDraftEnvironmentVariableResponse(
id=v.id,
type="env",
name=v.name,
description=v.description,
selector=list(v.selector),
value_type=v.value_type.exposed_type().value,
value=v.value,
edited=False,
visible=True,
editable=True,
)
)
return {"items": env_vars_list}
return WorkflowDraftEnvironmentVariableListResponse(items=env_vars_list).model_dump(mode="json")

View File

@ -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

View File

@ -1,53 +1,14 @@
"""Workflow run response schemas for console APIs.
Most workflow-run endpoints should document and serialize responses with the
Pydantic models in this module. The remaining Flask-RESTX field dictionaries are
kept only for workflow app-log endpoints that still build legacy log models.
"""
from __future__ import annotations
from datetime import datetime
from typing import Any
from flask_restx import Namespace, fields
from pydantic import AliasChoices, Field, field_validator
from fields.base import ResponseModel
from fields.end_user_fields import SimpleEndUser
from fields.member_fields import SimpleAccount
from libs.helper import TimestampField, to_timestamp
workflow_run_for_log_fields = {
"id": fields.String,
"version": fields.String,
"status": fields.String,
"triggered_from": fields.String,
"error": fields.String,
"elapsed_time": fields.Float,
"total_tokens": fields.Integer,
"total_steps": fields.Integer,
"created_at": TimestampField,
"finished_at": TimestampField,
"exceptions_count": fields.Integer,
}
def build_workflow_run_for_log_model(api_or_ns: Namespace):
return api_or_ns.model("WorkflowRunForLog", workflow_run_for_log_fields)
workflow_run_for_archived_log_fields = {
"id": fields.String,
"status": fields.String,
"triggered_from": fields.String,
"elapsed_time": fields.Float,
"total_tokens": fields.Integer,
}
def build_workflow_run_for_archived_log_model(api_or_ns: Namespace):
return api_or_ns.model("WorkflowRunForArchivedLog", workflow_run_for_archived_log_fields)
from fields.member_fields import SimpleAccountResponse
from libs.helper import to_timestamp
class WorkflowRunForLogResponse(ResponseModel):
@ -98,7 +59,7 @@ class WorkflowRunForListResponse(ResponseModel):
elapsed_time: float | None = None
total_tokens: int | None = None
total_steps: int | None = None
created_by_account: SimpleAccount | None = None
created_by_account: SimpleAccountResponse | None = None
created_at: int | None = None
finished_at: int | None = None
exceptions_count: int | None = None
@ -158,7 +119,7 @@ class WorkflowRunDetailResponse(ResponseModel):
total_tokens: int | None = None
total_steps: int | 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
finished_at: int | None = None
@ -194,7 +155,7 @@ class WorkflowRunNodeExecutionResponse(ResponseModel):
extras: Any = None
created_at: int | 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
finished_at: int | None = None
inputs_truncated: bool | None = None

File diff suppressed because it is too large Load Diff

View File

@ -3937,7 +3937,7 @@ Model class for provider with models response.
| output_variable_name | string | | Yes |
| type | string | | No |
#### SimpleAccount
#### SimpleAccountResponse
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
@ -4147,7 +4147,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 |

View File

@ -1004,6 +1004,9 @@ class WorkflowService:
"""
Build a human input form preview for a draft workflow.
Preview responses are non-actionable: they mirror the live pause payload
shape without creating a persisted form, recipient token, or expiration.
Args:
app_model: Target application model.
account: Current account.

View File

@ -62,6 +62,7 @@ from controllers.console.app.workflow_statistic import WorkflowStatisticQuery
from controllers.console.app.workflow_trigger import Parser, ParserEnable
from models.account import Account, AccountStatus
from models.model import AppMode
from services.workflow_draft_variable_service import WorkflowDraftVariableList
from tests.test_containers_integration_tests.controllers.console.helpers import (
authenticate_console_client,
create_console_account_and_tenant,
@ -512,7 +513,7 @@ class TestWorkflowDraftVariableEndpoints:
self.session = session
def list_variables_without_values(self, **_kwargs):
return {"items": [], "total": 0}
return WorkflowDraftVariableList(variables=[], total=0)
monkeypatch.setattr(workflow_draft_variable_module, "sessionmaker", DummySessionMaker)

View File

@ -607,7 +607,11 @@ class TestMiscApis:
method = unwrap(api.get)
service = MagicMock()
service.get_recommended_plugins.return_value = [{"id": "p1"}]
recommended_plugins = {
"installed_recommended_plugins": [{"id": "p1"}],
"uninstalled_recommended_plugins": [{"id": "p2"}],
}
service.get_recommended_plugins.return_value = recommended_plugins
user = make_account()
tenant_id = "tenant-1"
@ -619,7 +623,7 @@ class TestMiscApis:
),
):
result = method(api, tenant_id, user)
assert result == [{"id": "p1"}]
assert result == recommended_plugins
service.get_recommended_plugins.assert_called_once_with("all", user, tenant_id)
@ -826,7 +830,7 @@ class TestRagPipelineByIdApi:
result = method(api, pipeline, "old-workflow")
workflow_service.delete_workflow.assert_called_once()
assert result == (None, 204)
assert result == ("", 204)
def test_delete_active_workflow_rejected(self, app: Flask) -> None:
api = RagPipelineByIdApi()

View File

@ -0,0 +1,767 @@
import uuid
from contextlib import nullcontext
from inspect import unwrap
from types import SimpleNamespace
from typing import Any, NamedTuple
from unittest.mock import Mock, patch
import pytest
from flask import Flask
from controllers.console.app import workflow_draft_variable as draft_variable_module
from controllers.console.app.workflow_draft_variable import (
EnvironmentVariableCollectionApi,
NodeVariableCollectionApi,
VariableApi,
WorkflowDraftVariableFullContentResponse,
WorkflowDraftVariableListResponse,
WorkflowDraftVariableListWithoutValueResponse,
WorkflowDraftVariableResponse,
WorkflowDraftVariableWithoutValueResponse,
WorkflowVariableCollectionApi,
)
from core.workflow.variable_prefixes import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID
from factories.variable_factory import build_segment
from graphon.variables.types import SegmentType
from libs.datetime_utils import naive_utc_now
from libs.uuid_utils import uuidv7
from models import Account, App, AppMode
from models.workflow import WorkflowDraftVariable, WorkflowDraftVariableFile
from services.workflow_draft_variable_service import WorkflowDraftVariableList
_TEST_APP_ID = "test_app_id"
_TEST_NODE_EXEC_ID = str(uuid.uuid4())
def _app_model() -> App:
app_model = App()
app_model.id = _TEST_APP_ID
app_model.tenant_id = "tenant-1"
app_model.name = "test app"
app_model.mode = AppMode.WORKFLOW
return app_model
def _current_user() -> Account:
account = Account(name="Test User", email="user@example.com")
account.id = "user-1"
return account
def _node_variable(*, value: Any = "value") -> WorkflowDraftVariable:
variable = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
user_id="user-1",
node_id="node-1",
name="node_var",
value=build_segment(value),
node_execution_id=_TEST_NODE_EXEC_ID,
)
variable.id = str(uuid.uuid4())
return variable
def _assert_raw_payload_matches_model(payload: dict[str, Any], model: type[Any], expected: dict[str, Any]) -> None:
assert payload == expected
assert model.model_validate(payload).model_dump(mode="json") == expected
def test_workflow_draft_variable_update_payload_keeps_value_as_json_until_variable_type_is_known() -> None:
payload = draft_variable_module.WorkflowDraftVariableUpdatePayload.model_validate(
{"value": {"transfer_method": "ordinary-object-field", "nested": {"enabled": True}}}
)
assert payload.value == {"transfer_method": "ordinary-object-field", "nested": {"enabled": True}}
def test_workflow_variable_collection_get_returns_without_value_contract(
app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
variable = _node_variable()
captured_args: dict[str, Any] = {}
class WorkflowService:
def is_workflow_exist(self, *, app_model: Any) -> bool:
captured_args["workflow_app_id"] = app_model.id
return True
class DraftVariableService:
def __init__(self, *, session: object) -> None:
captured_args["session"] = session
def list_variables_without_values(self, **kwargs: Any) -> WorkflowDraftVariableList:
captured_args.update(kwargs)
return WorkflowDraftVariableList(variables=[variable], total=None)
session = object()
monkeypatch.setattr(draft_variable_module, "WorkflowService", WorkflowService)
monkeypatch.setattr(draft_variable_module, "WorkflowDraftVariableService", DraftVariableService)
monkeypatch.setattr(draft_variable_module, "db", SimpleNamespace(engine=object()))
monkeypatch.setattr(
draft_variable_module,
"sessionmaker",
lambda *_args, **_kwargs: SimpleNamespace(begin=lambda: nullcontext(session)),
)
api = WorkflowVariableCollectionApi()
handler = unwrap(api.get)
with app.test_request_context("/apps/app-1/workflows/draft/variables?page=2&limit=3", method="GET"):
payload = handler(api, _current_user(), _app_model())
expected_payload = {
"items": [
{
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node-1", "node_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
}
],
"total": None,
}
assert captured_args == {
"workflow_app_id": _TEST_APP_ID,
"session": session,
"app_id": _TEST_APP_ID,
"page": 2,
"limit": 3,
"user_id": "user-1",
}
_assert_raw_payload_matches_model(payload, WorkflowDraftVariableListWithoutValueResponse, expected_payload)
def test_node_variable_collection_get_returns_value_contract(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
variable = _node_variable(value=None)
class DraftVariableService:
def __init__(self, *, session: object) -> None:
pass
def list_node_variables(self, app_id: str, node_id: str, *, user_id: str) -> WorkflowDraftVariableList:
assert (app_id, node_id, user_id) == (_TEST_APP_ID, "node-1", "user-1")
return WorkflowDraftVariableList(variables=[variable])
monkeypatch.setattr(draft_variable_module, "WorkflowDraftVariableService", DraftVariableService)
monkeypatch.setattr(draft_variable_module, "db", SimpleNamespace(engine=object()))
monkeypatch.setattr(
draft_variable_module,
"sessionmaker",
lambda *_args, **_kwargs: SimpleNamespace(begin=lambda: nullcontext(object())),
)
api = NodeVariableCollectionApi()
handler = unwrap(api.get)
with app.test_request_context("/apps/app-1/workflows/draft/nodes/node-1/variables", method="GET"):
payload = handler(api, _current_user(), _app_model(), "node-1")
expected_payload = {
"items": [
{
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node-1", "node_var"],
"value_type": "none",
"edited": False,
"visible": True,
"is_truncated": False,
"value": None,
"full_content": None,
}
]
}
_assert_raw_payload_matches_model(payload, WorkflowDraftVariableListResponse, expected_payload)
def test_variable_patch_noop_returns_current_variable_contract(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
variable = _node_variable(value=42)
update_variable_mock = Mock()
class DraftVariableService:
def __init__(self, session: object) -> None:
pass
def get_variable(self, *, variable_id: str) -> WorkflowDraftVariable:
assert variable_id == variable.id
return variable
def update_variable(self, *args: Any, **kwargs: Any) -> None:
update_variable_mock(*args, **kwargs)
monkeypatch.setattr(draft_variable_module, "WorkflowDraftVariableService", DraftVariableService)
session = Mock(return_value=object())
session.commit = Mock()
monkeypatch.setattr(draft_variable_module, "db", SimpleNamespace(session=session))
api = VariableApi()
handler = unwrap(api.patch)
with app.test_request_context(f"/apps/app-1/workflows/draft/variables/{variable.id}", method="PATCH", json={}):
payload = handler(api, _current_user(), _app_model(), uuid.UUID(variable.id))
expected_payload = {
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node-1", "node_var"],
"value_type": "number",
"edited": False,
"visible": True,
"is_truncated": False,
"value": 42,
"full_content": None,
}
update_variable_mock.assert_not_called()
_assert_raw_payload_matches_model(payload, WorkflowDraftVariableResponse, expected_payload)
def test_variable_patch_file_value_forwards_raw_mapping_to_file_factory(
app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
variable = _node_variable(value="old")
variable.value_type = SegmentType.FILE
raw_mapping = {
"transfer_method": "local_file",
"upload_file_id": "file-1",
"filename": "kept-for-file-factory",
}
built_file = object()
captured: dict[str, Any] = {}
def build_from_mapping(**kwargs: Any) -> object:
captured.update(kwargs)
return built_file
def build_segment_with_type(segment_type: SegmentType, value: object):
assert segment_type == SegmentType.FILE
assert value is built_file
return build_segment("updated")
class DraftVariableService:
def __init__(self, session: object) -> None:
pass
def get_variable(self, *, variable_id: str) -> WorkflowDraftVariable:
assert variable_id == variable.id
return variable
def update_variable(self, target: WorkflowDraftVariable, *, name: str | None, value: Any) -> None:
assert target is variable
assert name is None
target.set_value(value)
monkeypatch.setattr(draft_variable_module, "WorkflowDraftVariableService", DraftVariableService)
monkeypatch.setattr(draft_variable_module, "build_from_mapping", build_from_mapping)
monkeypatch.setattr(draft_variable_module, "build_segment_with_type", build_segment_with_type)
session = Mock(return_value=object())
session.commit = Mock()
monkeypatch.setattr(draft_variable_module, "db", SimpleNamespace(session=session))
api = VariableApi()
handler = unwrap(api.patch)
with app.test_request_context(
f"/apps/app-1/workflows/draft/variables/{variable.id}",
method="PATCH",
json={"value": raw_mapping},
):
payload = handler(api, _current_user(), _app_model(), uuid.UUID(variable.id))
assert captured["tenant_id"] == "tenant-1"
assert captured["mapping"] == raw_mapping
expected_payload = {
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node-1", "node_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
"value": "updated",
"full_content": None,
}
_assert_raw_payload_matches_model(payload, WorkflowDraftVariableResponse, expected_payload)
def test_environment_variable_collection_get_returns_response_model_contract(
app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
env_var = SimpleNamespace(
id="env-1",
name="API_KEY",
description="secret token",
selector=["env", "API_KEY"],
value_type=SegmentType.SECRET,
value="token",
)
class WorkflowService:
def get_draft_workflow(self, *, app_model: Any) -> SimpleNamespace:
assert app_model.id == _TEST_APP_ID
return SimpleNamespace(environment_variables=[env_var])
monkeypatch.setattr(draft_variable_module, "WorkflowService", WorkflowService)
api = EnvironmentVariableCollectionApi()
handler = unwrap(api.get)
with app.test_request_context("/apps/app-1/workflows/draft/environment-variables", method="GET"):
payload = handler(api, _current_user(), _app_model())
expected_payload = {
"items": [
{
"id": "env-1",
"type": "env",
"name": "API_KEY",
"description": "secret token",
"selector": ["env", "API_KEY"],
"value_type": "secret",
"value": "token",
"edited": False,
"visible": True,
"editable": True,
}
]
}
_assert_raw_payload_matches_model(
payload,
draft_variable_module.WorkflowDraftEnvironmentVariableListResponse,
expected_payload,
)
class TestWorkflowDraftVariableFields:
def test_full_content_response_constructor(self):
"""Test that full_content serialization uses pre-loaded relationships."""
# Create mock objects with relationships pre-loaded
mock_variable = WorkflowDraftVariable(
file_id="test-file-id",
variable_file=WorkflowDraftVariableFile(
size=100000,
length=50,
value_type=SegmentType.OBJECT,
upload_file_id="test-upload-file-id",
tenant_id=str(uuid.uuid4()),
app_id=str(uuid.uuid4()),
user_id=str(uuid.uuid4()),
),
)
# Mock the file helpers
with patch("controllers.console.app.workflow_draft_variable.file_helpers", autospec=True) as mock_file_helpers:
mock_file_helpers.get_signed_file_url.return_value = "http://example.com/signed-url"
# Call the function
result = WorkflowDraftVariableFullContentResponse.from_workflow_draft_variable(mock_variable)
# Verify it returns the expected structure
assert result is not None
assert result.size_bytes == 100000
assert result.length == 50
assert result.value_type == "object"
assert result.download_url == "http://example.com/signed-url"
# Verify it used the pre-loaded relationships (no database queries)
mock_file_helpers.get_signed_file_url.assert_called_once_with("test-upload-file-id", as_attachment=True)
def test_full_content_response_constructor_handles_none_cases(self):
"""Test that full_content serialization handles None cases properly."""
# Test with no file_id
draft_var = WorkflowDraftVariable()
draft_var.file_id = None
result = WorkflowDraftVariableFullContentResponse.from_workflow_draft_variable(draft_var)
assert result is None
def test_full_content_response_constructor_preserves_none_size(self):
draft_var = WorkflowDraftVariable(
file_id="test-file-id",
variable_file=WorkflowDraftVariableFile(
size=None,
length=50,
value_type=SegmentType.OBJECT,
upload_file_id="test-upload-file-id",
tenant_id=str(uuid.uuid4()),
app_id=str(uuid.uuid4()),
user_id=str(uuid.uuid4()),
),
)
with patch("controllers.console.app.workflow_draft_variable.file_helpers", autospec=True) as mock_file_helpers:
mock_file_helpers.get_signed_file_url.return_value = "http://example.com/signed-url"
result = WorkflowDraftVariableFullContentResponse.from_workflow_draft_variable(draft_var)
assert result is not None
assert result.size_bytes is None
def test_full_content_response_constructor_should_raises_when_file_id_exists_but_file_is_none(self):
# Test with no file_id
draft_var = WorkflowDraftVariable()
draft_var.file_id = str(uuid.uuid4())
draft_var.variable_file = None
with pytest.raises(AssertionError):
result = WorkflowDraftVariableFullContentResponse.from_workflow_draft_variable(draft_var)
def test_conversation_variable(self):
conv_var = WorkflowDraftVariable.new_conversation_variable(
app_id=_TEST_APP_ID, name="conv_var", value=build_segment(1)
)
conv_var.id = str(uuid.uuid4())
conv_var.visible = True
expected_without_value: dict[str, Any] = {
"id": conv_var.id,
"type": conv_var.get_variable_type().value,
"name": "conv_var",
"description": "",
"selector": [CONVERSATION_VARIABLE_NODE_ID, "conv_var"],
"value_type": "number",
"edited": False,
"visible": True,
"is_truncated": False,
}
assert (
WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(conv_var).model_dump(mode="json")
== expected_without_value
)
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = 1
expected_with_value["full_content"] = None
assert (
WorkflowDraftVariableResponse.from_workflow_draft_variable(conv_var).model_dump(mode="json")
== expected_with_value
)
def test_create_sys_variable(self):
sys_var = WorkflowDraftVariable.new_sys_variable(
app_id=_TEST_APP_ID,
name="sys_var",
value=build_segment("a"),
editable=True,
node_execution_id=_TEST_NODE_EXEC_ID,
)
sys_var.id = str(uuid.uuid4())
sys_var.last_edited_at = naive_utc_now()
sys_var.visible = True
expected_without_value: dict[str, Any] = {
"id": sys_var.id,
"type": sys_var.get_variable_type().value,
"name": "sys_var",
"description": "",
"selector": [SYSTEM_VARIABLE_NODE_ID, "sys_var"],
"value_type": "string",
"edited": True,
"visible": True,
"is_truncated": False,
}
assert (
WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(sys_var).model_dump(mode="json")
== expected_without_value
)
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = "a"
expected_with_value["full_content"] = None
assert (
WorkflowDraftVariableResponse.from_workflow_draft_variable(sys_var).model_dump(mode="json")
== expected_with_value
)
def test_node_variable(self):
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="node_var",
value=build_segment([1, "a"]),
visible=False,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var.last_edited_at = naive_utc_now()
expected_without_value: dict[str, Any] = {
"id": node_var.id,
"type": node_var.get_variable_type().value,
"name": "node_var",
"description": "",
"selector": ["test_node", "node_var"],
"value_type": "array[any]",
"edited": True,
"visible": False,
"is_truncated": False,
}
assert (
WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(node_var).model_dump(mode="json")
== expected_without_value
)
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = [1, "a"]
expected_with_value["full_content"] = None
assert (
WorkflowDraftVariableResponse.from_workflow_draft_variable(node_var).model_dump(mode="json")
== expected_with_value
)
def test_node_variable_with_file(self):
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="node_var",
value=build_segment([1, "a"]),
visible=False,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var.last_edited_at = naive_utc_now()
variable_file = WorkflowDraftVariableFile(
upload_file_id=str(uuid.uuid4()),
size=1024,
length=10,
value_type=SegmentType.ARRAY_STRING,
tenant_id=str(uuidv7()),
app_id=str(uuidv7()),
user_id=str(uuidv7()),
)
variable_file.id = str(uuidv7())
node_var.variable_file = variable_file
node_var.file_id = variable_file.id
expected_without_value: dict[str, Any] = {
"id": node_var.id,
"type": node_var.get_variable_type().value,
"name": "node_var",
"description": "",
"selector": ["test_node", "node_var"],
"value_type": "array[any]",
"edited": True,
"visible": False,
"is_truncated": True,
}
with patch("controllers.console.app.workflow_draft_variable.file_helpers", autospec=True) as mock_file_helpers:
mock_file_helpers.get_signed_file_url.return_value = "http://example.com/signed-url"
assert (
WorkflowDraftVariableWithoutValueResponse.from_workflow_draft_variable(node_var).model_dump(mode="json")
== expected_without_value
)
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = [1, "a"]
expected_with_value["full_content"] = {
"size_bytes": 1024,
"value_type": "array[string]",
"length": 10,
"download_url": "http://example.com/signed-url",
}
assert (
WorkflowDraftVariableResponse.from_workflow_draft_variable(node_var).model_dump(mode="json")
== expected_with_value
)
class TestWorkflowDraftVariableList:
def test_workflow_draft_variable_list(self):
class TestCase(NamedTuple):
name: str
var_list: WorkflowDraftVariableList
expected: dict
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="test_var",
value=build_segment("a"),
visible=True,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var_dict = {
"id": node_var.id,
"type": node_var.get_variable_type().value,
"name": "test_var",
"description": "",
"selector": ["test_node", "test_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
}
cases = [
TestCase(
name="empty variable list",
var_list=WorkflowDraftVariableList(variables=[]),
expected={
"items": [],
"total": None,
},
),
TestCase(
name="empty variable list with total",
var_list=WorkflowDraftVariableList(variables=[], total=10),
expected={
"items": [],
"total": 10,
},
),
TestCase(
name="non-empty variable list",
var_list=WorkflowDraftVariableList(variables=[node_var], total=None),
expected={
"items": [node_var_dict],
"total": None,
},
),
TestCase(
name="non-empty variable list with total",
var_list=WorkflowDraftVariableList(variables=[node_var], total=10),
expected={
"items": [node_var_dict],
"total": 10,
},
),
]
for idx, case in enumerate(cases, 1):
assert (
WorkflowDraftVariableListWithoutValueResponse.from_workflow_draft_variable_list(
case.var_list
).model_dump(mode="json")
== case.expected
), f"Test case {idx} failed, {case.name=}"
def test_workflow_node_variables_fields():
conv_var = WorkflowDraftVariable.new_conversation_variable(
app_id=_TEST_APP_ID, name="conv_var", value=build_segment(1)
)
conv_var.visible = True
resp = WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
WorkflowDraftVariableList(variables=[conv_var])
).model_dump(mode="json")
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "conv_var"
assert item_dict["value"] == 1
def test_workflow_file_variable_with_signed_url():
"""Test that File type variables include signed URLs in API responses."""
from graphon.file import File, FileTransferMethod, FileType
# Create a File object with LOCAL_FILE transfer method (which generates signed URLs)
test_file = File(
file_id="test_file_id",
file_type=FileType.IMAGE,
transfer_method=FileTransferMethod.LOCAL_FILE,
related_id="test_upload_file_id",
filename="test.jpg",
extension=".jpg",
mime_type="image/jpeg",
size=12345,
)
# Create a WorkflowDraftVariable with the File
file_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="file_var",
value=build_segment(test_file),
node_execution_id=_TEST_NODE_EXEC_ID,
)
resp = WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
WorkflowDraftVariableList(variables=[file_var])
).model_dump(mode="json")
# Verify the response structure
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "file_var"
# Verify the value is a dict (File.to_dict() result) and contains expected fields
value = item_dict["value"]
assert isinstance(value, dict)
# Verify the File fields are preserved
assert value["id"] == test_file.id
assert value["filename"] == test_file.filename
assert value["type"] == test_file.type.value
assert value["transfer_method"] == test_file.transfer_method.value
assert value["size"] == test_file.size
# Verify the URL is present (it should be a signed URL for LOCAL_FILE transfer method)
remote_url = value["remote_url"]
assert remote_url is not None
assert isinstance(remote_url, str)
# For LOCAL_FILE, the URL should contain signature parameters
assert "timestamp=" in remote_url
assert "nonce=" in remote_url
assert "sign=" in remote_url
def test_workflow_file_variable_remote_url():
"""Test that File type variables with REMOTE_URL transfer method return the remote URL."""
from graphon.file import File, FileTransferMethod, FileType
# Create a File object with REMOTE_URL transfer method
test_file = File(
file_id="test_file_id",
file_type=FileType.IMAGE,
transfer_method=FileTransferMethod.REMOTE_URL,
remote_url="https://example.com/test.jpg",
filename="test.jpg",
extension=".jpg",
mime_type="image/jpeg",
size=12345,
)
# Create a WorkflowDraftVariable with the File
file_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="file_var",
value=build_segment(test_file),
node_execution_id=_TEST_NODE_EXEC_ID,
)
resp = WorkflowDraftVariableListResponse.from_workflow_draft_variable_list(
WorkflowDraftVariableList(variables=[file_var])
).model_dump(mode="json")
# Verify the response structure
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "file_var"
# Verify the value is a dict (File.to_dict() result) and contains expected fields
value = item_dict["value"]
assert isinstance(value, dict)
remote_url = value["remote_url"]
# For REMOTE_URL, the URL should be the original remote URL
assert remote_url == test_file.remote_url

View File

@ -77,9 +77,11 @@ def test_human_input_preview_delegates_to_service(
preview_payload = {
"form_id": "node-42",
"node_id": "node-42",
"node_title": "Human Input",
"form_content": "<div>example</div>",
"inputs": [{"name": "topic"}],
"actions": [{"id": "continue"}],
"actions": [{"id": "continue", "title": "Continue"}],
}
service_instance = MagicMock()
service_instance.get_human_input_form_preview.return_value = preview_payload
@ -88,7 +90,15 @@ def test_human_input_preview_delegates_to_service(
with app.test_request_context(case.path, method="POST", json={"inputs": {"topic": "tech"}}):
response = case.resource_cls().post(app_id=app_model.id, node_id="node-42")
assert response == preview_payload
assert response == {
**preview_payload,
"TYPE": "human_input_required",
"actions": [{"id": "continue", "title": "Continue", "button_style": "default"}],
"resolved_default_values": {},
"display_in_ui": False,
"form_token": None,
"expiration_time": None,
}
service_instance.get_human_input_form_preview.assert_called_once_with(
app_model=app_model,
account=account,

View File

@ -3,27 +3,14 @@ from __future__ import annotations
from datetime import UTC, datetime
from inspect import unwrap
from types import SimpleNamespace
from typing import Any
import pytest
from flask import Flask
from flask_restx import marshal
from controllers.console.app import workflow_run as workflow_run_module
from models import Account
def _serialize_200_response(handler, payload: Any) -> Any:
response_doc = getattr(handler, "__apidoc__", {}).get("responses", {}).get("200")
if response_doc is None:
return payload
response_model = response_doc[1]
if isinstance(response_model, dict):
return marshal(payload, response_model)
return payload
def _account() -> SimpleNamespace:
return SimpleNamespace(id="account-1", name="Alice", email="alice@example.com")
@ -100,11 +87,9 @@ def test_workflow_run_list_returns_frontend_history_contract(app: Flask, monkeyp
with app.test_request_context("/apps/app-1/workflow-runs?limit=10", method="GET"):
payload = handler(api, app_model=SimpleNamespace(id="app-1", tenant_id="tenant-1"))
response = _serialize_200_response(api.get, payload)
assert response["limit"] == 10
assert response["has_more"] is False
assert response["data"][0] == {
assert payload["limit"] == 10
assert payload["has_more"] is False
assert payload["data"][0] == {
"id": "run-1",
"version": "v1",
"status": "succeeded",
@ -141,10 +126,8 @@ def test_advanced_chat_workflow_run_list_keeps_message_fields(app: Flask, monkey
with app.test_request_context("/apps/app-1/advanced-chat/workflow-runs?limit=1", method="GET"):
payload = handler(api, app_model=SimpleNamespace(id="app-1", tenant_id="tenant-1"))
response = _serialize_200_response(api.get, payload)
assert response["data"][0]["conversation_id"] == "conversation-1"
assert response["data"][0]["message_id"] == "message-1"
assert payload["data"][0]["conversation_id"] == "conversation-1"
assert payload["data"][0]["message_id"] == "message-1"
def test_workflow_run_detail_returns_frontend_detail_contract(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
@ -180,9 +163,7 @@ def test_workflow_run_detail_returns_frontend_detail_contract(app: Flask, monkey
with app.test_request_context("/apps/app-1/workflow-runs/run-1", method="GET"):
payload = handler(api, app_model=SimpleNamespace(id="app-1", tenant_id="tenant-1"), run_id="run-1")
response = _serialize_200_response(api.get, payload)
assert response == {
assert payload == {
"id": "run-1",
"version": "v1",
"graph": {"nodes": []},
@ -219,9 +200,7 @@ def test_workflow_run_node_executions_return_frontend_trace_contract(
api, _current_account(), app_model=SimpleNamespace(id="app-1", tenant_id="tenant-1"), run_id="run-1"
)
response = _serialize_200_response(api.get, payload)
assert response == {
assert payload == {
"data": [
{
"id": "node-exec-1",

View File

@ -1,413 +0,0 @@
import uuid
from collections import OrderedDict
from typing import Any, NamedTuple
from unittest.mock import patch
import pytest
from flask_restx import marshal
from controllers.console.app.workflow_draft_variable import (
_WORKFLOW_DRAFT_VARIABLE_FIELDS,
_WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS,
_WORKFLOW_DRAFT_VARIABLE_LIST_WITHOUT_VALUE_FIELDS,
_WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS,
_serialize_full_content,
)
from core.workflow.variable_prefixes import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID
from factories.variable_factory import build_segment
from graphon.variables.types import SegmentType
from libs.datetime_utils import naive_utc_now
from libs.uuid_utils import uuidv7
from models.workflow import WorkflowDraftVariable, WorkflowDraftVariableFile
from services.workflow_draft_variable_service import WorkflowDraftVariableList
_TEST_APP_ID = "test_app_id"
_TEST_NODE_EXEC_ID = str(uuid.uuid4())
class TestWorkflowDraftVariableFields:
def test_serialize_full_content(self):
"""Test that _serialize_full_content uses pre-loaded relationships."""
# Create mock objects with relationships pre-loaded
mock_variable = WorkflowDraftVariable(
file_id="test-file-id",
variable_file=WorkflowDraftVariableFile(
size=100000,
length=50,
value_type=SegmentType.OBJECT,
upload_file_id="test-upload-file-id",
tenant_id=str(uuid.uuid4()),
app_id=str(uuid.uuid4()),
user_id=str(uuid.uuid4()),
),
)
# Mock the file helpers
with patch("controllers.console.app.workflow_draft_variable.file_helpers", autospec=True) as mock_file_helpers:
mock_file_helpers.get_signed_file_url.return_value = "http://example.com/signed-url"
# Call the function
result = _serialize_full_content(mock_variable)
# Verify it returns the expected structure
assert result is not None
assert result["size_bytes"] == 100000
assert result["length"] == 50
assert result["value_type"] == "object"
assert "download_url" in result
assert result["download_url"] == "http://example.com/signed-url"
# Verify it used the pre-loaded relationships (no database queries)
mock_file_helpers.get_signed_file_url.assert_called_once_with("test-upload-file-id", as_attachment=True)
def test_serialize_full_content_handles_none_cases(self):
"""Test that _serialize_full_content handles None cases properly."""
# Test with no file_id
draft_var = WorkflowDraftVariable()
draft_var.file_id = None
result = _serialize_full_content(draft_var)
assert result is None
def test_serialize_full_content_should_raises_when_file_id_exists_but_file_is_none(self):
# Test with no file_id
draft_var = WorkflowDraftVariable()
draft_var.file_id = str(uuid.uuid4())
draft_var.variable_file = None
with pytest.raises(AssertionError):
result = _serialize_full_content(draft_var)
def test_conversation_variable(self):
conv_var = WorkflowDraftVariable.new_conversation_variable(
app_id=_TEST_APP_ID, name="conv_var", value=build_segment(1)
)
conv_var.id = str(uuid.uuid4())
conv_var.visible = True
expected_without_value: OrderedDict[str, Any] = OrderedDict(
{
"id": conv_var.id,
"type": conv_var.get_variable_type().value,
"name": "conv_var",
"description": "",
"selector": [CONVERSATION_VARIABLE_NODE_ID, "conv_var"],
"value_type": "number",
"edited": False,
"visible": True,
"is_truncated": False,
}
)
assert marshal(conv_var, _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS) == expected_without_value
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = 1
expected_with_value["full_content"] = None
assert marshal(conv_var, _WORKFLOW_DRAFT_VARIABLE_FIELDS) == expected_with_value
def test_create_sys_variable(self):
sys_var = WorkflowDraftVariable.new_sys_variable(
app_id=_TEST_APP_ID,
name="sys_var",
value=build_segment("a"),
editable=True,
node_execution_id=_TEST_NODE_EXEC_ID,
)
sys_var.id = str(uuid.uuid4())
sys_var.last_edited_at = naive_utc_now()
sys_var.visible = True
expected_without_value = OrderedDict(
{
"id": sys_var.id,
"type": sys_var.get_variable_type().value,
"name": "sys_var",
"description": "",
"selector": [SYSTEM_VARIABLE_NODE_ID, "sys_var"],
"value_type": "string",
"edited": True,
"visible": True,
"is_truncated": False,
}
)
assert marshal(sys_var, _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS) == expected_without_value
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = "a"
expected_with_value["full_content"] = None
assert marshal(sys_var, _WORKFLOW_DRAFT_VARIABLE_FIELDS) == expected_with_value
def test_node_variable(self):
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="node_var",
value=build_segment([1, "a"]),
visible=False,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var.last_edited_at = naive_utc_now()
expected_without_value: OrderedDict[str, Any] = OrderedDict(
{
"id": node_var.id,
"type": node_var.get_variable_type().value,
"name": "node_var",
"description": "",
"selector": ["test_node", "node_var"],
"value_type": "array[any]",
"edited": True,
"visible": False,
"is_truncated": False,
}
)
assert marshal(node_var, _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS) == expected_without_value
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = [1, "a"]
expected_with_value["full_content"] = None
assert marshal(node_var, _WORKFLOW_DRAFT_VARIABLE_FIELDS) == expected_with_value
def test_node_variable_with_file(self):
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="node_var",
value=build_segment([1, "a"]),
visible=False,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var.last_edited_at = naive_utc_now()
variable_file = WorkflowDraftVariableFile(
upload_file_id=str(uuid.uuid4()),
size=1024,
length=10,
value_type=SegmentType.ARRAY_STRING,
tenant_id=str(uuidv7()),
app_id=str(uuidv7()),
user_id=str(uuidv7()),
)
variable_file.id = str(uuidv7())
node_var.variable_file = variable_file
node_var.file_id = variable_file.id
expected_without_value: OrderedDict[str, Any] = OrderedDict(
{
"id": node_var.id,
"type": node_var.get_variable_type(),
"name": "node_var",
"description": "",
"selector": ["test_node", "node_var"],
"value_type": "array[any]",
"edited": True,
"visible": False,
"is_truncated": True,
}
)
with patch("controllers.console.app.workflow_draft_variable.file_helpers", autospec=True) as mock_file_helpers:
mock_file_helpers.get_signed_file_url.return_value = "http://example.com/signed-url"
assert marshal(node_var, _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS) == expected_without_value
expected_with_value = expected_without_value.copy()
expected_with_value["value"] = [1, "a"]
expected_with_value["full_content"] = {
"size_bytes": 1024,
"value_type": "array[string]",
"length": 10,
"download_url": "http://example.com/signed-url",
}
assert marshal(node_var, _WORKFLOW_DRAFT_VARIABLE_FIELDS) == expected_with_value
class TestWorkflowDraftVariableList:
def test_workflow_draft_variable_list(self):
class TestCase(NamedTuple):
name: str
var_list: WorkflowDraftVariableList
expected: dict
node_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="test_var",
value=build_segment("a"),
visible=True,
node_execution_id=_TEST_NODE_EXEC_ID,
)
node_var.id = str(uuid.uuid4())
node_var_dict = OrderedDict(
{
"id": node_var.id,
"type": node_var.get_variable_type().value,
"name": "test_var",
"description": "",
"selector": ["test_node", "test_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
}
)
cases = [
TestCase(
name="empty variable list",
var_list=WorkflowDraftVariableList(variables=[]),
expected=OrderedDict(
{
"items": [],
"total": None,
}
),
),
TestCase(
name="empty variable list with total",
var_list=WorkflowDraftVariableList(variables=[], total=10),
expected=OrderedDict(
{
"items": [],
"total": 10,
}
),
),
TestCase(
name="non-empty variable list",
var_list=WorkflowDraftVariableList(variables=[node_var], total=None),
expected=OrderedDict(
{
"items": [node_var_dict],
"total": None,
}
),
),
TestCase(
name="non-empty variable list with total",
var_list=WorkflowDraftVariableList(variables=[node_var], total=10),
expected=OrderedDict(
{
"items": [node_var_dict],
"total": 10,
}
),
),
]
for idx, case in enumerate(cases, 1):
assert marshal(case.var_list, _WORKFLOW_DRAFT_VARIABLE_LIST_WITHOUT_VALUE_FIELDS) == case.expected, (
f"Test case {idx} failed, {case.name=}"
)
def test_workflow_node_variables_fields():
conv_var = WorkflowDraftVariable.new_conversation_variable(
app_id=_TEST_APP_ID, name="conv_var", value=build_segment(1)
)
resp = marshal(WorkflowDraftVariableList(variables=[conv_var]), _WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS)
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "conv_var"
assert item_dict["value"] == 1
def test_workflow_file_variable_with_signed_url():
"""Test that File type variables include signed URLs in API responses."""
from graphon.file import File, FileTransferMethod, FileType
# Create a File object with LOCAL_FILE transfer method (which generates signed URLs)
test_file = File(
file_id="test_file_id",
file_type=FileType.IMAGE,
transfer_method=FileTransferMethod.LOCAL_FILE,
related_id="test_upload_file_id",
filename="test.jpg",
extension=".jpg",
mime_type="image/jpeg",
size=12345,
)
# Create a WorkflowDraftVariable with the File
file_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="file_var",
value=build_segment(test_file),
node_execution_id=_TEST_NODE_EXEC_ID,
)
# Marshal the variable using the API fields
resp = marshal(WorkflowDraftVariableList(variables=[file_var]), _WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS)
# Verify the response structure
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "file_var"
# Verify the value is a dict (File.to_dict() result) and contains expected fields
value = item_dict["value"]
assert isinstance(value, dict)
# Verify the File fields are preserved
assert value["id"] == test_file.id
assert value["filename"] == test_file.filename
assert value["type"] == test_file.type.value
assert value["transfer_method"] == test_file.transfer_method.value
assert value["size"] == test_file.size
# Verify the URL is present (it should be a signed URL for LOCAL_FILE transfer method)
remote_url = value["remote_url"]
assert remote_url is not None
assert isinstance(remote_url, str)
# For LOCAL_FILE, the URL should contain signature parameters
assert "timestamp=" in remote_url
assert "nonce=" in remote_url
assert "sign=" in remote_url
def test_workflow_file_variable_remote_url():
"""Test that File type variables with REMOTE_URL transfer method return the remote URL."""
from graphon.file import File, FileTransferMethod, FileType
# Create a File object with REMOTE_URL transfer method
test_file = File(
file_id="test_file_id",
file_type=FileType.IMAGE,
transfer_method=FileTransferMethod.REMOTE_URL,
remote_url="https://example.com/test.jpg",
filename="test.jpg",
extension=".jpg",
mime_type="image/jpeg",
size=12345,
)
# Create a WorkflowDraftVariable with the File
file_var = WorkflowDraftVariable.new_node_variable(
app_id=_TEST_APP_ID,
node_id="test_node",
name="file_var",
value=build_segment(test_file),
node_execution_id=_TEST_NODE_EXEC_ID,
)
# Marshal the variable using the API fields
resp = marshal(WorkflowDraftVariableList(variables=[file_var]), _WORKFLOW_DRAFT_VARIABLE_LIST_FIELDS)
# Verify the response structure
assert isinstance(resp, dict)
assert len(resp["items"]) == 1
item_dict = resp["items"][0]
assert item_dict["name"] == "file_var"
# Verify the value is a dict (File.to_dict() result) and contains expected fields
value = item_dict["value"]
assert isinstance(value, dict)
remote_url = value["remote_url"]
# For REMOTE_URL, the URL should be the original remote URL
assert remote_url == test_file.remote_url

View File

@ -1,8 +1,11 @@
import uuid
from inspect import unwrap
from types import SimpleNamespace
from typing import Any
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask, Response
from flask import Flask
from controllers.common.errors import InvalidArgumentError, NotFoundError
from controllers.console import console_ns
@ -16,8 +19,26 @@ from controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable impor
RagPipelineVariableResetApi,
)
from core.workflow.variable_prefixes import SYSTEM_VARIABLE_NODE_ID
from factories.variable_factory import build_segment
from graphon.variables.types import SegmentType
from models.account import Account, TenantAccountRole
from models.workflow import WorkflowDraftVariable
from services.workflow_draft_variable_service import WorkflowDraftVariableList
_TEST_NODE_EXEC_ID = str(uuid.uuid4())
def _node_variable(*, app_id: str = "p1", value: Any = "hello") -> WorkflowDraftVariable:
variable = WorkflowDraftVariable.new_node_variable(
app_id=app_id,
user_id="account-1",
node_id="node1",
name="node_var",
value=build_segment(value),
node_execution_id=_TEST_NODE_EXEC_ID,
)
variable.id = str(uuid.uuid4())
return variable
@pytest.fixture
@ -47,13 +68,12 @@ class TestRagPipelineVariableCollectionApi:
method = unwrap(api.get)
pipeline = MagicMock(id="p1")
variable = _node_variable(value="hello")
rag_srv = MagicMock()
rag_srv.is_workflow_exist.return_value = True
# IMPORTANT: RESTX expects .variables
var_list = MagicMock()
var_list.variables = []
var_list = WorkflowDraftVariableList(variables=[variable], total=1)
draft_srv = MagicMock()
draft_srv.list_variables_without_values.return_value = var_list
@ -73,7 +93,22 @@ class TestRagPipelineVariableCollectionApi:
):
result = method(api, editor_user, pipeline)
assert result is var_list
assert result == {
"items": [
{
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node1", "node_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
}
],
"total": 1,
}
draft_srv.list_variables_without_values.assert_called_once_with(
app_id="p1",
page=1,
@ -114,8 +149,7 @@ class TestRagPipelineVariableCollectionApi:
):
result = method(api, editor_user, pipeline)
assert isinstance(result, Response)
assert result.status_code == 204
assert result == ("", 204)
class TestRagPipelineNodeVariableCollectionApi:
@ -124,9 +158,8 @@ class TestRagPipelineNodeVariableCollectionApi:
method = unwrap(api.get)
pipeline = MagicMock(id="p1")
var_list = MagicMock()
var_list.variables = []
variable = _node_variable(value=None)
var_list = WorkflowDraftVariableList(variables=[variable])
srv = MagicMock()
srv.list_node_variables.return_value = var_list
@ -142,7 +175,23 @@ class TestRagPipelineNodeVariableCollectionApi:
):
result = method(api, editor_user, pipeline, "node1")
assert result is var_list
assert result == {
"items": [
{
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node1", "node_var"],
"value_type": "none",
"edited": False,
"visible": True,
"is_truncated": False,
"value": None,
"full_content": None,
}
]
}
srv.list_node_variables.assert_called_once_with("p1", "node1", user_id="account-1")
def test_get_node_variables_invalid_node(self, app: Flask, editor_user):
@ -157,6 +206,40 @@ class TestRagPipelineNodeVariableCollectionApi:
class TestRagPipelineVariableApi:
def test_get_variable_success_returns_concrete_shape(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.get)
pipeline = MagicMock(id="p1")
variable = _node_variable(value={"answer": 42})
srv = MagicMock()
srv.get_variable.return_value = variable
with (
app.test_request_context("/"),
patch("controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.db", fake_db),
patch(
"controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.WorkflowDraftVariableService",
return_value=srv,
),
):
result = method(api, editor_user, pipeline, variable.id)
assert result == {
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node1", "node_var"],
"value_type": "object",
"edited": False,
"visible": True,
"is_truncated": False,
"value": {"answer": 42},
"full_content": None,
}
def test_get_variable_not_found(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.get)
@ -199,6 +282,42 @@ class TestRagPipelineVariableApi:
with pytest.raises(InvalidArgumentError):
method(api, editor_user, pipeline, "v1")
def test_patch_variable_noop_returns_current_concrete_shape(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.patch)
pipeline = MagicMock(id="p1", tenant_id="t1")
variable = _node_variable(value=42)
srv = MagicMock()
srv.get_variable.return_value = variable
with (
app.test_request_context("/", json={}),
patch.object(type(console_ns), "payload", {}),
patch("controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.db", fake_db),
patch(
"controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.WorkflowDraftVariableService",
return_value=srv,
),
):
result = method(api, editor_user, pipeline, variable.id)
assert result == {
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node1", "node_var"],
"value_type": "number",
"edited": False,
"visible": True,
"is_truncated": False,
"value": 42,
"full_content": None,
}
srv.update_variable.assert_not_called()
def test_delete_variable_success(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.delete)
@ -219,7 +338,7 @@ class TestRagPipelineVariableApi:
):
result = method(api, editor_user, pipeline, "v1")
assert result.status_code == 204
assert result == ("", 204)
class TestRagPipelineVariableResetApi:
@ -229,7 +348,7 @@ class TestRagPipelineVariableResetApi:
pipeline = MagicMock(id="p1")
workflow = MagicMock()
variable = MagicMock(app_id="p1")
variable = _node_variable(value="reset")
srv = MagicMock()
srv.get_variable.return_value = variable
@ -249,14 +368,22 @@ class TestRagPipelineVariableResetApi:
"controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.WorkflowDraftVariableService",
return_value=srv,
),
patch(
"controllers.console.datasets.rag_pipeline.rag_pipeline_draft_variable.marshal",
return_value={"id": "v1"},
),
):
result = method(api, editor_user, pipeline, "v1")
result = method(api, editor_user, pipeline, variable.id)
assert result == {"id": "v1"}
assert result == {
"id": variable.id,
"type": "node",
"name": "node_var",
"description": "",
"selector": ["node1", "node_var"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
"value": "reset",
"full_content": None,
}
class TestSystemAndEnvironmentVariablesApi:
@ -265,9 +392,16 @@ class TestSystemAndEnvironmentVariablesApi:
method = unwrap(api.get)
pipeline = MagicMock(id="p1")
var_list = MagicMock()
var_list.variables = []
variable = WorkflowDraftVariable.new_sys_variable(
app_id="p1",
user_id="account-1",
name="query",
value=build_segment("system query"),
editable=True,
node_execution_id=_TEST_NODE_EXEC_ID,
)
variable.id = str(uuid.uuid4())
var_list = WorkflowDraftVariableList(variables=[variable])
srv = MagicMock()
srv.list_system_variables.return_value = var_list
@ -283,19 +417,35 @@ class TestSystemAndEnvironmentVariablesApi:
):
result = method(api, editor_user, pipeline)
assert result is var_list
assert result == {
"items": [
{
"id": variable.id,
"type": "sys",
"name": "query",
"description": "",
"selector": ["sys", "query"],
"value_type": "string",
"edited": False,
"visible": True,
"is_truncated": False,
"value": "system query",
"full_content": None,
}
]
}
srv.list_system_variables.assert_called_once_with("p1", user_id="account-1")
def test_environment_variables_success(self, app: Flask, editor_user):
api = RagPipelineEnvironmentVariableCollectionApi()
method = unwrap(api.get)
env_var = MagicMock(
env_var = SimpleNamespace(
id="e1",
name="ENV",
description="d",
selector="s",
value_type=MagicMock(value="string"),
selector=["env", "ENV"],
value_type=SimpleNamespace(value="string"),
value="x",
)
@ -314,4 +464,19 @@ class TestSystemAndEnvironmentVariablesApi:
):
result = method(api, editor_user, pipeline)
assert len(result["items"]) == 1
assert result == {
"items": [
{
"id": "e1",
"type": "env",
"name": "ENV",
"description": "d",
"selector": ["env", "ENV"],
"value_type": "string",
"value": "x",
"edited": False,
"visible": True,
"editable": True,
}
]
}

View File

@ -3,7 +3,6 @@ from __future__ import annotations
import json
from datetime import datetime
from inspect import unwrap
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
@ -13,6 +12,7 @@ from werkzeug.exceptions import HTTPException, NotFound
from controllers.console.snippets import snippet_workflow as snippet_workflow_module
from models.account import Account, TenantAccountRole
from models.snippet import CustomizedSnippet
from models.workflow import Workflow, WorkflowKind, WorkflowType
def _account(account_id: str = "account-1") -> Account:
@ -35,6 +35,38 @@ def _snippet(**overrides) -> CustomizedSnippet:
return CustomizedSnippet(**data)
def _workflow(**overrides) -> Workflow:
workflow = Workflow.new(
tenant_id="tenant-1",
app_id="snippet-1",
type=WorkflowType.WORKFLOW.value,
version="2024-01-01 00:00:00",
graph=json.dumps({"nodes": [], "edges": []}),
features=json.dumps({}),
created_by="account-1",
environment_variables=[],
conversation_variables=[],
rag_pipeline_variables=[],
kind=WorkflowKind.SNIPPET.value,
marked_name="",
marked_comment="",
)
workflow.id = "workflow-1"
for key, value in overrides.items():
setattr(workflow, key, value)
return workflow
class _DbStub:
engine = object()
class _SessionStub:
def __init__(self, merged_snippet: CustomizedSnippet) -> None:
self.merge = Mock(return_value=merged_snippet)
self.commit = Mock()
@pytest.fixture(autouse=True)
def _patch_snippet_service_factory(monkeypatch: pytest.MonkeyPatch) -> None:
def factory():
@ -93,10 +125,15 @@ def test_get_snippet_raises_not_found_when_snippet_missing(app: Flask, monkeypat
def test_draft_workflow_get_raises_when_missing(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
snippet = _snippet()
class SnippetServiceStub:
def get_draft_workflow(self, *, snippet: CustomizedSnippet) -> None:
return None
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(get_draft_workflow=Mock(return_value=None)),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowApi()
@ -111,10 +148,15 @@ def test_draft_workflow_post_returns_400_for_invalid_graph(app: Flask, monkeypat
user = _account("account-1")
snippet = _snippet()
sync_draft_workflow = Mock(side_effect=ValueError("invalid graph"))
class SnippetServiceStub:
def sync_draft_workflow(self, **kwargs):
return sync_draft_workflow(**kwargs)
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(sync_draft_workflow=sync_draft_workflow),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowApi()
@ -131,27 +173,77 @@ def test_draft_workflow_post_returns_400_for_invalid_graph(app: Flask, monkeypat
assert response == {"message": "invalid graph"}
def _response_model_name(entry: object) -> str:
assert isinstance(entry, tuple)
assert len(entry) >= 2
model = entry[1]
name = getattr(model, "name", None)
assert isinstance(name, str)
return name
def test_snippet_workflow_endpoints_keep_response_docs() -> None:
assert snippet_workflow_module.SnippetDefaultBlockConfigsApi.get.__apidoc__["responses"]["200"] == (
"Default block configs retrieved successfully",
None,
{},
)
cases = [
(
snippet_workflow_module.SnippetDraftConfigApi.get,
snippet_workflow_module.SnippetDraftConfigResponse.__name__,
),
(
snippet_workflow_module.SnippetDraftRunIterationNodeApi.post,
snippet_workflow_module.EventStreamResponse.__name__,
),
(
snippet_workflow_module.SnippetDraftRunLoopNodeApi.post,
snippet_workflow_module.EventStreamResponse.__name__,
),
(
snippet_workflow_module.SnippetDraftWorkflowRunApi.post,
snippet_workflow_module.EventStreamResponse.__name__,
),
(
snippet_workflow_module.SnippetWorkflowTaskStopApi.post,
snippet_workflow_module.SimpleResultResponse.__name__,
),
]
for view, model_name in cases:
responses = getattr(view, "__apidoc__", {}).get("responses", {})
assert _response_model_name(responses["200"]) == model_name
def test_draft_config_returns_parallel_depth_limit(app) -> None:
api = snippet_workflow_module.SnippetDraftConfigApi()
handler = unwrap(api.get)
snippet = _snippet()
with app.test_request_context("/snippets/snippet-1/workflows/draft/config"):
assert handler(api, snippet=SimpleNamespace(id="snippet-1")) == {"parallel_depth_limit": 3}
assert handler(api, snippet=snippet) == {"parallel_depth_limit": 3}
def test_published_workflow_get_returns_none_when_not_published(app) -> None:
api = snippet_workflow_module.SnippetPublishedWorkflowApi()
handler = unwrap(api.get)
snippet = _snippet(is_published=False)
with app.test_request_context("/snippets/snippet-1/workflows/publish"):
assert handler(api, snippet=SimpleNamespace(id="snippet-1", is_published=False)) is None
assert handler(api, snippet=snippet) is None
def test_published_workflow_post_returns_400_when_publish_fails(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
user = _account("account-1")
snippet = _snippet()
merged_snippet = _snippet()
session = SimpleNamespace(merge=Mock(return_value=merged_snippet), commit=Mock())
session = _SessionStub(merged_snippet)
class SnippetServiceStub:
def publish_workflow(self, **kwargs):
raise ValueError("No valid workflow found.")
class SessionContext:
def __init__(self, engine):
@ -164,11 +256,11 @@ def test_published_workflow_post_returns_400_when_publish_fails(app: Flask, monk
return False
monkeypatch.setattr(snippet_workflow_module, "Session", SessionContext)
monkeypatch.setattr(snippet_workflow_module, "db", SimpleNamespace(engine=object()))
monkeypatch.setattr(snippet_workflow_module, "db", _DbStub())
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(publish_workflow=Mock(side_effect=ValueError("No valid workflow found."))),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetPublishedWorkflowApi()
@ -182,44 +274,97 @@ def test_published_workflow_post_returns_400_when_publish_fails(app: Flask, monk
session.commit.assert_not_called()
def test_default_block_configs_delegates_to_service(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
get_default_block_configs = Mock(return_value=[{"type": "llm"}])
def test_published_workflow_post_returns_publish_result(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
user = _account("account-1")
snippet = _snippet()
merged_snippet = _snippet()
workflow = _workflow(marked_name="Release 1", marked_comment="Initial release")
session = _SessionStub(merged_snippet)
publish_workflow = Mock(return_value=workflow)
class SnippetServiceStub:
def publish_workflow(self, **kwargs):
return publish_workflow(**kwargs)
class SessionContext:
def __init__(self, engine):
self.engine = engine
def __enter__(self):
return session
def __exit__(self, exc_type, exc, tb):
return False
monkeypatch.setattr(snippet_workflow_module, "Session", SessionContext)
monkeypatch.setattr(snippet_workflow_module, "db", _DbStub())
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(get_default_block_configs=get_default_block_configs),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetPublishedWorkflowApi()
handler = unwrap(api.post)
with app.test_request_context(
"/snippets/snippet-1/workflows/publish",
method="POST",
json={"marked_name": "Release 1", "marked_comment": "Initial release"},
):
response = handler(api, user, snippet)
assert response == {"result": "success", "created_at": int(workflow.created_at.timestamp())}
publish_workflow.assert_called_once_with(
session=session,
snippet=merged_snippet,
account=user,
)
session.commit.assert_called_once()
def test_default_block_configs_delegates_to_service(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
get_default_block_configs = Mock(return_value=[{"type": "llm"}])
class SnippetServiceStub:
def get_default_block_configs(self):
return get_default_block_configs()
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDefaultBlockConfigsApi()
handler = unwrap(api.get)
snippet = _snippet()
with app.test_request_context("/snippets/snippet-1/workflows/default-workflow-block-configs"):
result = handler(api, snippet=SimpleNamespace(id="snippet-1"))
result = handler(api, snippet=snippet)
assert result == [{"type": "llm"}]
get_default_block_configs.assert_called_once()
def test_list_published_snippet_workflows_includes_input_fields(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
workflow = SimpleNamespace(
id="workflow-1",
graph_dict={"nodes": [], "edges": []},
features_dict={},
unique_hash="hash-1",
workflow = _workflow(
graph=json.dumps({"nodes": [], "edges": []}),
features=json.dumps({}),
version="2024-01-01 00:00:00",
marked_name="",
marked_comment="",
created_by_account=None,
created_at=datetime(2024, 1, 1),
updated_by_account=None,
updated_at=datetime(2024, 1, 1),
tool_published=False,
environment_variables=[],
conversation_variables=[],
rag_pipeline_variables=[],
)
input_fields = [{"variable": "query", "type": "text"}]
snippet = _snippet(input_fields=json.dumps(input_fields))
monkeypatch.setattr(Workflow, "created_by_account", property(lambda _workflow: None))
monkeypatch.setattr(Workflow, "updated_by_account", property(lambda _workflow: None))
monkeypatch.setattr(Workflow, "tool_published", property(lambda _workflow: False))
class SessionContext:
def __init__(self, engine):
@ -232,11 +377,16 @@ def test_list_published_snippet_workflows_includes_input_fields(app: Flask, monk
return False
monkeypatch.setattr(snippet_workflow_module, "Session", SessionContext)
monkeypatch.setattr(snippet_workflow_module, "db", SimpleNamespace(engine=object()))
monkeypatch.setattr(snippet_workflow_module, "db", _DbStub())
class SnippetServiceStub:
def get_all_published_workflows(self, **kwargs):
return [workflow], False
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(get_all_published_workflows=Mock(return_value=([workflow], False))),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetPublishedAllWorkflowApi()
@ -249,18 +399,21 @@ def test_list_published_snippet_workflows_includes_input_fields(app: Flask, monk
def test_restore_published_snippet_workflow_to_draft_success(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
workflow = SimpleNamespace(
unique_hash="restored-hash",
workflow = _workflow(
updated_at=None,
created_at=datetime(2024, 1, 1),
)
user = _account("account-1")
snippet = _snippet()
class SnippetServiceStub:
def restore_published_workflow_to_draft(self, **kwargs):
return workflow
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(restore_published_workflow_to_draft=lambda **_kwargs: workflow),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowRestoreApi()
@ -273,21 +426,21 @@ def test_restore_published_snippet_workflow_to_draft_success(app: Flask, monkeyp
response = handler(api, user, snippet, workflow_id="published-workflow")
assert response["result"] == "success"
assert response["hash"] == "restored-hash"
assert response["hash"] == workflow.unique_hash
def test_restore_published_snippet_workflow_to_draft_not_found(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
user = _account("account-1")
snippet = _snippet()
class SnippetServiceStub:
def restore_published_workflow_to_draft(self, **kwargs):
raise snippet_workflow_module.WorkflowNotFoundError("Workflow not found")
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(
restore_published_workflow_to_draft=lambda **_kwargs: (_ for _ in ()).throw(
snippet_workflow_module.WorkflowNotFoundError("Workflow not found")
)
),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowRestoreApi()
@ -307,14 +460,14 @@ def test_restore_published_snippet_workflow_to_draft_returns_400_for_draft_sourc
user = _account("account-1")
snippet = _snippet()
class SnippetServiceStub:
def restore_published_workflow_to_draft(self, **kwargs):
raise snippet_workflow_module.IsDraftWorkflowError("source workflow must be published")
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(
restore_published_workflow_to_draft=lambda **_kwargs: (_ for _ in ()).throw(
snippet_workflow_module.IsDraftWorkflowError("source workflow must be published")
)
),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowRestoreApi()
@ -337,14 +490,14 @@ def test_restore_published_snippet_workflow_to_draft_returns_400_for_invalid_gra
user = _account("account-1")
snippet = _snippet()
class SnippetServiceStub:
def restore_published_workflow_to_draft(self, **kwargs):
raise ValueError("invalid snippet workflow graph")
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(
restore_published_workflow_to_draft=lambda **_kwargs: (_ for _ in ()).throw(
ValueError("invalid snippet workflow graph")
)
),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftWorkflowRestoreApi()
@ -363,10 +516,15 @@ def test_restore_published_snippet_workflow_to_draft_returns_400_for_invalid_gra
def test_workflow_run_detail_raises_not_found_when_run_missing(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
snippet = _snippet()
class SnippetServiceStub:
def get_snippet_workflow_run(self, **kwargs) -> None:
return None
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(get_snippet_workflow_run=Mock(return_value=None)),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetWorkflowRunDetailApi()
@ -381,14 +539,19 @@ def test_draft_node_last_run_raises_not_found_when_execution_missing(
app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
snippet = _snippet()
draft_workflow = SimpleNamespace(id="workflow-1")
draft_workflow = _workflow(id="workflow-1", version=Workflow.VERSION_DRAFT)
class SnippetServiceStub:
def get_draft_workflow(self, *, snippet: CustomizedSnippet) -> Workflow:
return draft_workflow
def get_snippet_node_last_run(self, **kwargs) -> None:
return None
monkeypatch.setattr(
snippet_workflow_module,
"SnippetService",
lambda: SimpleNamespace(
get_draft_workflow=Mock(return_value=draft_workflow),
get_snippet_node_last_run=Mock(return_value=None),
),
SnippetServiceStub,
)
api = snippet_workflow_module.SnippetDraftNodeLastRunApi()
@ -402,6 +565,12 @@ def test_draft_node_last_run_raises_not_found_when_execution_missing(
def test_workflow_task_stop_uses_queue_flag_and_graph_command(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
set_stop_flag = Mock()
send_stop_command = Mock()
class GraphEngineManagerStub:
def __init__(self, redis_client):
self.redis_client = redis_client
self.send_stop_command = send_stop_command
monkeypatch.setattr(
snippet_workflow_module.AppQueueManager,
"set_stop_flag_no_user_check",
@ -410,14 +579,15 @@ def test_workflow_task_stop_uses_queue_flag_and_graph_command(app: Flask, monkey
monkeypatch.setattr(
snippet_workflow_module,
"GraphEngineManager",
Mock(return_value=SimpleNamespace(send_stop_command=send_stop_command)),
GraphEngineManagerStub,
)
api = snippet_workflow_module.SnippetWorkflowTaskStopApi()
handler = unwrap(api.post)
snippet = _snippet()
with app.test_request_context("/snippets/snippet-1/workflow-runs/tasks/task-1/stop", method="POST"):
result = handler(api, snippet=SimpleNamespace(id="snippet-1"), task_id="task-1")
result = handler(api, snippet=snippet, task_id="task-1")
assert result == {"result": "success"}
set_stop_flag.assert_called_once_with("task-1")

View File

@ -1,15 +1,28 @@
import json
import uuid
from contextlib import nullcontext
from inspect import unwrap
from types import SimpleNamespace
from typing import Any, cast
from unittest.mock import Mock
import pytest
from flask import Flask
from controllers.console.snippets import snippet_workflow_draft_variable as module
from core.workflow.variable_prefixes import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID
from factories.variable_factory import build_environment_variable_from_mapping, build_segment
from graphon.variables.types import SegmentType
from models import workflow as workflow_model_module
from models.account import Account, AccountStatus
from models.snippet import CustomizedSnippet
from models.workflow import Workflow, WorkflowDraftVariable, WorkflowType
from services.workflow_draft_variable_service import WorkflowDraftVariableList
_TEST_SNIPPET_ID = str(uuid.uuid4())
_TEST_TENANT_ID = str(uuid.uuid4())
_TEST_USER_ID = str(uuid.uuid4())
_TEST_NODE_EXECUTION_ID = str(uuid.uuid4())
def _make_account() -> Account:
account = Account(
@ -17,16 +30,97 @@ def _make_account() -> Account:
email="tester@example.com",
status=AccountStatus.ACTIVE,
)
account.id = "user-1" # type: ignore[assignment]
account.id = _TEST_USER_ID
return account
def _make_snippet() -> CustomizedSnippet:
snippet = CustomizedSnippet()
snippet.id = _TEST_SNIPPET_ID
snippet.tenant_id = _TEST_TENANT_ID
snippet.name = "Reusable snippet"
snippet.description = "Snippet under test"
snippet.type = "node"
return snippet
def _make_draft_workflow(*, environment_variables: list[Any] | None = None) -> Workflow:
workflow = Workflow()
workflow.id = str(uuid.uuid4())
workflow.tenant_id = _TEST_TENANT_ID
workflow.app_id = _TEST_SNIPPET_ID
workflow.type = WorkflowType.SNIPPET
workflow.version = Workflow.VERSION_DRAFT
workflow.graph = "{}"
workflow.features = "{}"
workflow.created_by = _TEST_USER_ID
workflow._environment_variables = json.dumps(
{variable.id: variable.model_dump(mode="json") for variable in environment_variables or []}
)
return workflow
def _make_node_variable(
*, value: Any = "value", node_id: str = "llm-1", name: str = "node_var"
) -> WorkflowDraftVariable:
return WorkflowDraftVariable.new_node_variable(
app_id=_TEST_SNIPPET_ID,
user_id=_TEST_USER_ID,
node_id=node_id,
name=name,
value=build_segment(value),
node_execution_id=_TEST_NODE_EXECUTION_ID,
)
def _make_system_variable() -> WorkflowDraftVariable:
return WorkflowDraftVariable.new_sys_variable(
app_id=_TEST_SNIPPET_ID,
user_id=_TEST_USER_ID,
name="query",
value=build_segment("hello"),
node_execution_id=_TEST_NODE_EXECUTION_ID,
)
def _make_conversation_variable() -> WorkflowDraftVariable:
return WorkflowDraftVariable.new_conversation_variable(
app_id=_TEST_SNIPPET_ID,
user_id=_TEST_USER_ID,
name="topic",
value=build_segment("support"),
)
def _expected_variable_payload(variable: WorkflowDraftVariable, *, value: Any) -> dict[str, Any]:
expected_without_value = _expected_variable_without_value_payload(variable)
return {
**expected_without_value,
"value": value,
"full_content": None,
}
def _expected_variable_without_value_payload(variable: WorkflowDraftVariable) -> dict[str, Any]:
return {
"id": variable.id,
"type": "node",
"name": variable.name,
"description": "",
"selector": [variable.node_id, variable.name],
"value_type": str(variable.value_type.exposed_type()),
"edited": False,
"visible": True,
"is_truncated": False,
}
@pytest.fixture(autouse=True)
def _patch_snippet_service_factory(monkeypatch: pytest.MonkeyPatch):
def factory():
service_factory = module.SnippetService
if isinstance(service_factory, type):
return service_factory.__new__(service_factory)
return cast(Any, service_factory).__new__(service_factory)
return service_factory()
monkeypatch.setattr(module, "_snippet_service", factory)
@ -40,23 +134,17 @@ def app():
def test_ensure_snippet_draft_variable_row_allowed_rejects_system_variable():
variable = SimpleNamespace(node_id=SYSTEM_VARIABLE_NODE_ID)
with pytest.raises(module.NotFoundError, match="variable not found"):
module._ensure_snippet_draft_variable_row_allowed(variable=variable, variable_id="var-1")
module._ensure_snippet_draft_variable_row_allowed(variable=_make_system_variable(), variable_id="var-1")
def test_ensure_snippet_draft_variable_row_allowed_rejects_conversation_variable():
variable = SimpleNamespace(node_id=CONVERSATION_VARIABLE_NODE_ID)
with pytest.raises(module.NotFoundError, match="variable not found"):
module._ensure_snippet_draft_variable_row_allowed(variable=variable, variable_id="var-1")
module._ensure_snippet_draft_variable_row_allowed(variable=_make_conversation_variable(), variable_id="var-1")
def test_ensure_snippet_draft_variable_row_allowed_accepts_canvas_node_variable():
variable = SimpleNamespace(node_id="llm-1")
module._ensure_snippet_draft_variable_row_allowed(variable=variable, variable_id="var-1")
module._ensure_snippet_draft_variable_row_allowed(variable=_make_node_variable(), variable_id="var-1")
def test_conversation_variables_returns_empty_list(app: Flask):
@ -64,9 +152,9 @@ def test_conversation_variables_returns_empty_list(app: Flask):
handler = unwrap(api.get)
with app.test_request_context("/"):
result = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
result = handler(api, _make_account(), snippet=_make_snippet())
assert result == WorkflowDraftVariableList(variables=[])
assert result == {"items": []}
def test_system_variables_returns_empty_list(app: Flask):
@ -74,9 +162,9 @@ def test_system_variables_returns_empty_list(app: Flask):
handler = unwrap(api.get)
with app.test_request_context("/"):
result = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
result = handler(api, _make_account(), snippet=_make_snippet())
assert result == WorkflowDraftVariableList(variables=[])
assert result == {"items": []}
def test_delete_variable_collection_deletes_current_user_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
@ -89,10 +177,10 @@ def test_delete_variable_collection_deletes_current_user_variables(app: Flask, m
handler = unwrap(api.delete)
with app.test_request_context("/", method="DELETE"):
response = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
response = handler(api, _make_account(), snippet=_make_snippet())
assert response.status_code == 204
draft_var_service.delete_user_workflow_variables.assert_called_once_with("snippet-1", user_id="user-1")
assert response == ("", 204)
draft_var_service.delete_user_workflow_variables.assert_called_once_with(_TEST_SNIPPET_ID, user_id=_TEST_USER_ID)
db_session.commit.assert_called_once()
@ -108,11 +196,58 @@ def test_variable_collection_get_raises_when_draft_workflow_missing(app: Flask,
with app.test_request_context("/?page=1&limit=20"):
with pytest.raises(module.DraftWorkflowNotExist):
handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
handler(api, _make_account(), snippet=_make_snippet())
def test_variable_collection_get_returns_without_value_contract(app, monkeypatch):
variable = _make_node_variable(value="hidden-value")
draft_workflow = _make_draft_workflow()
captured_args: dict[str, Any] = {}
class DraftVariableService:
def __init__(self, *, session: object) -> None:
captured_args["session"] = session
def list_variables_without_values(self, **kwargs: Any) -> WorkflowDraftVariableList:
captured_args.update(kwargs)
return WorkflowDraftVariableList(variables=[variable], total=9)
session = object()
monkeypatch.setattr(
module,
"SnippetService",
Mock(return_value=SimpleNamespace(get_draft_workflow=Mock(return_value=draft_workflow))),
)
monkeypatch.setattr(module, "WorkflowDraftVariableService", DraftVariableService)
monkeypatch.setattr(module, "db", SimpleNamespace(engine=object()))
monkeypatch.setattr(
module,
"Session",
lambda *args, **kwargs: nullcontext(session),
)
api = module.SnippetWorkflowVariableCollectionApi()
handler = unwrap(api.get)
with app.test_request_context("/?page=2&limit=3", method="GET"):
result = handler(api, _make_account(), snippet=_make_snippet())
expected = {"items": [_expected_variable_without_value_payload(variable)], "total": 9}
assert captured_args == {
"session": session,
"app_id": _TEST_SNIPPET_ID,
"page": 2,
"limit": 3,
"user_id": _TEST_USER_ID,
"exclude_node_ids": module._SNIPPET_EXCLUDED_DRAFT_VARIABLE_NODE_IDS,
}
assert result == expected
module.WorkflowDraftVariableListWithoutValueResponse.model_validate(result)
def test_node_variable_collection_get_lists_node_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
variables = WorkflowDraftVariableList(variables=[SimpleNamespace(id="var-1")])
variable = _make_node_variable(value=None)
variables = WorkflowDraftVariableList(variables=[variable])
list_node_variables = Mock(return_value=variables)
class SessionContext:
@ -138,10 +273,12 @@ def test_node_variable_collection_get_lists_node_variables(app: Flask, monkeypat
handler = unwrap(api.get)
with app.test_request_context("/"):
result = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"), node_id="llm-1")
result = handler(api, _make_account(), snippet=_make_snippet(), node_id="llm-1")
assert result is variables
list_node_variables.assert_called_once_with("snippet-1", "llm-1", user_id="user-1")
expected = {"items": [_expected_variable_payload(variable, value=None)]}
assert result == expected
module.WorkflowDraftVariableListResponse.model_validate(result)
list_node_variables.assert_called_once_with(_TEST_SNIPPET_ID, "llm-1", user_id=_TEST_USER_ID)
def test_node_variable_collection_delete_deletes_node_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
@ -156,15 +293,15 @@ def test_node_variable_collection_delete_deletes_node_variables(app: Flask, monk
handler = unwrap(api.delete)
with app.test_request_context("/", method="DELETE"):
response = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"), node_id="llm-1")
response = handler(api, _make_account(), snippet=_make_snippet(), node_id="llm-1")
assert response.status_code == 204
delete_node_variables.assert_called_once_with("snippet-1", "llm-1", user_id="user-1")
assert response == ("", 204)
delete_node_variables.assert_called_once_with(_TEST_SNIPPET_ID, "llm-1", user_id=_TEST_USER_ID)
db_session.commit.assert_called_once()
def test_variable_patch_returns_variable_when_no_changes(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
variable = _make_node_variable(value=42)
draft_var_service = SimpleNamespace(get_variable=Mock(return_value=variable), update_variable=Mock())
db_session = Mock()
db_session.return_value = SimpleNamespace()
@ -178,17 +315,76 @@ def test_variable_patch_returns_variable_when_no_changes(app: Flask, monkeypatch
result = handler(
api,
_make_account(),
snippet=SimpleNamespace(id="snippet-1", tenant_id="tenant-1"),
variable_id="var-1",
snippet=_make_snippet(),
variable_id=variable.id,
)
assert result is variable
expected = _expected_variable_payload(variable, value=42)
assert result == expected
module.WorkflowDraftVariableResponse.model_validate(result)
draft_var_service.update_variable.assert_not_called()
db_session.commit.assert_not_called()
def test_variable_get_returns_raw_response_contract(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = _make_node_variable(value={"count": 2, "enabled": True})
draft_var_service = SimpleNamespace(get_variable=Mock(return_value=variable))
db_session = Mock()
db_session.return_value = SimpleNamespace()
monkeypatch.setattr(module.db, "session", db_session)
monkeypatch.setattr(module, "WorkflowDraftVariableService", Mock(return_value=draft_var_service))
api = module.SnippetVariableApi()
handler = unwrap(api.get)
with app.test_request_context("/", method="GET"):
result = handler(api, _make_account(), snippet=_make_snippet(), variable_id=variable.id)
expected = _expected_variable_payload(variable, value={"count": 2, "enabled": True})
assert result == expected
module.WorkflowDraftVariableResponse.model_validate(result)
draft_var_service.get_variable.assert_called_once_with(variable_id=variable.id)
def test_variable_patch_updates_from_pydantic_payload_and_returns_raw_contract(
app: Flask, monkeypatch: pytest.MonkeyPatch
):
variable = _make_node_variable(value=1, name="old_name")
request_model = module.WorkflowDraftVariableUpdatePayload.model_validate({"name": "renamed", "value": 13})
class DraftVariableService:
def __init__(self, session: object) -> None:
pass
def get_variable(self, *, variable_id: str) -> WorkflowDraftVariable:
assert variable_id == variable.id
return variable
def update_variable(self, target: WorkflowDraftVariable, *, name: str | None, value: Any) -> None:
assert target is variable
assert name == "renamed"
target.set_name(name)
target.set_value(value)
session = Mock(return_value=object())
session.commit = Mock()
monkeypatch.setattr(module, "WorkflowDraftVariableService", DraftVariableService)
monkeypatch.setattr(module.db, "session", session)
api = module.SnippetVariableApi()
handler = unwrap(api.patch)
with app.test_request_context("/", method="PATCH", json=request_model.model_dump(mode="json")):
result = handler(api, _make_account(), snippet=_make_snippet(), variable_id=variable.id)
expected = _expected_variable_payload(variable, value=13)
assert result == expected
module.WorkflowDraftVariableResponse.model_validate(result)
session.commit.assert_called_once()
def test_variable_delete_deletes_variable(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
variable = _make_node_variable()
delete_variable = Mock()
draft_var_service = SimpleNamespace(get_variable=Mock(return_value=variable), delete_variable=delete_variable)
db_session = Mock()
@ -200,16 +396,16 @@ def test_variable_delete_deletes_variable(app: Flask, monkeypatch: pytest.Monkey
handler = unwrap(api.delete)
with app.test_request_context("/", method="DELETE"):
response = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"), variable_id="var-1")
response = handler(api, _make_account(), snippet=_make_snippet(), variable_id=variable.id)
assert response.status_code == 204
assert response == ("", 204)
delete_variable.assert_called_once_with(variable)
db_session.commit.assert_called_once()
def test_variable_reset_returns_no_content_when_reset_result_is_none(app: Flask, monkeypatch: pytest.MonkeyPatch):
variable = SimpleNamespace(id="var-1", app_id="snippet-1", user_id="user-1", node_id="llm-1")
draft_workflow = SimpleNamespace(id="workflow-1")
variable = _make_node_variable()
draft_workflow = _make_draft_workflow()
draft_var_service = SimpleNamespace(
get_variable=Mock(return_value=variable),
reset_variable=Mock(return_value=None),
@ -228,42 +424,75 @@ def test_variable_reset_returns_no_content_when_reset_result_is_none(app: Flask,
handler = unwrap(api.put)
with app.test_request_context("/", method="PUT"):
response = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"), variable_id="var-1")
response = handler(api, _make_account(), snippet=_make_snippet(), variable_id=variable.id)
assert response.status_code == 204
draft_var_service.reset_variable.assert_called_once_with(draft_workflow, variable)
db_session.commit.assert_called_once()
def test_environment_variables_returns_workflow_environment_variables(app: Flask, monkeypatch: pytest.MonkeyPatch):
env_var = SimpleNamespace(
id="env-1",
name="API_KEY",
description="secret",
selector=["env", "API_KEY"],
value_type=SimpleNamespace(exposed_type=Mock(return_value=SimpleNamespace(value="secret"))),
value="sk-test",
def test_variable_reset_returns_raw_response_contract_when_variable_is_reset(
app: Flask, monkeypatch: pytest.MonkeyPatch
):
variable = _make_node_variable(value="edited")
reset_variable = _make_node_variable(value="default")
reset_variable.id = variable.id
draft_workflow = _make_draft_workflow()
draft_var_service = SimpleNamespace(
get_variable=Mock(return_value=variable),
reset_variable=Mock(return_value=reset_variable),
)
db_session = Mock()
db_session.return_value = SimpleNamespace()
monkeypatch.setattr(module.db, "session", db_session)
monkeypatch.setattr(module, "WorkflowDraftVariableService", Mock(return_value=draft_var_service))
monkeypatch.setattr(
module,
"SnippetService",
Mock(
return_value=SimpleNamespace(
get_draft_workflow=Mock(return_value=SimpleNamespace(environment_variables=[env_var]))
)
),
Mock(return_value=SimpleNamespace(get_draft_workflow=Mock(return_value=draft_workflow))),
)
api = module.SnippetVariableResetApi()
handler = unwrap(api.put)
with app.test_request_context("/", method="PUT"):
result = handler(api, _make_account(), snippet=_make_snippet(), variable_id=variable.id)
expected = _expected_variable_payload(reset_variable, value="default")
assert result == expected
module.WorkflowDraftVariableResponse.model_validate(result)
draft_var_service.reset_variable.assert_called_once_with(draft_workflow, variable)
db_session.commit.assert_called_once()
def test_environment_variables_returns_workflow_environment_variables(app, monkeypatch):
env_var = build_environment_variable_from_mapping(
{
"id": str(uuid.uuid4()),
"name": "API_KEY",
"description": "secret",
"value_type": SegmentType.SECRET,
"value": "sk-test",
}
)
draft_workflow = _make_draft_workflow(environment_variables=[env_var])
monkeypatch.setattr(workflow_model_module.encrypter, "decrypt_token", lambda tenant_id, token: token)
monkeypatch.setattr(
module,
"SnippetService",
Mock(return_value=SimpleNamespace(get_draft_workflow=Mock(return_value=draft_workflow))),
)
api = module.SnippetEnvironmentVariableCollectionApi()
handler = unwrap(api.get)
with app.test_request_context("/"):
result = handler(api, _make_account(), snippet=SimpleNamespace(id="snippet-1"))
result = handler(api, _make_account(), snippet=_make_snippet())
assert result == {
expected = {
"items": [
{
"id": "env-1",
"id": env_var.id,
"type": "env",
"name": "API_KEY",
"description": "secret",
@ -276,3 +505,5 @@ def test_environment_variables_returns_workflow_environment_variables(app: Flask
}
]
}
assert result == expected
module.WorkflowDraftEnvironmentVariableListResponse.model_validate(result)

View File

@ -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

View File

@ -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

View File

@ -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 = {

View File

@ -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(),
})

File diff suppressed because it is too large Load Diff

View File

@ -119,10 +119,9 @@ export type HumanInputFormPreviewPayload = {
}
export type HumanInputFormPreviewResponse = {
actions?: Array<{
[key: string]: unknown
}>
display_in_ui?: boolean | null
TYPE?: 'human_input_required'
actions?: Array<HumanInputUserActionResponse>
display_in_ui?: boolean
expiration_time?: number | null
form_content: string
form_id: string
@ -137,46 +136,6 @@ export type HumanInputFormPreviewResponse = {
}
}
export type HumanInputFormSubmitPayload = {
action: string
form_inputs: {
[key: string]: unknown
}
inputs: {
[key: string]: unknown
}
}
export type HumanInputFormSubmitResponse = {
[key: string]: unknown
}
export type IterationNodeRunPayload = {
inputs?: {
[key: string]: unknown
} | null
}
export type GeneratedAppResponse = JsonValue
export type LoopNodeRunPayload = {
inputs?: {
[key: string]: unknown
} | null
}
export type AdvancedChatWorkflowRunPayload = {
conversation_id?: string | null
files?: Array<{
[key: string]: unknown
}> | null
inputs?: {
[key: string]: unknown
} | null
parent_message_id?: string | null
query?: string
}
export type AgentDriveListResponse = {
items?: Array<AgentDriveItemResponse>
}
@ -422,6 +381,8 @@ export type CompletionMessagePayload = {
retriever_from?: string
}
export type GeneratedAppResponse = JsonValue
export type PaginatedConversationVariableResponse = {
data: Array<ConversationVariableResponse>
has_more: boolean
@ -472,6 +433,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 +449,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 +692,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 +760,7 @@ export type WorkflowCommentCreate = {
}
export type WorkflowCommentMentionUsersPayload = {
users: Array<AccountWithRole>
users: Array<AccountWithRoleResponse>
}
export type WorkflowCommentDetail = {
@ -876,18 +837,10 @@ export type WorkflowPaginationResponse = {
page: number
}
export type DefaultBlockConfigsResponse = Array<{
[key: string]: unknown
}>
export type DefaultBlockConfigResponse = {
[key: string]: unknown
}
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 +855,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
}
@ -923,13 +876,13 @@ export type SyncDraftWorkflowPayload = {
}
export type SyncDraftWorkflowResponse = {
hash?: string
result?: string
updated_at?: string
hash: string
result: string
updated_at: number
}
export type WorkflowDraftVariableList = {
items?: Array<WorkflowDraftVariable>
export type WorkflowDraftVariableListResponse = {
items: Array<WorkflowDraftVariableResponse>
}
export type ConversationVariableUpdatePayload = {
@ -938,8 +891,8 @@ export type ConversationVariableUpdatePayload = {
}>
}
export type EnvironmentVariableListResponse = {
items: Array<EnvironmentVariableItemResponse>
export type WorkflowDraftEnvironmentVariableListResponse = {
items: Array<WorkflowDraftEnvironmentVariableResponse>
}
export type EnvironmentVariableUpdatePayload = {
@ -961,7 +914,7 @@ export type HumanInputDeliveryTestPayload = {
}
}
export type EmptyObjectResponse = {
export type HumanInputDeliveryTestResponse = {
[key: string]: unknown
}
@ -1029,7 +982,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
@ -1062,17 +1015,6 @@ export type DraftWorkflowNodeRunPayload = {
query?: string
}
export type DraftWorkflowRunPayload = {
datasource_info_list: Array<{
[key: string]: unknown
}>
datasource_type: string
inputs: {
[key: string]: unknown
}
start_node_id: string
}
export type WorkflowRunSnapshotView = {
node_outputs?: Array<NodeOutputsView>
workflow_run_id: string
@ -1099,56 +1041,36 @@ export type OutputPreviewView = {
value?: unknown
}
export type DraftWorkflowTriggerRunRequest = {
node_id: string
export type WorkflowDraftVariableListWithoutValueResponse = {
items: Array<WorkflowDraftVariableWithoutValueResponse>
total: number | null
}
export type DraftWorkflowTriggerRunAllPayload = {
node_ids: Array<string>
}
export type WorkflowDraftVariableListWithoutValue = {
items?: Array<WorkflowDraftVariableWithoutValue>
total?: number
}
export type WorkflowDraftVariable = {
description?: string
edited?: boolean
full_content?: {
[key: string]: unknown
}
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value?:
| string
| number
| number
| boolean
| {
[key: string]: unknown
}
| Array<unknown>
| null
value_type?: string
visible?: boolean
export type WorkflowDraftVariableResponse = {
description: string
edited: boolean
full_content: WorkflowDraftVariableFullContentResponse | null
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value: unknown
value_type: string
visible: boolean
}
export type WorkflowDraftVariableUpdatePayload = {
name?: string | null
value?: unknown | null
value?: unknown
}
export type PublishWorkflowPayload = {
knowledge_base_setting?: {
[key: string]: unknown
} | null
marked_comment?: string | null
marked_name?: string | null
}
export type WorkflowPublishResponse = {
export type PublishWorkflowResponse = {
created_at: number
result: string
}
@ -1167,12 +1089,6 @@ export type WorkflowUpdatePayload = {
marked_name?: string | null
}
export type WorkflowRestoreResponse = {
hash: string
result: string
updated_at: number
}
export type ApiKeyList = {
data: Array<ApiKeyItem>
}
@ -1289,7 +1205,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
@ -1302,6 +1218,12 @@ export type AdvancedChatWorkflowRunForListResponse = {
version?: string | null
}
export type HumanInputUserActionResponse = {
button_style?: string
id: string
title: string
}
export type AgentDriveItemResponse = {
created_at?: number | null
file_kind: string
@ -1498,7 +1420,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 +1439,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 +1517,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 +1528,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 +1537,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 +1549,7 @@ export type WorkflowRunForListResponse = {
version?: string | null
}
export type SimpleAccount = {
export type SimpleAccountResponse = {
email: string
id: string
name: string
@ -1671,7 +1592,7 @@ export type WorkflowCommentBasic = {
updated_at?: number | null
}
export type AccountWithRole = {
export type AccountWithRoleResponse = {
avatar?: string | null
created_at?: number | null
email: string
@ -1760,7 +1681,7 @@ export type PipelineVariableResponse = {
variable: string
}
export type EnvironmentVariableItemResponse = {
export type WorkflowDraftEnvironmentVariableResponse = {
description?: string | null
editable: boolean
edited: boolean
@ -1961,16 +1882,23 @@ export type NodeOutputStatus
export type DeclaredOutputType = 'array' | 'boolean' | 'file' | 'number' | 'object' | 'string'
export type WorkflowDraftVariableWithoutValue = {
description?: string
edited?: boolean
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value_type?: string
visible?: boolean
export type WorkflowDraftVariableWithoutValueResponse = {
description: string
edited: boolean
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value_type: string
visible: boolean
}
export type WorkflowDraftVariableFullContentResponse = {
download_url: string
length: number | null
size_bytes: number | null
value_type: string
}
export type ModelConfigPartial = {
@ -2054,6 +1982,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
@ -2654,6 +2588,10 @@ export type WorkflowCommentDetailWritable = {
updated_at?: number | null
}
export type HumanInputDeliveryTestResponseWritable = {
[key: string]: unknown
}
export type AppPartialWritable = {
access_mode?: string | null
app_id?: string | null
@ -2999,88 +2937,6 @@ export type PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdForm
export type PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponse
= PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponses[keyof PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponses]
export type PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunData = {
body: HumanInputFormSubmitPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/advanced-chat/workflows/draft/human-input/nodes/{node_id}/form/run'
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses = {
200: HumanInputFormSubmitResponse
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunResponse
= PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses[keyof PostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses]
export type PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunData = {
body: IterationNodeRunPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/advanced-chat/workflows/draft/iteration/nodes/{node_id}/run'
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunErrors = {
403: unknown
404: unknown
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunResponse
= PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunResponses[keyof PostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunResponses]
export type PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunData = {
body: LoopNodeRunPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/advanced-chat/workflows/draft/loop/nodes/{node_id}/run'
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunErrors = {
403: unknown
404: unknown
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunResponse
= PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunResponses[keyof PostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunResponses]
export type PostAppsByAppIdAdvancedChatWorkflowsDraftRunData = {
body: AdvancedChatWorkflowRunPayload
path: {
app_id: string
}
query?: never
url: '/apps/{app_id}/advanced-chat/workflows/draft/run'
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftRunErrors = {
400: unknown
403: unknown
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdAdvancedChatWorkflowsDraftRunResponse
= PostAppsByAppIdAdvancedChatWorkflowsDraftRunResponses[keyof PostAppsByAppIdAdvancedChatWorkflowsDraftRunResponses]
export type GetAppsByAppIdAgentDriveFilesData = {
body?: never
path: {
@ -5114,45 +4970,6 @@ export type GetAppsByAppIdWorkflowsResponses = {
export type GetAppsByAppIdWorkflowsResponse
= GetAppsByAppIdWorkflowsResponses[keyof GetAppsByAppIdWorkflowsResponses]
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsData = {
body?: never
path: {
app_id: string
}
query?: never
url: '/apps/{app_id}/workflows/default-workflow-block-configs'
}
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsResponses = {
200: DefaultBlockConfigsResponse
}
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsResponse
= GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsResponses[keyof GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsResponses]
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeData = {
body?: never
path: {
app_id: string
block_type: string
}
query?: {
q?: string
}
url: '/apps/{app_id}/workflows/default-workflow-block-configs/{block_type}'
}
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeErrors = {
404: unknown
}
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses = {
200: DefaultBlockConfigResponse
}
export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse
= GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses[keyof GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses]
export type GetAppsByAppIdWorkflowsDraftData = {
body?: never
path: {
@ -5208,7 +5025,7 @@ export type GetAppsByAppIdWorkflowsDraftConversationVariablesErrors = {
}
export type GetAppsByAppIdWorkflowsDraftConversationVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetAppsByAppIdWorkflowsDraftConversationVariablesResponse
@ -5244,7 +5061,7 @@ export type GetAppsByAppIdWorkflowsDraftEnvironmentVariablesErrors = {
}
export type GetAppsByAppIdWorkflowsDraftEnvironmentVariablesResponses = {
200: EnvironmentVariableListResponse
200: WorkflowDraftEnvironmentVariableListResponse
}
export type GetAppsByAppIdWorkflowsDraftEnvironmentVariablesResponse
@ -5293,7 +5110,7 @@ export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestData
}
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestResponses = {
200: EmptyObjectResponse
200: HumanInputDeliveryTestResponse
}
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestResponse
@ -5316,67 +5133,6 @@ export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewRespo
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponse
= PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponses[keyof PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponses]
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunData = {
body: HumanInputFormSubmitPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/human-input/nodes/{node_id}/form/run'
}
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses = {
200: HumanInputFormSubmitResponse
}
export type PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponse
= PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses[keyof PostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponses]
export type PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunData = {
body: IterationNodeRunPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/iteration/nodes/{node_id}/run'
}
export type PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunErrors = {
403: unknown
404: unknown
}
export type PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponse
= PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponses[keyof PostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponses]
export type PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunData = {
body: LoopNodeRunPayload
path: {
app_id: string
node_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/loop/nodes/{node_id}/run'
}
export type PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunErrors = {
403: unknown
404: unknown
}
export type PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponse
= PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponses[keyof PostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponses]
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerData = {
body?: never
path: {
@ -5556,7 +5312,7 @@ export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunErrors = {
}
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunResponses = {
200: GeneratedAppResponse
200: WorkflowRunNodeExecutionResponse
}
export type PostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunResponse
@ -5590,32 +5346,12 @@ export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesData = {
}
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesResponse
= GetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesResponses[keyof GetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesResponses]
export type PostAppsByAppIdWorkflowsDraftRunData = {
body: DraftWorkflowRunPayload
path: {
app_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/run'
}
export type PostAppsByAppIdWorkflowsDraftRunErrors = {
403: unknown
}
export type PostAppsByAppIdWorkflowsDraftRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdWorkflowsDraftRunResponse
= PostAppsByAppIdWorkflowsDraftRunResponses[keyof PostAppsByAppIdWorkflowsDraftRunResponses]
export type GetAppsByAppIdWorkflowsDraftRunsByRunIdNodeOutputsData = {
body?: never
path: {
@ -5714,54 +5450,12 @@ export type GetAppsByAppIdWorkflowsDraftSystemVariablesData = {
}
export type GetAppsByAppIdWorkflowsDraftSystemVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetAppsByAppIdWorkflowsDraftSystemVariablesResponse
= GetAppsByAppIdWorkflowsDraftSystemVariablesResponses[keyof GetAppsByAppIdWorkflowsDraftSystemVariablesResponses]
export type PostAppsByAppIdWorkflowsDraftTriggerRunData = {
body: DraftWorkflowTriggerRunRequest
path: {
app_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/trigger/run'
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunErrors = {
403: unknown
500: unknown
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunResponse
= PostAppsByAppIdWorkflowsDraftTriggerRunResponses[keyof PostAppsByAppIdWorkflowsDraftTriggerRunResponses]
export type PostAppsByAppIdWorkflowsDraftTriggerRunAllData = {
body: DraftWorkflowTriggerRunAllPayload
path: {
app_id: string
}
query?: never
url: '/apps/{app_id}/workflows/draft/trigger/run-all'
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunAllErrors = {
403: unknown
500: unknown
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunAllResponses = {
200: GeneratedAppResponse
}
export type PostAppsByAppIdWorkflowsDraftTriggerRunAllResponse
= PostAppsByAppIdWorkflowsDraftTriggerRunAllResponses[keyof PostAppsByAppIdWorkflowsDraftTriggerRunAllResponses]
export type DeleteAppsByAppIdWorkflowsDraftVariablesData = {
body?: never
path: {
@ -5791,7 +5485,7 @@ export type GetAppsByAppIdWorkflowsDraftVariablesData = {
}
export type GetAppsByAppIdWorkflowsDraftVariablesResponses = {
200: WorkflowDraftVariableListWithoutValue
200: WorkflowDraftVariableListWithoutValueResponse
}
export type GetAppsByAppIdWorkflowsDraftVariablesResponse
@ -5833,7 +5527,7 @@ export type GetAppsByAppIdWorkflowsDraftVariablesByVariableIdErrors = {
}
export type GetAppsByAppIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type GetAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse
@ -5854,7 +5548,7 @@ export type PatchAppsByAppIdWorkflowsDraftVariablesByVariableIdErrors = {
}
export type PatchAppsByAppIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type PatchAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse
@ -5875,7 +5569,7 @@ export type PutAppsByAppIdWorkflowsDraftVariablesByVariableIdResetErrors = {
}
export type PutAppsByAppIdWorkflowsDraftVariablesByVariableIdResetResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
204: void
}
@ -5908,7 +5602,7 @@ export type PostAppsByAppIdWorkflowsPublishData = {
}
export type PostAppsByAppIdWorkflowsPublishResponses = {
200: WorkflowPublishResponse
200: PublishWorkflowResponse
}
export type PostAppsByAppIdWorkflowsPublishResponse
@ -6077,7 +5771,7 @@ export type PostAppsByAppIdWorkflowsByWorkflowIdRestoreErrors = {
}
export type PostAppsByAppIdWorkflowsByWorkflowIdRestoreResponses = {
200: WorkflowRestoreResponse
200: SyncDraftWorkflowResponse
}
export type PostAppsByAppIdWorkflowsByWorkflowIdRestoreResponse

View File

@ -43,61 +43,6 @@ export const zHumanInputFormPreviewPayload = z.object({
inputs: z.record(z.string(), z.unknown()).optional(),
})
/**
* HumanInputFormPreviewResponse
*/
export const zHumanInputFormPreviewResponse = z.object({
actions: z.array(z.record(z.string(), z.unknown())).optional(),
display_in_ui: z.boolean().nullish(),
expiration_time: z.int().nullish(),
form_content: z.string(),
form_id: z.string(),
form_token: z.string().nullish(),
inputs: z.array(z.record(z.string(), z.unknown())).optional(),
node_id: z.string(),
node_title: z.string(),
resolved_default_values: z.record(z.string(), z.unknown()).optional(),
})
/**
* HumanInputFormSubmitPayload
*/
export const zHumanInputFormSubmitPayload = z.object({
action: z.string(),
form_inputs: z.record(z.string(), z.unknown()),
inputs: z.record(z.string(), z.unknown()),
})
/**
* HumanInputFormSubmitResponse
*/
export const zHumanInputFormSubmitResponse = z.record(z.string(), z.unknown())
/**
* IterationNodeRunPayload
*/
export const zIterationNodeRunPayload = z.object({
inputs: z.record(z.string(), z.unknown()).nullish(),
})
/**
* LoopNodeRunPayload
*/
export const zLoopNodeRunPayload = z.object({
inputs: z.record(z.string(), z.unknown()).nullish(),
})
/**
* AdvancedChatWorkflowRunPayload
*/
export const zAdvancedChatWorkflowRunPayload = z.object({
conversation_id: z.string().nullish(),
files: z.array(z.record(z.string(), z.unknown())).nullish(),
inputs: z.record(z.string(), z.unknown()).nullish(),
parent_message_id: z.string().nullish(),
query: z.string().optional().default(''),
})
/**
* AgentDriveDownloadResponse
*/
@ -581,16 +526,6 @@ export const zWorkflowCommentResolve = z.object({
resolved_by: z.string().nullish(),
})
/**
* DefaultBlockConfigsResponse
*/
export const zDefaultBlockConfigsResponse = z.array(z.record(z.string(), z.unknown()))
/**
* DefaultBlockConfigResponse
*/
export const zDefaultBlockConfigResponse = z.record(z.string(), z.unknown())
/**
* SyncDraftWorkflowPayload
*/
@ -602,10 +537,13 @@ export const zSyncDraftWorkflowPayload = z.object({
hash: z.string().nullish(),
})
/**
* SyncDraftWorkflowResponse
*/
export const zSyncDraftWorkflowResponse = z.object({
hash: z.string().optional(),
result: z.string().optional(),
updated_at: z.string().optional(),
hash: z.string(),
result: z.string(),
updated_at: z.int(),
})
/**
@ -638,9 +576,9 @@ export const zHumanInputDeliveryTestPayload = z.object({
})
/**
* EmptyObjectResponse
* HumanInputDeliveryTestResponse
*/
export const zEmptyObjectResponse = z.record(z.string(), z.unknown())
export const zHumanInputDeliveryTestResponse = z.record(z.string(), z.unknown())
/**
* WorkflowComposerCopyFromRosterPayload
@ -660,80 +598,31 @@ export const zDraftWorkflowNodeRunPayload = z.object({
query: z.string().optional().default(''),
})
/**
* DraftWorkflowRunPayload
*/
export const zDraftWorkflowRunPayload = z.object({
datasource_info_list: z.array(z.record(z.string(), z.unknown())),
datasource_type: z.string(),
inputs: z.record(z.string(), z.unknown()),
start_node_id: z.string(),
})
/**
* EventStreamResponse
*/
export const zEventStreamResponse = z.string()
export const zDraftWorkflowTriggerRunRequest = z.object({
node_id: z.string(),
})
/**
* DraftWorkflowTriggerRunAllPayload
*/
export const zDraftWorkflowTriggerRunAllPayload = z.object({
node_ids: z.array(z.string()),
})
export const zWorkflowDraftVariable = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
full_content: z.record(z.string(), z.unknown()).optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value: z
.union([
z.string(),
z.int(),
z.number(),
z.boolean(),
z.record(z.string(), z.unknown()),
z.array(z.unknown()),
])
.nullish(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
})
export const zWorkflowDraftVariableList = z.object({
items: z.array(zWorkflowDraftVariable).optional(),
})
/**
* WorkflowDraftVariableUpdatePayload
*/
export const zWorkflowDraftVariableUpdatePayload = z.object({
name: z.string().nullish(),
value: z.unknown().nullish(),
value: z.unknown().optional(),
})
/**
* PublishWorkflowPayload
*
* Payload for publishing snippet workflow.
*/
export const zPublishWorkflowPayload = z.object({
knowledge_base_setting: z.record(z.string(), z.unknown()).nullish(),
marked_comment: z.string().max(100).nullish(),
marked_name: z.string().max(20).nullish(),
})
/**
* WorkflowPublishResponse
* PublishWorkflowResponse
*/
export const zWorkflowPublishResponse = z.object({
export const zPublishWorkflowResponse = z.object({
created_at: z.int(),
result: z.string(),
})
@ -758,15 +647,6 @@ export const zWorkflowUpdatePayload = z.object({
marked_name: z.string().max(20).nullish(),
})
/**
* WorkflowRestoreResponse
*/
export const zWorkflowRestoreResponse = z.object({
hash: z.string(),
result: z.string(),
updated_at: z.int(),
})
/**
* ApiKeyItem
*/
@ -919,6 +799,32 @@ export const zImport = z.object({
status: zImportStatus,
})
/**
* HumanInputUserActionResponse
*/
export const zHumanInputUserActionResponse = z.object({
button_style: z.string().optional().default('default'),
id: z.string(),
title: z.string(),
})
/**
* HumanInputFormPreviewResponse
*/
export const zHumanInputFormPreviewResponse = z.object({
TYPE: z.literal('human_input_required').optional().default('human_input_required'),
actions: z.array(zHumanInputUserActionResponse).optional(),
display_in_ui: z.boolean().optional().default(false),
expiration_time: z.int().nullish(),
form_content: z.string(),
form_id: z.string(),
form_token: z.string().nullish(),
inputs: z.array(z.record(z.string(), z.unknown())).optional(),
node_id: z.string(),
node_title: z.string(),
resolved_default_values: z.record(z.string(), z.unknown()).optional(),
})
/**
* AgentDriveItemResponse
*/
@ -1150,7 +1056,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 +1224,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 +1238,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 +1260,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 +1301,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 +1323,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 +1389,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 +1408,7 @@ export const zAccountWithRole = z.object({
* WorkflowCommentMentionUsersPayload
*/
export const zWorkflowCommentMentionUsersPayload = z.object({
users: z.array(zAccountWithRole),
users: z.array(zAccountWithRoleResponse),
})
/**
@ -1752,7 +1597,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 +1608,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(),
})
@ -1778,9 +1623,9 @@ export const zWorkflowPaginationResponse = z.object({
})
/**
* EnvironmentVariableItemResponse
* WorkflowDraftEnvironmentVariableResponse
*/
export const zEnvironmentVariableItemResponse = z.object({
export const zWorkflowDraftEnvironmentVariableResponse = z.object({
description: z.string().nullish(),
editable: z.boolean(),
edited: z.boolean(),
@ -1794,10 +1639,10 @@ export const zEnvironmentVariableItemResponse = z.object({
})
/**
* EnvironmentVariableListResponse
* WorkflowDraftEnvironmentVariableListResponse
*/
export const zEnvironmentVariableListResponse = z.object({
items: z.array(zEnvironmentVariableItemResponse),
export const zWorkflowDraftEnvironmentVariableListResponse = z.object({
items: z.array(zWorkflowDraftEnvironmentVariableResponse),
})
/**
@ -1984,21 +1829,61 @@ export const zOutputPreviewView = z.object({
value: z.unknown().optional(),
})
export const zWorkflowDraftVariableWithoutValue = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
/**
* WorkflowDraftVariableWithoutValueResponse
*/
export const zWorkflowDraftVariableWithoutValueResponse = z.object({
description: z.string(),
edited: z.boolean(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value_type: z.string(),
visible: z.boolean(),
})
export const zWorkflowDraftVariableListWithoutValue = z.object({
items: z.array(zWorkflowDraftVariableWithoutValue).optional(),
total: z.int().optional(),
/**
* WorkflowDraftVariableListWithoutValueResponse
*/
export const zWorkflowDraftVariableListWithoutValueResponse = z.object({
items: z.array(zWorkflowDraftVariableWithoutValueResponse),
total: z.int().nullable(),
})
/**
* WorkflowDraftVariableFullContentResponse
*/
export const zWorkflowDraftVariableFullContentResponse = z.object({
download_url: z.string(),
length: z.int().nullable(),
size_bytes: z.int().nullable(),
value_type: z.string(),
})
/**
* WorkflowDraftVariableResponse
*/
export const zWorkflowDraftVariableResponse = z.object({
description: z.string(),
edited: z.boolean(),
full_content: zWorkflowDraftVariableFullContentResponse.nullable(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value: z.unknown(),
value_type: z.string(),
visible: z.boolean(),
})
/**
* WorkflowDraftVariableListResponse
*/
export const zWorkflowDraftVariableListResponse = z.object({
items: z.array(zWorkflowDraftVariableResponse),
})
/**
@ -2152,20 +2037,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 +2237,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 +2289,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 +2379,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 +2415,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 +3409,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 +3423,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(),
})
@ -3492,6 +3446,11 @@ export const zMessageInfiniteScrollPaginationResponse = z.object({
*/
export const zGeneratedAppResponseWritable = zJsonValue
/**
* HumanInputDeliveryTestResponse
*/
export const zHumanInputDeliveryTestResponseWritable = z.record(z.string(), z.unknown())
/**
* AppPartial
*/
@ -3835,65 +3794,11 @@ export const zPostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFo
})
/**
* Human input form preview
* Human input form preview retrieved
*/
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponse
= zHumanInputFormPreviewResponse
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunBody
= zHumanInputFormSubmitPayload
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunPath
= z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Human input form submission result
*/
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftHumanInputNodesByNodeIdFormRunResponse
= zHumanInputFormSubmitResponse
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunBody
= zIterationNodeRunPayload
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Iteration node run started successfully
*/
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftIterationNodesByNodeIdRunResponse
= zGeneratedAppResponse
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunBody
= zLoopNodeRunPayload
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Loop node run started successfully
*/
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftLoopNodesByNodeIdRunResponse
= zGeneratedAppResponse
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftRunBody = zAdvancedChatWorkflowRunPayload
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftRunPath = z.object({
app_id: z.uuid(),
})
/**
* Workflow run started successfully
*/
export const zPostAppsByAppIdAdvancedChatWorkflowsDraftRunResponse = zGeneratedAppResponse
export const zGetAppsByAppIdAgentDriveFilesPath = z.object({
app_id: z.uuid(),
})
@ -5163,31 +5068,6 @@ export const zGetAppsByAppIdWorkflowsQuery = z.object({
*/
export const zGetAppsByAppIdWorkflowsResponse = zWorkflowPaginationResponse
export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsPath = z.object({
app_id: z.uuid(),
})
/**
* Default block configurations retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsResponse
= zDefaultBlockConfigsResponse
export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypePath = z.object({
app_id: z.uuid(),
block_type: z.string(),
})
export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeQuery = z.object({
q: z.string().optional(),
})
/**
* Default block configuration retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse
= zDefaultBlockConfigResponse
export const zGetAppsByAppIdWorkflowsDraftPath = z.object({
app_id: z.uuid(),
})
@ -5215,7 +5095,8 @@ export const zGetAppsByAppIdWorkflowsDraftConversationVariablesPath = z.object({
/**
* Conversation variables retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftConversationVariablesResponse = zWorkflowDraftVariableList
export const zGetAppsByAppIdWorkflowsDraftConversationVariablesResponse
= zWorkflowDraftVariableListResponse
export const zPostAppsByAppIdWorkflowsDraftConversationVariablesBody
= zConversationVariableUpdatePayload
@ -5237,7 +5118,7 @@ export const zGetAppsByAppIdWorkflowsDraftEnvironmentVariablesPath = z.object({
* Environment variables retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftEnvironmentVariablesResponse
= zEnvironmentVariableListResponse
= zWorkflowDraftEnvironmentVariableListResponse
export const zPostAppsByAppIdWorkflowsDraftEnvironmentVariablesBody
= zEnvironmentVariableUpdatePayload
@ -5271,10 +5152,10 @@ export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestPa
})
/**
* Human input delivery test result
* Human input delivery tested
*/
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestResponse
= zEmptyObjectResponse
= zHumanInputDeliveryTestResponse
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewBody
= zHumanInputFormPreviewPayload
@ -5285,49 +5166,11 @@ export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewPat
})
/**
* Human input form preview
* Human input form preview retrieved
*/
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponse
= zHumanInputFormPreviewResponse
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunBody
= zHumanInputFormSubmitPayload
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Human input form submission result
*/
export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponse
= zHumanInputFormSubmitResponse
export const zPostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunBody = zIterationNodeRunPayload
export const zPostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Workflow iteration node run started successfully
*/
export const zPostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponse = zGeneratedAppResponse
export const zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunBody = zLoopNodeRunPayload
export const zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
})
/**
* Workflow loop node run started successfully
*/
export const zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponse = zGeneratedAppResponse
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerPath = z.object({
app_id: z.uuid(),
node_id: z.string(),
@ -5451,7 +5294,8 @@ export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunPath = z.objec
/**
* Trigger event received and node executed successfully
*/
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunResponse = zGeneratedAppResponse
export const zPostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunResponse
= zWorkflowRunNodeExecutionResponse
export const zDeleteAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesPath = z.object({
app_id: z.uuid(),
@ -5472,18 +5316,7 @@ export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesPath = z.object(
* Node variables retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftNodesByNodeIdVariablesResponse
= zWorkflowDraftVariableList
export const zPostAppsByAppIdWorkflowsDraftRunBody = zDraftWorkflowRunPayload
export const zPostAppsByAppIdWorkflowsDraftRunPath = z.object({
app_id: z.uuid(),
})
/**
* Draft workflow run started successfully
*/
export const zPostAppsByAppIdWorkflowsDraftRunResponse = zGeneratedAppResponse
= zWorkflowDraftVariableListResponse
export const zGetAppsByAppIdWorkflowsDraftRunsByRunIdNodeOutputsPath = z.object({
app_id: z.uuid(),
@ -5538,29 +5371,8 @@ export const zGetAppsByAppIdWorkflowsDraftSystemVariablesPath = z.object({
/**
* System variables retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftSystemVariablesResponse = zWorkflowDraftVariableList
export const zPostAppsByAppIdWorkflowsDraftTriggerRunBody = zDraftWorkflowTriggerRunRequest
export const zPostAppsByAppIdWorkflowsDraftTriggerRunPath = z.object({
app_id: z.uuid(),
})
/**
* Trigger event received and workflow executed successfully
*/
export const zPostAppsByAppIdWorkflowsDraftTriggerRunResponse = zGeneratedAppResponse
export const zPostAppsByAppIdWorkflowsDraftTriggerRunAllBody = zDraftWorkflowTriggerRunAllPayload
export const zPostAppsByAppIdWorkflowsDraftTriggerRunAllPath = z.object({
app_id: z.uuid(),
})
/**
* Workflow executed successfully
*/
export const zPostAppsByAppIdWorkflowsDraftTriggerRunAllResponse = zGeneratedAppResponse
export const zGetAppsByAppIdWorkflowsDraftSystemVariablesResponse
= zWorkflowDraftVariableListResponse
export const zDeleteAppsByAppIdWorkflowsDraftVariablesPath = z.object({
app_id: z.uuid(),
@ -5583,7 +5395,8 @@ export const zGetAppsByAppIdWorkflowsDraftVariablesQuery = z.object({
/**
* Workflow variables retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftVariablesResponse = zWorkflowDraftVariableListWithoutValue
export const zGetAppsByAppIdWorkflowsDraftVariablesResponse
= zWorkflowDraftVariableListWithoutValueResponse
export const zDeleteAppsByAppIdWorkflowsDraftVariablesByVariableIdPath = z.object({
app_id: z.uuid(),
@ -5603,7 +5416,8 @@ export const zGetAppsByAppIdWorkflowsDraftVariablesByVariableIdPath = z.object({
/**
* Variable retrieved successfully
*/
export const zGetAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse = zWorkflowDraftVariable
export const zGetAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariableResponse
export const zPatchAppsByAppIdWorkflowsDraftVariablesByVariableIdBody
= zWorkflowDraftVariableUpdatePayload
@ -5616,7 +5430,8 @@ export const zPatchAppsByAppIdWorkflowsDraftVariablesByVariableIdPath = z.object
/**
* Variable updated successfully
*/
export const zPatchAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse = zWorkflowDraftVariable
export const zPatchAppsByAppIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariableResponse
export const zPutAppsByAppIdWorkflowsDraftVariablesByVariableIdResetPath = z.object({
app_id: z.uuid(),
@ -5624,7 +5439,7 @@ export const zPutAppsByAppIdWorkflowsDraftVariablesByVariableIdResetPath = z.obj
})
export const zPutAppsByAppIdWorkflowsDraftVariablesByVariableIdResetResponse = z.union([
zWorkflowDraftVariable,
zWorkflowDraftVariableResponse,
z.void(),
])
@ -5646,7 +5461,7 @@ export const zPostAppsByAppIdWorkflowsPublishPath = z.object({
/**
* Workflow published successfully
*/
export const zPostAppsByAppIdWorkflowsPublishResponse = zWorkflowPublishResponse
export const zPostAppsByAppIdWorkflowsPublishResponse = zPublishWorkflowResponse
export const zGetAppsByAppIdWorkflowsPublishedRunsByRunIdNodeOutputsPath = z.object({
app_id: z.uuid(),
@ -5739,7 +5554,7 @@ export const zPostAppsByAppIdWorkflowsByWorkflowIdRestorePath = z.object({
/**
* Workflow restored successfully
*/
export const zPostAppsByAppIdWorkflowsByWorkflowIdRestoreResponse = zWorkflowRestoreResponse
export const zPostAppsByAppIdWorkflowsByWorkflowIdRestoreResponse = zSyncDraftWorkflowResponse
export const zGetAppsByResourceIdApiKeysPath = z.object({
resource_id: z.uuid(),

View File

@ -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

View File

@ -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(),

View File

@ -24,11 +24,6 @@ import {
zGetRagPipelinesByPipelineIdWorkflowRunsPath,
zGetRagPipelinesByPipelineIdWorkflowRunsQuery,
zGetRagPipelinesByPipelineIdWorkflowRunsResponse,
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypePath,
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeQuery,
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse,
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsPath,
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponse,
zGetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesPath,
zGetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponse,
zGetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdLastRunPath,
@ -48,7 +43,6 @@ import {
zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdPath,
zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse,
zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesPath,
zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesQuery,
zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesResponse,
zGetRagPipelinesByPipelineIdWorkflowsPath,
zGetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersPath,
@ -93,35 +87,17 @@ import {
zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestorePath,
zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdRunBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdRunPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftResponse,
zPostRagPipelinesByPipelineIdWorkflowsDraftRunBody,
zPostRagPipelinesByPipelineIdWorkflowsDraftRunPath,
zPostRagPipelinesByPipelineIdWorkflowsDraftRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewBody,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewPath,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponse,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunBody,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunPath,
zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsPublishedRunBody,
zPostRagPipelinesByPipelineIdWorkflowsPublishedRunPath,
zPostRagPipelinesByPipelineIdWorkflowsPublishedRunResponse,
zPostRagPipelinesByPipelineIdWorkflowsPublishPath,
zPostRagPipelinesByPipelineIdWorkflowsPublishResponse,
zPostRagPipelinesImportsBody,
@ -506,87 +482,10 @@ export const workflowRuns = {
byRunId,
}
/**
* Get default block config
*/
export const get10 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
operationId: 'getRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockType',
path: '/rag/pipelines/{pipeline_id}/workflows/default-workflow-block-configs/{block_type}',
summary: 'Get default block config',
tags: ['console'],
})
.input(
z.object({
params: zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypePath,
query:
zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeQuery.optional(),
}),
)
.output(zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse)
export const byBlockType = {
get: get10,
}
/**
* Get default block config
*/
export const get11 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
operationId: 'getRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigs',
path: '/rag/pipelines/{pipeline_id}/workflows/default-workflow-block-configs',
summary: 'Get default block config',
tags: ['console'],
})
.input(z.object({ params: zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsPath }))
.output(zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponse)
export const defaultWorkflowBlockConfigs = {
get: get11,
byBlockType,
}
/**
* Run rag pipeline datasource
*/
export const post9 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRun',
path: '/rag/pipelines/{pipeline_id}/workflows/draft/datasource/nodes/{node_id}/run',
summary: 'Run rag pipeline datasource',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponse)
export const run = {
post: post9,
}
export const byNodeId = {
run,
}
export const nodes = {
byNodeId,
}
/**
* Set datasource variables
*/
export const post10 = oc
export const post9 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -604,18 +503,17 @@ export const post10 = oc
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectResponse)
export const variablesInspect = {
post: post10,
post: post9,
}
export const datasource = {
nodes,
variablesInspect,
}
/**
* Get draft workflow
*/
export const get12 = oc
export const get10 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -628,82 +526,10 @@ export const get12 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponse)
export const environmentVariables = {
get: get12,
get: get10,
}
/**
* Run draft workflow iteration node
*/
export const post11 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRun',
path: '/rag/pipelines/{pipeline_id}/workflows/draft/iteration/nodes/{node_id}/run',
summary: 'Run draft workflow iteration node',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponse)
export const run2 = {
post: post11,
}
export const byNodeId2 = {
run: run2,
}
export const nodes2 = {
byNodeId: byNodeId2,
}
export const iteration = {
nodes: nodes2,
}
/**
* Run draft workflow loop node
*/
export const post12 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRun',
path: '/rag/pipelines/{pipeline_id}/workflows/draft/loop/nodes/{node_id}/run',
summary: 'Run draft workflow loop node',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponse)
export const run3 = {
post: post12,
}
export const byNodeId3 = {
run: run3,
}
export const nodes3 = {
byNodeId: byNodeId3,
}
export const loop = {
nodes: nodes3,
}
export const get13 = oc
export const get11 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -715,13 +541,13 @@ export const get13 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdLastRunResponse)
export const lastRun = {
get: get13,
get: get11,
}
/**
* Run draft workflow node
*/
export const post13 = oc
export const post10 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -738,8 +564,8 @@ export const post13 = oc
)
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdRunResponse)
export const run4 = {
post: post13,
export const run = {
post: post10,
}
export const delete2 = oc
@ -756,7 +582,7 @@ export const delete2 = oc
)
.output(zDeleteRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesResponse)
export const get14 = oc
export const get12 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -769,23 +595,23 @@ export const get14 = oc
export const variables = {
delete: delete2,
get: get14,
get: get12,
}
export const byNodeId4 = {
export const byNodeId = {
lastRun,
run: run4,
run,
variables,
}
export const nodes4 = {
byNodeId: byNodeId4,
export const nodes = {
byNodeId,
}
/**
* Get first step parameters of rag pipeline
*/
export const get15 = oc
export const get13 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -803,7 +629,7 @@ export const get15 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersResponse)
export const parameters = {
get: get15,
get: get13,
}
export const preProcessing = {
@ -813,7 +639,7 @@ export const preProcessing = {
/**
* Get second step parameters of rag pipeline
*/
export const get16 = oc
export const get14 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -831,38 +657,14 @@ export const get16 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponse)
export const parameters2 = {
get: get16,
get: get14,
}
export const processing = {
parameters: parameters2,
}
/**
* Run draft workflow
*/
export const post14 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsDraftRun',
path: '/rag/pipelines/{pipeline_id}/workflows/draft/run',
summary: 'Run draft workflow',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsDraftRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsDraftRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftRunResponse)
export const run5 = {
post: post14,
}
export const get17 = oc
export const get15 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -874,7 +676,7 @@ export const get17 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesResponse)
export const systemVariables = {
get: get17,
get: get15,
}
export const put = oc
@ -908,7 +710,7 @@ export const delete3 = oc
)
.output(zDeleteRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse)
export const get18 = oc
export const get16 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -937,7 +739,7 @@ export const patch2 = oc
export const byVariableId = {
delete: delete3,
get: get18,
get: get16,
patch: patch2,
reset,
}
@ -957,7 +759,7 @@ export const delete4 = oc
/**
* Get draft workflow
*/
export const get19 = oc
export const get17 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -966,24 +768,19 @@ export const get19 = oc
summary: 'Get draft workflow',
tags: ['console'],
})
.input(
z.object({
params: zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesPath,
query: zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesQuery.optional(),
}),
)
.input(z.object({ params: zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesPath }))
.output(zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesResponse)
export const variables2 = {
delete: delete4,
get: get19,
get: get17,
byVariableId,
}
/**
* Get draft rag pipeline's workflow
*/
export const get20 = oc
export const get18 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -998,7 +795,7 @@ export const get20 = oc
/**
* Sync draft workflow
*/
export const post15 = oc
export const post11 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -1016,16 +813,13 @@ export const post15 = oc
.output(zPostRagPipelinesByPipelineIdWorkflowsDraftResponse)
export const draft = {
get: get20,
post: post15,
get: get18,
post: post11,
datasource,
environmentVariables,
iteration,
loop,
nodes: nodes4,
nodes,
preProcessing,
processing,
run: run5,
systemVariables,
variables: variables2,
}
@ -1033,7 +827,7 @@ export const draft = {
/**
* Get published pipeline
*/
export const get21 = oc
export const get19 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -1048,7 +842,7 @@ export const get21 = oc
/**
* Publish workflow
*/
export const post16 = oc
export const post12 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -1061,14 +855,14 @@ export const post16 = oc
.output(zPostRagPipelinesByPipelineIdWorkflowsPublishResponse)
export const publish2 = {
get: get21,
post: post16,
get: get19,
post: post12,
}
/**
* Run datasource content preview
*/
export const post17 = oc
export const post13 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -1086,50 +880,25 @@ export const post17 = oc
.output(zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponse)
export const preview = {
post: post17,
post: post13,
}
/**
* Run rag pipeline datasource
*/
export const post18 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRun',
path: '/rag/pipelines/{pipeline_id}/workflows/published/datasource/nodes/{node_id}/run',
summary: 'Run rag pipeline datasource',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponse)
export const run6 = {
post: post18,
}
export const byNodeId5 = {
export const byNodeId2 = {
preview,
run: run6,
}
export const nodes5 = {
byNodeId: byNodeId5,
export const nodes2 = {
byNodeId: byNodeId2,
}
export const datasource2 = {
nodes: nodes5,
nodes: nodes2,
}
/**
* Get first step parameters of rag pipeline
*/
export const get22 = oc
export const get20 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -1147,7 +916,7 @@ export const get22 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersResponse)
export const parameters3 = {
get: get22,
get: get20,
}
export const preProcessing2 = {
@ -1157,7 +926,7 @@ export const preProcessing2 = {
/**
* Get second step parameters of rag pipeline
*/
export const get23 = oc
export const get21 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -1175,45 +944,20 @@ export const get23 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponse)
export const parameters4 = {
get: get23,
get: get21,
}
export const processing2 = {
parameters: parameters4,
}
/**
* Run published workflow
*/
export const post19 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
operationId: 'postRagPipelinesByPipelineIdWorkflowsPublishedRun',
path: '/rag/pipelines/{pipeline_id}/workflows/published/run',
summary: 'Run published workflow',
tags: ['console'],
})
.input(
z.object({
body: zPostRagPipelinesByPipelineIdWorkflowsPublishedRunBody,
params: zPostRagPipelinesByPipelineIdWorkflowsPublishedRunPath,
}),
)
.output(zPostRagPipelinesByPipelineIdWorkflowsPublishedRunResponse)
export const run7 = {
post: post19,
}
export const published = {
datasource: datasource2,
preProcessing: preProcessing2,
processing: processing2,
run: run7,
}
export const post20 = oc
export const post14 = oc
.route({
inputStructure: 'detailed',
method: 'POST',
@ -1225,7 +969,7 @@ export const post20 = oc
.output(zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponse)
export const restore = {
post: post20,
post: post14,
}
/**
@ -1273,7 +1017,7 @@ export const byWorkflowId = {
/**
* Get published workflows
*/
export const get24 = oc
export const get22 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -1291,8 +1035,7 @@ export const get24 = oc
.output(zGetRagPipelinesByPipelineIdWorkflowsResponse)
export const workflows = {
get: get24,
defaultWorkflowBlockConfigs,
get: get22,
draft,
publish: publish2,
published,

View File

@ -89,7 +89,7 @@ export type PipelineTemplateDetailResponse = {
name: string
}
export type RagPipelineOpaqueResponse = unknown
export type DatasourcePluginListResponse = Array<PluginDatasourceProviderEntity>
export type RagPipelineImportPayload = {
description?: string | null
@ -107,6 +107,21 @@ export type RagPipelineImportCheckDependenciesResponse = {
leaked_dependencies?: Array<PluginDependency>
}
export type RagPipelineRecommendedPluginResponse = {
installed_recommended_plugins: Array<{
[key: string]: unknown
}>
uninstalled_recommended_plugins: Array<{
[key: string]: unknown
}>
}
export type RagPipelineTransformResponse = {
dataset_id: string
pipeline_id: string
status: string
}
export type WorkflowRunPaginationResponse = {
data: Array<WorkflowRunForListResponse>
has_more: boolean
@ -119,7 +134,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
@ -147,18 +162,10 @@ export type WorkflowPaginationResponse = {
page: number
}
export type DefaultBlockConfigsResponse = Array<{
[key: string]: unknown
}>
export type DefaultBlockConfigResponse = {
[key: string]: unknown
}
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 +180,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
}
@ -202,14 +209,6 @@ export type RagPipelineWorkflowSyncResponse = {
updated_at: number
}
export type DatasourceNodeRunPayload = {
credential_id?: string | null
datasource_type: string
inputs: {
[key: string]: unknown
}
}
export type DatasourceVariablesPayload = {
datasource_info: {
[key: string]: unknown
@ -221,7 +220,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
@ -244,14 +243,8 @@ export type WorkflowRunNodeExecutionResponse = {
title?: string | null
}
export type EnvironmentVariableListResponse = {
items: Array<EnvironmentVariableItemResponse>
}
export type NodeRunPayload = {
inputs?: {
[key: string]: unknown
} | null
export type RagPipelineEnvironmentVariableListResponse = {
items: Array<RagPipelineEnvironmentVariableResponse>
}
export type NodeRunRequiredPayload = {
@ -260,58 +253,36 @@ export type NodeRunRequiredPayload = {
}
}
export type WorkflowDraftVariableList = {
items?: Array<WorkflowDraftVariable>
export type WorkflowDraftVariableListResponse = {
items: Array<WorkflowDraftVariableResponse>
}
export type RagPipelineStepParametersResponse = {
export type RagPipelineVariablesResponse = {
variables: unknown
}
export type DraftWorkflowRunPayload = {
datasource_info_list: Array<{
[key: string]: unknown
}>
datasource_type: string
inputs: {
[key: string]: unknown
}
start_node_id: string
export type WorkflowDraftVariableListWithoutValueResponse = {
items: Array<WorkflowDraftVariableWithoutValueResponse>
total: number | null
}
export type WorkflowDraftVariableListWithoutValue = {
items?: Array<WorkflowDraftVariableWithoutValue>
total?: number
}
export type WorkflowDraftVariable = {
description?: string
edited?: boolean
full_content?: {
[key: string]: unknown
}
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value?:
| string
| number
| number
| boolean
| {
[key: string]: unknown
}
| Array<unknown>
| null
value_type?: string
visible?: boolean
export type WorkflowDraftVariableResponse = {
description: string
edited: boolean
full_content: WorkflowDraftVariableFullContentResponse | null
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value: unknown
value_type: string
visible: boolean
}
export type WorkflowDraftVariablePatchPayload = {
name?: string | null
value?: unknown | null
value?: unknown
}
export type RagPipelineWorkflowPublishResponse = {
@ -329,20 +300,6 @@ export type Parser = {
export type DataSourceContentPreviewResponse = unknown
export type PublishedWorkflowRunPayload = {
datasource_info_list: Array<{
[key: string]: unknown
}>
datasource_type: string
inputs: {
[key: string]: unknown
}
is_preview?: boolean
original_document_id?: string | null
response_mode?: 'blocking' | 'streaming'
start_node_id: string
}
export type WorkflowUpdatePayload = {
marked_comment?: string | null
marked_name?: string | null
@ -413,6 +370,14 @@ export type PipelineTemplateItemResponse = {
privacy_policy?: string | null
}
export type PluginDatasourceProviderEntity = {
declaration: DatasourceProviderEntityWithPlugin
is_authorized?: boolean
plugin_id: string
plugin_unique_identifier: string
provider: string
}
export type PluginDependency = {
current_identifier?: string | null
type: Type
@ -421,7 +386,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 +398,7 @@ export type WorkflowRunForListResponse = {
version?: string | null
}
export type SimpleAccount = {
export type SimpleAccountResponse = {
email: string
id: string
name: string
@ -479,8 +444,8 @@ export type PipelineVariableResponse = {
variable: string
}
export type EnvironmentVariableItemResponse = {
description?: string | null
export type RagPipelineEnvironmentVariableResponse = {
description: string
editable: boolean
edited: boolean
id: string
@ -492,16 +457,23 @@ export type EnvironmentVariableItemResponse = {
visible: boolean
}
export type WorkflowDraftVariableWithoutValue = {
description?: string
edited?: boolean
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value_type?: string
visible?: boolean
export type WorkflowDraftVariableWithoutValueResponse = {
description: string
edited: boolean
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value_type: string
visible: boolean
}
export type WorkflowDraftVariableFullContentResponse = {
download_url: string
length: number | null
size_bytes: number | null
value_type: string
}
export type DatasetRerankingModelResponse = {
@ -515,6 +487,14 @@ export type DatasetWeightedScoreResponse = {
weight_type?: string | null
}
export type DatasourceProviderEntityWithPlugin = {
credentials_schema?: Array<ProviderConfig>
datasources?: Array<DatasourceEntity>
identity: DatasourceProviderIdentity
oauth_schema?: OAuthSchema | null
provider_type: DatasourceProviderType
}
export type Type = 'github' | 'marketplace' | 'package'
export type Github = {
@ -544,6 +524,162 @@ export type DatasetVectorSettingResponse = {
vector_weight?: number | null
}
export type ProviderConfig = {
default?: number | string | number | boolean | null
help?: I18nObject | null
label?: I18nObject | null
multiple?: boolean
name: string
options?: Array<Option> | null
placeholder?: I18nObject | null
required?: boolean
scope?: AppSelectorScope | ModelSelectorScope | ToolSelectorScope | null
type: CoreEntitiesProviderEntitiesBasicProviderConfigType
url?: string | null
}
export type DatasourceEntity = {
description: I18nObject
identity: DatasourceIdentity
output_schema?: {
[key: string]: unknown
} | null
parameters?: Array<DatasourceParameter>
}
export type DatasourceProviderIdentity = {
author: string
description: I18nObject
icon: string
label: I18nObject
name: string
tags?: Array<ToolLabelEnum> | null
}
export type OAuthSchema = {
client_schema?: Array<ProviderConfig>
credentials_schema?: Array<ProviderConfig>
}
export type DatasourceProviderType
= | 'local_file'
| 'online_document'
| 'online_drive'
| 'website_crawl'
export type I18nObject = {
en_US: string
ja_JP?: string | null
pt_BR?: string | null
zh_Hans?: string | null
}
export type Option = {
label: I18nObject
value: string
}
export type AppSelectorScope = 'all' | 'chat' | 'completion' | 'workflow'
export type ModelSelectorScope
= | 'llm'
| 'moderation'
| 'rerank'
| 'speech2text'
| 'text-embedding'
| 'tts'
| 'vision'
export type ToolSelectorScope = 'all' | 'builtin' | 'custom' | 'workflow'
export type CoreEntitiesProviderEntitiesBasicProviderConfigType
= | 'app-selector'
| 'array[tools]'
| 'boolean'
| 'model-selector'
| 'secret-input'
| 'select'
| 'text-input'
export type DatasourceIdentity = {
author: string
icon?: string | null
label: I18nObject
name: string
provider: string
}
export type DatasourceParameter = {
auto_generate?: PluginParameterAutoGenerate | null
default?:
| number
| number
| string
| boolean
| Array<unknown>
| {
[key: string]: unknown
}
| null
description: I18nObject
label: I18nObject
max?: number | number | null
min?: number | number | null
name: string
options?: Array<PluginParameterOption>
placeholder?: I18nObject | null
precision?: number | null
required?: boolean
scope?: string | null
template?: PluginParameterTemplate | null
type: DatasourceParameterType
}
export type ToolLabelEnum
= | 'business'
| 'design'
| 'education'
| 'entertainment'
| 'finance'
| 'image'
| 'medical'
| 'news'
| 'other'
| 'productivity'
| 'rag'
| 'search'
| 'social'
| 'travel'
| 'utilities'
| 'videos'
| 'weather'
export type PluginParameterAutoGenerate = {
type: CorePluginEntitiesParametersPluginParameterAutoGenerateType
}
export type PluginParameterOption = {
icon?: string | null
label: I18nObject
value: string
}
export type PluginParameterTemplate = {
enabled?: boolean
}
export type DatasourceParameterType
= | 'boolean'
| 'file'
| 'files'
| 'number'
| 'secret-input'
| 'select'
| 'string'
| 'system-files'
export type CorePluginEntitiesParametersPluginParameterAutoGenerateType = 'prompt_instruction'
export type DeleteRagPipelineCustomizedTemplatesByTemplateIdData = {
body?: never
path: {
@ -663,7 +799,7 @@ export type GetRagPipelinesDatasourcePluginsData = {
}
export type GetRagPipelinesDatasourcePluginsResponses = {
200: RagPipelineOpaqueResponse
200: DatasourcePluginListResponse
}
export type GetRagPipelinesDatasourcePluginsResponse
@ -740,7 +876,7 @@ export type GetRagPipelinesRecommendedPluginsData = {
}
export type GetRagPipelinesRecommendedPluginsResponses = {
200: RagPipelineOpaqueResponse
200: RagPipelineRecommendedPluginResponse
}
export type GetRagPipelinesRecommendedPluginsResponse
@ -756,7 +892,7 @@ export type PostRagPipelinesTransformDatasetsByDatasetIdData = {
}
export type PostRagPipelinesTransformDatasetsByDatasetIdResponses = {
200: RagPipelineOpaqueResponse
200: RagPipelineTransformResponse
}
export type PostRagPipelinesTransformDatasetsByDatasetIdResponse
@ -891,41 +1027,6 @@ export type GetRagPipelinesByPipelineIdWorkflowsResponses = {
export type GetRagPipelinesByPipelineIdWorkflowsResponse
= GetRagPipelinesByPipelineIdWorkflowsResponses[keyof GetRagPipelinesByPipelineIdWorkflowsResponses]
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsData = {
body?: never
path: {
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/default-workflow-block-configs'
}
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponses = {
200: DefaultBlockConfigsResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponse
= GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponses[keyof GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponses]
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeData = {
body?: never
path: {
block_type: string
pipeline_id: string
}
query?: {
q?: string
}
url: '/rag/pipelines/{pipeline_id}/workflows/default-workflow-block-configs/{block_type}'
}
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses = {
200: DefaultBlockConfigResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse
= GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses[keyof GetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponses]
export type GetRagPipelinesByPipelineIdWorkflowsDraftData = {
body?: never
path: {
@ -962,23 +1063,6 @@ export type PostRagPipelinesByPipelineIdWorkflowsDraftResponses = {
export type PostRagPipelinesByPipelineIdWorkflowsDraftResponse
= PostRagPipelinesByPipelineIdWorkflowsDraftResponses[keyof PostRagPipelinesByPipelineIdWorkflowsDraftResponses]
export type PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunData = {
body: DatasourceNodeRunPayload
path: {
node_id: string
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/draft/datasource/nodes/{node_id}/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponse
= PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponses]
export type PostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectData = {
body: DatasourceVariablesPayload
path: {
@ -1005,46 +1089,12 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesData =
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponses = {
200: EnvironmentVariableListResponse
200: RagPipelineEnvironmentVariableListResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponse
= GetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponses[keyof GetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponses]
export type PostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunData = {
body: NodeRunPayload
path: {
node_id: string
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/draft/iteration/nodes/{node_id}/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponse
= PostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponses]
export type PostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunData = {
body: NodeRunPayload
path: {
node_id: string
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/draft/loop/nodes/{node_id}/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponse
= PostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponses]
export type GetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdLastRunData = {
body?: never
path: {
@ -1107,7 +1157,7 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesData
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesResponse
@ -1125,7 +1175,7 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersData
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersResponses = {
200: RagPipelineStepParametersResponse
200: RagPipelineVariablesResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersResponse
@ -1143,28 +1193,12 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersData =
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponses = {
200: RagPipelineStepParametersResponse
200: RagPipelineVariablesResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponse
= GetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponses[keyof GetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponses]
export type PostRagPipelinesByPipelineIdWorkflowsDraftRunData = {
body: DraftWorkflowRunPayload
path: {
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/draft/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsDraftRunResponse
= PostRagPipelinesByPipelineIdWorkflowsDraftRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsDraftRunResponses]
export type GetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesData = {
body?: never
path: {
@ -1175,7 +1209,7 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesData = {
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesResponse
@ -1202,15 +1236,12 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesData = {
path: {
pipeline_id: string
}
query?: {
limit?: number
page?: number
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/draft/variables'
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesResponses = {
200: WorkflowDraftVariableListWithoutValue
200: WorkflowDraftVariableListWithoutValueResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesResponse
@ -1244,7 +1275,7 @@ export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdData =
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse
@ -1261,7 +1292,7 @@ export type PatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdData
}
export type PatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type PatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse
@ -1278,7 +1309,7 @@ export type PutRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResetD
}
export type PutRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResetResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
204: void
}
@ -1335,23 +1366,6 @@ export type PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeI
export type PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponse
= PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponses[keyof PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponses]
export type PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunData = {
body: DatasourceNodeRunPayload
path: {
node_id: string
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/published/datasource/nodes/{node_id}/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponse
= PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponses]
export type GetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersData = {
body?: never
path: {
@ -1364,7 +1378,7 @@ export type GetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParameters
}
export type GetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersResponses = {
200: RagPipelineStepParametersResponse
200: RagPipelineVariablesResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersResponse
@ -1382,28 +1396,12 @@ export type GetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersDat
}
export type GetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponses = {
200: RagPipelineStepParametersResponse
200: RagPipelineVariablesResponse
}
export type GetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponse
= GetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponses[keyof GetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponses]
export type PostRagPipelinesByPipelineIdWorkflowsPublishedRunData = {
body: PublishedWorkflowRunPayload
path: {
pipeline_id: string
}
query?: never
url: '/rag/pipelines/{pipeline_id}/workflows/published/run'
}
export type PostRagPipelinesByPipelineIdWorkflowsPublishedRunResponses = {
200: RagPipelineOpaqueResponse
}
export type PostRagPipelinesByPipelineIdWorkflowsPublishedRunResponse
= PostRagPipelinesByPipelineIdWorkflowsPublishedRunResponses[keyof PostRagPipelinesByPipelineIdWorkflowsPublishedRunResponses]
export type DeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdData = {
body?: never
path: {

View File

@ -39,11 +39,6 @@ export const zPipelineTemplateDetailResponse = z.object({
name: z.string(),
})
/**
* RagPipelineOpaqueResponse
*/
export const zRagPipelineOpaqueResponse = z.unknown()
/**
* RagPipelineImportPayload
*/
@ -59,6 +54,23 @@ export const zRagPipelineImportPayload = z.object({
yaml_url: z.string().nullish(),
})
/**
* RagPipelineRecommendedPluginResponse
*/
export const zRagPipelineRecommendedPluginResponse = z.object({
installed_recommended_plugins: z.array(z.record(z.string(), z.unknown())),
uninstalled_recommended_plugins: z.array(z.record(z.string(), z.unknown())),
})
/**
* RagPipelineTransformResponse
*/
export const zRagPipelineTransformResponse = z.object({
dataset_id: z.string(),
pipeline_id: z.string(),
status: z.string(),
})
/**
* SimpleResultResponse
*/
@ -66,16 +78,6 @@ export const zSimpleResultResponse = z.object({
result: z.string(),
})
/**
* DefaultBlockConfigsResponse
*/
export const zDefaultBlockConfigsResponse = z.array(z.record(z.string(), z.unknown()))
/**
* DefaultBlockConfigResponse
*/
export const zDefaultBlockConfigResponse = z.record(z.string(), z.unknown())
/**
* DraftWorkflowSyncPayload
*/
@ -97,15 +99,6 @@ export const zRagPipelineWorkflowSyncResponse = z.object({
updated_at: z.int(),
})
/**
* DatasourceNodeRunPayload
*/
export const zDatasourceNodeRunPayload = z.object({
credential_id: z.string().nullish(),
datasource_type: z.string(),
inputs: z.record(z.string(), z.unknown()),
})
/**
* DatasourceVariablesPayload
*/
@ -116,13 +109,6 @@ export const zDatasourceVariablesPayload = z.object({
start_node_title: z.string(),
})
/**
* NodeRunPayload
*/
export const zNodeRunPayload = z.object({
inputs: z.record(z.string(), z.unknown()).nullish(),
})
/**
* NodeRunRequiredPayload
*/
@ -131,55 +117,18 @@ export const zNodeRunRequiredPayload = z.object({
})
/**
* RagPipelineStepParametersResponse
* RagPipelineVariablesResponse
*/
export const zRagPipelineStepParametersResponse = z.object({
export const zRagPipelineVariablesResponse = z.object({
variables: z.unknown(),
})
/**
* DraftWorkflowRunPayload
*/
export const zDraftWorkflowRunPayload = z.object({
datasource_info_list: z.array(z.record(z.string(), z.unknown())),
datasource_type: z.string(),
inputs: z.record(z.string(), z.unknown()),
start_node_id: z.string(),
})
export const zWorkflowDraftVariable = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
full_content: z.record(z.string(), z.unknown()).optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value: z
.union([
z.string(),
z.int(),
z.number(),
z.boolean(),
z.record(z.string(), z.unknown()),
z.array(z.unknown()),
])
.nullish(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
})
export const zWorkflowDraftVariableList = z.object({
items: z.array(zWorkflowDraftVariable).optional(),
})
/**
* WorkflowDraftVariablePatchPayload
*/
export const zWorkflowDraftVariablePatchPayload = z.object({
name: z.string().nullish(),
value: z.unknown().nullish(),
value: z.unknown().optional(),
})
/**
@ -204,19 +153,6 @@ export const zParser = z.object({
*/
export const zDataSourceContentPreviewResponse = z.unknown()
/**
* PublishedWorkflowRunPayload
*/
export const zPublishedWorkflowRunPayload = z.object({
datasource_info_list: z.array(z.record(z.string(), z.unknown())),
datasource_type: z.string(),
inputs: z.record(z.string(), z.unknown()),
is_preview: z.boolean().optional().default(false),
original_document_id: z.string().nullish(),
response_mode: z.enum(['blocking', 'streaming']).optional().default('streaming'),
start_node_id: z.string(),
})
/**
* WorkflowUpdatePayload
*/
@ -322,9 +258,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 +271,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 +307,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 +329,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 +407,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 +418,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(),
})
@ -497,10 +433,10 @@ export const zWorkflowPaginationResponse = z.object({
})
/**
* EnvironmentVariableItemResponse
* RagPipelineEnvironmentVariableResponse
*/
export const zEnvironmentVariableItemResponse = z.object({
description: z.string().nullish(),
export const zRagPipelineEnvironmentVariableResponse = z.object({
description: z.string(),
editable: z.boolean(),
edited: z.boolean(),
id: z.string(),
@ -513,27 +449,67 @@ export const zEnvironmentVariableItemResponse = z.object({
})
/**
* EnvironmentVariableListResponse
* RagPipelineEnvironmentVariableListResponse
*/
export const zEnvironmentVariableListResponse = z.object({
items: z.array(zEnvironmentVariableItemResponse),
export const zRagPipelineEnvironmentVariableListResponse = z.object({
items: z.array(zRagPipelineEnvironmentVariableResponse),
})
export const zWorkflowDraftVariableWithoutValue = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
/**
* WorkflowDraftVariableWithoutValueResponse
*/
export const zWorkflowDraftVariableWithoutValueResponse = z.object({
description: z.string(),
edited: z.boolean(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value_type: z.string(),
visible: z.boolean(),
})
export const zWorkflowDraftVariableListWithoutValue = z.object({
items: z.array(zWorkflowDraftVariableWithoutValue).optional(),
total: z.int().optional(),
/**
* WorkflowDraftVariableListWithoutValueResponse
*/
export const zWorkflowDraftVariableListWithoutValueResponse = z.object({
items: z.array(zWorkflowDraftVariableWithoutValueResponse),
total: z.int().nullable(),
})
/**
* WorkflowDraftVariableFullContentResponse
*/
export const zWorkflowDraftVariableFullContentResponse = z.object({
download_url: z.string(),
length: z.int().nullable(),
size_bytes: z.int().nullable(),
value_type: z.string(),
})
/**
* WorkflowDraftVariableResponse
*/
export const zWorkflowDraftVariableResponse = z.object({
description: z.string(),
edited: z.boolean(),
full_content: zWorkflowDraftVariableFullContentResponse.nullable(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value: z.unknown(),
value_type: z.string(),
visible: z.boolean(),
})
/**
* WorkflowDraftVariableListResponse
*/
export const zWorkflowDraftVariableListResponse = z.object({
items: z.array(zWorkflowDraftVariableResponse),
})
/**
@ -673,6 +649,263 @@ export const zDatasetDetailResponse = z.object({
word_count: z.int(),
})
/**
* DatasourceProviderType
*
* Enum class for datasource provider
*/
export const zDatasourceProviderType = z.enum([
'local_file',
'online_document',
'online_drive',
'website_crawl',
])
/**
* I18nObject
*
* Model class for i18n object.
*/
export const zI18nObject = z.object({
en_US: z.string(),
ja_JP: z.string().nullish(),
pt_BR: z.string().nullish(),
zh_Hans: z.string().nullish(),
})
/**
* Option
*/
export const zOption = z.object({
label: zI18nObject,
value: z.string(),
})
/**
* AppSelectorScope
*/
export const zAppSelectorScope = z.enum(['all', 'chat', 'completion', 'workflow'])
/**
* ModelSelectorScope
*/
export const zModelSelectorScope = z.enum([
'llm',
'moderation',
'rerank',
'speech2text',
'text-embedding',
'tts',
'vision',
])
/**
* ToolSelectorScope
*/
export const zToolSelectorScope = z.enum(['all', 'builtin', 'custom', 'workflow'])
/**
* Type
*/
export const zCoreEntitiesProviderEntitiesBasicProviderConfigType = z.enum([
'app-selector',
'array[tools]',
'boolean',
'model-selector',
'secret-input',
'select',
'text-input',
])
/**
* ProviderConfig
*
* Model class for common provider settings like credentials
*/
export const zProviderConfig = z.object({
default: z.union([z.int(), z.string(), z.number(), z.boolean()]).nullish(),
help: zI18nObject.nullish(),
label: zI18nObject.nullish(),
multiple: z.boolean().optional().default(false),
name: z.string(),
options: z.array(zOption).nullish(),
placeholder: zI18nObject.nullish(),
required: z.boolean().optional().default(false),
scope: z.union([zAppSelectorScope, zModelSelectorScope, zToolSelectorScope]).nullish(),
type: zCoreEntitiesProviderEntitiesBasicProviderConfigType,
url: z.string().nullish(),
})
/**
* OAuthSchema
*
* OAuth schema
*/
export const zOAuthSchema = z.object({
client_schema: z.array(zProviderConfig).optional(),
credentials_schema: z.array(zProviderConfig).optional(),
})
/**
* DatasourceIdentity
*/
export const zDatasourceIdentity = z.object({
author: z.string(),
icon: z.string().nullish(),
label: zI18nObject,
name: z.string(),
provider: z.string(),
})
/**
* ToolLabelEnum
*/
export const zToolLabelEnum = z.enum([
'business',
'design',
'education',
'entertainment',
'finance',
'image',
'medical',
'news',
'other',
'productivity',
'rag',
'search',
'social',
'travel',
'utilities',
'videos',
'weather',
])
/**
* DatasourceProviderIdentity
*/
export const zDatasourceProviderIdentity = z.object({
author: z.string(),
description: zI18nObject,
icon: z.string(),
label: zI18nObject,
name: z.string(),
tags: z.array(zToolLabelEnum).nullish().default([]),
})
/**
* PluginParameterOption
*/
export const zPluginParameterOption = z.object({
icon: z.string().nullish(),
label: zI18nObject,
value: z.string(),
})
/**
* PluginParameterTemplate
*/
export const zPluginParameterTemplate = z.object({
enabled: z.boolean().optional().default(false),
})
/**
* DatasourceParameterType
*
* removes TOOLS_SELECTOR from PluginParameterType
*/
export const zDatasourceParameterType = z.enum([
'boolean',
'file',
'files',
'number',
'secret-input',
'select',
'string',
'system-files',
])
/**
* Type
*/
export const zCorePluginEntitiesParametersPluginParameterAutoGenerateType = z.enum([
'prompt_instruction',
])
/**
* PluginParameterAutoGenerate
*/
export const zPluginParameterAutoGenerate = z.object({
type: zCorePluginEntitiesParametersPluginParameterAutoGenerateType,
})
/**
* DatasourceParameter
*
* Overrides type
*/
export const zDatasourceParameter = z.object({
auto_generate: zPluginParameterAutoGenerate.nullish(),
default: z
.union([
z.number(),
z.int(),
z.string(),
z.boolean(),
z.array(z.unknown()),
z.record(z.string(), z.unknown()),
])
.nullish(),
description: zI18nObject,
label: zI18nObject,
max: z.union([z.number(), z.int()]).nullish(),
min: z.union([z.number(), z.int()]).nullish(),
name: z.string(),
options: z.array(zPluginParameterOption).optional(),
placeholder: zI18nObject.nullish(),
precision: z.int().nullish(),
required: z.boolean().optional().default(false),
scope: z.string().nullish(),
template: zPluginParameterTemplate.nullish(),
type: zDatasourceParameterType,
})
/**
* DatasourceEntity
*/
export const zDatasourceEntity = z.object({
description: zI18nObject,
identity: zDatasourceIdentity,
output_schema: z.record(z.string(), z.unknown()).nullish(),
parameters: z.array(zDatasourceParameter).optional(),
})
/**
* DatasourceProviderEntityWithPlugin
*/
export const zDatasourceProviderEntityWithPlugin = z.object({
credentials_schema: z.array(zProviderConfig).optional(),
datasources: z.array(zDatasourceEntity).optional(),
identity: zDatasourceProviderIdentity,
oauth_schema: zOAuthSchema.nullish(),
provider_type: zDatasourceProviderType,
})
/**
* PluginDatasourceProviderEntity
*/
export const zPluginDatasourceProviderEntity = z.object({
declaration: zDatasourceProviderEntityWithPlugin,
is_authorized: z.boolean().optional().default(false),
plugin_id: z.string(),
plugin_unique_identifier: z.string(),
provider: z.string(),
})
/**
* DatasourcePluginListResponse
*/
export const zDatasourcePluginListResponse = z.array(zPluginDatasourceProviderEntity)
export const zDeleteRagPipelineCustomizedTemplatesByTemplateIdPath = z.object({
template_id: z.string(),
})
@ -739,9 +972,9 @@ export const zGetRagPipelineTemplatesByTemplateIdQuery = z.object({
export const zGetRagPipelineTemplatesByTemplateIdResponse = zPipelineTemplateDetailResponse
/**
* Success
* Datasource plugins retrieved successfully
*/
export const zGetRagPipelinesDatasourcePluginsResponse = zRagPipelineOpaqueResponse
export const zGetRagPipelinesDatasourcePluginsResponse = zDatasourcePluginListResponse
export const zPostRagPipelinesImportsBody = zRagPipelineImportPayload
@ -774,18 +1007,18 @@ export const zGetRagPipelinesRecommendedPluginsQuery = z.object({
})
/**
* Success
* Recommended plugins retrieved successfully
*/
export const zGetRagPipelinesRecommendedPluginsResponse = zRagPipelineOpaqueResponse
export const zGetRagPipelinesRecommendedPluginsResponse = zRagPipelineRecommendedPluginResponse
export const zPostRagPipelinesTransformDatasetsByDatasetIdPath = z.object({
dataset_id: z.uuid(),
})
/**
* Success
* Dataset transformed successfully
*/
export const zPostRagPipelinesTransformDatasetsByDatasetIdResponse = zRagPipelineOpaqueResponse
export const zPostRagPipelinesTransformDatasetsByDatasetIdResponse = zRagPipelineTransformResponse
export const zPostRagPipelinesByPipelineIdCustomizedPublishBody = zCustomizedPipelineTemplatePayload
@ -873,33 +1106,6 @@ export const zGetRagPipelinesByPipelineIdWorkflowsQuery = z.object({
*/
export const zGetRagPipelinesByPipelineIdWorkflowsResponse = zWorkflowPaginationResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsPath = z.object({
pipeline_id: z.uuid(),
})
/**
* Default block configs retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsResponse
= zDefaultBlockConfigsResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypePath
= z.object({
block_type: z.string(),
pipeline_id: z.uuid(),
})
export const zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeQuery
= z.object({
q: z.string().optional(),
})
/**
* Default block config retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeResponse
= zDefaultBlockConfigResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDraftPath = z.object({
pipeline_id: z.uuid(),
})
@ -920,20 +1126,6 @@ export const zPostRagPipelinesByPipelineIdWorkflowsDraftPath = z.object({
*/
export const zPostRagPipelinesByPipelineIdWorkflowsDraftResponse = zRagPipelineWorkflowSyncResponse
export const zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunBody
= zDatasourceNodeRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunPath = z.object({
node_id: z.string(),
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunResponse
= zRagPipelineOpaqueResponse
export const zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceVariablesInspectBody
= zDatasourceVariablesPayload
@ -955,34 +1147,7 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesPath
* Environment variables retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftEnvironmentVariablesResponse
= zEnvironmentVariableListResponse
export const zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunBody
= zNodeRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunPath = z.object({
node_id: z.string(),
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsDraftIterationNodesByNodeIdRunResponse
= zRagPipelineOpaqueResponse
export const zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunBody = zNodeRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunPath = z.object({
node_id: z.string(),
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsDraftLoopNodesByNodeIdRunResponse
= zRagPipelineOpaqueResponse
= zRagPipelineEnvironmentVariableListResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdLastRunPath = z.object({
node_id: z.string(),
@ -1028,7 +1193,7 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesPat
* Node variables retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftNodesByNodeIdVariablesResponse
= zWorkflowDraftVariableList
= zWorkflowDraftVariableListResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersPath = z.object({
pipeline_id: z.uuid(),
@ -1039,10 +1204,10 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersQu
})
/**
* Success
* First step parameters retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftPreProcessingParametersResponse
= zRagPipelineStepParametersResponse
= zRagPipelineVariablesResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersPath = z.object({
pipeline_id: z.uuid(),
@ -1053,21 +1218,10 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersQuery
})
/**
* Success
* Second step parameters retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftProcessingParametersResponse
= zRagPipelineStepParametersResponse
export const zPostRagPipelinesByPipelineIdWorkflowsDraftRunBody = zDraftWorkflowRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsDraftRunPath = z.object({
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsDraftRunResponse = zRagPipelineOpaqueResponse
= zRagPipelineVariablesResponse
export const zGetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesPath = z.object({
pipeline_id: z.uuid(),
@ -1077,14 +1231,14 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesPath = z.o
* System variables retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftSystemVariablesResponse
= zWorkflowDraftVariableList
= zWorkflowDraftVariableListResponse
export const zDeleteRagPipelinesByPipelineIdWorkflowsDraftVariablesPath = z.object({
pipeline_id: z.uuid(),
})
/**
* Workflow variables deleted successfully
* Variables deleted successfully
*/
export const zDeleteRagPipelinesByPipelineIdWorkflowsDraftVariablesResponse = z.void()
@ -1092,16 +1246,11 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesPath = z.object(
pipeline_id: z.uuid(),
})
export const zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesQuery = z.object({
limit: z.int().gte(1).lte(100).optional().default(20),
page: z.int().gte(1).lte(100000).optional().default(1),
})
/**
* Workflow variables retrieved successfully
* Variables retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesResponse
= zWorkflowDraftVariableListWithoutValue
= zWorkflowDraftVariableListWithoutValueResponse
export const zDeleteRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdPath = z.object({
pipeline_id: z.uuid(),
@ -1122,7 +1271,7 @@ export const zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdPath
* Variable retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariable
= zWorkflowDraftVariableResponse
export const zPatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdBody
= zWorkflowDraftVariablePatchPayload
@ -1136,7 +1285,7 @@ export const zPatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdPa
* Variable updated successfully
*/
export const zPatchRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariable
= zWorkflowDraftVariableResponse
export const zPutRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResetPath = z.object({
pipeline_id: z.uuid(),
@ -1144,7 +1293,7 @@ export const zPutRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdRese
})
export const zPutRagPipelinesByPipelineIdWorkflowsDraftVariablesByVariableIdResetResponse = z.union(
[zWorkflowDraftVariable, z.void()],
[zWorkflowDraftVariableResponse, z.void()],
)
export const zGetRagPipelinesByPipelineIdWorkflowsPublishPath = z.object({
@ -1181,21 +1330,6 @@ export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNod
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewResponse
= zDataSourceContentPreviewResponse
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunBody
= zDatasourceNodeRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunPath
= z.object({
node_id: z.string(),
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdRunResponse
= zRagPipelineOpaqueResponse
export const zGetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersPath = z.object({
pipeline_id: z.uuid(),
})
@ -1205,10 +1339,10 @@ export const zGetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParamete
})
/**
* Success
* First step parameters retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsPublishedPreProcessingParametersResponse
= zRagPipelineStepParametersResponse
= zRagPipelineVariablesResponse
export const zGetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersPath = z.object({
pipeline_id: z.uuid(),
@ -1219,21 +1353,10 @@ export const zGetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersQ
})
/**
* Success
* Second step parameters retrieved successfully
*/
export const zGetRagPipelinesByPipelineIdWorkflowsPublishedProcessingParametersResponse
= zRagPipelineStepParametersResponse
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedRunBody = zPublishedWorkflowRunPayload
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedRunPath = z.object({
pipeline_id: z.uuid(),
})
/**
* Success
*/
export const zPostRagPipelinesByPipelineIdWorkflowsPublishedRunResponse = zRagPipelineOpaqueResponse
= zRagPipelineVariablesResponse
export const zDeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdPath = z.object({
pipeline_id: z.uuid(),

View File

@ -17,8 +17,6 @@ import {
zGetSnippetsBySnippetIdWorkflowRunsPath,
zGetSnippetsBySnippetIdWorkflowRunsQuery,
zGetSnippetsBySnippetIdWorkflowRunsResponse,
zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsPath,
zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponse,
zGetSnippetsBySnippetIdWorkflowsDraftConfigPath,
zGetSnippetsBySnippetIdWorkflowsDraftConfigResponse,
zGetSnippetsBySnippetIdWorkflowsDraftConversationVariablesPath,
@ -65,7 +63,6 @@ import {
zPostSnippetsBySnippetIdWorkflowsDraftRunBody,
zPostSnippetsBySnippetIdWorkflowsDraftRunPath,
zPostSnippetsBySnippetIdWorkflowsDraftRunResponse,
zPostSnippetsBySnippetIdWorkflowsPublishBody,
zPostSnippetsBySnippetIdWorkflowsPublishPath,
zPostSnippetsBySnippetIdWorkflowsPublishResponse,
zPutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetPath,
@ -169,29 +166,10 @@ export const workflowRuns = {
byRunId,
}
/**
* Get default block configurations for snippet workflow
*/
export const get4 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
operationId: 'getSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigs',
path: '/snippets/{snippet_id}/workflows/default-workflow-block-configs',
summary: 'Get default block configurations for snippet workflow',
tags: ['console'],
})
.input(z.object({ params: zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsPath }))
.output(zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponse)
export const defaultWorkflowBlockConfigs = {
get: get4,
}
/**
* Get snippet draft workflow configuration limits
*/
export const get5 = oc
export const get4 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -204,13 +182,13 @@ export const get5 = oc
.output(zGetSnippetsBySnippetIdWorkflowsDraftConfigResponse)
export const config = {
get: get5,
get: get4,
}
/**
* Conversation variables are not used in snippet workflows; returns an empty list for API parity
*/
export const get6 = oc
export const get5 = oc
.route({
description:
'Conversation variables are not used in snippet workflows; returns an empty list for API parity',
@ -224,13 +202,13 @@ export const get6 = oc
.output(zGetSnippetsBySnippetIdWorkflowsDraftConversationVariablesResponse)
export const conversationVariables = {
get: get6,
get: get5,
}
/**
* Get environment variables from snippet draft workflow graph
*/
export const get7 = oc
export const get6 = oc
.route({
description: 'Get environment variables from snippet draft workflow graph',
inputStructure: 'detailed',
@ -243,7 +221,7 @@ export const get7 = oc
.output(zGetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesResponse)
export const environmentVariables = {
get: get7,
get: get6,
}
/**
@ -337,7 +315,7 @@ export const loop = {
* Returns the most recent execution record for the given node,
* including status, inputs, outputs, and timing information.
*/
export const get8 = oc
export const get7 = oc
.route({
description:
'Get last run result for a node in snippet draft workflow\nReturns the most recent execution record for the given node,\nincluding status, inputs, outputs, and timing information.',
@ -352,7 +330,7 @@ export const get8 = oc
.output(zGetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdLastRunResponse)
export const lastRun = {
get: get8,
get: get7,
}
/**
@ -404,7 +382,7 @@ export const delete_ = oc
/**
* Get variables for a specific node (snippet draft workflow)
*/
export const get9 = oc
export const get8 = oc
.route({
description: 'Get variables for a specific node (snippet draft workflow)',
inputStructure: 'detailed',
@ -418,7 +396,7 @@ export const get9 = oc
export const variables = {
delete: delete_,
get: get9,
get: get8,
}
export const byNodeId3 = {
@ -463,7 +441,7 @@ export const run4 = {
/**
* System variables are not used in snippet workflows; returns an empty list for API parity
*/
export const get10 = oc
export const get9 = oc
.route({
description:
'System variables are not used in snippet workflows; returns an empty list for API parity',
@ -477,7 +455,7 @@ export const get10 = oc
.output(zGetSnippetsBySnippetIdWorkflowsDraftSystemVariablesResponse)
export const systemVariables = {
get: get10,
get: get9,
}
/**
@ -518,7 +496,7 @@ export const delete2 = oc
/**
* Get a specific draft workflow variable (snippet scope)
*/
export const get11 = oc
export const get10 = oc
.route({
description: 'Get a specific draft workflow variable (snippet scope)',
inputStructure: 'detailed',
@ -552,7 +530,7 @@ export const patch = oc
export const byVariableId = {
delete: delete2,
get: get11,
get: get10,
patch,
reset,
}
@ -576,7 +554,7 @@ export const delete3 = oc
/**
* List draft workflow variables without values (paginated, snippet scope)
*/
export const get12 = oc
export const get11 = oc
.route({
description: 'List draft workflow variables without values (paginated, snippet scope)',
inputStructure: 'detailed',
@ -595,14 +573,14 @@ export const get12 = oc
export const variables2 = {
delete: delete3,
get: get12,
get: get11,
byVariableId,
}
/**
* Get draft workflow for snippet
*/
export const get13 = oc
export const get12 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -635,7 +613,7 @@ export const post6 = oc
.output(zPostSnippetsBySnippetIdWorkflowsDraftResponse)
export const draft = {
get: get13,
get: get12,
post: post6,
config,
conversationVariables,
@ -651,7 +629,7 @@ export const draft = {
/**
* Get published workflow for snippet
*/
export const get14 = oc
export const get13 = oc
.route({
inputStructure: 'detailed',
method: 'GET',
@ -675,16 +653,11 @@ export const post7 = oc
summary: 'Publish snippet workflow',
tags: ['console'],
})
.input(
z.object({
body: zPostSnippetsBySnippetIdWorkflowsPublishBody,
params: zPostSnippetsBySnippetIdWorkflowsPublishPath,
}),
)
.input(z.object({ params: zPostSnippetsBySnippetIdWorkflowsPublishPath }))
.output(zPostSnippetsBySnippetIdWorkflowsPublishResponse)
export const publish = {
get: get14,
get: get13,
post: post7,
}
@ -719,7 +692,7 @@ export const byWorkflowId = {
*
* Get all published workflows for a snippet
*/
export const get15 = oc
export const get14 = oc
.route({
description: 'Get all published workflows for a snippet',
inputStructure: 'detailed',
@ -738,8 +711,7 @@ export const get15 = oc
.output(zGetSnippetsBySnippetIdWorkflowsResponse)
export const workflows = {
get: get15,
defaultWorkflowBlockConfigs,
get: get14,
draft,
publish,
byWorkflowId,

View File

@ -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
@ -44,14 +44,10 @@ export type SnippetWorkflowPaginationResponse = {
page: number
}
export type DefaultBlockConfigsResponse = Array<{
[key: string]: unknown
}>
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 +65,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
}
@ -86,7 +82,7 @@ export type SnippetDraftSyncPayload = {
}> | null
}
export type WorkflowRestoreResponse = {
export type SyncDraftWorkflowResponse = {
hash: string
result: string
updated_at: number
@ -96,12 +92,12 @@ export type SnippetDraftConfigResponse = {
parallel_depth_limit: number
}
export type WorkflowDraftVariableList = {
items?: Array<WorkflowDraftVariable>
export type WorkflowDraftVariableListResponse = {
items: Array<WorkflowDraftVariableResponse>
}
export type EnvironmentVariableListResponse = {
items: Array<EnvironmentVariableItemResponse>
export type WorkflowDraftEnvironmentVariableListResponse = {
items: Array<WorkflowDraftEnvironmentVariableResponse>
}
export type SnippetIterationNodeRunPayload = {
@ -110,7 +106,7 @@ export type SnippetIterationNodeRunPayload = {
} | null
}
export type GeneratedAppResponse = JsonValue
export type EventStreamResponse = string
export type SnippetLoopNodeRunPayload = {
inputs?: {
@ -120,7 +116,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
@ -162,55 +158,38 @@ export type SnippetDraftRunPayload = {
}
}
export type WorkflowDraftVariableListWithoutValue = {
items?: Array<WorkflowDraftVariableWithoutValue>
total?: number
export type WorkflowDraftVariableListWithoutValueResponse = {
items: Array<WorkflowDraftVariableWithoutValueResponse>
total: number | null
}
export type WorkflowDraftVariable = {
description?: string
edited?: boolean
full_content?: {
[key: string]: unknown
}
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value?:
| string
| number
| number
| boolean
| {
[key: string]: unknown
}
| Array<unknown>
| null
value_type?: string
visible?: boolean
export type WorkflowDraftVariableResponse = {
description: string
edited: boolean
full_content: WorkflowDraftVariableFullContentResponse | null
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value: unknown
value_type: string
visible: boolean
}
export type WorkflowDraftVariableUpdatePayload = {
name?: string | null
value?: unknown | null
value?: unknown
}
export type PublishWorkflowPayload = {
knowledge_base_setting?: {
[key: string]: unknown
} | null
}
export type WorkflowPublishResponse = {
export type PublishWorkflowResponse = {
created_at: number
result: string
}
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 +201,7 @@ export type WorkflowRunForListResponse = {
version?: string | null
}
export type SimpleAccount = {
export type SimpleAccountResponse = {
email: string
id: string
name: string
@ -268,7 +247,7 @@ export type PipelineVariableResponse = {
variable: string
}
export type EnvironmentVariableItemResponse = {
export type WorkflowDraftEnvironmentVariableResponse = {
description?: string | null
editable: boolean
edited: boolean
@ -281,27 +260,23 @@ export type EnvironmentVariableItemResponse = {
visible: boolean
}
export type JsonValue
= | string
| number
| number
| boolean
| {
[key: string]: unknown
}
| Array<unknown>
| null
export type WorkflowDraftVariableWithoutValueResponse = {
description: string
edited: boolean
id: string
is_truncated: boolean
name: string
selector: Array<string>
type: string
value_type: string
visible: boolean
}
export type WorkflowDraftVariableWithoutValue = {
description?: string
edited?: boolean
id?: string
is_truncated?: boolean
name?: string
selector?: Array<string>
type?: string
value_type?: string
visible?: boolean
export type WorkflowDraftVariableFullContentResponse = {
download_url: string
length: number | null
size_bytes: number | null
value_type: string
}
export type GetSnippetsBySnippetIdWorkflowRunsData = {
@ -401,22 +376,6 @@ export type GetSnippetsBySnippetIdWorkflowsResponses = {
export type GetSnippetsBySnippetIdWorkflowsResponse
= GetSnippetsBySnippetIdWorkflowsResponses[keyof GetSnippetsBySnippetIdWorkflowsResponses]
export type GetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsData = {
body?: never
path: {
snippet_id: string
}
query?: never
url: '/snippets/{snippet_id}/workflows/default-workflow-block-configs'
}
export type GetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponses = {
200: DefaultBlockConfigsResponse
}
export type GetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponse
= GetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponses[keyof GetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponses]
export type GetSnippetsBySnippetIdWorkflowsDraftData = {
body?: never
path: {
@ -451,7 +410,7 @@ export type PostSnippetsBySnippetIdWorkflowsDraftErrors = {
}
export type PostSnippetsBySnippetIdWorkflowsDraftResponses = {
200: WorkflowRestoreResponse
200: SyncDraftWorkflowResponse
}
export type PostSnippetsBySnippetIdWorkflowsDraftResponse
@ -483,7 +442,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftConversationVariablesData = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftConversationVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftConversationVariablesResponse
@ -503,7 +462,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesErrors = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesResponses = {
200: EnvironmentVariableListResponse
200: WorkflowDraftEnvironmentVariableListResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesResponse
@ -524,7 +483,7 @@ export type PostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunErrors
}
export type PostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
200: EventStreamResponse
}
export type PostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunResponse
@ -545,7 +504,7 @@ export type PostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunErrors = {
}
export type PostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunResponses = {
200: GeneratedAppResponse
200: EventStreamResponse
}
export type PostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunResponse
@ -621,7 +580,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdVariablesData = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdVariablesResponse
@ -641,7 +600,7 @@ export type PostSnippetsBySnippetIdWorkflowsDraftRunErrors = {
}
export type PostSnippetsBySnippetIdWorkflowsDraftRunResponses = {
200: GeneratedAppResponse
200: EventStreamResponse
}
export type PostSnippetsBySnippetIdWorkflowsDraftRunResponse
@ -657,7 +616,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftSystemVariablesData = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftSystemVariablesResponses = {
200: WorkflowDraftVariableList
200: WorkflowDraftVariableListResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftSystemVariablesResponse
@ -692,7 +651,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftVariablesData = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftVariablesResponses = {
200: WorkflowDraftVariableListWithoutValue
200: WorkflowDraftVariableListWithoutValueResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftVariablesResponse
@ -734,7 +693,7 @@ export type GetSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdErrors = {
}
export type GetSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type GetSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponse
@ -755,7 +714,7 @@ export type PatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdErrors =
}
export type PatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
}
export type PatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponse
@ -776,7 +735,7 @@ export type PutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetErrors
}
export type PutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetResponses = {
200: WorkflowDraftVariable
200: WorkflowDraftVariableResponse
204: void
}
@ -804,7 +763,7 @@ export type GetSnippetsBySnippetIdWorkflowsPublishResponse
= GetSnippetsBySnippetIdWorkflowsPublishResponses[keyof GetSnippetsBySnippetIdWorkflowsPublishResponses]
export type PostSnippetsBySnippetIdWorkflowsPublishData = {
body: PublishWorkflowPayload
body?: never
path: {
snippet_id: string
}
@ -817,7 +776,7 @@ export type PostSnippetsBySnippetIdWorkflowsPublishErrors = {
}
export type PostSnippetsBySnippetIdWorkflowsPublishResponses = {
200: WorkflowPublishResponse
200: PublishWorkflowResponse
}
export type PostSnippetsBySnippetIdWorkflowsPublishResponse
@ -839,7 +798,7 @@ export type PostSnippetsBySnippetIdWorkflowsByWorkflowIdRestoreErrors = {
}
export type PostSnippetsBySnippetIdWorkflowsByWorkflowIdRestoreResponses = {
200: WorkflowRestoreResponse
200: SyncDraftWorkflowResponse
}
export type PostSnippetsBySnippetIdWorkflowsByWorkflowIdRestoreResponse

View File

@ -9,11 +9,6 @@ export const zSimpleResultResponse = z.object({
result: z.string(),
})
/**
* DefaultBlockConfigsResponse
*/
export const zDefaultBlockConfigsResponse = z.array(z.record(z.string(), z.unknown()))
/**
* SnippetDraftSyncPayload
*
@ -27,9 +22,9 @@ export const zSnippetDraftSyncPayload = z.object({
})
/**
* WorkflowRestoreResponse
* SyncDraftWorkflowResponse
*/
export const zWorkflowRestoreResponse = z.object({
export const zSyncDraftWorkflowResponse = z.object({
hash: z.string(),
result: z.string(),
updated_at: z.int(),
@ -51,6 +46,11 @@ export const zSnippetIterationNodeRunPayload = z.object({
inputs: z.record(z.string(), z.unknown()).nullish(),
})
/**
* EventStreamResponse
*/
export const zEventStreamResponse = z.string()
/**
* SnippetLoopNodeRunPayload
*
@ -81,62 +81,26 @@ export const zSnippetDraftRunPayload = z.object({
inputs: z.record(z.string(), z.unknown()),
})
export const zWorkflowDraftVariable = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
full_content: z.record(z.string(), z.unknown()).optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value: z
.union([
z.string(),
z.int(),
z.number(),
z.boolean(),
z.record(z.string(), z.unknown()),
z.array(z.unknown()),
])
.nullish(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
})
export const zWorkflowDraftVariableList = z.object({
items: z.array(zWorkflowDraftVariable).optional(),
})
/**
* WorkflowDraftVariableUpdatePayload
*/
export const zWorkflowDraftVariableUpdatePayload = z.object({
name: z.string().nullish(),
value: z.unknown().nullish(),
value: z.unknown().optional(),
})
/**
* PublishWorkflowPayload
*
* Payload for publishing snippet workflow.
* PublishWorkflowResponse
*/
export const zPublishWorkflowPayload = z.object({
knowledge_base_setting: z.record(z.string(), z.unknown()).nullish(),
})
/**
* WorkflowPublishResponse
*/
export const zWorkflowPublishResponse = z.object({
export const zPublishWorkflowResponse = z.object({
created_at: z.int(),
result: z.string(),
})
/**
* SimpleAccount
* SimpleAccountResponse
*/
export const zSimpleAccount = z.object({
export const zSimpleAccountResponse = z.object({
email: z.string(),
id: z.string(),
name: z.string(),
@ -147,7 +111,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 +147,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 +169,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 +247,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 +259,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(),
})
@ -310,9 +274,9 @@ export const zSnippetWorkflowPaginationResponse = z.object({
})
/**
* EnvironmentVariableItemResponse
* WorkflowDraftEnvironmentVariableResponse
*/
export const zEnvironmentVariableItemResponse = z.object({
export const zWorkflowDraftEnvironmentVariableResponse = z.object({
description: z.string().nullish(),
editable: z.boolean(),
edited: z.boolean(),
@ -326,43 +290,67 @@ export const zEnvironmentVariableItemResponse = z.object({
})
/**
* EnvironmentVariableListResponse
* WorkflowDraftEnvironmentVariableListResponse
*/
export const zEnvironmentVariableListResponse = z.object({
items: z.array(zEnvironmentVariableItemResponse),
export const zWorkflowDraftEnvironmentVariableListResponse = z.object({
items: z.array(zWorkflowDraftEnvironmentVariableResponse),
})
export const zJsonValue = z
.union([
z.string(),
z.int(),
z.number(),
z.boolean(),
z.record(z.string(), z.unknown()),
z.array(z.unknown()),
])
.nullable()
/**
* GeneratedAppResponse
* WorkflowDraftVariableWithoutValueResponse
*/
export const zGeneratedAppResponse = zJsonValue
export const zWorkflowDraftVariableWithoutValue = z.object({
description: z.string().optional(),
edited: z.boolean().optional(),
id: z.string().optional(),
is_truncated: z.boolean().optional(),
name: z.string().optional(),
selector: z.array(z.string()).optional(),
type: z.string().optional(),
value_type: z.string().optional(),
visible: z.boolean().optional(),
export const zWorkflowDraftVariableWithoutValueResponse = z.object({
description: z.string(),
edited: z.boolean(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value_type: z.string(),
visible: z.boolean(),
})
export const zWorkflowDraftVariableListWithoutValue = z.object({
items: z.array(zWorkflowDraftVariableWithoutValue).optional(),
total: z.int().optional(),
/**
* WorkflowDraftVariableListWithoutValueResponse
*/
export const zWorkflowDraftVariableListWithoutValueResponse = z.object({
items: z.array(zWorkflowDraftVariableWithoutValueResponse),
total: z.int().nullable(),
})
/**
* WorkflowDraftVariableFullContentResponse
*/
export const zWorkflowDraftVariableFullContentResponse = z.object({
download_url: z.string(),
length: z.int().nullable(),
size_bytes: z.int().nullable(),
value_type: z.string(),
})
/**
* WorkflowDraftVariableResponse
*/
export const zWorkflowDraftVariableResponse = z.object({
description: z.string(),
edited: z.boolean(),
full_content: zWorkflowDraftVariableFullContentResponse.nullable(),
id: z.string(),
is_truncated: z.boolean(),
name: z.string(),
selector: z.array(z.string()),
type: z.string(),
value: z.unknown(),
value_type: z.string(),
visible: z.boolean(),
})
/**
* WorkflowDraftVariableListResponse
*/
export const zWorkflowDraftVariableListResponse = z.object({
items: z.array(zWorkflowDraftVariableResponse),
})
export const zGetSnippetsBySnippetIdWorkflowRunsPath = z.object({
@ -424,16 +412,6 @@ export const zGetSnippetsBySnippetIdWorkflowsQuery = z.object({
*/
export const zGetSnippetsBySnippetIdWorkflowsResponse = zSnippetWorkflowPaginationResponse
export const zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsPath = z.object({
snippet_id: z.uuid(),
})
/**
* Default block configs retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDefaultWorkflowBlockConfigsResponse
= zDefaultBlockConfigsResponse
export const zGetSnippetsBySnippetIdWorkflowsDraftPath = z.object({
snippet_id: z.uuid(),
})
@ -452,7 +430,7 @@ export const zPostSnippetsBySnippetIdWorkflowsDraftPath = z.object({
/**
* Draft workflow synced successfully
*/
export const zPostSnippetsBySnippetIdWorkflowsDraftResponse = zWorkflowRestoreResponse
export const zPostSnippetsBySnippetIdWorkflowsDraftResponse = zSyncDraftWorkflowResponse
export const zGetSnippetsBySnippetIdWorkflowsDraftConfigPath = z.object({
snippet_id: z.uuid(),
@ -471,7 +449,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftConversationVariablesPath = z.
* Conversation variables retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftConversationVariablesResponse
= zWorkflowDraftVariableList
= zWorkflowDraftVariableListResponse
export const zGetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesPath = z.object({
snippet_id: z.uuid(),
@ -481,7 +459,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesPath = z.o
* Environment variables retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftEnvironmentVariablesResponse
= zEnvironmentVariableListResponse
= zWorkflowDraftEnvironmentVariableListResponse
export const zPostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunBody
= zSnippetIterationNodeRunPayload
@ -495,7 +473,7 @@ export const zPostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunPath
* Iteration node run started successfully (SSE stream)
*/
export const zPostSnippetsBySnippetIdWorkflowsDraftIterationNodesByNodeIdRunResponse
= zGeneratedAppResponse
= zEventStreamResponse
export const zPostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunBody
= zSnippetLoopNodeRunPayload
@ -509,7 +487,7 @@ export const zPostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunPath = z.
* Loop node run started successfully (SSE stream)
*/
export const zPostSnippetsBySnippetIdWorkflowsDraftLoopNodesByNodeIdRunResponse
= zGeneratedAppResponse
= zEventStreamResponse
export const zGetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdLastRunPath = z.object({
node_id: z.string(),
@ -555,7 +533,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdVariablesPath = z
* Node variables retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftNodesByNodeIdVariablesResponse
= zWorkflowDraftVariableList
= zWorkflowDraftVariableListResponse
export const zPostSnippetsBySnippetIdWorkflowsDraftRunBody = zSnippetDraftRunPayload
@ -566,7 +544,7 @@ export const zPostSnippetsBySnippetIdWorkflowsDraftRunPath = z.object({
/**
* Draft workflow run started successfully (SSE stream)
*/
export const zPostSnippetsBySnippetIdWorkflowsDraftRunResponse = zGeneratedAppResponse
export const zPostSnippetsBySnippetIdWorkflowsDraftRunResponse = zEventStreamResponse
export const zGetSnippetsBySnippetIdWorkflowsDraftSystemVariablesPath = z.object({
snippet_id: z.uuid(),
@ -576,7 +554,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftSystemVariablesPath = z.object
* System variables retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftSystemVariablesResponse
= zWorkflowDraftVariableList
= zWorkflowDraftVariableListResponse
export const zDeleteSnippetsBySnippetIdWorkflowsDraftVariablesPath = z.object({
snippet_id: z.uuid(),
@ -600,7 +578,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftVariablesQuery = z.object({
* Workflow variables retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftVariablesResponse
= zWorkflowDraftVariableListWithoutValue
= zWorkflowDraftVariableListWithoutValueResponse
export const zDeleteSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdPath = z.object({
snippet_id: z.uuid(),
@ -621,7 +599,7 @@ export const zGetSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdPath = z.
* Variable retrieved successfully
*/
export const zGetSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariable
= zWorkflowDraftVariableResponse
export const zPatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdBody
= zWorkflowDraftVariableUpdatePayload
@ -635,7 +613,7 @@ export const zPatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdPath =
* Variable updated successfully
*/
export const zPatchSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResponse
= zWorkflowDraftVariable
= zWorkflowDraftVariableResponse
export const zPutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetPath = z.object({
snippet_id: z.uuid(),
@ -643,7 +621,7 @@ export const zPutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetPath
})
export const zPutSnippetsBySnippetIdWorkflowsDraftVariablesByVariableIdResetResponse = z.union([
zWorkflowDraftVariable,
zWorkflowDraftVariableResponse,
z.void(),
])
@ -656,8 +634,6 @@ export const zGetSnippetsBySnippetIdWorkflowsPublishPath = z.object({
*/
export const zGetSnippetsBySnippetIdWorkflowsPublishResponse = zSnippetWorkflowResponse
export const zPostSnippetsBySnippetIdWorkflowsPublishBody = zPublishWorkflowPayload
export const zPostSnippetsBySnippetIdWorkflowsPublishPath = z.object({
snippet_id: z.uuid(),
})
@ -665,7 +641,7 @@ export const zPostSnippetsBySnippetIdWorkflowsPublishPath = z.object({
/**
* Workflow published successfully
*/
export const zPostSnippetsBySnippetIdWorkflowsPublishResponse = zWorkflowPublishResponse
export const zPostSnippetsBySnippetIdWorkflowsPublishResponse = zPublishWorkflowResponse
export const zPostSnippetsBySnippetIdWorkflowsByWorkflowIdRestorePath = z.object({
snippet_id: z.uuid(),
@ -675,4 +651,5 @@ export const zPostSnippetsBySnippetIdWorkflowsByWorkflowIdRestorePath = z.object
/**
* Workflow restored successfully
*/
export const zPostSnippetsBySnippetIdWorkflowsByWorkflowIdRestoreResponse = zWorkflowRestoreResponse
export const zPostSnippetsBySnippetIdWorkflowsByWorkflowIdRestoreResponse
= zSyncDraftWorkflowResponse

View File

@ -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

View File

@ -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

View File

@ -1414,7 +1414,7 @@ export type SelectInputConfig = {
type?: 'select'
}
export type SimpleAccount = {
export type SimpleAccountResponse = {
email: string
id: string
name: string
@ -1572,7 +1572,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

View File

@ -1676,9 +1676,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 +2196,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(),

View File

@ -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
},
},
},

View File

@ -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[] {