mirror of
https://github.com/langgenius/dify.git
synced 2026-07-01 19:36:52 +08:00
Compare commits
1 Commits
codex/migr
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bf46b82303 |
@ -1,10 +1,9 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal, cast
|
||||
|
||||
from flask import request
|
||||
from flask_restx import Resource, fields, marshal, marshal_with
|
||||
from pydantic import AliasChoices, BaseModel, Field, field_validator
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import select
|
||||
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
|
||||
|
||||
@ -64,7 +63,6 @@ from fields.app_fields import (
|
||||
site_fields,
|
||||
tag_fields,
|
||||
)
|
||||
from fields.base import ResponseModel
|
||||
from fields.dataset_fields import dataset_fields
|
||||
from fields.member_fields import simple_account_fields
|
||||
from fields.message_fields import SuggestedQuestionsResponse
|
||||
@ -77,7 +75,7 @@ from fields.workflow_fields import (
|
||||
from graphon.graph_engine.manager import GraphEngineManager
|
||||
from graphon.model_runtime.errors.invoke import InvokeError
|
||||
from libs import helper
|
||||
from libs.helper import to_timestamp, uuid_value
|
||||
from libs.helper import uuid_value
|
||||
from models import Account
|
||||
from models.account import TenantStatus
|
||||
from models.model import AppMode, Site
|
||||
@ -182,266 +180,6 @@ class TrialDatasetListQuery(BaseModel):
|
||||
ids: list[str] = Field(default_factory=list, description="Dataset IDs")
|
||||
|
||||
|
||||
type TrialAppMode = Literal["chat", "agent-chat", "advanced-chat", "workflow", "completion"]
|
||||
type TrialIconType = Literal["emoji", "image", "link"]
|
||||
type JsonObject = dict[str, Any]
|
||||
|
||||
|
||||
class TrialAppModel(ResponseModel):
|
||||
provider: str
|
||||
name: str
|
||||
mode: str | None = None
|
||||
completion_params: JsonObject = Field(default_factory=dict)
|
||||
|
||||
|
||||
class TrialAppAgentMode(ResponseModel):
|
||||
enabled: bool | None = None
|
||||
strategy: str | None = None
|
||||
tools: list[JsonObject] = Field(default_factory=list)
|
||||
|
||||
|
||||
class TrialAppModelConfigResponse(ResponseModel):
|
||||
opening_statement: str | None = None
|
||||
suggested_questions: list[str] = Field(
|
||||
default_factory=list,
|
||||
validation_alias=AliasChoices("suggested_questions_list", "suggested_questions"),
|
||||
)
|
||||
suggested_questions_after_answer: JsonObject | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("suggested_questions_after_answer_dict", "suggested_questions_after_answer"),
|
||||
)
|
||||
speech_to_text: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("speech_to_text_dict", "speech_to_text")
|
||||
)
|
||||
text_to_speech: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("text_to_speech_dict", "text_to_speech")
|
||||
)
|
||||
retriever_resource: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("retriever_resource_dict", "retriever_resource")
|
||||
)
|
||||
annotation_reply: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("annotation_reply_dict", "annotation_reply")
|
||||
)
|
||||
more_like_this: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("more_like_this_dict", "more_like_this")
|
||||
)
|
||||
sensitive_word_avoidance: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("sensitive_word_avoidance_dict", "sensitive_word_avoidance")
|
||||
)
|
||||
external_data_tools: list[JsonObject] = Field(
|
||||
default_factory=list, validation_alias=AliasChoices("external_data_tools_list", "external_data_tools")
|
||||
)
|
||||
model: TrialAppModel | None = Field(default=None, validation_alias=AliasChoices("model_dict", "model"))
|
||||
user_input_form: list[JsonObject] = Field(
|
||||
default_factory=list, validation_alias=AliasChoices("user_input_form_list", "user_input_form")
|
||||
)
|
||||
dataset_query_variable: str | None = None
|
||||
pre_prompt: str | None = None
|
||||
agent_mode: TrialAppAgentMode | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("agent_mode_dict", "agent_mode"),
|
||||
)
|
||||
prompt_type: str | None = None
|
||||
chat_prompt_config: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("chat_prompt_config_dict", "chat_prompt_config")
|
||||
)
|
||||
completion_prompt_config: JsonObject | None = Field(
|
||||
default=None, validation_alias=AliasChoices("completion_prompt_config_dict", "completion_prompt_config")
|
||||
)
|
||||
dataset_configs: JsonObject | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("dataset_configs_dict", "dataset_configs"),
|
||||
)
|
||||
file_upload: JsonObject | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("file_upload_dict", "file_upload"),
|
||||
)
|
||||
created_by: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_by: str | None = None
|
||||
updated_at: int | None = None
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class TrialDeletedToolResponse(ResponseModel):
|
||||
type: str
|
||||
tool_name: str
|
||||
provider_id: str
|
||||
|
||||
|
||||
class TrialTagResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
|
||||
|
||||
class TrialSiteResponse(ResponseModel):
|
||||
access_token: str | None = Field(default=None, validation_alias="code")
|
||||
code: str | None = None
|
||||
title: str
|
||||
icon_type: TrialIconType | None = None
|
||||
icon: str | None = None
|
||||
icon_background: str | None = None
|
||||
description: str | None = None
|
||||
default_language: str
|
||||
chat_color_theme: str | None = None
|
||||
chat_color_theme_inverted: bool | None = None
|
||||
customize_domain: str | None = None
|
||||
copyright: str | None = None
|
||||
privacy_policy: str | None = None
|
||||
input_placeholder: str | None = None
|
||||
custom_disclaimer: str | None = None
|
||||
customize_token_strategy: str | None = None
|
||||
prompt_public: bool | None = None
|
||||
app_base_url: str | None = None
|
||||
show_workflow_steps: bool | None = None
|
||||
use_icon_as_answer_icon: bool | None = None
|
||||
created_by: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_by: str | None = None
|
||||
updated_at: int | None = None
|
||||
icon_url: str | None = None
|
||||
|
||||
@field_validator("icon_type", mode="before")
|
||||
@classmethod
|
||||
def _normalize_icon_type(cls, value: Any) -> str | None:
|
||||
if hasattr(value, "value"):
|
||||
return value.value
|
||||
return value
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class TrialWorkflowPartialResponse(ResponseModel):
|
||||
id: str
|
||||
created_by: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_by: str | None = None
|
||||
updated_at: int | None = None
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class TrialAppDetailResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
mode: TrialAppMode = Field(validation_alias="mode_compatible_with_agent")
|
||||
icon_type: TrialIconType | None = None
|
||||
icon: str | None = None
|
||||
icon_background: str | None = None
|
||||
icon_url: str | None = None
|
||||
enable_site: bool
|
||||
enable_api: bool
|
||||
model_config_: TrialAppModelConfigResponse | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("app_model_config", "model_config"),
|
||||
alias="model_config",
|
||||
)
|
||||
workflow: TrialWorkflowPartialResponse | None = None
|
||||
api_base_url: str | None = None
|
||||
use_icon_as_answer_icon: bool | None = None
|
||||
max_active_requests: int | None = None
|
||||
created_by: str | None = None
|
||||
created_at: int | None = None
|
||||
updated_by: str | None = None
|
||||
updated_at: int | None = None
|
||||
deleted_tools: list[TrialDeletedToolResponse] = Field(default_factory=list)
|
||||
access_mode: str | None = None
|
||||
tags: list[TrialTagResponse] = Field(default_factory=list)
|
||||
permission_keys: list[str] = Field(default_factory=list)
|
||||
site: TrialSiteResponse
|
||||
|
||||
@field_validator("icon_type", mode="before")
|
||||
@classmethod
|
||||
def _normalize_icon_type(cls, value: Any) -> str | None:
|
||||
if hasattr(value, "value"):
|
||||
return value.value
|
||||
return value
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class TrialDatasetResponse(ResponseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
permission: str | None = None
|
||||
data_source_type: str | None = None
|
||||
indexing_technique: str | None = None
|
||||
created_by: str | None = None
|
||||
created_at: int | None = None
|
||||
permission_keys: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class TrialDatasetListResponse(ResponseModel):
|
||||
data: list[TrialDatasetResponse]
|
||||
has_more: bool
|
||||
limit: int
|
||||
total: int
|
||||
page: int
|
||||
|
||||
|
||||
class TrialWorkflowViewport(ResponseModel):
|
||||
x: float
|
||||
y: float
|
||||
zoom: float
|
||||
|
||||
|
||||
class TrialWorkflowGraph(ResponseModel):
|
||||
nodes: list[JsonObject]
|
||||
edges: list[JsonObject]
|
||||
viewport: TrialWorkflowViewport
|
||||
|
||||
|
||||
class TrialWorkflowAccount(ResponseModel):
|
||||
id: str
|
||||
name: str | None = None
|
||||
email: str | None = None
|
||||
|
||||
|
||||
class TrialWorkflowResponse(ResponseModel):
|
||||
id: str
|
||||
graph: TrialWorkflowGraph = Field(validation_alias=AliasChoices("graph_dict", "graph"))
|
||||
features: JsonObject = Field(default_factory=dict, validation_alias=AliasChoices("features_dict", "features"))
|
||||
hash: str | None = Field(default=None, validation_alias=AliasChoices("unique_hash", "hash"))
|
||||
version: str | None = None
|
||||
marked_name: str | None = None
|
||||
marked_comment: str | None = None
|
||||
created_by: TrialWorkflowAccount | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("created_by_account", "created_by"),
|
||||
)
|
||||
created_at: int | None = None
|
||||
updated_by: TrialWorkflowAccount | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("updated_by_account", "updated_by"),
|
||||
)
|
||||
updated_at: int | None = None
|
||||
tool_published: bool | None = None
|
||||
environment_variables: list[JsonObject] = Field(default_factory=list)
|
||||
conversation_variables: list[JsonObject] = Field(default_factory=list)
|
||||
rag_pipeline_variables: list[JsonObject] = Field(default_factory=list)
|
||||
|
||||
@field_validator("created_at", "updated_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
register_schema_models(
|
||||
console_ns,
|
||||
WorkflowRunRequest,
|
||||
@ -459,9 +197,6 @@ register_response_schema_models(
|
||||
SimpleResultResponse,
|
||||
SiteResponse,
|
||||
SuggestedQuestionsResponse,
|
||||
TrialAppDetailResponse,
|
||||
TrialDatasetListResponse,
|
||||
TrialWorkflowResponse,
|
||||
)
|
||||
|
||||
|
||||
@ -831,7 +566,7 @@ class TrialAppParameterApi(Resource):
|
||||
|
||||
|
||||
class AppApi(Resource):
|
||||
@console_ns.response(200, "Success", console_ns.models[TrialAppDetailResponse.__name__])
|
||||
@console_ns.response(200, "Success", app_detail_with_site_model)
|
||||
@get_app_model_with_trial(None)
|
||||
@marshal_with(app_detail_with_site_model)
|
||||
def get(self, app_model):
|
||||
@ -844,7 +579,7 @@ class AppApi(Resource):
|
||||
|
||||
|
||||
class AppWorkflowApi(Resource):
|
||||
@console_ns.response(200, "Success", console_ns.models[TrialWorkflowResponse.__name__])
|
||||
@console_ns.response(200, "Success", workflow_model)
|
||||
@get_app_model_with_trial(None)
|
||||
@marshal_with(workflow_model)
|
||||
def get(self, app_model):
|
||||
@ -858,7 +593,7 @@ class AppWorkflowApi(Resource):
|
||||
|
||||
class DatasetListApi(Resource):
|
||||
@console_ns.doc(params=query_params_from_model(TrialDatasetListQuery))
|
||||
@console_ns.response(200, "Success", console_ns.models[TrialDatasetListResponse.__name__])
|
||||
@console_ns.response(200, "Success", dataset_list_model)
|
||||
@get_app_model_with_trial(None)
|
||||
def get(self, app_model):
|
||||
page = request.args.get("page", default=1, type=int)
|
||||
|
||||
@ -9385,7 +9385,7 @@ Bedrock retrieval test (internal use only)
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [TrialAppDetailResponse](#trialappdetailresponse)<br> |
|
||||
| 200 | Success | **application/json**: [TrialAppDetailWithSite](#trialappdetailwithsite)<br> |
|
||||
|
||||
### [POST] /trial-apps/{app_id}/audio-to-text
|
||||
#### Parameters
|
||||
@ -9452,7 +9452,7 @@ Bedrock retrieval test (internal use only)
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [TrialDatasetListResponse](#trialdatasetlistresponse)<br> |
|
||||
| 200 | Success | **application/json**: [TrialDatasetList](#trialdatasetlist)<br> |
|
||||
|
||||
### [GET] /trial-apps/{app_id}/messages/{message_id}/suggested-questions
|
||||
#### Parameters
|
||||
@ -9532,7 +9532,7 @@ Returns the site configuration for the application including theme, icons, and t
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Success | **application/json**: [TrialWorkflowResponse](#trialworkflowresponse)<br> |
|
||||
| 200 | Success | **application/json**: [TrialWorkflow](#trialworkflow)<br> |
|
||||
|
||||
### [POST] /trial-apps/{app_id}/workflows/run
|
||||
**Run workflow**
|
||||
@ -18048,12 +18048,6 @@ Input field definition for snippet parameters.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| JSONValueType | | | |
|
||||
|
||||
#### JsonObject
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| JsonObject | object | | |
|
||||
|
||||
#### JsonValue
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21283,43 +21277,6 @@ Enum class for tool provider
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| tracing_provider | string | Tracing provider name | Yes |
|
||||
|
||||
#### TrialAppAgentMode
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| enabled | boolean | | No |
|
||||
| strategy | string | | No |
|
||||
| tools | [ [JsonObject](#jsonobject) ] | | No |
|
||||
|
||||
#### TrialAppDetailResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| access_mode | string | | No |
|
||||
| api_base_url | string | | No |
|
||||
| created_at | integer | | No |
|
||||
| created_by | string | | No |
|
||||
| deleted_tools | [ [TrialDeletedToolResponse](#trialdeletedtoolresponse) ] | | No |
|
||||
| description | string | | No |
|
||||
| enable_api | boolean | | Yes |
|
||||
| enable_site | boolean | | Yes |
|
||||
| icon | string | | No |
|
||||
| icon_background | string | | No |
|
||||
| icon_type | [TrialIconType](#trialicontype) | | No |
|
||||
| icon_url | string | | No |
|
||||
| id | string | | Yes |
|
||||
| max_active_requests | integer | | No |
|
||||
| mode | [TrialAppMode](#trialappmode) | | Yes |
|
||||
| model_config | [TrialAppModelConfigResponse](#trialappmodelconfigresponse) | | No |
|
||||
| name | string | | Yes |
|
||||
| permission_keys | [ string ] | | No |
|
||||
| site | [TrialSiteResponse](#trialsiteresponse) | | Yes |
|
||||
| tags | [ [TrialTagResponse](#trialtagresponse) ] | | No |
|
||||
| updated_at | integer | | No |
|
||||
| updated_by | string | | No |
|
||||
| use_icon_as_answer_icon | boolean | | No |
|
||||
| workflow | [TrialWorkflowPartialResponse](#trialworkflowpartialresponse) | | No |
|
||||
|
||||
#### TrialAppDetailWithSite
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21349,21 +21306,6 @@ Enum class for tool provider
|
||||
| use_icon_as_answer_icon | boolean | | No |
|
||||
| workflow | [TrialWorkflowPartial](#trialworkflowpartial) | | No |
|
||||
|
||||
#### TrialAppMode
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| TrialAppMode | string | | |
|
||||
|
||||
#### TrialAppModel
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| completion_params | [JsonObject](#jsonobject) | | No |
|
||||
| mode | string | | No |
|
||||
| name | string | | Yes |
|
||||
| provider | string | | Yes |
|
||||
|
||||
#### TrialAppModelConfig
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21393,35 +21335,6 @@ Enum class for tool provider
|
||||
| updated_by | string | | No |
|
||||
| user_input_form | [ object ] | | No |
|
||||
|
||||
#### TrialAppModelConfigResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_mode | [TrialAppAgentMode](#trialappagentmode) | | No |
|
||||
| annotation_reply | [JsonObject](#jsonobject) | | No |
|
||||
| chat_prompt_config | [JsonObject](#jsonobject) | | No |
|
||||
| completion_prompt_config | [JsonObject](#jsonobject) | | No |
|
||||
| created_at | integer | | No |
|
||||
| created_by | string | | No |
|
||||
| dataset_configs | [JsonObject](#jsonobject) | | No |
|
||||
| dataset_query_variable | string | | No |
|
||||
| external_data_tools | [ [JsonObject](#jsonobject) ] | | No |
|
||||
| file_upload | [JsonObject](#jsonobject) | | No |
|
||||
| model | [TrialAppModel](#trialappmodel) | | No |
|
||||
| more_like_this | [JsonObject](#jsonobject) | | No |
|
||||
| opening_statement | string | | No |
|
||||
| pre_prompt | string | | No |
|
||||
| prompt_type | string | | No |
|
||||
| retriever_resource | [JsonObject](#jsonobject) | | No |
|
||||
| sensitive_word_avoidance | [JsonObject](#jsonobject) | | No |
|
||||
| speech_to_text | [JsonObject](#jsonobject) | | No |
|
||||
| suggested_questions | [ string ] | | No |
|
||||
| suggested_questions_after_answer | [JsonObject](#jsonobject) | | No |
|
||||
| text_to_speech | [JsonObject](#jsonobject) | | No |
|
||||
| updated_at | integer | | No |
|
||||
| updated_by | string | | No |
|
||||
| user_input_form | [ [JsonObject](#jsonobject) ] | | No |
|
||||
|
||||
#### TrialConversationVariable
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21464,30 +21377,6 @@ Enum class for tool provider
|
||||
| limit | integer, <br>**Default:** 20 | Number of items per page | No |
|
||||
| page | integer, <br>**Default:** 1 | Page number | No |
|
||||
|
||||
#### TrialDatasetListResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [TrialDatasetResponse](#trialdatasetresponse) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### TrialDatasetResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by | string | | No |
|
||||
| data_source_type | string | | No |
|
||||
| description | string | | No |
|
||||
| id | string | | Yes |
|
||||
| indexing_technique | string | | No |
|
||||
| name | string | | Yes |
|
||||
| permission | string | | No |
|
||||
| permission_keys | [ string ] | | No |
|
||||
|
||||
#### TrialDeletedTool
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21496,20 +21385,6 @@ Enum class for tool provider
|
||||
| tool_name | string | | No |
|
||||
| type | string | | No |
|
||||
|
||||
#### TrialDeletedToolResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| provider_id | string | | Yes |
|
||||
| tool_name | string | | Yes |
|
||||
| type | string | | Yes |
|
||||
|
||||
#### TrialIconType
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| TrialIconType | string | | |
|
||||
|
||||
#### TrialModelsResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21572,36 +21447,6 @@ Enum class for tool provider
|
||||
| updated_by | string | | No |
|
||||
| use_icon_as_answer_icon | boolean | | No |
|
||||
|
||||
#### TrialSiteResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| access_token | string | | No |
|
||||
| app_base_url | string | | No |
|
||||
| chat_color_theme | string | | No |
|
||||
| chat_color_theme_inverted | boolean | | No |
|
||||
| code | string | | No |
|
||||
| copyright | string | | No |
|
||||
| created_at | integer | | No |
|
||||
| created_by | string | | No |
|
||||
| custom_disclaimer | string | | No |
|
||||
| customize_domain | string | | No |
|
||||
| customize_token_strategy | string | | No |
|
||||
| default_language | string | | Yes |
|
||||
| description | string | | No |
|
||||
| icon | string | | No |
|
||||
| icon_background | string | | No |
|
||||
| icon_type | [TrialIconType](#trialicontype) | | No |
|
||||
| icon_url | string | | No |
|
||||
| input_placeholder | string | | No |
|
||||
| privacy_policy | string | | No |
|
||||
| prompt_public | boolean | | No |
|
||||
| show_workflow_steps | boolean | | No |
|
||||
| title | string | | Yes |
|
||||
| updated_at | integer | | No |
|
||||
| updated_by | string | | No |
|
||||
| use_icon_as_answer_icon | boolean | | No |
|
||||
|
||||
#### TrialTag
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21610,14 +21455,6 @@ Enum class for tool provider
|
||||
| name | string | | No |
|
||||
| type | string | | No |
|
||||
|
||||
#### TrialTagResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| id | string | | Yes |
|
||||
| name | string | | Yes |
|
||||
| type | string | | Yes |
|
||||
|
||||
#### TrialWorkflow
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21638,22 +21475,6 @@ Enum class for tool provider
|
||||
| updated_by | [TrialSimpleAccount](#trialsimpleaccount) | | No |
|
||||
| version | string | | No |
|
||||
|
||||
#### TrialWorkflowAccount
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| email | string | | No |
|
||||
| id | string | | Yes |
|
||||
| name | string | | No |
|
||||
|
||||
#### TrialWorkflowGraph
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| edges | [ [JsonObject](#jsonobject) ] | | Yes |
|
||||
| nodes | [ [JsonObject](#jsonobject) ] | | Yes |
|
||||
| viewport | [TrialWorkflowViewport](#trialworkflowviewport) | | Yes |
|
||||
|
||||
#### TrialWorkflowPartial
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -21664,44 +21485,6 @@ Enum class for tool provider
|
||||
| updated_at | long | | No |
|
||||
| updated_by | string | | No |
|
||||
|
||||
#### TrialWorkflowPartialResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| created_by | string | | No |
|
||||
| id | string | | Yes |
|
||||
| updated_at | integer | | No |
|
||||
| updated_by | string | | No |
|
||||
|
||||
#### TrialWorkflowResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| conversation_variables | [ [JsonObject](#jsonobject) ] | | No |
|
||||
| created_at | integer | | No |
|
||||
| created_by | [TrialWorkflowAccount](#trialworkflowaccount) | | No |
|
||||
| environment_variables | [ [JsonObject](#jsonobject) ] | | No |
|
||||
| features | [JsonObject](#jsonobject) | | No |
|
||||
| graph | [TrialWorkflowGraph](#trialworkflowgraph) | | Yes |
|
||||
| hash | string | | No |
|
||||
| id | string | | Yes |
|
||||
| marked_comment | string | | No |
|
||||
| marked_name | string | | No |
|
||||
| rag_pipeline_variables | [ [JsonObject](#jsonobject) ] | | No |
|
||||
| tool_published | boolean | | No |
|
||||
| updated_at | integer | | No |
|
||||
| updated_by | [TrialWorkflowAccount](#trialworkflowaccount) | | No |
|
||||
| version | string | | No |
|
||||
|
||||
#### TrialWorkflowViewport
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| x | number | | Yes |
|
||||
| y | number | | Yes |
|
||||
| zoom | number | | Yes |
|
||||
|
||||
#### TriggerCreationMethod
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|
||||
@ -7274,6 +7274,19 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/try-app.spec.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/try-app.ts": {
|
||||
"no-barrel-files/no-barrel-files": {
|
||||
"count": 2
|
||||
},
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/service/use-apps.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
@ -7393,6 +7406,11 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/types/app.ts": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/types/assets.d.ts": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 5
|
||||
@ -7464,6 +7482,16 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/utils/model-config.spec.ts": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 13
|
||||
}
|
||||
},
|
||||
"web/utils/model-config.ts": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 6
|
||||
}
|
||||
},
|
||||
"web/utils/tool-call.spec.ts": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 1
|
||||
|
||||
@ -4,31 +4,31 @@ export type ClientOptions = {
|
||||
baseUrl: `${string}://${string}/console/api` | (string & {})
|
||||
}
|
||||
|
||||
export type TrialAppDetailResponse = {
|
||||
access_mode?: string | null
|
||||
api_base_url?: string | null
|
||||
created_at?: number | null
|
||||
created_by?: string | null
|
||||
deleted_tools?: Array<TrialDeletedToolResponse>
|
||||
description?: string | null
|
||||
enable_api: boolean
|
||||
enable_site: boolean
|
||||
icon?: string | null
|
||||
icon_background?: string | null
|
||||
icon_type?: TrialIconType | null
|
||||
icon_url?: string | null
|
||||
id: string
|
||||
max_active_requests?: number | null
|
||||
mode: TrialAppMode
|
||||
model_config?: TrialAppModelConfigResponse | null
|
||||
name: string
|
||||
export type TrialAppDetailWithSite = {
|
||||
access_mode?: string
|
||||
api_base_url?: string
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
deleted_tools?: Array<TrialDeletedTool>
|
||||
description?: string
|
||||
enable_api?: boolean
|
||||
enable_site?: boolean
|
||||
icon?: string
|
||||
icon_background?: string
|
||||
icon_type?: string
|
||||
icon_url?: string
|
||||
id?: string
|
||||
max_active_requests?: number
|
||||
mode?: string
|
||||
model_config?: TrialAppModelConfig
|
||||
name?: string
|
||||
permission_keys?: Array<string>
|
||||
site: TrialSiteResponse
|
||||
tags?: Array<TrialTagResponse>
|
||||
updated_at?: number | null
|
||||
updated_by?: string | null
|
||||
use_icon_as_answer_icon?: boolean | null
|
||||
workflow?: TrialWorkflowPartialResponse | null
|
||||
site?: TrialSite
|
||||
tags?: Array<TrialTag>
|
||||
updated_at?: number
|
||||
updated_by?: string
|
||||
use_icon_as_answer_icon?: boolean
|
||||
workflow?: TrialWorkflowPartial
|
||||
}
|
||||
|
||||
export type AudioTranscriptResponse = {
|
||||
@ -58,12 +58,12 @@ export type CompletionRequest = {
|
||||
retriever_from?: string
|
||||
}
|
||||
|
||||
export type TrialDatasetListResponse = {
|
||||
data: Array<TrialDatasetResponse>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
total: number
|
||||
export type TrialDatasetList = {
|
||||
data?: Array<TrialDataset>
|
||||
has_more?: boolean
|
||||
limit?: number
|
||||
page?: number
|
||||
total?: number
|
||||
}
|
||||
|
||||
export type SuggestedQuestionsResponse = {
|
||||
@ -112,22 +112,28 @@ export type TextToSpeechRequest = {
|
||||
|
||||
export type AudioBinaryResponse = Blob | File
|
||||
|
||||
export type TrialWorkflowResponse = {
|
||||
conversation_variables?: Array<JsonObject2>
|
||||
created_at?: number | null
|
||||
created_by?: TrialWorkflowAccount | null
|
||||
environment_variables?: Array<JsonObject2>
|
||||
features?: JsonObject2
|
||||
graph: TrialWorkflowGraph
|
||||
hash?: string | null
|
||||
id: string
|
||||
marked_comment?: string | null
|
||||
marked_name?: string | null
|
||||
rag_pipeline_variables?: Array<JsonObject2>
|
||||
tool_published?: boolean | null
|
||||
updated_at?: number | null
|
||||
updated_by?: TrialWorkflowAccount | null
|
||||
version?: string | null
|
||||
export type TrialWorkflow = {
|
||||
conversation_variables?: Array<TrialConversationVariable>
|
||||
created_at?: number
|
||||
created_by?: TrialSimpleAccount
|
||||
environment_variables?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
features?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
graph?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
hash?: string
|
||||
id?: string
|
||||
marked_comment?: string
|
||||
marked_name?: string
|
||||
rag_pipeline_variables?: Array<TrialPipelineVariable>
|
||||
tool_published?: boolean
|
||||
updated_at?: number
|
||||
updated_by?: TrialSimpleAccount
|
||||
version?: string
|
||||
}
|
||||
|
||||
export type WorkflowRunRequest = {
|
||||
@ -141,83 +147,108 @@ export type SimpleResultResponse = {
|
||||
result: string
|
||||
}
|
||||
|
||||
export type TrialDeletedToolResponse = {
|
||||
provider_id: string
|
||||
tool_name: string
|
||||
type: string
|
||||
export type TrialDeletedTool = {
|
||||
provider_id?: string
|
||||
tool_name?: string
|
||||
type?: string
|
||||
}
|
||||
|
||||
export type TrialIconType = 'emoji' | 'image' | 'link'
|
||||
|
||||
export type TrialAppMode = 'advanced-chat' | 'agent-chat' | 'chat' | 'completion' | 'workflow'
|
||||
|
||||
export type TrialAppModelConfigResponse = {
|
||||
agent_mode?: TrialAppAgentMode | null
|
||||
annotation_reply?: JsonObject2 | null
|
||||
chat_prompt_config?: JsonObject2 | null
|
||||
completion_prompt_config?: JsonObject2 | null
|
||||
created_at?: number | null
|
||||
created_by?: string | null
|
||||
dataset_configs?: JsonObject2 | null
|
||||
dataset_query_variable?: string | null
|
||||
external_data_tools?: Array<JsonObject2>
|
||||
file_upload?: JsonObject2 | null
|
||||
model?: TrialAppModel | null
|
||||
more_like_this?: JsonObject2 | null
|
||||
opening_statement?: string | null
|
||||
pre_prompt?: string | null
|
||||
prompt_type?: string | null
|
||||
retriever_resource?: JsonObject2 | null
|
||||
sensitive_word_avoidance?: JsonObject2 | null
|
||||
speech_to_text?: JsonObject2 | null
|
||||
export type TrialAppModelConfig = {
|
||||
agent_mode?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
annotation_reply?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
chat_prompt_config?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
completion_prompt_config?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
dataset_configs?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
dataset_query_variable?: string
|
||||
external_data_tools?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
file_upload?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
model?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
more_like_this?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
opening_statement?: string
|
||||
pre_prompt?: string
|
||||
prompt_type?: string
|
||||
retriever_resource?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
sensitive_word_avoidance?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
speech_to_text?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
suggested_questions?: Array<string>
|
||||
suggested_questions_after_answer?: JsonObject2 | null
|
||||
text_to_speech?: JsonObject2 | null
|
||||
updated_at?: number | null
|
||||
updated_by?: string | null
|
||||
user_input_form?: Array<JsonObject2>
|
||||
suggested_questions_after_answer?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
text_to_speech?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
updated_at?: number
|
||||
updated_by?: string
|
||||
user_input_form?: Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
}
|
||||
|
||||
export type TrialSiteResponse = {
|
||||
access_token?: string | null
|
||||
app_base_url?: string | null
|
||||
chat_color_theme?: string | null
|
||||
chat_color_theme_inverted?: boolean | null
|
||||
code?: string | null
|
||||
copyright?: string | null
|
||||
created_at?: number | null
|
||||
created_by?: string | null
|
||||
custom_disclaimer?: string | null
|
||||
customize_domain?: string | null
|
||||
customize_token_strategy?: string | null
|
||||
default_language: string
|
||||
description?: string | null
|
||||
icon?: string | null
|
||||
icon_background?: string | null
|
||||
icon_type?: TrialIconType | null
|
||||
icon_url?: string | null
|
||||
input_placeholder?: string | null
|
||||
privacy_policy?: string | null
|
||||
prompt_public?: boolean | null
|
||||
show_workflow_steps?: boolean | null
|
||||
title: string
|
||||
updated_at?: number | null
|
||||
updated_by?: string | null
|
||||
use_icon_as_answer_icon?: boolean | null
|
||||
export type TrialSite = {
|
||||
access_token?: string
|
||||
app_base_url?: string
|
||||
chat_color_theme?: string
|
||||
chat_color_theme_inverted?: boolean
|
||||
code?: string
|
||||
copyright?: string
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
custom_disclaimer?: string
|
||||
customize_domain?: string
|
||||
customize_token_strategy?: string
|
||||
default_language?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
icon_background?: string
|
||||
icon_type?: string
|
||||
icon_url?: string
|
||||
privacy_policy?: string
|
||||
prompt_public?: boolean
|
||||
show_workflow_steps?: boolean
|
||||
title?: string
|
||||
updated_at?: number
|
||||
updated_by?: string
|
||||
use_icon_as_answer_icon?: boolean
|
||||
}
|
||||
|
||||
export type TrialTagResponse = {
|
||||
id: string
|
||||
name: string
|
||||
type: string
|
||||
export type TrialTag = {
|
||||
id?: string
|
||||
name?: string
|
||||
type?: string
|
||||
}
|
||||
|
||||
export type TrialWorkflowPartialResponse = {
|
||||
created_at?: number | null
|
||||
created_by?: string | null
|
||||
id: string
|
||||
updated_at?: number | null
|
||||
updated_by?: string | null
|
||||
export type TrialWorkflowPartial = {
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
id?: string
|
||||
updated_at?: number
|
||||
updated_by?: string
|
||||
}
|
||||
|
||||
export type JsonValue
|
||||
@ -231,15 +262,15 @@ export type JsonValue
|
||||
| Array<unknown>
|
||||
| null
|
||||
|
||||
export type TrialDatasetResponse = {
|
||||
created_at?: number | null
|
||||
created_by?: string | null
|
||||
data_source_type?: string | null
|
||||
description?: string | null
|
||||
id: string
|
||||
indexing_technique?: string | null
|
||||
name: string
|
||||
permission?: string | null
|
||||
export type TrialDataset = {
|
||||
created_at?: number
|
||||
created_by?: string
|
||||
data_source_type?: string
|
||||
description?: string
|
||||
id?: string
|
||||
indexing_technique?: string
|
||||
name?: string
|
||||
permission?: string
|
||||
permission_keys?: Array<string>
|
||||
}
|
||||
|
||||
@ -255,39 +286,53 @@ export type SystemParameters = {
|
||||
workflow_file_upload_limit: number
|
||||
}
|
||||
|
||||
export type JsonObject2 = {
|
||||
[key: string]: unknown
|
||||
export type TrialConversationVariable = {
|
||||
description?: string
|
||||
id?: string
|
||||
name?: string
|
||||
value?:
|
||||
| string
|
||||
| number
|
||||
| number
|
||||
| boolean
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
| null
|
||||
value_type?: string
|
||||
}
|
||||
|
||||
export type TrialWorkflowAccount = {
|
||||
email?: string | null
|
||||
id: string
|
||||
name?: string | null
|
||||
export type TrialSimpleAccount = {
|
||||
email?: string
|
||||
id?: string
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type TrialWorkflowGraph = {
|
||||
edges: Array<JsonObject2>
|
||||
nodes: Array<JsonObject2>
|
||||
viewport: TrialWorkflowViewport
|
||||
}
|
||||
|
||||
export type TrialAppAgentMode = {
|
||||
enabled?: boolean | null
|
||||
strategy?: string | null
|
||||
tools?: Array<JsonObject2>
|
||||
}
|
||||
|
||||
export type TrialAppModel = {
|
||||
completion_params?: JsonObject2
|
||||
mode?: string | null
|
||||
name: string
|
||||
provider: string
|
||||
}
|
||||
|
||||
export type TrialWorkflowViewport = {
|
||||
x: number
|
||||
y: number
|
||||
zoom: number
|
||||
export type TrialPipelineVariable = {
|
||||
allow_file_extension?: Array<string>
|
||||
allow_file_upload_methods?: Array<string>
|
||||
allowed_file_types?: Array<string>
|
||||
belong_to_node_id?: string
|
||||
default_value?:
|
||||
| string
|
||||
| number
|
||||
| number
|
||||
| boolean
|
||||
| {
|
||||
[key: string]: unknown
|
||||
}
|
||||
| Array<unknown>
|
||||
| null
|
||||
label?: string
|
||||
max_length?: number
|
||||
options?: Array<string>
|
||||
placeholder?: string
|
||||
required?: boolean
|
||||
tooltips?: string
|
||||
type?: string
|
||||
unit?: string
|
||||
variable?: string
|
||||
}
|
||||
|
||||
export type GeneratedAppResponseWritable = JsonValue
|
||||
@ -319,7 +364,7 @@ export type GetTrialAppsByAppIdData = {
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdResponses = {
|
||||
200: TrialAppDetailResponse
|
||||
200: TrialAppDetailWithSite
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdResponse
|
||||
@ -387,7 +432,7 @@ export type GetTrialAppsByAppIdDatasetsData = {
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdDatasetsResponses = {
|
||||
200: TrialDatasetListResponse
|
||||
200: TrialDatasetList
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdDatasetsResponse
|
||||
@ -468,7 +513,7 @@ export type GetTrialAppsByAppIdWorkflowsData = {
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdWorkflowsResponses = {
|
||||
200: TrialWorkflowResponse
|
||||
200: TrialWorkflow
|
||||
}
|
||||
|
||||
export type GetTrialAppsByAppIdWorkflowsResponse
|
||||
|
||||
@ -90,74 +90,169 @@ export const zSimpleResultResponse = z.object({
|
||||
result: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialDeletedToolResponse
|
||||
*/
|
||||
export const zTrialDeletedToolResponse = z.object({
|
||||
provider_id: z.string(),
|
||||
tool_name: z.string(),
|
||||
type: z.string(),
|
||||
export const zTrialDeletedTool = z.object({
|
||||
provider_id: z.string().optional(),
|
||||
tool_name: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
})
|
||||
|
||||
export const zTrialIconType = z.enum(['emoji', 'image', 'link'])
|
||||
|
||||
export const zTrialAppMode = z.enum([
|
||||
'advanced-chat',
|
||||
'agent-chat',
|
||||
'chat',
|
||||
'completion',
|
||||
'workflow',
|
||||
])
|
||||
|
||||
/**
|
||||
* TrialSiteResponse
|
||||
*/
|
||||
export const zTrialSiteResponse = z.object({
|
||||
access_token: z.string().nullish(),
|
||||
app_base_url: z.string().nullish(),
|
||||
chat_color_theme: z.string().nullish(),
|
||||
chat_color_theme_inverted: z.boolean().nullish(),
|
||||
code: z.string().nullish(),
|
||||
copyright: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
custom_disclaimer: z.string().nullish(),
|
||||
customize_domain: z.string().nullish(),
|
||||
customize_token_strategy: z.string().nullish(),
|
||||
default_language: z.string(),
|
||||
description: z.string().nullish(),
|
||||
icon: z.string().nullish(),
|
||||
icon_background: z.string().nullish(),
|
||||
icon_type: zTrialIconType.nullish(),
|
||||
icon_url: z.string().nullish(),
|
||||
input_placeholder: z.string().nullish(),
|
||||
privacy_policy: z.string().nullish(),
|
||||
prompt_public: z.boolean().nullish(),
|
||||
show_workflow_steps: z.boolean().nullish(),
|
||||
title: z.string(),
|
||||
updated_at: z.int().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
use_icon_as_answer_icon: z.boolean().nullish(),
|
||||
export const zTrialAppModelConfig = z.object({
|
||||
agent_mode: z.record(z.string(), z.unknown()).optional(),
|
||||
annotation_reply: z.record(z.string(), z.unknown()).optional(),
|
||||
chat_prompt_config: z.record(z.string(), z.unknown()).optional(),
|
||||
completion_prompt_config: z.record(z.string(), z.unknown()).optional(),
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
dataset_configs: z.record(z.string(), z.unknown()).optional(),
|
||||
dataset_query_variable: z.string().optional(),
|
||||
external_data_tools: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
file_upload: z.record(z.string(), z.unknown()).optional(),
|
||||
model: z.record(z.string(), z.unknown()).optional(),
|
||||
more_like_this: z.record(z.string(), z.unknown()).optional(),
|
||||
opening_statement: z.string().optional(),
|
||||
pre_prompt: z.string().optional(),
|
||||
prompt_type: z.string().optional(),
|
||||
retriever_resource: z.record(z.string(), z.unknown()).optional(),
|
||||
sensitive_word_avoidance: z.record(z.string(), z.unknown()).optional(),
|
||||
speech_to_text: z.record(z.string(), z.unknown()).optional(),
|
||||
suggested_questions: z.array(z.string()).optional(),
|
||||
suggested_questions_after_answer: z.record(z.string(), z.unknown()).optional(),
|
||||
text_to_speech: z.record(z.string(), z.unknown()).optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: z.string().optional(),
|
||||
user_input_form: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialTagResponse
|
||||
*/
|
||||
export const zTrialTagResponse = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
export const zTrialSite = z.object({
|
||||
access_token: z.string().optional(),
|
||||
app_base_url: z.string().optional(),
|
||||
chat_color_theme: z.string().optional(),
|
||||
chat_color_theme_inverted: z.boolean().optional(),
|
||||
code: z.string().optional(),
|
||||
copyright: z.string().optional(),
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
custom_disclaimer: z.string().optional(),
|
||||
customize_domain: z.string().optional(),
|
||||
customize_token_strategy: z.string().optional(),
|
||||
default_language: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
icon: z.string().optional(),
|
||||
icon_background: z.string().optional(),
|
||||
icon_type: z.string().optional(),
|
||||
icon_url: z.string().optional(),
|
||||
privacy_policy: z.string().optional(),
|
||||
prompt_public: z.boolean().optional(),
|
||||
show_workflow_steps: z.boolean().optional(),
|
||||
title: z.string().optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: z.string().optional(),
|
||||
use_icon_as_answer_icon: z.boolean().optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialWorkflowPartialResponse
|
||||
*/
|
||||
export const zTrialWorkflowPartialResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
id: z.string(),
|
||||
updated_at: z.int().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
export const zTrialTag = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
})
|
||||
|
||||
export const zTrialWorkflowPartial = z.object({
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: z.string().optional(),
|
||||
})
|
||||
|
||||
export const zTrialAppDetailWithSite = z.object({
|
||||
access_mode: z.string().optional(),
|
||||
api_base_url: z.string().optional(),
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
deleted_tools: z.array(zTrialDeletedTool).optional(),
|
||||
description: z.string().optional(),
|
||||
enable_api: z.boolean().optional(),
|
||||
enable_site: z.boolean().optional(),
|
||||
icon: z.string().optional(),
|
||||
icon_background: z.string().optional(),
|
||||
icon_type: z.string().optional(),
|
||||
icon_url: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
max_active_requests: z.int().optional(),
|
||||
mode: z.string().optional(),
|
||||
model_config: zTrialAppModelConfig.optional(),
|
||||
name: z.string().optional(),
|
||||
permission_keys: z.array(z.string()).optional(),
|
||||
site: zTrialSite.optional(),
|
||||
tags: z.array(zTrialTag).optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: z.string().optional(),
|
||||
use_icon_as_answer_icon: z.boolean().optional(),
|
||||
workflow: zTrialWorkflowPartial.optional(),
|
||||
})
|
||||
|
||||
export const zJsonValue = z
|
||||
@ -176,30 +271,32 @@ export const zJsonValue = z
|
||||
*/
|
||||
export const zGeneratedAppResponse = zJsonValue
|
||||
|
||||
/**
|
||||
* TrialDatasetResponse
|
||||
*/
|
||||
export const zTrialDatasetResponse = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
data_source_type: z.string().nullish(),
|
||||
description: z.string().nullish(),
|
||||
id: z.string(),
|
||||
indexing_technique: z.string().nullish(),
|
||||
name: z.string(),
|
||||
permission: z.string().nullish(),
|
||||
export const zTrialDataset = z.object({
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: z.string().optional(),
|
||||
data_source_type: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
indexing_technique: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
permission: z.string().optional(),
|
||||
permission_keys: z.array(z.string()).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialDatasetListResponse
|
||||
*/
|
||||
export const zTrialDatasetListResponse = z.object({
|
||||
data: z.array(zTrialDatasetResponse),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
total: z.int(),
|
||||
export const zTrialDatasetList = z.object({
|
||||
data: z.array(zTrialDataset).optional(),
|
||||
has_more: z.boolean().optional(),
|
||||
limit: z.int().optional(),
|
||||
page: z.int().optional(),
|
||||
total: z.int().optional(),
|
||||
})
|
||||
|
||||
export const zJsonObject = z.record(z.string(), z.unknown())
|
||||
@ -233,133 +330,87 @@ export const zParameters = z.object({
|
||||
user_input_form: z.array(zJsonObject),
|
||||
})
|
||||
|
||||
export const zJsonObject2 = z.record(z.string(), z.unknown())
|
||||
|
||||
/**
|
||||
* TrialWorkflowAccount
|
||||
*/
|
||||
export const zTrialWorkflowAccount = z.object({
|
||||
email: z.string().nullish(),
|
||||
id: z.string(),
|
||||
name: z.string().nullish(),
|
||||
export const zTrialConversationVariable = z.object({
|
||||
description: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
name: 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(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialAppAgentMode
|
||||
*/
|
||||
export const zTrialAppAgentMode = z.object({
|
||||
enabled: z.boolean().nullish(),
|
||||
strategy: z.string().nullish(),
|
||||
tools: z.array(zJsonObject2).optional(),
|
||||
export const zTrialSimpleAccount = z.object({
|
||||
email: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialAppModel
|
||||
*/
|
||||
export const zTrialAppModel = z.object({
|
||||
completion_params: zJsonObject2.optional(),
|
||||
mode: z.string().nullish(),
|
||||
name: z.string(),
|
||||
provider: z.string(),
|
||||
export const zTrialPipelineVariable = z.object({
|
||||
allow_file_extension: z.array(z.string()).optional(),
|
||||
allow_file_upload_methods: z.array(z.string()).optional(),
|
||||
allowed_file_types: z.array(z.string()).optional(),
|
||||
belong_to_node_id: z.string().optional(),
|
||||
default_value: z
|
||||
.union([
|
||||
z.string(),
|
||||
z.int(),
|
||||
z.number(),
|
||||
z.boolean(),
|
||||
z.record(z.string(), z.unknown()),
|
||||
z.array(z.unknown()),
|
||||
])
|
||||
.nullish(),
|
||||
label: z.string().optional(),
|
||||
max_length: z.int().optional(),
|
||||
options: z.array(z.string()).optional(),
|
||||
placeholder: z.string().optional(),
|
||||
required: z.boolean().optional(),
|
||||
tooltips: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
unit: z.string().optional(),
|
||||
variable: z.string().optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialAppModelConfigResponse
|
||||
*/
|
||||
export const zTrialAppModelConfigResponse = z.object({
|
||||
agent_mode: zTrialAppAgentMode.nullish(),
|
||||
annotation_reply: zJsonObject2.nullish(),
|
||||
chat_prompt_config: zJsonObject2.nullish(),
|
||||
completion_prompt_config: zJsonObject2.nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
dataset_configs: zJsonObject2.nullish(),
|
||||
dataset_query_variable: z.string().nullish(),
|
||||
external_data_tools: z.array(zJsonObject2).optional(),
|
||||
file_upload: zJsonObject2.nullish(),
|
||||
model: zTrialAppModel.nullish(),
|
||||
more_like_this: zJsonObject2.nullish(),
|
||||
opening_statement: z.string().nullish(),
|
||||
pre_prompt: z.string().nullish(),
|
||||
prompt_type: z.string().nullish(),
|
||||
retriever_resource: zJsonObject2.nullish(),
|
||||
sensitive_word_avoidance: zJsonObject2.nullish(),
|
||||
speech_to_text: zJsonObject2.nullish(),
|
||||
suggested_questions: z.array(z.string()).optional(),
|
||||
suggested_questions_after_answer: zJsonObject2.nullish(),
|
||||
text_to_speech: zJsonObject2.nullish(),
|
||||
updated_at: z.int().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
user_input_form: z.array(zJsonObject2).optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialAppDetailResponse
|
||||
*/
|
||||
export const zTrialAppDetailResponse = z.object({
|
||||
access_mode: z.string().nullish(),
|
||||
api_base_url: z.string().nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
created_by: z.string().nullish(),
|
||||
deleted_tools: z.array(zTrialDeletedToolResponse).optional(),
|
||||
description: z.string().nullish(),
|
||||
enable_api: z.boolean(),
|
||||
enable_site: z.boolean(),
|
||||
icon: z.string().nullish(),
|
||||
icon_background: z.string().nullish(),
|
||||
icon_type: zTrialIconType.nullish(),
|
||||
icon_url: z.string().nullish(),
|
||||
id: z.string(),
|
||||
max_active_requests: z.int().nullish(),
|
||||
mode: zTrialAppMode,
|
||||
model_config: zTrialAppModelConfigResponse.nullish(),
|
||||
name: z.string(),
|
||||
permission_keys: z.array(z.string()).optional(),
|
||||
site: zTrialSiteResponse,
|
||||
tags: z.array(zTrialTagResponse).optional(),
|
||||
updated_at: z.int().nullish(),
|
||||
updated_by: z.string().nullish(),
|
||||
use_icon_as_answer_icon: z.boolean().nullish(),
|
||||
workflow: zTrialWorkflowPartialResponse.nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialWorkflowViewport
|
||||
*/
|
||||
export const zTrialWorkflowViewport = z.object({
|
||||
x: z.number(),
|
||||
y: z.number(),
|
||||
zoom: z.number(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialWorkflowGraph
|
||||
*/
|
||||
export const zTrialWorkflowGraph = z.object({
|
||||
edges: z.array(zJsonObject2),
|
||||
nodes: z.array(zJsonObject2),
|
||||
viewport: zTrialWorkflowViewport,
|
||||
})
|
||||
|
||||
/**
|
||||
* TrialWorkflowResponse
|
||||
*/
|
||||
export const zTrialWorkflowResponse = z.object({
|
||||
conversation_variables: z.array(zJsonObject2).optional(),
|
||||
created_at: z.int().nullish(),
|
||||
created_by: zTrialWorkflowAccount.nullish(),
|
||||
environment_variables: z.array(zJsonObject2).optional(),
|
||||
features: zJsonObject2.optional(),
|
||||
graph: zTrialWorkflowGraph,
|
||||
hash: z.string().nullish(),
|
||||
id: z.string(),
|
||||
marked_comment: z.string().nullish(),
|
||||
marked_name: z.string().nullish(),
|
||||
rag_pipeline_variables: z.array(zJsonObject2).optional(),
|
||||
tool_published: z.boolean().nullish(),
|
||||
updated_at: z.int().nullish(),
|
||||
updated_by: zTrialWorkflowAccount.nullish(),
|
||||
version: z.string().nullish(),
|
||||
export const zTrialWorkflow = z.object({
|
||||
conversation_variables: z.array(zTrialConversationVariable).optional(),
|
||||
created_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
created_by: zTrialSimpleAccount.optional(),
|
||||
environment_variables: z.array(z.record(z.string(), z.unknown())).optional(),
|
||||
features: z.record(z.string(), z.unknown()).optional(),
|
||||
graph: z.record(z.string(), z.unknown()).optional(),
|
||||
hash: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
marked_comment: z.string().optional(),
|
||||
marked_name: z.string().optional(),
|
||||
rag_pipeline_variables: z.array(zTrialPipelineVariable).optional(),
|
||||
tool_published: z.boolean().optional(),
|
||||
updated_at: z.coerce
|
||||
.bigint()
|
||||
.min(BigInt('-9223372036854775808'), {
|
||||
error: 'Invalid value: Expected int64 to be >= -9223372036854775808',
|
||||
})
|
||||
.max(BigInt('9223372036854775807'), {
|
||||
error: 'Invalid value: Expected int64 to be <= 9223372036854775807',
|
||||
})
|
||||
.optional(),
|
||||
updated_by: zTrialSimpleAccount.optional(),
|
||||
version: z.string().optional(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -394,7 +445,7 @@ export const zGetTrialAppsByAppIdPath = z.object({
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetTrialAppsByAppIdResponse = zTrialAppDetailResponse
|
||||
export const zGetTrialAppsByAppIdResponse = zTrialAppDetailWithSite
|
||||
|
||||
export const zPostTrialAppsByAppIdAudioToTextPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
@ -440,7 +491,7 @@ export const zGetTrialAppsByAppIdDatasetsQuery = z.object({
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetTrialAppsByAppIdDatasetsResponse = zTrialDatasetListResponse
|
||||
export const zGetTrialAppsByAppIdDatasetsResponse = zTrialDatasetList
|
||||
|
||||
export const zGetTrialAppsByAppIdMessagesByMessageIdSuggestedQuestionsPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
@ -489,7 +540,7 @@ export const zGetTrialAppsByAppIdWorkflowsPath = z.object({
|
||||
/**
|
||||
* Success
|
||||
*/
|
||||
export const zGetTrialAppsByAppIdWorkflowsResponse = zTrialWorkflowResponse
|
||||
export const zGetTrialAppsByAppIdWorkflowsResponse = zTrialWorkflow
|
||||
|
||||
export const zPostTrialAppsByAppIdWorkflowsRunBody = zWorkflowRunRequest
|
||||
|
||||
|
||||
@ -215,7 +215,7 @@ describe('App Publisher Flow', () => {
|
||||
fireEvent.click(screen.getByText('common.openInExplore'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockToastError).toHaveBeenCalledWith('No app found in Explore')
|
||||
expect(mockToastError).toHaveBeenCalledWith('notPublishedYet')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -562,7 +562,7 @@ describe('AppPublisher', () => {
|
||||
fireEvent.click(screen.getByText('publisher-open-in-explore'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockToastError).toHaveBeenCalledWith('No app found in Explore')
|
||||
expect(mockToastError).toHaveBeenCalledWith('notPublishedYet')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -231,7 +231,7 @@ export function AppPublisher({
|
||||
const { installed_apps } = await fetchInstalledAppList(appDetail.id)
|
||||
if (installed_apps?.length > 0)
|
||||
return `${basePath}${buildInstalledAppPath(installed_apps[0]!.id)}`
|
||||
throw new Error('No app found in Explore')
|
||||
throw new Error(t('notPublishedYet', { ns: 'app' }))
|
||||
}, {
|
||||
onError: (err) => {
|
||||
toast.error(`${err.message || err}`)
|
||||
|
||||
@ -14,6 +14,10 @@ import { StarredAppCard } from '../starred-app-card'
|
||||
|
||||
let mockWebappAuthEnabled = false
|
||||
let mockRbacEnabled = true
|
||||
const mockUserCanAccessApp = vi.hoisted(() => ({
|
||||
result: true as boolean | undefined,
|
||||
isLoading: false,
|
||||
}))
|
||||
|
||||
const render = (ui: React.ReactElement) => renderWithSystemFeatures(ui, {
|
||||
systemFeatures: {
|
||||
@ -118,15 +122,15 @@ vi.mock('@/service/explore', () => ({
|
||||
|
||||
vi.mock('@/service/access-control', () => ({
|
||||
useGetUserCanAccessApp: () => ({
|
||||
data: { result: true },
|
||||
isLoading: false,
|
||||
data: mockUserCanAccessApp.result === undefined ? undefined : { result: mockUserCanAccessApp.result },
|
||||
isLoading: mockUserCanAccessApp.isLoading,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/access-control/use-app-access-control', () => ({
|
||||
useGetUserCanAccessApp: () => ({
|
||||
data: { result: true },
|
||||
isLoading: false,
|
||||
data: mockUserCanAccessApp.result === undefined ? undefined : { result: mockUserCanAccessApp.result },
|
||||
isLoading: mockUserCanAccessApp.isLoading,
|
||||
}),
|
||||
}))
|
||||
|
||||
@ -380,6 +384,8 @@ describe('AppCard', () => {
|
||||
mockOpenAsyncWindow.mockReset()
|
||||
mockWebappAuthEnabled = false
|
||||
mockRbacEnabled = true
|
||||
mockUserCanAccessApp.result = true
|
||||
mockUserCanAccessApp.isLoading = false
|
||||
mockDeleteMutationPending = false
|
||||
mockToggleStarMutationPending = false
|
||||
mockAppContext.isCurrentWorkspaceEditor = true
|
||||
@ -1733,6 +1739,28 @@ describe('AppCard', () => {
|
||||
})
|
||||
|
||||
describe('Open in Explore - No App Found', () => {
|
||||
it('should tell workflow users to publish before opening in explore', async () => {
|
||||
const workflowApp = createMockApp({
|
||||
mode: AppModeEnum.WORKFLOW,
|
||||
workflow: undefined,
|
||||
})
|
||||
render(<AppCard app={workflowApp} />)
|
||||
|
||||
fireEvent.click(screen.getByTestId('dropdown-menu-trigger'))
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('app.openInExplore')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByText('app.openInExplore'))
|
||||
|
||||
expect(mockOpenAsyncWindow).not.toHaveBeenCalled()
|
||||
expect(exploreService.fetchInstalledAppList).not.toHaveBeenCalled()
|
||||
expect(toastMocks.record).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'app.notPublishedYet',
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle case when installed_apps is empty array', async () => {
|
||||
(exploreService.fetchInstalledAppList as Mock).mockResolvedValueOnce({ installed_apps: [] })
|
||||
|
||||
@ -1756,6 +1784,10 @@ describe('AppCard', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(exploreService.fetchInstalledAppList).toHaveBeenCalled()
|
||||
expect(toastMocks.record).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'app.notPublishedYet',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1944,6 +1976,31 @@ describe('AppCard', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep open in explore visible for unpublished workflow apps while access check is pending', async () => {
|
||||
mockUserCanAccessApp.result = false
|
||||
mockUserCanAccessApp.isLoading = true
|
||||
const workflowApp = createMockApp({
|
||||
mode: AppModeEnum.WORKFLOW,
|
||||
workflow: undefined,
|
||||
})
|
||||
|
||||
render(<AppCard app={workflowApp} />)
|
||||
|
||||
fireEvent.click(screen.getByTestId('dropdown-menu-trigger'))
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('app.openInExplore')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByText('app.openInExplore'))
|
||||
|
||||
expect(mockOpenAsyncWindow).not.toHaveBeenCalled()
|
||||
expect(exploreService.fetchInstalledAppList).not.toHaveBeenCalled()
|
||||
expect(toastMocks.record).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'app.notPublishedYet',
|
||||
})
|
||||
})
|
||||
|
||||
it('should close access control modal when onClose is called', async () => {
|
||||
render(<AppCard app={mockApp} />)
|
||||
|
||||
|
||||
@ -90,6 +90,11 @@ const ACCESS_MODE_LABEL_KEYS = {
|
||||
[AccessMode.EXTERNAL_MEMBERS]: 'accessItemsDescription.external',
|
||||
} as const
|
||||
|
||||
const APP_MODES_REQUIRING_PUBLISHED_WORKFLOW_IN_EXPLORE = new Set<AppModeEnum>([
|
||||
AppModeEnum.ADVANCED_CHAT,
|
||||
AppModeEnum.WORKFLOW,
|
||||
])
|
||||
|
||||
type AppCardProps = {
|
||||
app: App
|
||||
onlineUsers?: WorkflowOnlineUser[]
|
||||
@ -103,6 +108,10 @@ type AppAccessModeIconProps = {
|
||||
|
||||
const getAppResourceMaintainer = (app: App) => app.maintainer
|
||||
|
||||
function requiresPublishedWorkflowInExplore(app: App) {
|
||||
return APP_MODES_REQUIRING_PUBLISHED_WORKFLOW_IN_EXPLORE.has(app.mode)
|
||||
}
|
||||
|
||||
function AppAccessModeIcon({ accessMode }: AppAccessModeIconProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -182,12 +191,17 @@ function AppCardOperationsMenu({
|
||||
async function handleOpenInstalledApp(e: MouseEvent<HTMLElement>) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
if (requiresPublishedWorkflowInExplore(app) && !app.workflow?.id) {
|
||||
toast.error(t('notPublishedYet', { ns: 'app' }))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await openAsyncWindow(async () => {
|
||||
const { installed_apps } = await fetchInstalledAppList(app.id)
|
||||
if (installed_apps?.length > 0)
|
||||
return `${basePath}${buildInstalledAppPath(installed_apps[0]!.id)}`
|
||||
throw new Error('No app found in Explore')
|
||||
throw new Error(t('notPublishedYet', { ns: 'app' }))
|
||||
}, {
|
||||
onError: (err) => {
|
||||
toast.error(`${err.message || err}`)
|
||||
@ -272,10 +286,12 @@ function AppCardOperationsMenuContent(props: AppCardOperationsMenuContentProps)
|
||||
appId: props.app.id,
|
||||
enabled: systemFeatures.webapp_auth.enabled,
|
||||
})
|
||||
const needsPublishBeforeExplore = requiresPublishedWorkflowInExplore(props.app) && !props.app.workflow?.id
|
||||
|
||||
const shouldShowOpenInExploreOption = !props.app.has_draft_trigger
|
||||
&& (
|
||||
!systemFeatures.webapp_auth.enabled
|
||||
needsPublishBeforeExplore
|
||||
|| !systemFeatures.webapp_auth.enabled
|
||||
|| (!isGettingUserCanAccessApp && Boolean(userCanAccessApp?.result))
|
||||
)
|
||||
|
||||
|
||||
@ -68,9 +68,9 @@ const AppInfo: FC<Props> = ({
|
||||
<AppIcon
|
||||
size="large"
|
||||
iconType={appDetail.site.icon_type}
|
||||
icon={appDetail.site.icon ?? undefined}
|
||||
background={appDetail.site.icon_background ?? undefined}
|
||||
imageUrl={appDetail.site.icon_url ?? undefined}
|
||||
icon={appDetail.site.icon}
|
||||
background={appDetail.site.icon_background}
|
||||
imageUrl={appDetail.site.icon_url}
|
||||
/>
|
||||
<AppTypeIcon
|
||||
wrapperClassName="absolute -bottom-0.5 -right-0.5 w-4 h-4 shadow-sm"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
|
||||
import type { ToolNodeType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import type { TryAppInfo } from '@/service/try-app'
|
||||
import type { AgentTool } from '@/types/app'
|
||||
import { uniqBy } from 'es-toolkit/compat'
|
||||
@ -66,33 +68,6 @@ const getIconUrl = (providerId: string, type: ProviderType) => {
|
||||
return `${MARKETPLACE_API_PREFIX}/plugins/${organization}/${pluginName}/icon`
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
const isAgentTool = (value: unknown): value is AgentTool => {
|
||||
if (!isRecord(value))
|
||||
return false
|
||||
|
||||
return typeof value.provider_id === 'string'
|
||||
&& typeof value.tool_label === 'string'
|
||||
&& value.enabled === true
|
||||
}
|
||||
|
||||
const hasLLMRequirementData = (value: unknown): value is { model: { name: string, provider: string } } => {
|
||||
if (!isRecord(value) || !isRecord(value.model))
|
||||
return false
|
||||
|
||||
return typeof value.model.name === 'string' && typeof value.model.provider === 'string'
|
||||
}
|
||||
|
||||
const hasToolRequirementData = (value: unknown): value is { provider_id: string, tool_label: string } => {
|
||||
if (!isRecord(value))
|
||||
return false
|
||||
|
||||
return typeof value.provider_id === 'string' && typeof value.tool_label === 'string'
|
||||
}
|
||||
|
||||
const useGetRequirements = ({ appDetail, appId }: Params) => {
|
||||
const isBasic = ['chat', 'completion', 'agent-chat'].includes(appDetail.mode)
|
||||
const isAgent = appDetail.mode === 'agent-chat'
|
||||
@ -100,44 +75,41 @@ const useGetRequirements = ({ appDetail, appId }: Params) => {
|
||||
const { data: flowData } = useGetTryAppFlowPreview(appId, isBasic)
|
||||
|
||||
const requirements: RequirementItem[] = []
|
||||
const modelConfig = appDetail.model_config
|
||||
const model = modelConfig?.model
|
||||
if (isBasic && model) {
|
||||
const modelProvider = model.provider
|
||||
const name = model.provider.split('/').pop() || ''
|
||||
if (isBasic) {
|
||||
const modelProvider = appDetail.model_config.model.provider
|
||||
const name = appDetail.model_config.model.provider.split('/').pop() || ''
|
||||
requirements.push({
|
||||
name,
|
||||
iconUrl: getIconUrl(modelProvider, 'model'),
|
||||
})
|
||||
}
|
||||
if (isAgent && modelConfig?.agent_mode?.tools) {
|
||||
requirements.push(...modelConfig.agent_mode.tools.filter(isAgentTool).map(tool => ({
|
||||
name: tool.tool_label,
|
||||
iconUrl: getIconUrl(tool.provider_id, 'tool'),
|
||||
})))
|
||||
if (isAgent) {
|
||||
requirements.push(...appDetail.model_config.agent_mode.tools.filter(data => (data as AgentTool).enabled).map((data) => {
|
||||
const tool = data as AgentTool
|
||||
return {
|
||||
name: tool.tool_label,
|
||||
iconUrl: getIconUrl(tool.provider_id, 'tool'),
|
||||
}
|
||||
}))
|
||||
}
|
||||
if (isAdvanced && flowData && flowData?.graph?.nodes?.length > 0) {
|
||||
const nodes = flowData.graph.nodes
|
||||
requirements.push(...nodes.flatMap((node) => {
|
||||
const data = isRecord(node.data) ? node.data : null
|
||||
if (data?.type !== BlockEnum.LLM || !hasLLMRequirementData(data))
|
||||
return []
|
||||
|
||||
return [{
|
||||
const llmNodes = nodes.filter(node => node.data.type === BlockEnum.LLM)
|
||||
requirements.push(...llmNodes.map((node) => {
|
||||
const data = node.data as LLMNodeType
|
||||
return {
|
||||
name: data.model.name,
|
||||
iconUrl: getIconUrl(data.model.provider, 'model'),
|
||||
}]
|
||||
}
|
||||
}))
|
||||
|
||||
requirements.push(...nodes.flatMap((node) => {
|
||||
const data = isRecord(node.data) ? node.data : null
|
||||
if (data?.type !== BlockEnum.Tool || !hasToolRequirementData(data))
|
||||
return []
|
||||
|
||||
return [{
|
||||
const toolNodes = nodes.filter(node => node.data.type === BlockEnum.Tool)
|
||||
requirements.push(...toolNodes.map((node) => {
|
||||
const data = node.data as ToolNodeType
|
||||
return {
|
||||
name: data.tool_label,
|
||||
iconUrl: getIconUrl(data.provider_id, 'tool'),
|
||||
}]
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@ -70,9 +70,9 @@ const TryApp: FC<Props> = ({
|
||||
<AppIcon
|
||||
size="large"
|
||||
iconType={appDetail.site.icon_type}
|
||||
icon={appDetail.site.icon ?? undefined}
|
||||
background={appDetail.site.icon_background ?? undefined}
|
||||
imageUrl={appDetail.site.icon_url ?? undefined}
|
||||
icon={appDetail.site.icon}
|
||||
background={appDetail.site.icon_background}
|
||||
imageUrl={appDetail.site.icon_url}
|
||||
/>
|
||||
<div className="grow truncate system-md-semibold text-text-primary" title={appDetail.name}>{appDetail.name}</div>
|
||||
</div>
|
||||
|
||||
@ -4,8 +4,7 @@ import type { FC } from 'react'
|
||||
import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types'
|
||||
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { ModelConfig } from '@/models/debug'
|
||||
import type { TryAppInfo } from '@/service/try-app'
|
||||
import type { PromptVariable } from '@/types/app'
|
||||
import type { ModelConfig as BackendModelConfig, PromptVariable } from '@/types/app'
|
||||
import { noop } from 'es-toolkit/function'
|
||||
import { clone } from 'es-toolkit/object'
|
||||
import * as React from 'react'
|
||||
@ -54,62 +53,6 @@ const defaultModelConfig = {
|
||||
dataSets: [],
|
||||
agentConfig: DEFAULT_AGENT_SETTING,
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
const getString = (value: unknown) => {
|
||||
return typeof value === 'string' ? value : ''
|
||||
}
|
||||
|
||||
const getBoolean = (value: unknown) => {
|
||||
return typeof value === 'boolean' ? value : false
|
||||
}
|
||||
|
||||
const getAgentTools = (agentMode: unknown) => {
|
||||
if (!isRecord(agentMode) || !Array.isArray(agentMode.tools))
|
||||
return []
|
||||
|
||||
return agentMode.tools.filter(isRecord)
|
||||
}
|
||||
|
||||
const isEnabledDatasetTool = (tool: Record<string, unknown>) => {
|
||||
return isRecord(tool.dataset) && tool.dataset.enabled === true
|
||||
}
|
||||
|
||||
const getDatasetConfigItems = (datasetConfigs: unknown) => {
|
||||
if (!isRecord(datasetConfigs) || !isRecord(datasetConfigs.datasets) || !Array.isArray(datasetConfigs.datasets.datasets))
|
||||
return []
|
||||
|
||||
return datasetConfigs.datasets.datasets.filter(isRecord)
|
||||
}
|
||||
|
||||
const getDatasetId = (value: Record<string, unknown>) => {
|
||||
if (typeof value.id === 'string')
|
||||
return value.id
|
||||
|
||||
if (isRecord(value.dataset) && typeof value.dataset.id === 'string')
|
||||
return value.dataset.id
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const normalizeExternalDataToolFormItem = (item: Record<string, unknown>) => {
|
||||
return {
|
||||
external_data_tool: {
|
||||
variable: getString(item.variable),
|
||||
label: getString(item.label),
|
||||
enabled: getBoolean(item.enabled),
|
||||
type: getString(item.type),
|
||||
config: isRecord(item.config) ? item.config : undefined,
|
||||
required: true,
|
||||
icon: getString(item.icon),
|
||||
icon_background: getString(item.icon_background),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const BasicAppPreview: FC<Props> = ({
|
||||
appId,
|
||||
}) => {
|
||||
@ -130,13 +73,16 @@ const BasicAppPreview: FC<Props> = ({
|
||||
const modelConfig = appDetail?.model_config
|
||||
if (!modelConfig)
|
||||
return []
|
||||
let datasets: any = null
|
||||
|
||||
const agentDatasetTools = getAgentTools(modelConfig.agent_mode).filter(isEnabledDatasetTool)
|
||||
const datasetConfigItems = getDatasetConfigItems(modelConfig.dataset_configs)
|
||||
const datasets = agentDatasetTools.length > 0 ? agentDatasetTools : datasetConfigItems
|
||||
if (modelConfig.agent_mode?.tools?.find(({ dataset }: any) => dataset?.enabled))
|
||||
datasets = modelConfig.agent_mode?.tools.filter(({ dataset }: any) => dataset?.enabled)
|
||||
// new dataset struct
|
||||
else if (modelConfig.dataset_configs.datasets?.datasets?.length > 0)
|
||||
datasets = modelConfig.dataset_configs?.datasets?.datasets
|
||||
|
||||
if (datasets?.length && datasets?.length > 0)
|
||||
return datasets.map(getDatasetId).filter((id): id is string => !!id)
|
||||
return datasets.map(({ dataset }: any) => dataset.id)
|
||||
|
||||
return []
|
||||
})()
|
||||
@ -144,29 +90,41 @@ const BasicAppPreview: FC<Props> = ({
|
||||
const dataSets = dataSetData?.data || []
|
||||
const isLoading = isLoadingAppDetail || isLoadingDatasets || isLoadingToolProviders
|
||||
|
||||
const modelConfig: ModelConfig = ((modelConfig?: TryAppInfo['model_config']) => {
|
||||
if (isLoading || !modelConfig?.model)
|
||||
const modelConfig: ModelConfig = ((modelConfig?: BackendModelConfig) => {
|
||||
if (isLoading || !modelConfig)
|
||||
return defaultModelConfig
|
||||
|
||||
const model = modelConfig.model
|
||||
const mode = model.mode === ModelModeType.chat || model.mode === ModelModeType.completion ? model.mode : ModelModeType.unset
|
||||
|
||||
const newModelConfig = {
|
||||
provider: correctModelProvider(model.provider),
|
||||
model_id: model.name,
|
||||
mode,
|
||||
mode: model.mode,
|
||||
configs: {
|
||||
prompt_template: modelConfig.pre_prompt || '',
|
||||
prompt_variables: userInputsFormToPromptVariables(
|
||||
[
|
||||
...(modelConfig.user_input_form || []),
|
||||
...(modelConfig.user_input_form as any),
|
||||
...(
|
||||
modelConfig.external_data_tools?.length
|
||||
? modelConfig.external_data_tools.map(normalizeExternalDataToolFormItem)
|
||||
? modelConfig.external_data_tools.map((item) => {
|
||||
return {
|
||||
external_data_tool: {
|
||||
variable: item.variable as string,
|
||||
label: item.label as string,
|
||||
enabled: item.enabled,
|
||||
type: item.type as string,
|
||||
config: item.config,
|
||||
required: true,
|
||||
icon: item.icon,
|
||||
icon_background: item.icon_background,
|
||||
},
|
||||
}
|
||||
})
|
||||
: []
|
||||
),
|
||||
],
|
||||
modelConfig.dataset_query_variable ?? undefined,
|
||||
modelConfig.dataset_query_variable,
|
||||
),
|
||||
},
|
||||
more_like_this: modelConfig.more_like_this,
|
||||
@ -185,25 +143,21 @@ const BasicAppPreview: FC<Props> = ({
|
||||
// eslint-disable-next-line style/multiline-ternary
|
||||
? ({
|
||||
max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
|
||||
...(isRecord(modelConfig.agent_mode) ? modelConfig.agent_mode : {}),
|
||||
...modelConfig.agent_mode,
|
||||
// remove dataset
|
||||
enabled: true, // modelConfig.agent_mode?.enabled is not correct. old app: the value of app with dataset's is always true
|
||||
tools: getAgentTools(modelConfig.agent_mode).filter((tool) => {
|
||||
tools: modelConfig.agent_mode?.tools.filter((tool: any) => {
|
||||
return !tool.dataset
|
||||
}).map((tool) => {
|
||||
const providerId = getString(tool.provider_id)
|
||||
const providerName = getString(tool.provider_name)
|
||||
const providerType = getString(tool.provider_type)
|
||||
const toolName = getString(tool.tool_name)
|
||||
const toolInCollectionList = collectionList?.find(c => providerId === c.id)
|
||||
}).map((tool: any) => {
|
||||
const toolInCollectionList = collectionList?.find(c => tool.provider_id === c.id)
|
||||
return {
|
||||
...tool,
|
||||
isDeleted: appDetail?.deleted_tools?.some(deletedTool => deletedTool.provider_id === providerId && deletedTool.tool_name === toolName),
|
||||
isDeleted: appDetail?.deleted_tools?.some((deletedTool: any) => deletedTool.id === tool.id && deletedTool.tool_name === tool.tool_name),
|
||||
notAuthor: toolInCollectionList?.is_team_authorization === false,
|
||||
...(providerType === 'builtin'
|
||||
...(tool.provider_type === 'builtin'
|
||||
? {
|
||||
provider_id: correctToolProvider(providerName, !!toolInCollectionList),
|
||||
provider_name: correctToolProvider(providerName, !!toolInCollectionList),
|
||||
provider_id: correctToolProvider(tool.provider_name, !!toolInCollectionList),
|
||||
provider_name: correctToolProvider(tool.provider_name, !!toolInCollectionList),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
'use client'
|
||||
import type { TrialWorkflowGraph } from '@dify/contracts/api/console/trial-apps/types.gen'
|
||||
import type { FC } from 'react'
|
||||
import type { Edge, Node } from '@/app/components/workflow/types'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import * as React from 'react'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import WorkflowPreview from '@/app/components/workflow/workflow-preview'
|
||||
import { useGetTryAppFlowPreview } from '@/service/use-try-app'
|
||||
|
||||
@ -14,119 +11,6 @@ type Props = {
|
||||
readonly className?: string
|
||||
}
|
||||
|
||||
const blockTypeMap: Record<string, BlockEnum> = {
|
||||
'agent': BlockEnum.Agent,
|
||||
'agent-v2': BlockEnum.AgentV2,
|
||||
'answer': BlockEnum.Answer,
|
||||
'assigner': BlockEnum.Assigner,
|
||||
'code': BlockEnum.Code,
|
||||
'datasource': BlockEnum.DataSource,
|
||||
'datasource-empty': BlockEnum.DataSourceEmpty,
|
||||
'document-extractor': BlockEnum.DocExtractor,
|
||||
'end': BlockEnum.End,
|
||||
'http-request': BlockEnum.HttpRequest,
|
||||
'human-input': BlockEnum.HumanInput,
|
||||
'if-else': BlockEnum.IfElse,
|
||||
'iteration': BlockEnum.Iteration,
|
||||
'iteration-start': BlockEnum.IterationStart,
|
||||
'knowledge-index': BlockEnum.KnowledgeBase,
|
||||
'knowledge-retrieval': BlockEnum.KnowledgeRetrieval,
|
||||
'list-operator': BlockEnum.ListFilter,
|
||||
'llm': BlockEnum.LLM,
|
||||
'loop': BlockEnum.Loop,
|
||||
'loop-end': BlockEnum.LoopEnd,
|
||||
'loop-start': BlockEnum.LoopStart,
|
||||
'parameter-extractor': BlockEnum.ParameterExtractor,
|
||||
'question-classifier': BlockEnum.QuestionClassifier,
|
||||
'start': BlockEnum.Start,
|
||||
'start-placeholder': BlockEnum.StartPlaceholder,
|
||||
'template-transform': BlockEnum.TemplateTransform,
|
||||
'tool': BlockEnum.Tool,
|
||||
'trigger-plugin': BlockEnum.TriggerPlugin,
|
||||
'trigger-schedule': BlockEnum.TriggerSchedule,
|
||||
'trigger-webhook': BlockEnum.TriggerWebhook,
|
||||
'variable-aggregator': BlockEnum.VariableAggregator,
|
||||
'variable-assigner': BlockEnum.VariableAssigner,
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
const getString = (value: unknown) => {
|
||||
return typeof value === 'string' ? value : undefined
|
||||
}
|
||||
|
||||
const getPosition = (value: unknown) => {
|
||||
if (!isRecord(value) || typeof value.x !== 'number' || typeof value.y !== 'number')
|
||||
return { x: 0, y: 0 }
|
||||
|
||||
return {
|
||||
x: value.x,
|
||||
y: value.y,
|
||||
}
|
||||
}
|
||||
|
||||
const getBlockType = (value: unknown) => {
|
||||
if (typeof value !== 'string')
|
||||
return null
|
||||
|
||||
return blockTypeMap[value] || null
|
||||
}
|
||||
|
||||
const normalizeWorkflowPreviewGraph = (graph: TrialWorkflowGraph) => {
|
||||
const nodes: Node[] = graph.nodes.flatMap((node) => {
|
||||
const id = getString(node.id)
|
||||
if (!id)
|
||||
return []
|
||||
|
||||
const data = isRecord(node.data) ? node.data : {}
|
||||
const type = getBlockType(data.type) || BlockEnum.Start
|
||||
const title = getString(data.title) || ''
|
||||
|
||||
return [{
|
||||
id,
|
||||
position: getPosition(node.position),
|
||||
...(getString(node.type) ? { type: getString(node.type) } : {}),
|
||||
data: {
|
||||
...data,
|
||||
desc: getString(data.desc) || '',
|
||||
title,
|
||||
type,
|
||||
},
|
||||
}]
|
||||
})
|
||||
const edges: Edge[] = graph.edges.flatMap((edge) => {
|
||||
const id = getString(edge.id)
|
||||
if (!id)
|
||||
return []
|
||||
|
||||
const data = isRecord(edge.data) ? edge.data : {}
|
||||
const sourceType = getBlockType(data.sourceType) || BlockEnum.Start
|
||||
const targetType = getBlockType(data.targetType) || BlockEnum.Start
|
||||
|
||||
return [{
|
||||
id,
|
||||
source: getString(edge.source) || '',
|
||||
target: getString(edge.target) || '',
|
||||
...(getString(edge.type) ? { type: getString(edge.type) } : {}),
|
||||
...(getString(edge.sourceHandle) ? { sourceHandle: getString(edge.sourceHandle) } : {}),
|
||||
...(getString(edge.targetHandle) ? { targetHandle: getString(edge.targetHandle) } : {}),
|
||||
data: {
|
||||
...data,
|
||||
sourceType,
|
||||
targetType,
|
||||
},
|
||||
}]
|
||||
})
|
||||
|
||||
return {
|
||||
nodes,
|
||||
edges,
|
||||
viewport: graph.viewport,
|
||||
}
|
||||
}
|
||||
|
||||
const FlowAppPreview: FC<Props> = ({
|
||||
appId,
|
||||
className,
|
||||
@ -142,11 +26,10 @@ const FlowAppPreview: FC<Props> = ({
|
||||
}
|
||||
if (!data)
|
||||
return null
|
||||
const previewGraph = normalizeWorkflowPreviewGraph(data.graph)
|
||||
return (
|
||||
<div className="size-full">
|
||||
<WorkflowPreview
|
||||
{...previewGraph}
|
||||
{...data.graph}
|
||||
className={cn(className)}
|
||||
miniMapToRight
|
||||
/>
|
||||
|
||||
65
web/contract/console/try-app.ts
Normal file
65
web/contract/console/try-app.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import type { ChatConfig } from '@/app/components/base/chat/types'
|
||||
import type { DataSetListResponse } from '@/models/datasets'
|
||||
import type { TryAppFlowPreview, TryAppInfo } from '@/models/try-app'
|
||||
import { trialApps } from '@dify/contracts/api/console/trial-apps/orpc.gen'
|
||||
import { type } from '@orpc/contract'
|
||||
import { base } from '../base'
|
||||
|
||||
export const trialAppInfoContract = base
|
||||
.route({
|
||||
path: '/trial-apps/{appId}',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<TryAppInfo>())
|
||||
|
||||
export const trialAppDatasetsContract = base
|
||||
.route({
|
||||
path: '/trial-apps/{appId}/datasets',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
query: {
|
||||
ids: string[]
|
||||
}
|
||||
}>())
|
||||
.output(type<DataSetListResponse>())
|
||||
|
||||
export const trialAppWorkflowsContract = base
|
||||
.route({
|
||||
path: '/trial-apps/{appId}/workflows',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<TryAppFlowPreview>())
|
||||
|
||||
export const trialAppParametersContract = base
|
||||
.route({
|
||||
path: '/trial-apps/{appId}/parameters',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
}>())
|
||||
.output(type<ChatConfig>())
|
||||
|
||||
export const trialAppsRouterContract = {
|
||||
...trialApps,
|
||||
info: trialAppInfoContract,
|
||||
datasets: trialAppDatasetsContract,
|
||||
parameters: trialAppParametersContract,
|
||||
workflows: trialAppWorkflowsContract,
|
||||
}
|
||||
@ -39,7 +39,6 @@ import { systemFeatures } from '@dify/contracts/api/console/system-features/orpc
|
||||
import { tagBindings } from '@dify/contracts/api/console/tag-bindings/orpc.gen'
|
||||
import { tags } from '@dify/contracts/api/console/tags/orpc.gen'
|
||||
import { test } from '@dify/contracts/api/console/test/orpc.gen'
|
||||
import { trialApps } from '@dify/contracts/api/console/trial-apps/orpc.gen'
|
||||
import { trialModels } from '@dify/contracts/api/console/trial-models/orpc.gen'
|
||||
import { website } from '@dify/contracts/api/console/website/orpc.gen'
|
||||
import { workflowGenerate } from '@dify/contracts/api/console/workflow-generate/orpc.gen'
|
||||
@ -52,6 +51,7 @@ import { modelProvidersRouterContract } from './console/model-providers'
|
||||
import { pluginsRouterContract } from './console/plugins'
|
||||
import { snippetsRouterContract } from './console/snippets'
|
||||
import { triggersRouterContract } from './console/trigger'
|
||||
import { trialAppsRouterContract } from './console/try-app'
|
||||
|
||||
const communityContract = {
|
||||
account,
|
||||
@ -95,7 +95,6 @@ const communityContract = {
|
||||
tagBindings,
|
||||
tags,
|
||||
test,
|
||||
trialApps,
|
||||
trialModels,
|
||||
website,
|
||||
workflow,
|
||||
@ -112,4 +111,5 @@ export const consoleRouterContract = {
|
||||
rbacAccessConfig: rbacAccessConfigContract,
|
||||
snippets: snippetsRouterContract,
|
||||
triggers: triggersRouterContract,
|
||||
trialApps: trialAppsRouterContract,
|
||||
}
|
||||
|
||||
21
web/models/try-app.ts
Normal file
21
web/models/try-app.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type { Viewport } from 'reactflow'
|
||||
import type { Edge, Node } from '@/app/components/workflow/types'
|
||||
import type { SiteInfo } from '@/models/share'
|
||||
import type { AppModeEnum, ModelConfig } from '@/types/app'
|
||||
|
||||
export type TryAppInfo = {
|
||||
name: string
|
||||
description: string
|
||||
mode: AppModeEnum
|
||||
site: SiteInfo
|
||||
model_config: ModelConfig
|
||||
deleted_tools: { id: string, tool_name: string }[]
|
||||
}
|
||||
|
||||
export type TryAppFlowPreview = {
|
||||
graph: {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
viewport: Viewport
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ const customConsoleContractLoaders: Record<string, () => Promise<AnyContractRout
|
||||
import('@/contract/console/access-control').then(({ rbacAccessConfigContract }) => wrapConsoleContract('rbacAccessConfig', rbacAccessConfigContract)),
|
||||
snippets: () => import('@/contract/console/snippets').then(({ snippetsRouterContract }) => wrapConsoleContract('snippets', snippetsRouterContract)),
|
||||
triggers: () => import('@/contract/console/trigger').then(({ triggersRouterContract }) => wrapConsoleContract('triggers', triggersRouterContract)),
|
||||
trialApps: () => import('@/contract/console/try-app').then(({ trialAppsRouterContract }) => wrapConsoleContract('trialApps', trialAppsRouterContract)),
|
||||
}
|
||||
|
||||
export async function loadConsoleContractForSegment(segment: string) {
|
||||
|
||||
@ -1,33 +1,26 @@
|
||||
import { consoleClient } from '@/service/client'
|
||||
import { get } from './base'
|
||||
import { fetchTryAppDatasets } from './try-app'
|
||||
|
||||
vi.mock('./base', () => ({
|
||||
get: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
trialApps: {
|
||||
byAppId: {
|
||||
datasets: {
|
||||
get: vi.fn(),
|
||||
},
|
||||
},
|
||||
info: vi.fn(),
|
||||
workflows: vi.fn(),
|
||||
parameters: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
describe('fetchTryAppDatasets', () => {
|
||||
it('serializes ids as repeated query params', async () => {
|
||||
vi.mocked(consoleClient.trialApps.byAppId.datasets.get).mockResolvedValue({
|
||||
data: [],
|
||||
has_more: false,
|
||||
limit: 20,
|
||||
page: 1,
|
||||
total: 0,
|
||||
})
|
||||
vi.mocked(get).mockResolvedValue({ data: [] })
|
||||
|
||||
await fetchTryAppDatasets('app-1', ['id-1', 'id-2'])
|
||||
|
||||
expect(consoleClient.trialApps.byAppId.datasets.get).toHaveBeenCalledWith({
|
||||
params: { app_id: 'app-1' },
|
||||
query: { ids: ['id-1', 'id-2'] },
|
||||
})
|
||||
expect(get).toHaveBeenCalledWith('/trial-apps/app-1/datasets?ids=id-1&ids=id-2')
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,292 +1,28 @@
|
||||
import type { ChatConfig } from '@/app/components/base/chat/types'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
import { ANNOTATION_DEFAULT, DEFAULT_AGENT_SETTING } from '@/config'
|
||||
import { PromptMode } from '@/models/debug'
|
||||
import type { DataSetListResponse } from '@/models/datasets'
|
||||
import type { TryAppFlowPreview, TryAppInfo } from '@/models/try-app'
|
||||
import qs from 'qs'
|
||||
import { consoleClient } from '@/service/client'
|
||||
import { Resolution, RETRIEVE_TYPE, TransferMethod, TtsAutoPlay } from '@/types/app'
|
||||
import { get } from './base'
|
||||
|
||||
type TryAppParameters = import('@dify/contracts/api/console/trial-apps/types.gen').Parameters
|
||||
|
||||
const transferMethodValues = new Set<string>(Object.values(TransferMethod))
|
||||
const supportUploadFileTypeValues = new Set<string>(Object.values(SupportUploadFileTypes))
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
export const fetchTryAppInfo = (appId: string): Promise<TryAppInfo> => {
|
||||
return consoleClient.trialApps.info({ params: { appId } })
|
||||
}
|
||||
|
||||
const getString = (value: unknown, fallback = '') => {
|
||||
return typeof value === 'string' ? value : fallback
|
||||
export const fetchTryAppDatasets = (appId: string, ids: string[]): Promise<DataSetListResponse> => {
|
||||
const queryString = qs.stringify({ ids }, { indices: false })
|
||||
const url = `/trial-apps/${encodeURIComponent(appId)}/datasets${queryString ? `?${queryString}` : ''}`
|
||||
|
||||
return get<DataSetListResponse>(url)
|
||||
}
|
||||
|
||||
const getOptionalString = (value: unknown) => {
|
||||
return typeof value === 'string' ? value : undefined
|
||||
export const fetchTryAppFlowPreview = (appId: string): Promise<TryAppFlowPreview> => {
|
||||
return consoleClient.trialApps.workflows({ params: { appId } })
|
||||
.then(res => res as TryAppFlowPreview)
|
||||
}
|
||||
|
||||
const getBoolean = (value: unknown, fallback = false) => {
|
||||
return typeof value === 'boolean' ? value : fallback
|
||||
export const fetchTryAppParams = (appId: string): Promise<ChatConfig> => {
|
||||
return consoleClient.trialApps.parameters({ params: { appId } })
|
||||
}
|
||||
|
||||
const getNumber = (value: unknown, fallback: number) => {
|
||||
return typeof value === 'number' ? value : fallback
|
||||
}
|
||||
|
||||
const getStringArray = (value: unknown) => {
|
||||
return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []
|
||||
}
|
||||
|
||||
const getStringRecord = (value: unknown) => {
|
||||
if (!isRecord(value))
|
||||
return undefined
|
||||
|
||||
const record: Record<string, string | undefined> = {}
|
||||
Object.entries(value).forEach(([key, item]) => {
|
||||
if (typeof item === 'string')
|
||||
record[key] = item
|
||||
})
|
||||
return record
|
||||
}
|
||||
|
||||
const normalizeEnabledConfig = (value: Record<string, unknown>, fallback = false) => {
|
||||
return {
|
||||
...value,
|
||||
enabled: getBoolean(value.enabled, fallback),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeTextToSpeechConfig = (value: Record<string, unknown>): ChatConfig['text_to_speech'] => {
|
||||
const autoPlay = getString(value.autoPlay)
|
||||
const config = { ...value }
|
||||
delete config.autoPlay
|
||||
return {
|
||||
...normalizeEnabledConfig(config),
|
||||
voice: getOptionalString(value.voice),
|
||||
language: getOptionalString(value.language),
|
||||
...(autoPlay === TtsAutoPlay.enabled || autoPlay === TtsAutoPlay.disabled ? { autoPlay } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeAnnotationReplyConfig = (value: Record<string, unknown>): ChatConfig['annotation_reply'] => {
|
||||
const embeddingModel = isRecord(value.embedding_model) ? value.embedding_model : {}
|
||||
return {
|
||||
id: getString(value.id),
|
||||
enabled: getBoolean(value.enabled),
|
||||
score_threshold: getNumber(value.score_threshold, ANNOTATION_DEFAULT.score_threshold),
|
||||
embedding_model: {
|
||||
embedding_provider_name: getString(embeddingModel.embedding_provider_name),
|
||||
embedding_model_name: getString(embeddingModel.embedding_model_name),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const getTransferMethods = (value: unknown, fallback: TransferMethod[]) => {
|
||||
if (!Array.isArray(value))
|
||||
return fallback
|
||||
|
||||
const methods = value.filter((item): item is TransferMethod => {
|
||||
return typeof item === 'string' && transferMethodValues.has(item)
|
||||
})
|
||||
return methods.length > 0 ? methods : fallback
|
||||
}
|
||||
|
||||
const getSupportUploadFileTypes = (value: unknown): SupportUploadFileTypes[] => {
|
||||
if (!Array.isArray(value))
|
||||
return []
|
||||
|
||||
return value.filter((item): item is SupportUploadFileTypes => {
|
||||
return typeof item === 'string' && supportUploadFileTypeValues.has(item)
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeVisionSettings = (value: unknown): NonNullable<ChatConfig['file_upload']>['image'] => {
|
||||
const image = isRecord(value) ? value : {}
|
||||
return {
|
||||
enabled: getBoolean(image.enabled),
|
||||
number_limits: getNumber(image.number_limits, 3),
|
||||
detail: getString(image.detail) === Resolution.low ? Resolution.low : Resolution.high,
|
||||
transfer_methods: getTransferMethods(image.transfer_methods, [TransferMethod.local_file, TransferMethod.remote_url]),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeFileUploadConfig = (value: Record<string, unknown>): ChatConfig['file_upload'] => {
|
||||
const allowedUploadMethods = getTransferMethods(value.allowed_upload_methods, [TransferMethod.local_file, TransferMethod.remote_url])
|
||||
const allowedFileUploadMethods = getTransferMethods(value.allowed_file_upload_methods, allowedUploadMethods)
|
||||
|
||||
return {
|
||||
image: normalizeVisionSettings(value.image),
|
||||
allowed_file_upload_methods: allowedFileUploadMethods,
|
||||
allowed_upload_methods: allowedUploadMethods,
|
||||
allowed_file_types: getSupportUploadFileTypes(value.allowed_file_types),
|
||||
allowed_file_extensions: getStringArray(value.allowed_file_extensions),
|
||||
max_length: getNumber(value.max_length, 1),
|
||||
number_limits: getNumber(value.number_limits, 1),
|
||||
}
|
||||
}
|
||||
|
||||
const defaultDatasetConfigs: ChatConfig['dataset_configs'] = {
|
||||
retrieval_model: RETRIEVE_TYPE.oneWay,
|
||||
reranking_model: {
|
||||
reranking_provider_name: '',
|
||||
reranking_model_name: '',
|
||||
},
|
||||
top_k: 4,
|
||||
score_threshold_enabled: false,
|
||||
score_threshold: null,
|
||||
datasets: {
|
||||
datasets: [],
|
||||
},
|
||||
}
|
||||
|
||||
const normalizeBaseInputForm = (value: Record<string, unknown>) => {
|
||||
return {
|
||||
default: getString(value.default),
|
||||
label: getString(value.label),
|
||||
variable: getString(value.variable),
|
||||
required: getBoolean(value.required, true),
|
||||
hide: getBoolean(value.hide),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeTextInputForm = (value: Record<string, unknown>) => {
|
||||
return {
|
||||
...normalizeBaseInputForm(value),
|
||||
max_length: getNumber(value.max_length, 0),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeFileInputForm = (value: Record<string, unknown>) => {
|
||||
return {
|
||||
...normalizeBaseInputForm(value),
|
||||
max_length: getNumber(value.max_length, 1),
|
||||
allowed_file_upload_methods: getTransferMethods(value.allowed_file_upload_methods, [
|
||||
TransferMethod.local_file,
|
||||
TransferMethod.remote_url,
|
||||
]),
|
||||
allowed_upload_methods: getTransferMethods(value.allowed_upload_methods, [
|
||||
TransferMethod.local_file,
|
||||
TransferMethod.remote_url,
|
||||
]),
|
||||
allowed_file_types: getSupportUploadFileTypes(value.allowed_file_types),
|
||||
allowed_file_extensions: getStringArray(value.allowed_file_extensions),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeUserInputFormItem = (item: Record<string, unknown>): ChatConfig['user_input_form'][number] | null => {
|
||||
if (isRecord(item['text-input']))
|
||||
return { 'text-input': normalizeTextInputForm(item['text-input']) }
|
||||
|
||||
if (isRecord(item.paragraph))
|
||||
return { paragraph: normalizeTextInputForm(item.paragraph) }
|
||||
|
||||
if (isRecord(item.select)) {
|
||||
return {
|
||||
select: {
|
||||
...normalizeBaseInputForm(item.select),
|
||||
options: getStringArray(item.select.options),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecord(item.number)) {
|
||||
return {
|
||||
number: {
|
||||
...normalizeBaseInputForm(item.number),
|
||||
max_length: getNumber(item.number.max_length, 0),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecord(item.checkbox)) {
|
||||
return {
|
||||
checkbox: {
|
||||
...normalizeBaseInputForm(item.checkbox),
|
||||
default: getBoolean(item.checkbox.default),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecord(item.file))
|
||||
return { file: normalizeFileInputForm(item.file) }
|
||||
|
||||
if (isRecord(item['file-list']))
|
||||
return { 'file-list': normalizeFileInputForm(item['file-list']) }
|
||||
|
||||
if (isRecord(item.external_data_tool)) {
|
||||
return {
|
||||
external_data_tool: {
|
||||
label: getString(item.external_data_tool.label),
|
||||
variable: getString(item.external_data_tool.variable),
|
||||
required: getBoolean(item.external_data_tool.required, true),
|
||||
hide: getBoolean(item.external_data_tool.hide),
|
||||
type: getOptionalString(item.external_data_tool.type),
|
||||
enabled: getBoolean(item.external_data_tool.enabled),
|
||||
icon: getOptionalString(item.external_data_tool.icon),
|
||||
icon_background: getOptionalString(item.external_data_tool.icon_background),
|
||||
config: getStringRecord(item.external_data_tool.config),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (isRecord(item.json_object)) {
|
||||
const jsonSchema = item.json_object.json_schema
|
||||
return {
|
||||
json_object: {
|
||||
...normalizeBaseInputForm(item.json_object),
|
||||
json_schema: typeof jsonSchema === 'string' || isRecord(jsonSchema) ? jsonSchema : undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const normalizeUserInputForm = (items: TryAppParameters['user_input_form']): ChatConfig['user_input_form'] => {
|
||||
return items.reduce<ChatConfig['user_input_form']>((result, item) => {
|
||||
const normalized = normalizeUserInputFormItem(item)
|
||||
if (normalized)
|
||||
result.push(normalized)
|
||||
return result
|
||||
}, [])
|
||||
}
|
||||
|
||||
const normalizeTryAppParams = (params: TryAppParameters): ChatConfig => {
|
||||
return {
|
||||
opening_statement: params.opening_statement ?? '',
|
||||
suggested_questions: params.suggested_questions,
|
||||
suggested_questions_after_answer: normalizeEnabledConfig(params.suggested_questions_after_answer),
|
||||
speech_to_text: normalizeEnabledConfig(params.speech_to_text),
|
||||
text_to_speech: normalizeTextToSpeechConfig(params.text_to_speech),
|
||||
retriever_resource: normalizeEnabledConfig(params.retriever_resource),
|
||||
annotation_reply: normalizeAnnotationReplyConfig(params.annotation_reply),
|
||||
more_like_this: normalizeEnabledConfig(params.more_like_this),
|
||||
sensitive_word_avoidance: normalizeEnabledConfig(params.sensitive_word_avoidance),
|
||||
file_upload: normalizeFileUploadConfig(params.file_upload),
|
||||
user_input_form: normalizeUserInputForm(params.user_input_form),
|
||||
system_parameters: params.system_parameters,
|
||||
pre_prompt: '',
|
||||
prompt_type: PromptMode.simple,
|
||||
agent_mode: DEFAULT_AGENT_SETTING,
|
||||
dataset_configs: defaultDatasetConfigs,
|
||||
}
|
||||
}
|
||||
|
||||
export const fetchTryAppInfo = (appId: string) => {
|
||||
return consoleClient.trialApps.byAppId.get({ params: { app_id: appId } })
|
||||
}
|
||||
|
||||
export const fetchTryAppDatasets = (appId: string, ids: string[]) => {
|
||||
return consoleClient.trialApps.byAppId.datasets.get({
|
||||
params: { app_id: appId },
|
||||
query: { ids },
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchTryAppFlowPreview = (appId: string) => {
|
||||
return consoleClient.trialApps.byAppId.workflows.get({ params: { app_id: appId } })
|
||||
}
|
||||
|
||||
export const fetchTryAppParams = (appId: string) => {
|
||||
return consoleClient.trialApps.byAppId.parameters.get({ params: { app_id: appId } })
|
||||
.then(normalizeTryAppParams)
|
||||
}
|
||||
|
||||
export type TryAppInfo = Awaited<ReturnType<typeof fetchTryAppInfo>>
|
||||
export type { TryAppInfo } from '@/models/try-app'
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import type { DataSetListResponse } from '@/models/datasets'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { fetchTryAppDatasets, fetchTryAppFlowPreview, fetchTryAppInfo, fetchTryAppParams } from './try-app'
|
||||
|
||||
export const useGetTryAppInfo = (appId: string) => {
|
||||
return useQuery({
|
||||
queryKey: consoleQuery.trialApps.byAppId.get.queryKey({ input: { params: { app_id: appId } } }),
|
||||
queryKey: consoleQuery.trialApps.info.queryKey({ input: { params: { appId } } }),
|
||||
queryFn: () => {
|
||||
return fetchTryAppInfo(appId)
|
||||
},
|
||||
@ -14,7 +15,7 @@ export const useGetTryAppInfo = (appId: string) => {
|
||||
|
||||
export const useGetTryAppParams = (appId: string) => {
|
||||
return useQuery({
|
||||
queryKey: consoleQuery.trialApps.byAppId.parameters.get.queryKey({ input: { params: { app_id: appId } } }),
|
||||
queryKey: consoleQuery.trialApps.parameters.queryKey({ input: { params: { appId } } }),
|
||||
queryFn: () => {
|
||||
return fetchTryAppParams(appId)
|
||||
},
|
||||
@ -23,8 +24,8 @@ export const useGetTryAppParams = (appId: string) => {
|
||||
}
|
||||
|
||||
export const useGetTryAppDataSets = (appId: string, ids: string[]) => {
|
||||
return useQuery({
|
||||
queryKey: consoleQuery.trialApps.byAppId.datasets.get.queryKey({ input: { params: { app_id: appId }, query: { ids } } }),
|
||||
return useQuery<DataSetListResponse>({
|
||||
queryKey: consoleQuery.trialApps.datasets.queryKey({ input: { params: { appId }, query: { ids } } }),
|
||||
queryFn: () => {
|
||||
return fetchTryAppDatasets(appId, ids)
|
||||
},
|
||||
@ -34,7 +35,7 @@ export const useGetTryAppDataSets = (appId: string, ids: string[]) => {
|
||||
|
||||
export const useGetTryAppFlowPreview = (appId: string, disabled?: boolean) => {
|
||||
return useQuery({
|
||||
queryKey: consoleQuery.trialApps.byAppId.workflows.get.queryKey({ input: { params: { app_id: appId } } }),
|
||||
queryKey: consoleQuery.trialApps.workflows.queryKey({ input: { params: { appId } } }),
|
||||
enabled: !disabled,
|
||||
queryFn: () => {
|
||||
return fetchTryAppFlowPreview(appId)
|
||||
|
||||
@ -85,47 +85,22 @@ export type PromptVariable = {
|
||||
}
|
||||
|
||||
type TextTypeFormItem = {
|
||||
default?: string
|
||||
default: string
|
||||
label: string
|
||||
variable: string
|
||||
required: boolean
|
||||
max_length?: number
|
||||
hide?: boolean
|
||||
max_length: number
|
||||
hide: boolean
|
||||
}
|
||||
|
||||
type SelectTypeFormItem = {
|
||||
default?: string
|
||||
default: string
|
||||
label: string
|
||||
variable: string
|
||||
required: boolean
|
||||
options?: string[]
|
||||
hide?: boolean
|
||||
options: string[]
|
||||
hide: boolean
|
||||
}
|
||||
|
||||
type NumberTypeFormItem = Omit<TextTypeFormItem, 'default' | 'max_length'> & {
|
||||
default?: string | number
|
||||
max_length?: number
|
||||
}
|
||||
|
||||
type CheckboxTypeFormItem = Omit<TextTypeFormItem, 'default' | 'max_length'> & {
|
||||
default?: string | boolean
|
||||
}
|
||||
|
||||
type FileTypeFormItem = Omit<TextTypeFormItem, 'max_length'> & Partial<UploadFileSetting> & {
|
||||
max_length?: number
|
||||
}
|
||||
|
||||
type ExternalDataToolFormItem = ExternalDataTool & {
|
||||
label: string
|
||||
variable: string
|
||||
required?: boolean
|
||||
hide?: boolean
|
||||
}
|
||||
|
||||
type JsonObjectFormItem = Omit<TextTypeFormItem, 'max_length'> & {
|
||||
json_schema?: string | Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* User Input Form Item
|
||||
*/
|
||||
@ -135,18 +110,6 @@ export type UserInputFormItem = {
|
||||
select: SelectTypeFormItem
|
||||
} | {
|
||||
paragraph: TextTypeFormItem
|
||||
} | {
|
||||
number: NumberTypeFormItem
|
||||
} | {
|
||||
checkbox: CheckboxTypeFormItem
|
||||
} | {
|
||||
file: FileTypeFormItem
|
||||
} | {
|
||||
'file-list': FileTypeFormItem
|
||||
} | {
|
||||
external_data_tool: ExternalDataToolFormItem
|
||||
} | {
|
||||
json_object: JsonObjectFormItem
|
||||
}
|
||||
|
||||
export type AgentTool = {
|
||||
@ -155,7 +118,7 @@ export type AgentTool = {
|
||||
provider_name: string
|
||||
tool_name: string
|
||||
tool_label: string
|
||||
tool_parameters: Record<string, unknown>
|
||||
tool_parameters: Record<string, any>
|
||||
enabled: boolean
|
||||
isDeleted?: boolean
|
||||
notAuthor?: boolean
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import type { UserInputFormItem } from '@/types/app'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
/**
|
||||
* Test suite for model configuration transformation utilities
|
||||
*
|
||||
@ -19,20 +18,6 @@ import {
|
||||
userInputsFormToPromptVariables,
|
||||
} from './model-config'
|
||||
|
||||
const getTextInput = (item: UserInputFormItem | undefined) => {
|
||||
if (!item || !('text-input' in item))
|
||||
throw new Error('Expected text-input user input form item')
|
||||
|
||||
return item['text-input']
|
||||
}
|
||||
|
||||
const getSelectInput = (item: UserInputFormItem | undefined) => {
|
||||
if (!item || !('select' in item))
|
||||
throw new Error('Expected select user input form item')
|
||||
|
||||
return item.select
|
||||
}
|
||||
|
||||
describe('Model Config Utilities', () => {
|
||||
describe('userInputsFormToPromptVariables', () => {
|
||||
/**
|
||||
@ -125,7 +110,7 @@ describe('Model Config Utilities', () => {
|
||||
default: '',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
]
|
||||
|
||||
const result = userInputsFormToPromptVariables(userInputs)
|
||||
@ -155,7 +140,7 @@ describe('Model Config Utilities', () => {
|
||||
default: '',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
]
|
||||
|
||||
const result = userInputsFormToPromptVariables(userInputs)
|
||||
@ -214,13 +199,13 @@ describe('Model Config Utilities', () => {
|
||||
label: 'Profile Picture',
|
||||
variable: 'profile_pic',
|
||||
required: false,
|
||||
allowed_file_types: [SupportUploadFileTypes.image],
|
||||
allowed_file_types: ['image'],
|
||||
allowed_file_extensions: ['.jpg', '.png'],
|
||||
allowed_file_upload_methods: ['local_file', 'remote_url'],
|
||||
default: '',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
]
|
||||
|
||||
const result = userInputsFormToPromptVariables(userInputs)
|
||||
@ -252,14 +237,14 @@ describe('Model Config Utilities', () => {
|
||||
label: 'Documents',
|
||||
variable: 'documents',
|
||||
required: true,
|
||||
allowed_file_types: [SupportUploadFileTypes.document],
|
||||
allowed_file_types: ['document'],
|
||||
allowed_file_extensions: ['.pdf', '.docx'],
|
||||
allowed_file_upload_methods: ['local_file'],
|
||||
max_length: 5,
|
||||
default: '',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
]
|
||||
|
||||
const result = userInputsFormToPromptVariables(userInputs)
|
||||
@ -298,7 +283,7 @@ describe('Model Config Utilities', () => {
|
||||
icon_background: '#FF5733',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
]
|
||||
|
||||
const result = userInputsFormToPromptVariables(userInputs)
|
||||
@ -364,7 +349,7 @@ describe('Model Config Utilities', () => {
|
||||
default: '',
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
{
|
||||
select: {
|
||||
label: 'Gender',
|
||||
@ -568,7 +553,7 @@ describe('Model Config Utilities', () => {
|
||||
const result = promptVariablesToUserInputsForm(promptVariables)
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(getTextInput(result[0]).variable).toBe('valid_key')
|
||||
expect((result[0] as any)['text-input']?.variable).toBe('valid_key')
|
||||
})
|
||||
|
||||
/**
|
||||
@ -628,8 +613,8 @@ describe('Model Config Utilities', () => {
|
||||
|
||||
const result = promptVariablesToUserInputsForm(promptVariables)
|
||||
|
||||
expect(getTextInput(result[0]).required).toBe(true)
|
||||
expect(getTextInput(result[1]).required).toBe(false)
|
||||
expect((result[0] as any)['text-input']?.required).toBe(true)
|
||||
expect((result[1] as any)['text-input']?.required).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@ -758,7 +743,7 @@ describe('Model Config Utilities', () => {
|
||||
bool1: 1,
|
||||
bool2: 0,
|
||||
bool3: 'yes',
|
||||
bool4: null,
|
||||
bool4: null as any,
|
||||
}
|
||||
|
||||
const result = formatBooleanInputs(useInputs, inputs)
|
||||
@ -826,9 +811,9 @@ describe('Model Config Utilities', () => {
|
||||
const backToUserInputs = promptVariablesToUserInputsForm(promptVars)
|
||||
|
||||
expect(backToUserInputs).toHaveLength(2)
|
||||
expect(getTextInput(backToUserInputs[0]).variable).toBe('name')
|
||||
expect(getSelectInput(backToUserInputs[1]).variable).toBe('type')
|
||||
expect(getSelectInput(backToUserInputs[1]).options).toEqual(['A', 'B', 'C'])
|
||||
expect((backToUserInputs[0] as any)['text-input']?.variable).toBe('name')
|
||||
expect((backToUserInputs[1] as any).select?.variable).toBe('type')
|
||||
expect((backToUserInputs[1] as any).select?.options).toEqual(['A', 'B', 'C'])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,139 +1,94 @@
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import type { UserInputFormItem } from '@/types/app'
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
const getString = (value: unknown) => {
|
||||
return typeof value === 'string' ? value : ''
|
||||
}
|
||||
|
||||
const getOptionalString = (value: unknown) => {
|
||||
return typeof value === 'string' ? value : undefined
|
||||
}
|
||||
|
||||
const getBoolean = (value: unknown, fallback = false) => {
|
||||
return typeof value === 'boolean' ? value : fallback
|
||||
}
|
||||
|
||||
const getNumber = (value: unknown) => {
|
||||
return typeof value === 'number' ? value : undefined
|
||||
}
|
||||
|
||||
const getDefaultValue = (value: unknown) => {
|
||||
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? value : undefined
|
||||
}
|
||||
|
||||
const getStringArray = (value: unknown) => {
|
||||
return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []
|
||||
}
|
||||
|
||||
const getStringRecord = (value: unknown) => {
|
||||
if (!isRecord(value))
|
||||
return undefined
|
||||
|
||||
const record: Record<string, string | undefined> = {}
|
||||
Object.entries(value).forEach(([key, item]) => {
|
||||
if (typeof item === 'string')
|
||||
record[key] = item
|
||||
})
|
||||
return record
|
||||
}
|
||||
|
||||
const getRecord = (value: unknown) => {
|
||||
return isRecord(value) ? value : {}
|
||||
}
|
||||
|
||||
const getInputFormContent = (item: Record<string, unknown>) => {
|
||||
if (isRecord(item.paragraph))
|
||||
return { type: 'paragraph', content: item.paragraph }
|
||||
|
||||
if (isRecord(item['text-input']))
|
||||
return { type: 'string', content: item['text-input'] }
|
||||
|
||||
if (isRecord(item.number))
|
||||
return { type: 'number', content: item.number }
|
||||
|
||||
if (isRecord(item.checkbox))
|
||||
return { type: 'boolean', content: item.checkbox }
|
||||
|
||||
if (isRecord(item.file))
|
||||
return { type: 'file', content: item.file }
|
||||
|
||||
if (isRecord(item['file-list']))
|
||||
return { type: 'file-list', content: item['file-list'] }
|
||||
|
||||
if (isRecord(item.external_data_tool))
|
||||
return { type: getString(item.external_data_tool.type), content: item.external_data_tool }
|
||||
|
||||
if (isRecord(item.json_object))
|
||||
return { type: 'json_object', content: item.json_object }
|
||||
|
||||
return { type: 'select', content: getRecord(item.select) }
|
||||
}
|
||||
|
||||
export const userInputsFormToPromptVariables = (useInputs: Record<string, unknown>[] | null, dataset_query_variable?: string) => {
|
||||
export const userInputsFormToPromptVariables = (useInputs: UserInputFormItem[] | null, dataset_query_variable?: string) => {
|
||||
if (!useInputs)
|
||||
return []
|
||||
const promptVariables: PromptVariable[] = []
|
||||
useInputs.forEach((item) => {
|
||||
const { type, content } = getInputFormContent(item)
|
||||
const variable = getString(content.variable)
|
||||
const is_context_var = dataset_query_variable === variable
|
||||
useInputs.forEach((item: any) => {
|
||||
const isParagraph = !!item.paragraph
|
||||
|
||||
const [type, content] = (() => {
|
||||
if (isParagraph)
|
||||
return ['paragraph', item.paragraph]
|
||||
|
||||
if (item['text-input'])
|
||||
return ['string', item['text-input']]
|
||||
|
||||
if (item.number)
|
||||
return ['number', item.number]
|
||||
|
||||
if (item.checkbox)
|
||||
return ['boolean', item.checkbox]
|
||||
|
||||
if (item.file)
|
||||
return ['file', item.file]
|
||||
|
||||
if (item['file-list'])
|
||||
return ['file-list', item['file-list']]
|
||||
|
||||
if (item.external_data_tool)
|
||||
return [item.external_data_tool.type, item.external_data_tool]
|
||||
|
||||
if (item.json_object)
|
||||
return ['json_object', item.json_object]
|
||||
|
||||
return ['select', item.select || {}]
|
||||
})()
|
||||
const is_context_var = dataset_query_variable === content?.variable
|
||||
|
||||
if (type === 'string' || type === 'paragraph') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type,
|
||||
max_length: getNumber(content.max_length),
|
||||
max_length: content.max_length,
|
||||
options: [],
|
||||
is_context_var,
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else if (type === 'number') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type,
|
||||
options: [],
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else if (type === 'boolean') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type: 'checkbox',
|
||||
options: [],
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else if (type === 'select') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type: 'select',
|
||||
options: getStringArray(content.options),
|
||||
options: content.options,
|
||||
is_context_var,
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else if (type === 'file') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type,
|
||||
config: {
|
||||
allowed_file_types: content.allowed_file_types,
|
||||
@ -141,38 +96,38 @@ export const userInputsFormToPromptVariables = (useInputs: Record<string, unknow
|
||||
allowed_file_upload_methods: content.allowed_file_upload_methods,
|
||||
number_limits: 1,
|
||||
},
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else if (type === 'file-list') {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type,
|
||||
config: {
|
||||
allowed_file_types: content.allowed_file_types,
|
||||
allowed_file_extensions: content.allowed_file_extensions,
|
||||
allowed_file_upload_methods: content.allowed_file_upload_methods,
|
||||
number_limits: getNumber(content.max_length),
|
||||
number_limits: content.max_length,
|
||||
},
|
||||
hide: getBoolean(content.hide),
|
||||
default: getDefaultValue(content.default),
|
||||
hide: content.hide,
|
||||
default: content.default,
|
||||
})
|
||||
}
|
||||
else {
|
||||
promptVariables.push({
|
||||
key: variable,
|
||||
name: getString(content.label),
|
||||
required: getBoolean(content.required, true),
|
||||
type: getString(content.type || type),
|
||||
enabled: getBoolean(content.enabled),
|
||||
config: getRecord(content.config),
|
||||
icon: getOptionalString(content.icon),
|
||||
icon_background: getOptionalString(content.icon_background),
|
||||
key: content.variable,
|
||||
name: content.label,
|
||||
required: content.required,
|
||||
type: content.type,
|
||||
enabled: content.enabled,
|
||||
config: content.config,
|
||||
icon: content.icon,
|
||||
icon_background: content.icon_background,
|
||||
is_context_var,
|
||||
hide: getBoolean(content.hide),
|
||||
hide: content.hide,
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -183,10 +138,10 @@ export const promptVariablesToUserInputsForm = (promptVariables: PromptVariable[
|
||||
const userInputs: UserInputFormItem[] = []
|
||||
promptVariables.filter(({ key, name }) => {
|
||||
return key && key.trim() && name && name.trim()
|
||||
}).forEach((item) => {
|
||||
if (item.type === 'string') {
|
||||
}).forEach((item: any) => {
|
||||
if (item.type === 'string' || item.type === 'paragraph') {
|
||||
userInputs.push({
|
||||
'text-input': {
|
||||
[item.type === 'string' ? 'text-input' : 'paragraph']: {
|
||||
label: item.name,
|
||||
variable: item.key,
|
||||
required: item.required !== false, // default true
|
||||
@ -194,43 +149,19 @@ export const promptVariablesToUserInputsForm = (promptVariables: PromptVariable[
|
||||
default: '',
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
return
|
||||
}
|
||||
if (item.type === 'paragraph') {
|
||||
if (item.type === 'number' || item.type === 'checkbox') {
|
||||
userInputs.push({
|
||||
paragraph: {
|
||||
label: item.name,
|
||||
variable: item.key,
|
||||
required: item.required !== false, // default true
|
||||
max_length: item.max_length,
|
||||
default: '',
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
if (item.type === 'number') {
|
||||
userInputs.push({
|
||||
number: {
|
||||
[item.type]: {
|
||||
label: item.name,
|
||||
variable: item.key,
|
||||
required: item.required !== false, // default true
|
||||
default: '',
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
}
|
||||
else if (item.type === 'checkbox') {
|
||||
userInputs.push({
|
||||
checkbox: {
|
||||
label: item.name,
|
||||
variable: item.key,
|
||||
required: item.required !== false, // default true
|
||||
default: '',
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
else if (item.type === 'select') {
|
||||
userInputs.push({
|
||||
@ -239,10 +170,10 @@ export const promptVariablesToUserInputsForm = (promptVariables: PromptVariable[
|
||||
variable: item.key,
|
||||
required: item.required !== false, // default true
|
||||
options: item.options,
|
||||
default: getString(item.default),
|
||||
default: item.default ?? '',
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
else {
|
||||
userInputs.push({
|
||||
@ -251,20 +182,20 @@ export const promptVariablesToUserInputsForm = (promptVariables: PromptVariable[
|
||||
variable: item.key,
|
||||
enabled: item.enabled,
|
||||
type: item.type,
|
||||
config: getStringRecord(item.config),
|
||||
config: item.config,
|
||||
required: item.required,
|
||||
icon: item.icon,
|
||||
icon_background: item.icon_background,
|
||||
hide: item.hide,
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
})
|
||||
|
||||
return userInputs
|
||||
}
|
||||
|
||||
export const formatBooleanInputs = (useInputs?: PromptVariable[] | null, inputs?: Record<string, string | number | object | boolean | null> | null) => {
|
||||
export const formatBooleanInputs = (useInputs?: PromptVariable[] | null, inputs?: Record<string, string | number | object | boolean> | null) => {
|
||||
if (!useInputs)
|
||||
return inputs
|
||||
const res = { ...inputs }
|
||||
|
||||
Reference in New Issue
Block a user