Copy disabled (too large)
Download .txt
Showing preview only (84,225K chars total). Download the full file to get everything.
Repository: langgenius/dify
Branch: main
Commit: 4e1d0604391e
Files: 9937
Total size: 76.5 MB
Directory structure:
gitextract_8lu11vbd/
├── .agents/
│ └── skills/
│ ├── backend-code-review/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── architecture-rule.md
│ │ ├── db-schema-rule.md
│ │ ├── repositories-rule.md
│ │ └── sqlalchemy-rule.md
│ ├── component-refactoring/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── complexity-patterns.md
│ │ ├── component-splitting.md
│ │ └── hook-extraction.md
│ ├── frontend-code-review/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── business-logic.md
│ │ ├── code-quality.md
│ │ └── performance.md
│ ├── frontend-query-mutation/
│ │ ├── SKILL.md
│ │ ├── agents/
│ │ │ └── openai.yaml
│ │ └── references/
│ │ ├── contract-patterns.md
│ │ └── runtime-rules.md
│ └── frontend-testing/
│ ├── SKILL.md
│ ├── assets/
│ │ ├── component-test.template.tsx
│ │ ├── hook-test.template.ts
│ │ └── utility-test.template.ts
│ └── references/
│ ├── async-testing.md
│ ├── checklist.md
│ ├── common-patterns.md
│ ├── domain-components.md
│ ├── mocking.md
│ └── workflow.md
├── .claude/
│ └── settings.json
├── .coveragerc
├── .devcontainer/
│ ├── Dockerfile
│ ├── README.md
│ ├── devcontainer.json
│ ├── noop.txt
│ ├── post_create_command.sh
│ └── post_start_command.sh
├── .editorconfig
├── .gemini/
│ └── config.yaml
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── DISCUSSION_TEMPLATE/
│ │ ├── general.yml
│ │ ├── help.yml
│ │ └── suggestion.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.yml
│ │ └── refactor.yml
│ ├── actions/
│ │ └── setup-web/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── labeler.yml
│ ├── linters/
│ │ ├── .hadolint.yaml
│ │ ├── .isort.cfg
│ │ ├── .yaml-lint.yml
│ │ └── editorconfig-checker.json
│ ├── pull_request_template.md
│ └── workflows/
│ ├── anti-slop.yml
│ ├── api-tests.yml
│ ├── autofix.yml
│ ├── build-push.yml
│ ├── db-migration-test.yml
│ ├── deploy-agent-dev.yml
│ ├── deploy-dev.yml
│ ├── deploy-enterprise.yml
│ ├── deploy-hitl.yml
│ ├── docker-build.yml
│ ├── expose_service_ports.sh
│ ├── labeler.yml
│ ├── main-ci.yml
│ ├── pyrefly-diff-comment.yml
│ ├── pyrefly-diff.yml
│ ├── semantic-pull-request.yml
│ ├── stale.yml
│ ├── style.yml
│ ├── tool-test-sdks.yaml
│ ├── translate-i18n-claude.yml
│ ├── trigger-i18n-sync.yml
│ ├── vdb-tests-full.yml
│ ├── vdb-tests.yml
│ ├── web-e2e.yml
│ └── web-tests.yml
├── .gitignore
├── .nvmrc
├── .vite-hooks/
│ └── pre-commit
├── .vscode/
│ ├── README.md
│ └── launch.json.template
├── AGENTS.md
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── api/
│ ├── .dockerignore
│ ├── .importlinter
│ ├── .ruff.toml
│ ├── AGENTS.md
│ ├── Dockerfile
│ ├── README.md
│ ├── app.py
│ ├── app_factory.py
│ ├── celery_entrypoint.py
│ ├── cnt_base.sh
│ ├── commands/
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── plugin.py
│ │ ├── retention.py
│ │ ├── storage.py
│ │ ├── system.py
│ │ └── vector.py
│ ├── configs/
│ │ ├── __init__.py
│ │ ├── app_config.py
│ │ ├── deploy/
│ │ │ └── __init__.py
│ │ ├── enterprise/
│ │ │ └── __init__.py
│ │ ├── extra/
│ │ │ ├── __init__.py
│ │ │ ├── archive_config.py
│ │ │ ├── notion_config.py
│ │ │ └── sentry_config.py
│ │ ├── feature/
│ │ │ ├── __init__.py
│ │ │ └── hosted_service/
│ │ │ └── __init__.py
│ │ ├── middleware/
│ │ │ ├── __init__.py
│ │ │ ├── cache/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── redis_config.py
│ │ │ │ └── redis_pubsub_config.py
│ │ │ ├── storage/
│ │ │ │ ├── aliyun_oss_storage_config.py
│ │ │ │ ├── amazon_s3_storage_config.py
│ │ │ │ ├── azure_blob_storage_config.py
│ │ │ │ ├── baidu_obs_storage_config.py
│ │ │ │ ├── clickzetta_volume_storage_config.py
│ │ │ │ ├── google_cloud_storage_config.py
│ │ │ │ ├── huawei_obs_storage_config.py
│ │ │ │ ├── oci_storage_config.py
│ │ │ │ ├── opendal_storage_config.py
│ │ │ │ ├── supabase_storage_config.py
│ │ │ │ ├── tencent_cos_storage_config.py
│ │ │ │ └── volcengine_tos_storage_config.py
│ │ │ └── vdb/
│ │ │ ├── alibabacloud_mysql_config.py
│ │ │ ├── analyticdb_config.py
│ │ │ ├── baidu_vector_config.py
│ │ │ ├── chroma_config.py
│ │ │ ├── clickzetta_config.py
│ │ │ ├── couchbase_config.py
│ │ │ ├── elasticsearch_config.py
│ │ │ ├── hologres_config.py
│ │ │ ├── huawei_cloud_config.py
│ │ │ ├── iris_config.py
│ │ │ ├── lindorm_config.py
│ │ │ ├── matrixone_config.py
│ │ │ ├── milvus_config.py
│ │ │ ├── myscale_config.py
│ │ │ ├── oceanbase_config.py
│ │ │ ├── opengauss_config.py
│ │ │ ├── opensearch_config.py
│ │ │ ├── oracle_config.py
│ │ │ ├── pgvector_config.py
│ │ │ ├── pgvectors_config.py
│ │ │ ├── qdrant_config.py
│ │ │ ├── relyt_config.py
│ │ │ ├── tablestore_config.py
│ │ │ ├── tencent_vector_config.py
│ │ │ ├── tidb_on_qdrant_config.py
│ │ │ ├── tidb_vector_config.py
│ │ │ ├── upstash_config.py
│ │ │ ├── vastbase_vector_config.py
│ │ │ ├── vikingdb_config.py
│ │ │ └── weaviate_config.py
│ │ ├── observability/
│ │ │ ├── __init__.py
│ │ │ └── otel/
│ │ │ └── otel_config.py
│ │ ├── packaging/
│ │ │ ├── __init__.py
│ │ │ └── pyproject.py
│ │ └── remote_settings_sources/
│ │ ├── __init__.py
│ │ ├── apollo/
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── python_3x.py
│ │ │ └── utils.py
│ │ ├── base.py
│ │ ├── enums.py
│ │ └── nacos/
│ │ ├── __init__.py
│ │ ├── http_request.py
│ │ └── utils.py
│ ├── constants/
│ │ ├── __init__.py
│ │ ├── languages.py
│ │ ├── mimetypes.py
│ │ ├── model_template.py
│ │ ├── pipeline_templates.json
│ │ ├── recommended_apps.json
│ │ └── tts_auto_play_timeout.py
│ ├── context/
│ │ ├── __init__.py
│ │ ├── execution_context.py
│ │ ├── flask_app_context.py
│ │ └── models.py
│ ├── contexts/
│ │ ├── __init__.py
│ │ └── wrapper.py
│ ├── controllers/
│ │ ├── __init__.py
│ │ ├── common/
│ │ │ ├── errors.py
│ │ │ ├── fields.py
│ │ │ ├── file_response.py
│ │ │ ├── helpers.py
│ │ │ └── schema.py
│ │ ├── console/
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── apikey.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_prompt_template.py
│ │ │ │ ├── agent.py
│ │ │ │ ├── annotation.py
│ │ │ │ ├── app.py
│ │ │ │ ├── app_import.py
│ │ │ │ ├── audio.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── conversation_variables.py
│ │ │ │ ├── error.py
│ │ │ │ ├── generator.py
│ │ │ │ ├── mcp_server.py
│ │ │ │ ├── message.py
│ │ │ │ ├── model_config.py
│ │ │ │ ├── ops_trace.py
│ │ │ │ ├── site.py
│ │ │ │ ├── statistic.py
│ │ │ │ ├── workflow.py
│ │ │ │ ├── workflow_app_log.py
│ │ │ │ ├── workflow_draft_variable.py
│ │ │ │ ├── workflow_run.py
│ │ │ │ ├── workflow_statistic.py
│ │ │ │ ├── workflow_trigger.py
│ │ │ │ └── wraps.py
│ │ │ ├── auth/
│ │ │ │ ├── activate.py
│ │ │ │ ├── data_source_bearer_auth.py
│ │ │ │ ├── data_source_oauth.py
│ │ │ │ ├── email_register.py
│ │ │ │ ├── error.py
│ │ │ │ ├── forgot_password.py
│ │ │ │ ├── login.py
│ │ │ │ ├── oauth.py
│ │ │ │ └── oauth_server.py
│ │ │ ├── billing/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── billing.py
│ │ │ │ └── compliance.py
│ │ │ ├── datasets/
│ │ │ │ ├── data_source.py
│ │ │ │ ├── datasets.py
│ │ │ │ ├── datasets_document.py
│ │ │ │ ├── datasets_segments.py
│ │ │ │ ├── error.py
│ │ │ │ ├── external.py
│ │ │ │ ├── hit_testing.py
│ │ │ │ ├── hit_testing_base.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── rag_pipeline/
│ │ │ │ │ ├── datasource_auth.py
│ │ │ │ │ ├── datasource_content_preview.py
│ │ │ │ │ ├── rag_pipeline.py
│ │ │ │ │ ├── rag_pipeline_datasets.py
│ │ │ │ │ ├── rag_pipeline_draft_variable.py
│ │ │ │ │ ├── rag_pipeline_import.py
│ │ │ │ │ └── rag_pipeline_workflow.py
│ │ │ │ ├── website.py
│ │ │ │ └── wraps.py
│ │ │ ├── error.py
│ │ │ ├── explore/
│ │ │ │ ├── audio.py
│ │ │ │ ├── banner.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── error.py
│ │ │ │ ├── installed_app.py
│ │ │ │ ├── message.py
│ │ │ │ ├── parameter.py
│ │ │ │ ├── recommended_app.py
│ │ │ │ ├── saved_message.py
│ │ │ │ ├── trial.py
│ │ │ │ ├── workflow.py
│ │ │ │ └── wraps.py
│ │ │ ├── extension.py
│ │ │ ├── feature.py
│ │ │ ├── files.py
│ │ │ ├── human_input_form.py
│ │ │ ├── init_validate.py
│ │ │ ├── notification.py
│ │ │ ├── ping.py
│ │ │ ├── remote_files.py
│ │ │ ├── setup.py
│ │ │ ├── spec.py
│ │ │ ├── tag/
│ │ │ │ └── tags.py
│ │ │ ├── version.py
│ │ │ ├── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── account.py
│ │ │ │ ├── agent_providers.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── error.py
│ │ │ │ ├── load_balancing_config.py
│ │ │ │ ├── members.py
│ │ │ │ ├── model_providers.py
│ │ │ │ ├── models.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── tool_providers.py
│ │ │ │ ├── trigger_providers.py
│ │ │ │ └── workspace.py
│ │ │ └── wraps.py
│ │ ├── fastopenapi.py
│ │ ├── files/
│ │ │ ├── __init__.py
│ │ │ ├── image_preview.py
│ │ │ ├── tool_files.py
│ │ │ └── upload.py
│ │ ├── inner_api/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── dsl.py
│ │ │ ├── mail.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── plugin.py
│ │ │ │ └── wraps.py
│ │ │ ├── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── workspace.py
│ │ │ └── wraps.py
│ │ ├── mcp/
│ │ │ ├── __init__.py
│ │ │ └── mcp.py
│ │ ├── service_api/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── annotation.py
│ │ │ │ ├── app.py
│ │ │ │ ├── audio.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── error.py
│ │ │ │ ├── file.py
│ │ │ │ ├── file_preview.py
│ │ │ │ ├── message.py
│ │ │ │ ├── site.py
│ │ │ │ └── workflow.py
│ │ │ ├── dataset/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── dataset.py
│ │ │ │ ├── document.py
│ │ │ │ ├── error.py
│ │ │ │ ├── hit_testing.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── rag_pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline_workflow.py
│ │ │ │ │ └── serializers.py
│ │ │ │ └── segment.py
│ │ │ ├── end_user/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── end_user.py
│ │ │ │ └── error.py
│ │ │ ├── index.py
│ │ │ ├── workspace/
│ │ │ │ └── models.py
│ │ │ └── wraps.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── trigger.py
│ │ │ └── webhook.py
│ │ └── web/
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── audio.py
│ │ ├── completion.py
│ │ ├── conversation.py
│ │ ├── error.py
│ │ ├── feature.py
│ │ ├── files.py
│ │ ├── forgot_password.py
│ │ ├── human_input_form.py
│ │ ├── login.py
│ │ ├── message.py
│ │ ├── passport.py
│ │ ├── remote_files.py
│ │ ├── saved_message.py
│ │ ├── site.py
│ │ ├── workflow.py
│ │ ├── workflow_events.py
│ │ └── wraps.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent/
│ │ │ ├── __init__.py
│ │ │ ├── base_agent_runner.py
│ │ │ ├── cot_agent_runner.py
│ │ │ ├── cot_chat_agent_runner.py
│ │ │ ├── cot_completion_agent_runner.py
│ │ │ ├── entities.py
│ │ │ ├── errors.py
│ │ │ ├── fc_agent_runner.py
│ │ │ ├── output_parser/
│ │ │ │ └── cot_output_parser.py
│ │ │ ├── plugin_entities.py
│ │ │ ├── prompt/
│ │ │ │ └── template.py
│ │ │ └── strategy/
│ │ │ ├── base.py
│ │ │ └── plugin.py
│ │ ├── app/
│ │ │ ├── __init__.py
│ │ │ ├── app_config/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base_app_config_manager.py
│ │ │ │ ├── common/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── parameters_mapping/
│ │ │ │ │ │ └── __init__.py
│ │ │ │ │ └── sensitive_word_avoidance/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ ├── easy_ui_based_app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── agent/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── dataset/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── model_config/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── converter.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── prompt_template/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ └── variables/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── features/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── file_upload/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── more_like_this/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── opening_statement/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── retrieval_resource/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── speech_to_text/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── suggested_questions_after_answer/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ └── text_to_speech/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ └── workflow_ui_based_app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── variables/
│ │ │ │ ├── __init__.py
│ │ │ │ └── manager.py
│ │ │ ├── apps/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ └── generate_task_pipeline.py
│ │ │ │ ├── agent_chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── base_app_generate_response_converter.py
│ │ │ │ ├── base_app_generator.py
│ │ │ │ ├── base_app_queue_manager.py
│ │ │ │ ├── base_app_runner.py
│ │ │ │ ├── chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── common/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── graph_runtime_state_support.py
│ │ │ │ │ └── workflow_response_converter.py
│ │ │ │ ├── completion/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── draft_variable_saver.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── message_based_app_generator.py
│ │ │ │ ├── message_based_app_queue_manager.py
│ │ │ │ ├── message_generator.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ ├── pipeline_config_manager.py
│ │ │ │ │ ├── pipeline_generator.py
│ │ │ │ │ ├── pipeline_queue_manager.py
│ │ │ │ │ └── pipeline_runner.py
│ │ │ │ ├── streaming_utils.py
│ │ │ │ ├── workflow/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_queue_manager.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ └── generate_task_pipeline.py
│ │ │ │ └── workflow_app_runner.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_strategy.py
│ │ │ │ ├── app_invoke_entities.py
│ │ │ │ ├── queue_entities.py
│ │ │ │ ├── rag_pipeline_invoke_entities.py
│ │ │ │ └── task_entities.py
│ │ │ ├── features/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── annotation_reply/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── annotation_reply.py
│ │ │ │ ├── hosting_moderation/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── hosting_moderation.py
│ │ │ │ └── rate_limiting/
│ │ │ │ ├── __init__.py
│ │ │ │ └── rate_limit.py
│ │ │ ├── file_access/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── controller.py
│ │ │ │ ├── protocols.py
│ │ │ │ └── scope.py
│ │ │ ├── layers/
│ │ │ │ ├── conversation_variable_persist_layer.py
│ │ │ │ ├── pause_state_persist_layer.py
│ │ │ │ ├── suspend_layer.py
│ │ │ │ ├── timeslice_layer.py
│ │ │ │ └── trigger_post_layer.py
│ │ │ ├── llm/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── model_access.py
│ │ │ │ └── quota.py
│ │ │ ├── task_pipeline/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── based_generate_task_pipeline.py
│ │ │ │ ├── easy_ui_based_generate_task_pipeline.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── message_cycle_manager.py
│ │ │ │ └── message_file_utils.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── file_runtime.py
│ │ │ └── layers/
│ │ │ ├── __init__.py
│ │ │ ├── llm_quota.py
│ │ │ ├── observability.py
│ │ │ └── persistence.py
│ │ ├── base/
│ │ │ ├── __init__.py
│ │ │ └── tts/
│ │ │ ├── __init__.py
│ │ │ └── app_generator_tts_publisher.py
│ │ ├── callback_handler/
│ │ │ ├── __init__.py
│ │ │ ├── agent_tool_callback_handler.py
│ │ │ ├── index_tool_callback_handler.py
│ │ │ └── workflow_tool_callback_handler.py
│ │ ├── datasource/
│ │ │ ├── __base/
│ │ │ │ ├── datasource_plugin.py
│ │ │ │ ├── datasource_provider.py
│ │ │ │ └── datasource_runtime.py
│ │ │ ├── __init__.py
│ │ │ ├── datasource_file_manager.py
│ │ │ ├── datasource_manager.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ ├── common_entities.py
│ │ │ │ └── datasource_entities.py
│ │ │ ├── errors.py
│ │ │ ├── local_file/
│ │ │ │ ├── local_file_plugin.py
│ │ │ │ └── local_file_provider.py
│ │ │ ├── online_document/
│ │ │ │ ├── online_document_plugin.py
│ │ │ │ └── online_document_provider.py
│ │ │ ├── online_drive/
│ │ │ │ ├── online_drive_plugin.py
│ │ │ │ └── online_drive_provider.py
│ │ │ ├── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ └── message_transformer.py
│ │ │ └── website_crawl/
│ │ │ ├── website_crawl_plugin.py
│ │ │ └── website_crawl_provider.py
│ │ ├── db/
│ │ │ ├── __init__.py
│ │ │ └── session_factory.py
│ │ ├── entities/
│ │ │ ├── __init__.py
│ │ │ ├── agent_entities.py
│ │ │ ├── document_task.py
│ │ │ ├── embedding_type.py
│ │ │ ├── execution_extra_content.py
│ │ │ ├── knowledge_entities.py
│ │ │ ├── mcp_provider.py
│ │ │ ├── model_entities.py
│ │ │ ├── parameter_entities.py
│ │ │ ├── provider_configuration.py
│ │ │ └── provider_entities.py
│ │ ├── errors/
│ │ │ ├── __init__.py
│ │ │ └── error.py
│ │ ├── extension/
│ │ │ ├── __init__.py
│ │ │ ├── api_based_extension_requestor.py
│ │ │ ├── extensible.py
│ │ │ └── extension.py
│ │ ├── external_data_tool/
│ │ │ ├── __init__.py
│ │ │ ├── api/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── api.py
│ │ │ ├── base.py
│ │ │ ├── external_data_fetch.py
│ │ │ └── factory.py
│ │ ├── helper/
│ │ │ ├── __init__.py
│ │ │ ├── code_executor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── code_executor.py
│ │ │ │ ├── code_node_provider.py
│ │ │ │ ├── javascript/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── javascript_code_provider.py
│ │ │ │ │ └── javascript_transformer.py
│ │ │ │ ├── jinja2/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── jinja2_formatter.py
│ │ │ │ │ └── jinja2_transformer.py
│ │ │ │ ├── python3/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── python3_code_provider.py
│ │ │ │ │ └── python3_transformer.py
│ │ │ │ └── template_transformer.py
│ │ │ ├── credential_utils.py
│ │ │ ├── csv_sanitizer.py
│ │ │ ├── download.py
│ │ │ ├── encrypter.py
│ │ │ ├── http_client_pooling.py
│ │ │ ├── marketplace.py
│ │ │ ├── model_provider_cache.py
│ │ │ ├── moderation.py
│ │ │ ├── module_import_helper.py
│ │ │ ├── name_generator.py
│ │ │ ├── position_helper.py
│ │ │ ├── provider_cache.py
│ │ │ ├── provider_encryption.py
│ │ │ ├── ssrf_proxy.py
│ │ │ ├── tool_parameter_cache.py
│ │ │ └── trace_id_helper.py
│ │ ├── hosting_configuration.py
│ │ ├── indexing_runner.py
│ │ ├── llm_generator/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── llm_generator.py
│ │ │ ├── output_parser/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── errors.py
│ │ │ │ ├── rule_config_generator.py
│ │ │ │ ├── structured_output.py
│ │ │ │ └── suggested_questions_after_answer.py
│ │ │ └── prompts.py
│ │ ├── logging/
│ │ │ ├── __init__.py
│ │ │ ├── context.py
│ │ │ ├── filters.py
│ │ │ └── structured_formatter.py
│ │ ├── mcp/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ └── auth_flow.py
│ │ │ ├── auth_client.py
│ │ │ ├── auth_client_comparison.md
│ │ │ ├── client/
│ │ │ │ ├── sse_client.py
│ │ │ │ └── streamable_client.py
│ │ │ ├── entities.py
│ │ │ ├── error.py
│ │ │ ├── mcp_client.py
│ │ │ ├── server/
│ │ │ │ └── streamable_http.py
│ │ │ ├── session/
│ │ │ │ ├── base_session.py
│ │ │ │ └── client_session.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── memory/
│ │ │ └── token_buffer_memory.py
│ │ ├── model_manager.py
│ │ ├── moderation/
│ │ │ ├── __init__.py
│ │ │ ├── api/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── api.py
│ │ │ ├── base.py
│ │ │ ├── factory.py
│ │ │ ├── input_moderation.py
│ │ │ ├── keywords/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── keywords.py
│ │ │ ├── openai_moderation/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── openai_moderation.py
│ │ │ └── output_moderation.py
│ │ ├── ops/
│ │ │ ├── __init__.py
│ │ │ ├── aliyun_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_trace.py
│ │ │ │ ├── data_exporter/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── traceclient.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── aliyun_trace_entity.py
│ │ │ │ │ └── semconv.py
│ │ │ │ └── utils.py
│ │ │ ├── arize_phoenix_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── arize_phoenix_trace.py
│ │ │ ├── base_trace_instance.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── config_entity.py
│ │ │ │ └── trace_entity.py
│ │ │ ├── langfuse_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── langfuse_trace_entity.py
│ │ │ │ └── langfuse_trace.py
│ │ │ ├── langsmith_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── langsmith_trace_entity.py
│ │ │ │ └── langsmith_trace.py
│ │ │ ├── mlflow_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── mlflow_trace.py
│ │ │ ├── opik_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── opik_trace.py
│ │ │ ├── ops_trace_manager.py
│ │ │ ├── tencent_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── client.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── semconv.py
│ │ │ │ │ └── tencent_trace_entity.py
│ │ │ │ ├── span_builder.py
│ │ │ │ ├── tencent_trace.py
│ │ │ │ └── utils.py
│ │ │ ├── utils.py
│ │ │ └── weave_trace/
│ │ │ ├── __init__.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ └── weave_trace_entity.py
│ │ │ └── weave_trace.py
│ │ ├── plugin/
│ │ │ ├── backwards_invocation/
│ │ │ │ ├── app.py
│ │ │ │ ├── base.py
│ │ │ │ ├── encrypt.py
│ │ │ │ ├── model.py
│ │ │ │ ├── node.py
│ │ │ │ └── tool.py
│ │ │ ├── endpoint/
│ │ │ │ └── exc.py
│ │ │ ├── entities/
│ │ │ │ ├── base.py
│ │ │ │ ├── bundle.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── marketplace.py
│ │ │ │ ├── oauth.py
│ │ │ │ ├── parameters.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── plugin_daemon.py
│ │ │ │ └── request.py
│ │ │ ├── impl/
│ │ │ │ ├── agent.py
│ │ │ │ ├── asset.py
│ │ │ │ ├── base.py
│ │ │ │ ├── datasource.py
│ │ │ │ ├── debugging.py
│ │ │ │ ├── dynamic_select.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── model.py
│ │ │ │ ├── model_runtime.py
│ │ │ │ ├── model_runtime_factory.py
│ │ │ │ ├── oauth.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── tool.py
│ │ │ │ └── trigger.py
│ │ │ └── utils/
│ │ │ ├── chunk_merger.py
│ │ │ ├── converter.py
│ │ │ └── http_parser.py
│ │ ├── prompt/
│ │ │ ├── __init__.py
│ │ │ ├── advanced_prompt_transform.py
│ │ │ ├── agent_history_prompt_transform.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ └── advanced_prompt_entities.py
│ │ │ ├── prompt_templates/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_prompt_templates.py
│ │ │ │ ├── baichuan_chat.json
│ │ │ │ ├── baichuan_completion.json
│ │ │ │ ├── common_chat.json
│ │ │ │ └── common_completion.json
│ │ │ ├── prompt_transform.py
│ │ │ ├── simple_prompt_transform.py
│ │ │ └── utils/
│ │ │ ├── __init__.py
│ │ │ ├── extract_thread_messages.py
│ │ │ ├── get_thread_messages_length.py
│ │ │ ├── prompt_message_util.py
│ │ │ └── prompt_template_parser.py
│ │ ├── provider_manager.py
│ │ ├── rag/
│ │ │ ├── __init__.py
│ │ │ ├── cleaner/
│ │ │ │ ├── clean_processor.py
│ │ │ │ └── cleaner_base.py
│ │ │ ├── data_post_processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_post_processor.py
│ │ │ │ └── reorder.py
│ │ │ ├── datasource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── keyword/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── jieba/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── jieba.py
│ │ │ │ │ │ ├── jieba_keyword_table_handler.py
│ │ │ │ │ │ └── stopwords.py
│ │ │ │ │ ├── keyword_base.py
│ │ │ │ │ ├── keyword_factory.py
│ │ │ │ │ └── keyword_type.py
│ │ │ │ ├── retrieval_service.py
│ │ │ │ └── vdb/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── alibabacloud_mysql/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── alibabacloud_mysql_vector.py
│ │ │ │ ├── analyticdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── analyticdb_vector.py
│ │ │ │ │ ├── analyticdb_vector_openapi.py
│ │ │ │ │ └── analyticdb_vector_sql.py
│ │ │ │ ├── baidu/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── baidu_vector.py
│ │ │ │ ├── chroma/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── chroma_vector.py
│ │ │ │ ├── clickzetta/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── clickzetta_vector.py
│ │ │ │ ├── couchbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── couchbase_vector.py
│ │ │ │ ├── elasticsearch/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── elasticsearch_ja_vector.py
│ │ │ │ │ └── elasticsearch_vector.py
│ │ │ │ ├── field.py
│ │ │ │ ├── hologres/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── hologres_vector.py
│ │ │ │ ├── huawei/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── huawei_cloud_vector.py
│ │ │ │ ├── iris/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── iris_vector.py
│ │ │ │ ├── lindorm/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── lindorm_vector.py
│ │ │ │ ├── matrixone/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── matrixone_vector.py
│ │ │ │ ├── milvus/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── milvus_vector.py
│ │ │ │ ├── myscale/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── myscale_vector.py
│ │ │ │ ├── oceanbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── oceanbase_vector.py
│ │ │ │ ├── opengauss/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── opengauss.py
│ │ │ │ ├── opensearch/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── opensearch_vector.py
│ │ │ │ ├── oracle/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── oraclevector.py
│ │ │ │ ├── pgvecto_rs/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── collection.py
│ │ │ │ │ └── pgvecto_rs.py
│ │ │ │ ├── pgvector/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── pgvector.py
│ │ │ │ ├── pyvastbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── vastbase_vector.py
│ │ │ │ ├── qdrant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── qdrant_vector.py
│ │ │ │ ├── relyt/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── relyt_vector.py
│ │ │ │ ├── tablestore/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tablestore_vector.py
│ │ │ │ ├── tencent/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tencent_vector.py
│ │ │ │ ├── tidb_on_qdrant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── tidb_on_qdrant_vector.py
│ │ │ │ │ └── tidb_service.py
│ │ │ │ ├── tidb_vector/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tidb_vector.py
│ │ │ │ ├── upstash/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── upstash_vector.py
│ │ │ │ ├── vector_base.py
│ │ │ │ ├── vector_factory.py
│ │ │ │ ├── vector_type.py
│ │ │ │ ├── vikingdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── vikingdb_vector.py
│ │ │ │ └── weaviate/
│ │ │ │ ├── __init__.py
│ │ │ │ └── weaviate_vector.py
│ │ │ ├── docstore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── dataset_docstore.py
│ │ │ ├── embedding/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cached_embedding.py
│ │ │ │ ├── embedding_base.py
│ │ │ │ └── retrieval.py
│ │ │ ├── entities/
│ │ │ │ ├── citation_metadata.py
│ │ │ │ ├── context_entities.py
│ │ │ │ ├── event.py
│ │ │ │ └── metadata_entities.py
│ │ │ ├── extractor/
│ │ │ │ ├── blob/
│ │ │ │ │ └── blob.py
│ │ │ │ ├── csv_extractor.py
│ │ │ │ ├── entity/
│ │ │ │ │ ├── datasource_type.py
│ │ │ │ │ └── extract_setting.py
│ │ │ │ ├── excel_extractor.py
│ │ │ │ ├── extract_processor.py
│ │ │ │ ├── extractor_base.py
│ │ │ │ ├── firecrawl/
│ │ │ │ │ ├── firecrawl_app.py
│ │ │ │ │ └── firecrawl_web_extractor.py
│ │ │ │ ├── helpers.py
│ │ │ │ ├── html_extractor.py
│ │ │ │ ├── jina_reader_extractor.py
│ │ │ │ ├── markdown_extractor.py
│ │ │ │ ├── notion_extractor.py
│ │ │ │ ├── pdf_extractor.py
│ │ │ │ ├── text_extractor.py
│ │ │ │ ├── unstructured/
│ │ │ │ │ ├── unstructured_doc_extractor.py
│ │ │ │ │ ├── unstructured_eml_extractor.py
│ │ │ │ │ ├── unstructured_epub_extractor.py
│ │ │ │ │ ├── unstructured_markdown_extractor.py
│ │ │ │ │ ├── unstructured_msg_extractor.py
│ │ │ │ │ ├── unstructured_ppt_extractor.py
│ │ │ │ │ ├── unstructured_pptx_extractor.py
│ │ │ │ │ └── unstructured_xml_extractor.py
│ │ │ │ ├── watercrawl/
│ │ │ │ │ ├── client.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── extractor.py
│ │ │ │ │ └── provider.py
│ │ │ │ └── word_extractor.py
│ │ │ ├── index_processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── constant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── built_in_field.py
│ │ │ │ │ ├── doc_type.py
│ │ │ │ │ ├── index_type.py
│ │ │ │ │ └── query_type.py
│ │ │ │ ├── index_processor.py
│ │ │ │ ├── index_processor_base.py
│ │ │ │ ├── index_processor_factory.py
│ │ │ │ └── processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── paragraph_index_processor.py
│ │ │ │ ├── parent_child_index_processor.py
│ │ │ │ └── qa_index_processor.py
│ │ │ ├── models/
│ │ │ │ ├── __init__.py
│ │ │ │ └── document.py
│ │ │ ├── pipeline/
│ │ │ │ ├── __init__.py
│ │ │ │ └── queue.py
│ │ │ ├── rerank/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entity/
│ │ │ │ │ └── weight.py
│ │ │ │ ├── rerank_base.py
│ │ │ │ ├── rerank_factory.py
│ │ │ │ ├── rerank_model.py
│ │ │ │ ├── rerank_type.py
│ │ │ │ └── weight_rerank.py
│ │ │ ├── retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── dataset_retrieval.py
│ │ │ │ ├── output_parser/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── react_output.py
│ │ │ │ │ └── structured_chat.py
│ │ │ │ ├── retrieval_methods.py
│ │ │ │ ├── router/
│ │ │ │ │ ├── multi_dataset_function_call_router.py
│ │ │ │ │ └── multi_dataset_react_route.py
│ │ │ │ └── template_prompts.py
│ │ │ ├── splitter/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixed_text_splitter.py
│ │ │ │ └── text_splitter.py
│ │ │ └── summary_index/
│ │ │ ├── __init__.py
│ │ │ └── summary_index.py
│ │ ├── repositories/
│ │ │ ├── __init__.py
│ │ │ ├── celery_workflow_execution_repository.py
│ │ │ ├── celery_workflow_node_execution_repository.py
│ │ │ ├── factory.py
│ │ │ ├── human_input_repository.py
│ │ │ ├── sqlalchemy_workflow_execution_repository.py
│ │ │ └── sqlalchemy_workflow_node_execution_repository.py
│ │ ├── schemas/
│ │ │ ├── __init__.py
│ │ │ ├── builtin/
│ │ │ │ └── schemas/
│ │ │ │ └── v1/
│ │ │ │ ├── file.json
│ │ │ │ ├── general_structure.json
│ │ │ │ ├── multimodal_general_structure.json
│ │ │ │ ├── multimodal_parent_child_structure.json
│ │ │ │ ├── parent_child_structure.json
│ │ │ │ └── qa_structure.json
│ │ │ ├── registry.py
│ │ │ ├── resolver.py
│ │ │ └── schema_manager.py
│ │ ├── telemetry/
│ │ │ ├── __init__.py
│ │ │ ├── events.py
│ │ │ └── gateway.py
│ │ ├── tools/
│ │ │ ├── __base/
│ │ │ │ ├── tool.py
│ │ │ │ ├── tool_provider.py
│ │ │ │ └── tool_runtime.py
│ │ │ ├── __init__.py
│ │ │ ├── builtin_tool/
│ │ │ │ ├── _position.yaml
│ │ │ │ ├── provider.py
│ │ │ │ ├── providers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _positions.py
│ │ │ │ │ ├── audio/
│ │ │ │ │ │ ├── audio.py
│ │ │ │ │ │ ├── audio.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── asr.py
│ │ │ │ │ │ ├── asr.yaml
│ │ │ │ │ │ ├── tts.py
│ │ │ │ │ │ └── tts.yaml
│ │ │ │ │ ├── code/
│ │ │ │ │ │ ├── code.py
│ │ │ │ │ │ ├── code.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── simple_code.py
│ │ │ │ │ │ └── simple_code.yaml
│ │ │ │ │ ├── time/
│ │ │ │ │ │ ├── time.py
│ │ │ │ │ │ ├── time.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── current_time.py
│ │ │ │ │ │ ├── current_time.yaml
│ │ │ │ │ │ ├── localtime_to_timestamp.py
│ │ │ │ │ │ ├── localtime_to_timestamp.yaml
│ │ │ │ │ │ ├── timestamp_to_localtime.py
│ │ │ │ │ │ ├── timestamp_to_localtime.yaml
│ │ │ │ │ │ ├── timezone_conversion.py
│ │ │ │ │ │ ├── timezone_conversion.yaml
│ │ │ │ │ │ ├── weekday.py
│ │ │ │ │ │ └── weekday.yaml
│ │ │ │ │ └── webscraper/
│ │ │ │ │ ├── tools/
│ │ │ │ │ │ ├── webscraper.py
│ │ │ │ │ │ └── webscraper.yaml
│ │ │ │ │ ├── webscraper.py
│ │ │ │ │ └── webscraper.yaml
│ │ │ │ └── tool.py
│ │ │ ├── custom_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ ├── common_entities.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── tool_bundle.py
│ │ │ │ ├── tool_entities.py
│ │ │ │ └── values.py
│ │ │ ├── errors.py
│ │ │ ├── mcp_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── plugin_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── signature.py
│ │ │ ├── tool_engine.py
│ │ │ ├── tool_file_manager.py
│ │ │ ├── tool_label_manager.py
│ │ │ ├── tool_manager.py
│ │ │ ├── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── dataset_retriever/
│ │ │ │ │ ├── dataset_multi_retriever_tool.py
│ │ │ │ │ ├── dataset_retriever_base_tool.py
│ │ │ │ │ └── dataset_retriever_tool.py
│ │ │ │ ├── dataset_retriever_tool.py
│ │ │ │ ├── encryption.py
│ │ │ │ ├── message_transformer.py
│ │ │ │ ├── model_invocation_utils.py
│ │ │ │ ├── parser.py
│ │ │ │ ├── system_oauth_encryption.py
│ │ │ │ ├── text_processing_utils.py
│ │ │ │ ├── uuid_utils.py
│ │ │ │ ├── web_reader_tool.py
│ │ │ │ ├── workflow_configuration_sync.py
│ │ │ │ └── yaml_utils.py
│ │ │ └── workflow_as_tool/
│ │ │ ├── provider.py
│ │ │ └── tool.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── debug/
│ │ │ │ ├── event_bus.py
│ │ │ │ ├── event_selectors.py
│ │ │ │ └── events.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ └── entities.py
│ │ │ ├── errors.py
│ │ │ ├── provider.py
│ │ │ ├── trigger_manager.py
│ │ │ └── utils/
│ │ │ ├── encryption.py
│ │ │ ├── endpoint.py
│ │ │ └── locks.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ ├── file_reference.py
│ │ ├── human_input_compat.py
│ │ ├── human_input_forms.py
│ │ ├── node_factory.py
│ │ ├── node_runtime.py
│ │ ├── nodes/
│ │ │ ├── __init__.py
│ │ │ ├── agent/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_node.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── message_transformer.py
│ │ │ │ ├── plugin_strategy_adapter.py
│ │ │ │ ├── runtime_support.py
│ │ │ │ └── strategy_protocols.py
│ │ │ ├── datasource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── datasource_node.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── protocols.py
│ │ │ ├── knowledge_index/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── knowledge_index_node.py
│ │ │ │ └── protocols.py
│ │ │ ├── knowledge_retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── knowledge_retrieval_node.py
│ │ │ │ ├── retrieval.py
│ │ │ │ └── template_prompts.py
│ │ │ ├── trigger_plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── trigger_event_node.py
│ │ │ ├── trigger_schedule/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── trigger_schedule_node.py
│ │ │ └── trigger_webhook/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── exc.py
│ │ │ └── node.py
│ │ ├── system_variables.py
│ │ ├── template_rendering.py
│ │ ├── variable_pool_initializer.py
│ │ ├── variable_prefixes.py
│ │ ├── workflow_entry.py
│ │ └── workflow_run_outputs.py
│ ├── dify_app.py
│ ├── docker/
│ │ └── entrypoint.sh
│ ├── enterprise/
│ │ ├── __init__.py
│ │ └── telemetry/
│ │ ├── DATA_DICTIONARY.md
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── contracts.py
│ │ ├── draft_trace.py
│ │ ├── enterprise_trace.py
│ │ ├── entities/
│ │ │ └── __init__.py
│ │ ├── event_handlers.py
│ │ ├── exporter.py
│ │ ├── id_generator.py
│ │ ├── metric_handler.py
│ │ └── telemetry_log.py
│ ├── enums/
│ │ ├── __init__.py
│ │ ├── cloud_plan.py
│ │ ├── hosted_provider.py
│ │ └── quota_type.py
│ ├── events/
│ │ ├── __init__.py
│ │ ├── app_event.py
│ │ ├── dataset_event.py
│ │ ├── document_event.py
│ │ ├── document_index_event.py
│ │ ├── event_handlers/
│ │ │ ├── __init__.py
│ │ │ ├── clean_when_dataset_deleted.py
│ │ │ ├── clean_when_document_deleted.py
│ │ │ ├── create_document_index.py
│ │ │ ├── create_installed_app_when_app_created.py
│ │ │ ├── create_site_record_when_app_created.py
│ │ │ ├── delete_tool_parameters_cache_when_sync_draft_workflow.py
│ │ │ ├── queue_credential_sync_when_tenant_created.py
│ │ │ ├── sync_plugin_trigger_when_app_created.py
│ │ │ ├── sync_webhook_when_app_created.py
│ │ │ ├── sync_workflow_schedule_when_app_published.py
│ │ │ ├── update_app_dataset_join_when_app_model_config_updated.py
│ │ │ ├── update_app_dataset_join_when_app_published_workflow_updated.py
│ │ │ ├── update_app_triggers_when_app_published_workflow_updated.py
│ │ │ └── update_provider_when_message_created.py
│ │ ├── message_event.py
│ │ └── tenant_event.py
│ ├── extensions/
│ │ ├── __init__.py
│ │ ├── ext_app_metrics.py
│ │ ├── ext_blueprints.py
│ │ ├── ext_celery.py
│ │ ├── ext_code_based_extension.py
│ │ ├── ext_commands.py
│ │ ├── ext_compress.py
│ │ ├── ext_database.py
│ │ ├── ext_enterprise_telemetry.py
│ │ ├── ext_fastopenapi.py
│ │ ├── ext_forward_refs.py
│ │ ├── ext_hosting_provider.py
│ │ ├── ext_import_modules.py
│ │ ├── ext_logging.py
│ │ ├── ext_login.py
│ │ ├── ext_logstore.py
│ │ ├── ext_mail.py
│ │ ├── ext_migrate.py
│ │ ├── ext_orjson.py
│ │ ├── ext_otel.py
│ │ ├── ext_proxy_fix.py
│ │ ├── ext_redis.py
│ │ ├── ext_request_logging.py
│ │ ├── ext_sentry.py
│ │ ├── ext_session_factory.py
│ │ ├── ext_set_secretkey.py
│ │ ├── ext_storage.py
│ │ ├── ext_timezone.py
│ │ ├── ext_warnings.py
│ │ ├── logstore/
│ │ │ ├── __init__.py
│ │ │ ├── aliyun_logstore.py
│ │ │ ├── aliyun_logstore_pg.py
│ │ │ ├── repositories/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── logstore_api_workflow_node_execution_repository.py
│ │ │ │ ├── logstore_api_workflow_run_repository.py
│ │ │ │ ├── logstore_workflow_execution_repository.py
│ │ │ │ └── logstore_workflow_node_execution_repository.py
│ │ │ └── sql_escape.py
│ │ ├── otel/
│ │ │ ├── __init__.py
│ │ │ ├── celery_sqlcommenter.py
│ │ │ ├── decorators/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── handler.py
│ │ │ │ └── handlers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── generate_handler.py
│ │ │ │ └── workflow_app_runner_handler.py
│ │ │ ├── instrumentation.py
│ │ │ ├── parser/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── llm.py
│ │ │ │ ├── retrieval.py
│ │ │ │ └── tool.py
│ │ │ ├── runtime.py
│ │ │ └── semconv/
│ │ │ ├── __init__.py
│ │ │ ├── dify.py
│ │ │ └── gen_ai.py
│ │ └── storage/
│ │ ├── aliyun_oss_storage.py
│ │ ├── aws_s3_storage.py
│ │ ├── azure_blob_storage.py
│ │ ├── baidu_obs_storage.py
│ │ ├── base_storage.py
│ │ ├── clickzetta_volume/
│ │ │ ├── __init__.py
│ │ │ ├── clickzetta_volume_storage.py
│ │ │ ├── file_lifecycle.py
│ │ │ └── volume_permissions.py
│ │ ├── google_cloud_storage.py
│ │ ├── huawei_obs_storage.py
│ │ ├── opendal_storage.py
│ │ ├── oracle_oci_storage.py
│ │ ├── storage_type.py
│ │ ├── supabase_storage.py
│ │ ├── tencent_cos_storage.py
│ │ └── volcengine_tos_storage.py
│ ├── factories/
│ │ ├── __init__.py
│ │ ├── agent_factory.py
│ │ ├── file_factory/
│ │ │ ├── __init__.py
│ │ │ ├── builders.py
│ │ │ ├── common.py
│ │ │ ├── message_files.py
│ │ │ ├── remote.py
│ │ │ ├── storage_keys.py
│ │ │ └── validation.py
│ │ └── variable_factory.py
│ ├── fields/
│ │ ├── __init__.py
│ │ ├── _value_type_serializer.py
│ │ ├── annotation_fields.py
│ │ ├── api_based_extension_fields.py
│ │ ├── app_fields.py
│ │ ├── conversation_fields.py
│ │ ├── conversation_variable_fields.py
│ │ ├── data_source_fields.py
│ │ ├── dataset_fields.py
│ │ ├── document_fields.py
│ │ ├── end_user_fields.py
│ │ ├── file_fields.py
│ │ ├── hit_testing_fields.py
│ │ ├── installed_app_fields.py
│ │ ├── member_fields.py
│ │ ├── message_fields.py
│ │ ├── rag_pipeline_fields.py
│ │ ├── raws.py
│ │ ├── segment_fields.py
│ │ ├── tag_fields.py
│ │ ├── workflow_app_log_fields.py
│ │ ├── workflow_fields.py
│ │ ├── workflow_run_fields.py
│ │ └── workflow_trigger_fields.py
│ ├── gunicorn.conf.py
│ ├── libs/
│ │ ├── __init__.py
│ │ ├── archive_storage.py
│ │ ├── broadcast_channel/
│ │ │ ├── channel.py
│ │ │ ├── exc.py
│ │ │ └── redis/
│ │ │ ├── __init__.py
│ │ │ ├── _subscription.py
│ │ │ ├── channel.py
│ │ │ ├── sharded_channel.py
│ │ │ └── streams_channel.py
│ │ ├── collection_utils.py
│ │ ├── custom_inputs.py
│ │ ├── datetime_utils.py
│ │ ├── db_migration_lock.py
│ │ ├── email_i18n.py
│ │ ├── email_template_renderer.py
│ │ ├── encryption.py
│ │ ├── exception.py
│ │ ├── external_api.py
│ │ ├── file_utils.py
│ │ ├── flask_utils.py
│ │ ├── gmpy2_pkcs10aep_cipher.py
│ │ ├── helper.py
│ │ ├── infinite_scroll_pagination.py
│ │ ├── json_in_md_parser.py
│ │ ├── login.py
│ │ ├── module_loading.py
│ │ ├── oauth.py
│ │ ├── oauth_data_source.py
│ │ ├── orjson.py
│ │ ├── passport.py
│ │ ├── password.py
│ │ ├── pyrefly_diagnostics.py
│ │ ├── rsa.py
│ │ ├── schedule_utils.py
│ │ ├── sendgrid.py
│ │ ├── smtp.py
│ │ ├── time_parser.py
│ │ ├── token.py
│ │ ├── typing.py
│ │ ├── uuid_utils.py
│ │ ├── validators.py
│ │ └── workspace_permission.py
│ ├── migrations/
│ │ ├── README
│ │ ├── alembic.ini
│ │ ├── env.py
│ │ ├── script.py.mako
│ │ └── versions/
│ │ ├── 00bacef91f18_rename_api_provider_description.py
│ │ ├── 03f98355ba0e_add_workflow_tool_label_and_tool_.py
│ │ ├── 04c602f5dc9b_update_appmodelconfig_and_add_table_.py
│ │ ├── 053da0c1d756_add_api_tool_privacy.py
│ │ ├── 114eed84c228_remove_tool_id_from_model_invoke.py
│ │ ├── 161cadc1af8d_add_dataset_permission_tenant_id.py
│ │ ├── 16830a790f0f_.py
│ │ ├── 16fa53d9faec_add_provider_model_support.py
│ │ ├── 17b5ab037c40_add_keyworg_table_storage_type.py
│ │ ├── 187385f442fc_modify_provider_model_name_length.py
│ │ ├── 2024_08_09_0801-1787fbae959a_update_tools_original_url_length.py
│ │ ├── 2024_08_13_0633-63a83fcf12ba_support_conversation_variables.py
│ │ ├── 2024_08_14_1354-8782057ff0dc_add_conversations_dialogue_count.py
│ │ ├── 2024_08_15_0956-0251a1c768cc_add_tidb_auth_binding.py
│ │ ├── 2024_08_15_1001-a6be81136580_app_and_site_icon_type.py
│ │ ├── 2024_08_20_0455-2dbe42621d96_rename_workflow__conversation_variables_.py
│ │ ├── 2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py
│ │ ├── 2024_09_01_1255-030f4915f36a_add_use_icon_as_answer_icon_fields_for_.py
│ │ ├── 2024_09_11_1012-d57ba9ebb251_add_parent_message_id_to_messages.py
│ │ ├── 2024_09_24_0922-6af6a521a53e_update_retrieval_resource.py
│ │ ├── 2024_09_25_0434-33f5fac87f29_external_knowledge_api.py
│ │ ├── 2024_09_29_0835-ddcc8bbef391_increase_max_length_of_builtin_tool_provider.py
│ │ ├── 2024_10_09_1329-d8e744d88ed6_fix_wrong_service_api_history.py
│ │ ├── 2024_10_10_0516-bbadea11becb_add_name_and_size_to_tool_files.py
│ │ ├── 2024_10_22_0959-43fa78bc3b7d_add_white_list.py
│ │ ├── 2024_10_28_0720-08ec4f75af5e_add_tenant_plugin_permisisons.py
│ │ ├── 2024_11_01_0434-d3f6769a94a3_add_upload_files_source_url.py
│ │ ├── 2024_11_01_0449-93ad8c19c40b_rename_conversation_variables_index_name.py
│ │ ├── 2024_11_01_0540-f4d7ce70a7ca_update_upload_files_source_url.py
│ │ ├── 2024_11_01_0622-d07474999927_update_type_of_custom_disclaimer_to_text.py
│ │ ├── 2024_11_01_0623-09a8d1878d9b_update_workflows_graph_features_and_.py
│ │ ├── 2024_11_12_0925-01d6889832f7_add_created_at_index_for_messages.py
│ │ ├── 2024_11_22_0701-e19037032219_parent_child_index.py
│ │ ├── 2024_11_28_0553-cf8f4fc45278_add_exceptions_count_field_to_.py
│ │ ├── 2024_12_19_1746-11b07f66c737_remove_unused_tool_providers.py
│ │ ├── 2024_12_20_0628-e1944c35e15e_add_retry_index_field_to_node_execution_.py
│ │ ├── 2024_12_23_1154-d7999dfa4aae_remove_workflow_node_executions_retry_.py
│ │ ├── 2024_12_25_1137-923752d42eb6_add_auto_disabled_dataset_logs.py
│ │ ├── 2025_01_01_2000-a91b476a53de_change_workflow_runs_total_tokens_to_.py
│ │ ├── 2025_01_14_0617-f051706725cc_add_rate_limit_logs.py
│ │ ├── 2025_02_27_0917-d20049ed0af6_add_metadata_function.py
│ │ ├── 2025_03_03_0304-4413929e1ec2_extend_provider_name_column.py
│ │ ├── 2025_03_03_1436-ee79d9b1c156_add_marked_name_and_marked_comment_in_.py
│ │ ├── 2025_03_07_0315-5511c782ee4c_extend_provider_column.py
│ │ ├── 2025_03_29_2227-6a9f914f656c_change_documentsegment_and_childchunk_.py
│ │ ├── 2025_05_14_1403-d28f2004b072_add_index_for_workflow_conversation_.py
│ │ ├── 2025_05_15_1531-2adcbe1f5dfb_add_workflowdraftvariable_model.py
│ │ ├── 2025_06_06_1424-4474872b0ee6_workflow_draft_varaibles_add_node_execution_id.py
│ │ ├── 2025_06_19_1633-0ab65e1cc7fa_remove_sequence_number_from_workflow_.py
│ │ ├── 2025_06_25_0936-58eb7bdb93fe_add_mcp_server_tool_and_app_server.py
│ │ ├── 2025_07_02_2332-1c9ba48be8e4_add_uuidv7_function_in_sql.py
│ │ ├── 2025_07_04_1705-71f5020c6470_tool_oauth.py
│ │ ├── 2025_07_21_0935-1a83934ad6d1_update_models.py
│ │ ├── 2025_07_22_0019-375fe79ead14_oauth_refresh_token.py
│ │ ├── 2025_07_23_1508-8bcc02c9bd07_add_tenant_plugin_autoupgrade_table.py
│ │ ├── 2025_07_24_1450-532b3f888abf_manual_dataset_field_update.py
│ │ ├── 2025_08_07_1115-fa8b0fa6f407_add_timeout_for_tool_mcp_providers.py
│ │ ├── 2025_08_09_1553-e8446f481c1e_add_provider_credential_pool_support.py
│ │ ├── 2025_08_13_1605-0e154742a5fa_add_provider_model_multi_credential.py
│ │ ├── 2025_08_20_1747-8d289573e1da_add_oauth_provider_apps.py
│ │ ├── 2025_08_29_1534-b95962a3885c_add_workflow_app_log_run_id_index.py
│ │ ├── 2025_09_08_1007-c20211f18133_add_headers_to_mcp_provider.py
│ │ ├── 2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py
│ │ ├── 2025_09_17_1515-68519ad5cd18_knowledge_pipeline_migrate.py
│ │ ├── 2025_10_14_1618-d98acf217d43_add_app_mode_for_messsage.py
│ │ ├── 2025_10_21_1430-ae662b25d9bc_remove_builtin_template_user.py
│ │ ├── 2025_10_22_1611-03f8dcbc611e_add_workflowpause_model.py
│ │ ├── 2025_10_30_1518-669ffd70119c_introduce_trigger.py
│ │ ├── 2025_11_06_1603-9e6fa5cbcd80_make_message_annotation_question_not_.py
│ │ ├── 2025_11_12_1537-d57accd375ae_support_multi_modal.py
│ │ ├── 2025_11_15_2102-09cfdda155d1_mysql_adaptation.py
│ │ ├── 2025_11_18_1859-7bb281b7a422_add_workflow_pause_reasons_table.py
│ │ ├── 2025_12_16_1817-03ea244985ce_add_type_column_not_null_default_tool.py
│ │ ├── 2025_12_25_1039-7df29de0f6be_add_credit_pool.py
│ │ ├── 2026_01_09_1630-905527cc8fd3_add_workflow_run_created_at_id_idx.py
│ │ ├── 2026_01_12_1729-3334862ee907_feat_add_created_at_id_index_to_messages.py
│ │ ├── 2026_01_16_1715-288345cd01d1_change_workflow_node_execution_run_index.py
│ │ ├── 2026_01_17_1110-f9f6d18a37f9_add_table_explore_banner_and_trial.py
│ │ ├── 2026_01_21_1718-9d77545f524e_add_workflow_archive_logs.py
│ │ ├── 2026_01_27_1815-788d3099ae3a_add_summary_index_feature.py
│ │ ├── 2026_01_29_1415-e8c3b3c46151_add_human_input_related_db_models.py
│ │ ├── 2026_02_09_0950-c3df22613c99_drop_server_default_for_app_trail_.py
│ │ ├── 2026_02_10_1507-f55813ffe2c8_fix_tenant_default_model_unique.py
│ │ ├── 2026_02_11_1549-fce013ca180e_fix_index_to_optimize_message_clean_job_.py
│ │ ├── 2026_02_26_1336-e288952f2994_add_partial_indexes_on_conversations_.py
│ │ ├── 2026_03_02_1805-0ec65df55790_add_indexes_for_human_input_forms.py
│ │ ├── 2026_03_04_1600-6b5f9f8b1a2c_add_user_id_to_workflow_draft_variables.py
│ │ ├── 23db93619b9d_add_message_files_into_agent_thought.py
│ │ ├── 246ba09cbbdb_add_app_anntation_setting.py
│ │ ├── 2a3aebbbf4bb_add_app_tracing.py
│ │ ├── 2beac44e5f5f_add_is_universal_in_apps.py
│ │ ├── 2c8af9671032_add_qa_document_language.py
│ │ ├── 2e9819ca5b28_add_tenant_id_in_api_token.py
│ │ ├── 380c6aa5a70d_add_tool_labels_to_agent_thought.py
│ │ ├── 3b18fea55204_add_tool_label_bings.py
│ │ ├── 3c7cac9521c6_add_tags_and_binding_table.py
│ │ ├── 3ef9b2b6bee6_add_assistant_app.py
│ │ ├── 408176b91ad3_add_max_active_requests.py
│ │ ├── 42e85ed5564d_conversation_columns_set_nullable.py
│ │ ├── 46976cc39132_add_annotation_histoiry_score.py
│ │ ├── 47cc7df8c4f3_modify_default_model_name_length.py
│ │ ├── 4823da1d26cf_add_tool_file.py
│ │ ├── 4829e54d2fee_change_message_chain_id_to_nullable.py
│ │ ├── 4bcffcd64aa4_update_dataset_model_field_null_.py
│ │ ├── 4e99a8df00ff_add_load_balancing.py
│ │ ├── 4ff534e1eb11_add_workflow_to_site.py
│ │ ├── 5022897aaceb_add_model_name_in_embedding.py
│ │ ├── 53bf8af60645_update_model.py
│ │ ├── 563cf8bf777b_enable_tool_file_without_conversation_id.py
│ │ ├── 5fda94355fce_custom_disclaimer.py
│ │ ├── 614f77cecc48_add_last_active_at.py
│ │ ├── 63f9175e515b_merge_branches.py
│ │ ├── 64a70a7aab8b_add_workflow_run_index.py
│ │ ├── 64b051264f32_init.py
│ │ ├── 675b5321501b_add_node_execution_id_into_node_.py
│ │ ├── 6dcb43972bdc_add_dataset_retriever_resource.py
│ │ ├── 6e2cfb077b04_add_dataset_collection_binding.py
│ │ ├── 6e957a32015b_add_embedding_cache_created_at_index.py
│ │ ├── 714aafe25d39_add_anntation_history_match_response.py
│ │ ├── 77e83833755c_add_app_config_retriever_resource.py
│ │ ├── 7b45942e39bb_add_api_key_auth_binding.py
│ │ ├── 7bdef072e63a_add_workflow_tool.py
│ │ ├── 7ce5a52e4eee_add_tool_providers.py
│ │ ├── 7e6a8693e07a_add_table_dataset_permissions.py
│ │ ├── 853f9b9cd3b6_add_message_price_unit.py
│ │ ├── 88072f0caa04_add_custom_config_in_tenant.py
│ │ ├── 89c7899ca936_.py
│ │ ├── 8ae9bc661daa_add_tool_conversation_variables_idx.py
│ │ ├── 8d2d099ceb74_add_qa_model_support.py
│ │ ├── 8e5588e6412e_add_environment_variable_to_workflow_.py
│ │ ├── 8ec536f3c800_rename_api_provider_credentails.py
│ │ ├── 8fe468ba0ca5_add_gpt4v_supports.py
│ │ ├── 968fff4c0ab9_add_api_based_extension.py
│ │ ├── 9e98fbaffb88_add_workflow_tool_version.py
│ │ ├── 9f4e3427ea84_add_created_by_role.py
│ │ ├── 9fafbd60eca1_add_message_file_belongs_to.py
│ │ ├── a45f4dfde53b_add_language_to_recommend_apps.py
│ │ ├── a5b56fb053ef_app_config_add_speech_to_text.py
│ │ ├── a8d7385a7b66_add_embeddings_provider_name.py
│ │ ├── a8f9b3c45e4a_add_tenant_id_db_index.py
│ │ ├── a9836e3baeee_add_external_data_tools_in_app_model_.py
│ │ ├── ab23c11305d4_add_dataset_query_variable_at_app_model_.py
│ │ ├── ad472b61a054_add_api_provider_icon.py
│ │ ├── b24be59fbb04_.py
│ │ ├── b2602e131636_add_workflow_run_id_index_for_message.py
│ │ ├── b289e2408ee2_add_workflow.py
│ │ ├── b3a09c049e8e_add_advanced_prompt_templates.py
│ │ ├── b5429b71023c_messages_columns_set_nullable.py
│ │ ├── b69ca54b9208_add_chatbot_color_theme.py
│ │ ├── bf0aec5ba2cf_add_provider_order.py
│ │ ├── c031d46af369_remove_app_model_config_trace_config_.py
│ │ ├── c3311b089690_add_tool_meta.py
│ │ ├── c71211c8f604_add_tool_invoke_model_log.py
│ │ ├── cc04d0998d4d_set_model_config_column_nullable.py
│ │ ├── d3d503a3471c_add_is_deleted_to_conversations.py
│ │ ├── de95f5c77138_migration_serpapi_api_key.py
│ │ ├── dfb3b7f477da_add_tool_index.py
│ │ ├── e1901f623fd0_add_annotation_reply.py
│ │ ├── e2eacc9a1b63_add_status_for_message.py
│ │ ├── e32f6ccb87c6_e08af0a69ccefbb59fa80c778efee300bb780980.py
│ │ ├── e35ed59becda_modify_quota_limit_field_type.py
│ │ ├── e8883b0148c9_add_dataset_model_name.py
│ │ ├── eeb2e349e6ac_increase_max_model_name_length.py
│ │ ├── f25003750af4_add_created_updated_at.py
│ │ ├── f2a6fc85e260_add_anntation_history_message_id.py
│ │ ├── f9107f83abab_add_desc_for_apps.py
│ │ ├── fca025d3b60f_add_dataset_retrival_model.py
│ │ └── fecff1c3da27_remove_extra_tracing_app_config_table.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── _workflow_exc.py
│ │ ├── account.py
│ │ ├── api_based_extension.py
│ │ ├── base.py
│ │ ├── dataset.py
│ │ ├── engine.py
│ │ ├── enums.py
│ │ ├── execution_extra_content.py
│ │ ├── human_input.py
│ │ ├── model.py
│ │ ├── oauth.py
│ │ ├── provider.py
│ │ ├── provider_ids.py
│ │ ├── source.py
│ │ ├── task.py
│ │ ├── tools.py
│ │ ├── trigger.py
│ │ ├── types.py
│ │ ├── utils/
│ │ │ ├── __init__.py
│ │ │ └── file_input_compat.py
│ │ ├── web.py
│ │ └── workflow.py
│ ├── pyproject.toml
│ ├── pyrefly-local-excludes.txt
│ ├── pyrightconfig.json
│ ├── pytest.ini
│ ├── repositories/
│ │ ├── __init__.py
│ │ ├── api_workflow_node_execution_repository.py
│ │ ├── api_workflow_run_repository.py
│ │ ├── entities/
│ │ │ └── workflow_pause.py
│ │ ├── execution_extra_content_repository.py
│ │ ├── factory.py
│ │ ├── sqlalchemy_api_workflow_node_execution_repository.py
│ │ ├── sqlalchemy_api_workflow_run_repository.py
│ │ ├── sqlalchemy_execution_extra_content_repository.py
│ │ ├── sqlalchemy_workflow_trigger_log_repository.py
│ │ ├── types.py
│ │ └── workflow_trigger_log_repository.py
│ ├── schedule/
│ │ ├── check_upgradable_plugin_task.py
│ │ ├── clean_embedding_cache_task.py
│ │ ├── clean_messages.py
│ │ ├── clean_unused_datasets_task.py
│ │ ├── clean_workflow_runlogs_precise.py
│ │ ├── clean_workflow_runs_task.py
│ │ ├── create_tidb_serverless_task.py
│ │ ├── mail_clean_document_notify_task.py
│ │ ├── queue_monitor_task.py
│ │ ├── trigger_provider_refresh_task.py
│ │ ├── update_api_token_last_used_task.py
│ │ ├── update_tidb_serverless_status_task.py
│ │ └── workflow_schedule_task.py
│ ├── services/
│ │ ├── __init__.py
│ │ ├── account_service.py
│ │ ├── advanced_prompt_template_service.py
│ │ ├── agent_service.py
│ │ ├── annotation_service.py
│ │ ├── api_based_extension_service.py
│ │ ├── api_token_service.py
│ │ ├── app_dsl_service.py
│ │ ├── app_generate_service.py
│ │ ├── app_model_config_service.py
│ │ ├── app_service.py
│ │ ├── app_task_service.py
│ │ ├── async_workflow_service.py
│ │ ├── attachment_service.py
│ │ ├── audio_service.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── api_key_auth_base.py
│ │ │ ├── api_key_auth_factory.py
│ │ │ ├── api_key_auth_service.py
│ │ │ ├── auth_type.py
│ │ │ ├── firecrawl/
│ │ │ │ ├── __init__.py
│ │ │ │ └── firecrawl.py
│ │ │ ├── jina/
│ │ │ │ ├── __init__.py
│ │ │ │ └── jina.py
│ │ │ ├── jina.py
│ │ │ └── watercrawl/
│ │ │ ├── __init__.py
│ │ │ └── watercrawl.py
│ │ ├── billing_service.py
│ │ ├── clear_free_plan_tenant_expired_logs.py
│ │ ├── code_based_extension_service.py
│ │ ├── conversation_service.py
│ │ ├── conversation_variable_updater.py
│ │ ├── credit_pool_service.py
│ │ ├── dataset_service.py
│ │ ├── datasource_provider_service.py
│ │ ├── document_indexing_proxy/
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── batch_indexing_base.py
│ │ │ ├── document_indexing_task_proxy.py
│ │ │ └── duplicate_document_indexing_task_proxy.py
│ │ ├── end_user_service.py
│ │ ├── enterprise/
│ │ │ ├── __init__.py
│ │ │ ├── account_deletion_sync.py
│ │ │ ├── base.py
│ │ │ ├── enterprise_service.py
│ │ │ ├── plugin_manager_service.py
│ │ │ └── workspace_sync.py
│ │ ├── entities/
│ │ │ ├── __init__.py
│ │ │ ├── external_knowledge_entities/
│ │ │ │ └── external_knowledge_entities.py
│ │ │ ├── knowledge_entities/
│ │ │ │ ├── knowledge_entities.py
│ │ │ │ └── rag_pipeline_entities.py
│ │ │ └── model_provider_entities.py
│ │ ├── errors/
│ │ │ ├── __init__.py
│ │ │ ├── account.py
│ │ │ ├── app.py
│ │ │ ├── app_model_config.py
│ │ │ ├── audio.py
│ │ │ ├── base.py
│ │ │ ├── chunk.py
│ │ │ ├── conversation.py
│ │ │ ├── dataset.py
│ │ │ ├── document.py
│ │ │ ├── enterprise.py
│ │ │ ├── file.py
│ │ │ ├── index.py
│ │ │ ├── llm.py
│ │ │ ├── message.py
│ │ │ ├── plugin.py
│ │ │ ├── workflow_service.py
│ │ │ └── workspace.py
│ │ ├── external_knowledge_service.py
│ │ ├── feature_service.py
│ │ ├── feedback_service.py
│ │ ├── file_service.py
│ │ ├── hit_testing_service.py
│ │ ├── human_input_delivery_test_service.py
│ │ ├── human_input_service.py
│ │ ├── knowledge_service.py
│ │ ├── message_service.py
│ │ ├── metadata_service.py
│ │ ├── model_load_balancing_service.py
│ │ ├── model_provider_service.py
│ │ ├── oauth_server.py
│ │ ├── operation_service.py
│ │ ├── ops_service.py
│ │ ├── plugin/
│ │ │ ├── __init__.py
│ │ │ ├── data_migration.py
│ │ │ ├── dependencies_analysis.py
│ │ │ ├── endpoint_service.py
│ │ │ ├── oauth_service.py
│ │ │ ├── plugin_auto_upgrade_service.py
│ │ │ ├── plugin_migration.py
│ │ │ ├── plugin_parameter_service.py
│ │ │ ├── plugin_permission_service.py
│ │ │ └── plugin_service.py
│ │ ├── rag_pipeline/
│ │ │ ├── entity/
│ │ │ │ └── pipeline_service_api_entities.py
│ │ │ ├── pipeline_generate_service.py
│ │ │ ├── pipeline_template/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── built_in/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── built_in_retrieval.py
│ │ │ │ ├── customized/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── customized_retrieval.py
│ │ │ │ ├── database/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── database_retrieval.py
│ │ │ │ ├── pipeline_template_base.py
│ │ │ │ ├── pipeline_template_factory.py
│ │ │ │ ├── pipeline_template_type.py
│ │ │ │ └── remote/
│ │ │ │ ├── __init__.py
│ │ │ │ └── remote_retrieval.py
│ │ │ ├── rag_pipeline.py
│ │ │ ├── rag_pipeline_dsl_service.py
│ │ │ ├── rag_pipeline_manage_service.py
│ │ │ ├── rag_pipeline_task_proxy.py
│ │ │ ├── rag_pipeline_transform_service.py
│ │ │ └── transform/
│ │ │ ├── file-general-economy.yml
│ │ │ ├── file-general-high-quality.yml
│ │ │ ├── file-parentchild.yml
│ │ │ ├── notion-general-economy.yml
│ │ │ ├── notion-general-high-quality.yml
│ │ │ ├── notion-parentchild.yml
│ │ │ ├── website-crawl-general-economy.yml
│ │ │ ├── website-crawl-general-high-quality.yml
│ │ │ └── website-crawl-parentchild.yml
│ │ ├── recommend_app/
│ │ │ ├── __init__.py
│ │ │ ├── buildin/
│ │ │ │ ├── __init__.py
│ │ │ │ └── buildin_retrieval.py
│ │ │ ├── database/
│ │ │ │ ├── __init__.py
│ │ │ │ └── database_retrieval.py
│ │ │ ├── recommend_app_base.py
│ │ │ ├── recommend_app_factory.py
│ │ │ ├── recommend_app_type.py
│ │ │ └── remote/
│ │ │ ├── __init__.py
│ │ │ └── remote_retrieval.py
│ │ ├── recommended_app_service.py
│ │ ├── retention/
│ │ │ ├── __init__.py
│ │ │ ├── conversation/
│ │ │ │ ├── message_export_service.py
│ │ │ │ ├── messages_clean_policy.py
│ │ │ │ └── messages_clean_service.py
│ │ │ └── workflow_run/
│ │ │ ├── __init__.py
│ │ │ ├── archive_paid_plan_workflow_run.py
│ │ │ ├── clear_free_plan_expired_workflow_run_logs.py
│ │ │ ├── constants.py
│ │ │ ├── delete_archived_workflow_run.py
│ │ │ └── restore_archived_workflow_run.py
│ │ ├── saved_message_service.py
│ │ ├── summary_index_service.py
│ │ ├── tag_service.py
│ │ ├── tools/
│ │ │ ├── api_tools_manage_service.py
│ │ │ ├── builtin_tools_manage_service.py
│ │ │ ├── mcp_tools_manage_service.py
│ │ │ ├── tool_labels_service.py
│ │ │ ├── tools_manage_service.py
│ │ │ ├── tools_transform_service.py
│ │ │ └── workflow_tools_manage_service.py
│ │ ├── trigger/
│ │ │ ├── app_trigger_service.py
│ │ │ ├── schedule_service.py
│ │ │ ├── trigger_provider_service.py
│ │ │ ├── trigger_request_service.py
│ │ │ ├── trigger_service.py
│ │ │ ├── trigger_subscription_builder_service.py
│ │ │ ├── trigger_subscription_operator_service.py
│ │ │ └── webhook_service.py
│ │ ├── variable_truncator.py
│ │ ├── vector_service.py
│ │ ├── web_conversation_service.py
│ │ ├── webapp_auth_service.py
│ │ ├── website_service.py
│ │ ├── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── queue_dispatcher.py
│ │ │ ├── scheduler.py
│ │ │ └── workflow_converter.py
│ │ ├── workflow_app_service.py
│ │ ├── workflow_draft_variable_service.py
│ │ ├── workflow_event_snapshot_service.py
│ │ ├── workflow_restore.py
│ │ ├── workflow_run_service.py
│ │ ├── workflow_service.py
│ │ └── workspace_service.py
│ ├── tasks/
│ │ ├── __init__.py
│ │ ├── add_document_to_index_task.py
│ │ ├── annotation/
│ │ │ ├── add_annotation_to_index_task.py
│ │ │ ├── batch_import_annotations_task.py
│ │ │ ├── delete_annotation_index_task.py
│ │ │ ├── disable_annotation_reply_task.py
│ │ │ ├── enable_annotation_reply_task.py
│ │ │ └── update_annotation_to_index_task.py
│ │ ├── app_generate/
│ │ │ ├── __init__.py
│ │ │ └── workflow_execute_task.py
│ │ ├── async_workflow_tasks.py
│ │ ├── batch_clean_document_task.py
│ │ ├── batch_create_segment_to_index_task.py
│ │ ├── clean_dataset_task.py
│ │ ├── clean_document_task.py
│ │ ├── clean_notion_document_task.py
│ │ ├── create_segment_to_index_task.py
│ │ ├── deal_dataset_index_update_task.py
│ │ ├── deal_dataset_vector_index_task.py
│ │ ├── delete_account_task.py
│ │ ├── delete_conversation_task.py
│ │ ├── delete_segment_from_index_task.py
│ │ ├── disable_segment_from_index_task.py
│ │ ├── disable_segments_from_index_task.py
│ │ ├── document_indexing_sync_task.py
│ │ ├── document_indexing_task.py
│ │ ├── document_indexing_update_task.py
│ │ ├── duplicate_document_indexing_task.py
│ │ ├── enable_segment_to_index_task.py
│ │ ├── enable_segments_to_index_task.py
│ │ ├── enterprise_telemetry_task.py
│ │ ├── generate_summary_index_task.py
│ │ ├── human_input_timeout_tasks.py
│ │ ├── mail_account_deletion_task.py
│ │ ├── mail_change_mail_task.py
│ │ ├── mail_email_code_login.py
│ │ ├── mail_human_input_delivery_task.py
│ │ ├── mail_inner_task.py
│ │ ├── mail_invite_member_task.py
│ │ ├── mail_owner_transfer_task.py
│ │ ├── mail_register_task.py
│ │ ├── mail_reset_password_task.py
│ │ ├── ops_trace_task.py
│ │ ├── process_tenant_plugin_autoupgrade_check_task.py
│ │ ├── rag_pipeline/
│ │ │ ├── priority_rag_pipeline_run_task.py
│ │ │ └── rag_pipeline_run_task.py
│ │ ├── recover_document_indexing_task.py
│ │ ├── regenerate_summary_index_task.py
│ │ ├── remove_app_and_related_data_task.py
│ │ ├── remove_document_from_index_task.py
│ │ ├── retry_document_indexing_task.py
│ │ ├── sync_website_document_indexing_task.py
│ │ ├── trigger_processing_tasks.py
│ │ ├── trigger_subscription_refresh_tasks.py
│ │ ├── workflow_cfs_scheduler/
│ │ │ ├── cfs_scheduler.py
│ │ │ └── entities.py
│ │ ├── workflow_draft_var_tasks.py
│ │ ├── workflow_execution_tasks.py
│ │ ├── workflow_node_execution_tasks.py
│ │ └── workflow_schedule_tasks.py
│ ├── templates/
│ │ ├── change_mail_completed_template_en-US.html
│ │ ├── change_mail_completed_template_zh-CN.html
│ │ ├── change_mail_confirm_new_template_en-US.html
│ │ ├── change_mail_confirm_new_template_zh-CN.html
│ │ ├── change_mail_confirm_old_template_en-US.html
│ │ ├── change_mail_confirm_old_template_zh-CN.html
│ │ ├── clean_document_job_mail_template-US.html
│ │ ├── delete_account_code_email_template_en-US.html
│ │ ├── delete_account_success_template_en-US.html
│ │ ├── email_code_login_mail_template_en-US.html
│ │ ├── email_code_login_mail_template_zh-CN.html
│ │ ├── invite_member_mail_template_en-US.html
│ │ ├── invite_member_mail_template_zh-CN.html
│ │ ├── queue_monitor_alert_email_template_en-US.html
│ │ ├── register_email_template_en-US.html
│ │ ├── register_email_template_zh-CN.html
│ │ ├── register_email_when_account_exist_template_en-US.html
│ │ ├── register_email_when_account_exist_template_zh-CN.html
│ │ ├── reset_password_mail_template_en-US.html
│ │ ├── reset_password_mail_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_template_zh-CN.html
│ │ ├── transfer_workspace_new_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_new_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_old_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_old_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_owner_confirm_template_en-US.html
│ │ ├── transfer_workspace_owner_confirm_template_zh-CN.html
│ │ └── without-brand/
│ │ ├── change_mail_completed_template_en-US.html
│ │ ├── change_mail_completed_template_zh-CN.html
│ │ ├── change_mail_confirm_new_template_en-US.html
│ │ ├── change_mail_confirm_new_template_zh-CN.html
│ │ ├── change_mail_confirm_old_template_en-US.html
│ │ ├── change_mail_confirm_old_template_zh-CN.html
│ │ ├── email_code_login_mail_template_en-US.html
│ │ ├── email_code_login_mail_template_zh-CN.html
│ │ ├── invite_member_mail_template_en-US.html
│ │ ├── invite_member_mail_template_zh-CN.html
│ │ ├── register_email_template_en-US.html
│ │ ├── register_email_template_zh-CN.html
│ │ ├── register_email_when_account_exist_template_en-US.html
│ │ ├── register_email_when_account_exist_template_zh-CN.html
│ │ ├── reset_password_mail_template_en-US.html
│ │ ├── reset_password_mail_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_template_zh-CN.html
│ │ ├── transfer_workspace_new_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_new_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_old_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_old_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_owner_confirm_template_en-US.html
│ │ └── transfer_workspace_owner_confirm_template_zh-CN.html
│ └── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── fixtures/
│ │ └── workflow/
│ │ ├── answer_end_with_text.yml
│ │ ├── array_iteration_formatting_workflow.yml
│ │ ├── basic_chatflow.yml
│ │ ├── basic_llm_chat_workflow.yml
│ │ ├── chatflow_time_tool_static_output_workflow.yml
│ │ ├── conditional_hello_branching_workflow.yml
│ │ ├── conditional_parallel_code_execution_workflow.yml
│ │ ├── conditional_streaming_vs_template_workflow.yml
│ │ ├── dual_switch_variable_aggregator_workflow.yml
│ │ ├── end_node_without_value_type_field_workflow.yml
│ │ ├── http_request_with_json_tool_workflow.yml
│ │ ├── increment_loop_with_break_condition_workflow.yml
│ │ ├── iteration_flatten_output_disabled_workflow.yml
│ │ ├── iteration_flatten_output_enabled_workflow.yml
│ │ ├── loop_contains_answer.yml
│ │ ├── multilingual_parallel_llm_streaming_workflow.yml
│ │ ├── search_dify_from_2023_to_2025.yml
│ │ ├── simple_passthrough_workflow.yml
│ │ ├── test-answer-order.yml
│ │ ├── test_complex_branch.yml
│ │ ├── test_streaming_conversation_variables.yml
│ │ ├── test_streaming_conversation_variables_v1_overwrite.yml
│ │ └── update-conversation-variable-in-iteration.yml
│ ├── integration_tests/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ └── console/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_chat_message_permissions.py
│ │ │ │ ├── test_description_validation.py
│ │ │ │ ├── test_feedback_api_basic.py
│ │ │ │ ├── test_feedback_export_api.py
│ │ │ │ ├── test_model_config_permissions.py
│ │ │ │ └── test_workflow_draft_variable.py
│ │ │ └── workspace/
│ │ │ └── test_trigger_provider_permissions.py
│ │ ├── core/
│ │ │ ├── datasource/
│ │ │ │ └── test_datasource_manager_integration.py
│ │ │ └── workflow/
│ │ │ └── nodes/
│ │ │ └── datasource/
│ │ │ └── test_datasource_node_integration.py
│ │ ├── factories/
│ │ │ ├── __init__.py
│ │ │ └── test_storage_key_loader.py
│ │ ├── libs/
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_data.py
│ │ │ │ └── test_helpers.py
│ │ │ └── test_api_token_cache_integration.py
│ │ ├── model_runtime/
│ │ │ └── __mock/
│ │ │ ├── plugin_daemon.py
│ │ │ └── plugin_model.py
│ │ ├── plugin/
│ │ │ ├── __mock/
│ │ │ │ └── http.py
│ │ │ └── tools/
│ │ │ └── test_fetch_all_tools.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_plugin_lifecycle.py
│ │ │ ├── retention/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_messages_clean_service.py
│ │ │ │ └── test_workflow_run_archiver.py
│ │ │ └── test_workflow_draft_variable_service.py
│ │ ├── storage/
│ │ │ └── test_clickzetta_volume.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ └── test_remove_app_and_related_data_task.py
│ │ ├── tools/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ └── http.py
│ │ │ ├── __mock_server/
│ │ │ │ └── openapi_todo.py
│ │ │ ├── api_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_api_tool.py
│ │ │ └── code/
│ │ │ └── __init__.py
│ │ ├── utils/
│ │ │ ├── child_class.py
│ │ │ ├── lazy_load_class.py
│ │ │ ├── parent_class.py
│ │ │ └── test_module_import_helper.py
│ │ ├── vdb/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── baiduvectordb.py
│ │ │ │ ├── hologres.py
│ │ │ │ ├── huaweicloudvectordb.py
│ │ │ │ ├── tcvectordb.py
│ │ │ │ ├── upstashvectordb.py
│ │ │ │ └── vikingdb.py
│ │ │ ├── analyticdb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_analyticdb.py
│ │ │ ├── baidu/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_baidu.py
│ │ │ ├── chroma/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_chroma.py
│ │ │ ├── clickzetta/
│ │ │ │ ├── README.md
│ │ │ │ ├── test_clickzetta.py
│ │ │ │ └── test_docker_integration.py
│ │ │ ├── couchbase/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_couchbase.py
│ │ │ ├── elasticsearch/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_elasticsearch.py
│ │ │ ├── hologres/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_hologres.py
│ │ │ ├── huawei/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_huawei_cloud.py
│ │ │ ├── iris/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_iris.py
│ │ │ ├── lindorm/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_lindorm.py
│ │ │ ├── matrixone/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_matrixone.py
│ │ │ ├── milvus/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_milvus.py
│ │ │ ├── myscale/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_myscale.py
│ │ │ ├── oceanbase/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bench_oceanbase.py
│ │ │ │ └── test_oceanbase.py
│ │ │ ├── opengauss/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opengauss.py
│ │ │ ├── opensearch/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opensearch.py
│ │ │ ├── oracle/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_oraclevector.py
│ │ │ ├── pgvecto_rs/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pgvecto_rs.py
│ │ │ ├── pgvector/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pgvector.py
│ │ │ ├── pyvastbase/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_vastbase_vector.py
│ │ │ ├── qdrant/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_qdrant.py
│ │ │ ├── tablestore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tablestore.py
│ │ │ ├── tcvectordb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tencent.py
│ │ │ ├── test_vector_store.py
│ │ │ ├── tidb_vector/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── check_tiflash_ready.py
│ │ │ │ └── test_tidb_vector.py
│ │ │ ├── upstash/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_upstash_vector.py
│ │ │ ├── vikingdb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_vikingdb.py
│ │ │ └── weaviate/
│ │ │ ├── __init__.py
│ │ │ └── test_weaviate.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ ├── nodes/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── code_executor.py
│ │ │ │ ├── http.py
│ │ │ │ └── model.py
│ │ │ ├── code_executor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_code_executor.py
│ │ │ │ ├── test_code_javascript.py
│ │ │ │ ├── test_code_jinja2.py
│ │ │ │ └── test_code_python3.py
│ │ │ ├── knowledge_index/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_knowledge_index_node_integration.py
│ │ │ ├── knowledge_retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_knowledge_retrieval_node_integration.py
│ │ │ ├── test_code.py
│ │ │ ├── test_http.py
│ │ │ ├── test_llm.py
│ │ │ ├── test_parameter_extractor.py
│ │ │ ├── test_template_transform.py
│ │ │ └── test_tool.py
│ │ └── test_sync_workflow.py
│ ├── test_containers_integration_tests/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ ├── console/
│ │ │ │ ├── app/
│ │ │ │ │ ├── test_app_apis.py
│ │ │ │ │ ├── test_app_import_api.py
│ │ │ │ │ ├── test_chat_conversation_status_count_api.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_statistic.py
│ │ │ │ │ └── test_workflow_draft_variable.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── test_data_source_bearer_auth.py
│ │ │ │ │ ├── test_data_source_oauth.py
│ │ │ │ │ ├── test_email_register.py
│ │ │ │ │ ├── test_forgot_password.py
│ │ │ │ │ ├── test_oauth.py
│ │ │ │ │ ├── test_oauth_server.py
│ │ │ │ │ └── test_password_reset.py
│ │ │ │ ├── datasets/
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── test_rag_pipeline.py
│ │ │ │ │ │ ├── test_rag_pipeline_datasets.py
│ │ │ │ │ │ ├── test_rag_pipeline_import.py
│ │ │ │ │ │ └── test_rag_pipeline_workflow.py
│ │ │ │ │ └── test_data_source.py
│ │ │ │ ├── explore/
│ │ │ │ │ └── test_conversation.py
│ │ │ │ ├── helpers.py
│ │ │ │ ├── test_apikey.py
│ │ │ │ └── workspace/
│ │ │ │ ├── test_tool_provider.py
│ │ │ │ ├── test_trigger_providers.py
│ │ │ │ └── test_workspace_wraps.py
│ │ │ ├── mcp/
│ │ │ │ └── test_mcp.py
│ │ │ └── web/
│ │ │ ├── test_conversation.py
│ │ │ ├── test_web_forgot_password.py
│ │ │ └── test_wraps.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── layers/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pause_state_persist_layer.py
│ │ │ ├── rag/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_queue_integration.py
│ │ │ │ └── retrieval/
│ │ │ │ └── test_dataset_retrieval_integration.py
│ │ │ ├── repositories/
│ │ │ │ └── test_human_input_form_repository_impl.py
│ │ │ └── workflow/
│ │ │ └── test_human_input_resume_node_execution.py
│ │ ├── factories/
│ │ │ ├── __init__.py
│ │ │ └── test_storage_key_loader.py
│ │ ├── helpers/
│ │ │ ├── __init__.py
│ │ │ └── execution_extra_content.py
│ │ ├── libs/
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ ├── test_channel.py
│ │ │ │ ├── test_sharded_channel.py
│ │ │ │ └── test_streams_channel.py
│ │ │ ├── test_auto_renew_redis_lock_integration.py
│ │ │ └── test_rate_limiter_integration.py
│ │ ├── models/
│ │ │ ├── test_account.py
│ │ │ ├── test_app_model_config.py
│ │ │ ├── test_dataset_models.py
│ │ │ └── test_types_enum_text.py
│ │ ├── repositories/
│ │ │ ├── test_sqlalchemy_api_workflow_node_execution_repository.py
│ │ │ ├── test_sqlalchemy_api_workflow_run_repository.py
│ │ │ ├── test_sqlalchemy_execution_extra_content_repository.py
│ │ │ ├── test_sqlalchemy_workflow_trigger_log_repository.py
│ │ │ └── test_workflow_run_repository.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_key_auth_service.py
│ │ │ │ └── test_auth_integration.py
│ │ │ ├── dataset_collection_binding.py
│ │ │ ├── dataset_service_update_delete.py
│ │ │ ├── document_service_status.py
│ │ │ ├── enterprise/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_account_deletion_sync.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_plugin_parameter_service.py
│ │ │ │ └── test_plugin_service.py
│ │ │ ├── recommend_app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_database_retrieval.py
│ │ │ ├── test_account_service.py
│ │ │ ├── test_advanced_prompt_template_service.py
│ │ │ ├── test_agent_service.py
│ │ │ ├── test_annotation_service.py
│ │ │ ├── test_api_based_extension_service.py
│ │ │ ├── test_api_token_service.py
│ │ │ ├── test_app_dsl_service.py
│ │ │ ├── test_app_generate_service.py
│ │ │ ├── test_app_service.py
│ │ │ ├── test_attachment_service.py
│ │ │ ├── test_billing_service.py
│ │ │ ├── test_conversation_service.py
│ │ │ ├── test_conversation_variable_updater.py
│ │ │ ├── test_credit_pool_service.py
│ │ │ ├── test_dataset_permission_service.py
│ │ │ ├── test_dataset_service.py
│ │ │ ├── test_dataset_service_batch_update_document_status.py
│ │ │ ├── test_dataset_service_create_dataset.py
│ │ │ ├── test_dataset_service_delete_dataset.py
│ │ │ ├── test_dataset_service_get_segments.py
│ │ │ ├── test_dataset_service_retrieval.py
│ │ │ ├── test_dataset_service_update_dataset.py
│ │ │ ├── test_delete_archived_workflow_run.py
│ │ │ ├── test_document_service_display_status.py
│ │ │ ├── test_document_service_rename_document.py
│ │ │ ├── test_end_user_service.py
│ │ │ ├── test_feature_service.py
│ │ │ ├── test_feedback_service.py
│ │ │ ├── test_file_service.py
│ │ │ ├── test_file_service_zip_and_lookup.py
│ │ │ ├── test_human_input_delivery_test.py
│ │ │ ├── test_human_input_delivery_test_service.py
│ │ │ ├── test_message_export_service.py
│ │ │ ├── test_message_service.py
│ │ │ ├── test_message_service_execution_extra_content.py
│ │ │ ├── test_message_service_extra_contents.py
│ │ │ ├── test_messages_clean_service.py
│ │ │ ├── test_metadata_partial_update.py
│ │ │ ├── test_metadata_service.py
│ │ │ ├── test_model_load_balancing_service.py
│ │ │ ├── test_model_provider_service.py
│ │ │ ├── test_oauth_server_service.py
│ │ │ ├── test_restore_archived_workflow_run.py
│ │ │ ├── test_saved_message_service.py
│ │ │ ├── test_tag_service.py
│ │ │ ├── test_trigger_provider_service.py
│ │ │ ├── test_web_conversation_service.py
│ │ │ ├── test_webapp_auth_service.py
│ │ │ ├── test_webhook_service.py
│ │ │ ├── test_workflow_app_service.py
│ │ │ ├── test_workflow_draft_variable_service.py
│ │ │ ├── test_workflow_run_service.py
│ │ │ ├── test_workflow_service.py
│ │ │ ├── test_workspace_service.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_tools_manage_service.py
│ │ │ │ ├── test_mcp_tools_manage_service.py
│ │ │ │ ├── test_tools_transform_service.py
│ │ │ │ └── test_workflow_tools_manage_service.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── test_workflow_converter.py
│ │ │ ├── test_workflow_deletion.py
│ │ │ └── test_workflow_node_execution_service_repository.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── test_add_document_to_index_task.py
│ │ │ ├── test_batch_clean_document_task.py
│ │ │ ├── test_batch_create_segment_to_index_task.py
│ │ │ ├── test_clean_dataset_task.py
│ │ │ ├── test_clean_notion_document_task.py
│ │ │ ├── test_create_segment_to_index_task.py
│ │ │ ├── test_dataset_indexing_task.py
│ │ │ ├── test_deal_dataset_vector_index_task.py
│ │ │ ├── test_delete_segment_from_index_task.py
│ │ │ ├── test_disable_segment_from_index_task.py
│ │ │ ├── test_disable_segments_from_index_task.py
│ │ │ ├── test_document_indexing_sync_task.py
│ │ │ ├── test_document_indexing_task.py
│ │ │ ├── test_document_indexing_update_task.py
│ │ │ ├── test_duplicate_document_indexing_task.py
│ │ │ ├── test_enable_segments_to_index_task.py
│ │ │ ├── test_mail_account_deletion_task.py
│ │ │ ├── test_mail_change_mail_task.py
│ │ │ ├── test_mail_email_code_login_task.py
│ │ │ ├── test_mail_human_input_delivery_task.py
│ │ │ ├── test_mail_inner_task.py
│ │ │ ├── test_mail_invite_member_task.py
│ │ │ ├── test_mail_owner_transfer_task.py
│ │ │ ├── test_mail_register_task.py
│ │ │ ├── test_rag_pipeline_run_tasks.py
│ │ │ └── test_remove_app_and_related_data_task.py
│ │ ├── test_opendal_fs_default_root.py
│ │ ├── test_workflow_pause_integration.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ └── test_trigger_e2e.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ └── nodes/
│ │ ├── __init__.py
│ │ └── code_executor/
│ │ ├── __init__.py
│ │ ├── test_code_executor.py
│ │ ├── test_code_javascript.py
│ │ ├── test_code_jinja2.py
│ │ ├── test_code_python3.py
│ │ └── test_utils.py
│ ├── unit_tests/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── commands/
│ │ │ ├── test_clean_expired_messages.py
│ │ │ └── test_upgrade_db.py
│ │ ├── configs/
│ │ │ └── test_dify_config.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ ├── __init__.py
│ │ │ ├── common/
│ │ │ │ ├── test_errors.py
│ │ │ │ ├── test_fields.py
│ │ │ │ ├── test_file_response.py
│ │ │ │ ├── test_helpers.py
│ │ │ │ └── test_schema.py
│ │ │ ├── console/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_annotation_api.py
│ │ │ │ │ ├── test_annotation_security.py
│ │ │ │ │ ├── test_app_response_models.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_audio_api.py
│ │ │ │ │ ├── test_conversation_api.py
│ │ │ │ │ ├── test_conversation_read_timestamp.py
│ │ │ │ │ ├── test_description_validation.py
│ │ │ │ │ ├── test_generator_api.py
│ │ │ │ │ ├── test_message_api.py
│ │ │ │ │ ├── test_model_config_api.py
│ │ │ │ │ ├── test_statistic_api.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ ├── test_workflow_human_input_debug_api.py
│ │ │ │ │ ├── test_workflow_pause_details_api.py
│ │ │ │ │ ├── test_wraps.py
│ │ │ │ │ └── workflow_draft_variables_test.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── test_account_activation.py
│ │ │ │ │ ├── test_authentication_security.py
│ │ │ │ │ ├── test_email_verification.py
│ │ │ │ │ ├── test_login_logout.py
│ │ │ │ │ └── test_token_refresh.py
│ │ │ │ ├── billing/
│ │ │ │ │ └── test_billing.py
│ │ │ │ ├── datasets/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_datasource_auth.py
│ │ │ │ │ │ ├── test_datasource_content_preview.py
│ │ │ │ │ │ └── test_rag_pipeline_draft_variable.py
│ │ │ │ │ ├── test_datasets.py
│ │ │ │ │ ├── test_datasets_document.py
│ │ │ │ │ ├── test_datasets_document_download.py
│ │ │ │ │ ├── test_datasets_segments.py
│ │ │ │ │ ├── test_external.py
│ │ │ │ │ ├── test_external_dataset_payload.py
│ │ │ │ │ ├── test_hit_testing.py
│ │ │ │ │ ├── test_hit_testing_base.py
│ │ │ │ │ ├── test_metadata.py
│ │ │ │ │ ├── test_website.py
│ │ │ │ │ └── test_wraps.py
│ │ │ │ ├── explore/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_banner.py
│ │ │ │ │ ├── test_completion.py
│ │ │ │ │ ├── test_installed_app.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_parameter.py
│ │ │ │ │ ├── test_recommended_app.py
│ │ │ │ │ ├── test_saved_message.py
│ │ │ │ │ ├── test_trial.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ └── test_wraps.py
│ │ │ │ ├── tag/
│ │ │ │ │ └── test_tags.py
│ │ │ │ ├── test_admin.py
│ │ │ │ ├── test_document_detail_api_data_source_info.py
│ │ │ │ ├── test_extension.py
│ │ │ │ ├── test_fastopenapi_ping.py
│ │ │ │ ├── test_fastopenapi_setup.py
│ │ │ │ ├── test_fastopenapi_version.py
│ │ │ │ ├── test_feature.py
│ │ │ │ ├── test_files.py
│ │ │ │ ├── test_files_security.py
│ │ │ │ ├── test_human_input_form.py
│ │ │ │ ├── test_init_validate.py
│ │ │ │ ├── test_remote_files.py
│ │ │ │ ├── test_spec.py
│ │ │ │ ├── test_version.py
│ │ │ │ ├── test_workspace_account.py
│ │ │ │ ├── test_workspace_members.py
│ │ │ │ ├── test_wraps.py
│ │ │ │ └── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_accounts.py
│ │ │ │ ├── test_agent_providers.py
│ │ │ │ ├── test_endpoint.py
│ │ │ │ ├── test_load_balancing_config.py
│ │ │ │ ├── test_members.py
│ │ │ │ ├── test_model_providers.py
│ │ │ │ ├── test_models.py
│ │ │ │ ├── test_plugin.py
│ │ │ │ ├── test_tool_providers.py
│ │ │ │ └── test_workspace.py
│ │ │ ├── files/
│ │ │ │ ├── test_image_preview.py
│ │ │ │ ├── test_tool_files.py
│ │ │ │ └── test_upload.py
│ │ │ ├── inner_api/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_dsl.py
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_plugin.py
│ │ │ │ │ └── test_plugin_wraps.py
│ │ │ │ ├── test_auth_wraps.py
│ │ │ │ ├── test_mail.py
│ │ │ │ └── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_workspace.py
│ │ │ ├── service_api/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_annotation.py
│ │ │ │ │ ├── test_app.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_chat_request_payload.py
│ │ │ │ │ ├── test_completion.py
│ │ │ │ │ ├── test_conversation.py
│ │ │ │ │ ├── test_file.py
│ │ │ │ │ ├── test_file_preview.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ └── test_workflow_fields.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── dataset/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_rag_pipeline_workflow.py
│ │ │ │ │ ├── test_dataset.py
│ │ │ │ │ ├── test_dataset_segment.py
│ │ │ │ │ ├── test_document.py
│ │ │ │ │ ├── test_hit_testing.py
│ │ │ │ │ ├── test_metadata.py
│ │ │ │ │ ├── test_rag_pipeline_file_upload_serialization.py
│ │ │ │ │ └── test_rag_pipeline_route_registration.py
│ │ │ │ ├── end_user/
│ │ │ │ │ └── test_end_user.py
│ │ │ │ ├── test_index.py
│ │ │ │ ├── test_site.py
│ │ │ │ └── test_wraps.py
│ │ │ ├── test_compare_versions.py
│ │ │ ├── test_conversation_rename_payload.py
│ │ │ ├── trigger/
│ │ │ │ ├── test_trigger.py
│ │ │ │ └── test_webhook.py
│ │ │ └── web/
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_app.py
│ │ │ ├── test_audio.py
│ │ │ ├── test_completion.py
│ │ │ ├── test_error.py
│ │ │ ├── test_feature.py
│ │ │ ├── test_files.py
│ │ │ ├── test_human_input_form.py
│ │ │ ├── test_message_endpoints.py
│ │ │ ├── test_message_list.py
│ │ │ ├── test_passport.py
│ │ │ ├── test_pydantic_models.py
│ │ │ ├── test_remote_files.py
│ │ │ ├── test_saved_message.py
│ │ │ ├── test_site.py
│ │ │ ├── test_web_login.py
│ │ │ ├── test_web_passport.py
│ │ │ ├── test_workflow.py
│ │ │ └── test_workflow_events.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── agent/
│ │ │ │ ├── conftest.py
│ │ │ │ ├── output_parser/
│ │ │ │ │ └── test_cot_output_parser.py
│ │ │ │ ├── strategy/
│ │ │ │ │ ├── test_base.py
│ │ │ │ │ └── test_plugin.py
│ │ │ │ ├── test_base_agent_runner.py
│ │ │ │ ├── test_cot_agent_runner.py
│ │ │ │ ├── test_cot_chat_agent_runner.py
│ │ │ │ ├── test_cot_completion_agent_runner.py
│ │ │ │ ├── test_fc_agent_runner.py
│ │ │ │ └── test_plugin_entities.py
│ │ │ ├── app/
│ │ │ │ ├── app_config/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── common/
│ │ │ │ │ │ ├── test_parameters_mapping.py
│ │ │ │ │ │ └── test_sensitive_word_avoidance_manager.py
│ │ │ │ │ ├── easy_ui_based_app/
│ │ │ │ │ │ ├── test_agent_manager.py
│ │ │ │ │ │ ├── test_dataset_manager.py
│ │ │ │ │ │ ├── test_model_config_converter.py
│ │ │ │ │ │ ├── test_model_config_manager.py
│ │ │ │ │ │ ├── test_prompt_template_manager.py
│ │ │ │ │ │ └── test_variables_manager.py
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── file_upload/
│ │ │ │ │ │ │ └── test_manager.py
│ │ │ │ │ │ └── test_additional_feature_managers.py
│ │ │ │ │ ├── test_base_app_config_manager.py
│ │ │ │ │ ├── test_entities.py
│ │ │ │ │ └── workflow_ui_based_app/
│ │ │ │ │ └── test_workflow_ui_based_app_manager.py
│ │ │ │ ├── apps/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── advanced_chat/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ │ ├── test_app_generator.py
│ │ │ │ │ │ ├── test_app_runner_conversation_variables.py
│ │ │ │ │ │ ├── test_app_runner_input_moderation.py
│ │ │ │ │ │ ├── test_generate_response_converter.py
│ │ │ │ │ │ ├── test_generate_task_pipeline.py
│ │ │ │ │ │ └── test_generate_task_pipeline_core.py
│ │ │ │ │ ├── agent_chat/
│ │ │ │ │ │ ├── test_agent_chat_app_config_manager.py
│ │ │ │ │ │ ├── test_agent_chat_app_generator.py
│ │ │ │ │ │ ├── test_agent_chat_app_runner.py
│ │ │ │ │ │ └── test_agent_chat_generate_response_converter.py
│ │ │ │ │ ├── chat/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ │ ├── test_app_generator_and_runner.py
│ │ │ │ │ │ ├── test_base_app_runner_multimodal.py
│ │ │ │ │ │ └── test_generate_response_converter.py
│ │ │ │ │ ├── common/
│ │ │ │ │ │ ├── test_graph_runtime_state_support.py
│ │ │ │ │ │ ├── test_workflow_response_converter.py
│ │ │ │ │ │ ├── test_workflow_response_converter_human_input.py
│ │ │ │ │ │ ├── test_workflow_response_converter_resumption.py
│ │ │ │ │ │ └── test_workflow_response_converter_truncation.py
│ │ │ │ │ ├── completion/
│ │ │ │ │ │ ├── test_app_runner.py
│ │ │ │ │ │ ├── test_completion_app_config_manager.py
│ │ │ │ │ │ ├── test_completion_completion_app_generator.py
│ │ │ │ │ │ └── test_completion_generate_response_converter.py
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ ├── test_pipeline_config_manager.py
│ │ │ │ │ │ ├── test_pipeline_generate_response_converter.py
│ │ │ │ │ │ ├── test_pipeline_generator.py
│ │ │ │ │ │ ├── test_pipeline_queue_manager.py
│ │ │ │ │ │ └── test_pipeline_runner.py
│ │ │ │ │ ├── test_advanced_chat_app_generator.py
│ │ │ │ │ ├── test_base_app_generator.py
│ │ │ │ │ ├── test_base_app_queue_manager.py
│ │ │ │ │ ├── test_base_app_runner.py
│ │ │ │ │ ├── test_exc.py
│ │ │ │ │ ├── test_message_based_app_generator.py
│ │ │ │ │ ├── test_message_based_app_queue_manager.py
│ │ │ │ │ ├── test_message_generator.py
│ │ │ │ │ ├── test_pause_resume.py
│ │ │ │ │ ├── test_streaming_utils.py
│ │ │ │ │ ├── test_workflow_app_generator.py
│ │ │ │ │ ├── test_workflow_app_runner_core.py
│ │ │ │ │ ├── test_workflow_app_runner_notifications.py
│ │ │ │ │ ├── test_workflow_app_runner_single_node.py
│ │ │ │ │ ├── test_workflow_pause_events.py
│ │ │ │ │ └── workflow/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ ├── test_app_generator_extra.py
│ │ │ │ │ ├── test_app_queue_manager.py
│ │ │ │ │ ├── test_errors.py
│ │ │ │ │ ├── test_generate_response_converter.py
│ │ │ │ │ ├── test_generate_task_pipeline.py
│ │ │ │ │ └── test_generate_task_pipeline_core.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── test_app_invoke_entities.py
│ │ │ │ │ ├── test_queue_entities.py
│ │ │ │ │ ├── test_rag_pipeline_invoke_entities.py
│ │ │ │ │ └── test_task_entities.py
│ │ │ │ ├── features/
│ │ │ │ │ ├── rate_limiting/
│ │ │ │ │ │ ├── conftest.py
│ │ │ │ │ │ └── test_rate_limit.py
│ │ │ │ │ ├── test_annotation_reply.py
│ │ │ │ │ └── test_hosting_moderation.py
│ │ │ │ ├── layers/
│ │ │ │ │ ├── test_conversation_variable_persist_layer.py
│ │ │ │ │ ├── test_pause_state_persist_layer.py
│ │ │ │ │ ├── test_suspend_layer.py
│ │ │ │ │ ├── test_timeslice_layer.py
│ │ │ │ │ └── test_trigger_post_layer.py
│ │ │ │ ├── task_pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_based_generate_task_pipeline.py
│ │ │ │ │ ├── test_easy_ui_based_generate_task_pipeline.py
│ │ │ │ │ ├── test_easy_ui_based_generate_task_pipeline_core.py
│ │ │ │ │ ├── test_easy_ui_message_end_files.py
│ │ │ │ │ ├── test_exc.py
│ │ │ │ │ └── test_message_cycle_manager_optimization.py
│ │ │ │ ├── test_easy_ui_model_config_manager.py
│ │ │ │ └── workflow/
│ │ │ │ ├── layers/
│ │ │ │ │ └── test_persistence.py
│ │ │ │ ├── test_file_runtime.py
│ │ │ │ ├── test_node_factory.py
│ │ │ │ ├── test_observability_layer_extra.py
│ │ │ │ └── test_persistence_layer.py
│ │ │ ├── base/
│ │ │ │ └── test_app_generator_tts_publisher.py
│ │ │ ├── callback_handler/
│ │ │ │ ├── test_agent_tool_callback_handler.py
│ │ │ │ ├── test_index_tool_callback_handler.py
│ │ │ │ └── test_workflow_tool_callback_handler.py
│ │ │ ├── datasource/
│ │ │ │ ├── __base/
│ │ │ │ │ ├── test_datasource_plugin.py
│ │ │ │ │ ├── test_datasource_provider.py
│ │ │ │ │ └── test_datasource_runtime.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── test_api_entities.py
│ │ │ │ │ ├── test_common_entities.py
│ │ │ │ │ └── test_datasource_entities.py
│ │ │ │ ├── local_file/
│ │ │ │ │ ├── test_local_file_plugin.py
│ │ │ │ │ └── test_local_file_provider.py
│ │ │ │ ├── online_document/
│ │ │ │ │ ├── test_online_document_plugin.py
│ │ │ │ │ └── test_online_document_provider.py
│ │ │ │ ├── online_drive/
│ │ │ │ │ ├── test_online_drive_plugin.py
│ │ │ │ │ └── test_online_drive_provider.py
│ │ │ │ ├── test_datasource_file_manager.py
│ │ │ │ ├── test_datasource_manager.py
│ │ │ │ ├── test_errors.py
│ │ │ │ ├── test_file_upload.py
│ │ │ │ ├── test_notion_provider.py
│ │ │ │ ├── test_website_crawl.py
│ │ │ │ ├── utils/
│ │ │ │ │ └── test_message_transformer.py
│ │ │ │ └── website_crawl/
│ │ │ │ ├── test_website_crawl_plugin.py
│ │ │ │ └── test_website_crawl_provider.py
│ │ │ ├── entities/
│ │ │ │ ├── test_entities_agent_entities.py
│ │ │ │ ├── test_entities_document_task.py
│ │ │ │ ├── test_entities_embedding_type.py
│ │ │ │ ├── test_entities_execution_extra_content.py
│ │ │ │ ├── test_entities_knowledge_entities.py
│ │ │ │ ├── test_entities_mcp_provider.py
│ │ │ │ ├── test_entities_model_entities.py
│ │ │ │ ├── test_entities_parameter_entities.py
│ │ │ │ ├── test_entities_provider_configuration.py
│ │ │ │ └── test_entities_provider_entities.py
│ │ │ ├── extension/
│ │ │ │ ├── test_api_based_extension_requestor.py
│ │ │ │ ├── test_extensible.py
│ │ │ │ └── test_extension.py
│ │ │ ├── external_data_tool/
│ │ │ │ ├── api/
│ │ │ │ │ └── test_api.py
│ │ │ │ ├── test_base.py
│ │ │ │ ├── test_external_data_fetch.py
│ │ │ │ └── test_factory.py
│ │ │ ├── file/
│ │ │ │ └── test_models.py
│ │ │ ├── helper/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── code_executor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── javascript/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_javascript_transformer.py
│ │ │ │ │ └── python3/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_python3_transformer.py
│ │ │ │ ├── test_csv_sanitizer.py
│ │ │ │ ├── test_encrypter.py
│ │ │ │ ├── test_ssrf_proxy.py
│ │ │ │ └── test_trace_id_helper.py
│ │ │ ├── llm_generator/
│ │ │ │ ├── output_parser/
│ │ │ │ │ ├── test_rule_config_generator.py
│ │ │ │ │ └── test_structured_output.py
│ │ │ │ └── test_llm_generator.py
│ │ │ ├── logging/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_context.py
│ │ │ │ ├── test_filters.py
│ │ │ │ ├── test_structured_formatter.py
│ │ │ │ └── test_trace_helpers.py
│ │ │ ├── mcp/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_auth_flow.py
│ │ │ │ ├── client/
│ │ │ │ │ ├── test_session.py
│ │ │ │ │ ├── test_sse.py
│ │ │ │ │ └── test_streamable_http.py
│ │ │ │ ├── server/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_streamable_http.py
│ │ │ │ ├── session/
│ │ │ │ │ ├── test_base_session.py
│ │ │ │ │ └── test_client_session.py
│ │ │ │ ├── test_auth_client_inheritance.py
│ │ │ │ ├── test_entities.py
│ │ │ │ ├── test_error.py
│ │ │ │ ├── test_mcp_client.py
│ │ │ │ ├── test_types.py
│ │ │ │ └── test_utils.py
│ │ │ ├── memory/
│ │ │ │ └── test_token_buffer_memory.py
│ │ │ ├── model_runtime/
│ │ │ │ └── test_model_provider_factory.py
│ │ │ ├── moderation/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── api/
│ │ │ │ │ └── test_api.py
│ │ │ │ ├── test_content_moderation.py
│ │ │ │ ├── test_input_moderation.py
│ │ │ │ ├── test_output_moderation.py
│ │ │ │ └── test_sensitive_word_filter.py
│ │ │ ├── ops/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_trace/
│ │ │ │ │ ├── data_exporter/
│ │ │ │ │ │ └── test_traceclient.py
│ │ │ │ │ ├── entities/
│ │ │ │ │ │ ├── test_aliyun_trace_entity.py
│ │ │ │ │ │ └── test_semconv.py
│ │ │ │ │ ├── test_aliyun_trace.py
│ │ │ │ │ └── test_aliyun_trace_utils.py
│ │ │ │ ├── arize_phoenix_trace/
│ │ │ │ │ └── test_arize_phoenix_trace.py
│ │ │ │ ├── langfuse_trace/
│ │ │ │ │ └── test_langfuse_trace.py
│ │ │ │ ├── langsmith_trace/
│ │ │ │ │ └── test_langsmith_trace.py
│ │ │ │ ├── mlflow_trace/
│ │ │ │ │ └── test_mlflow_trace.py
│ │ │ │ ├── opik_trace/
│ │ │ │ │ └── test_opik_trace.py
│ │ │ │ ├── tencent_trace/
│ │ │ │ │ ├── test_client.py
│ │ │ │ │ ├── test_span_builder.py
│ │ │ │ │ ├── test_tencent_trace.py
│ │ │ │ │ └── test_tencent_trace_utils.py
│ │ │ │ ├── test_arize_phoenix_trace.py
│ │ │ │ ├── test_base_trace_instance.py
│ │ │ │ ├── test_config_entity.py
│ │ │ │ ├── test_lookup_helpers.py
│ │ │ │ ├── test_opik_trace.py
│ │ │ │ ├── test_ops_trace_manager.py
│ │ │ │ ├── test_trace_queue_manager.py
│ │ │ │ ├── test_utils.py
│ │ │ │ └── weave_trace/
│ │ │ │ └── test_weave_trace.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── impl/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_agent_client.py
│ │ │ │ │ ├── test_asset_manager.py
│ │ │ │ │ ├── test_base_client_impl.py
│ │ │ │ │ ├── test_datasource_manager.py
│ │ │ │ │ ├── test_debugging_client.py
│ │ │ │ │ ├── test_endpoint_client_impl.py
│ │ │ │ │ ├── test_exc_impl.py
│ │ │ │ │ ├── test_model_client.py
│ │ │ │ │ ├── test_model_runtime_factory.py
│ │ │ │ │ ├── test_oauth_handler.py
│ │ │ │ │ ├── test_tool_manager.py
│ │ │ │ │ └── test_trigger_client.py
│ │ │ │ ├── test_backwards_invocation_app.py
│ │ │ │ ├── test_backwards_invocation_model.py
│ │ │ │ ├── test_endpoint_client.py
│ │ │ │ ├── test_model_runtime_adapter.py
│ │ │ │ ├── test_plugin_entities.py
│ │ │ │ ├── test_plugin_manager.py
│ │ │ │ ├── test_plugin_runtime.py
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_chunk_merger.py
│ │ │ │ └── test_http_parser.py
│ │ │ ├── prompt/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_advanced_prompt_transform.py
│ │ │ │ ├── test_agent_history_prompt_transform.py
│ │ │ │ ├── test_extract_thread_messages.py
│ │ │ │ ├── test_prompt_message.py
│ │ │ │ ├── test_prompt_transform.py
│ │ │ │ └── test_simple_prompt_transform.py
│ │ │ ├── rag/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cleaner/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_clean_processor.py
│ │ │ │ ├── data_post_processor/
│ │ │ │ │ └── test_data_post_processor.py
│ │ │ │ ├── datasource/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── keyword/
│ │ │ │ │ │ ├── jieba/
│ │ │ │ │ │ │ ├── test_jieba.py
│ │ │ │ │ │ │ ├── test_jieba_keyword_table_handler.py
│ │ │ │ │ │ │ └── test_stopwords.py
│ │ │ │ │ │ ├── test_keyword_base.py
│ │ │ │ │ │ └── test_keyword_factory.py
│ │ │ │ │ ├── test_datasource_retrieval.py
│ │ │ │ │ └── vdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── alibabacloud_mysql/
│ │ │ │ │ │ ├── test_alibabacloud_mysql_factory.py
│ │ │ │ │ │ └── test_alibabacloud_mysql_vector.py
│ │ │ │ │ ├── analyticdb/
│ │ │ │ │ │ ├── test_analyticdb_vector.py
│ │ │ │ │ │ ├── test_analyticdb_vector_openapi.py
│ │ │ │ │ │ └── test_analyticdb_vector_sql.py
│ │ │ │ │ ├── baidu/
│ │ │ │ │ │ └── test_baidu_vector.py
│ │ │ │ │ ├── chroma/
│ │ │ │ │ │ └── test_chroma_vector.py
│ │ │ │ │ ├── clickzetta/
│ │ │ │ │ │ └── test_clickzetta_vector.py
│ │ │ │ │ ├── couchbase/
│ │ │ │ │ │ └── test_couchbase_vector.py
│ │ │ │ │ ├── elasticsearch/
│ │ │ │ │ │ ├── test_elasticsearch_ja_vector.py
│ │ │ │ │ │ └── test_elasticsearch_vector.py
│ │ │ │ │ ├── hologres/
│ │ │ │ │ │ └── test_hologres_vector.py
│ │ │ │ │ ├── huawei/
│ │ │ │ │ │ └── test_huawei_cloud_vector.py
│ │ │ │ │ ├── iris/
│ │ │ │ │ │ └── test_iris_vector.py
│ │ │ │ │ ├── lindorm/
│ │ │ │ │ │ └── test_lindorm_vector.py
│ │ │ │ │ ├── matrixone/
│ │ │ │ │ │ └── test_matrixone_vector.py
│ │ │ │ │ ├── milvus/
│ │ │ │ │ │ └── test_milvus.py
│ │ │ │ │ ├── myscale/
│ │ │ │ │ │ └── test_myscale_vector.py
│ │ │ │ │ ├── oceanbase/
│ │ │ │ │ │ └── test_oceanbase_vector.py
│ │ │ │ │ ├── opengauss/
│ │ │ │ │ │ └── test_opengauss.py
│ │ │ │ │ ├── opensearch/
│ │ │ │ │ │ └── test_opensearch_vector.py
│ │ │ │ │ ├── oracle/
│ │ │ │ │ │ └── test_oraclevector.py
│ │ │ │ │ ├── pgvecto_rs/
│ │ │ │ │ │ └── test_pgvecto_rs.py
│ │ │ │ │ ├── pgvector/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_pgvector.py
│ │ │ │ │ ├── pyvastbase/
│ │ │ │ │ │ └── test_vastbase_vector.py
│ │ │ │ │ ├── qdrant/
│ │ │ │ │ │ └── test_qdrant_vector.py
│ │ │ │ │ ├── relyt/
│ │ │ │ │ │ └── test_relyt_vector.py
│ │ │ │ │ ├── tablestore/
│ │ │ │ │ │ └── test_tablestore_vector.py
│ │ │ │ │ ├── tencent/
│ │ │ │ │ │ └── test_tencent_vector.py
│ │ │ │ │ ├── test_field.py
│ │ │ │ │ ├── test_vector_base.py
│ │ │ │ │ ├── test_vector_factory.py
│ │ │ │ │ ├── tidb_on_qdrant/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_tidb_on_qdrant_vector.py
│ │ │ │ │ ├── tidb_vector/
│ │ │ │ │ │ └── test_tidb_vector.py
│ │ │ │ │ ├── upstash/
│ │ │ │ │ │ └── test_upstash_vector.py
│ │ │ │ │ ├── vikingdb/
│ │ │ │ │ │ └── test_vikingdb_vector.py
│ │ │ │ │ └── weaviate/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_weavaite.py
│ │ │ │ │ └── test_weaviate_vector.py
│ │ │ │ ├── docstore/
│ │ │ │ │ └── test_dataset_docstore.py
│ │ │ │ ├── embedding/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_cached_embedding.py
│ │ │ │ │ ├── test_embedding_base.py
│ │ │ │ │ └── test_embedding_service.py
│ │ │ │ ├── extractor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── blob/
│ │ │ │ │ │ └── test_blob.py
│ │ │ │ │ ├── firecrawl/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_firecrawl.py
│ │ │ │ │ ├── test_csv_extractor.py
│ │ │ │ │ ├── test_excel_extractor.py
│ │ │ │ │ ├── test_extract_processor.py
│ │ │ │ │ ├── test_extractor_base.py
│ │ │ │ │ ├── test_helpers.py
│ │ │ │ │ ├── test_html_extractor.py
│ │ │ │ │ ├── test_jina_reader_extractor.py
│ │ │ │ │ ├── test_markdown_extractor.py
│ │ │ │ │ ├── test_notion_extractor.py
│ │ │ │ │ ├── test_pdf_extractor.py
│ │ │ │ │ ├── test_text_extractor.py
│ │ │ │ │ ├── test_word_extractor.py
│ │ │ │ │ ├── unstructured/
│ │ │ │ │ │ └── test_unstructured_extractors.py
│ │ │ │ │ └── watercrawl/
│ │ │ │ │ └── test_watercrawl.py
│ │ │ │ ├── indexing/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── processor/
│ │ │ │ │ │ ├── conftest.py
│ │ │ │ │ │ ├── test_paragraph_index_processor.py
│ │ │ │ │ │ ├── test_parent_child_index_processor.py
│ │ │ │ │ │ └── test_qa_index_processor.py
│ │ │ │ │ ├── test_index_processor.py
│ │ │ │ │ ├── test_index_processor_base.py
│ │ │ │ │ ├── test_index_processor_factory.py
│ │ │ │ │ └── test_indexing_runner.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ └── test_queue.py
│ │ │ │ ├── rerank/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_reranker.py
│ │ │ │ ├── retrieval/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_dataset_retrieval.py
│ │ │ │ │ ├── test_dataset_retrieval_methods.py
│ │ │ │ │ ├── test_multi_dataset_function_call_router.py
│ │ │ │ │ ├── test_multi_dataset_react_route.py
│ │ │ │ │ └── test_structured_chat_output_parser.py
│ │ │ │ └── splitter/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_text_splitter.py
│ │ │ ├── repositories/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_celery_workflow_execution_repository.py
│ │ │ │ ├── test_celery_workflow_node_execution_repository.py
│ │ │ │ ├── test_factory.py
│ │ │ │ ├── test_human_input_form_repository_impl.py
│ │ │ │ ├── test_human_input_repository.py
│ │ │ │ ├── test_sqlalchemy_workflow_execution_repository.py
│ │ │ │ ├── test_sqlalchemy_workflow_node_execution_repository.py
│ │ │ │ ├── test_workflow_node_execution_conflict_handling.py
│ │ │ │ └── test_workflow_node_execution_truncation.py
│ │ │ ├── schemas/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_registry.py
│ │ │ │ ├── test_resolver.py
│ │ │ │ └── test_schema_manager.py
│ │ │ ├── telemetry/
│ │ │ │ ├── test_facade.py
│ │ │ │ └── test_gateway_integration.py
│ │ │ ├── test_file.py
│ │ │ ├── test_model_manager.py
│ │ │ ├── test_provider_configuration.py
│ │ │ ├── test_provider_manager.py
│ │ │ ├── test_trigger_debug_event_selectors.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_api_entities.py
│ │ │ │ ├── test_base_tool.py
│ │ │ │ ├── test_builtin_tool_base.py
│ │ │ │ ├── test_builtin_tool_provider.py
│ │ │ │ ├── test_builtin_tools_extra.py
│ │ │ │ ├── test_custom_tool.py
│ │ │ │ ├── test_custom_tool_provider.py
│ │ │ │ ├── test_dataset_retriever_tool.py
│ │ │ │ ├── test_mcp_tool.py
│ │ │ │ ├── test_mcp_tool_provider.py
│ │ │ │ ├── test_plugin_tool.py
│ │ │ │ ├── test_plugin_tool_provider.py
│ │ │ │ ├── test_signature.py
│ │ │ │ ├── test_tool_engine.py
│ │ │ │ ├── test_tool_entities.py
│ │ │ │ ├── test_tool_file_manager.py
│ │ │ │ ├── test_tool_label_manager.py
│ │ │ │ ├── test_tool_manager.py
│ │ │ │ ├── test_tool_parameter_type.py
│ │ │ │ ├── test_tool_provider_controller.py
│ │ │ │ ├── utils/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_configuration.py
│ │ │ │ │ ├── test_encryption.py
│ │ │ │ │ ├── test_message_transformer.py
│ │ │ │ │ ├── test_misc_utils_extra.py
│ │ │ │ │ ├── test_model_invocation_utils.py
│ │ │ │ │ ├── test_parser.py
│ │ │ │ │ ├── test_system_oauth_encryption.py
│ │ │ │ │ ├── test_tool_engine_serialization.py
│ │ │ │ │ ├── test_web_reader_tool.py
│ │ │ │ │ └── test_workflow_configuration_sync.py
│ │ │ │ └── workflow_as_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_provider.py
│ │ │ │ └── test_tool.py
│ │ │ ├── trigger/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── debug/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_debug_event_bus.py
│ │ │ │ │ └── test_debug_event_selectors.py
│ │ │ │ ├── test_provider.py
│ │ │ │ ├── test_trigger_manager.py
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_utils_encryption.py
│ │ │ │ ├── test_utils_endpoint.py
│ │ │ │ └── test_utils_locks.py
│ │ │ ├── variables/
│ │ │ │ ├── test_segment.py
│ │ │ │ ├── test_segment_type.py
│ │ │ │ ├── test_segment_type_validation.py
│ │ │ │ └── test_variables.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── context/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_execution_context.py
│ │ │ │ └── test_flask_app_context.py
│ │ │ ├── entities/
│ │ │ │ └── test_private_workflow_pause.py
│ │ │ ├── graph_engine/
│ │ │ │ ├── README.md
│ │ │ │ ├── __init__.py
│ │ │ │ ├── layers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── conftest.py
│ │ │ │ │ ├── test_llm_quota.py
│ │ │ │ │ └── test_observability.py
│ │ │ │ ├── test_mock_config.py
│ │ │ │ ├── test_mock_factory.py
│ │ │ │ ├── test_mock_nodes.py
│ │ │ │ ├── test_parallel_human_input_join_resume.py
│ │ │ │ ├── test_table_runner.py
│ │ │ │ └── test_tool_in_chatflow.py
│ │ │ ├── nodes/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_message_transformer.py
│ │ │ │ │ └── test_runtime_support.py
│ │ │ │ ├── answer/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_answer.py
│ │ │ │ ├── base/
│ │ │ │ │ ├── test_base_node.py
│ │ │ │ │ └── test_get_node_type_classes_mapping.py
│ │ │ │ ├── code/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── code_node_spec.py
│ │ │ │ ├── datasource/
│ │ │ │ │ └── test_datasource_node.py
│ │ │ │ ├── http_request/
│ │ │ │ │ ├── test_http_request_executor.py
│ │ │ │ │ └── test_http_request_node.py
│ │ │ │ ├── human_input/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_email_delivery_config.py
│ │ │ │ │ ├── test_entities.py
│ │ │ │ │ └── test_human_input_form_filled_event.py
│ │ │ │ ├── iteration/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_iteration_child_engine_errors.py
│ │ │ │ ├── knowledge_index/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_knowledge_index_node.py
│ │ │ │ ├── knowledge_retrieval/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_knowledge_retrieval_node.py
│ │ │ │ ├── list_operator/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── node_spec.py
│ │ │ │ ├── llm/
│ │ │ │ │ ├── test_llm_utils.py
│ │ │ │ │ └── test_node.py
│ │ │ │ ├── parameter_extractor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_parameter_extractor_node.py
│ │ │ │ ├── template_transform/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── template_transform_node_spec.py
│ │ │ │ │ └── test_template_transform_node.py
│ │ │ │ ├── test_base_node.py
│ │ │ │ ├── test_document_extractor_node.py
│ │ │ │ ├── test_if_else.py
│ │ │ │ ├── test_list_operator.py
│ │ │ │ ├── test_start_node_json_object.py
│ │ │ │ ├── tool/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_tool_node.py
│ │ │ │ │ └── test_tool_node_runtime.py
│ │ │ │ ├── trigger_plugin/
│ │ │ │ │ └── test_trigger_event_node.py
│ │ │ │ └── webhook/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_entities.py
│ │ │ │ ├── test_exceptions.py
│ │ │ │ ├── test_webhook_file_conversion.py
│ │ │ │ └── test_webhook_node.py
│ │ │ ├── test_human_input_compat.py
│ │ │ ├── test_human_input_forms.py
│ │ │ ├── test_node_factory.py
│ │ │ ├── test_node_mapping_bootstrap.py
│ │ │ ├── test_node_runtime.py
│ │ │ ├── test_system_variable.py
│ │ │ ├── test_variable_pool.py
│ │ │ ├── test_variable_pool_conver.py
│ │ │ ├── test_workflow_entry.py
│ │ │ ├── test_workflow_entry_helpers.py
│ │ │ └── test_workflow_entry_redis_channel.py
│ │ ├── enterprise/
│ │ │ └── telemetry/
│ │ │ ├── __init__.py
│ │ │ ├── test_contracts.py
│ │ │ ├── test_draft_trace.py
│ │ │ ├── test_enterprise_trace.py
│ │ │ ├── test_event_handlers.py
│ │ │ ├── test_exporter.py
│ │ │ ├── test_gateway.py
│ │ │ ├── test_id_generator.py
│ │ │ ├── test_metric_handler.py
│ │ │ └── test_telemetry_log.py
│ │ ├── events/
│ │ │ └── test_app_event_signals.py
│ │ ├── extensions/
│ │ │ ├── logstore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_sql_escape.py
│ │ │ ├── otel/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── decorators/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── handlers/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_generate_handler.py
│ │ │ │ │ │ └── test_workflow_app_runner_handler.py
│ │ │ │ │ ├── test_base.py
│ │ │ │ │ └── test_handler.py
│ │ │ │ └── test_celery_sqlcommenter.py
│ │ │ ├── storage/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_supabase_storage.py
│ │ │ ├── test_celery_ssl.py
│ │ │ ├── test_ext_request_logging.py
│ │ │ ├── test_pubsub_channel.py
│ │ │ └── test_redis.py
│ │ ├── factories/
│ │ │ ├── test_build_from_mapping.py
│ │ │ ├── test_file_factory.py
│ │ │ └── test_variable_factory.py
│ │ ├── fields/
│ │ │ └── test_file_fields.py
│ │ ├── libs/
│ │ │ ├── _human_input/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── support.py
│ │ │ │ ├── test_form_service.py
│ │ │ │ └── test_models.py
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ ├── test_channel_unit_tests.py
│ │ │ │ └── test_streams_channel_unit_tests.py
│ │ │ ├── test_api_token_cache.py
│ │ │ ├── test_archive_storage.py
│ │ │ ├── test_cron_compatibility.py
│ │ │ ├── test_custom_inputs.py
│ │ │ ├── test_datetime_utils.py
│ │ │ ├── test_email.py
│ │ │ ├── test_email_i18n.py
│ │ │ ├── test_encryption.py
│ │ │ ├── test_external_api.py
│ │ │ ├── test_file_utils.py
│ │ │ ├── test_flask_utils.py
│ │ │ ├── test_helper.py
│ │ │ ├── test_json_in_md_parser.py
│ │ │ ├── test_jwt_imports.py
│ │ │ ├── test_login.py
│ │ │ ├── test_oauth_base.py
│ │ │ ├── test_oauth_clients.py
│ │ │ ├── test_orjson.py
│ │ │ ├── test_pandas.py
│ │ │ ├── test_passport.py
│ │ │ ├── test_password.py
│ │ │ ├── test_pyrefly_diagnostics.py
│ │ │ ├── test_rate_limiter.py
│ │ │ ├── test_rsa.py
│ │ │ ├── test_schedule_utils_enhanced.py
│ │ │ ├── test_sendgrid_client.py
│ │ │ ├── test_smtp_client.py
│ │ │ ├── test_time_parser.py
│ │ │ ├── test_token.py
│ │ │ ├── test_uuid_utils.py
│ │ │ ├── test_workspace_permission.py
│ │ │ └── test_yarl.py
│ │ ├── models/
│ │ │ ├── __init__.py
│ │ │ ├── test_account.py
│ │ │ ├── test_account_models.py
│ │ │ ├── test_app_models.py
│ │ │ ├── test_base.py
│ │ │ ├── test_conversation_variable.py
│ │ │ ├── test_dataset_models.py
│ │ │ ├── test_enums_creator_user_role.py
│ │ │ ├── test_model.py
│ │ │ ├── test_plugin_entities.py
│ │ │ ├── test_provider_models.py
│ │ │ ├── test_tool_models.py
│ │ │ ├── test_workflow.py
│ │ │ ├── test_workflow_models.py
│ │ │ ├── test_workflow_node_execution_offload.py
│ │ │ └── test_workflow_trigger_log.py
│ │ ├── oss/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_oss.py
│ │ │ │ ├── base.py
│ │ │ │ ├── local.py
│ │ │ │ ├── tencent_cos.py
│ │ │ │ └── volcengine_tos.py
│ │ │ ├── aliyun_oss/
│ │ │ │ └── aliyun_oss/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_aliyun_oss.py
│ │ │ ├── opendal/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opendal.py
│ │ │ ├── tencent_cos/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tencent_cos.py
│ │ │ └── volcengine_tos/
│ │ │ ├── __init__.py
│ │ │ └── test_volcengine_tos.py
│ │ ├── repositories/
│ │ │ ├── __init__.py
│ │ │ └── workflow_node_execution/
│ │ │ ├── __init__.py
│ │ │ ├── test_sqlalchemy_repository.py
│ │ │ └── test_sqlalchemy_workflow_node_execution_repository.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_key_auth_base.py
│ │ │ │ ├── test_api_key_auth_factory.py
│ │ │ │ ├── test_auth_type.py
│ │ │ │ ├── test_firecrawl_auth.py
│ │ │ │ ├── test_jina_auth.py
│ │ │ │ ├── test_jina_auth_standalone_module.py
│ │ │ │ └── test_watercrawl_auth.py
│ │ │ ├── controller_api.py
│ │ │ ├── dataset_metadata.py
│ │ │ ├── dataset_permission_service.py
│ │ │ ├── dataset_service_test_helpers.py
│ │ │ ├── dataset_service_update_delete.py
│ │ │ ├── document_indexing_task_proxy.py
│ │ │ ├── document_service_status.py
│ │ │ ├── document_service_validation.py
│ │ │ ├── enterprise/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_enterprise_service.py
│ │ │ │ ├── test_plugin_manager_service.py
│ │ │ │ └── test_traceparent_propagation.py
│ │ │ ├── external_dataset_service.py
│ │ │ ├── hit_service.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_dependencies_analysis.py
│ │ │ │ ├── test_endpoint_service.py
│ │ │ │ ├── test_oauth_service.py
│ │ │ │ ├── test_plugin_auto_upgrade_service.py
│ │ │ │ └── test_plugin_permission_service.py
│ │ │ ├── recommend_app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_buildin_retrieval.py
│ │ │ │ ├── test_recommend_app_factory.py
│ │ │ │ ├── test_recommend_app_type.py
│ │ │ │ └── test_remote_retrieval.py
│ │ │ ├── retention/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_messages_clean_policy.py
│ │ │ │ └── workflow_run/
│ │ │ │ ├── test_clear_free_plan_expired_workflow_run_logs.py
│ │ │ │ └── test_restore_archived_workflow_run.py
│ │ │ ├── segment_service.py
│ │ │ ├── services_test_help.py
│ │ │ ├── test_account_service.py
│ │ │ ├── test_annotation_service.py
│ │ │ ├── test_app_dsl_service.py
│ │ │ ├── test_app_dsl_service_import_yaml_url.py
│ │ │ ├── test_app_generate_service.py
│ │ │ ├── test_app_generate_service_streaming_integration.py
│ │ │ ├── test_app_model_config_service.py
│ │ │ ├── test_app_task_service.py
│ │ │ ├── test_archive_workflow_run_logs.py
│ │ │ ├── test_async_workflow_service.py
│ │ │ ├── test_audio_service.py
│ │ │ ├── test_batch_indexing_base.py
│ │ │ ├── test_billing_service.py
│ │ │ ├── test_clear_free_plan_expired_workflow_run_logs.py
│ │ │ ├── test_clear_free_plan_tenant_expired_logs.py
│ │ │ ├── test_code_based_extension_service.py
│ │ │ ├── test_conversation_service.py
│ │ │ ├── test_dataset_service_dataset.py
│ │ │ ├── test_dataset_service_document.py
│ │ │ ├── test_dataset_service_lock_not_owned.py
│ │ │ ├── test_dataset_service_segment.py
│ │ │ ├── test_datasource_provider_service.py
│ │ │ ├── test_document_indexing_task_proxy.py
│ │ │ ├── test_duplicate_document_indexing_task_proxy.py
│ │ │ ├── test_export_app_messages.py
│ │ │ ├── test_external_dataset_service.py
│ │ │ ├── test_feature_service_human_input_email_delivery.py
│ │ │ ├── test_file_service.py
│ │ │ ├── test_hit_testing_service.py
│ │ │ ├── test_human_input_service.py
│ │ │ ├── test_knowledge_service.py
│ │ │ ├── test_message_service.py
│ │ │ ├── test_messages_clean_service.py
│ │ │ ├── test_metadata_bug_complete.py
│ │ │ ├── test_metadata_nullable_bug.py
│ │ │ ├── test_model_load_balancing_service.py
│ │ │ ├── test_model_provider_service_sanitization.py
│ │ │ ├── test_operation_service.py
│ │ │ ├── test_ops_service.py
│ │ │ ├── test_rag_pipeline_task_proxy.py
│ │ │ ├── test_recommended_app_service.py
│ │ │ ├── test_schedule_service.py
│ │ │ ├── test_summary_index_service.py
│ │ │ ├── test_trigger_provider_service.py
│ │ │ ├── test_variable_truncator.py
│ │ │ ├── test_vector_service.py
│ │ │ ├── test_webhook_service.py
│ │ │ ├── test_website_service.py
│ │ │ ├── test_workflow_run_service_pause.py
│ │ │ ├── test_workflow_service.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_builtin_tools_manage_service.py
│ │ │ │ ├── test_mcp_tools_transform.py
│ │ │ │ ├── test_tool_labels_service.py
│ │ │ │ ├── test_tools_manage_service.py
│ │ │ │ └── test_tools_transform_service.py
│ │ │ ├── vector_service.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── test_draft_var_loader_simple.py
│ │ │ ├── test_queue_dispatcher.py
│ │ │ ├── test_scheduler.py
│ │ │ ├── test_workflow_draft_variable_service.py
│ │ │ ├── test_workflow_event_snapshot_service.py
│ │ │ ├── test_workflow_human_input_delivery.py
│ │ │ └── test_workflow_restore.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── test_async_workflow_tasks.py
│ │ │ ├── test_clean_dataset_task.py
│ │ │ ├── test_dataset_indexing_task.py
│ │ │ ├── test_delete_account_task.py
│ │ │ ├── test_document_indexing_sync_task.py
│ │ │ ├── test_duplicate_document_indexing_task.py
│ │ │ ├── test_enterprise_telemetry_task.py
│ │ │ ├── test_human_input_timeout_tasks.py
│ │ │ ├── test_mail_human_input_delivery_task.py
│ │ │ ├── test_mail_send_task.py
│ │ │ ├── test_remove_app_and_related_data_task.py
│ │ │ ├── test_summary_queue_isolation.py
│ │ │ ├── test_workflow_execute_task.py
│ │ │ └── test_workflow_node_execution_tasks.py
│ │ ├── tools/
│ │ │ ├── __init__.py
│ │ │ ├── test_api_tool.py
│ │ │ └── test_mcp_tool.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── http_parser/
│ │ │ └── test_oauth_convert_request_to_raw_data.py
│ │ ├── oauth_encryption/
│ │ │ └── test_system_oauth_encryption.py
│ │ ├── position_helper/
│ │ │ └── test_position_helper.py
│ │ ├── structured_output_parser/
│ │ │ ├── __init__.py
│ │ │ └── test_structured_output_parser.py
│ │ ├── test_text_processing.py
│ │ └── yaml/
│ │ ├── __init__.py
│ │ └── test_yaml_utils.py
│ └── workflow_test_utils.py
├── codecov.yml
├── dev/
│ ├── basedpyright-check
│ ├── pyrefly-check-local
│ ├── pytest/
│ │ ├── pytest_config_tests.py
│ │ ├── pytest_full.sh
│ │ ├── pytest_unit_tests.sh
│ │ └── pytest_vdb.sh
│ ├── reformat
│ ├── setup
│ ├── start-api
│ ├── start-beat
│ ├── start-docker-compose
│ ├── start-web
│ ├── start-worker
│ ├── sync-uv
│ ├── ty-check
│ └── update-uv
├── docker/
│ ├── README.md
│ ├── certbot/
│ │ ├── README.md
│ │ ├── docker-entrypoint.sh
│ │ └── update-cert.template.txt
│ ├── couchbase-server/
│ │ ├── Dockerfile
│ │ └── init-cbserver.sh
│ ├── dify-env-sync.py
│ ├── dify-env-sync.sh
│ ├── docker-compose-template.yaml
│ ├── docker-compose.middleware.yaml
│ ├── docker-compose.yaml
│ ├── elasticsearch/
│ │ └── docker-entrypoint.sh
│ ├── generate_docker_compose
│ ├── iris/
│ │ ├── docker-entrypoint.sh
│ │ └── iris-init.script
│ ├── middleware.env.example
│ ├── nginx/
│ │ ├── conf.d/
│ │ │ └── default.conf.template
│ │ ├── docker-entrypoint.sh
│ │ ├── https.conf.template
│ │ ├── nginx.conf.template
│ │ ├── proxy.conf.template
│ │ └── ssl/
│ │ └── .gitkeep
│ ├── pgvector/
│ │ └── docker-entrypoint.sh
│ ├── ssrf_proxy/
│ │ ├── docker-entrypoint.sh
│ │ └── squid.conf.template
│ ├── startupscripts/
│ │ ├── init.sh
│ │ └── init_user.script
│ ├── tidb/
│ │ ├── config/
│ │ │ ├── pd.toml
│ │ │ ├── tiflash-learner.toml
│ │ │ └── tiflash.toml
│ │ └── docker-compose.yaml
│ └── volumes/
│ ├── myscale/
│ │ └── config/
│ │ └── users.d/
│ │ └── custom_users_config.xml
│ ├── oceanbase/
│ │ └── init.d/
│ │ └── vec_memory.sql
│ ├── opensearch/
│ │ └── opensearch_dashboards.yml
│ └── sandbox/
│ └── conf/
│ ├── config.yaml
│ └── config.yaml.example
├── docs/
│ ├── ar-SA/
│ │ └── README.md
│ ├── bn-BD/
│ │ └── README.md
│ ├── de-DE/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── es-ES/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── eu-ai-act-compliance.md
│ ├── fr-FR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── hi-IN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── it-IT/
│ │ └── README.md
│ ├── ja-JP/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── ko-KR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── pt-BR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── sl-SI/
│ │ └── README.md
│ ├── suggested-questions-configuration.md
│ ├── tlh/
│ │ └── README.md
│ ├── tr-TR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── vi-VN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── weaviate/
│ │ └── WEAVIATE_MIGRATION_GUIDE/
│ │ └── README.md
│ ├── zh-CN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ └── zh-TW/
│ ├── CONTRIBUTING.md
│ └── README.md
├── e2e/
│ ├── .gitignore
│ ├── AGENTS.md
│ ├── README.md
│ ├── cucumber.config.ts
│ ├── features/
│ │ ├── apps/
│ │ │ └── create-app.feature
│ │ ├── smoke/
│ │ │ ├── authenticated-entry.feature
│ │ │ └── install.feature
│ │ ├── step-definitions/
│ │ │ ├── apps/
│ │ │ │ └── create-app.steps.ts
│ │ │ ├── common/
│ │ │ │ ├── auth.steps.ts
│ │ │ │ └── navigation.steps.ts
│ │ │ └── smoke/
│ │ │ └── install.steps.ts
│ │ └── support/
│ │ ├── hooks.ts
│ │ └── world.ts
│ ├── fixtures/
│ │ └── auth.ts
│ ├── package.json
│ ├── scripts/
│ │ ├── common.ts
│ │ ├── run-cucumber.ts
│ │ └── setup.ts
│ ├── support/
│ │ ├── process.ts
│ │ └── web-server.ts
│ ├── test-env.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── package.json
├── pnpm-workspace.yaml
├── scripts/
│ └── stress-test/
│ ├── README.md
│ ├── cleanup.py
│ ├── common/
│ │ ├── __init__.py
│ │ ├── config_helper.py
│ │ └── logger_helper.py
│ ├── locust.conf
│ ├── run_locust_stress_test.sh
│ ├── setup/
│ │ ├── configure_openai_plugin.py
│ │ ├── create_api_key.py
│ │ ├── dsl/
│ │ │ └── workflow_llm.yml
│ │ ├── import_workflow_app.py
│ │ ├── install_openai_plugin.py
│ │ ├── login_admin.py
│ │ ├── mock_openai_server.py
│ │ ├── publish_workflow.py
│ │ ├── run_workflow.py
│ │ └── setup_admin.py
│ ├── setup_all.py
│ └── sse_benchmark.py
├── sdks/
│ ├── README.md
│ ├── nodejs-client/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ └── publish.sh
│ │ ├── src/
│ │ │ ├── client/
│ │ │ │ ├── base.test.ts
│ │ │ │ ├── base.ts
│ │ │ │ ├── chat.test.ts
│ │ │ │ ├── chat.ts
│ │ │ │ ├── completion.test.ts
│ │ │ │ ├── completion.ts
│ │ │ │ ├── knowledge-base.test.ts
│ │ │ │ ├── knowledge-base.ts
│ │ │ │ ├── validation.test.ts
│ │ │ │ ├── validation.ts
│ │ │ │ ├── workflow.test.ts
│ │ │ │ ├── workflow.ts
│ │ │ │ ├── workspace.test.ts
│ │ │ │ └── workspace.ts
│ │ │ ├── errors/
│ │ │ │ ├── dify-error.test.ts
│ │ │ │ └── dify-error.ts
│ │ │ ├── http/
│ │ │ │ ├── client.test.ts
│ │ │ │ ├── client.ts
│ │ │ │ ├── form-data.test.ts
│ │ │ │ ├── form-data.ts
│ │ │ │ ├── retry.test.ts
│ │ │ │ ├── retry.ts
│ │ │ │ ├── sse.test.ts
│ │ │ │ └── sse.ts
│ │ │ ├── index.test.ts
│ │ │ ├── index.ts
│ │ │ ├── internal/
│ │ │ │ └── type-guards.ts
│ │ │ └── types/
│ │ │ ├── annotation.ts
│ │ │ ├── chat.ts
│ │ │ ├── common.ts
│ │ │ ├── completion.ts
│ │ │ ├── knowledge-base.ts
│ │ │ ├── workflow.ts
│ │ │ └── workspace.ts
│ │ ├── tests/
│ │ │ ├── http.integration.test.ts
│ │ │ └── test-utils.ts
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.ts
│ └── php-client/
│ ├── .gitignore
│ ├── README.md
│ ├── composer.json
│ └── dify-client.php
├── taze.config.js
├── vite.config.ts
└── web/
├── .gitignore
├── .npmrc
├── .storybook/
│ ├── __mocks__/
│ │ ├── context-block.tsx
│ │ ├── history-block.tsx
│ │ └── query-block.tsx
│ ├── main.ts
│ ├── preview.tsx
│ ├── storybook.css
│ └── utils/
│ ├── audio-player-manager.mock.ts
│ └── form-story-wrapper.tsx
├── .vscode/
│ ├── extensions.json
│ ├── launch.json
│ └── settings.example.json
├── AGENTS.md
├── Dockerfile
├── Dockerfile.dockerignore
├── README.md
├── __mocks__/
│ ├── provider-context.ts
│ └── zustand.ts
├── __tests__/
│ ├── apps/
│ │ ├── app-card-operations-flow.test.tsx
│ │ ├── app-list-browsing-flow.test.tsx
│ │ └── create-app-flow.test.tsx
│ ├── billing/
│ │ ├── billing-integration.test.tsx
│ │ ├── cloud-plan-payment-flow.test.tsx
│ │ ├── education-verification-flow.test.tsx
│ │ ├── partner-stack-flow.test.tsx
│ │ ├── pricing-modal-flow.test.tsx
│ │ └── self-hosted-plan-flow.test.tsx
│ ├── datasets/
│ │ ├── create-dataset-flow.test.tsx
│ │ ├── dataset-settings-flow.test.tsx
│ │ ├── document-management.test.tsx
│ │ ├── external-knowledge-base.test.tsx
│ │ ├── hit-testing-flow.test.tsx
│ │ ├── metadata-management-flow.test.tsx
│ │ ├── pipeline-datasource-flow.test.tsx
│ │ └── segment-crud.test.tsx
│ ├── description-validation.test.tsx
│ ├── develop/
│ │ ├── api-key-management-flow.test.tsx
│ │ └── develop-page-flow.test.tsx
│ ├── document-detail-navigation-fix.test.tsx
│ ├── document-list-sorting.test.tsx
│ ├── embedded-user-id-auth.test.tsx
│ ├── embedded-user-id-store.test.tsx
│ ├── explore/
│ │ ├── explore-app-list-flow.test.tsx
│ │ ├── installed-app-flow.test.tsx
│ │ └── sidebar-lifecycle-flow.test.tsx
│ ├── goto-anything/
│ │ ├── command-selector.test.tsx
│ │ ├── match-action.test.ts
│ │ ├── scope-command-tags.test.tsx
│ │ ├── search-error-handling.test.ts
│ │ └── slash-command-modes.test.tsx
│ ├── i18n-upload-features.test.ts
│ ├── instrumentation-client.spec.ts
│ ├── navigation-utils.test.ts
│ ├── plugin-tool-workflow-error.test.tsx
│ ├── plugins/
│ │ ├── plugin-auth-flow.test.tsx
│ │ ├── plugin-card-rendering.test.tsx
│ │ ├── plugin-data-utilities.test.ts
│ │ ├── plugin-install-flow.test.ts
│ │ ├── plugin-marketplace-to-install.test.tsx
│ │ └── plugin-page-filter-management.test.tsx
│ ├── rag-pipeline/
│ │ ├── chunk-preview-formatting.test.ts
│ │ ├── dsl-export-import-flow.test.ts
│ │ ├── input-field-crud-flow.test.ts
│ │ ├── input-field-editor-flow.test.ts
│ │ └── test-run-flow.test.ts
│ ├── real-browser-flicker.test.tsx
│ ├── share/
│ │ ├── text-generation-index-flow.test.tsx
│ │ ├── text-generation-run-batch-flow.test.tsx
│ │ └── text-generation-run-once-flow.test.tsx
│ ├── tools/
│ │ ├── tool-browsing-and-filtering.test.tsx
│ │ ├── tool-data-processing.test.ts
│ │ └── tool-provider-detail-flow.test.tsx
│ ├── unified-tags-logic.test.ts
│ ├── workflow-onboarding-integration.test.tsx
│ └── xss-prevention.test.tsx
├── app/
│ ├── (commonLayout)/
│ │ ├── app/
│ │ │ └── (appDetailLayout)/
│ │ │ ├── [appId]/
│ │ │ │ ├── annotations/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── configuration/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── develop/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout-main.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── logs/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── overview/
│ │ │ │ │ ├── card-view.tsx
│ │ │ │ │ ├── chart-view.tsx
│ │ │ │ │ ├── long-time-range-picker.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── time-range-picker/
│ │ │ │ │ │ ├── date-picker.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── range-selector.tsx
│ │ │ │ │ └── tracing/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── svg-attribute-error-reproduction.spec.tsx
│ │ │ │ │ ├── config-button.tsx
│ │ │ │ │ ├── config-popup.tsx
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── field.tsx
│ │ │ │ │ ├── panel.tsx
│ │ │ │ │ ├── provider-config-modal.tsx
│ │ │ │ │ ├── provider-panel.tsx
│ │ │ │ │ ├── tracing-icon.tsx
│ │ │ │ │ └── type.ts
│ │ │ │ ├── style.module.css
│ │ │ │ └── workflow/
│ │ │ │ └── page.tsx
│ │ │ └── layout.tsx
│ │ ├── apps/
│ │ │ └── page.tsx
│ │ ├── datasets/
│ │ │ ├── (datasetDetailLayout)/
│ │ │ │ ├── [datasetId]/
│ │ │ │ │ ├── api/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── documents/
│ │ │ │ │ │ ├── [documentId]/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── settings/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── create/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── create-from-pipeline/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ ├── hitTesting/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── layout-main.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── settings/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── layout.tsx
│ │ │ ├── connect/
│ │ │ │ └── page.tsx
│ │ │ ├── create/
│ │ │ │ └── page.tsx
│ │ │ ├── create-from-pipeline/
│ │ │ │ └── page.tsx
│ │ │ ├── layout.spec.tsx
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ ├── education-apply/
│ │ │ └── page.tsx
│ │ ├── explore/
│ │ │ ├── apps/
│ │ │ │ └── page.tsx
│ │ │ ├── installed/
│ │ │ │ └── [appId]/
│ │ │ │ └── page.tsx
│ │ │ └── layout.tsx
│ │ ├── layout.tsx
│ │ ├── plugins/
│ │ │ └── page.tsx
│ │ ├── role-route-guard.spec.tsx
│ │ ├── role-route-guard.tsx
│ │ └── tools/
│ │ └── page.tsx
│ ├── (humanInputLayout)/
│ │ └── form/
│ │ └── [token]/
│ │ ├── form.tsx
│ │ └── page.tsx
│ ├── (shareLayout)/
│ │ ├── chat/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── chatbot/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── completion/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── components/
│ │ │ ├── authenticated-layout.tsx
│ │ │ └── splash.tsx
│ │ ├── layout.tsx
│ │ ├── webapp-reset-password/
│ │ │ ├── check-code/
│ │ │ │ └── page.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ └── set-password/
│ │ │ └── page.tsx
│ │ ├── webapp-signin/
│ │ │ ├── check-code/
│ │ │ │ └── page.tsx
│ │ │ ├── components/
│ │ │ │ ├── external-member-sso-auth.tsx
│ │ │ │ ├── mail-and-code-auth.tsx
│ │ │ │ ├── mail-and-password-auth.tsx
│ │ │ │ └── sso-auth.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── normalForm.tsx
│ │ │ └── page.tsx
│ │ └── workflow/
│ │ └── [token]/
│ │ └── page.tsx
│ ├── account/
│ │ ├── (commonLayout)/
│ │ │ ├── account-page/
│ │ │ │ ├── AvatarWithEdit.tsx
│ │ │ │ ├── email-change-modal.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── delete-account/
│ │ │ │ ├── components/
│ │ │ │ │ ├── check-email.tsx
│ │ │ │ │ ├── feed-back.tsx
│ │ │ │ │ └── verify-email.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── state.tsx
│ │ │ ├── header.tsx
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ └── oauth/
│ │ └── authorize/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── activate/
│ │ ├── activateForm.tsx
│ │ └── page.tsx
│ ├── components/
│ │ ├── app/
│ │ │ ├── annotation/
│ │ │ │ ├── add-annotation-modal/
│ │ │ │ │ ├── edit-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── batch-action.spec.tsx
│ │ │ │ ├── batch-action.tsx
│ │ │ │ ├── batch-add-annotation-modal/
│ │ │ │ │ ├── csv-downloader.spec.tsx
│ │ │ │ │ ├── csv-downloader.tsx
│ │ │ │ │ ├── csv-uploader.spec.tsx
│ │ │ │ │ ├── csv-uploader.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── clear-all-annotations-confirm-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── edit-annotation-modal/
│ │ │ │ │ ├── edit-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── empty-element.spec.tsx
│ │ │ │ ├── empty-element.tsx
│ │ │ │ ├── filter.spec.tsx
│ │ │ │ ├── filter.tsx
│ │ │ │ ├── header-opts/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ ├── remove-annotation-confirm-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── type.ts
│ │ │ │ └── view-annotation-modal/
│ │ │ │ ├── hit-history-no-data.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-access-control/
│ │ │ │ ├── access-control-dialog.tsx
│ │ │ │ ├── access-control-item.tsx
│ │ │ │ ├── access-control.spec.tsx
│ │ │ │ ├── add-member-or-group-pop.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── specific-groups-or-members.tsx
│ │ │ ├── app-publisher/
│ │ │ │ ├── features-wrapper.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── publish-with-multiple-model.tsx
│ │ │ │ ├── suggested-action.tsx
│ │ │ │ └── version-info-modal.tsx
│ │ │ ├── configuration/
│ │ │ │ ├── base/
│ │ │ │ │ ├── feature-panel/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── group-name/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── operation-btn/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── var-highlight/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ └── warning-mask/
│ │ │ │ │ ├── cannot-query-dataset.spec.tsx
│ │ │ │ │ ├── cannot-query-dataset.tsx
│ │ │ │ │ ├── formatting-changed.spec.tsx
│ │ │ │ │ ├── formatting-changed.tsx
│ │ │ │ │ ├── has-not-set-api.spec.tsx
│ │ │ │ │ ├── has-not-set-api.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── config/
│ │ │ │ │ ├── agent/
│ │ │ │ │ │ ├── agent-setting/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── item-panel.spec.tsx
│ │ │ │ │ │ │ └── item-panel.tsx
│ │ │ │ │ │ ├── agent-tools/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── setting-built-in-tool.spec.tsx
│ │ │ │ │ │ │ └── setting-built-in-tool.tsx
│ │ │ │ │ │ └── prompt-editor.tsx
│ │ │ │ │ ├── agent-setting-button.spec.tsx
│ │ │ │ │ ├── agent-setting-button.tsx
│ │ │ │ │ ├── assistant-type-picker/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── automatic/
│ │ │ │ │ │ ├── automatic-btn.spec.tsx
│ │ │ │ │ │ ├── automatic-btn.tsx
│ │ │ │ │ │ ├── get-automatic-res.tsx
│ │ │ │ │ │ ├── idea-output.tsx
│ │ │ │ │ │ ├── instruction-editor-in-workflow.tsx
│ │ │ │ │ │ ├── instruction-editor.tsx
│ │ │ │ │ │ ├── prompt-res-in-workflow.tsx
│ │ │ │ │ │ ├── prompt-res.tsx
│ │ │ │ │ │ ├── prompt-toast.tsx
│ │ │ │ │ │ ├── res-placeholder.tsx
│ │ │ │ │ │ ├── result.tsx
│ │ │ │ │ │ ├── style.module.css
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ ├── use-gen-data.ts
│ │ │ │ │ │ └── version-selector.tsx
│ │ │ │ │ ├── code-generator/
│ │ │ │ │ │ └── get-code-generator-res.tsx
│ │ │ │ │ ├── config-audio.spec.tsx
│ │ │ │ │ ├── config-audio.tsx
│ │ │ │ │ ├── config-document.spec.tsx
│ │ │ │ │ ├── config-document.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── config-prompt/
│ │ │ │ │ ├── advanced-prompt-input.tsx
│ │ │ │ │ ├── confirm-add-var/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── conversation-history/
│ │ │ │ │ │ ├── edit-modal.spec.tsx
│ │ │ │ │ │ ├── edit-modal.tsx
│ │ │ │ │ │ ├── history-panel.spec.tsx
│ │ │ │ │ │ └── history-panel.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── message-type-selector.spec.tsx
│ │ │ │ │ ├── message-type-selector.tsx
│ │ │ │ │ ├── prompt-editor-height-resize-wrap.spec.tsx
│ │ │ │ │ ├── prompt-editor-height-resize-wrap.tsx
│ │ │ │ │ ├── simple-prompt-input.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── config-var/
│ │ │ │ │ ├── config-modal/
│ │ │ │ │ │ ├── config.ts
│ │ │ │ │ │ ├── field.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── type-select.tsx
│ │ │ │ │ ├── config-select/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── config-string/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── input-type-icon.tsx
│ │ │ │ │ ├── modal-foot.tsx
│ │ │ │ │ ├── select-type-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── select-var-type.tsx
│ │ │ │ │ └── var-item.tsx
│ │ │ │ ├── config-vision/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── param-config-content.tsx
│ │ │ │ │ └── param-config.tsx
│ │ │ │ ├── ctrl-btn-group/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── dataset-config/
│ │ │ │ │ ├── card-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── context-var/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── var-picker.spec.tsx
│ │ │ │ │ │ └── var-picker.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── params-config/
│ │ │ │ │ │ ├── config-content.spec.tsx
│ │ │ │ │ │ ├── config-content.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── weighted-score.spec.tsx
│ │ │ │ │ │ └── weighted-score.tsx
│ │ │ │ │ ├── select-dataset/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── settings-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── retrieval-section.spec.tsx
│ │ │ │ │ └── retrieval-section.tsx
│ │ │ │ ├── debug/
│ │ │ │ │ ├── chat-user-input.spec.tsx
│ │ │ │ │ ├── chat-user-input.tsx
│ │ │ │ │ ├── debug-with-multiple-model/
│ │ │ │ │ │ ├── chat-item.spec.tsx
│ │ │ │ │ │ ├── chat-item.tsx
│ │ │ │ │ │ ├── context-provider.tsx
│ │ │ │ │ │ ├── context.spec.tsx
│ │ │ │ │ │ ├── context.ts
│ │ │ │ │ │ ├── debug-item.spec.tsx
│ │ │ │ │ │ ├── debug-item.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── model-parameter-trigger.spec.tsx
│ │ │ │ │ │ ├── model-parameter-trigger.tsx
│ │ │ │ │ │ ├── text-generation-item.spec.tsx
│ │ │ │ │ │ └── text-generation-item.tsx
│ │ │ │ │ ├── debug-with-single-model/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ └── use-advanced-prompt-config.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── prompt-value-panel/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── utils.spec.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── style.module.css
│ │ │ │ └── tools/
│ │ │ │ ├── external-data-tool-modal.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-app-dialog/
│ │ │ │ ├── app-card/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── app-list/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── sidebar.spec.tsx
│ │ │ │ │ └── sidebar.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-app-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-from-dsl-modal/
│ │ │ │ ├── dsl-confirm-modal.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── uploader.tsx
│ │ │ ├── duplicate-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── in-site-message/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── notification.spec.tsx
│ │ │ │ └── notification.tsx
│ │ │ ├── log/
│ │ │ │ ├── empty-element.spec.tsx
│ │ │ │ ├── empty-element.tsx
│ │ │ │ ├── filter.spec.tsx
│ │ │ │ ├── filter.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ ├── model-info.spec.tsx
│ │ │ │ ├── model-info.tsx
│ │ │ │ ├── var-panel.spec.tsx
│ │ │ │ └── var-panel.tsx
│ │ │ ├── log-annotation/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── overview/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── toggle-logic.test.ts
│ │ │ │ ├── apikey-info-panel/
│ │ │ │ │ ├── apikey-info-panel.test-utils.tsx
│ │ │ │ │ ├── cloud.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── app-card.tsx
│ │ │ │ ├── app-chart.tsx
│ │ │ │ ├── customize/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── embedded/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── settings/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── style.module.css
│ │ │ │ ├── trigger-card.spec.tsx
│ │ │ │ └── trigger-card.tsx
│ │ │ ├── store.ts
│ │ │ ├── switch-app-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── text-generate/
│ │ │ │ ├── item/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── result-tab.tsx
│ │ │ │ └── saved-items/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── no-data/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── type-selector/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ └── workflow-log/
│ │ │ ├── detail.spec.tsx
│ │ │ ├── detail.tsx
│ │ │ ├── filter.spec.tsx
│ │ │ ├── filter.tsx
│ │ │ ├── index.spec.tsx
│ │ │ ├── index.tsx
│ │ │ ├── list.spec.tsx
│ │ │ ├── list.tsx
│ │ │ ├── trigger-by-display.spec.tsx
│ │ │ └── trigger-by-display.tsx
│ │ ├── app-initializer.tsx
│ │ ├── app-sidebar/
│ │ │ ├── __tests__/
│ │ │ │ ├── app-sidebar-dropdown.spec.tsx
│ │ │ │ ├── basic.spec.tsx
│ │ │ │ ├── dataset-sidebar-dropdown.spec.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── sidebar-animation-issues.spec.tsx
│ │ │ │ ├── text-squeeze-fix-verification.spec.tsx
│ │ │ │ └── toggle-button.spec.tsx
│ │ │ ├── app-info/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── app-info-detail-panel.spec.tsx
│ │ │ │ │ ├── app-info-modals.spec.tsx
│ │ │ │ │ ├── app-info-trigger.spec.tsx
│ │ │ │ │ ├── app-mode-labels.spec.ts
│ │ │ │ │ ├── app-operations.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── use-app-info-actions.spec.ts
│ │ │ │ ├── app-info-detail-panel.tsx
│ │ │ │ ├── app-info-modals.tsx
│ │ │ │ ├── app-info-trigger.tsx
│ │ │ │ ├── app-mode-labels.ts
│ │ │ │ ├── app-operations.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── use-app-info-actions.ts
│ │ │ ├── app-sidebar-dropdown.tsx
│ │ │ ├── basic.tsx
│ │ │ ├── dataset-info/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── dropdown-callbacks.spec.tsx
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── dropdown.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── menu-item.tsx
│ │ │ │ └── menu.tsx
│ │ │ ├── dataset-sidebar-dropdown.tsx
│ │ │ ├── index.tsx
│ │ │ ├── nav-link/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ └── toggle-button.tsx
│ │ ├── apps/
│ │ │ ├── __tests__/
│ │ │ │ ├── app-card.spec.tsx
│ │ │ │ ├── empty.spec.tsx
│ │ │ │ ├── footer.spec.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ └── new-app-card.spec.tsx
│ │ │ ├── app-card-skeleton.tsx
│ │ │ ├── app-card.tsx
│ │ │ ├── empty.tsx
│ │ │ ├── footer.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── use-apps-query-state.spec.tsx
│ │ │ │ │ └── use-dsl-drag-drop.spec.ts
│ │ │ │ ├── use-apps-query-state.ts
│ │ │ │ └── use-dsl-drag-drop.ts
│ │ │ ├── index.tsx
│ │ │ ├── list.tsx
│ │ │ └── new-app-card.tsx
│ │ ├── base/
│ │ │ ├── __tests__/
│ │ │ │ ├── alert.spec.tsx
│ │ │ │ ├── app-unavailable.spec.tsx
│ │ │ │ ├── badge.spec.tsx
│ │ │ │ ├── theme-selector.spec.tsx
│ │ │ │ └── theme-switcher.spec.tsx
│ │ │ ├── action-button/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── agent-log-modal/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── detail.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── iteration.spec.tsx
│ │ │ │ │ ├── result.spec.tsx
│ │ │ │ │ ├── tool-call.spec.tsx
│ │ │ │ │ └── tracing.spec.tsx
│ │ │ │ ├── detail.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── iteration.tsx
│ │ │ │ ├── result.tsx
│ │ │ │ ├── tool-call.tsx
│ │ │ │ └── tracing.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── amplitude/
│ │ │ │ ├── AmplitudeProvider.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── AmplitudeProvider.spec.tsx
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── lazy-amplitude-provider.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── answer-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-icon-picker/
│ │ │ │ ├── ImageInput.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── ImageInput.spec.tsx
│ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── hooks.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── style.module.css
│ │ │ │ └── utils.ts
│ │ │ ├── app-unavailable.tsx
│ │ │ ├── audio-btn/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── audio.player.manager.spec.ts
│ │ │ │ │ ├── audio.spec.ts
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── audio.player.manager.ts
│ │ │ │ ├── audio.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.css
│ │ │ ├── audio-gallery/
│ │ │ │ ├── AudioPlayer.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── AudioPlayer.spec.tsx
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── auto-height-textarea/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.scss
│ │ │ ├── avatar/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── badge/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── block-input/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── button/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── add-button.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── sync-button.spec.tsx
│ │ │ │ ├── add-button.stories.tsx
│ │ │ │ ├── add-button.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── sync-button.stories.tsx
│ │ │ │ └── sync-button.tsx
│ │ │ ├── carousel/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── chat/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── utils.spec.ts.snap
│ │ │ │ │ ├── branchedTestMessages.json
│ │ │ │ │ ├── legacyTestMessages.json
│ │ │ │ │ ├── mixedTestMessages.json
│ │ │ │ │ ├── multiRootNodesMessages.json
│ │ │ │ │ ├── multiRootNodesWithLegacyTestMessages.json
│ │ │ │ │ ├── partialMessages.json
│ │ │ │ │ ├── realWorldMessages.json
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── chat/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── check-input-forms-hooks.spec.tsx
│ │ │ │ │ │ ├── content-switch.spec.tsx
│ │ │ │ │ │ ├── context.spec.tsx
│ │ │ │ │ │ ├── hooks.multimodal.spec.ts
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── question.spec.tsx
│ │ │ │ │ │ ├── try-to-ask.spec.tsx
│ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ ├── answer/
│ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ ├── markdownContent.ts
│ │ │ │ │ │ │ ├── markdownContentSVG.ts
│ │ │ │ │ │ │ └── workflowProcess.ts
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── agent-content.spec.tsx
│ │ │ │ │ │ │ ├── basic-content.spec.tsx
│ │ │ │ │ │ │ ├── human-input-filled-form-list.spec.tsx
│ │ │ │ │ │ │ ├── human-input-form-list.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── more.spec.tsx
│ │ │ │ │ │ │ ├── operation.spec.tsx
│ │ │ │ │ │ │ ├── suggested-questions.spec.tsx
│ │ │ │ │ │ │ ├── tool-detail.spec.tsx
│ │ │ │ │ │ │ └── workflow-process.spec.tsx
│ │ │ │ │ │ ├── agent-content.tsx
│ │ │ │ │ │ ├── basic-content.tsx
│ │ │ │ │ │ ├── human-input-content/
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ ├── content-item.spec.tsx
│ │ │ │ │ │ │ │ ├── content-wrapper.spec.tsx
│ │ │ │ │ │ │ │ ├── executed-action.spec.tsx
│ │ │ │ │ │ │ │ ├── expiration-time.spec.tsx
│ │ │ │ │ │ │ │ ├── human-input-form.spec.tsx
│ │ │ │ │ │ │ │ ├── submitted-content.spec.tsx
│ │ │ │ │ │ │ │ ├── submitted.spec.tsx
│ │ │ │ │ │ │ │ ├── tips.spec.tsx
│ │ │ │ │ │ │ │ ├── unsubmitted.spec.tsx
│ │ │ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ │ │ ├── content-item.tsx
│ │ │ │ │ │ │ ├── content-wrapper.tsx
│ │ │ │ │ │ │ ├── executed-action.tsx
│ │ │ │ │ │ │ ├── expiration-time.tsx
│ │ │ │ │ │ │ ├── human-input-form.tsx
│ │ │ │ │ │ │ ├── submitted-content.tsx
│ │ │ │ │ │ │ ├── submitted.tsx
│ │ │ │ │ │ │ ├── tips.tsx
│ │ │ │ │ │ │ ├── type.ts
│ │ │ │ │ │ │ ├── unsubmitted.tsx
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── human-input-filled-form-list.tsx
│ │ │ │ │ │ ├── human-input-form-list.tsx
│ │ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── more.tsx
│ │ │ │ │ │ ├── operation.tsx
│ │ │ │ │ │ ├── suggested-questions.tsx
│ │ │ │ │ │ ├── tool-detail.tsx
│ │ │ │ │ │ └── workflow-process.tsx
│ │ │ │ │ ├── chat-input-area/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── hooks.spec.ts
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── operation.spec.tsx
│ │ │ │ │ │ ├── hooks.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── operation.tsx
│ │ │ │ │ ├── check-input-forms-hooks.ts
│ │ │ │ │ ├── citation/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── popup.spec.tsx
│ │ │ │ │ │ │ ├── progress-tooltip.spec.tsx
│ │ │ │ │ │ │ └── tooltip.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── popup.tsx
│ │ │ │ │ │ ├── progress-tooltip.tsx
│ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ ├── content-switch.tsx
│ │ │ │ │ ├── context-provider.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── hooks.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── loading-anim/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ ├── log/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── question.stories.tsx
│ │ │ │ │ ├── question.tsx
│ │ │ │ │ ├── thought/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── try-to-ask.tsx
│ │ │ │ │ ├── type.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── chat-with-history/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── chat-wrapper.spec.tsx
│ │ │ │ │ │ ├── header-in-mobile.spec.tsx
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ ├── chat-wrapper.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── header/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── mobile-operation-dropdown.spec.tsx
│ │ │ │ │ │ │ └── operation.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── mobile-operation-dropdown.tsx
│ │ │ │ │ │ └── operation.tsx
│ │ │ │ │ ├── header-in-mobile.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── inputs-form/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── content.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── view-form-dropdown.spec.tsx
│ │ │ │ │ │ ├── content.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── view-form-dropdown.tsx
│ │ │ │ │ └── sidebar/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── item.spec.tsx
│ │ │ │ │ │ ├── list.spec.tsx
│ │ │ │ │ │ ├── operation.spec.tsx
│ │ │ │ │ │ └── rename-modal.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── item.tsx
│ │ │ │ │ ├── list.tsx
│ │ │ │ │ ├── operation.tsx
│ │ │ │ │ └── rename-modal.tsx
│ │ │ │ ├── constants.ts
│ │ │ │ ├── embedded-chatbot/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── chat-wrapper.spec.tsx
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ ├── chat-wrapper.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── header/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── inputs-form/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── content.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── view-form-dropdown.spec.tsx
│ │ │ │ │ │ ├── content.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── view-form-dropdown.tsx
│ │ │ │ │ ├── theme/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── theme-context.spec.ts
│ │ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ │ ├── theme-context.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ ├── checkbox/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── assets/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── indeterminate-icon.spec.tsx
│ │ │ │ │ └── indeterminate-icon.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── checkbox-list/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── chip/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── confirm/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── content-dialog/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── copy-feedback/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.css
│ │ │ ├── copy-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── corner-label/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── date-and-time-picker/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── hooks.spec.ts
│ │ │ │ ├── calendar/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── days-of-week.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── item.spec.tsx
│ │ │ │ │ ├── days-of-week.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── item.tsx
│ │ │ │ ├── common/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── option-list-item.spec.tsx
│ │ │ │ │ └── option-list-item.tsx
│ │ │ │ ├── date-picker/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── footer.spec.tsx
│ │ │ │ │ │ ├── header.spec.tsx
│ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ ├── footer.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── hooks.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── time-picker/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── footer.spec.tsx
│ │ │ │ │ │ ├── header.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── options.spec.tsx
│ │ │ │ │ ├── footer.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── options.tsx
│ │ │ │ ├── types.ts
│ │
================================================
FILE CONTENTS
================================================
================================================
FILE: .agents/skills/backend-code-review/SKILL.md
================================================
---
name: backend-code-review
description: Review backend code for quality, security, maintainability, and best practices based on established checklist rules. Use when the user requests a review, analysis, or improvement of backend files (e.g., `.py`) under the `api/` directory. Do NOT use for frontend files (e.g., `.tsx`, `.ts`, `.js`). Supports pending-change review, code snippets review, and file-focused review.
---
# Backend Code Review
## When to use this skill
Use this skill whenever the user asks to **review, analyze, or improve** backend code (e.g., `.py`) under the `api/` directory. Supports the following review modes:
- **Pending-change review**: when the user asks to review current changes (inspect staged/working-tree files slated for commit to get the changes).
- **Code snippets review**: when the user pastes code snippets (e.g., a function/class/module excerpt) into the chat and asks for a review.
- **File-focused review**: when the user points to specific files and asks for a review of those files (one file or a small, explicit set of files, e.g., `api/...`, `api/app.py`).
Do NOT use this skill when:
- The request is about frontend code or UI (e.g., `.tsx`, `.ts`, `.js`, `web/`).
- The user is not asking for a review/analysis/improvement of backend code.
- The scope is not under `api/` (unless the user explicitly asks to review backend-related changes outside `api/`).
## How to use this skill
Follow these steps when using this skill:
1. **Identify the review mode** (pending-change vs snippet vs file-focused) based on the user’s input. Keep the scope tight: review only what the user provided or explicitly referenced.
2. Follow the rules defined in **Checklist** to perform the review. If no Checklist rule matches, apply **General Review Rules** as a fallback to perform the best-effort review.
3. Compose the final output strictly follow the **Required Output Format**.
Notes when using this skill:
- Always include actionable fixes or suggestions (including possible code snippets).
- Use best-effort `File:Line` references when a file path and line numbers are available; otherwise, use the most specific identifier you can.
## Checklist
- db schema design: if the review scope includes code/files under `api/models/` or `api/migrations/`, follow [references/db-schema-rule.md](references/db-schema-rule.md) to perform the review
- architecture: if the review scope involves controller/service/core-domain/libs/model layering, dependency direction, or moving responsibilities across modules, follow [references/architecture-rule.md](references/architecture-rule.md) to perform the review
- repositories abstraction: if the review scope contains table/model operations (e.g., `select(...)`, `session.execute(...)`, joins, CRUD) and is not under `api/repositories`, `api/core/repositories`, or `api/extensions/*/repositories/`, follow [references/repositories-rule.md](references/repositories-rule.md) to perform the review
- sqlalchemy patterns: if the review scope involves SQLAlchemy session/query usage, db transaction/crud usage, or raw SQL usage, follow [references/sqlalchemy-rule.md](references/sqlalchemy-rule.md) to perform the review
## General Review Rules
### 1. Security Review
Check for:
- SQL injection vulnerabilities
- Server-Side Request Forgery (SSRF)
- Command injection
- Insecure deserialization
- Hardcoded secrets/credentials
- Improper authentication/authorization
- Insecure direct object references
### 2. Performance Review
Check for:
- N+1 queries
- Missing database indexes
- Memory leaks
- Blocking operations in async code
- Missing caching opportunities
### 3. Code Quality Review
Check for:
- Code forward compatibility
- Code duplication (DRY violations)
- Functions doing too much (SRP violations)
- Deep nesting / complex conditionals
- Magic numbers/strings
- Poor naming
- Missing error handling
- Incomplete type coverage
### 4. Testing Review
Check for:
- Missing test coverage for new code
- Tests that don't test behavior
- Flaky test patterns
- Missing edge cases
## Required Output Format
When this skill invoked, the response must exactly follow one of the two templates:
### Template A (any findings)
```markdown
# Code Review Summary
Found <X> critical issues need to be fixed:
## 🔴 Critical (Must Fix)
### 1. <brief description of the issue>
FilePath: <path> line <line>
<relevant code snippet or pointer>
#### Explanation
<detailed explanation and references of the issue>
#### Suggested Fix
1. <brief description of suggested fix>
2. <code example> (optional, omit if not applicable)
---
... (repeat for each critical issue) ...
Found <Y> suggestions for improvement:
## 🟡 Suggestions (Should Consider)
### 1. <brief description of the suggestion>
FilePath: <path> line <line>
<relevant code snippet or pointer>
#### Explanation
<detailed explanation and references of the suggestion>
#### Suggested Fix
1. <brief description of suggested fix>
2. <code example> (optional, omit if not applicable)
---
... (repeat for each suggestion) ...
Found <Z> optional nits:
## 🟢 Nits (Optional)
### 1. <brief description of the nit>
FilePath: <path> line <line>
<relevant code snippet or pointer>
#### Explanation
<explanation and references of the optional nit>
#### Suggested Fix
- <minor suggestions>
---
... (repeat for each nits) ...
## ✅ What's Good
- <Positive feedback on good patterns>
```
- If there are no critical issues or suggestions or option nits or good points, just omit that section.
- If the issue number is more than 10, summarize as "Found 10+ critical issues/suggestions/optional nits" and only output the first 10 items.
- Don't compress the blank lines between sections; keep them as-is for readability.
- If there is any issue requires code changes, append a brief follow-up question to ask whether the user wants to apply the fix(es) after the structured output. For example: "Would you like me to use the Suggested fix(es) to address these issues?"
### Template B (no issues)
```markdown
## Code Review Summary
✅ No issues found.
```
================================================
FILE: .agents/skills/backend-code-review/references/architecture-rule.md
================================================
# Rule Catalog — Architecture
## Scope
- Covers: controller/service/core-domain/libs/model layering, dependency direction, responsibility placement, observability-friendly flow.
## Rules
### Keep business logic out of controllers
- Category: maintainability
- Severity: critical
- Description: Controllers should parse input, call services, and return serialized responses. Business decisions inside controllers make behavior hard to reuse and test.
- Suggested fix: Move domain/business logic into the service or core/domain layer. Keep controller handlers thin and orchestration-focused.
- Example:
- Bad:
```python
@bp.post("/apps/<app_id>/publish")
def publish_app(app_id: str):
payload = request.get_json() or {}
if payload.get("force") and current_user.role != "admin":
raise ValueError("only admin can force publish")
app = App.query.get(app_id)
app.status = "published"
db.session.commit()
return {"result": "ok"}
```
- Good:
```python
@bp.post("/apps/<app_id>/publish")
def publish_app(app_id: str):
payload = PublishRequest.model_validate(request.get_json() or {})
app_service.publish_app(app_id=app_id, force=payload.force, actor_id=current_user.id)
return {"result": "ok"}
```
### Preserve layer dependency direction
- Category: best practices
- Severity: critical
- Description: Controllers may depend on services, and services may depend on core/domain abstractions. Reversing this direction (for example, core importing controller/web modules) creates cycles and leaks transport concerns into domain code.
- Suggested fix: Extract shared contracts into core/domain or service-level modules and make upper layers depend on lower, not the reverse.
- Example:
- Bad:
```python
# core/policy/publish_policy.py
from controllers.console.app import request_context
def can_publish() -> bool:
return request_context.current_user.is_admin
```
- Good:
```python
# core/policy/publish_policy.py
def can_publish(role: str) -> bool:
return role == "admin"
# service layer adapts web/user context to domain input
allowed = can_publish(role=current_user.role)
```
### Keep libs business-agnostic
- Category: maintainability
- Severity: critical
- Description: Modules under `api/libs/` should remain reusable, business-agnostic building blocks. They must not encode product/domain-specific rules, workflow orchestration, or business decisions.
- Suggested fix:
- If business logic appears in `api/libs/`, extract it into the appropriate `services/` or `core/` module and keep `libs` focused on generic, cross-cutting helpers.
- Keep `libs` dependencies clean: avoid importing service/controller/domain-specific modules into `api/libs/`.
- Example:
- Bad:
```python
# api/libs/conversation_filter.py
from services.conversation_service import ConversationService
def should_archive_conversation(conversation, tenant_id: str) -> bool:
# Domain policy and service dependency are leaking into libs.
service = ConversationService()
if service.has_paid_plan(tenant_id):
return conversation.idle_days > 90
return conversation.idle_days > 30
```
- Good:
```python
# api/libs/datetime_utils.py (business-agnostic helper)
def older_than_days(idle_days: int, threshold_days: int) -> bool:
return idle_days > threshold_days
# services/conversation_service.py (business logic stays in service/core)
from libs.datetime_utils import older_than_days
def should_archive_conversation(conversation, tenant_id: str) -> bool:
threshold_days = 90 if has_paid_plan(tenant_id) else 30
return older_than_days(conversation.idle_days, threshold_days)
```
================================================
FILE: .agents/skills/backend-code-review/references/db-schema-rule.md
================================================
# Rule Catalog — DB Schema Design
## Scope
- Covers: model/base inheritance, schema boundaries in model properties, tenant-aware schema design, index redundancy checks, dialect portability in models, and cross-database compatibility in migrations.
- Does NOT cover: session lifecycle, transaction boundaries, and query execution patterns (handled by `sqlalchemy-rule.md`).
## Rules
### Do not query other tables inside `@property`
- Category: [maintainability, performance]
- Severity: critical
- Description: A model `@property` must not open sessions or query other tables. This hides dependencies across models, tightly couples schema objects to data access, and can cause N+1 query explosions when iterating collections.
- Suggested fix:
- Keep model properties pure and local to already-loaded fields.
- Move cross-table data fetching to service/repository methods.
- For list/batch reads, fetch required related data explicitly (join/preload/bulk query) before rendering derived values.
- Example:
- Bad:
```python
class Conversation(TypeBase):
__tablename__ = "conversations"
@property
def app_name(self) -> str:
with Session(db.engine, expire_on_commit=False) as session:
app = session.execute(select(App).where(App.id == self.app_id)).scalar_one()
return app.name
```
- Good:
```python
class Conversation(TypeBase):
__tablename__ = "conversations"
@property
def display_title(self) -> str:
return self.name or "Untitled"
# Service/repository layer performs explicit batch fetch for related App rows.
```
### Prefer including `tenant_id` in model definitions
- Category: maintainability
- Severity: suggestion
- Description: In multi-tenant domains, include `tenant_id` in schema definitions whenever the entity belongs to tenant-owned data. This improves data isolation safety and keeps future partitioning/sharding strategies practical as data volume grows.
- Suggested fix:
- Add a `tenant_id` column and ensure related unique/index constraints include tenant dimension when applicable.
- Propagate `tenant_id` through service/repository contracts to keep access paths tenant-aware.
- Exception: if a table is explicitly designed as non-tenant-scoped global metadata, document that design decision clearly.
- Example:
- Bad:
```python
from sqlalchemy.orm import Mapped
class Dataset(TypeBase):
__tablename__ = "datasets"
id: Mapped[str] = mapped_column(StringUUID, primary_key=True)
name: Mapped[str] = mapped_column(sa.String(255), nullable=False)
```
- Good:
```python
from sqlalchemy.orm import Mapped
class Dataset(TypeBase):
__tablename__ = "datasets"
id: Mapped[str] = mapped_column(StringUUID, primary_key=True)
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False, index=True)
name: Mapped[str] = mapped_column(sa.String(255), nullable=False)
```
### Detect and avoid duplicate/redundant indexes
- Category: performance
- Severity: suggestion
- Description: Review index definitions for leftmost-prefix redundancy. For example, index `(a, b, c)` can safely cover most lookups for `(a, b)`. Keeping both may increase write overhead and can mislead the optimizer into suboptimal execution plans.
- Suggested fix:
- Before adding an index, compare against existing composite indexes by leftmost-prefix rules.
- Drop or avoid creating redundant prefixes unless there is a proven query-pattern need.
- Apply the same review standard in both model `__table_args__` and migration index DDL.
- Example:
- Bad:
```python
__table_args__ = (
sa.Index("idx_msg_tenant_app", "tenant_id", "app_id"),
sa.Index("idx_msg_tenant_app_created", "tenant_id", "app_id", "created_at"),
)
```
- Good:
```python
__table_args__ = (
# Keep the wider index unless profiling proves a dedicated short index is needed.
sa.Index("idx_msg_tenant_app_created", "tenant_id", "app_id", "created_at"),
)
```
### Avoid PostgreSQL-only dialect usage in models; wrap in `models.types`
- Category: maintainability
- Severity: critical
- Description: Model/schema definitions should avoid PostgreSQL-only constructs directly in business models. When database-specific behavior is required, encapsulate it in `api/models/types.py` using both PostgreSQL and MySQL dialect implementations, then consume that abstraction from model code.
- Suggested fix:
- Do not directly place dialect-only types/operators in model columns when a portable wrapper can be used.
- Add or extend wrappers in `models.types` (for example, `AdjustedJSON`, `LongText`, `BinaryData`) to normalize behavior across PostgreSQL and MySQL.
- Example:
- Bad:
```python
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped
class ToolConfig(TypeBase):
__tablename__ = "tool_configs"
config: Mapped[dict] = mapped_column(JSONB, nullable=False)
```
- Good:
```python
from sqlalchemy.orm import Mapped
from models.types import AdjustedJSON
class ToolConfig(TypeBase):
__tablename__ = "tool_configs"
config: Mapped[dict] = mapped_column(AdjustedJSON(), nullable=False)
```
### Guard migration incompatibilities with dialect checks and shared types
- Category: maintainability
- Severity: critical
- Description: Migration scripts under `api/migrations/versions/` must account for PostgreSQL/MySQL incompatibilities explicitly. For dialect-sensitive DDL or defaults, branch on the active dialect (for example, `conn.dialect.name == "postgresql"`), and prefer reusable compatibility abstractions from `models.types` where applicable.
- Suggested fix:
- In migration upgrades/downgrades, bind connection and branch by dialect for incompatible SQL fragments.
- Reuse `models.types` wrappers in column definitions when that keeps behavior aligned with runtime models.
- Avoid one-dialect-only migration logic unless there is a documented, deliberate compatibility exception.
- Example:
- Bad:
```python
with op.batch_alter_table("dataset_keyword_tables") as batch_op:
batch_op.add_column(
sa.Column(
"data_source_type",
sa.String(255),
server_default=sa.text("'database'::character varying"),
nullable=False,
)
)
```
- Good:
```python
def _is_pg(conn) -> bool:
return conn.dialect.name == "postgresql"
conn = op.get_bind()
default_expr = sa.text("'database'::character varying") if _is_pg(conn) else sa.text("'database'")
with op.batch_alter_table("dataset_keyword_tables") as batch_op:
batch_op.add_column(
sa.Column("data_source_type", sa.String(255), server_default=default_expr, nullable=False)
)
```
================================================
FILE: .agents/skills/backend-code-review/references/repositories-rule.md
================================================
# Rule Catalog - Repositories Abstraction
## Scope
- Covers: when to reuse existing repository abstractions, when to introduce new repositories, and how to preserve dependency direction between service/core and infrastructure implementations.
- Does NOT cover: SQLAlchemy session lifecycle and query-shape specifics (handled by `sqlalchemy-rule.md`), and table schema/migration design (handled by `db-schema-rule.md`).
## Rules
### Introduce repositories abstraction
- Category: maintainability
- Severity: suggestion
- Description: If a table/model already has a repository abstraction, all reads/writes/queries for that table should use the existing repository. If no repository exists, introduce one only when complexity justifies it, such as large/high-volume tables, repeated complex query logic, or likely storage-strategy variation.
- Suggested fix:
- First check `api/repositories`, `api/core/repositories`, and `api/extensions/*/repositories/` to verify whether the table/model already has a repository abstraction. If it exists, route all operations through it and add missing repository methods instead of bypassing it with ad-hoc SQLAlchemy access.
- If no repository exists, add one only when complexity warrants it (for example, repeated complex queries, large data domains, or multiple storage strategies), while preserving dependency direction (service/core depends on abstraction; infra provides implementation).
- Example:
- Bad:
```python
# Existing repository is ignored and service uses ad-hoc table queries.
class AppService:
def archive_app(self, app_id: str, tenant_id: str) -> None:
app = self.session.execute(
select(App).where(App.id == app_id, App.tenant_id == tenant_id)
).scalar_one()
app.archived = True
self.session.commit()
```
- Good:
```python
# Case A: Existing repository must be reused for all table operations.
class AppService:
def archive_app(self, app_id: str, tenant_id: str) -> None:
app = self.app_repo.get_by_id(app_id=app_id, tenant_id=tenant_id)
app.archived = True
self.app_repo.save(app)
# If the query is missing, extend the existing abstraction.
active_apps = self.app_repo.list_active_for_tenant(tenant_id=tenant_id)
```
- Bad:
```python
# No repository exists, but large-domain query logic is scattered in service code.
class ConversationService:
def list_recent_for_app(self, app_id: str, tenant_id: str, limit: int) -> list[Conversation]:
...
# many filters/joins/pagination variants duplicated across services
```
- Good:
```python
# Case B: Introduce repository for large/complex domains or storage variation.
class ConversationRepository(Protocol):
def list_recent_for_app(self, app_id: str, tenant_id: str, limit: int) -> list[Conversation]: ...
class SqlAlchemyConversationRepository:
def list_recent_for_app(self, app_id: str, tenant_id: str, limit: int) -> list[Conversation]:
...
class ConversationService:
def __init__(self, conversation_repo: ConversationRepository):
self.conversation_repo = conversation_repo
```
================================================
FILE: .agents/skills/backend-code-review/references/sqlalchemy-rule.md
================================================
# Rule Catalog — SQLAlchemy Patterns
## Scope
- Covers: SQLAlchemy session and transaction lifecycle, query construction, tenant scoping, raw SQL boundaries, and write-path concurrency safeguards.
- Does NOT cover: table/model schema and migration design details (handled by `db-schema-rule.md`).
## Rules
### Use Session context manager with explicit transaction control behavior
- Category: best practices
- Severity: critical
- Description: Session and transaction lifecycle must be explicit and bounded on write paths. Missing commits can silently drop intended updates, while ad-hoc or long-lived transactions increase contention, lock duration, and deadlock risk.
- Suggested fix:
- Use **explicit `session.commit()`** after completing a related write unit.
- Or use **`session.begin()` context manager** for automatic commit/rollback on a scoped block.
- Keep transaction windows short: avoid network I/O, heavy computation, or unrelated work inside the transaction.
- Example:
- Bad:
```python
# Missing commit: write may never be persisted.
with Session(db.engine, expire_on_commit=False) as session:
run = session.get(WorkflowRun, run_id)
run.status = "cancelled"
# Long transaction: external I/O inside a DB transaction.
with Session(db.engine, expire_on_commit=False) as session, session.begin():
run = session.get(WorkflowRun, run_id)
run.status = "cancelled"
call_external_api()
```
- Good:
```python
# Option 1: explicit commit.
with Session(db.engine, expire_on_commit=False) as session:
run = session.get(WorkflowRun, run_id)
run.status = "cancelled"
session.commit()
# Option 2: scoped transaction with automatic commit/rollback.
with Session(db.engine, expire_on_commit=False) as session, session.begin():
run = session.get(WorkflowRun, run_id)
run.status = "cancelled"
# Keep non-DB work outside transaction scope.
call_external_api()
```
### Enforce tenant_id scoping on shared-resource queries
- Category: security
- Severity: critical
- Description: Reads and writes against shared tables must be scoped by `tenant_id` to prevent cross-tenant data leakage or corruption.
- Suggested fix: Add `tenant_id` predicate to all tenant-owned entity queries and propagate tenant context through service/repository interfaces.
- Example:
- Bad:
```python
stmt = select(Workflow).where(Workflow.id == workflow_id)
workflow = session.execute(stmt).scalar_one_or_none()
```
- Good:
```python
stmt = select(Workflow).where(
Workflow.id == workflow_id,
Workflow.tenant_id == tenant_id,
)
workflow = session.execute(stmt).scalar_one_or_none()
```
### Prefer SQLAlchemy expressions over raw SQL by default
- Category: maintainability
- Severity: suggestion
- Description: Raw SQL should be exceptional. ORM/Core expressions are easier to evolve, safer to compose, and more consistent with the codebase.
- Suggested fix: Rewrite straightforward raw SQL into SQLAlchemy `select/update/delete` expressions; keep raw SQL only when required by clear technical constraints.
- Example:
- Bad:
```python
row = session.execute(
text("SELECT * FROM workflows WHERE id = :id AND tenant_id = :tenant_id"),
{"id": workflow_id, "tenant_id": tenant_id},
).first()
```
- Good:
```python
stmt = select(Workflow).where(
Workflow.id == workflow_id,
Workflow.tenant_id == tenant_id,
)
row = session.execute(stmt).scalar_one_or_none()
```
### Protect write paths with concurrency safeguards
- Category: quality
- Severity: critical
- Description: Multi-writer paths without explicit concurrency control can silently overwrite data. Choose the safeguard based on contention level, lock scope, and throughput cost instead of defaulting to one strategy.
- Suggested fix:
- **Optimistic locking**: Use when contention is usually low and retries are acceptable. Add a version (or updated_at) guard in `WHERE` and treat `rowcount == 0` as a conflict.
- **Redis distributed lock**: Use when the critical section spans multiple steps/processes (or includes non-DB side effects) and you need cross-worker mutual exclusion.
- **SELECT ... FOR UPDATE**: Use when contention is high on the same rows and strict in-transaction serialization is required. Keep transactions short to reduce lock wait/deadlock risk.
- In all cases, scope by `tenant_id` and verify affected row counts for conditional writes.
- Example:
- Bad:
```python
# No tenant scope, no conflict detection, and no lock on a contested write path.
session.execute(update(WorkflowRun).where(WorkflowRun.id == run_id).values(status="cancelled"))
session.commit() # silently overwrites concurrent updates
```
- Good:
```python
# 1) Optimistic lock (low contention, retry on conflict)
result = session.execute(
update(WorkflowRun)
.where(
WorkflowRun.id == run_id,
WorkflowRun.tenant_id == tenant_id,
WorkflowRun.version == expected_version,
)
.values(status="cancelled", version=WorkflowRun.version + 1)
)
if result.rowcount == 0:
raise WorkflowStateConflictError("stale version, retry")
# 2) Redis distributed lock (cross-worker critical section)
lock_name = f"workflow_run_lock:{tenant_id}:{run_id}"
with redis_client.lock(lock_name, timeout=20):
session.execute(
update(WorkflowRun)
.where(WorkflowRun.id == run_id, WorkflowRun.tenant_id == tenant_id)
.values(status="cancelled")
)
session.commit()
# 3) Pessimistic lock with SELECT ... FOR UPDATE (high contention)
run = session.execute(
select(WorkflowRun)
.where(WorkflowRun.id == run_id, WorkflowRun.tenant_id == tenant_id)
.with_for_update()
).scalar_one()
run.status = "cancelled"
session.commit()
```
================================================
FILE: .agents/skills/component-refactoring/SKILL.md
================================================
---
name: component-refactoring
description: Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
---
# Dify Component Refactoring Skill
Refactor high-complexity React components in the Dify frontend codebase with the patterns and workflow below.
> **Complexity Threshold**: Components with complexity > 50 (measured by `pnpm analyze-component`) should be refactored before testing.
## Quick Reference
### Commands (run from `web/`)
Use paths relative to `web/` (e.g., `app/components/...`).
Use `refactor-component` for refactoring prompts and `analyze-component` for testing prompts and metrics.
```bash
cd web
# Generate refactoring prompt
pnpm refactor-component <path>
# Output refactoring analysis as JSON
pnpm refactor-component <path> --json
# Generate testing prompt (after refactoring)
pnpm analyze-component <path>
# Output testing analysis as JSON
pnpm analyze-component <path> --json
```
### Complexity Analysis
```bash
# Analyze component complexity
pnpm analyze-component <path> --json
# Key metrics to check:
# - complexity: normalized score 0-100 (target < 50)
# - maxComplexity: highest single function complexity
# - lineCount: total lines (target < 300)
```
### Complexity Score Interpretation
| Score | Level | Action |
|-------|-------|--------|
| 0-25 | 🟢 Simple | Ready for testing |
| 26-50 | 🟡 Medium | Consider minor refactoring |
| 51-75 | 🟠 Complex | **Refactor before testing** |
| 76-100 | 🔴 Very Complex | **Must refactor** |
## Core Refactoring Patterns
### Pattern 1: Extract Custom Hooks
**When**: Component has complex state management, multiple `useState`/`useEffect`, or business logic mixed with UI.
**Dify Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-<feature>.ts`.
```typescript
// ❌ Before: Complex state logic in component
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// 50+ lines of state management logic...
return <div>...</div>
}
// ✅ After: Extract to custom hook
// hooks/use-model-config.ts
export const useModelConfig = (appId: string) => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// Related state management logic here
return { modelConfig, setModelConfig, completionParams, setCompletionParams }
}
// Component becomes cleaner
const Configuration: FC = () => {
const { modelConfig, setModelConfig } = useModelConfig(appId)
return <div>...</div>
}
```
**Dify Examples**:
- `web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts`
- `web/app/components/app/configuration/debug/hooks.tsx`
- `web/app/components/workflow/hooks/use-workflow.ts`
### Pattern 2: Extract Sub-Components
**When**: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
**Dify Convention**: Place sub-components in subdirectories or as separate files in the same directory.
```typescript
// ❌ Before: Monolithic JSX with multiple sections
const AppInfo = () => {
return (
<div>
{/* 100 lines of header UI */}
{/* 100 lines of operations UI */}
{/* 100 lines of modals */}
</div>
)
}
// ✅ After: Split into focused components
// app-info/
// ├── index.tsx (orchestration only)
// ├── app-header.tsx (header UI)
// ├── app-operations.tsx (operations UI)
// └── app-modals.tsx (modal management)
const AppInfo = () => {
const { showModal, setShowModal } = useAppInfoModals()
return (
<div>
<AppHeader appDetail={appDetail} />
<AppOperations onAction={handleAction} />
<AppModals show={showModal} onClose={() => setShowModal(null)} />
</div>
)
}
```
**Dify Examples**:
- `web/app/components/app/configuration/` directory structure
- `web/app/components/workflow/nodes/` per-node organization
### Pattern 3: Simplify Conditional Logic
**When**: Deep nesting (> 3 levels), complex ternaries, or multiple `if/else` chains.
```typescript
// ❌ Before: Deeply nested conditionals
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh />
case LanguagesSupported[7]:
return <TemplateChatJa />
default:
return <TemplateChatEn />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
// Another 15 lines...
}
// More conditions...
}, [appDetail, locale])
// ✅ After: Use lookup tables + early returns
const TEMPLATE_MAP = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
// ...
},
}
const Template = useMemo(() => {
const modeTemplates = TEMPLATE_MAP[appDetail?.mode]
if (!modeTemplates) return null
const TemplateComponent = modeTemplates[locale] || modeTemplates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])
```
### Pattern 4: Extract API/Data Logic
**When**: Component directly handles API calls, data transformation, or complex async operations.
**Dify Convention**:
- This skill is for component decomposition, not query/mutation design.
- When refactoring data fetching, follow `web/AGENTS.md`.
- Use `frontend-query-mutation` for contracts, query shape, data-fetching wrappers, query/mutation call-site patterns, conditional queries, invalidation, and mutation error handling.
- Do not introduce deprecated `useInvalid` / `useReset`.
- Do not add thin passthrough `useQuery` wrappers during refactoring; only extract a custom hook when it truly orchestrates multiple queries/mutations or shared derived state.
**Dify Examples**:
- `web/service/use-workflow.ts`
- `web/service/use-common.ts`
- `web/service/knowledge/use-dataset.ts`
- `web/service/knowledge/use-document.ts`
### Pattern 5: Extract Modal/Dialog Management
**When**: Component manages multiple modals with complex open/close states.
**Dify Convention**: Modals should be extracted with their state management.
```typescript
// ❌ Before: Multiple modal states in component
const AppInfo = () => {
const [showEditModal, setShowEditModal] = useState(false)
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
const [showSwitchModal, setShowSwitchModal] = useState(false)
const [showImportDSLModal, setShowImportDSLModal] = useState(false)
// 5+ more modal states...
}
// ✅ After: Extract to modal management hook
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null
const useAppInfoModals = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
const closeModal = useCallback(() => setActiveModal(null), [])
return {
activeModal,
openModal,
closeModal,
isOpen: (type: ModalType) => activeModal === type,
}
}
```
### Pattern 6: Extract Form Logic
**When**: Complex form validation, submission handling, or field transformation.
**Dify Convention**: Use `@tanstack/react-form` patterns from `web/app/components/base/form/`.
```typescript
// ✅ Use existing form infrastructure
import { useAppForm } from '@/app/components/base/form'
const ConfigForm = () => {
const form = useAppForm({
defaultValues: { name: '', description: '' },
onSubmit: handleSubmit,
})
return <form.Provider>...</form.Provider>
}
```
## Dify-Specific Refactoring Guidelines
### 1. Context Provider Extraction
**When**: Component provides complex context values with multiple states.
```typescript
// ❌ Before: Large context value object
const value = {
appId, isAPIKeySet, isTrailFinished, mode, modelModeType,
promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,
// 50+ more properties...
}
return <ConfigContext.Provider value={value}>...</ConfigContext.Provider>
// ✅ After: Split into domain-specific contexts
<ModelConfigProvider value={modelConfigValue}>
<DatasetConfigProvider value={datasetConfigValue}>
<UIConfigProvider value={uiConfigValue}>
{children}
</UIConfigProvider>
</DatasetConfigProvider>
</ModelConfigProvider>
```
**Dify Reference**: `web/context/` directory structure
### 2. Workflow Node Components
**When**: Refactoring workflow node components (`web/app/components/workflow/nodes/`).
**Conventions**:
- Keep node logic in `use-interactions.ts`
- Extract panel UI to separate files
- Use `_base` components for common patterns
```
nodes/<node-type>/
├── index.tsx # Node registration
├── node.tsx # Node visual component
├── panel.tsx # Configuration panel
├── use-interactions.ts # Node-specific hooks
└── types.ts # Type definitions
```
### 3. Configuration Components
**When**: Refactoring app configuration components.
**Conventions**:
- Separate config sections into subdirectories
- Use existing patterns from `web/app/components/app/configuration/`
- Keep feature toggles in dedicated components
### 4. Tool/Plugin Components
**When**: Refactoring tool-related components (`web/app/components/tools/`).
**Conventions**:
- Follow existing modal patterns
- Use service hooks from `web/service/use-tools.ts`
- Keep provider-specific logic isolated
## Refactoring Workflow
### Step 1: Generate Refactoring Prompt
```bash
pnpm refactor-component <path>
```
This command will:
- Analyze component complexity and features
- Identify specific refactoring actions needed
- Generate a prompt for AI assistant (auto-copied to clipboard on macOS)
- Provide detailed requirements based on detected patterns
### Step 2: Analyze Details
```bash
pnpm analyze-component <path> --json
```
Identify:
- Total complexity score
- Max function complexity
- Line count
- Features detected (state, effects, API, etc.)
### Step 3: Plan
Create a refactoring plan based on detected features:
| Detected Feature | Refactoring Action |
|------------------|-------------------|
| `hasState: true` + `hasEffects: true` | Extract custom hook |
| `hasAPI: true` | Extract data/service hook |
| `hasEvents: true` (many) | Extract event handlers |
| `lineCount > 300` | Split into sub-components |
| `maxComplexity > 50` | Simplify conditional logic |
### Step 4: Execute Incrementally
1. **Extract one piece at a time**
2. **Run lint, type-check, and tests after each extraction**
3. **Verify functionality before next step**
```
For each extraction:
┌────────────────────────────────────────┐
│ 1. Extract code │
│ 2. Run: pnpm lint:fix │
│ 3. Run: pnpm type-check:tsgo │
│ 4. Run: pnpm test │
│ 5. Test functionality manually │
│ 6. PASS? → Next extraction │
│ FAIL? → Fix before continuing │
└────────────────────────────────────────┘
```
### Step 5: Verify
After refactoring:
```bash
# Re-run refactor command to verify improvements
pnpm refactor-component <path>
# If complexity < 25 and lines < 200, you'll see:
# ✅ COMPONENT IS WELL-STRUCTURED
# For detailed metrics:
pnpm analyze-component <path> --json
# Target metrics:
# - complexity < 50
# - lineCount < 300
# - maxComplexity < 30
```
## Common Mistakes to Avoid
### ❌ Over-Engineering
```typescript
// ❌ Too many tiny hooks
const useButtonText = () => useState('Click')
const useButtonDisabled = () => useState(false)
const useButtonLoading = () => useState(false)
// ✅ Cohesive hook with related state
const useButtonState = () => {
const [text, setText] = useState('Click')
const [disabled, setDisabled] = useState(false)
const [loading, setLoading] = useState(false)
return { text, setText, disabled, setDisabled, loading, setLoading }
}
```
### ❌ Breaking Existing Patterns
- Follow existing directory structures
- Maintain naming conventions
- Preserve export patterns for compatibility
### ❌ Premature Abstraction
- Only extract when there's clear complexity benefit
- Don't create abstractions for single-use code
- Keep refactored code in the same domain area
## References
### Dify Codebase Examples
- **Hook extraction**: `web/app/components/app/configuration/hooks/`
- **Component splitting**: `web/app/components/app/configuration/`
- **Service hooks**: `web/service/use-*.ts`
- **Workflow patterns**: `web/app/components/workflow/hooks/`
- **Form patterns**: `web/app/components/base/form/`
### Related Skills
- `frontend-testing` - For testing refactored components
- `web/docs/test.md` - Testing specification
================================================
FILE: .agents/skills/component-refactoring/references/complexity-patterns.md
================================================
# Complexity Reduction Patterns
This document provides patterns for reducing cognitive complexity in Dify React components.
## Understanding Complexity
### SonarJS Cognitive Complexity
The `pnpm analyze-component` tool uses SonarJS cognitive complexity metrics:
- **Total Complexity**: Sum of all functions' complexity in the file
- **Max Complexity**: Highest single function complexity
### What Increases Complexity
| Pattern | Complexity Impact |
|---------|-------------------|
| `if/else` | +1 per branch |
| Nested conditions | +1 per nesting level |
| `switch/case` | +1 per case |
| `for/while/do` | +1 per loop |
| `&&`/`||` chains | +1 per operator |
| Nested callbacks | +1 per nesting level |
| `try/catch` | +1 per catch |
| Ternary expressions | +1 per nesting |
## Pattern 1: Replace Conditionals with Lookup Tables
**Before** (complexity: ~15):
```typescript
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh appDetail={appDetail} />
case LanguagesSupported[7]:
return <TemplateChatJa appDetail={appDetail} />
default:
return <TemplateChatEn appDetail={appDetail} />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateAdvancedChatZh appDetail={appDetail} />
case LanguagesSupported[7]:
return <TemplateAdvancedChatJa appDetail={appDetail} />
default:
return <TemplateAdvancedChatEn appDetail={appDetail} />
}
}
if (appDetail?.mode === AppModeEnum.WORKFLOW) {
// Similar pattern...
}
return null
}, [appDetail, locale])
```
**After** (complexity: ~3):
```typescript
// Define lookup table outside component
const TEMPLATE_MAP: Record<AppModeEnum, Record<string, FC<TemplateProps>>> = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
[LanguagesSupported[7]]: TemplateAdvancedChatJa,
default: TemplateAdvancedChatEn,
},
[AppModeEnum.WORKFLOW]: {
[LanguagesSupported[1]]: TemplateWorkflowZh,
[LanguagesSupported[7]]: TemplateWorkflowJa,
default: TemplateWorkflowEn,
},
// ...
}
// Clean component logic
const Template = useMemo(() => {
if (!appDetail?.mode) return null
const templates = TEMPLATE_MAP[appDetail.mode]
if (!templates) return null
const TemplateComponent = templates[locale] ?? templates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])
```
## Pattern 2: Use Early Returns
**Before** (complexity: ~10):
```typescript
const handleSubmit = () => {
if (isValid) {
if (hasChanges) {
if (isConnected) {
submitData()
} else {
showConnectionError()
}
} else {
showNoChangesMessage()
}
} else {
showValidationError()
}
}
```
**After** (complexity: ~4):
```typescript
const handleSubmit = () => {
if (!isValid) {
showValidationError()
return
}
if (!hasChanges) {
showNoChangesMessage()
return
}
if (!isConnected) {
showConnectionError()
return
}
submitData()
}
```
## Pattern 3: Extract Complex Conditions
**Before** (complexity: high):
```typescript
const canPublish = (() => {
if (mode !== AppModeEnum.COMPLETION) {
if (!isAdvancedMode)
return true
if (modelModeType === ModelModeType.completion) {
if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
return false
return true
}
return true
}
return !promptEmpty
})()
```
**After** (complexity: lower):
```typescript
// Extract to named functions
const canPublishInCompletionMode = () => !promptEmpty
const canPublishInChatMode = () => {
if (!isAdvancedMode) return true
if (modelModeType !== ModelModeType.completion) return true
return hasSetBlockStatus.history && hasSetBlockStatus.query
}
// Clean main logic
const canPublish = mode === AppModeEnum.COMPLETION
? canPublishInCompletionMode()
: canPublishInChatMode()
```
## Pattern 4: Replace Chained Ternaries
**Before** (complexity: ~5):
```typescript
const statusText = serverActivated
? t('status.running')
: serverPublished
? t('status.inactive')
: appUnpublished
? t('status.unpublished')
: t('status.notConfigured')
```
**After** (complexity: ~2):
```typescript
const getStatusText = () => {
if (serverActivated) return t('status.running')
if (serverPublished) return t('status.inactive')
if (appUnpublished) return t('status.unpublished')
return t('status.notConfigured')
}
const statusText = getStatusText()
```
Or use lookup:
```typescript
const STATUS_TEXT_MAP = {
running: 'status.running',
inactive: 'status.inactive',
unpublished: 'status.unpublished',
notConfigured: 'status.notConfigured',
} as const
const getStatusKey = (): keyof typeof STATUS_TEXT_MAP => {
if (serverActivated) return 'running'
if (serverPublished) return 'inactive'
if (appUnpublished) return 'unpublished'
return 'notConfigured'
}
const statusText = t(STATUS_TEXT_MAP[getStatusKey()])
```
## Pattern 5: Flatten Nested Loops
**Before** (complexity: high):
```typescript
const processData = (items: Item[]) => {
const results: ProcessedItem[] = []
for (const item of items) {
if (item.isValid) {
for (const child of item.children) {
if (child.isActive) {
for (const prop of child.properties) {
if (prop.value !== null) {
results.push({
itemId: item.id,
childId: child.id,
propValue: prop.value,
})
}
}
}
}
}
}
return results
}
```
**After** (complexity: lower):
```typescript
// Use functional approach
const processData = (items: Item[]) => {
return items
.filter(item => item.isValid)
.flatMap(item =>
item.children
.filter(child => child.isActive)
.flatMap(child =>
child.properties
.filter(prop => prop.value !== null)
.map(prop => ({
itemId: item.id,
childId: child.id,
propValue: prop.value,
}))
)
)
}
```
## Pattern 6: Extract Event Handler Logic
**Before** (complexity: high in component):
```typescript
const Component = () => {
const handleSelect = (data: DataSet[]) => {
if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
hideSelectDataSet()
return
}
formattingChangedDispatcher()
let newDatasets = data
if (data.find(item => !item.name)) {
const newSelected = produce(data, (draft) => {
data.forEach((item, index) => {
if (!item.name) {
const newItem = dataSets.find(i => i.id === item.id)
if (newItem)
draft[index] = newItem
}
})
})
setDataSets(newSelected)
newDatasets = newSelected
}
else {
setDataSets(data)
}
hideSelectDataSet()
// 40 more lines of logic...
}
return <div>...</div>
}
```
**After** (complexity: lower):
```typescript
// Extract to hook or utility
const useDatasetSelection = (dataSets: DataSet[], setDataSets: SetState<DataSet[]>) => {
const normalizeSelection = (data: DataSet[]) => {
const hasUnloadedItem = data.some(item => !item.name)
if (!hasUnloadedItem) return data
return produce(data, (draft) => {
data.forEach((item, index) => {
if (!item.name) {
const existing = dataSets.find(i => i.id === item.id)
if (existing) draft[index] = existing
}
})
})
}
const hasSelectionChanged = (newData: DataSet[]) => {
return !isEqual(
newData.map(item => item.id),
dataSets.map(item => item.id)
)
}
return { normalizeSelection, hasSelectionChanged }
}
// Component becomes cleaner
const Component = () => {
const { normalizeSelection, hasSelectionChanged } = useDatasetSelection(dataSets, setDataSets)
const handleSelect = (data: DataSet[]) => {
if (!hasSelectionChanged(data)) {
hideSelectDataSet()
return
}
formattingChangedDispatcher()
const normalized = normalizeSelection(data)
setDataSets(normalized)
hideSelectDataSet()
}
return <div>...</div>
}
```
## Pattern 7: Reduce Boolean Logic Complexity
**Before** (complexity: ~8):
```typescript
const toggleDisabled = hasInsufficientPermissions
|| appUnpublished
|| missingStartNode
|| triggerModeDisabled
|| (isAdvancedApp && !currentWorkflow?.graph)
|| (isBasicApp && !basicAppConfig.updated_at)
```
**After** (complexity: ~3):
```typescript
// Extract meaningful boolean functions
const isAppReady = () => {
if (isAdvancedApp) return !!currentWorkflow?.graph
return !!basicAppConfig.updated_at
}
const hasRequiredPermissions = () => {
return isCurrentWorkspaceEditor && !hasInsufficientPermissions
}
const canToggle = () => {
if (!hasRequiredPermissions()) return false
if (!isAppReady()) return false
if (missingStartNode) return false
if (triggerModeDisabled) return false
return true
}
const toggleDisabled = !canToggle()
```
## Pattern 8: Simplify useMemo/useCallback Dependencies
**Before** (complexity: multiple recalculations):
```typescript
const payload = useMemo(() => {
let parameters: Parameter[] = []
let outputParameters: OutputParameter[] = []
if (!published) {
parameters = (inputs || []).map((item) => ({
name: item.variable,
description: '',
form: 'llm',
required: item.required,
type: item.type,
}))
outputParameters = (outputs || []).map((item) => ({
name: item.variable,
description: '',
type: item.value_type,
}))
}
else if (detail && detail.tool) {
parameters = (inputs || []).map((item) => ({
// Complex transformation...
}))
outputParameters = (outputs || []).map((item) => ({
// Complex transformation...
}))
}
return {
icon: detail?.icon || icon,
label: detail?.label || name,
// ...more fields
}
}, [detail, published, workflowAppId, icon, name, description, inputs, outputs])
```
**After** (complexity: separated concerns):
```typescript
// Separate transformations
const useParameterTransform = (inputs: InputVar[], detail?: ToolDetail, published?: boolean) => {
return useMemo(() => {
if (!published) {
return inputs.map(item => ({
name: item.variable,
description: '',
form: 'llm',
required: item.required,
type: item.type,
}))
}
if (!detail?.tool) return []
return inputs.map(item => ({
name: item.variable,
required: item.required,
type: item.type === 'paragraph' ? 'string' : item.type,
description: detail.tool.parameters.find(p => p.name === item.variable)?.llm_description || '',
form: detail.tool.parameters.find(p => p.name === item.variable)?.form || 'llm',
}))
}, [inputs, detail, published])
}
// Component uses hook
const parameters = useParameterTransform(inputs, detail, published)
const outputParameters = useOutputTransform(outputs, detail, published)
const payload = useMemo(() => ({
icon: detail?.icon || icon,
label: detail?.label || name,
parameters,
outputParameters,
// ...
}), [detail, icon, name, parameters, outputParameters])
```
## Target Metrics After Refactoring
| Metric | Target |
|--------|--------|
| Total Complexity | < 50 |
| Max Function Complexity | < 30 |
| Function Length | < 30 lines |
| Nesting Depth | ≤ 3 levels |
| Conditional Chains | ≤ 3 conditions |
================================================
FILE: .agents/skills/component-refactoring/references/component-splitting.md
================================================
# Component Splitting Patterns
This document provides detailed guidance on splitting large components into smaller, focused components in Dify.
## When to Split Components
Split a component when you identify:
1. **Multiple UI sections** - Distinct visual areas with minimal coupling that can be composed independently
1. **Conditional rendering blocks** - Large `{condition && <JSX />}` blocks
1. **Repeated patterns** - Similar UI structures used multiple times
1. **300+ lines** - Component exceeds manageable size
1. **Modal clusters** - Multiple modals rendered in one component
## Splitting Strategies
### Strategy 1: Section-Based Splitting
Identify visual sections and extract each as a component.
```typescript
// ❌ Before: Monolithic component (500+ lines)
const ConfigurationPage = () => {
return (
<div>
{/* Header Section - 50 lines */}
<div className="header">
<h1>{t('configuration.title')}</h1>
<div className="actions">
{isAdvancedMode && <Badge>Advanced</Badge>}
<ModelParameterModal ... />
<AppPublisher ... />
</div>
</div>
{/* Config Section - 200 lines */}
<div className="config">
<Config />
</div>
{/* Debug Section - 150 lines */}
<div className="debug">
<Debug ... />
</div>
{/* Modals Section - 100 lines */}
{showSelectDataSet && <SelectDataSet ... />}
{showHistoryModal && <EditHistoryModal ... />}
{showUseGPT4Confirm && <Confirm ... />}
</div>
)
}
// ✅ After: Split into focused components
// configuration/
// ├── index.tsx (orchestration)
// ├── configuration-header.tsx
// ├── configuration-content.tsx
// ├── configuration-debug.tsx
// └── configuration-modals.tsx
// configuration-header.tsx
interface ConfigurationHeaderProps {
isAdvancedMode: boolean
onPublish: () => void
}
const ConfigurationHeader: FC<ConfigurationHeaderProps> = ({
isAdvancedMode,
onPublish,
}) => {
const { t } = useTranslation()
return (
<div className="header">
<h1>{t('configuration.title')}</h1>
<div className="actions">
{isAdvancedMode && <Badge>Advanced</Badge>}
<ModelParameterModal ... />
<AppPublisher onPublish={onPublish} />
</div>
</div>
)
}
// index.tsx (orchestration only)
const ConfigurationPage = () => {
const { modelConfig, setModelConfig } = useModelConfig()
const { activeModal, openModal, closeModal } = useModalState()
return (
<div>
<ConfigurationHeader
isAdvancedMode={isAdvancedMode}
onPublish={handlePublish}
/>
<ConfigurationContent
modelConfig={modelConfig}
onConfigChange={setModelConfig}
/>
{!isMobile && (
<ConfigurationDebug
inputs={inputs}
onSetting={handleSetting}
/>
)}
<ConfigurationModals
activeModal={activeModal}
onClose={closeModal}
/>
</div>
)
}
```
### Strategy 2: Conditional Block Extraction
Extract large conditional rendering blocks.
```typescript
// ❌ Before: Large conditional blocks
const AppInfo = () => {
return (
<div>
{expand ? (
<div className="expanded">
{/* 100 lines of expanded view */}
</div>
) : (
<div className="collapsed">
{/* 50 lines of collapsed view */}
</div>
)}
</div>
)
}
// ✅ After: Separate view components
const AppInfoExpanded: FC<AppInfoViewProps> = ({ appDetail, onAction }) => {
return (
<div className="expanded">
{/* Clean, focused expanded view */}
</div>
)
}
const AppInfoCollapsed: FC<AppInfoViewProps> = ({ appDetail, onAction }) => {
return (
<div className="collapsed">
{/* Clean, focused collapsed view */}
</div>
)
}
const AppInfo = () => {
return (
<div>
{expand
? <AppInfoExpanded appDetail={appDetail} onAction={handleAction} />
: <AppInfoCollapsed appDetail={appDetail} onAction={handleAction} />
}
</div>
)
}
```
### Strategy 3: Modal Extraction
Extract modals with their trigger logic.
```typescript
// ❌ Before: Multiple modals in one component
const AppInfo = () => {
const [showEdit, setShowEdit] = useState(false)
const [showDuplicate, setShowDuplicate] = useState(false)
const [showDelete, setShowDelete] = useState(false)
const [showSwitch, setShowSwitch] = useState(false)
const onEdit = async (data) => { /* 20 lines */ }
const onDuplicate = async (data) => { /* 20 lines */ }
const onDelete = async () => { /* 15 lines */ }
return (
<div>
{/* Main content */}
{showEdit && <EditModal onConfirm={onEdit} onClose={() => setShowEdit(false)} />}
{showDuplicate && <DuplicateModal onConfirm={onDuplicate} onClose={() => setShowDuplicate(false)} />}
{showDelete && <DeleteConfirm onConfirm={onDelete} onClose={() => setShowDelete(false)} />}
{showSwitch && <SwitchModal ... />}
</div>
)
}
// ✅ After: Modal manager component
// app-info-modals.tsx
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | null
interface AppInfoModalsProps {
appDetail: AppDetail
activeModal: ModalType
onClose: () => void
onSuccess: () => void
}
const AppInfoModals: FC<AppInfoModalsProps> = ({
appDetail,
activeModal,
onClose,
onSuccess,
}) => {
const handleEdit = async (data) => { /* logic */ }
const handleDuplicate = async (data) => { /* logic */ }
const handleDelete = async () => { /* logic */ }
return (
<>
{activeModal === 'edit' && (
<EditModal
appDetail={appDetail}
onConfirm={handleEdit}
onClose={onClose}
/>
)}
{activeModal === 'duplicate' && (
<DuplicateModal
appDetail={appDetail}
onConfirm={handleDuplicate}
onClose={onClose}
/>
)}
{activeModal === 'delete' && (
<DeleteConfirm
onConfirm={handleDelete}
onClose={onClose}
/>
)}
{activeModal === 'switch' && (
<SwitchModal
appDetail={appDetail}
onClose={onClose}
/>
)}
</>
)
}
// Parent component
const AppInfo = () => {
const { activeModal, openModal, closeModal } = useModalState()
return (
<div>
{/* Main content with openModal triggers */}
<Button onClick={() => openModal('edit')}>Edit</Button>
<AppInfoModals
appDetail={appDetail}
activeModal={activeModal}
onClose={closeModal}
onSuccess={handleSuccess}
/>
</div>
)
}
```
### Strategy 4: List Item Extraction
Extract repeated item rendering.
```typescript
// ❌ Before: Inline item rendering
const OperationsList = () => {
return (
<div>
{operations.map(op => (
<div key={op.id} className="operation-item">
<span className="icon">{op.icon}</span>
<span className="title">{op.title}</span>
<span className="description">{op.description}</span>
<button onClick={() => op.onClick()}>
{op.actionLabel}
</button>
{op.badge && <Badge>{op.badge}</Badge>}
{/* More complex rendering... */}
</div>
))}
</div>
)
}
// ✅ After: Extracted item component
interface OperationItemProps {
operation: Operation
onAction: (id: string) => void
}
const OperationItem: FC<OperationItemProps> = ({ operation, onAction }) => {
return (
<div className="operation-item">
<span className="icon">{operation.icon}</span>
<span className="title">{operation.title}</span>
<span className="description">{operation.description}</span>
<button onClick={() => onAction(operation.id)}>
{operation.actionLabel}
</button>
{operation.badge && <Badge>{operation.badge}</Badge>}
</div>
)
}
const OperationsList = () => {
const handleAction = useCallback((id: string) => {
const op = operations.find(o => o.id === id)
op?.onClick()
}, [operations])
return (
<div>
{operations.map(op => (
<OperationItem
key={op.id}
operation={op}
onAction={handleAction}
/>
))}
</div>
)
}
```
## Directory Structure Patterns
### Pattern A: Flat Structure (Simple Components)
For components with 2-3 sub-components:
```
component-name/
├── index.tsx # Main component
├── sub-component-a.tsx
├── sub-component-b.tsx
└── types.ts # Shared types
```
### Pattern B: Nested Structure (Complex Components)
For components with many sub-components:
```
component-name/
├── index.tsx # Main orchestration
├── types.ts # Shared types
├── hooks/
│ ├── use-feature-a.ts
│ └── use-feature-b.ts
├── components/
│ ├── header/
│ │ └── index.tsx
│ ├── content/
│ │ └── index.tsx
│ └── modals/
│ └── index.tsx
└── utils/
└── helpers.ts
```
### Pattern C: Feature-Based Structure (Dify Standard)
Following Dify's existing patterns:
```
configuration/
├── index.tsx # Main page component
├── base/ # Base/shared components
│ ├── feature-panel/
│ ├── group-name/
│ └── operation-btn/
├── config/ # Config section
│ ├── index.tsx
│ ├── agent/
│ └── automatic/
├── dataset-config/ # Dataset section
│ ├── index.tsx
│ ├── card-item/
│ └── params-config/
├── debug/ # Debug section
│ ├── index.tsx
│ └── hooks.tsx
└── hooks/ # Shared hooks
└── use-advanced-prompt-config.ts
```
## Props Design
### Minimal Props Principle
Pass only what's needed:
```typescript
// ❌ Bad: Passing entire objects when only some fields needed
<ConfigHeader appDetail={appDetail} modelConfig={modelConfig} />
// ✅ Good: Destructure to minimum required
<ConfigHeader
appName={appDetail.name}
isAdvancedMode={modelConfig.isAdvanced}
onPublish={handlePublish}
/>
```
### Callback Props Pattern
Use callbacks for child-to-parent communication:
```typescript
// Parent
const Parent = () => {
const [value, setValue] = useState('')
return (
<Child
value={value}
onChange={setValue}
onSubmit={handleSubmit}
/>
)
}
// Child
interface ChildProps {
value: string
onChange: (value: string) => void
onSubmit: () => void
}
const Child: FC<ChildProps> = ({ value, onChange, onSubmit }) => {
return (
<div>
<input value={value} onChange={e => onChange(e.target.value)} />
<button onClick={onSubmit}>Submit</button>
</div>
)
}
```
### Render Props for Flexibility
When sub-components need parent context:
```typescript
interface ListProps<T> {
items: T[]
renderItem: (item: T, index: number) => React.ReactNode
renderEmpty?: () => React.ReactNode
}
function List<T>({ items, renderItem, renderEmpty }: ListProps<T>) {
if (items.length === 0 && renderEmpty) {
return <>{renderEmpty()}</>
}
return (
<div>
{items.map((item, index) => renderItem(item, index))}
</div>
)
}
// Usage
<List
items={operations}
renderItem={(op, i) => <OperationItem key={i} operation={op} />}
renderEmpty={() => <EmptyState message="No operations" />}
/>
```
================================================
FILE: .agents/skills/component-refactoring/references/hook-extraction.md
================================================
# Hook Extraction Patterns
This document provides detailed guidance on extracting custom hooks from complex components in Dify.
## When to Extract Hooks
Extract a custom hook when you identify:
1. **Coupled state groups** - Multiple `useState` hooks that are always used together
1. **Complex effects** - `useEffect` with multiple dependencies or cleanup logic
1. **Business logic** - Data transformations, validations, or calculations
1. **Reusable patterns** - Logic that appears in multiple components
## Extraction Process
### Step 1: Identify State Groups
Look for state variables that are logically related:
```typescript
// ❌ These belong together - extract to hook
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
const [modelModeType, setModelModeType] = useState<ModelModeType>(...)
// These are model-related state that should be in useModelConfig()
```
### Step 2: Identify Related Effects
Find effects that modify the grouped state:
```typescript
// ❌ These effects belong with the state above
useEffect(() => {
if (hasFetchedDetail && !modelModeType) {
const mode = currModel?.model_properties.mode
if (mode) {
const newModelConfig = produce(modelConfig, (draft) => {
draft.mode = mode
})
setModelConfig(newModelConfig)
}
}
}, [textGenerationModelList, hasFetchedDetail, modelModeType, currModel])
```
### Step 3: Create the Hook
```typescript
// hooks/use-model-config.ts
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { ModelConfig } from '@/models/debug'
import { produce } from 'immer'
import { useEffect, useState } from 'react'
import { ModelModeType } from '@/types/app'
interface UseModelConfigParams {
initialConfig?: Partial<ModelConfig>
currModel?: { model_properties?: { mode?: ModelModeType } }
hasFetchedDetail: boolean
}
interface UseModelConfigReturn {
modelConfig: ModelConfig
setModelConfig: (config: ModelConfig) => void
completionParams: FormValue
setCompletionParams: (params: FormValue) => void
modelModeType: ModelModeType
}
export const useModelConfig = ({
initialConfig,
currModel,
hasFetchedDetail,
}: UseModelConfigParams): UseModelConfigReturn => {
const [modelConfig, setModelConfig] = useState<ModelConfig>({
provider: 'langgenius/openai/openai',
model_id: 'gpt-3.5-turbo',
mode: ModelModeType.unset,
// ... default values
...initialConfig,
})
const [completionParams, setCompletionParams] = useState<FormValue>({})
const modelModeType = modelConfig.mode
// Fill old app data missing model mode
useEffect(() => {
if (hasFetchedDetail && !modelModeType) {
const mode = currModel?.model_properties?.mode
if (mode) {
setModelConfig(produce(modelConfig, (draft) => {
draft.mode = mode
}))
}
}
}, [hasFetchedDetail, modelModeType, currModel])
return {
modelConfig,
setModelConfig,
completionParams,
setCompletionParams,
modelModeType,
}
}
```
### Step 4: Update Component
```typescript
// Before: 50+ lines of state management
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
// ... lots of related state and effects
}
// After: Clean component
const Configuration: FC = () => {
const {
modelConfig,
setModelConfig,
completionParams,
setCompletionParams,
modelModeType,
} = useModelConfig({
currModel,
hasFetchedDetail,
})
// Component now focuses on UI
}
```
## Naming Conventions
### Hook Names
- Use `use` prefix: `useModelConfig`, `useDatasetConfig`
- Be specific: `useAdvancedPromptConfig` not `usePrompt`
- Include domain: `useWorkflowVariables`, `useMCPServer`
### File Names
- Kebab-case: `use-model-config.ts`
- Place in `hooks/` subdirectory when multiple hooks exist
- Place alongside component for single-use hooks
### Return Type Names
- Suffix with `Return`: `UseModelConfigReturn`
- Suffix params with `Params`: `UseModelConfigParams`
## Common Hook Patterns in Dify
### 1. Data Fetching / Mutation Hooks
When hook extraction touches query or mutation code, do not use this reference as the source of truth for data-layer patterns.
- Follow `web/AGENTS.md` first.
- Use `frontend-query-mutation` for contracts, query shape, data-fetching wrappers, query/mutation call-site patterns, conditional queries, invalidation, and mutation error handling.
- Do not introduce deprecated `useInvalid` / `useReset`.
- Do not extract thin passthrough `useQuery` hooks; only extract orchestration hooks.
### 2. Form State Hook
```typescript
// Pattern: Form state + validation + submission
export const useConfigForm = (initialValues: ConfigFormValues) => {
const [values, setValues] = useState(initialValues)
const [errors, setErrors] = useState<Record<string, string>>({})
const [isSubmitting, setIsSubmitting] = useState(false)
const validate = useCallback(() => {
const newErrors: Record<string, string> = {}
if (!values.name) newErrors.name = 'Name is required'
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}, [values])
const handleChange = useCallback((field: string, value: any) => {
setValues(prev => ({ ...prev, [field]: value }))
}, [])
const handleSubmit = useCallback(async (onSubmit: (values: ConfigFormValues) => Promise<void>) => {
if (!validate()) return
setIsSubmitting(true)
try {
await onSubmit(values)
} finally {
setIsSubmitting(false)
}
}, [values, validate])
return { values, errors, isSubmitting, handleChange, handleSubmit }
}
```
### 3. Modal State Hook
```typescript
// Pattern: Multiple modal management
type ModalType = 'edit' | 'delete' | 'duplicate' | null
export const useModalState = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const [modalData, setModalData] = useState<any>(null)
const openModal = useCallback((type: ModalType, data?: any) => {
setActiveModal(type)
setModalData(data)
}, [])
const closeModal = useCallback(() => {
setActiveModal(null)
setModalData(null)
}, [])
return {
activeModal,
modalData,
openModal,
closeModal,
isOpen: useCallback((type: ModalType) => activeModal === type, [activeModal]),
}
}
```
### 4. Toggle/Boolean Hook
```typescript
// Pattern: Boolean state with convenience methods
export const useToggle = (initialValue = false) => {
const [value, setValue] = useState(initialValue)
const toggle = useCallback(() => setValue(v => !v), [])
const setTrue = useCallback(() => setValue(true), [])
const setFalse = useCallback(() => setValue(false), [])
return [value, { toggle, setTrue, setFalse, set: setValue }] as const
}
// Usage
const [isExpanded, { toggle, setTrue: expand, setFalse: collapse }] = useToggle()
```
## Testing Extracted Hooks
After extraction, test hooks in isolation:
```typescript
// use-model-config.spec.ts
import { renderHook, act } from '@testing-library/react'
import { useModelConfig } from './use-model-config'
describe('useModelConfig', () => {
it('should initialize with default values', () => {
const { result } = renderHook(() => useModelConfig({
hasFetchedDetail: false,
}))
expect(result.current.modelConfig.provider).toBe('langgenius/openai/openai')
expect(result.current.modelModeType).toBe(ModelModeType.unset)
})
it('should update model config', () => {
const { result } = renderHook(() => useModelConfig({
hasFetchedDetail: true,
}))
act(() => {
result.current.setModelConfig({
...result.current.modelConfig,
model_id: 'gpt-4',
})
})
expect(result.current.modelConfig.model_id).toBe('gpt-4')
})
})
```
================================================
FILE: .agents/skills/frontend-code-review/SKILL.md
================================================
---
name: frontend-code-review
description: "Trigger when the user requests a review of frontend files (e.g., `.tsx`, `.ts`, `.js`). Support both pending-change reviews and focused file reviews while applying the checklist rules."
---
# Frontend Code Review
## Intent
Use this skill whenever the user asks to review frontend code (especially `.tsx`, `.ts`, or `.js` files). Support two review modes:
1. **Pending-change review** – inspect staged/working-tree files slated for commit and flag checklist violations before submission.
2. **File-targeted review** – review the specific file(s) the user names and report the relevant checklist findings.
Stick to the checklist below for every applicable file and mode.
## Checklist
See [references/code-quality.md](references/code-quality.md), [references/performance.md](references/performance.md), [references/business-logic.md](references/business-logic.md) for the living checklist split by category—treat it as the canonical set of rules to follow.
Flag each rule violation with urgency metadata so future reviewers can prioritize fixes.
## Review Process
1. Open the relevant component/module. Gather lines that relate to class names, React Flow hooks, prop memoization, and styling.
2. For each rule in the review point, note where the code deviates and capture a representative snippet.
3. Compose the review section per the template below. Group violations first by **Urgent** flag, then by category order (Code Quality, Performance, Business Logic).
## Required output
When invoked, the response must exactly follow one of the two templates:
### Template A (any findings)
```
# Code review
Found <N> urgent issues need to be fixed:
## 1 <brief description of bug>
FilePath: <path> line <line>
<relevant code snippet or pointer>
### Suggested fix
<brief description of suggested fix>
---
... (repeat for each urgent issue) ...
Found <M> suggestions for improvement:
## 1 <brief description of suggestion>
FilePath: <path> line <line>
<relevant code snippet or pointer>
### Suggested fix
<brief description of suggested fix>
---
... (repeat for each suggestion) ...
```
If there are no urgent issues, omit that section. If there are no suggestions, omit that section.
If the issue number is more than 10, summarize as "10+ urgent issues" or "10+ suggestions" and just output the first 10 issues.
Don't compress the blank lines between sections; keep them as-is for readability.
If you use Template A (i.e., there are issues to fix) and at least one issue requires code changes, append a brief follow-up question after the structured output asking whether the user wants you to apply the suggested fix(es). For example: "Would you like me to use the Suggested fix section to address these issues?"
### Template B (no issues)
```
## Code review
No issues found.
```
================================================
FILE: .agents/skills/frontend-code-review/references/business-logic.md
================================================
# Rule Catalog — Business Logic
## Can't use workflowStore in Node components
IsUrgent: True
### Description
File path pattern of node components: `web/app/components/workflow/nodes/[nodeName]/node.tsx`
Node components are also used when creating a RAG Pipe from a template, but in that context there is no workflowStore Provider, which results in a blank screen. [This Issue](https://github.com/langgenius/dify/issues/29168) was caused by exactly this reason.
### Suggested Fix
Use `import { useNodes } from 'reactflow'` instead of `import useNodes from '@/app/components/workflow/store/workflow/use-nodes'`.
================================================
FILE: .agents/skills/frontend-code-review/references/code-quality.md
================================================
# Rule Catalog — Code Quality
## Conditional class names use utility function
IsUrgent: True
Category: Code Quality
### Description
Ensure conditional CSS is handled via the shared `classNames` instead of custom ternaries, string concatenation, or template strings. Centralizing class logic keeps components consistent and easier to maintain.
### Suggested Fix
```ts
import { cn } from '@/utils/classnames'
const classNames = cn(isActive ? 'text-primary-600' : 'text-gray-500')
```
## Tailwind-first styling
IsUrgent: True
Category: Code Quality
### Description
Favor Tailwind CSS utility classes instead of adding new `.module.css` files unless a Tailwind combination cannot achieve the required styling. Keeping styles in Tailwind improves consistency and reduces maintenance overhead.
Update this file when adding, editing, or removing Code Quality rules so the catalog remains accurate.
## Classname ordering for easy overrides
### Description
When writing components, always place the incoming `className` prop after the component’s own class values so that downstream consumers can override or extend the styling. This keeps your component’s defaults but still lets external callers change or remove specific styles.
Example:
```tsx
import { cn } from '@/utils/classnames'
const Button = ({ className }) => {
return <div className={cn('bg-primary-600', className)}></div>
}
```
================================================
FILE: .agents/skills/frontend-code-review/references/performance.md
================================================
# Rule Catalog — Performance
## React Flow data usage
IsUrgent: True
Category: Performance
### Description
When rendering React Flow, prefer `useNodes`/`useEdges` for UI consumption and rely on `useStoreApi` inside callbacks that mutate or read node/edge state. Avoid manually pulling Flow data outside of these hooks.
## Complex prop memoization
IsUrgent: True
Category: Performance
### Description
Wrap complex prop values (objects, arrays, maps) in `useMemo` prior to passing them into child components to guarantee stable references and prevent unnecessary renders.
Update this file when adding, editing, or removing Performance rules so the catalog remains accurate.
Wrong:
```tsx
<HeavyComp
config={{
provider: ...,
detail: ...
}}
/>
```
Right:
```tsx
const config = useMemo(() => ({
provider: ...,
detail: ...
}), [provider, detail]);
<HeavyComp
config={config}
/>
```
================================================
FILE: .agents/skills/frontend-query-mutation/SKILL.md
================================================
---
name: frontend-query-mutation
description: Guide for implementing Dify frontend query and mutation patterns with TanStack Query and oRPC. Trigger when creating or updating contracts in web/contract, wiring router composition, consuming consoleQuery or marketplaceQuery in components or services, deciding whether to call queryOptions() directly or extract a helper or use-* hook, handling conditional queries, cache invalidation, mutation error handling, or migrating legacy service calls to contract-first query and mutation helpers.
---
# Frontend Query & Mutation
## Intent
- Keep contract as the single source of truth in `web/contract/*`.
- Prefer contract-shaped `queryOptions()` and `mutationOptions()`.
- Keep invalidation and mutation flow knowledge in the service layer.
- Keep abstractions minimal to preserve TypeScript inference.
## Workflow
1. Identify the change surface.
- Read `references/contract-patterns.md` for contract files, router composition, client helpers, and query or mutation call-site shape.
- Read `references/runtime-rules.md` for conditional queries, invalidation, error handling, and legacy migrations.
- Read both references when a task spans contract shape and runtime behavior.
2. Implement the smallest abstraction that fits the task.
- Default to direct `useQuery(...)` or `useMutation(...)` calls with oRPC helpers at the call site.
- Extract a small shared query helper only when multiple call sites share the same extra options.
- Create `web/service/use-{domain}.ts` only for orchestration or shared domain behavior.
3. Preserve Dify conventions.
- Keep contract inputs in `{ params, query?, body? }` shape.
- Bind invalidation in the service-layer mutation definition.
- Prefer `mutate(...)`; use `mutateAsync(...)` only when Promise semantics are required.
## Files Commonly Touched
- `web/contract/console/*.ts`
- `web/contract/marketplace.ts`
- `web/contract/router.ts`
- `web/service/client.ts`
- `web/service/use-*.ts`
- component and hook call sites using `consoleQuery` or `marketplaceQuery`
## References
- Use `references/contract-patterns.md` for contract shape, router registration, query and mutation helpers, and anti-patterns that degrade inference.
- Use `references/runtime-rules.md` for conditional queries, invalidation, `mutate` versus `mutateAsync`, and legacy migration rules.
Treat this skill as the single query and mutation entry point for Dify frontend work. Keep detailed rules in the reference files instead of duplicating them in project docs.
================================================
FILE: .agents/skills/frontend-query-mutation/agents/openai.yaml
================================================
interface:
display_name: "Frontend Query & Mutation"
short_description: "Dify TanStack Query and oRPC patterns"
default_prompt: "Use this skill when implementing or reviewing Dify frontend contracts, query and mutation call sites, conditional queries, invalidation, or legacy query/mutation migrations."
================================================
FILE: .agents/skills/frontend-query-mutation/references/contract-patterns.md
================================================
# Contract Patterns
## Table of Contents
- Intent
- Minimal structure
- Core workflow
- Query usage decision rule
- Mutation usage decision rule
- Anti-patterns
- Contract rules
- Type export
## Intent
- Keep contract as the single source of truth in `web/contract/*`.
- Default query usage to call-site `useQuery(consoleQuery|marketplaceQuery.xxx.queryOptions(...))` when endpoint behavior maps 1:1 to the contract.
- Keep abstractions minimal and preserve TypeScript inference.
## Minimal Structure
```text
web/contract/
├── base.ts
├── router.ts
├── marketplace.ts
└── console/
├── billing.ts
└── ...other domains
web/service/client.ts
```
## Core Workflow
1. Define contract in `web/contract/console/{domain}.ts` or `web/contract/marketplace.ts`.
- Use `base.route({...}).output(type<...>())` as the baseline.
- Add `.input(type<...>())` only when the request has `params`, `query`, or `body`.
- For `GET` without input, omit `.input(...)`; do not use `.input(type<unknown>())`.
2. Register contract in `web/contract/router.ts`.
- Import directly from domain files and nest by API prefix.
3. Consume from UI call sites via oRPC query utilities.
```typescript
import { useQuery } from '@tanstack/react-query'
import { consoleQuery } from '@/service/client'
const invoiceQuery = useQuery(consoleQuery.billing.invoices.queryOptions({
staleTime: 5 * 60 * 1000,
throwOnError: true,
select: invoice => invoice.url,
}))
```
## Query Usage Decision Rule
1. Default to direct `*.queryOptions(...)` usage at the call site.
2. If 3 or more call sites share the same extra options, extract a small query helper, not a `use-*` passthrough hook.
3. Create `web/service/use-{domain}.ts` only for orchestration.
- Combine multiple queries or mutations.
- Share domain-level derived state or invalidation helpers.
```typescript
const invoicesBaseQueryOptions = () =>
consoleQuery.billing.invoices.queryOptions({ retry: false })
const invoiceQuery = useQuery({
...invoicesBaseQueryOptions(),
throwOnError: true,
})
```
## Mutation Usage Decision Rule
1. Default to mutation helpers from `consoleQuery` or `marketplaceQuery`, for example `useMutation(consoleQuery.billing.bindPartnerStack.mutationOptions(...))`.
2. If the mutation flow is heavily custom, use oRPC clients as `mutationFn`, for example `consoleClient.xxx` or `marketplaceClient.xxx`, instead of handwritten non-oRPC mutation logic.
## Anti-Patterns
- Do not wrap `useQuery` with `options?: Partial<UseQueryOptions>`.
- Do not split local `queryKey` and `queryFn` when oRPC `queryOptions` already exists and fits the use case.
- Do not create thin `use-*` passthrough hooks for a single endpoint.
- These patterns can degrade inference, especially around `throwOnError` and `select`, and add unnecessary indirection.
## Contract Rules
- Input structure: always use `{ params, query?, body? }`.
- No-input `GET`: omit `.input(...)`; do not use `.input(type<unknown>())`.
- Path params: use `{paramName}` in the path and match it in the `params` object.
- Router nesting: group by API prefix, for example `/billing/*` becomes `billing: {}`.
- No barrel files: import directly from specific files.
- Types: import from `@/types/` and use the `type<T>()` helper.
- Mutations: prefer `mutationOptions`; use explicit `mutationKey` mainly for defaults, filtering, and devtools.
## Type Export
```typescript
export type ConsoleInputs = InferContractRouterInputs<typeof consoleRouterContract>
```
================================================
FILE: .agents/skills/frontend-query-mutation/references/runtime-rules.md
================================================
# Runtime Rules
## Table of Contents
- Conditional queries
- Cache invalidation
- Key API guide
- `mutate` vs `mutateAsync`
- Legacy migration
## Conditional Queries
Prefer contract-shaped `queryOptions(...)`.
When required input is missing, prefer `input: skipToken` instead of placeholder params or non-null assertions.
Use `enabled` only for extra business gating after the input itself is already valid.
```typescript
import { skipToken, useQuery } from '@tanstack/react-query'
// Disable the query by skipping input construction.
function useAccessMode(appId: string | undefined) {
return useQuery(consoleQuery.accessControl.appAccessMode.queryOptions({
input: appId
? { params: { appId } }
: skipToken,
}))
}
// Avoid runtime-only guards that bypass type checking.
function useBadAccessMode(appId: string | undefined) {
return useQuery(consoleQuery.accessControl.appAccessMode.queryOptions({
input: { params: { appId: appId! } },
enabled: !!appId,
}))
}
```
## Cache Invalidation
Bind invalidation in the service-layer mutation definition.
Components may add UI feedback in call-site callbacks, but they should not decide which queries to invalidate.
Use:
- `.key()` for namespace or prefix invalidation
- `.queryKey(...)` only for exact cache reads or writes such as `getQueryData` and `setQueryData`
- `queryClient.invalidateQueries(...)` in mutation `onSuccess`
Do not use deprecated `useInvalid` from `use-base.ts`.
```typescript
// Service layer owns cache invalidation.
export const useUpdateAccessMode = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.accessControl.updateAccessMode.mutationOptions({
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: consoleQuery.accessControl.appWhitelistSubjects.key(),
})
},
}))
}
// Component only adds UI behavior.
updateAccessMode({ appId, mode }, {
onSuccess: () => Toast.notify({ type: 'success', message: '...' }),
})
// Avoid putting invalidation knowledge in the component.
mutate({ appId, mode }, {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: consoleQuery.accessControl.appWhitelistSubjects.key(),
})
},
})
```
## Key API Guide
- `.key(...)`
- Use for partial matching operations.
- Prefer it for invalidation, refetch, and cancel patterns.
- Example: `queryClient.invalidateQueries({ queryKey: consoleQuery.billing.key() })`
- `.queryKey(...)`
- Use for a specific query's full key.
- Prefer it for exact cache addressing and direct reads or writes.
- `.mutationKey(...)`
- Use for a specific mutation's full key.
- Prefer it for mutation defaults registration, mutation-status filtering, and devtools grouping.
## `mutate` vs `mutateAsync`
Prefer `mutate` by default.
Use `mutateAsync` only when Promise semantics are truly required, such as parallel mutations or sequential steps with result dependencies.
Rules:
- Event handlers should usually call `mutate(...)` with `onSuccess` or `onError`.
- Every `await mutateAsync(...)` must be wrapped in `try/catch`.
- Do not use `mutateAsync` when callbacks already express the flow clearly.
```typescript
// Default case.
mutation.mutate(data, {
onSuccess: result => router.push(result.url),
})
// Promise semantics are required.
try {
const order = await createOrder.mutateAsync(orderData)
await confirmPayment.mutateAsync({ orderId: order.id, token })
router.push(`/orders/${order.id}`)
}
catch (error) {
Toast.notify({
type: 'error',
message: error instanceof Error ? error.message : 'Unknown error',
})
}
```
## Legacy Migration
When touching old code, migrate it toward these rules:
| Old pattern | New pattern |
|---|---|
| `useInvalid(key)` in service layer | `queryClient.invalidateQueries(...)` inside mutation `onSuccess` |
| component-triggered invalidation after mutation | move invalidation into the service-layer mutation definition |
| imperative fetch plus manual invalidation | wrap it in `useMutation(...mutationOptions(...))` |
| `await mutateAsync()` without `try/catch` | switch to `mutate(...)` or add `try/catch` |
================================================
FILE: .agents/skills/frontend-testing/SKILL.md
================================================
---
name: frontend-testing
description: Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.
---
# Dify Frontend Testing Skill
This skill enables Claude to generate high-quality, comprehensive frontend tests for the Dify project following established conventions and best practices.
> **⚠️ Authoritative Source**: This skill is derived from `web/docs/test.md`. Use Vitest mock/timer APIs (`vi.*`).
## When to Apply This Skill
Apply this skill when the user:
- Asks to **write tests** for a component, hook, or utility
- Asks to **review existing tests** for completeness
- Mentions **Vitest**, **React Testing Library**, **RTL**, or **spec files**
- Requests **test coverage** improvement
- Uses `pnpm analyze-component` output as context
- Mentions **testing**, **unit tests**, or **integration tests** for frontend code
- Wants to understand **testing patterns** in the Dify codebase
**Do NOT apply** when:
- User is asking about backend/API tests (Python/pytest)
- User is asking about E2E tests (Playwright/Cypress)
- User is only asking conceptual questions without code context
## Quick Reference
### Tech Stack
| Tool | Version | Purpose |
|------|---------|---------|
| Vitest | 4.0.16 | Test runner |
| React Testing Library | 16.0 | Component testing |
| jsdom | - | Test environment |
| nock | 14.0 | HTTP mocking |
| TypeScript | 5.x | Type safety |
### Key Commands
```bash
# Run all tests
pnpm test
# Watch mode
pnpm test:watch
# Run specific file
pnpm test path/to/file.spec.tsx
# Generate coverage report
pnpm test:coverage
# Analyze component complexity
pnpm analyze-component <path>
# Review existing test
pnpm analyze-component <path> --review
```
### File Naming
- Test files: `ComponentName.spec.tsx` inside a same-level `__tests__/` directory
- Placement rule: Component, hook, and utility tests must live in a sibling `__tests__/` folder at the same level as the source under test. For example, `foo/index.tsx` maps to `foo/__tests__/index.spec.tsx`, and `foo/bar.ts` maps to `foo/__tests__/bar.spec.ts`.
- Integration tests: `web/__tests__/` directory
## Test Structure Template
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import Component from './index'
// ✅ Import real project components (DO NOT mock these)
// import Loading from '@/app/components/base/loading'
// import { ChildComponent } from './child-component'
// ✅ Mock external dependencies only
vi.mock('@/service/api')
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
usePathname: () => '/test',
}))
// ✅ Zustand stores: Use real stores (auto-mocked globally)
// Set test state with: useAppStore.setState({ ... })
// Shared state for mocks (if needed)
let mockSharedState = false
describe('ComponentName', () => {
beforeEach(() => {
vi.clearAllMocks() // ✅ Reset mocks BEFORE each test
mockSharedState = false // ✅ Reset shared state
})
// Rendering tests (REQUIRED)
describe('Rendering', () => {
it('should render without crashing', () => {
// Arrange
const props = { title: 'Test' }
// Act
render(<Component {...props} />)
// Assert
expect(screen.getByText('Test')).toBeInTheDocument()
})
})
// Props tests (REQUIRED)
describe('Props', () => {
it('should apply custom className', () => {
render(<Component className="custom" />)
expect(screen.getByRole('button')).toHaveClass('custom')
})
})
// User Interactions
describe('User Interactions', () => {
it('should handle click events', () => {
const handleClick = vi.fn()
render(<Component onClick={handleClick} />)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
// Edge Cases (REQUIRED)
describe('Edge Cases', () => {
it('should handle null data', () => {
render(<Component data={null} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
render(<Component items={[]} />)
expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
})
})
```
## Testing Workflow (CRITICAL)
### ⚠️ Incremental Approach Required
**NEVER generate all test files at once.** For complex components or multi-file directories:
1. **Analyze & Plan**: List all files, order by complexity (simple → complex)
1. **Process ONE at a time**: Write test → Run test → Fix if needed → Next
1. **Verify before proceeding**: Do NOT continue to next file until current passes
```
For each file:
┌────────────────────────────────────────┐
│ 1. Write test │
│ 2. Run: pnpm test <file>.spec.tsx │
│ 3. PASS? → Mark complete, next file │
│ FAIL? → Fix first, then continue │
└────────────────────────────────────────┘
```
### Complexity-Based Order
Process in this order for multi-file testing:
1. 🟢 Utility functions (simplest)
1. 🟢 Custom hooks
1. 🟡 Simple components (presentational)
1. 🟡 Medium components (state, effects)
1. 🔴 Complex components (API, routing)
1. 🔴 Integration tests (index files - last)
### When to Refactor First
- **Complexity > 50**: Break into smaller pieces before testing
- **500+ lines**: Consider splitting before testing
- **Many dependencies**: Extract logic into hooks first
> 📖 See `references/workflow.md` for complete workflow details and todo list format.
## Testing Strategy
### Path-Level Testing (Directory Testing)
When assigned to test a directory/path, test **ALL content** within that path:
- Test all components, hooks, utilities in the directory (not just `index` file)
- Use incremental approach: one file at a time, verify each before proceeding
- Goal: 100% coverage of ALL files in the directory
### Integration Testing First
**Prefer integration testing** when writing tests for a directory:
- ✅ **Import real project components** directly (including base components and siblings)
- ✅ **Only mock**: API services (`@/service/*`), `next/navigation`, complex context providers
- ❌ **DO NOT mock** base components (`@/app/components/base/*`)
- ❌ **DO NOT mock** sibling/child components in the same directory
> See [Test Structure Template](#test-structure-template) for correct import/mock patterns.
### `nuqs` Query State Testing (Required for URL State Hooks)
When a component or hook uses `useQueryState` / `useQueryStates`:
- ✅ Use `NuqsTestingAdapter` (prefer shared helpers in `web/test/nuqs-testing.tsx`)
- ✅ Assert URL synchronization via `onUrlUpdate` (`searchParams`, `options.history`)
- ✅ For custom parsers (`createParser`), keep `parse` and `serialize` bijective and add round-trip edge cases (`%2F`, `%25`, spaces, legacy encoded values)
- ✅ Verify default-clearing behavior (default values should be removed from URL when applicable)
- ⚠️ Only mock `nuqs` directly when URL behavior is explicitly out of scope for the test
## Core Principles
### 1. AAA Pattern (Arrange-Act-Assert)
Every test should clearly separate:
- **Arrange**: Setup test data and render component
- **Act**: Perform user actions
- **Assert**: Verify expected outcomes
### 2. Black-Box Testing
- Test observable behavior, not implementation details
- Use semantic queries (getByRole, getByLabelText)
- Avoid testing internal state directly
- **Prefer pattern matching over hardcoded strings** in assertions:
```typescript
// ❌ Avoid: hardcoded text assertions
expect(screen.getByText('Loading...')).toBeInTheDocument()
// ✅ Better: role-based queries
expect(screen.getByRole('status')).toBeInTheDocument()
// ✅ Better: pattern matching
expect(screen.getByText(/loading/i)).toBeInTheDocument()
```
### 3. Single Behavior Per Test
Each test verifies ONE user-observable behavior:
```typescript
// ✅ Good: One behavior
it('should disable button when loading', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
})
// ❌ Bad: Multiple behaviors
it('should handle loading state', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
expect(screen.getByText('Loading...')).toBeInTheDocument()
expect(screen.getByRole('button')).toHaveClass('loading')
})
```
### 4. Semantic Naming
Use `should <behavior> when <condition>`:
```typescript
it('should show error message when validation fails')
it('should call onSubmit when form is valid')
it('should disable input when isReadOnly is true')
```
## Required Test Scenarios
### Always Required (All Components)
1. **Rendering**: Component renders without crashing
1. **Props**: Required props, optional props, default values
1. **Edge Cases**: null, undefined, empty values, boundary conditions
### Conditional (When Present)
| Feature | Test Focus |
|---------|-----------|
| `useState` | Initial state, transitions, cleanup |
| `useEffect` | Execution, dependencies, cleanup |
| Event handlers | All onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
| `useCallback`/`useMemo` | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
## Coverage Goals (Per File)
For each test file generated, aim for:
- ✅ **100%** function coverage
- ✅ **100%** statement coverage
- ✅ **>95%** branch coverage
- ✅ **>95%** line coverage
> **Note**: For multi-file directories, process one file at a time with full coverage each. See `references/workflow.md`.
## Detailed Guides
For more detailed information, refer to:
- `references/workflow.md` - **Incremental testing workflow** (MUST READ for multi-file testing)
- `references/mocking.md` - Mock patterns, Zustand store testing, and best practices
- `references/async-testing.md` - Async operations and API calls
- `references/domain-components.md` - Workflow, Dataset, Configuration testing
- `references/common-patterns.md` - Frequently used testing patterns
- `references/checklist.md` - Test generation checklist and validation steps
## Authoritative References
### Primary Specification (MUST follow)
- **`web/docs/test.md`** - The canonical testing specification. This skill is derived from this document.
### Reference Examples in Codebase
- `web/utils/classnames.spec.ts` - Utility function tests
- `web/app/components/base/button/index.spec.tsx` - Component tests
- `web/__mocks__/provider-context.ts` - Mock factory example
### Project Configuration
- `web/vitest.config.ts` - Vitest configuration
- `web/vitest.setup.ts` - Test environment setup
- `web/scripts/analyze-component.js` - Component analysis tool
- Modules are not mocked automatically. Global mocks live in `web/vitest.setup.ts` (for example `react-i18next`, `next/image`); mock other modules like `ky` or `mime` locally in test files.
================================================
FILE: .agents/skills/frontend-testing/assets/component-test.template.tsx
================================================
/**
* Test Template for React Components
*
* WHY THIS STRUCTURE?
* - Organized sections make tests easy to navigate and maintain
* - Mocks at top ensure consistent test isolation
* - Factory functions reduce duplication and improve readability
* - describe blocks group related scenarios for better debugging
*
* INSTRUCTIONS:
* 1. Replace `ComponentName` with your component name
* 2. Update import path
* 3. Add/remove test sections based on component features (use analyze-component)
* 4. Follow AAA pattern: Arrange → Act → Assert
*
* RUN FIRST: pnpm analyze-component <path> to identify required test scenarios
*/
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
// import ComponentName from './index'
// ============================================================================
// Mocks
// ============================================================================
// WHY: Mocks must be hoisted to top of file (Vitest requirement).
// They run BEFORE imports, so keep them before component imports.
// i18n (automatically mocked)
// WHY: Global mock in web/vitest.setup.ts is auto-loaded by Vitest setup
// The global mock provides: useTranslation, Trans, useMixedTranslation, useGetLanguage
// No explicit mock needed for most tests
//
// Override only if custom translations are required:
// import { createReactI18nextMock } from '@/test/i18n-mock'
// vi.mock('react-i18next', () => createReactI18nextMock({
// 'my.custom.key': 'Custom Translation',
// 'button.save': 'Save',
// }))
// Router (if component uses useRouter, usePathname, useSearchParams)
// WHY: Isolates tests from Next.js routing, enables testing navigation behavior
// const mockPush = vi.fn()
// vi.mock('@/next/navigation', () => ({
// useRouter: () => ({ push: mockPush }),
// usePathname: () => '/test-path',
// }))
// API services (if component fetches data)
// WHY: Prevents real network calls, enables testing all states (loading/success/error)
// vi.mock('@/service/api')
// import * as api from '@/service/api'
// const mockedApi = vi.mocked(api)
// Shared mock state (for portal/dropdown components)
// WHY: Portal components like PortalToFollowElem need shared state between
// parent and child mocks to correctly simulate open/close behavior
// let mockOpenState = false
// ============================================================================
// Test Data Factories
// ============================================================================
// WHY FACTORIES?
// - Avoid hard-coded test data scattered across tests
// - Easy to create variations with overrides
// - Type-safe when using actual types from source
// - Single source of truth for default test values
// const createMockProps = (overrides = {}) => ({
// // Default props that make component render successfully
// ...overrides,
// })
// const createMockItem = (overrides = {}) => ({
// id: 'item-1',
// name: 'Test Item',
// ...overrides,
// })
// ============================================================================
// Test Helpers
// ============================================================================
// const renderComponent = (props = {}) => {
// return render(<ComponentName {...createMockProps(props)} />)
// }
// ============================================================================
// Tests
// ============================================================================
describe('ComponentName', () => {
// WHY beforeEach with clearAllMocks?
// - Ensures each test starts with clean slate
// - Prevents mock call history from leaking between tests
// - MUST be beforeEach (not afterEach) to reset BEFORE assertions like toHaveBeenCalledTimes
beforeEach(() => {
vi.clearAllMocks()
// Reset shared mock state if used (CRITICAL for portal/dropdown tests)
// mockOpenState = false
})
// --------------------------------------------------------------------------
// Rendering Tests (REQUIRED - Every component MUST have these)
// --------------------------------------------------------------------------
// WHY: Catches import errors, missing providers, and basic render issues
describe('Rendering', () => {
it('should render without crashing', () => {
// Arrange - Setup data and mocks
// const props = createMockProps()
// Act - Render the component
// render(<ComponentName {...props} />)
// Assert - Verify expected output
// Prefer getByRole for accessibility; it's what users "see"
// expect(screen.getByRole('...')).toBeInTheDocument()
})
it('should render with default props', () => {
// WHY: Verifies component works without optional props
// render(<ComponentName />)
// expect(screen.getByText('...')).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Props Tests (REQUIRED - Every component MUST test prop behavior)
// --------------------------------------------------------------------------
// WHY: Props are the component's API contract. Test them thoroughly.
describe('Props', () => {
it('should apply custom className', () => {
// WHY: Common pattern in Dify - components should merge custom classes
// render(<ComponentName className="custom-class" />)
// expect(screen.getByTestId('component')).toHaveClass('custom-class')
})
it('should use default values for optional props', () => {
// WHY: Verifies TypeScript defaults work at runtime
// render(<ComponentName />)
// expect(screen.getByRole('...')).toHaveAttribute('...', 'default-value')
})
})
// --------------------------------------------------------------------------
// User Interactions (if component has event handlers - on*, handle*)
// --------------------------------------------------------------------------
// WHY: Event handlers are core functionality. Test from user's perspective.
describe('User Interactions', () => {
it('should call onClick when clicked', async () => {
// WHY userEvent over fireEvent?
// - userEvent simulates real user behavior (focus, hover, then click)
// - fireEvent is lower-level, doesn't trigger all browser events
// const user = userEvent.setup()
// const handleClick = vi.fn()
// render(<ComponentName onClick={handleClick} />)
//
// await user.click(screen.getByRole('button'))
//
// expect(handleClick).toHaveBeenCalledTimes(1)
})
it('should call onChange when value changes', async () => {
// const user = userEvent.setup()
// const handleChange = vi.fn()
// render(<ComponentName onChange={handleChange} />)
//
// await user.type(screen.getByRole('textbox'), 'new value')
//
// expect(handleChange).toHaveBeenCalled()
})
})
// --------------------------------------------------------------------------
// State Management (if component uses useState/useReducer)
// --------------------------------------------------------------------------
// WHY: Test state through observable UI changes, not internal state values
describe('State Management', () => {
it('should update state on interaction', async () => {
// WHY test via UI, not state?
// - State is implementation detail; UI is what users see
// - If UI works correctly, state must be correct
// const user = userEvent.setup()
// render(<ComponentName />)
//
// // Initial state - verify what user sees
// expect(screen.getByText('Initial')).toBeInTheDocument()
//
// // Trigger state change via user action
// await user.click(screen.getByRole('button'))
//
// // New state - verify UI updated
// expect(screen.getByText('Updated')).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Async Operations (if component fetches data - useQuery, fetch)
// --------------------------------------------------------------------------
// WHY: Async operations have 3 states users experience: loading, success, error
describe('Async Operations', () => {
it('should show loading state', () => {
// WHY never-resolving promise?
// - Keeps component in loading state for assertion
// - Alternative: use fake timers
// mockedApi.fetchData.mockImplementation(() => new Promise(() => {}))
// render(<ComponentName />)
//
// expect(screen.getByText(/loading/i)).toBeInTheDocument()
})
it('should show data on success', async () => {
// WHY waitFor?
// - Component updates asynchronously after fetch resolves
// - waitFor retries assertion until it passes or times out
// mockedApi.fetchData.mockResolvedValue({ items: ['Item 1'] })
// render(<ComponentName />)
//
// await waitFor(() => {
// expect(screen.getByText('Item 1')).toBeInTheDocument()
// })
})
it('should show error on failure', async () => {
// mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
// render(<ComponentName />)
//
// await waitFor(() => {
// expect(screen.getByText(/error/i)).toBeInTheDocument()
// })
})
})
// --------------------------------------------------------------------------
// Edge Cases (REQUIRED - Every component MUST handle edge cases)
// --------------------------------------------------------------------------
// WHY: Real-world data is messy. Components must handle:
// - Null/undefined from API failures or optional fields
// - Empty arrays/strings from user clearing data
// - Boundary values (0, MAX_INT, special characters)
describe('Edge Cases', () => {
it('should handle null value', () => {
// WHY test null specifically?
// - API might return null for missing data
// - Prevents "Cannot read property of null" in production
// render(<ComponentName value={null} />)
// expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle undefined value', () => {
// WHY test undefined separately from null?
// - TypeScript treats them differently
// - Optional props are undefined, not null
// render(<ComponentName value={undefined} />)
// expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
// WHY: Empty state often needs special UI (e.g., "No items yet")
// render(<ComponentName items={[]} />)
// expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
it('should handle empty string', () => {
// WHY: Empty strings are truthy in JS but visually empty
// render(<ComponentName text="" />)
// expect(screen.getByText(/placeholder/i)).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Accessibility (optional but recommended for Dify's enterprise users)
// --------------------------------------------------------------------------
// WHY: Dify has enterprise customers who may require accessibility compliance
describe('Accessibility', () => {
it('should have accessible name', () => {
// WHY getByRole with name?
// - Tests that screen readers can identify the element
// - Enforces proper labeling practices
// render(<ComponentName label="Test Label" />)
// expect(screen.getByRole('button', { name: /test label/i })).toBeInTheDocument()
})
it('should support keyboard navigation', async () => {
// WHY: Some users can't use a mouse
// const user = userEvent.setup()
// render(<ComponentName />)
//
// await user.tab()
// expect(screen.getByRole('button')).toHaveFocus()
})
})
})
================================================
FILE: .agents/skills/frontend-testing/assets/hook-test.template.ts
================================================
/**
* Test Template for Custom Hooks
*
* Instructions:
* 1. Replace `useHookName` with your hook name
* 2. Update import path
* 3. Add/remove test sections based on hook features
*/
import { renderHook, act, waitFor } from '@testing-library/react'
// import { useHookName } from './use-hook-name'
// ============================================================================
// Mocks
// ============================================================================
// API services (if hook fetches data)
// vi.mock('@/service/api')
// import * as api from '@/service/api'
// const mockedApi = vi.mocked(api)
// ============================================================================
// Test Helpers
// ============================================================================
// Wrapper for hooks that need context
// const createWrapper = (contextValue = {}) => {
// return ({ children }: { children: React.ReactNode }) => (
// <SomeContext.Provider value={contextValue}>
// {children}
// </SomeContext.Provider>
// )
// }
// ============================================================================
// Tests
// ============================================================================
describe('useHookName', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// --------------------------------------------------------------------------
// Initial State
// --------------------------------------------------------------------------
describe('Initial State', () => {
it('should return initial state', () => {
// const { result } = renderHook(() => useHookName())
//
// expect(result.current.value).toBe(initialValue)
// expect(result.current.isLoading).toBe(false)
})
it('should accept initial value from props', () => {
// const { result } = renderHook(() => useHookName({ initialValue: 'custom' }))
//
// expect(result.current.value).toBe('custom')
})
})
// --------------------------------------------------------------------------
// State Updates
// --------------------------------------------------------------------------
describe('State Updates', () => {
it('should update value when setValue is called', () => {
// const { result } = renderHook(() => useHookName())
//
// act(() => {
// result.current.setValue('new value')
// })
//
// expect(result.current.value).toBe('new value')
})
it('should reset to initial value', () => {
// const { result } = renderHook(() => useHookName({ initialValue: 'initial' }))
//
// act(() => {
// result.current.setValue('changed')
// })
// expect(result.current.value).toBe('changed')
//
// act(() => {
// result.current.reset()
// })
// expect(result.current.value).toBe('initial')
})
})
// --------------------------------------------------------------------------
// Async Operations
// --------------------------------------------------------------------------
describe('Async Operations', () => {
it('should fetch data on mount', async () => {
// mockedApi.fetchData.mockResolvedValue({ data: 'test' })
//
// const { result } = renderHook(() => useHookName())
//
// // Initially loading
// expect(result.current.isLoading).toBe(true)
//
// // Wait for data
// await waitFor(() => {
// expect(result.current.isLoading).toBe(false)
// })
//
// expect(result.current.data).toEqual({ data: 'test' })
})
it('should handle fetch error', async () => {
// mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
//
// const { result } = renderHook(() => useHookName())
//
// await waitFor(() => {
// expect(result.current.error).toBeTruthy()
// })
//
// expect(result.current.error?.message).toBe('Network error')
})
it('should refetch when dependency changes', async () => {
// mockedApi.fetchData.mockResolvedValue({ data: 'test' })
//
// const { result, rerender } = renderHook(
// ({ id }) => useHookName(id),
// { initialProps: { id: '1' } }
// )
//
// await waitFor(() => {
// expect(mockedApi.fetchData).toHaveBeenCalledWith('1')
// })
//
// rerender({ id: '2' })
//
// await waitFor(() => {
// expect(mockedApi.fetchData).toHaveBeenCalledWith('2')
// })
})
})
// --------------------------------------------------------------------------
// Side Effects
// --------------------------------------------------------------------------
describe('Side Effects', () => {
it('should call callback when value changes', () => {
// const callback = vi.fn()
// const { result } = renderHook(() => useHookName({ onChange: callback }))
//
// act(() => {
// result.current.setValue('new value')
// })
//
// expect(callback).toHaveBeenCalledWith('new value')
})
it('should cleanup on unmount', () => {
// const cleanup = vi.fn()
// vi.spyOn(window, 'addEventListener')
// vi.spyOn(window, 'removeEventListener')
//
// const { unmount } = renderHook(() => useHookName())
//
// expect(window.addEventListener).toHaveBeenCalled()
//
// unmount()
//
// expect(window.removeEventListener).toHaveBeenCalled()
})
})
// --------------------------------------------------------------------------
// Edge Cases
// --------------------------------------------------------------------------
describe('Edge Cases', () => {
it('should handle null input', () => {
// const { result } = renderHook(() => useHookName(null))
//
// expect(result.current.value).toBeNull()
})
it('should handle rapid updates', () => {
// const { result } = renderHook(() => useHookName())
//
// act(() => {
// result.current.setValue('1')
// result.current.setValue('2')
// result.current.setValue('3')
// })
//
// expect(result.current.value).toBe('3')
})
})
// --------------------------------------------------------------------------
// With Context (if hook uses context)
// --------------------------------------------------------------------------
describe('With Context', () => {
it('should use context value', () => {
// const wrapper = createWrapper({ someValue: 'context-value' })
// const { result } = renderHook(() => useHookName(), { wrapper })
//
// expect(result.current.contextValue).toBe('context-value')
})
})
})
================================================
FILE: .agents/skills/frontend-testing/assets/utility-test.template.ts
================================================
/**
* Test Template for Utility Functions
*
* Instructions:
* 1. Replace `utilityFunction` with your function name
* 2. Update import path
* 3. Use test.each for data-driven tests
*/
// import { utilityFunction } from './utility'
// ============================================================================
// Tests
// ============================================================================
describe('utilityFunction', () => {
// --------------------------------------------------------------------------
// Basic Functionality
// --------------------------------------------------------------------------
describe('Basic Functionality', () => {
it('should return expected result for valid input', () => {
// expect(utilityFunction('input')).toBe('expected-output')
})
it('should handle multiple arguments', () => {
// expect(utilityFunction('a', 'b', 'c')).toBe('abc')
})
})
// --------------------------------------------------------------------------
// Data-Driven Tests
// --------------------------------------------------------------------------
describe('Input/Output Mapping', () => {
test.each([
// [input, expected]
['input1', 'output1'],
['input2', 'output2'],
['input3', 'output3'],
])('should return %s for input %s', (input, expected) => {
// expect(utilityFunction(input)).toBe(expected)
})
})
// --------------------------------------------------------------------------
// Edge Cases
// --------------------------------------------------------------------------
describe('Edge Cases', () => {
it('should handle empty string', () => {
// expect(utilityFunction('')).toBe('')
})
it('should handle null', () => {
// expect(utilityFunction(null)).toBe(null)
// or
// expect(() => utilityFunction(null)).toThrow()
})
it('should handle undefined', () => {
// expect(utilityFunction(undefined)).toBe(undefined)
// or
// expect(() => utilityFunction(undefined)).toThrow()
})
it('should handle empty array', () => {
// expect(utilityFunction([])).toEqual([])
})
it('should handle empty object', () => {
// expect(utilityFunction({})).toEqual({})
})
})
// --------------------------------------------------------------------------
// Boundary Conditions
// --------------------------------------------------------------------------
describe('Boundary Conditions', () => {
it('should handle minimum value', () => {
// expect(utilityFunction(0)).toBe(0)
})
it('should handle maximum value', () => {
// expect(utilityFunction(Number.MAX_SAFE_INTEGER)).toBe(...)
})
it('should handle negative numbers', () => {
// expect(utilityFunction(-1)).toBe(...)
})
})
// --------------------------------------------------------------------------
// Type Coercion (if applicable)
// --------------------------------------------------------------------------
describe('Type Handling', () => {
it('should handle numeric string', () => {
// expect(utilityFunction('123')).toBe(123)
})
it('should handle boolean', () => {
// expect(utilityFunction(true)).toBe(...)
})
})
// --------------------------------------------------------------------------
// Error Cases
// --------------------------------------------------------------------------
describe('Error Handling', () => {
it('should throw for invalid input', () => {
// expect(() => utilityFunction('invalid')).toThrow('Error message')
})
it('should throw with specific error type', () => {
// expect(() => utilityFunction('invalid')).toThrow(ValidationError)
})
})
// --------------------------------------------------------------------------
// Complex Objects (if applicable)
// --------------------------------------------------------------------------
describe('Object Handling', () => {
it('should preserve object structure', () => {
// const input = { a: 1, b: 2 }
// expect(utilityFunction(input)).toEqual({ a: 1, b: 2 })
})
it('should handle nested objects', () => {
// const input = { nested: { deep: 'value' } }
// expect(utilityFunction(input)).toEqual({ nested: { deep: 'transformed' } })
})
it('should not mutate input', () => {
// const input = { a: 1 }
// const inputCopy = { ...input }
// utilityFunction(input)
// expect(input).toEqual(inputCopy)
})
})
// --------------------------------------------------------------------------
// Array Handling (if applicable)
// --------------------------------------------------------------------------
describe('Array Handling', () => {
it('should process all elements', () => {
// expect(utilityFunction([1, 2, 3])).toEqual([2, 4, 6])
})
it('should handle single element array', () => {
// expect(utilityFunction([1])).toEqual([2])
})
it('should preserve order', () => {
// expect(utilityFunction(['c', 'a', 'b'])).toEqual(['c', 'a', 'b'])
})
})
})
================================================
FILE: .agents/skills/frontend-testing/references/async-testing.md
================================================
# Async Testing Guide
## Core Async Patterns
### 1. waitFor - Wait for Condition
```typescript
import { render, screen, waitFor } from '@testing-library/react'
it('should load and display data', async () => {
render(<DataComponent />)
// Wait for element to appear
await waitFor(() => {
expect(screen.getByText('Loaded Data')).toBeInTheDocument()
})
})
it('should hide loading spinner after load', async () => {
render(<DataComponent />)
// Wait for element to disappear
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument()
})
})
```
### 2. findBy\* - Async Queries
```typescript
it('should show user name after fetch', async () => {
render(<UserProfile />)
// findBy returns a promise, auto-waits up to 1000ms
const userName = await screen.findByText('John Doe')
expect(userName).toBeInTheDocument()
// findByRole with options
const button = await screen.findByRole('button', { name: /submit/i })
expect(button).toBeEnabled()
})
```
### 3. userEvent for Async Interactions
```typescript
import userEvent from '@testing-library/user-event'
it('should submit form', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn()
render(<Form onSubmit={onSubmit} />)
// userEvent methods are async
await user.type(screen.getByLabelText('Email'), 'test@example.com')
await user.click(screen.getByRole('button', { name: /submit/i }))
await waitFor(() => {
expect(onSubmit).toHaveBeenCalledWith({ email: 'test@example.com' })
})
})
```
## Fake Timers
### When to Use Fake Timers
- Testing components with `setTimeout`/`setInterval`
- Testing debounce/throttle behavior
- Testing animations or delayed transitions
- Testing polling or retry logic
### Basic Fake Timer Setup
```typescript
describe('Debounced Search', () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('should debounce search input', async () => {
const onSearch = vi.fn()
render(<SearchInput onSearch={onSearch} debounceMs={300} />)
// Type in the input
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'query' } })
// Search not called immediately
expect(onSearch).not.toHaveBeenCalled()
// Advance timers
vi.advanceTimersByTime(300)
// Now search is called
expect(onSearch).toHaveBeenCalledWith('query')
})
})
```
### Fake Timers with Async Code
```typescript
it('should retry on failure', async () => {
vi.useFakeTimers()
const fetchData = vi.fn()
.mockRejectedValueOnce(new Error('Network error'))
.mockResolvedValueOnce({ data: 'success' })
render(<RetryComponent fetchData={fetchData} retryDelayMs={1000} />)
// First call fails
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(1)
})
// Advance timer for retry
vi.advanceTimersByTime(1000)
// Second call succeeds
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(2)
expect(screen.getByText('success')).toBeInTheDocument()
})
vi.useRealTimers()
})
```
### Common Fake Timer Utilities
```typescript
// Run all pending timers
vi.runAllTimers()
// Run only pending timers (not new ones created during execution)
vi.runOnlyPendingTimers()
// Advance by specific time
vi.advanceTimersByTime(1000)
// Get current fake time
Date.now()
// Clear all timers
vi.clearAllTimers()
```
## API Testing Patterns
### Loading → Success → Error States
```typescript
describe('DataFetcher', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should show loading state', () => {
mockedApi.fetchData.mockImplementation(() => new Promise(() => {})) // Never resolves
render(<DataFetcher />)
expect(screen.getByTestId('loading-spinner')).toBeInTheDocument()
})
it('should show data on success', async () => {
mockedApi.fetchData.mockResolvedValue({ items: ['Item 1', 'Item 2'] })
render(<DataFetcher />)
// Use findBy* for multiple async elements (better error messages than waitFor with multiple assertions)
const item1 = await screen.findByText('Item 1')
const item2 = await screen.findByText('Item 2')
expect(item1).toBeInTheDocument()
expect(item2).toBeInTheDocument()
expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument()
})
it('should show error on failure', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Failed to fetch'))
render(<DataFetcher />)
await waitFor(() => {
expect(screen.getByText(/failed to fetch/i)).toBeInTheDocument()
})
})
it('should retry on error', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
render(<DataFetcher />)
await waitFor(() => {
expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
})
mockedApi.fetchData.mockResolvedValue({ items: ['Item 1'] })
fireEvent.click(screen.getByRole('button', { name: /retry/i }))
await waitFor(() => {
expect(screen.getByText('Item 1')).toBeInTheDocument()
})
})
})
```
### Testing Mutations
```typescript
it('should submit form and show success', async () => {
const user = userEvent.setup()
mockedApi.createItem.mockResolvedValue({ id: '1', name: 'New Item' })
render(<CreateItemForm />)
await user.type(screen.getByLabelText('Name'), 'New Item')
await user.click(screen.getByRole('button', { name: /create/i }))
// Button should be disabled during submission
expect(screen.getByRole('button', { name: /creating/i })).toBeDisabled()
await waitFor(() => {
expect(screen.getByText(/created successfully/i)).toBeInTheDocument()
})
expect(mockedApi.createItem).toHaveBeenCalledWith({ name: 'New Item' })
})
```
## useEffect Testing
### Testing Effect Execution
```typescript
it('should fetch data on mount', async () => {
const fetchData = vi.fn().mockResolvedValue({ data: 'test' })
render(<ComponentWithEffect fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(1)
})
})
```
### Testing Effect Dependencies
```typescript
it('should refetch when id changes', async () => {
const fetchData = vi.fn().mockResolvedValue({ data: 'test' })
const { rerender } = render(<ComponentWithEffect id="1" fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledWith('1')
})
rerender(<ComponentWithEffect id="2" fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledWith('2')
expect(fetchData).toHaveBeenCalledTimes(2)
})
})
```
### Testing Effect Cleanup
```typescript
it('should cleanup subscription on unmount', () => {
const subscribe = vi.fn()
const unsubscribe = vi.fn()
subscribe.mockReturnValue(unsubscribe)
const { unmount } = render(<SubscriptionComponent subscribe={subscribe} />)
expect(subscribe).toHaveBeenCalledTimes(1)
unmount()
expect(unsubscribe).toHaveBeenCalledTimes(1)
})
```
## Common Async Pitfalls
### ❌ Don't: Forget to await
```typescript
// Bad - test may pass even if assertion fails
it('should load data', () => {
render(<Component />)
waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
// Good - properly awaited
it('should load data', async () => {
render(<Component />)
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
```
### ❌ Don't: Use multiple assertions in single waitFor
```typescript
// Bad - if first assertion fails, won't know about second
await waitFor(() => {
expect(screen.getByText('Title')).toBeInTheDocument()
expect(screen.getByText('Description')).toBeInTheDocument()
})
// Good - separate waitFor or use findBy
const title = await screen.findByText('Title')
const description = await screen.findByText('Description')
expect(title).toBeInTheDocument()
expect(description).toBeInTheDocument()
```
### ❌ Don't: Mix fake timers with real async
```typescript
// Bad - fake timers don't work well with real Promises
vi.useFakeTimers()
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
}) // May timeout!
// Good - use runAllTimers or advanceTimersByTime
vi.useFakeTimers()
render(<Component />)
vi.runAllTimers()
expect(screen.getByText('Data')).toBeInTheDocument()
```
================================================
FILE: .agents/skills/frontend-testing/references/checklist.md
================================================
# Test Generation Checklist
Use this checklist when generating or reviewing tests for Dify frontend components.
## Pre-Generation
- [ ] Read the component source code completely
- [ ] Identify component type (component, hook, utility, page)
- [ ] Run `pnpm analyze-component <path>` if available
- [ ] Note complexity score and features detected
- [ ] Check for existing tests in the same directory
- [ ] **Identify ALL files in the directory** that need testing (not just index)
## Testing Strategy
### ⚠️ Incremental Workflow (CRITICAL for Multi-File)
- [ ] **NEVER generate all tests at once** - process one file at a time
- [ ] Order files by complexity: utilities → hooks → simple → complex → integration
- [ ] Create a todo list to track progress before starting
- [ ] For EACH file: write → run test → verify pass → then next
- [ ] **DO NOT proceed** to next file until current one passes
### Path-Level Coverage
- [ ] **Test ALL files** in the assigned directory/path
- [ ] List all components, hooks, utilities that need coverage
- [ ] Decide: single spec file (integration) or multiple spec files (unit)
### Complexity Assessment
- [ ] Run `pnpm analyze-component <path>` for complexity score
- [ ] **Complexity > 50**: Consider refactoring before testing
- [ ] **500+ lines**: Consider splitting before testing
- [ ] **30-50 complexity**: Use multiple describe blocks, organized structure
### Integration vs Mocking
- [ ] **DO NOT mock base components** (`Loading`, `Button`, `Tooltip`, etc.)
- [ ] Import real project components instead of mocking
- [ ] Only mock: API calls, complex context providers, third-party libs with side effects
- [ ] Prefer integration testing when using single spec file
## Required Test Sections
### All Components MUST Have
- [ ] **Rendering tests** - Component renders without crashing
- [ ] **Props tests** - Required props, optional props, default values
- [ ] **Edge cases** - null, undefined, empty values, boundaries
### Conditional Sections (Add When Feature Present)
| Feature | Add Tests For |
|---------|---------------|
| `useState` | Initial state, transitions, cleanup |
| `useEffect` | Execution, dependencies, cleanup |
| Event handlers | onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
| `useCallback`/`useMemo` | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
## Code Quality Checklist
### Structure
- [ ] Uses `describe` blocks to group related tests
- [ ] Test names follow `should <behavior> when <condition>` pattern
- [ ] AAA pattern (Arrange-Act-Assert) is clear
- [ ] Comments explain complex test scenarios
### Mocks
- [ ] **DO NOT mock base components** (`@/app/components/base/*`)
- [ ] `vi.clearAllMocks()` in `beforeEach` (not `afterEach`)
- [ ] Shared mock state reset in `beforeEach`
- [ ] i18n uses global mock (auto-loaded in `web/vitest.setup.ts`); only override locally for custom translations
- [ ] Router mocks match actual Next.js API
- [ ] Mocks reflect actual component conditional behavior
- [ ] Only mock: API services, complex context providers, third-party libs
- [ ] For `nuqs` URL-state tests, wrap with `NuqsTestingAdapter` (prefer `web/test/nuqs-testing.tsx`)
- [ ] For `nuqs` URL-state tests, assert `onUrlUpdate` payload (`searchParams`, `options.history`)
- [ ] If custom `nuqs` parser exists, add round-trip tests for encoded edge cases (`%2F`, `%25`, spaces, legacy encoded values)
### Queries
- [ ] Prefer semantic queries (`getByRole`, `getByLabelText`)
- [ ] Use `queryBy*` for absence assertions
- [ ] Use `findBy*` for async elements
- [ ] `getByTestId` only as last resort
### Async
- [ ] All async tests use `async/await`
- [ ] `waitFor` wraps async assertions
- [ ] Fake timers properly setup/teardown
- [ ] No floating promises
### TypeScript
- [ ] No `any` types without justification
- [ ] Mock data uses actual types from source
- [ ] Factory functions have proper return types
## Coverage Goals (Per File)
For the current file being tested:
- [ ] 100% function coverage
- [ ] 100% statement coverage
- [ ] >95% branch coverage
- [ ] >95% line coverage
## Post-Generation (Per File)
**Run these checks after EACH test file, not just at the end:**
- [ ] Run `pnpm test path/to/file.spec.tsx` - **MUST PASS before next file**
- [ ] Fix any failures immediately
- [ ] Mark file as complete in todo list
- [ ] Only then proceed to next file
### After All Files Complete
- [ ] Run full directory test: `pnpm test path/to/directory/`
- [ ] Check coverage report: `pnpm test:coverage`
- [ ] Run `pnpm lint:fix` on all test files
- [ ] Run `pnpm type-check:tsgo`
## Common Issues to Watch
### False Positives
```typescript
// ❌ Mock doesn't match actual behavior
vi.mock('./Component', () => () => <div>Mocked</div>)
// ✅ Mock matches actual conditional logic
vi.mock('./Component', () => ({ isOpen }: any) =>
isOpen ? <div>Content</div> : null
)
```
### State Leakage
```typescript
// ❌ Shared state not reset
let mockState = false
vi.mock('./useHook', () => () => mockState)
// ✅ Reset in beforeEach
beforeEach(() => {
mockState = false
})
```
### Async Race Conditions
```typescript
// ❌ Not awaited
it('loads data', () => {
render(<Component />)
expect(screen.getByText('Data')).toBeInTheDocument()
})
// ✅ Properly awaited
it('loads data', async () => {
render(<Component />)
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
```
### Missing Edge Cases
Always test these scenarios:
- `null` / `undefined` inputs
- Empty strings / arrays / objects
- Boundary values (0, -1, MAX_INT)
- Error states
- Loading states
- Disabled states
## Quick Commands
```bash
# Run specific test
pnpm test path/to/file.spec.tsx
# Run with coverage
pnpm test:coverage path/to/file.spec.tsx
# Watch mode
pnpm test:watch path/to/file.spec.tsx
# Update snapshots (use sparingly)
pnpm test -u path/to/file.spec.tsx
# Analyze component
pnpm analyze-component path/to/component.tsx
# Review existing test
pnpm analyze-component path/to/component.tsx --review
```
================================================
FILE: .agents/skills/frontend-testing/references/common-patterns.md
================================================
# Common Testing Patterns
## Query Priority
Use queries in this order (most to least preferred):
```typescript
// 1. getByRole - Most recommended (accessibility)
screen.getByRole('button', { name: /submit/i })
screen.getByRole('textbox', { name: /email/i })
screen.getByRole('heading', { level: 1 })
// 2. getByLabelText - Form fields
screen.getByLabelText('Email address')
screen.getByLabelText(/password/i)
// 3. getByPlaceholderText - When no label
screen.getByPlaceholderText('Search...')
// 4. getByText - Non-interactive elements
screen.getByText('Welcome to Dify')
screen.getByText(/loading/i)
// 5. getByDisplayValue - Current input value
screen.getByDisplayValue('current value')
// 6. getByAltText - Images
screen.getByAltText('Company logo')
// 7. getByTitle - Tooltip elements
screen.getByTitle('Close')
// 8. getByTestId - Last resort only!
screen.getByTestId('custom-element')
```
## Event Handling Patterns
### Click Events
```typescript
// Basic click
fireEvent.click(screen.getByRole('button'))
// With userEvent (preferred for realistic interaction)
const user = userEvent.setup()
await user.click(screen.getByRole('button'))
// Double click
await user.dblClick(screen.getByRole('button'))
// Right click
await user.pointer({ keys: '[MouseRight]', target: screen.getByRole('button') })
```
### Form Input
```typescript
const user = userEvent.setup()
// Type in input
await user.type(screen.getByRole('textbox'), 'Hello World')
// Clear and type
await user.clear(screen.getByRole('textbox'))
await user.type(screen.getByRole('textbox'), 'New value')
// Select option
await user.selectOptions(screen.getByRole('combobox'), 'option-value')
// Check checkbox
await user.click(screen.getByRole('checkbox'))
// Upload file
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
```
### Keyboard Events
```typescript
const user = userEvent.setup()
// Press Enter
await user.keyboard('{Enter}')
// Press Escape
await user.keyboard('{Escape}')
// Keyboard shortcut
await user.keyboard('{Control>}a{/Control}') // Ctrl+A
// Tab navigation
await user.tab()
// Arrow keys
await user.keyboard('{ArrowDown}')
await user.keyboard('{ArrowUp}')
```
## Component State Testing
### Testing State Transitions
```typescript
describe('Counter', () => {
it('should increment count', async () => {
const user = userEvent.setup()
render(<Counter initialCount={0} />)
// Initial state
expect(screen.getByText('Count: 0')).toBeInTheDocument()
// Trigger transition
await user.click(screen.getByRole('button', { name: /increment/i }))
// New state
expect(screen.getByText('Count: 1')).toBeInTheDocument()
})
})
```
### Testing Controlled Components
```typescript
describe('ControlledInput', () => {
it('should call onChange with new value', async () => {
const user = userEvent.setup()
const handleChange = vi.fn()
render(<ControlledInput value="" onChange={handleChange} />)
await user.type(screen.getByRole('textbox'), 'a')
expect(handleChange).toHaveBeenCalledWith('a')
})
it('should display controlled value', () => {
render(<ControlledInput value="controlled" onChange={vi.fn()} />)
expect(screen.getByRole('textbox')).toHaveValue('controlled')
})
})
```
## Conditional Rendering Testing
```typescript
describe('ConditionalComponent', () => {
it('should show loading state', () => {
render(<DataDisplay isLoading={true} data={null} />)
expect(screen.getByText(/loading/i)).toBeInTheDocument()
expect(screen.queryByTestId('data-content')).not.toBeInTheDocument()
})
it('should show error state', () => {
render(<DataDisplay isLoading={false} data={null} error="Failed to load" />)
expect(screen.getByText(/failed to load/i)).toBeInTheDocument()
})
it('should show data when loaded', () => {
render(<DataDisplay isLoading={false} data={{ name: 'Test' }} />)
expect(screen.getByText('Test')).toBeInTheDocument()
})
it('should show empty state when no data', () => {
render(<DataDisplay isLoading={false} data={[]} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
})
```
## List Rendering Testing
```typescript
describe('ItemList', () => {
const items = [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
{ id: '3', name: 'Item 3' },
]
it('should render all items', () => {
render(<ItemList items={items} />)
expect(screen.getAllByRole('listitem')).toHaveLength(3)
items.forEach(item => {
expect(screen.getByText(item.name)).toBeInTheDocument()
})
})
it('should handle item selection', async () => {
const user = userEvent.setup()
const onSelect = vi.fn()
render(<ItemList items={items} onSelect={onSelect} />)
await user.click(screen.getByText('Item 2'))
expect(onSelect).toHaveBeenCalledWith(items[1])
})
it('should handle empty list', () => {
render(<ItemList items={[]} />)
expect(screen.getByText(/no items/i)).toBeInTheDocument()
})
})
```
## Modal/Dialog Testing
```typescript
describe('Modal', () => {
it('should not render when closed', () => {
render(<Modal isOpen={false} onClose={vi.fn()} />)
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
it('should render when open', () => {
render(<Modal isOpen={true} onClose={vi.fn()} />)
expect(screen.getByRole('dialog')).toBeInTheDocument()
})
it('should call onClose when clicking overlay', async () => {
const user = userEvent.setup()
const handleClose = vi.fn()
render(<Modal isOpen={true} onClose={handleClose} />)
await user.click(screen.getByTestId('modal-overlay'))
expect(handleClose).toHaveBeenCalled()
})
it('should call onClose when pressing Escape', async () => {
const user = userEvent.setup()
const handleClose = vi.fn()
render(<Modal isOpen={true} onClose={handleClose} />)
await user.keyboard('{Escape}')
expect(handleClose).toHaveBeenCalled()
})
it('should trap focus inside modal', async () => {
const user = userEvent.setup()
render(
<Modal isOpen={true} onClose={vi.fn()}>
<button>First</button>
<button>Second</button>
</Modal>
)
// Focus should cycle within modal
await user.tab()
expect(screen.getByText('First')).toHaveFocus()
await user.tab()
expect(screen.getByText('Second')).toHaveFocus()
await user.tab()
expect(screen.getByText('First')).toHaveFocus() // Cycles back
})
})
```
## Form Testing
```typescript
describe('LoginForm', () => {
it('should submit valid form', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn()
render(<LoginForm onSubmit={onSubmit} />)
await user.type(screen.getByLabelText(/email/i), 'test@example.com')
await user.type(screen.getByLabelText(/password/i), 'password123')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123',
})
})
it('should show validation errors', async () => {
const user = userEvent.setup()
render(<LoginForm onSubmit={vi.fn()} />)
// Submit empty form
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByText(/email is required/i)).toBeInTheDocument()
expect(screen.getByText(/password is required/i)).toBeInTheDocument()
})
it('should validate email format', async () => {
const user = userEvent.setup()
render(<LoginForm onSubmit={vi.fn()} />)
await user.type(screen.getByLabelText(/email/i), 'invalid-email')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByText(/invalid email/i)).toBeInTheDocument()
})
it('should disable submit button while submitting', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn(() => new Promise(resolve => setTimeout(resolve, 100)))
render(<LoginForm onSubmit={onSubmit} />)
await user.type(screen.getByLabelText(/email/i), 'test@example.com')
await user.type(screen.getByLabelText(/password/i), 'password123')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByRole('button', { name: /signing in/i })).toBeDisabled()
await waitFor(() => {
expect(screen.getByRole('button', { name: /sign in/i })).toBeEnabled()
})
})
})
```
## Data-Driven Tests with test.each
```typescript
describe('StatusBadge', () => {
test.each([
['success', 'bg-green-500'],
['warning', 'bg-yellow-500'],
['error', 'bg-red-500'],
['info', 'bg-blue-500'],
])('should apply correct class for %s status', (status, expectedClass) => {
render(<StatusBadge status={status} />)
expect(screen.getByTestId('status-badge')).toHaveClass(expectedClass)
})
test.each([
{ input: null, expected: 'Unknown' },
{ input: undefined, expected: 'Unknown' },
{ input: '', expected: 'Unknown' },
{ input: 'invalid', expected: 'Unknown' },
])('should show "Unknown" for invalid input: $input', ({ input, expected }) => {
render(<StatusBadge status={input} />)
expect(screen.getByText(expected)).toBeInTheDocument()
})
})
```
## Debugging Tips
```typescript
// Print entire DOM
screen.debug()
// Print specific element
screen.debug(screen.getByRole('button'))
// Log testing playground URL
screen.logTestingPlaygroundURL()
// Pretty print DOM
import { prettyDOM } from '@testing-library/react'
console.log(prettyDOM(screen.getByRole('dialog')))
// Check available roles
import { getRoles } from '@testing-library/react'
console.log(getRoles(container))
```
## Common Mistakes to Avoid
### ❌ Don't Use Implementation Details
```typescript
// Bad - testing implementation
expect(component.state.isOpen).toBe(true)
expect(wrapper.find('.internal-class').length).toBe(1)
// Good - testing behavior
expect(screen.getByRole('dialog')).toBeInTheDocument()
```
### ❌ Don't Forget Cleanup
```typescript
// Bad - may leak state between tests
it('test 1', () => {
render(<Component />)
})
// Good - cleanup is automatic with RTL, but reset mocks
beforeEach(() => {
vi.clearAllMocks()
})
```
### ❌ Don't Use Exact String Matching (Prefer Black-Box Assertions)
```typescript
// ❌ Bad - hardcoded strings are brittle
expect(screen.getByText('Submit Form')).toBeInTheDocument()
expect(screen.getByText('Loading...')).toBeInTheDocument()
// ✅ Good - role-based queries (most semantic)
expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument()
expect(screen.getByRole('status')).toBeInTheDocument()
// ✅ Good - pattern matching (flexible)
expect(screen.getByText(/submit/i)).toBeInTheDocument()
expect(screen.getByText(/loading/i)).toBeInTheDocument()
// ✅ Good - test behavior, not exact UI text
expect(screen.getByRole('button')).toBeDisabled()
expect(screen.getByRole('alert')).toBeInTheDocument()
```
**Why prefer black-box assertions?**
- Text content may change (i18n, copy updates)
- Role-based queries test accessibility
- Pattern matching is resilient to minor changes
- Tests focus on behavior, not implementation details
### ❌ Don't Assert on Absence Without Query
```typescript
// Bad - throws if not found
expect(screen.getByText('Error')).not.toBeInTheDocument() // Error!
// Good - use queryBy for absence assertions
expect(screen.queryByText('Error')).not.toBeInTheDocument()
```
================================================
FILE: .agents/skills/frontend-testing/references/domain-components.md
================================================
# Domain-Specific Component Testing
This guide covers testing patterns for Dify's domain-specific components.
## Workflow Components (`workflow/`)
Workflow components handle node configuration, data flow, and graph operations.
### Key Test Areas
1. **Node Configuration**
1. **Data Validation**
1. **Variable Passing**
1. **Edge Connections**
1. **Error Handling**
### Example: Node Configuration Panel
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import NodeConfigPanel from './node-config-panel'
import { createMockNode, createMockWorkflowContext } from '@/__mocks__/workflow'
// Mock workflow context
vi.mock('@/app/components/workflow/hooks', () => ({
useWorkflowStore: () => mockWorkflowStore,
useNodesInteractions: () => mockNodesInteractions,
}))
let mockWorkflowStore = {
nodes: [],
edges: [],
updateNode: vi.fn(),
}
let mockNodesInteractions = {
handleNodeSelect: vi.fn(),
handleNodeDelete: vi.fn(),
}
describe('NodeConfigPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
mockWorkflowStore = {
nodes: [],
edges: [],
updateNode: vi.fn(),
}
})
describe('Node Configuration', () => {
it('should render node type selector', () => {
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
expect(screen.getByLabelText(/model/i)).toBeInTheDocument()
})
it('should update node config on change', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
await user.selectOptions(screen.getByLabelText(/model/i), 'gpt-4')
expect(mockWorkflowStore.updateNode).toHaveBeenCalledWith(
node.id,
expect.objectContaining({ model: 'gpt-4' })
)
})
})
describe('Data Validation', () => {
it('should show error for invalid input', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'code' })
render(<NodeConfigPanel node={node} />)
// Enter invalid code
const codeInput = screen.getByLabelText(/code/i)
await user.clear(codeInput)
await user.type(codeInput, 'invalid syntax {{{')
await waitFor(() => {
expect(screen.getByText(/syntax error/i)).toBeInTheDocument()
})
})
it('should validate required fields', async () => {
const node = createMockNode({ type: 'http', data: { url: '' } })
render(<NodeConfigPanel node={node} />)
fireEvent.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(screen.getByText(/url is required/i)).toBeInTheDocument()
})
})
})
describe('Variable Passing', () => {
it('should display available variables from upstream nodes', () => {
const upstreamNode = createMockNode({
id: 'node-1',
type: 'start',
data: { outputs: [{ name: 'user_input', type: 'string' }] },
})
const currentNode = createMockNode({
id: 'node-2',
type: 'llm',
})
mockWorkflowStore.nodes = [upstreamNode, currentNode]
mockWorkflowStore.edges = [{ source: 'node-1', target: 'node-2' }]
render(<NodeConfigPanel node={currentNode} />)
// Variable selector should show upstream variables
fireEvent.click(screen.getByRole('button', { name: /add variable/i }))
expect(screen.getByText('user_input')).toBeInTheDocument()
})
it('should insert variable into prompt template', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
// Click variable button
await user.click(screen.getByRole('button', { name: /insert variable/i }))
await user.click(screen.getByText('user_input'))
const promptInput = screen.getByLabelText(/prompt/i)
expect(promptInput).toHaveValue(expect.stringContaining('{{user_input}}'))
})
})
})
```
## Dataset Components (`dataset/`)
Dataset components handle file uploads, data display, and search/filter operations.
### Key Test Areas
1. **File Upload**
1. **File Type Validation**
1. **Pagination**
1. **Search & Filtering**
1. **Data Format Handling**
### Example: Document Uploader
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import DocumentUploader from './document-uploader'
vi.mock('@/service/datasets', () => ({
uploadDocument: vi.fn(),
parseDocument: vi.fn(),
}))
import * as datasetService from '@/service/datasets'
const mockedService = vi.mocked(datasetService)
describe('DocumentUploader', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('File Upload', () => {
it('should accept valid file types', async () => {
const user = userEvent.setup()
const onUpload = vi.fn()
mockedService.uploadDocument.mockResolvedValue({ id: 'doc-1' })
render(<DocumentUploader onUpload={onUpload} />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
const input = screen.getByLabelText(/upload/i)
await user.upload(input, file)
await waitFor(() => {
expect(mockedService.uploadDocument).toHaveBeenCalledWith(
expect.any(FormData)
)
})
})
it('should reject invalid file types', async () => {
const user = userEvent.setup()
render(<DocumentUploader />)
const file = new File(['content'], 'test.exe', { type: 'application/x-msdownload' })
const input = screen.getByLabelText(/upload/i)
await user.upload(input, file)
expect(screen.getByText(/unsupported file type/i)).toBeInTheDocument()
expect(mockedService.uploadDocument).not.toHaveBeenCalled()
})
it('should show upload progress', async () => {
const user = userEvent.setup()
// Mock upload with progress
mockedService.uploadDocument.mockImplementation(() => {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: 'doc-1' }), 100)
})
})
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
expect(screen.getByRole('progressbar')).toBeInTheDocument()
await waitFor(() => {
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument()
})
})
})
describe('Error Handling', () => {
it('should handle upload failure', async () => {
const user = userEvent.setup()
mockedService.uploadDocument.mockRejectedValue(new Error('Upload failed'))
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
await waitFor(() => {
expect(screen.getByText(/upload failed/i)).toBeInTheDocument()
})
})
it('should allow retry after failure', async () => {
const user = userEvent.setup()
mockedService.uploadDocument
.mockRejectedValueOnce(new Error('Network error'))
.mockResolvedValueOnce({ id: 'doc-1' })
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
await waitFor(() => {
expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
})
await user.click(screen.getByRole('button', { name: /retry/i }))
await waitFor(() => {
expect(screen.getByText(/uploaded successfully/i)).toBeInTheDocument()
})
})
})
})
```
### Example: Document List with Pagination
```typescript
describe('DocumentList', () => {
describe('Pagination', () => {
it('should load first page on mount', async () => {
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '1', name: 'Doc 1' }],
total: 50,
page: 1,
pageSize: 10,
})
render(<DocumentList datasetId="ds-1" />)
await waitFor(() => {
expect(screen.getByText('Doc 1')).toBeInTheDocument()
})
expect(mockedService.getDocuments).toHaveBeenCalledWith('ds-1', { page: 1 })
})
it('should navigate to next page', async () => {
const user = userEvent.setup()
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '1', name: 'Doc 1' }],
total: 50,
page: 1,
pageSize: 10,
})
render(<DocumentList datasetId="ds-1" />)
await waitFor(() => {
expect(screen.getByText('Doc 1')).toBeInTheDocument()
})
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '11', name: 'Doc 11' }],
total: 50,
page: 2,
pageSize: 10,
})
await user.click(screen.getByRole('button', { name: /next/i }))
await waitFor(() => {
expect(screen.getByText('Doc 11')).toBeInTheDocument()
})
})
})
describe('Search & Filtering', () => {
it('should filter by search query', async () => {
const user = userEvent.setup()
vi.useFakeTimers()
render(<DocumentList datasetId="ds-1" />)
await user.type(screen.getByPlaceholderText(/search/i), 'test query')
// Debounce
vi.advanceTimersByTime(300)
await waitFor(() => {
expect(mockedService.getDocuments).toHaveBeenCalledWith(
'ds-1',
expect.objectContaining({ search: 'test query' })
)
})
vi.useRealTimers()
})
})
})
```
## Configuration Components (`app/configuration/`, `config/`)
Configuration components handle forms, validation, and data persistence.
### Key Test Areas
1. **Form Validation**
1. **Save/Reset**
1. **Required vs Optional Fields**
1. **Configuration Persistence**
1. **Error Feedback**
### Example: App Configuration Form
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import AppConfigForm from './app-config-form'
vi.mock('@/service/apps', () => ({
updateAppConfig: vi.fn(),
getAppConfig: vi.fn(),
}))
import * as appService from '@/service/apps'
const mockedService = vi.mocked(appService)
describe('AppConfigForm', () => {
const defaultConfig = {
name: 'My App',
description: '',
icon: 'default',
openingStatement: '',
}
beforeEach(() => {
vi.clearAllMocks()
mockedService.getAppConfig.mockResolvedValue(defaultConfig)
})
describe('Form Validation', () => {
it('should require app name', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Clear name field
await user.clear(screen.getByLabelText(/name/i))
await user.click(screen.getByRole('button', { name: /save/i }))
expect(screen.getByText(/name is required/i)).toBeInTheDocument()
expect(mockedService.updateAppConfig).not.toHaveBeenCalled()
})
it('should validate name length', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toBeInTheDocument()
})
// Enter very long name
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'a'.repeat(101))
expect(screen.getByText(/name must be less than 100 characters/i)).toBeInTheDocument()
})
it('should allow empty optional fields', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockResolvedValue({ success: true })
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Leave description empty (optional)
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(mockedService.updateAppConfig).toHaveBeenCalled()
})
})
})
describe('Save/Reset Functionality', () => {
it('should save configuration', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockResolvedValue({ success: true })
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'Updated App')
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(mockedService.updateAppConfig).toHaveBeenCalledWith(
'app-1',
expect.objectContaining({ name: 'Updated App' })
)
})
expect(screen.getByText(/saved successfully/i)).toBeInTheDocument()
})
it('should reset to default values', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Make changes
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'Changed Name')
// Reset
await user.click(screen.getByRole('button', { name: /reset/i }))
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
it('should show unsaved changes warning', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Make changes
await user.type(screen.getByLabelText(/name/i), ' Updated')
expect(screen.getByText(/unsaved changes/i)).toBeInTheDocument()
})
})
describe('Error Handling', () => {
it('should show error on save failure', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockRejectedValue(new Error('Server error'))
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(screen.getByText(/failed to save/i)).toBeInTheDocument()
})
})
})
})
```
================================================
FILE: .agents/skills/frontend-testing/references/mocking.md
================================================
# Mocking Guide for Dify Frontend Tests
## ⚠️ Important: What NOT to Mock
### DO NOT Mock Base Components
**Never mock components from `@/app/components/base/`** such as:
- `Loading`, `Spinner`
- `Button`, `Input`, `Select`
- `Tooltip`, `Modal`, `Dropdown`
- `Icon`, `Badge`, `Tag`
**Why?**
- Base components will have their own dedicated tests
- Mocking them creates false positives (tests pass but real integration fails)
- Using real components tests actual integration behavior
```typescript
// ❌ WRONG: Don't mock base components
vi.mock('@/app/components/base/loading', () => () => <div>Loading</div>)
vi.mock('@/app/components/base/button', () => ({ children }: any) => <button>{children}</button>)
// ✅ CORRECT: Import and use real base components
import Loading from '@/app/components/base/loading'
import Button from '@/app/components/base/button'
// They will render normally in tests
```
### What TO Mock
Only mock these categories:
1. **API services** (`@/service/*`) - Network calls
1. **Complex context providers** - When setup is too difficult
1. **Third-party libraries with side effects** - `next/navigation`, external SDKs
1. **i18n** - Always mock to return keys
### Zustand Stores - DO NOT Mock Manually
**Zustand is globally mocked** in `web/vitest.setup.ts`. Use real stores with `setState()`:
```typescript
// ✅ CORRECT: Use real store, set test state
import { useAppStore } from '@/app/components/app/store'
useAppStore.setState({ appDetail: { id: 'test', name: 'Test' } })
render(<MyComponent />)
// ❌ WRONG: Don't mock the store module
vi.mock('@/app/components/app/store', () => ({ ... }))
```
See [Zustand Store Testing](#zustand-store-testing) section for full details.
## Mock Placement
| Location | Purpose |
|----------|---------|
| `web/vitest.setup.ts` | Global mocks shared by all tests (`react-i18next`, `next/image`, `zustand`) |
| `web/__mocks__/zustand.ts` | Zustand mock implementation (auto-resets stores after each test) |
| `web/__mocks__/` | Reusable mock factories shared across multiple test files |
| Test file | Test-specific mocks, inline with `vi.mock()` |
Modules are not mocked automatically. Use `vi.mock` in test files, or add global mocks in `web/vitest.setup.ts`.
**Note**: Zustand is special - it's globally mocked but you should NOT mock store modules manually. See [Zustand Store Testing](#zustand-store-testing).
## Essential Mocks
### 1. i18n (Auto-loaded via Global Mock)
A global mock is defined in `web/vitest.setup.ts` and is auto-loaded by Vitest setup.
The global mock provides:
- `useTranslation` - returns translation keys with namespace prefix
- `Trans` component - renders i18nKey and components
- `useMixedTranslation` (from `@/app/components/plugins/marketplace/hooks`)
- `useGetLanguage` (from `@/context/i18n`) - returns `'en-US'`
**Default behavior**: Most tests should use the global mock (no local override needed).
**For custom translations**: Use the helper function from `@/test/i18n-mock`:
```typescript
import { createReactI18nextMock } from '@/test/i18n-mock'
vi.mock('react-i18next', () => createReactI18nextMock({
'my.custom.key': 'Custom translation',
'button.save': 'Save',
}))
```
**Avoid**: Manually defining `useTranslation` mocks that just return the key - the global mock already does this.
### 2. Next.js Router
```typescript
const mockPush = vi.fn()
const mockReplace = vi.fn()
vi.mock('next/navigation', () => ({
useRouter: () => ({
push: mockPush,
replace: mockReplace,
back: vi.fn(),
prefetch: vi.fn(),
}),
usePathname: () => '/current-path',
useSearchParams: () => new URLSearchParams('?key=value'),
}))
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should navigate on click', () => {
render(<Component />)
fireEvent.click(screen.getByRole('button'))
expect(mockPush).toHaveBeenCalledWith('/expected-path')
})
})
```
### 2.1 `nuqs` Query State (Preferred: Testing Adapter)
For tests that validate URL query behavior, use `NuqsTestingAdapter` instead of mocking `nuqs` directly.
```typescript
import { renderHookWithNuqs } from '@/test/nuqs-testing'
it('should sync query to URL with push history', async () => {
const { result, onUrlUpdate } = renderHookWithNuqs(() => useMyQueryState(), {
searchParams: '?page=1',
})
act(() => {
result.current.setQuery({ page: 2 })
})
await waitFor(() => expect(onUrlUpdate).toHaveBeenCalled())
const update = onUrlUpdate.mock.calls[onUrlUpdate.mock.calls.length - 1][0]
expect(update.options.history).toBe('push')
expect(update.searchParams.get('page')).toBe('2')
})
```
Use direct `vi.mock('nuqs')` only when URL synchronization is intentionally out of scope.
### 3. Portal Components (with Shared State)
```typescript
// ⚠️ Important: Use shared state for components that depend on each other
let mockPortalOpenState = false
vi.mock('@/app/components/base/portal-to-follow-elem', () => ({
PortalToFollowElem: ({ children, open, ...props }: any) => {
mockPortalOpenState = open || false // Update shared state
return <div data-testid="portal" data-open={open}>{children}</div>
},
PortalToFollowElemContent: ({ children }: any) => {
// ✅ Matches actual: returns null when portal is closed
if (!mockPortalOpenState) return null
return <div data-testid="portal-content">{children}</div>
},
PortalToFollowElemTrigger: ({ children }: any) => (
<div data-testid="portal-trigger">{children}</div>
),
}))
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
mockPortalOpenState = false // ✅ Reset shared state
})
})
```
### 4. API Service Mocks
```typescript
import * as api from '@/service/api'
vi.mock('@/service/api')
const mockedApi = vi.mocked(api)
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
// Setup default mock implementation
mockedApi.fetchData.mockResolvedValue({ data: [] })
})
it('should show data on success', async () => {
mockedApi.fetchData.mockResolvedValue({ data: [{ id: 1 }] })
render(<Component />)
await waitFor(() => {
expect(screen.getByText('1')).toBeInTheDocument()
})
})
it('should show error on failure', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
render(<Component />)
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument()
})
})
})
```
### 5. HTTP Mocking with Nock
```typescript
import nock from 'nock'
const GITHUB_HOST = 'https://api.github.com'
const GITHUB_PATH = '/repos/owner/repo'
const mockGithubApi = (status: number, body: Record<string, unknown>, delayMs = 0) => {
return nock(GITHUB_HOST)
.get(GITHUB_PATH)
.delay(delayMs)
.reply(status, body)
}
describe('GithubComponent', () => {
afterEach(() => {
nock.cleanAll()
})
it('should display repo info', async () => {
mockGithubApi(200, { name: 'dify', stars: 1000 })
render(<GithubComponent />)
await waitFor(() => {
expect(screen.getByText('dify')).toBeInTheDocument()
})
})
it('should handle API error', async () => {
mockGithubApi(500, { message: 'Server error' })
render(<GithubComponent />)
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument()
})
})
})
```
### 6. Context Providers
```typescript
import { ProviderContext } from '@/context/provider-context'
import { createMockProviderContextValue, createMockPlan } from '@/__mocks__/provider-context'
describe('Component with Context', () => {
it('should render for free plan', () => {
const mockContext = createMockPlan('sandbox')
render(
<ProviderContext.Provider value={mockContext}>
<Component />
</ProviderContext.Provider>
)
expect(screen.getByText('Upgrade')).toBeInTheDocument()
})
it('should render for pro plan', () => {
const mockContext = createMockPlan('professional')
render(
<ProviderContext.Provider value={mockContext}>
<Component />
</ProviderContext.Provider>
)
expect(screen.queryByText('Upgrade')).not.toBeInTheDocument()
})
})
```
### 7. React Query
```typescript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const createTestQueryClient = () => new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
})
const renderWithQueryClient = (ui: React.ReactElement) => {
const queryClient = createTestQueryClient()
return render(
<QueryClientProvider client={queryClient}>
{ui}
</QueryClientProvider>
)
}
```
## Mock Best Practices
### ✅ DO
1. **Use real base components** - Import from `@/app/components/base/` directly
1. **Use real project components** - Prefer importing over mocking
1. **Use real Zustand stores** - Set test state via `store.setState()`
1. **Reset mocks in `beforeEach`**, not `afterEach`
1. **Match actual component behavior** in mocks (when mocking is necessary)
1. **Use factory functions** for complex mock data
1. **Import actual types** for type safety
1. **Reset shared mock state** in `beforeEach`
### ❌ DON'T
1. **Don't mock base components** (`Loading`, `Button`, `Tooltip`, etc.)
1. **Don't mock Zustand store modules** - Use real stores with `setState()`
1. Don't mock components you can import directly
1. Don't create overly simplified mocks that miss conditional logic
1. Don't forget to clean up nock after each test
1. Don't use `any` types in mocks without necessity
### Mock Decision Tree
```
Need to use a component in test?
│
├─ Is it from @/app/components/base/*?
│ └─ YES → Import real component, DO NOT mock
│
├─ Is it a project component?
│ └─ YES → Prefer importing real component
│ Only mock if setup is extremely complex
│
├─ Is it an API service (@/service/*)?
│ └─ YES → Mock it
│
├─ Is it a third-party lib with side effects?
│ └─ YES → Mock it (next/navigation, external SDKs)
│
├─ Is it a Zustand store?
│ └─ YES → DO NOT mock the module!
│ Use real store + setState() to set test state
│ (Global mock handles auto-reset)
│
└─ Is it i18n?
└─ YES → Uses shared mock (auto-loaded). Override only for custom translations
```
## Zustand Store Testing
### Global Zustand Mock (Auto-loaded)
Zustand is globally mocked in `web/vitest.setup.ts` following the [official Zustand testing guide](https://zustand.docs.pmnd.rs/guides/testing). The mock in `web/__mocks__/zustand.ts` provides:
- Real store behavior with `getState()`, `setState()`, `subscribe()` methods
- Automatic store reset after each test via `afterEach`
- Proper test isolation between tests
### ✅ Recommended: Use Real Stores (Official Best Practice)
**DO NOT mock store modules manually.** Import and use the real store, then use `setState()` to set test state:
```typescript
// ✅ CORRECT: Use real store with setState
import { useAppStore } from '@/app/components/app/store'
describe('MyComponent', () => {
it('should render app details', () => {
// Arrange: Set test state via setState
useAppStore.setState({
appDetail: {
id: 'test-app',
name: 'Test App',
mode: 'chat',
},
})
// Act
render(<MyComponent />)
// Assert
expect(screen.getByText('Test App')).toBeInTheDocument()
// Can also verify store state directly
expect(useAppStore.getState().appDetail?.name).toBe('Test App')
})
// No cleanup needed - global mock auto-resets after each test
})
```
### ❌ Avoid: Manual Store Module Mocking
Manual mocking conflicts with the global Zustand mock and loses store functionality:
```typescript
// ❌ WRONG: Don't mock the store module
vi.mock('@/app/components/app/store', () => ({
useStore: (selector) => mockSelector(selector), // Missing getState, setState!
}))
// ❌ WRONG: This conflicts with global zustand mock
vi.mock('@/app/components/workflow/store', () => ({
useWorkflowStore: vi.fn(() => mockState),
}))
```
**Problems with manual mocking:**
1. Loses `getState()`, `setState()`, `subscribe()` methods
1. Conflicts with global Zustand mock behavior
1. Requires manual maintenance of store API
1. Tests don't reflect actual store behavior
### When Manual Store Mocking is Necessary
In rare cases where the store has complex initialization or side effects, you can mock it, but ensure you provide the full store API:
```typescript
// If you MUST mock (rare), include full store API
const mockStore = {
appDetail: { id: 'test', name: 'Test' },
setAppDetail: vi.fn(),
}
vi.mock('@/app/components/app/store', () => ({
useStore: Object.assign(
(selector: (state: typeof mockStore) => unknown) => selector(mockStore),
{
getState: () => mockStore,
setState: vi.fn(),
subscribe: vi.fn(),
},
),
}))
```
### Store Testing Decision Tree
```
Need to test a component using Zustand store?
│
├─ Can you use the real store?
│ └─ YES → Use real store + setState (RECOMMENDED)
│ useAppStore.setState({ ... })
│
├─ Does the store have complex initialization/side effects?
│ └─ YES → Consider mocking, but include full API
│ (getState, setState, subscribe)
│
└─ Are you testing the store itself (not a component)?
└─ YES → Test store directly with getState/setState
const store = useMyStore
store.setState({ count: 0 })
store.getState().increment()
expect(store.getState().count).toBe(1)
```
### Example: Testing Store Actions
```typescript
import { useCounterStore } from '@/stores/counter'
describe('Counter Store', () => {
it('should increment count', () => {
// Initial state (auto-reset by global mock)
expect(useCounterStore.getState().count).toBe(0)
// Call action
useCounterStore.getState().increment()
// Verify state change
expect(useCounterStore.getState().count).toBe(1)
})
it('should reset to initial state', () => {
// Set some state
useCounterStore.setState({ count: 100 })
expect(useCounterStore.getState().count).toBe(100)
// After this test, global mock will reset to initial state
})
})
```
## Factory Function Pattern
```typescript
// __mocks__/data-factories.ts
import type { User, Project } from '@/types'
export const createMockUser = (overrides: Partial<User> = {}): User => ({
id: 'user-1',
name: 'Test User',
email: 'test@example.com',
role: 'member',
createdAt: new Date().toISOString(),
...overrides,
})
export const createMockProject = (overrides: Partial<Project> = {}): Project => ({
id: 'project-1',
name: 'Test Project',
description: 'A test project',
owner: createMockUser(),
members: [],
createdAt: new Date().toISOString(),
...overrides,
})
// Usage in tests
it('should display project owner', () => {
const project = createMockProject({
owner: createMockUser({ name: 'John Doe' }),
})
render(<ProjectCard project={project} />)
expect(screen.getByText('John Doe')).toBeInTheDocument()
})
```
================================================
FILE: .agents/skills/frontend-testing/references/workflow.md
================================================
# Testing Workflow Guide
This guide defines the workflow for generating tests, especially for complex components or directories with multiple files.
## Scope Clarification
This guide addresses **multi-file workflow** (how to process multiple test files). For coverage requirements within a single test file, see `web/docs/test.md` § Coverage Goals.
| Scope | Rule |
|-------|------|
| **Single file** | Complete coverage in one generation (100% function, >95% branch) |
| **Multi-file directory** | Process one file at a time, verify each before proceeding |
## ⚠️ Critical Rule: Incremental Approach for Multi-File Testing
When testing a **directory with multiple files**, **NEVER generate all test files at once.** Use an incremental, verify-as-you-go approach.
### Why Incremental?
| Batch Approach (❌) | Incremental Approach (✅) |
|---------------------|---------------------------|
| Generate 5+ tests at once | Generate 1 test at a time |
| Run tests only at the end | Run test immediately after each file |
| Multiple failures compound | Single point of failure, easy to debug |
| Hard to identify root cause | Clear cause-effect relationship |
| Mock issues affect many files | Mock issues caught early |
| Messy git history | Clean, atomic commits possible |
## Single File Workflow
When testing a **single component, hook, or utility**:
```
1. Read source code completely
2. Run `pnpm analyze-component <path>` (if available)
3. Check complexity score and features detected
4. Write the test file
5. Run test: `pnpm test <file>.spec.tsx`
6. Fix any failures
7. Verify coverage meets goals (100% function, >95% branch)
```
## Directory/Multi-File Workflow (MUST FOLLOW)
When testing a **directory or multiple files**, follow this strict workflow:
### Step 1: Analyze and Plan
1. **List all files** that need tests in the directory
1. **Categorize by complexity**:
- 🟢 **Simple**: Utility functions, simple hooks, presentational components
- 🟡 **Medium**: Components with state, effects, or event handlers
- 🔴 **Complex**: Components with API calls, routing, or many dependencies
1. **Order by dependency**: Test dependencies before dependents
1. **Create a todo list** to track progress
### Step 2: Determine Processing Order
Process files in this recommended order:
```
1. Utility functions (simplest, no React)
2. Custom hooks (isolated logic)
3. Simple presentational components (few/no props)
4. Medium complexity components (state, effects)
5. Complex components (API, routing, many deps)
6. Container/index components (integration tests - last)
```
**Rationale**:
- Simpler files help establish mock patterns
- Hooks used by components should be tested first
- Integration tests (index files) depend on child components working
### Step 3: Process Each File Incrementally
**For EACH file in the ordered list:**
```
┌─────────────────────────────────────────────┐
│ 1. Write test file │
│ 2. Run: pnpm test <file>.spec.tsx │
│ 3. If FAIL → Fix immediately, re-run │
│ 4. If PASS → Mark complete in todo list │
│ 5. ONLY THEN proceed to next file │
└─────────────────────────────────────────────┘
```
**DO NOT proceed to the next file until the current one passes.**
### Step 4: Final Verification
After all individual tests pass:
```bash
# Run all tests in the directory together
pnpm test path/to/directory/
# Check coverage
pnpm test:coverage path/to/directory/
```
## Component Complexity Guidelines
Use `pnpm analyze-component <path>` to assess complexity before testing.
### 🔴 Very Complex Components (Complexity > 50)
**Consider refactoring BEFORE testing:**
- Break component into smaller, testable pieces
- Extract complex logic into custom hooks
- Separate container and presentational layers
**If testing as-is:**
- Use integration tests for complex workflows
- Use `test.each()` for data-driven testing
- Multiple `describe` blocks for organization
- Consider testing major sections separately
### 🟡 Medium Complexity (Complexity 30-50)
- Group related tests in `describe` blocks
- Test integration scenarios between internal parts
- Focus on state transitions and side effects
- Use helper functions to reduce test complexity
### 🟢 Simple Components (Complexity < 30)
- Standard test structure
- Focus on props, rendering, and edge cases
- Usually straightforward to test
### 📏 Large Files (500+ lines)
Regardless of complexity score:
- **Strongly consider refactoring** before testing
- If testing as-is, test major sections separately
- Create helper functions for test setup
- May need multiple test files
## Todo List Format
When testing multiple files, use a todo list like this:
```
Testing: path/to/directory/
Ordered by complexity (simple → complex):
☐ utils/helper.ts [utility, simple]
☐ hooks/use-custom-hook.ts [hook, simple]
☐ empty-state.tsx [component, simple]
☐ item-card.tsx [component, medium]
☐ list.tsx [component, complex]
☐ index.tsx [integration]
Progress: 0/6 complete
```
Update status as you complete each:
- ☐ → ⏳ (in progress)
- ⏳ → ✅ (complete and verified)
- ⏳ → ❌ (blocked, needs attention)
## When to Stop and Verify
**Always run tests after:**
- Completing a test file
- Making changes to fix a failure
- Modifying shared mocks
- Updating test utilities or helpers
**Signs you should pause:**
- More than 2 consecutive test failures
- Mock-related errors appearing
- Unclear why a test is failing
- Test passing but coverage unexpectedly low
## Common Pitfalls to Avoid
### ❌ Don't: Generate Everything First
```
# BAD: Writing all files then testing
Write component-a.spec.tsx
Write component-b.spec.tsx
Write component-c.spec.tsx
Write component-d.spec.tsx
Run pnpm test ← Multiple failures, hard to debug
```
### ✅ Do: Verify Each Step
```
# GOOD: Incremental with verification
Write component-a.spec.tsx
Run pnpm test component-a.spec.tsx ✅
Write component-b.spec.tsx
Run pnpm test component-b.spec.tsx ✅
...continue...
```
### ❌ Don't: Skip Verification for "Simple" Components
Even simple components can have:
- Import errors
- Missing mock setup
- Incorrect assumptions about props
**Always verify, regardless of perceived simplicity.**
### ❌ Don't: Continue When Tests Fail
Failing tests compound:
- A mock issue in file A affects files B, C, D
- Fixing A later requires revisiting all dependent tests
- Time wasted on debugging cascading failures
**Fix failures immediately before proceeding.**
## Integration with Claude's Todo Feature
When using Claude for multi-file testing:
1. **Ask Claude to create a todo list** before starting
1. **Request one file at a time** or ensure Claude processes incrementally
1. **Verify each test passes** before asking for the next
1. **Mark todos complete** as you progress
Example prompt:
```
Test all components in `path/to/directory/`.
First, analyze the directory and create a todo list ordered by complexity.
Then, process ONE file at a time, waiting for my confirmation that tests pass
before proceeding to the next.
```
## Summary Checklist
Before starting multi-file testing:
- [ ] Listed all files needing tests
- [ ] Ordered by complexity (simple → complex)
- [ ] Created todo list for tracking
- [ ] Understand dependencies between files
During testing:
- [ ] Processing ONE file at a time
- [ ] Running tests after EACH file
- [ ] Fixing failures BEFORE proceeding
- [ ] Updating todo list progress
After completion:
- [ ] All individual tests pass
- [ ] Full directory test run passes
- [ ] Coverage goals met
- [ ] Todo list shows all complete
================================================
FILE: .claude/settings.json
================================================
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "npx -y block-no-verify@1.1.1"
}
]
}
]
}
}
================================================
FILE: .coveragerc
================================================
[run]
omit =
api/tests/*
api/migrations/*
api/core/rag/datasource/vdb/*
================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/python:3.12-bookworm
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install libgmp-dev libmpfr-dev libmpc-dev
================================================
FILE: .devcontainer/README.md
================================================
# Development with devcontainer
This project includes a devcontainer configuration that allows you to open the project in a container with a fully configured development environment.
Both frontend and backend environments are initialized when the container is started.
## GitHub Codespaces
[](https://codespaces.new/langgenius/dify)
you can simply click the button above to open this project in GitHub Codespaces.
For more info, check out the [GitHub documentation](https://docs.github.com/en/free-pro-team@latest/github/developing-online-with-codespaces/creating-a-codespace#creating-a-codespace).
## VS Code Dev Containers
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/langgenius/dify)
if you have VS Code installed, you can click the button above to open this project in VS Code Dev Containers.
You can learn more in the [Dev Containers documentation](https://code.visualstudio.com/docs/devcontainers/containers).
## Pros of Devcontainer
Unified Development Environment: By using devcontainers, you can ensure that all developers are developing in the same environment, reducing the occurrence of "it works on my machine" type of issues.
Quick Start: New developers can set up their development environment in a few simple steps, without spending a lot of time on environment configuration.
Isolation: Devcontainers isolate your project from your host operating system, reducing the chance of OS updates or other application installations impacting the development environment.
## Cons of Devcontainer
Learning Curve: For developers unfamiliar with Docker and VS Code, using devcontainers may be somewhat complex.
Performance Impact: While usually minimal, programs running inside a devcontainer may be slightly slower than those running directly on the host.
## Troubleshooting
if you see such error message when you open this project in codespaces:

a simple workaround is change `/signin` endpoint into another one, then login with GitHub account and close the tab, then change it back to `/signin` endpoint. Then all things will be fine.
The reason is `signin` endpoint is not allowed in codespaces, details can be found [here](https://github.com/orgs/community/discussions/5204)
================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/anaconda
{
"name": "Python 3.12",
"build": {
"context": "..",
"dockerfile": "Dockerfile"
},
"mounts": [
"source=dify-dev-tmp,target=/tmp,type=volume"
],
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "lts"
},
"ghcr.io/devcontainers-extra/features/npm-package:1": {
"package": "typescript",
"version": "latest"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"moby": true,
"azureDnsAutoDetection": true,
"installDockerBuildx": true,
"version": "latest",
"dockerDashComposeVersion": "v2"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.pylint",
"GitHub.copilot",
"ms-python.python"
]
}
},
"postStartCommand": "./.devcontainer/post_start_command.sh",
"postCreateCommand": "./.devcontainer/post_create_command.sh"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "python --version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
}
================================================
FILE: .devcontainer/noop.txt
================================================
This file copied into the container along with environment.yml* from the parent
folder. This file is included to prevents the Dockerfile COPY instruction from
failing if no environment.yml is found.
================================================
FILE: .devcontainer/post_create_command.sh
================================================
#!/bin/bash
WORKSPACE_ROOT=$(pwd)
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
corepack enable
cd web && pnpm install
pipx install uv
echo "alias start-api=\"cd $WORKSPACE_ROOT/api && uv run python -m flask run --host 0.0.0.0 --port=5001 --debug\"" >> ~/.bashrc
echo "alias start-worker=\"cd $WORKSPACE_ROOT/api && uv run python -m celery -A app.celery worker -P threads -c 1 --loglevel INFO -Q dataset,dataset_summary,priority_dataset,priority_pipeline,pipeline,mail,ops_trace,app_deletion,plugin,workflow_storage,conversation,workflow,schedule_poller,schedule_executor,triggered_workflow_dispatcher,trigger_refresh_executor,retention\"" >> ~/.bashrc
echo "alias start-web=\"cd $WORKSPACE_ROOT/web && pnpm dev:inspect\"" >> ~/.bashrc
echo "alias start-web-prod=\"cd $WORKSPACE_ROOT/web && pnpm build && pnpm start\"" >> ~/.bashrc
echo "alias start-containers=\"cd $WORKSPACE_ROOT/docker && docker-compose -f docker-compose.middleware.yaml -p dify --env-file middleware.env up -d\"" >> ~/.bashrc
echo "alias stop-containers=\"cd $WORKSPACE_ROOT/docker && docker-compose -f docker-compose.middleware.yaml -p dify --env-file middleware.env down\"" >> ~/.bashrc
source /home/vscode/.bashrc
================================================
FILE: .devcontainer/post_start_command.sh
================================================
#!/bin/bash
cd api && uv sync
================================================
FILE: .editorconfig
================================================
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.py]
indent_size = 4
indent_style = space
[*.{yml,yaml}]
indent_style = space
indent_size = 2
[*.toml]
indent_size = 4
indent_style = space
# Markdown and MDX are whitespace sensitive languages.
# Do not remove trailing spaces.
[*.{md,mdx}]
trim_trailing_whitespace = false
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,jsx,ts,tsx,mjs}]
indent_style = space
indent_size = 2
# Matches the exact files package.json
[package.json]
indent_style = space
indent_size = 2
================================================
FILE: .gemini/config.yaml
================================================
have_fun: false
memory_config:
disabled: false
code_review:
disable: true
comment_severity_threshold: MEDIUM
max_review_comments: -1
pull_request_opened:
help: false
summary: false
code_review: false
include_drafts: false
ignore_patterns: []
================================================
FILE: .gitattributes
================================================
# Ensure that .sh scripts use LF as line separator, even if they are checked out
# to Windows(NTFS) file-system, by a user of Docker for Windows.
# These .sh scripts will be run from the Container after `docker compose up -d`.
# If they appear to be CRLF style, Dash from the Container will fail to execute
# them.
*.sh text eol=lf
================================================
FILE: .github/CODEOWNERS
================================================
# CODEOWNERS
# This file defines code ownership for the Dify project.
# Each line is a file pattern followed by one or more owners.
# Owners can be @username, @org/team-name, or email addresses.
# For more information, see: https://docs.github.com/en/repositories/managing-your-repositorys-settings
Showing preview only (714K chars total). Download the full file or copy to clipboard to get everything.
gitextract_8lu11vbd/
├── .agents/
│ └── skills/
│ ├── backend-code-review/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── architecture-rule.md
│ │ ├── db-schema-rule.md
│ │ ├── repositories-rule.md
│ │ └── sqlalchemy-rule.md
│ ├── component-refactoring/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── complexity-patterns.md
│ │ ├── component-splitting.md
│ │ └── hook-extraction.md
│ ├── frontend-code-review/
│ │ ├── SKILL.md
│ │ └── references/
│ │ ├── business-logic.md
│ │ ├── code-quality.md
│ │ └── performance.md
│ ├── frontend-query-mutation/
│ │ ├── SKILL.md
│ │ ├── agents/
│ │ │ └── openai.yaml
│ │ └── references/
│ │ ├── contract-patterns.md
│ │ └── runtime-rules.md
│ └── frontend-testing/
│ ├── SKILL.md
│ ├── assets/
│ │ ├── component-test.template.tsx
│ │ ├── hook-test.template.ts
│ │ └── utility-test.template.ts
│ └── references/
│ ├── async-testing.md
│ ├── checklist.md
│ ├── common-patterns.md
│ ├── domain-components.md
│ ├── mocking.md
│ └── workflow.md
├── .claude/
│ └── settings.json
├── .coveragerc
├── .devcontainer/
│ ├── Dockerfile
│ ├── README.md
│ ├── devcontainer.json
│ ├── noop.txt
│ ├── post_create_command.sh
│ └── post_start_command.sh
├── .editorconfig
├── .gemini/
│ └── config.yaml
├── .gitattributes
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── DISCUSSION_TEMPLATE/
│ │ ├── general.yml
│ │ ├── help.yml
│ │ └── suggestion.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.yml
│ │ └── refactor.yml
│ ├── actions/
│ │ └── setup-web/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── labeler.yml
│ ├── linters/
│ │ ├── .hadolint.yaml
│ │ ├── .isort.cfg
│ │ ├── .yaml-lint.yml
│ │ └── editorconfig-checker.json
│ ├── pull_request_template.md
│ └── workflows/
│ ├── anti-slop.yml
│ ├── api-tests.yml
│ ├── autofix.yml
│ ├── build-push.yml
│ ├── db-migration-test.yml
│ ├── deploy-agent-dev.yml
│ ├── deploy-dev.yml
│ ├── deploy-enterprise.yml
│ ├── deploy-hitl.yml
│ ├── docker-build.yml
│ ├── expose_service_ports.sh
│ ├── labeler.yml
│ ├── main-ci.yml
│ ├── pyrefly-diff-comment.yml
│ ├── pyrefly-diff.yml
│ ├── semantic-pull-request.yml
│ ├── stale.yml
│ ├── style.yml
│ ├── tool-test-sdks.yaml
│ ├── translate-i18n-claude.yml
│ ├── trigger-i18n-sync.yml
│ ├── vdb-tests-full.yml
│ ├── vdb-tests.yml
│ ├── web-e2e.yml
│ └── web-tests.yml
├── .gitignore
├── .nvmrc
├── .vite-hooks/
│ └── pre-commit
├── .vscode/
│ ├── README.md
│ └── launch.json.template
├── AGENTS.md
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── api/
│ ├── .dockerignore
│ ├── .importlinter
│ ├── .ruff.toml
│ ├── AGENTS.md
│ ├── Dockerfile
│ ├── README.md
│ ├── app.py
│ ├── app_factory.py
│ ├── celery_entrypoint.py
│ ├── cnt_base.sh
│ ├── commands/
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── plugin.py
│ │ ├── retention.py
│ │ ├── storage.py
│ │ ├── system.py
│ │ └── vector.py
│ ├── configs/
│ │ ├── __init__.py
│ │ ├── app_config.py
│ │ ├── deploy/
│ │ │ └── __init__.py
│ │ ├── enterprise/
│ │ │ └── __init__.py
│ │ ├── extra/
│ │ │ ├── __init__.py
│ │ │ ├── archive_config.py
│ │ │ ├── notion_config.py
│ │ │ └── sentry_config.py
│ │ ├── feature/
│ │ │ ├── __init__.py
│ │ │ └── hosted_service/
│ │ │ └── __init__.py
│ │ ├── middleware/
│ │ │ ├── __init__.py
│ │ │ ├── cache/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── redis_config.py
│ │ │ │ └── redis_pubsub_config.py
│ │ │ ├── storage/
│ │ │ │ ├── aliyun_oss_storage_config.py
│ │ │ │ ├── amazon_s3_storage_config.py
│ │ │ │ ├── azure_blob_storage_config.py
│ │ │ │ ├── baidu_obs_storage_config.py
│ │ │ │ ├── clickzetta_volume_storage_config.py
│ │ │ │ ├── google_cloud_storage_config.py
│ │ │ │ ├── huawei_obs_storage_config.py
│ │ │ │ ├── oci_storage_config.py
│ │ │ │ ├── opendal_storage_config.py
│ │ │ │ ├── supabase_storage_config.py
│ │ │ │ ├── tencent_cos_storage_config.py
│ │ │ │ └── volcengine_tos_storage_config.py
│ │ │ └── vdb/
│ │ │ ├── alibabacloud_mysql_config.py
│ │ │ ├── analyticdb_config.py
│ │ │ ├── baidu_vector_config.py
│ │ │ ├── chroma_config.py
│ │ │ ├── clickzetta_config.py
│ │ │ ├── couchbase_config.py
│ │ │ ├── elasticsearch_config.py
│ │ │ ├── hologres_config.py
│ │ │ ├── huawei_cloud_config.py
│ │ │ ├── iris_config.py
│ │ │ ├── lindorm_config.py
│ │ │ ├── matrixone_config.py
│ │ │ ├── milvus_config.py
│ │ │ ├── myscale_config.py
│ │ │ ├── oceanbase_config.py
│ │ │ ├── opengauss_config.py
│ │ │ ├── opensearch_config.py
│ │ │ ├── oracle_config.py
│ │ │ ├── pgvector_config.py
│ │ │ ├── pgvectors_config.py
│ │ │ ├── qdrant_config.py
│ │ │ ├── relyt_config.py
│ │ │ ├── tablestore_config.py
│ │ │ ├── tencent_vector_config.py
│ │ │ ├── tidb_on_qdrant_config.py
│ │ │ ├── tidb_vector_config.py
│ │ │ ├── upstash_config.py
│ │ │ ├── vastbase_vector_config.py
│ │ │ ├── vikingdb_config.py
│ │ │ └── weaviate_config.py
│ │ ├── observability/
│ │ │ ├── __init__.py
│ │ │ └── otel/
│ │ │ └── otel_config.py
│ │ ├── packaging/
│ │ │ ├── __init__.py
│ │ │ └── pyproject.py
│ │ └── remote_settings_sources/
│ │ ├── __init__.py
│ │ ├── apollo/
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── python_3x.py
│ │ │ └── utils.py
│ │ ├── base.py
│ │ ├── enums.py
│ │ └── nacos/
│ │ ├── __init__.py
│ │ ├── http_request.py
│ │ └── utils.py
│ ├── constants/
│ │ ├── __init__.py
│ │ ├── languages.py
│ │ ├── mimetypes.py
│ │ ├── model_template.py
│ │ ├── pipeline_templates.json
│ │ ├── recommended_apps.json
│ │ └── tts_auto_play_timeout.py
│ ├── context/
│ │ ├── __init__.py
│ │ ├── execution_context.py
│ │ ├── flask_app_context.py
│ │ └── models.py
│ ├── contexts/
│ │ ├── __init__.py
│ │ └── wrapper.py
│ ├── controllers/
│ │ ├── __init__.py
│ │ ├── common/
│ │ │ ├── errors.py
│ │ │ ├── fields.py
│ │ │ ├── file_response.py
│ │ │ ├── helpers.py
│ │ │ └── schema.py
│ │ ├── console/
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── apikey.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_prompt_template.py
│ │ │ │ ├── agent.py
│ │ │ │ ├── annotation.py
│ │ │ │ ├── app.py
│ │ │ │ ├── app_import.py
│ │ │ │ ├── audio.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── conversation_variables.py
│ │ │ │ ├── error.py
│ │ │ │ ├── generator.py
│ │ │ │ ├── mcp_server.py
│ │ │ │ ├── message.py
│ │ │ │ ├── model_config.py
│ │ │ │ ├── ops_trace.py
│ │ │ │ ├── site.py
│ │ │ │ ├── statistic.py
│ │ │ │ ├── workflow.py
│ │ │ │ ├── workflow_app_log.py
│ │ │ │ ├── workflow_draft_variable.py
│ │ │ │ ├── workflow_run.py
│ │ │ │ ├── workflow_statistic.py
│ │ │ │ ├── workflow_trigger.py
│ │ │ │ └── wraps.py
│ │ │ ├── auth/
│ │ │ │ ├── activate.py
│ │ │ │ ├── data_source_bearer_auth.py
│ │ │ │ ├── data_source_oauth.py
│ │ │ │ ├── email_register.py
│ │ │ │ ├── error.py
│ │ │ │ ├── forgot_password.py
│ │ │ │ ├── login.py
│ │ │ │ ├── oauth.py
│ │ │ │ └── oauth_server.py
│ │ │ ├── billing/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── billing.py
│ │ │ │ └── compliance.py
│ │ │ ├── datasets/
│ │ │ │ ├── data_source.py
│ │ │ │ ├── datasets.py
│ │ │ │ ├── datasets_document.py
│ │ │ │ ├── datasets_segments.py
│ │ │ │ ├── error.py
│ │ │ │ ├── external.py
│ │ │ │ ├── hit_testing.py
│ │ │ │ ├── hit_testing_base.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── rag_pipeline/
│ │ │ │ │ ├── datasource_auth.py
│ │ │ │ │ ├── datasource_content_preview.py
│ │ │ │ │ ├── rag_pipeline.py
│ │ │ │ │ ├── rag_pipeline_datasets.py
│ │ │ │ │ ├── rag_pipeline_draft_variable.py
│ │ │ │ │ ├── rag_pipeline_import.py
│ │ │ │ │ └── rag_pipeline_workflow.py
│ │ │ │ ├── website.py
│ │ │ │ └── wraps.py
│ │ │ ├── error.py
│ │ │ ├── explore/
│ │ │ │ ├── audio.py
│ │ │ │ ├── banner.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── error.py
│ │ │ │ ├── installed_app.py
│ │ │ │ ├── message.py
│ │ │ │ ├── parameter.py
│ │ │ │ ├── recommended_app.py
│ │ │ │ ├── saved_message.py
│ │ │ │ ├── trial.py
│ │ │ │ ├── workflow.py
│ │ │ │ └── wraps.py
│ │ │ ├── extension.py
│ │ │ ├── feature.py
│ │ │ ├── files.py
│ │ │ ├── human_input_form.py
│ │ │ ├── init_validate.py
│ │ │ ├── notification.py
│ │ │ ├── ping.py
│ │ │ ├── remote_files.py
│ │ │ ├── setup.py
│ │ │ ├── spec.py
│ │ │ ├── tag/
│ │ │ │ └── tags.py
│ │ │ ├── version.py
│ │ │ ├── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── account.py
│ │ │ │ ├── agent_providers.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── error.py
│ │ │ │ ├── load_balancing_config.py
│ │ │ │ ├── members.py
│ │ │ │ ├── model_providers.py
│ │ │ │ ├── models.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── tool_providers.py
│ │ │ │ ├── trigger_providers.py
│ │ │ │ └── workspace.py
│ │ │ └── wraps.py
│ │ ├── fastopenapi.py
│ │ ├── files/
│ │ │ ├── __init__.py
│ │ │ ├── image_preview.py
│ │ │ ├── tool_files.py
│ │ │ └── upload.py
│ │ ├── inner_api/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── dsl.py
│ │ │ ├── mail.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── plugin.py
│ │ │ │ └── wraps.py
│ │ │ ├── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── workspace.py
│ │ │ └── wraps.py
│ │ ├── mcp/
│ │ │ ├── __init__.py
│ │ │ └── mcp.py
│ │ ├── service_api/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── annotation.py
│ │ │ │ ├── app.py
│ │ │ │ ├── audio.py
│ │ │ │ ├── completion.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── error.py
│ │ │ │ ├── file.py
│ │ │ │ ├── file_preview.py
│ │ │ │ ├── message.py
│ │ │ │ ├── site.py
│ │ │ │ └── workflow.py
│ │ │ ├── dataset/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── dataset.py
│ │ │ │ ├── document.py
│ │ │ │ ├── error.py
│ │ │ │ ├── hit_testing.py
│ │ │ │ ├── metadata.py
│ │ │ │ ├── rag_pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline_workflow.py
│ │ │ │ │ └── serializers.py
│ │ │ │ └── segment.py
│ │ │ ├── end_user/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── end_user.py
│ │ │ │ └── error.py
│ │ │ ├── index.py
│ │ │ ├── workspace/
│ │ │ │ └── models.py
│ │ │ └── wraps.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── trigger.py
│ │ │ └── webhook.py
│ │ └── web/
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── audio.py
│ │ ├── completion.py
│ │ ├── conversation.py
│ │ ├── error.py
│ │ ├── feature.py
│ │ ├── files.py
│ │ ├── forgot_password.py
│ │ ├── human_input_form.py
│ │ ├── login.py
│ │ ├── message.py
│ │ ├── passport.py
│ │ ├── remote_files.py
│ │ ├── saved_message.py
│ │ ├── site.py
│ │ ├── workflow.py
│ │ ├── workflow_events.py
│ │ └── wraps.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent/
│ │ │ ├── __init__.py
│ │ │ ├── base_agent_runner.py
│ │ │ ├── cot_agent_runner.py
│ │ │ ├── cot_chat_agent_runner.py
│ │ │ ├── cot_completion_agent_runner.py
│ │ │ ├── entities.py
│ │ │ ├── errors.py
│ │ │ ├── fc_agent_runner.py
│ │ │ ├── output_parser/
│ │ │ │ └── cot_output_parser.py
│ │ │ ├── plugin_entities.py
│ │ │ ├── prompt/
│ │ │ │ └── template.py
│ │ │ └── strategy/
│ │ │ ├── base.py
│ │ │ └── plugin.py
│ │ ├── app/
│ │ │ ├── __init__.py
│ │ │ ├── app_config/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base_app_config_manager.py
│ │ │ │ ├── common/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── parameters_mapping/
│ │ │ │ │ │ └── __init__.py
│ │ │ │ │ └── sensitive_word_avoidance/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ ├── easy_ui_based_app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── agent/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── dataset/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── model_config/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── converter.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── prompt_template/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ └── variables/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── features/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── file_upload/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── more_like_this/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── opening_statement/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── retrieval_resource/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── speech_to_text/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ ├── suggested_questions_after_answer/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── manager.py
│ │ │ │ │ └── text_to_speech/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── manager.py
│ │ │ │ └── workflow_ui_based_app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── variables/
│ │ │ │ ├── __init__.py
│ │ │ │ └── manager.py
│ │ │ ├── apps/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ └── generate_task_pipeline.py
│ │ │ │ ├── agent_chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── base_app_generate_response_converter.py
│ │ │ │ ├── base_app_generator.py
│ │ │ │ ├── base_app_queue_manager.py
│ │ │ │ ├── base_app_runner.py
│ │ │ │ ├── chat/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── common/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── graph_runtime_state_support.py
│ │ │ │ │ └── workflow_response_converter.py
│ │ │ │ ├── completion/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ └── generate_response_converter.py
│ │ │ │ ├── draft_variable_saver.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── message_based_app_generator.py
│ │ │ │ ├── message_based_app_queue_manager.py
│ │ │ │ ├── message_generator.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ ├── pipeline_config_manager.py
│ │ │ │ │ ├── pipeline_generator.py
│ │ │ │ │ ├── pipeline_queue_manager.py
│ │ │ │ │ └── pipeline_runner.py
│ │ │ │ ├── streaming_utils.py
│ │ │ │ ├── workflow/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── app_config_manager.py
│ │ │ │ │ ├── app_generator.py
│ │ │ │ │ ├── app_queue_manager.py
│ │ │ │ │ ├── app_runner.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── generate_response_converter.py
│ │ │ │ │ └── generate_task_pipeline.py
│ │ │ │ └── workflow_app_runner.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_strategy.py
│ │ │ │ ├── app_invoke_entities.py
│ │ │ │ ├── queue_entities.py
│ │ │ │ ├── rag_pipeline_invoke_entities.py
│ │ │ │ └── task_entities.py
│ │ │ ├── features/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── annotation_reply/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── annotation_reply.py
│ │ │ │ ├── hosting_moderation/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── hosting_moderation.py
│ │ │ │ └── rate_limiting/
│ │ │ │ ├── __init__.py
│ │ │ │ └── rate_limit.py
│ │ │ ├── file_access/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── controller.py
│ │ │ │ ├── protocols.py
│ │ │ │ └── scope.py
│ │ │ ├── layers/
│ │ │ │ ├── conversation_variable_persist_layer.py
│ │ │ │ ├── pause_state_persist_layer.py
│ │ │ │ ├── suspend_layer.py
│ │ │ │ ├── timeslice_layer.py
│ │ │ │ └── trigger_post_layer.py
│ │ │ ├── llm/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── model_access.py
│ │ │ │ └── quota.py
│ │ │ ├── task_pipeline/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── based_generate_task_pipeline.py
│ │ │ │ ├── easy_ui_based_generate_task_pipeline.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── message_cycle_manager.py
│ │ │ │ └── message_file_utils.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── file_runtime.py
│ │ │ └── layers/
│ │ │ ├── __init__.py
│ │ │ ├── llm_quota.py
│ │ │ ├── observability.py
│ │ │ └── persistence.py
│ │ ├── base/
│ │ │ ├── __init__.py
│ │ │ └── tts/
│ │ │ ├── __init__.py
│ │ │ └── app_generator_tts_publisher.py
│ │ ├── callback_handler/
│ │ │ ├── __init__.py
│ │ │ ├── agent_tool_callback_handler.py
│ │ │ ├── index_tool_callback_handler.py
│ │ │ └── workflow_tool_callback_handler.py
│ │ ├── datasource/
│ │ │ ├── __base/
│ │ │ │ ├── datasource_plugin.py
│ │ │ │ ├── datasource_provider.py
│ │ │ │ └── datasource_runtime.py
│ │ │ ├── __init__.py
│ │ │ ├── datasource_file_manager.py
│ │ │ ├── datasource_manager.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ ├── common_entities.py
│ │ │ │ └── datasource_entities.py
│ │ │ ├── errors.py
│ │ │ ├── local_file/
│ │ │ │ ├── local_file_plugin.py
│ │ │ │ └── local_file_provider.py
│ │ │ ├── online_document/
│ │ │ │ ├── online_document_plugin.py
│ │ │ │ └── online_document_provider.py
│ │ │ ├── online_drive/
│ │ │ │ ├── online_drive_plugin.py
│ │ │ │ └── online_drive_provider.py
│ │ │ ├── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ └── message_transformer.py
│ │ │ └── website_crawl/
│ │ │ ├── website_crawl_plugin.py
│ │ │ └── website_crawl_provider.py
│ │ ├── db/
│ │ │ ├── __init__.py
│ │ │ └── session_factory.py
│ │ ├── entities/
│ │ │ ├── __init__.py
│ │ │ ├── agent_entities.py
│ │ │ ├── document_task.py
│ │ │ ├── embedding_type.py
│ │ │ ├── execution_extra_content.py
│ │ │ ├── knowledge_entities.py
│ │ │ ├── mcp_provider.py
│ │ │ ├── model_entities.py
│ │ │ ├── parameter_entities.py
│ │ │ ├── provider_configuration.py
│ │ │ └── provider_entities.py
│ │ ├── errors/
│ │ │ ├── __init__.py
│ │ │ └── error.py
│ │ ├── extension/
│ │ │ ├── __init__.py
│ │ │ ├── api_based_extension_requestor.py
│ │ │ ├── extensible.py
│ │ │ └── extension.py
│ │ ├── external_data_tool/
│ │ │ ├── __init__.py
│ │ │ ├── api/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── api.py
│ │ │ ├── base.py
│ │ │ ├── external_data_fetch.py
│ │ │ └── factory.py
│ │ ├── helper/
│ │ │ ├── __init__.py
│ │ │ ├── code_executor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── code_executor.py
│ │ │ │ ├── code_node_provider.py
│ │ │ │ ├── javascript/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── javascript_code_provider.py
│ │ │ │ │ └── javascript_transformer.py
│ │ │ │ ├── jinja2/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── jinja2_formatter.py
│ │ │ │ │ └── jinja2_transformer.py
│ │ │ │ ├── python3/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── python3_code_provider.py
│ │ │ │ │ └── python3_transformer.py
│ │ │ │ └── template_transformer.py
│ │ │ ├── credential_utils.py
│ │ │ ├── csv_sanitizer.py
│ │ │ ├── download.py
│ │ │ ├── encrypter.py
│ │ │ ├── http_client_pooling.py
│ │ │ ├── marketplace.py
│ │ │ ├── model_provider_cache.py
│ │ │ ├── moderation.py
│ │ │ ├── module_import_helper.py
│ │ │ ├── name_generator.py
│ │ │ ├── position_helper.py
│ │ │ ├── provider_cache.py
│ │ │ ├── provider_encryption.py
│ │ │ ├── ssrf_proxy.py
│ │ │ ├── tool_parameter_cache.py
│ │ │ └── trace_id_helper.py
│ │ ├── hosting_configuration.py
│ │ ├── indexing_runner.py
│ │ ├── llm_generator/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── llm_generator.py
│ │ │ ├── output_parser/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── errors.py
│ │ │ │ ├── rule_config_generator.py
│ │ │ │ ├── structured_output.py
│ │ │ │ └── suggested_questions_after_answer.py
│ │ │ └── prompts.py
│ │ ├── logging/
│ │ │ ├── __init__.py
│ │ │ ├── context.py
│ │ │ ├── filters.py
│ │ │ └── structured_formatter.py
│ │ ├── mcp/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ └── auth_flow.py
│ │ │ ├── auth_client.py
│ │ │ ├── auth_client_comparison.md
│ │ │ ├── client/
│ │ │ │ ├── sse_client.py
│ │ │ │ └── streamable_client.py
│ │ │ ├── entities.py
│ │ │ ├── error.py
│ │ │ ├── mcp_client.py
│ │ │ ├── server/
│ │ │ │ └── streamable_http.py
│ │ │ ├── session/
│ │ │ │ ├── base_session.py
│ │ │ │ └── client_session.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── memory/
│ │ │ └── token_buffer_memory.py
│ │ ├── model_manager.py
│ │ ├── moderation/
│ │ │ ├── __init__.py
│ │ │ ├── api/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── api.py
│ │ │ ├── base.py
│ │ │ ├── factory.py
│ │ │ ├── input_moderation.py
│ │ │ ├── keywords/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── keywords.py
│ │ │ ├── openai_moderation/
│ │ │ │ ├── __builtin__
│ │ │ │ ├── __init__.py
│ │ │ │ └── openai_moderation.py
│ │ │ └── output_moderation.py
│ │ ├── ops/
│ │ │ ├── __init__.py
│ │ │ ├── aliyun_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_trace.py
│ │ │ │ ├── data_exporter/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── traceclient.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── aliyun_trace_entity.py
│ │ │ │ │ └── semconv.py
│ │ │ │ └── utils.py
│ │ │ ├── arize_phoenix_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── arize_phoenix_trace.py
│ │ │ ├── base_trace_instance.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── config_entity.py
│ │ │ │ └── trace_entity.py
│ │ │ ├── langfuse_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── langfuse_trace_entity.py
│ │ │ │ └── langfuse_trace.py
│ │ │ ├── langsmith_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── langsmith_trace_entity.py
│ │ │ │ └── langsmith_trace.py
│ │ │ ├── mlflow_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── mlflow_trace.py
│ │ │ ├── opik_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── opik_trace.py
│ │ │ ├── ops_trace_manager.py
│ │ │ ├── tencent_trace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── client.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── semconv.py
│ │ │ │ │ └── tencent_trace_entity.py
│ │ │ │ ├── span_builder.py
│ │ │ │ ├── tencent_trace.py
│ │ │ │ └── utils.py
│ │ │ ├── utils.py
│ │ │ └── weave_trace/
│ │ │ ├── __init__.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ └── weave_trace_entity.py
│ │ │ └── weave_trace.py
│ │ ├── plugin/
│ │ │ ├── backwards_invocation/
│ │ │ │ ├── app.py
│ │ │ │ ├── base.py
│ │ │ │ ├── encrypt.py
│ │ │ │ ├── model.py
│ │ │ │ ├── node.py
│ │ │ │ └── tool.py
│ │ │ ├── endpoint/
│ │ │ │ └── exc.py
│ │ │ ├── entities/
│ │ │ │ ├── base.py
│ │ │ │ ├── bundle.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── marketplace.py
│ │ │ │ ├── oauth.py
│ │ │ │ ├── parameters.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── plugin_daemon.py
│ │ │ │ └── request.py
│ │ │ ├── impl/
│ │ │ │ ├── agent.py
│ │ │ │ ├── asset.py
│ │ │ │ ├── base.py
│ │ │ │ ├── datasource.py
│ │ │ │ ├── debugging.py
│ │ │ │ ├── dynamic_select.py
│ │ │ │ ├── endpoint.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── model.py
│ │ │ │ ├── model_runtime.py
│ │ │ │ ├── model_runtime_factory.py
│ │ │ │ ├── oauth.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── tool.py
│ │ │ │ └── trigger.py
│ │ │ └── utils/
│ │ │ ├── chunk_merger.py
│ │ │ ├── converter.py
│ │ │ └── http_parser.py
│ │ ├── prompt/
│ │ │ ├── __init__.py
│ │ │ ├── advanced_prompt_transform.py
│ │ │ ├── agent_history_prompt_transform.py
│ │ │ ├── entities/
│ │ │ │ ├── __init__.py
│ │ │ │ └── advanced_prompt_entities.py
│ │ │ ├── prompt_templates/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── advanced_prompt_templates.py
│ │ │ │ ├── baichuan_chat.json
│ │ │ │ ├── baichuan_completion.json
│ │ │ │ ├── common_chat.json
│ │ │ │ └── common_completion.json
│ │ │ ├── prompt_transform.py
│ │ │ ├── simple_prompt_transform.py
│ │ │ └── utils/
│ │ │ ├── __init__.py
│ │ │ ├── extract_thread_messages.py
│ │ │ ├── get_thread_messages_length.py
│ │ │ ├── prompt_message_util.py
│ │ │ └── prompt_template_parser.py
│ │ ├── provider_manager.py
│ │ ├── rag/
│ │ │ ├── __init__.py
│ │ │ ├── cleaner/
│ │ │ │ ├── clean_processor.py
│ │ │ │ └── cleaner_base.py
│ │ │ ├── data_post_processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_post_processor.py
│ │ │ │ └── reorder.py
│ │ │ ├── datasource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── keyword/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── jieba/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── jieba.py
│ │ │ │ │ │ ├── jieba_keyword_table_handler.py
│ │ │ │ │ │ └── stopwords.py
│ │ │ │ │ ├── keyword_base.py
│ │ │ │ │ ├── keyword_factory.py
│ │ │ │ │ └── keyword_type.py
│ │ │ │ ├── retrieval_service.py
│ │ │ │ └── vdb/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── alibabacloud_mysql/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── alibabacloud_mysql_vector.py
│ │ │ │ ├── analyticdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── analyticdb_vector.py
│ │ │ │ │ ├── analyticdb_vector_openapi.py
│ │ │ │ │ └── analyticdb_vector_sql.py
│ │ │ │ ├── baidu/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── baidu_vector.py
│ │ │ │ ├── chroma/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── chroma_vector.py
│ │ │ │ ├── clickzetta/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── clickzetta_vector.py
│ │ │ │ ├── couchbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── couchbase_vector.py
│ │ │ │ ├── elasticsearch/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── elasticsearch_ja_vector.py
│ │ │ │ │ └── elasticsearch_vector.py
│ │ │ │ ├── field.py
│ │ │ │ ├── hologres/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── hologres_vector.py
│ │ │ │ ├── huawei/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── huawei_cloud_vector.py
│ │ │ │ ├── iris/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── iris_vector.py
│ │ │ │ ├── lindorm/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── lindorm_vector.py
│ │ │ │ ├── matrixone/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── matrixone_vector.py
│ │ │ │ ├── milvus/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── milvus_vector.py
│ │ │ │ ├── myscale/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── myscale_vector.py
│ │ │ │ ├── oceanbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── oceanbase_vector.py
│ │ │ │ ├── opengauss/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── opengauss.py
│ │ │ │ ├── opensearch/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── opensearch_vector.py
│ │ │ │ ├── oracle/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── oraclevector.py
│ │ │ │ ├── pgvecto_rs/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── collection.py
│ │ │ │ │ └── pgvecto_rs.py
│ │ │ │ ├── pgvector/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── pgvector.py
│ │ │ │ ├── pyvastbase/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── vastbase_vector.py
│ │ │ │ ├── qdrant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── qdrant_vector.py
│ │ │ │ ├── relyt/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── relyt_vector.py
│ │ │ │ ├── tablestore/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tablestore_vector.py
│ │ │ │ ├── tencent/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tencent_vector.py
│ │ │ │ ├── tidb_on_qdrant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── tidb_on_qdrant_vector.py
│ │ │ │ │ └── tidb_service.py
│ │ │ │ ├── tidb_vector/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── tidb_vector.py
│ │ │ │ ├── upstash/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── upstash_vector.py
│ │ │ │ ├── vector_base.py
│ │ │ │ ├── vector_factory.py
│ │ │ │ ├── vector_type.py
│ │ │ │ ├── vikingdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── vikingdb_vector.py
│ │ │ │ └── weaviate/
│ │ │ │ ├── __init__.py
│ │ │ │ └── weaviate_vector.py
│ │ │ ├── docstore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── dataset_docstore.py
│ │ │ ├── embedding/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cached_embedding.py
│ │ │ │ ├── embedding_base.py
│ │ │ │ └── retrieval.py
│ │ │ ├── entities/
│ │ │ │ ├── citation_metadata.py
│ │ │ │ ├── context_entities.py
│ │ │ │ ├── event.py
│ │ │ │ └── metadata_entities.py
│ │ │ ├── extractor/
│ │ │ │ ├── blob/
│ │ │ │ │ └── blob.py
│ │ │ │ ├── csv_extractor.py
│ │ │ │ ├── entity/
│ │ │ │ │ ├── datasource_type.py
│ │ │ │ │ └── extract_setting.py
│ │ │ │ ├── excel_extractor.py
│ │ │ │ ├── extract_processor.py
│ │ │ │ ├── extractor_base.py
│ │ │ │ ├── firecrawl/
│ │ │ │ │ ├── firecrawl_app.py
│ │ │ │ │ └── firecrawl_web_extractor.py
│ │ │ │ ├── helpers.py
│ │ │ │ ├── html_extractor.py
│ │ │ │ ├── jina_reader_extractor.py
│ │ │ │ ├── markdown_extractor.py
│ │ │ │ ├── notion_extractor.py
│ │ │ │ ├── pdf_extractor.py
│ │ │ │ ├── text_extractor.py
│ │ │ │ ├── unstructured/
│ │ │ │ │ ├── unstructured_doc_extractor.py
│ │ │ │ │ ├── unstructured_eml_extractor.py
│ │ │ │ │ ├── unstructured_epub_extractor.py
│ │ │ │ │ ├── unstructured_markdown_extractor.py
│ │ │ │ │ ├── unstructured_msg_extractor.py
│ │ │ │ │ ├── unstructured_ppt_extractor.py
│ │ │ │ │ ├── unstructured_pptx_extractor.py
│ │ │ │ │ └── unstructured_xml_extractor.py
│ │ │ │ ├── watercrawl/
│ │ │ │ │ ├── client.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── extractor.py
│ │ │ │ │ └── provider.py
│ │ │ │ └── word_extractor.py
│ │ │ ├── index_processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── constant/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── built_in_field.py
│ │ │ │ │ ├── doc_type.py
│ │ │ │ │ ├── index_type.py
│ │ │ │ │ └── query_type.py
│ │ │ │ ├── index_processor.py
│ │ │ │ ├── index_processor_base.py
│ │ │ │ ├── index_processor_factory.py
│ │ │ │ └── processor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── paragraph_index_processor.py
│ │ │ │ ├── parent_child_index_processor.py
│ │ │ │ └── qa_index_processor.py
│ │ │ ├── models/
│ │ │ │ ├── __init__.py
│ │ │ │ └── document.py
│ │ │ ├── pipeline/
│ │ │ │ ├── __init__.py
│ │ │ │ └── queue.py
│ │ │ ├── rerank/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entity/
│ │ │ │ │ └── weight.py
│ │ │ │ ├── rerank_base.py
│ │ │ │ ├── rerank_factory.py
│ │ │ │ ├── rerank_model.py
│ │ │ │ ├── rerank_type.py
│ │ │ │ └── weight_rerank.py
│ │ │ ├── retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── dataset_retrieval.py
│ │ │ │ ├── output_parser/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── react_output.py
│ │ │ │ │ └── structured_chat.py
│ │ │ │ ├── retrieval_methods.py
│ │ │ │ ├── router/
│ │ │ │ │ ├── multi_dataset_function_call_router.py
│ │ │ │ │ └── multi_dataset_react_route.py
│ │ │ │ └── template_prompts.py
│ │ │ ├── splitter/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixed_text_splitter.py
│ │ │ │ └── text_splitter.py
│ │ │ └── summary_index/
│ │ │ ├── __init__.py
│ │ │ └── summary_index.py
│ │ ├── repositories/
│ │ │ ├── __init__.py
│ │ │ ├── celery_workflow_execution_repository.py
│ │ │ ├── celery_workflow_node_execution_repository.py
│ │ │ ├── factory.py
│ │ │ ├── human_input_repository.py
│ │ │ ├── sqlalchemy_workflow_execution_repository.py
│ │ │ └── sqlalchemy_workflow_node_execution_repository.py
│ │ ├── schemas/
│ │ │ ├── __init__.py
│ │ │ ├── builtin/
│ │ │ │ └── schemas/
│ │ │ │ └── v1/
│ │ │ │ ├── file.json
│ │ │ │ ├── general_structure.json
│ │ │ │ ├── multimodal_general_structure.json
│ │ │ │ ├── multimodal_parent_child_structure.json
│ │ │ │ ├── parent_child_structure.json
│ │ │ │ └── qa_structure.json
│ │ │ ├── registry.py
│ │ │ ├── resolver.py
│ │ │ └── schema_manager.py
│ │ ├── telemetry/
│ │ │ ├── __init__.py
│ │ │ ├── events.py
│ │ │ └── gateway.py
│ │ ├── tools/
│ │ │ ├── __base/
│ │ │ │ ├── tool.py
│ │ │ │ ├── tool_provider.py
│ │ │ │ └── tool_runtime.py
│ │ │ ├── __init__.py
│ │ │ ├── builtin_tool/
│ │ │ │ ├── _position.yaml
│ │ │ │ ├── provider.py
│ │ │ │ ├── providers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── _positions.py
│ │ │ │ │ ├── audio/
│ │ │ │ │ │ ├── audio.py
│ │ │ │ │ │ ├── audio.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── asr.py
│ │ │ │ │ │ ├── asr.yaml
│ │ │ │ │ │ ├── tts.py
│ │ │ │ │ │ └── tts.yaml
│ │ │ │ │ ├── code/
│ │ │ │ │ │ ├── code.py
│ │ │ │ │ │ ├── code.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── simple_code.py
│ │ │ │ │ │ └── simple_code.yaml
│ │ │ │ │ ├── time/
│ │ │ │ │ │ ├── time.py
│ │ │ │ │ │ ├── time.yaml
│ │ │ │ │ │ └── tools/
│ │ │ │ │ │ ├── current_time.py
│ │ │ │ │ │ ├── current_time.yaml
│ │ │ │ │ │ ├── localtime_to_timestamp.py
│ │ │ │ │ │ ├── localtime_to_timestamp.yaml
│ │ │ │ │ │ ├── timestamp_to_localtime.py
│ │ │ │ │ │ ├── timestamp_to_localtime.yaml
│ │ │ │ │ │ ├── timezone_conversion.py
│ │ │ │ │ │ ├── timezone_conversion.yaml
│ │ │ │ │ │ ├── weekday.py
│ │ │ │ │ │ └── weekday.yaml
│ │ │ │ │ └── webscraper/
│ │ │ │ │ ├── tools/
│ │ │ │ │ │ ├── webscraper.py
│ │ │ │ │ │ └── webscraper.yaml
│ │ │ │ │ ├── webscraper.py
│ │ │ │ │ └── webscraper.yaml
│ │ │ │ └── tool.py
│ │ │ ├── custom_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ ├── common_entities.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── tool_bundle.py
│ │ │ │ ├── tool_entities.py
│ │ │ │ └── values.py
│ │ │ ├── errors.py
│ │ │ ├── mcp_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── plugin_tool/
│ │ │ │ ├── provider.py
│ │ │ │ └── tool.py
│ │ │ ├── signature.py
│ │ │ ├── tool_engine.py
│ │ │ ├── tool_file_manager.py
│ │ │ ├── tool_label_manager.py
│ │ │ ├── tool_manager.py
│ │ │ ├── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── dataset_retriever/
│ │ │ │ │ ├── dataset_multi_retriever_tool.py
│ │ │ │ │ ├── dataset_retriever_base_tool.py
│ │ │ │ │ └── dataset_retriever_tool.py
│ │ │ │ ├── dataset_retriever_tool.py
│ │ │ │ ├── encryption.py
│ │ │ │ ├── message_transformer.py
│ │ │ │ ├── model_invocation_utils.py
│ │ │ │ ├── parser.py
│ │ │ │ ├── system_oauth_encryption.py
│ │ │ │ ├── text_processing_utils.py
│ │ │ │ ├── uuid_utils.py
│ │ │ │ ├── web_reader_tool.py
│ │ │ │ ├── workflow_configuration_sync.py
│ │ │ │ └── yaml_utils.py
│ │ │ └── workflow_as_tool/
│ │ │ ├── provider.py
│ │ │ └── tool.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── debug/
│ │ │ │ ├── event_bus.py
│ │ │ │ ├── event_selectors.py
│ │ │ │ └── events.py
│ │ │ ├── entities/
│ │ │ │ ├── api_entities.py
│ │ │ │ └── entities.py
│ │ │ ├── errors.py
│ │ │ ├── provider.py
│ │ │ ├── trigger_manager.py
│ │ │ └── utils/
│ │ │ ├── encryption.py
│ │ │ ├── endpoint.py
│ │ │ └── locks.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ ├── file_reference.py
│ │ ├── human_input_compat.py
│ │ ├── human_input_forms.py
│ │ ├── node_factory.py
│ │ ├── node_runtime.py
│ │ ├── nodes/
│ │ │ ├── __init__.py
│ │ │ ├── agent/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_node.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── message_transformer.py
│ │ │ │ ├── plugin_strategy_adapter.py
│ │ │ │ ├── runtime_support.py
│ │ │ │ └── strategy_protocols.py
│ │ │ ├── datasource/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── datasource_node.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── protocols.py
│ │ │ ├── knowledge_index/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── knowledge_index_node.py
│ │ │ │ └── protocols.py
│ │ │ ├── knowledge_retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ ├── knowledge_retrieval_node.py
│ │ │ │ ├── retrieval.py
│ │ │ │ └── template_prompts.py
│ │ │ ├── trigger_plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── trigger_event_node.py
│ │ │ ├── trigger_schedule/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities.py
│ │ │ │ ├── exc.py
│ │ │ │ └── trigger_schedule_node.py
│ │ │ └── trigger_webhook/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── exc.py
│ │ │ └── node.py
│ │ ├── system_variables.py
│ │ ├── template_rendering.py
│ │ ├── variable_pool_initializer.py
│ │ ├── variable_prefixes.py
│ │ ├── workflow_entry.py
│ │ └── workflow_run_outputs.py
│ ├── dify_app.py
│ ├── docker/
│ │ └── entrypoint.sh
│ ├── enterprise/
│ │ ├── __init__.py
│ │ └── telemetry/
│ │ ├── DATA_DICTIONARY.md
│ │ ├── README.md
│ │ ├── __init__.py
│ │ ├── contracts.py
│ │ ├── draft_trace.py
│ │ ├── enterprise_trace.py
│ │ ├── entities/
│ │ │ └── __init__.py
│ │ ├── event_handlers.py
│ │ ├── exporter.py
│ │ ├── id_generator.py
│ │ ├── metric_handler.py
│ │ └── telemetry_log.py
│ ├── enums/
│ │ ├── __init__.py
│ │ ├── cloud_plan.py
│ │ ├── hosted_provider.py
│ │ └── quota_type.py
│ ├── events/
│ │ ├── __init__.py
│ │ ├── app_event.py
│ │ ├── dataset_event.py
│ │ ├── document_event.py
│ │ ├── document_index_event.py
│ │ ├── event_handlers/
│ │ │ ├── __init__.py
│ │ │ ├── clean_when_dataset_deleted.py
│ │ │ ├── clean_when_document_deleted.py
│ │ │ ├── create_document_index.py
│ │ │ ├── create_installed_app_when_app_created.py
│ │ │ ├── create_site_record_when_app_created.py
│ │ │ ├── delete_tool_parameters_cache_when_sync_draft_workflow.py
│ │ │ ├── queue_credential_sync_when_tenant_created.py
│ │ │ ├── sync_plugin_trigger_when_app_created.py
│ │ │ ├── sync_webhook_when_app_created.py
│ │ │ ├── sync_workflow_schedule_when_app_published.py
│ │ │ ├── update_app_dataset_join_when_app_model_config_updated.py
│ │ │ ├── update_app_dataset_join_when_app_published_workflow_updated.py
│ │ │ ├── update_app_triggers_when_app_published_workflow_updated.py
│ │ │ └── update_provider_when_message_created.py
│ │ ├── message_event.py
│ │ └── tenant_event.py
│ ├── extensions/
│ │ ├── __init__.py
│ │ ├── ext_app_metrics.py
│ │ ├── ext_blueprints.py
│ │ ├── ext_celery.py
│ │ ├── ext_code_based_extension.py
│ │ ├── ext_commands.py
│ │ ├── ext_compress.py
│ │ ├── ext_database.py
│ │ ├── ext_enterprise_telemetry.py
│ │ ├── ext_fastopenapi.py
│ │ ├── ext_forward_refs.py
│ │ ├── ext_hosting_provider.py
│ │ ├── ext_import_modules.py
│ │ ├── ext_logging.py
│ │ ├── ext_login.py
│ │ ├── ext_logstore.py
│ │ ├── ext_mail.py
│ │ ├── ext_migrate.py
│ │ ├── ext_orjson.py
│ │ ├── ext_otel.py
│ │ ├── ext_proxy_fix.py
│ │ ├── ext_redis.py
│ │ ├── ext_request_logging.py
│ │ ├── ext_sentry.py
│ │ ├── ext_session_factory.py
│ │ ├── ext_set_secretkey.py
│ │ ├── ext_storage.py
│ │ ├── ext_timezone.py
│ │ ├── ext_warnings.py
│ │ ├── logstore/
│ │ │ ├── __init__.py
│ │ │ ├── aliyun_logstore.py
│ │ │ ├── aliyun_logstore_pg.py
│ │ │ ├── repositories/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── logstore_api_workflow_node_execution_repository.py
│ │ │ │ ├── logstore_api_workflow_run_repository.py
│ │ │ │ ├── logstore_workflow_execution_repository.py
│ │ │ │ └── logstore_workflow_node_execution_repository.py
│ │ │ └── sql_escape.py
│ │ ├── otel/
│ │ │ ├── __init__.py
│ │ │ ├── celery_sqlcommenter.py
│ │ │ ├── decorators/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── handler.py
│ │ │ │ └── handlers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── generate_handler.py
│ │ │ │ └── workflow_app_runner_handler.py
│ │ │ ├── instrumentation.py
│ │ │ ├── parser/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── llm.py
│ │ │ │ ├── retrieval.py
│ │ │ │ └── tool.py
│ │ │ ├── runtime.py
│ │ │ └── semconv/
│ │ │ ├── __init__.py
│ │ │ ├── dify.py
│ │ │ └── gen_ai.py
│ │ └── storage/
│ │ ├── aliyun_oss_storage.py
│ │ ├── aws_s3_storage.py
│ │ ├── azure_blob_storage.py
│ │ ├── baidu_obs_storage.py
│ │ ├── base_storage.py
│ │ ├── clickzetta_volume/
│ │ │ ├── __init__.py
│ │ │ ├── clickzetta_volume_storage.py
│ │ │ ├── file_lifecycle.py
│ │ │ └── volume_permissions.py
│ │ ├── google_cloud_storage.py
│ │ ├── huawei_obs_storage.py
│ │ ├── opendal_storage.py
│ │ ├── oracle_oci_storage.py
│ │ ├── storage_type.py
│ │ ├── supabase_storage.py
│ │ ├── tencent_cos_storage.py
│ │ └── volcengine_tos_storage.py
│ ├── factories/
│ │ ├── __init__.py
│ │ ├── agent_factory.py
│ │ ├── file_factory/
│ │ │ ├── __init__.py
│ │ │ ├── builders.py
│ │ │ ├── common.py
│ │ │ ├── message_files.py
│ │ │ ├── remote.py
│ │ │ ├── storage_keys.py
│ │ │ └── validation.py
│ │ └── variable_factory.py
│ ├── fields/
│ │ ├── __init__.py
│ │ ├── _value_type_serializer.py
│ │ ├── annotation_fields.py
│ │ ├── api_based_extension_fields.py
│ │ ├── app_fields.py
│ │ ├── conversation_fields.py
│ │ ├── conversation_variable_fields.py
│ │ ├── data_source_fields.py
│ │ ├── dataset_fields.py
│ │ ├── document_fields.py
│ │ ├── end_user_fields.py
│ │ ├── file_fields.py
│ │ ├── hit_testing_fields.py
│ │ ├── installed_app_fields.py
│ │ ├── member_fields.py
│ │ ├── message_fields.py
│ │ ├── rag_pipeline_fields.py
│ │ ├── raws.py
│ │ ├── segment_fields.py
│ │ ├── tag_fields.py
│ │ ├── workflow_app_log_fields.py
│ │ ├── workflow_fields.py
│ │ ├── workflow_run_fields.py
│ │ └── workflow_trigger_fields.py
│ ├── gunicorn.conf.py
│ ├── libs/
│ │ ├── __init__.py
│ │ ├── archive_storage.py
│ │ ├── broadcast_channel/
│ │ │ ├── channel.py
│ │ │ ├── exc.py
│ │ │ └── redis/
│ │ │ ├── __init__.py
│ │ │ ├── _subscription.py
│ │ │ ├── channel.py
│ │ │ ├── sharded_channel.py
│ │ │ └── streams_channel.py
│ │ ├── collection_utils.py
│ │ ├── custom_inputs.py
│ │ ├── datetime_utils.py
│ │ ├── db_migration_lock.py
│ │ ├── email_i18n.py
│ │ ├── email_template_renderer.py
│ │ ├── encryption.py
│ │ ├── exception.py
│ │ ├── external_api.py
│ │ ├── file_utils.py
│ │ ├── flask_utils.py
│ │ ├── gmpy2_pkcs10aep_cipher.py
│ │ ├── helper.py
│ │ ├── infinite_scroll_pagination.py
│ │ ├── json_in_md_parser.py
│ │ ├── login.py
│ │ ├── module_loading.py
│ │ ├── oauth.py
│ │ ├── oauth_data_source.py
│ │ ├── orjson.py
│ │ ├── passport.py
│ │ ├── password.py
│ │ ├── pyrefly_diagnostics.py
│ │ ├── rsa.py
│ │ ├── schedule_utils.py
│ │ ├── sendgrid.py
│ │ ├── smtp.py
│ │ ├── time_parser.py
│ │ ├── token.py
│ │ ├── typing.py
│ │ ├── uuid_utils.py
│ │ ├── validators.py
│ │ └── workspace_permission.py
│ ├── migrations/
│ │ ├── README
│ │ ├── alembic.ini
│ │ ├── env.py
│ │ ├── script.py.mako
│ │ └── versions/
│ │ ├── 00bacef91f18_rename_api_provider_description.py
│ │ ├── 03f98355ba0e_add_workflow_tool_label_and_tool_.py
│ │ ├── 04c602f5dc9b_update_appmodelconfig_and_add_table_.py
│ │ ├── 053da0c1d756_add_api_tool_privacy.py
│ │ ├── 114eed84c228_remove_tool_id_from_model_invoke.py
│ │ ├── 161cadc1af8d_add_dataset_permission_tenant_id.py
│ │ ├── 16830a790f0f_.py
│ │ ├── 16fa53d9faec_add_provider_model_support.py
│ │ ├── 17b5ab037c40_add_keyworg_table_storage_type.py
│ │ ├── 187385f442fc_modify_provider_model_name_length.py
│ │ ├── 2024_08_09_0801-1787fbae959a_update_tools_original_url_length.py
│ │ ├── 2024_08_13_0633-63a83fcf12ba_support_conversation_variables.py
│ │ ├── 2024_08_14_1354-8782057ff0dc_add_conversations_dialogue_count.py
│ │ ├── 2024_08_15_0956-0251a1c768cc_add_tidb_auth_binding.py
│ │ ├── 2024_08_15_1001-a6be81136580_app_and_site_icon_type.py
│ │ ├── 2024_08_20_0455-2dbe42621d96_rename_workflow__conversation_variables_.py
│ │ ├── 2024_08_25_0441-d0187d6a88dd_add_created_by_and_updated_by_to_app_.py
│ │ ├── 2024_09_01_1255-030f4915f36a_add_use_icon_as_answer_icon_fields_for_.py
│ │ ├── 2024_09_11_1012-d57ba9ebb251_add_parent_message_id_to_messages.py
│ │ ├── 2024_09_24_0922-6af6a521a53e_update_retrieval_resource.py
│ │ ├── 2024_09_25_0434-33f5fac87f29_external_knowledge_api.py
│ │ ├── 2024_09_29_0835-ddcc8bbef391_increase_max_length_of_builtin_tool_provider.py
│ │ ├── 2024_10_09_1329-d8e744d88ed6_fix_wrong_service_api_history.py
│ │ ├── 2024_10_10_0516-bbadea11becb_add_name_and_size_to_tool_files.py
│ │ ├── 2024_10_22_0959-43fa78bc3b7d_add_white_list.py
│ │ ├── 2024_10_28_0720-08ec4f75af5e_add_tenant_plugin_permisisons.py
│ │ ├── 2024_11_01_0434-d3f6769a94a3_add_upload_files_source_url.py
│ │ ├── 2024_11_01_0449-93ad8c19c40b_rename_conversation_variables_index_name.py
│ │ ├── 2024_11_01_0540-f4d7ce70a7ca_update_upload_files_source_url.py
│ │ ├── 2024_11_01_0622-d07474999927_update_type_of_custom_disclaimer_to_text.py
│ │ ├── 2024_11_01_0623-09a8d1878d9b_update_workflows_graph_features_and_.py
│ │ ├── 2024_11_12_0925-01d6889832f7_add_created_at_index_for_messages.py
│ │ ├── 2024_11_22_0701-e19037032219_parent_child_index.py
│ │ ├── 2024_11_28_0553-cf8f4fc45278_add_exceptions_count_field_to_.py
│ │ ├── 2024_12_19_1746-11b07f66c737_remove_unused_tool_providers.py
│ │ ├── 2024_12_20_0628-e1944c35e15e_add_retry_index_field_to_node_execution_.py
│ │ ├── 2024_12_23_1154-d7999dfa4aae_remove_workflow_node_executions_retry_.py
│ │ ├── 2024_12_25_1137-923752d42eb6_add_auto_disabled_dataset_logs.py
│ │ ├── 2025_01_01_2000-a91b476a53de_change_workflow_runs_total_tokens_to_.py
│ │ ├── 2025_01_14_0617-f051706725cc_add_rate_limit_logs.py
│ │ ├── 2025_02_27_0917-d20049ed0af6_add_metadata_function.py
│ │ ├── 2025_03_03_0304-4413929e1ec2_extend_provider_name_column.py
│ │ ├── 2025_03_03_1436-ee79d9b1c156_add_marked_name_and_marked_comment_in_.py
│ │ ├── 2025_03_07_0315-5511c782ee4c_extend_provider_column.py
│ │ ├── 2025_03_29_2227-6a9f914f656c_change_documentsegment_and_childchunk_.py
│ │ ├── 2025_05_14_1403-d28f2004b072_add_index_for_workflow_conversation_.py
│ │ ├── 2025_05_15_1531-2adcbe1f5dfb_add_workflowdraftvariable_model.py
│ │ ├── 2025_06_06_1424-4474872b0ee6_workflow_draft_varaibles_add_node_execution_id.py
│ │ ├── 2025_06_19_1633-0ab65e1cc7fa_remove_sequence_number_from_workflow_.py
│ │ ├── 2025_06_25_0936-58eb7bdb93fe_add_mcp_server_tool_and_app_server.py
│ │ ├── 2025_07_02_2332-1c9ba48be8e4_add_uuidv7_function_in_sql.py
│ │ ├── 2025_07_04_1705-71f5020c6470_tool_oauth.py
│ │ ├── 2025_07_21_0935-1a83934ad6d1_update_models.py
│ │ ├── 2025_07_22_0019-375fe79ead14_oauth_refresh_token.py
│ │ ├── 2025_07_23_1508-8bcc02c9bd07_add_tenant_plugin_autoupgrade_table.py
│ │ ├── 2025_07_24_1450-532b3f888abf_manual_dataset_field_update.py
│ │ ├── 2025_08_07_1115-fa8b0fa6f407_add_timeout_for_tool_mcp_providers.py
│ │ ├── 2025_08_09_1553-e8446f481c1e_add_provider_credential_pool_support.py
│ │ ├── 2025_08_13_1605-0e154742a5fa_add_provider_model_multi_credential.py
│ │ ├── 2025_08_20_1747-8d289573e1da_add_oauth_provider_apps.py
│ │ ├── 2025_08_29_1534-b95962a3885c_add_workflow_app_log_run_id_index.py
│ │ ├── 2025_09_08_1007-c20211f18133_add_headers_to_mcp_provider.py
│ │ ├── 2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py
│ │ ├── 2025_09_17_1515-68519ad5cd18_knowledge_pipeline_migrate.py
│ │ ├── 2025_10_14_1618-d98acf217d43_add_app_mode_for_messsage.py
│ │ ├── 2025_10_21_1430-ae662b25d9bc_remove_builtin_template_user.py
│ │ ├── 2025_10_22_1611-03f8dcbc611e_add_workflowpause_model.py
│ │ ├── 2025_10_30_1518-669ffd70119c_introduce_trigger.py
│ │ ├── 2025_11_06_1603-9e6fa5cbcd80_make_message_annotation_question_not_.py
│ │ ├── 2025_11_12_1537-d57accd375ae_support_multi_modal.py
│ │ ├── 2025_11_15_2102-09cfdda155d1_mysql_adaptation.py
│ │ ├── 2025_11_18_1859-7bb281b7a422_add_workflow_pause_reasons_table.py
│ │ ├── 2025_12_16_1817-03ea244985ce_add_type_column_not_null_default_tool.py
│ │ ├── 2025_12_25_1039-7df29de0f6be_add_credit_pool.py
│ │ ├── 2026_01_09_1630-905527cc8fd3_add_workflow_run_created_at_id_idx.py
│ │ ├── 2026_01_12_1729-3334862ee907_feat_add_created_at_id_index_to_messages.py
│ │ ├── 2026_01_16_1715-288345cd01d1_change_workflow_node_execution_run_index.py
│ │ ├── 2026_01_17_1110-f9f6d18a37f9_add_table_explore_banner_and_trial.py
│ │ ├── 2026_01_21_1718-9d77545f524e_add_workflow_archive_logs.py
│ │ ├── 2026_01_27_1815-788d3099ae3a_add_summary_index_feature.py
│ │ ├── 2026_01_29_1415-e8c3b3c46151_add_human_input_related_db_models.py
│ │ ├── 2026_02_09_0950-c3df22613c99_drop_server_default_for_app_trail_.py
│ │ ├── 2026_02_10_1507-f55813ffe2c8_fix_tenant_default_model_unique.py
│ │ ├── 2026_02_11_1549-fce013ca180e_fix_index_to_optimize_message_clean_job_.py
│ │ ├── 2026_02_26_1336-e288952f2994_add_partial_indexes_on_conversations_.py
│ │ ├── 2026_03_02_1805-0ec65df55790_add_indexes_for_human_input_forms.py
│ │ ├── 2026_03_04_1600-6b5f9f8b1a2c_add_user_id_to_workflow_draft_variables.py
│ │ ├── 23db93619b9d_add_message_files_into_agent_thought.py
│ │ ├── 246ba09cbbdb_add_app_anntation_setting.py
│ │ ├── 2a3aebbbf4bb_add_app_tracing.py
│ │ ├── 2beac44e5f5f_add_is_universal_in_apps.py
│ │ ├── 2c8af9671032_add_qa_document_language.py
│ │ ├── 2e9819ca5b28_add_tenant_id_in_api_token.py
│ │ ├── 380c6aa5a70d_add_tool_labels_to_agent_thought.py
│ │ ├── 3b18fea55204_add_tool_label_bings.py
│ │ ├── 3c7cac9521c6_add_tags_and_binding_table.py
│ │ ├── 3ef9b2b6bee6_add_assistant_app.py
│ │ ├── 408176b91ad3_add_max_active_requests.py
│ │ ├── 42e85ed5564d_conversation_columns_set_nullable.py
│ │ ├── 46976cc39132_add_annotation_histoiry_score.py
│ │ ├── 47cc7df8c4f3_modify_default_model_name_length.py
│ │ ├── 4823da1d26cf_add_tool_file.py
│ │ ├── 4829e54d2fee_change_message_chain_id_to_nullable.py
│ │ ├── 4bcffcd64aa4_update_dataset_model_field_null_.py
│ │ ├── 4e99a8df00ff_add_load_balancing.py
│ │ ├── 4ff534e1eb11_add_workflow_to_site.py
│ │ ├── 5022897aaceb_add_model_name_in_embedding.py
│ │ ├── 53bf8af60645_update_model.py
│ │ ├── 563cf8bf777b_enable_tool_file_without_conversation_id.py
│ │ ├── 5fda94355fce_custom_disclaimer.py
│ │ ├── 614f77cecc48_add_last_active_at.py
│ │ ├── 63f9175e515b_merge_branches.py
│ │ ├── 64a70a7aab8b_add_workflow_run_index.py
│ │ ├── 64b051264f32_init.py
│ │ ├── 675b5321501b_add_node_execution_id_into_node_.py
│ │ ├── 6dcb43972bdc_add_dataset_retriever_resource.py
│ │ ├── 6e2cfb077b04_add_dataset_collection_binding.py
│ │ ├── 6e957a32015b_add_embedding_cache_created_at_index.py
│ │ ├── 714aafe25d39_add_anntation_history_match_response.py
│ │ ├── 77e83833755c_add_app_config_retriever_resource.py
│ │ ├── 7b45942e39bb_add_api_key_auth_binding.py
│ │ ├── 7bdef072e63a_add_workflow_tool.py
│ │ ├── 7ce5a52e4eee_add_tool_providers.py
│ │ ├── 7e6a8693e07a_add_table_dataset_permissions.py
│ │ ├── 853f9b9cd3b6_add_message_price_unit.py
│ │ ├── 88072f0caa04_add_custom_config_in_tenant.py
│ │ ├── 89c7899ca936_.py
│ │ ├── 8ae9bc661daa_add_tool_conversation_variables_idx.py
│ │ ├── 8d2d099ceb74_add_qa_model_support.py
│ │ ├── 8e5588e6412e_add_environment_variable_to_workflow_.py
│ │ ├── 8ec536f3c800_rename_api_provider_credentails.py
│ │ ├── 8fe468ba0ca5_add_gpt4v_supports.py
│ │ ├── 968fff4c0ab9_add_api_based_extension.py
│ │ ├── 9e98fbaffb88_add_workflow_tool_version.py
│ │ ├── 9f4e3427ea84_add_created_by_role.py
│ │ ├── 9fafbd60eca1_add_message_file_belongs_to.py
│ │ ├── a45f4dfde53b_add_language_to_recommend_apps.py
│ │ ├── a5b56fb053ef_app_config_add_speech_to_text.py
│ │ ├── a8d7385a7b66_add_embeddings_provider_name.py
│ │ ├── a8f9b3c45e4a_add_tenant_id_db_index.py
│ │ ├── a9836e3baeee_add_external_data_tools_in_app_model_.py
│ │ ├── ab23c11305d4_add_dataset_query_variable_at_app_model_.py
│ │ ├── ad472b61a054_add_api_provider_icon.py
│ │ ├── b24be59fbb04_.py
│ │ ├── b2602e131636_add_workflow_run_id_index_for_message.py
│ │ ├── b289e2408ee2_add_workflow.py
│ │ ├── b3a09c049e8e_add_advanced_prompt_templates.py
│ │ ├── b5429b71023c_messages_columns_set_nullable.py
│ │ ├── b69ca54b9208_add_chatbot_color_theme.py
│ │ ├── bf0aec5ba2cf_add_provider_order.py
│ │ ├── c031d46af369_remove_app_model_config_trace_config_.py
│ │ ├── c3311b089690_add_tool_meta.py
│ │ ├── c71211c8f604_add_tool_invoke_model_log.py
│ │ ├── cc04d0998d4d_set_model_config_column_nullable.py
│ │ ├── d3d503a3471c_add_is_deleted_to_conversations.py
│ │ ├── de95f5c77138_migration_serpapi_api_key.py
│ │ ├── dfb3b7f477da_add_tool_index.py
│ │ ├── e1901f623fd0_add_annotation_reply.py
│ │ ├── e2eacc9a1b63_add_status_for_message.py
│ │ ├── e32f6ccb87c6_e08af0a69ccefbb59fa80c778efee300bb780980.py
│ │ ├── e35ed59becda_modify_quota_limit_field_type.py
│ │ ├── e8883b0148c9_add_dataset_model_name.py
│ │ ├── eeb2e349e6ac_increase_max_model_name_length.py
│ │ ├── f25003750af4_add_created_updated_at.py
│ │ ├── f2a6fc85e260_add_anntation_history_message_id.py
│ │ ├── f9107f83abab_add_desc_for_apps.py
│ │ ├── fca025d3b60f_add_dataset_retrival_model.py
│ │ └── fecff1c3da27_remove_extra_tracing_app_config_table.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── _workflow_exc.py
│ │ ├── account.py
│ │ ├── api_based_extension.py
│ │ ├── base.py
│ │ ├── dataset.py
│ │ ├── engine.py
│ │ ├── enums.py
│ │ ├── execution_extra_content.py
│ │ ├── human_input.py
│ │ ├── model.py
│ │ ├── oauth.py
│ │ ├── provider.py
│ │ ├── provider_ids.py
│ │ ├── source.py
│ │ ├── task.py
│ │ ├── tools.py
│ │ ├── trigger.py
│ │ ├── types.py
│ │ ├── utils/
│ │ │ ├── __init__.py
│ │ │ └── file_input_compat.py
│ │ ├── web.py
│ │ └── workflow.py
│ ├── pyproject.toml
│ ├── pyrefly-local-excludes.txt
│ ├── pyrightconfig.json
│ ├── pytest.ini
│ ├── repositories/
│ │ ├── __init__.py
│ │ ├── api_workflow_node_execution_repository.py
│ │ ├── api_workflow_run_repository.py
│ │ ├── entities/
│ │ │ └── workflow_pause.py
│ │ ├── execution_extra_content_repository.py
│ │ ├── factory.py
│ │ ├── sqlalchemy_api_workflow_node_execution_repository.py
│ │ ├── sqlalchemy_api_workflow_run_repository.py
│ │ ├── sqlalchemy_execution_extra_content_repository.py
│ │ ├── sqlalchemy_workflow_trigger_log_repository.py
│ │ ├── types.py
│ │ └── workflow_trigger_log_repository.py
│ ├── schedule/
│ │ ├── check_upgradable_plugin_task.py
│ │ ├── clean_embedding_cache_task.py
│ │ ├── clean_messages.py
│ │ ├── clean_unused_datasets_task.py
│ │ ├── clean_workflow_runlogs_precise.py
│ │ ├── clean_workflow_runs_task.py
│ │ ├── create_tidb_serverless_task.py
│ │ ├── mail_clean_document_notify_task.py
│ │ ├── queue_monitor_task.py
│ │ ├── trigger_provider_refresh_task.py
│ │ ├── update_api_token_last_used_task.py
│ │ ├── update_tidb_serverless_status_task.py
│ │ └── workflow_schedule_task.py
│ ├── services/
│ │ ├── __init__.py
│ │ ├── account_service.py
│ │ ├── advanced_prompt_template_service.py
│ │ ├── agent_service.py
│ │ ├── annotation_service.py
│ │ ├── api_based_extension_service.py
│ │ ├── api_token_service.py
│ │ ├── app_dsl_service.py
│ │ ├── app_generate_service.py
│ │ ├── app_model_config_service.py
│ │ ├── app_service.py
│ │ ├── app_task_service.py
│ │ ├── async_workflow_service.py
│ │ ├── attachment_service.py
│ │ ├── audio_service.py
│ │ ├── auth/
│ │ │ ├── __init__.py
│ │ │ ├── api_key_auth_base.py
│ │ │ ├── api_key_auth_factory.py
│ │ │ ├── api_key_auth_service.py
│ │ │ ├── auth_type.py
│ │ │ ├── firecrawl/
│ │ │ │ ├── __init__.py
│ │ │ │ └── firecrawl.py
│ │ │ ├── jina/
│ │ │ │ ├── __init__.py
│ │ │ │ └── jina.py
│ │ │ ├── jina.py
│ │ │ └── watercrawl/
│ │ │ ├── __init__.py
│ │ │ └── watercrawl.py
│ │ ├── billing_service.py
│ │ ├── clear_free_plan_tenant_expired_logs.py
│ │ ├── code_based_extension_service.py
│ │ ├── conversation_service.py
│ │ ├── conversation_variable_updater.py
│ │ ├── credit_pool_service.py
│ │ ├── dataset_service.py
│ │ ├── datasource_provider_service.py
│ │ ├── document_indexing_proxy/
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── batch_indexing_base.py
│ │ │ ├── document_indexing_task_proxy.py
│ │ │ └── duplicate_document_indexing_task_proxy.py
│ │ ├── end_user_service.py
│ │ ├── enterprise/
│ │ │ ├── __init__.py
│ │ │ ├── account_deletion_sync.py
│ │ │ ├── base.py
│ │ │ ├── enterprise_service.py
│ │ │ ├── plugin_manager_service.py
│ │ │ └── workspace_sync.py
│ │ ├── entities/
│ │ │ ├── __init__.py
│ │ │ ├── external_knowledge_entities/
│ │ │ │ └── external_knowledge_entities.py
│ │ │ ├── knowledge_entities/
│ │ │ │ ├── knowledge_entities.py
│ │ │ │ └── rag_pipeline_entities.py
│ │ │ └── model_provider_entities.py
│ │ ├── errors/
│ │ │ ├── __init__.py
│ │ │ ├── account.py
│ │ │ ├── app.py
│ │ │ ├── app_model_config.py
│ │ │ ├── audio.py
│ │ │ ├── base.py
│ │ │ ├── chunk.py
│ │ │ ├── conversation.py
│ │ │ ├── dataset.py
│ │ │ ├── document.py
│ │ │ ├── enterprise.py
│ │ │ ├── file.py
│ │ │ ├── index.py
│ │ │ ├── llm.py
│ │ │ ├── message.py
│ │ │ ├── plugin.py
│ │ │ ├── workflow_service.py
│ │ │ └── workspace.py
│ │ ├── external_knowledge_service.py
│ │ ├── feature_service.py
│ │ ├── feedback_service.py
│ │ ├── file_service.py
│ │ ├── hit_testing_service.py
│ │ ├── human_input_delivery_test_service.py
│ │ ├── human_input_service.py
│ │ ├── knowledge_service.py
│ │ ├── message_service.py
│ │ ├── metadata_service.py
│ │ ├── model_load_balancing_service.py
│ │ ├── model_provider_service.py
│ │ ├── oauth_server.py
│ │ ├── operation_service.py
│ │ ├── ops_service.py
│ │ ├── plugin/
│ │ │ ├── __init__.py
│ │ │ ├── data_migration.py
│ │ │ ├── dependencies_analysis.py
│ │ │ ├── endpoint_service.py
│ │ │ ├── oauth_service.py
│ │ │ ├── plugin_auto_upgrade_service.py
│ │ │ ├── plugin_migration.py
│ │ │ ├── plugin_parameter_service.py
│ │ │ ├── plugin_permission_service.py
│ │ │ └── plugin_service.py
│ │ ├── rag_pipeline/
│ │ │ ├── entity/
│ │ │ │ └── pipeline_service_api_entities.py
│ │ │ ├── pipeline_generate_service.py
│ │ │ ├── pipeline_template/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── built_in/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── built_in_retrieval.py
│ │ │ │ ├── customized/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── customized_retrieval.py
│ │ │ │ ├── database/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── database_retrieval.py
│ │ │ │ ├── pipeline_template_base.py
│ │ │ │ ├── pipeline_template_factory.py
│ │ │ │ ├── pipeline_template_type.py
│ │ │ │ └── remote/
│ │ │ │ ├── __init__.py
│ │ │ │ └── remote_retrieval.py
│ │ │ ├── rag_pipeline.py
│ │ │ ├── rag_pipeline_dsl_service.py
│ │ │ ├── rag_pipeline_manage_service.py
│ │ │ ├── rag_pipeline_task_proxy.py
│ │ │ ├── rag_pipeline_transform_service.py
│ │ │ └── transform/
│ │ │ ├── file-general-economy.yml
│ │ │ ├── file-general-high-quality.yml
│ │ │ ├── file-parentchild.yml
│ │ │ ├── notion-general-economy.yml
│ │ │ ├── notion-general-high-quality.yml
│ │ │ ├── notion-parentchild.yml
│ │ │ ├── website-crawl-general-economy.yml
│ │ │ ├── website-crawl-general-high-quality.yml
│ │ │ └── website-crawl-parentchild.yml
│ │ ├── recommend_app/
│ │ │ ├── __init__.py
│ │ │ ├── buildin/
│ │ │ │ ├── __init__.py
│ │ │ │ └── buildin_retrieval.py
│ │ │ ├── database/
│ │ │ │ ├── __init__.py
│ │ │ │ └── database_retrieval.py
│ │ │ ├── recommend_app_base.py
│ │ │ ├── recommend_app_factory.py
│ │ │ ├── recommend_app_type.py
│ │ │ └── remote/
│ │ │ ├── __init__.py
│ │ │ └── remote_retrieval.py
│ │ ├── recommended_app_service.py
│ │ ├── retention/
│ │ │ ├── __init__.py
│ │ │ ├── conversation/
│ │ │ │ ├── message_export_service.py
│ │ │ │ ├── messages_clean_policy.py
│ │ │ │ └── messages_clean_service.py
│ │ │ └── workflow_run/
│ │ │ ├── __init__.py
│ │ │ ├── archive_paid_plan_workflow_run.py
│ │ │ ├── clear_free_plan_expired_workflow_run_logs.py
│ │ │ ├── constants.py
│ │ │ ├── delete_archived_workflow_run.py
│ │ │ └── restore_archived_workflow_run.py
│ │ ├── saved_message_service.py
│ │ ├── summary_index_service.py
│ │ ├── tag_service.py
│ │ ├── tools/
│ │ │ ├── api_tools_manage_service.py
│ │ │ ├── builtin_tools_manage_service.py
│ │ │ ├── mcp_tools_manage_service.py
│ │ │ ├── tool_labels_service.py
│ │ │ ├── tools_manage_service.py
│ │ │ ├── tools_transform_service.py
│ │ │ └── workflow_tools_manage_service.py
│ │ ├── trigger/
│ │ │ ├── app_trigger_service.py
│ │ │ ├── schedule_service.py
│ │ │ ├── trigger_provider_service.py
│ │ │ ├── trigger_request_service.py
│ │ │ ├── trigger_service.py
│ │ │ ├── trigger_subscription_builder_service.py
│ │ │ ├── trigger_subscription_operator_service.py
│ │ │ └── webhook_service.py
│ │ ├── variable_truncator.py
│ │ ├── vector_service.py
│ │ ├── web_conversation_service.py
│ │ ├── webapp_auth_service.py
│ │ ├── website_service.py
│ │ ├── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── entities.py
│ │ │ ├── queue_dispatcher.py
│ │ │ ├── scheduler.py
│ │ │ └── workflow_converter.py
│ │ ├── workflow_app_service.py
│ │ ├── workflow_draft_variable_service.py
│ │ ├── workflow_event_snapshot_service.py
│ │ ├── workflow_restore.py
│ │ ├── workflow_run_service.py
│ │ ├── workflow_service.py
│ │ └── workspace_service.py
│ ├── tasks/
│ │ ├── __init__.py
│ │ ├── add_document_to_index_task.py
│ │ ├── annotation/
│ │ │ ├── add_annotation_to_index_task.py
│ │ │ ├── batch_import_annotations_task.py
│ │ │ ├── delete_annotation_index_task.py
│ │ │ ├── disable_annotation_reply_task.py
│ │ │ ├── enable_annotation_reply_task.py
│ │ │ └── update_annotation_to_index_task.py
│ │ ├── app_generate/
│ │ │ ├── __init__.py
│ │ │ └── workflow_execute_task.py
│ │ ├── async_workflow_tasks.py
│ │ ├── batch_clean_document_task.py
│ │ ├── batch_create_segment_to_index_task.py
│ │ ├── clean_dataset_task.py
│ │ ├── clean_document_task.py
│ │ ├── clean_notion_document_task.py
│ │ ├── create_segment_to_index_task.py
│ │ ├── deal_dataset_index_update_task.py
│ │ ├── deal_dataset_vector_index_task.py
│ │ ├── delete_account_task.py
│ │ ├── delete_conversation_task.py
│ │ ├── delete_segment_from_index_task.py
│ │ ├── disable_segment_from_index_task.py
│ │ ├── disable_segments_from_index_task.py
│ │ ├── document_indexing_sync_task.py
│ │ ├── document_indexing_task.py
│ │ ├── document_indexing_update_task.py
│ │ ├── duplicate_document_indexing_task.py
│ │ ├── enable_segment_to_index_task.py
│ │ ├── enable_segments_to_index_task.py
│ │ ├── enterprise_telemetry_task.py
│ │ ├── generate_summary_index_task.py
│ │ ├── human_input_timeout_tasks.py
│ │ ├── mail_account_deletion_task.py
│ │ ├── mail_change_mail_task.py
│ │ ├── mail_email_code_login.py
│ │ ├── mail_human_input_delivery_task.py
│ │ ├── mail_inner_task.py
│ │ ├── mail_invite_member_task.py
│ │ ├── mail_owner_transfer_task.py
│ │ ├── mail_register_task.py
│ │ ├── mail_reset_password_task.py
│ │ ├── ops_trace_task.py
│ │ ├── process_tenant_plugin_autoupgrade_check_task.py
│ │ ├── rag_pipeline/
│ │ │ ├── priority_rag_pipeline_run_task.py
│ │ │ └── rag_pipeline_run_task.py
│ │ ├── recover_document_indexing_task.py
│ │ ├── regenerate_summary_index_task.py
│ │ ├── remove_app_and_related_data_task.py
│ │ ├── remove_document_from_index_task.py
│ │ ├── retry_document_indexing_task.py
│ │ ├── sync_website_document_indexing_task.py
│ │ ├── trigger_processing_tasks.py
│ │ ├── trigger_subscription_refresh_tasks.py
│ │ ├── workflow_cfs_scheduler/
│ │ │ ├── cfs_scheduler.py
│ │ │ └── entities.py
│ │ ├── workflow_draft_var_tasks.py
│ │ ├── workflow_execution_tasks.py
│ │ ├── workflow_node_execution_tasks.py
│ │ └── workflow_schedule_tasks.py
│ ├── templates/
│ │ ├── change_mail_completed_template_en-US.html
│ │ ├── change_mail_completed_template_zh-CN.html
│ │ ├── change_mail_confirm_new_template_en-US.html
│ │ ├── change_mail_confirm_new_template_zh-CN.html
│ │ ├── change_mail_confirm_old_template_en-US.html
│ │ ├── change_mail_confirm_old_template_zh-CN.html
│ │ ├── clean_document_job_mail_template-US.html
│ │ ├── delete_account_code_email_template_en-US.html
│ │ ├── delete_account_success_template_en-US.html
│ │ ├── email_code_login_mail_template_en-US.html
│ │ ├── email_code_login_mail_template_zh-CN.html
│ │ ├── invite_member_mail_template_en-US.html
│ │ ├── invite_member_mail_template_zh-CN.html
│ │ ├── queue_monitor_alert_email_template_en-US.html
│ │ ├── register_email_template_en-US.html
│ │ ├── register_email_template_zh-CN.html
│ │ ├── register_email_when_account_exist_template_en-US.html
│ │ ├── register_email_when_account_exist_template_zh-CN.html
│ │ ├── reset_password_mail_template_en-US.html
│ │ ├── reset_password_mail_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_template_zh-CN.html
│ │ ├── transfer_workspace_new_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_new_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_old_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_old_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_owner_confirm_template_en-US.html
│ │ ├── transfer_workspace_owner_confirm_template_zh-CN.html
│ │ └── without-brand/
│ │ ├── change_mail_completed_template_en-US.html
│ │ ├── change_mail_completed_template_zh-CN.html
│ │ ├── change_mail_confirm_new_template_en-US.html
│ │ ├── change_mail_confirm_new_template_zh-CN.html
│ │ ├── change_mail_confirm_old_template_en-US.html
│ │ ├── change_mail_confirm_old_template_zh-CN.html
│ │ ├── email_code_login_mail_template_en-US.html
│ │ ├── email_code_login_mail_template_zh-CN.html
│ │ ├── invite_member_mail_template_en-US.html
│ │ ├── invite_member_mail_template_zh-CN.html
│ │ ├── register_email_template_en-US.html
│ │ ├── register_email_template_zh-CN.html
│ │ ├── register_email_when_account_exist_template_en-US.html
│ │ ├── register_email_when_account_exist_template_zh-CN.html
│ │ ├── reset_password_mail_template_en-US.html
│ │ ├── reset_password_mail_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_no_register_template_zh-CN.html
│ │ ├── reset_password_mail_when_account_not_exist_template_en-US.html
│ │ ├── reset_password_mail_when_account_not_exist_template_zh-CN.html
│ │ ├── transfer_workspace_new_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_new_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_old_owner_notify_template_en-US.html
│ │ ├── transfer_workspace_old_owner_notify_template_zh-CN.html
│ │ ├── transfer_workspace_owner_confirm_template_en-US.html
│ │ └── transfer_workspace_owner_confirm_template_zh-CN.html
│ └── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── fixtures/
│ │ └── workflow/
│ │ ├── answer_end_with_text.yml
│ │ ├── array_iteration_formatting_workflow.yml
│ │ ├── basic_chatflow.yml
│ │ ├── basic_llm_chat_workflow.yml
│ │ ├── chatflow_time_tool_static_output_workflow.yml
│ │ ├── conditional_hello_branching_workflow.yml
│ │ ├── conditional_parallel_code_execution_workflow.yml
│ │ ├── conditional_streaming_vs_template_workflow.yml
│ │ ├── dual_switch_variable_aggregator_workflow.yml
│ │ ├── end_node_without_value_type_field_workflow.yml
│ │ ├── http_request_with_json_tool_workflow.yml
│ │ ├── increment_loop_with_break_condition_workflow.yml
│ │ ├── iteration_flatten_output_disabled_workflow.yml
│ │ ├── iteration_flatten_output_enabled_workflow.yml
│ │ ├── loop_contains_answer.yml
│ │ ├── multilingual_parallel_llm_streaming_workflow.yml
│ │ ├── search_dify_from_2023_to_2025.yml
│ │ ├── simple_passthrough_workflow.yml
│ │ ├── test-answer-order.yml
│ │ ├── test_complex_branch.yml
│ │ ├── test_streaming_conversation_variables.yml
│ │ ├── test_streaming_conversation_variables_v1_overwrite.yml
│ │ └── update-conversation-variable-in-iteration.yml
│ ├── integration_tests/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ └── console/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_chat_message_permissions.py
│ │ │ │ ├── test_description_validation.py
│ │ │ │ ├── test_feedback_api_basic.py
│ │ │ │ ├── test_feedback_export_api.py
│ │ │ │ ├── test_model_config_permissions.py
│ │ │ │ └── test_workflow_draft_variable.py
│ │ │ └── workspace/
│ │ │ └── test_trigger_provider_permissions.py
│ │ ├── core/
│ │ │ ├── datasource/
│ │ │ │ └── test_datasource_manager_integration.py
│ │ │ └── workflow/
│ │ │ └── nodes/
│ │ │ └── datasource/
│ │ │ └── test_datasource_node_integration.py
│ │ ├── factories/
│ │ │ ├── __init__.py
│ │ │ └── test_storage_key_loader.py
│ │ ├── libs/
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_data.py
│ │ │ │ └── test_helpers.py
│ │ │ └── test_api_token_cache_integration.py
│ │ ├── model_runtime/
│ │ │ └── __mock/
│ │ │ ├── plugin_daemon.py
│ │ │ └── plugin_model.py
│ │ ├── plugin/
│ │ │ ├── __mock/
│ │ │ │ └── http.py
│ │ │ └── tools/
│ │ │ └── test_fetch_all_tools.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_plugin_lifecycle.py
│ │ │ ├── retention/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_messages_clean_service.py
│ │ │ │ └── test_workflow_run_archiver.py
│ │ │ └── test_workflow_draft_variable_service.py
│ │ ├── storage/
│ │ │ └── test_clickzetta_volume.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ └── test_remove_app_and_related_data_task.py
│ │ ├── tools/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ └── http.py
│ │ │ ├── __mock_server/
│ │ │ │ └── openapi_todo.py
│ │ │ ├── api_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_api_tool.py
│ │ │ └── code/
│ │ │ └── __init__.py
│ │ ├── utils/
│ │ │ ├── child_class.py
│ │ │ ├── lazy_load_class.py
│ │ │ ├── parent_class.py
│ │ │ └── test_module_import_helper.py
│ │ ├── vdb/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── baiduvectordb.py
│ │ │ │ ├── hologres.py
│ │ │ │ ├── huaweicloudvectordb.py
│ │ │ │ ├── tcvectordb.py
│ │ │ │ ├── upstashvectordb.py
│ │ │ │ └── vikingdb.py
│ │ │ ├── analyticdb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_analyticdb.py
│ │ │ ├── baidu/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_baidu.py
│ │ │ ├── chroma/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_chroma.py
│ │ │ ├── clickzetta/
│ │ │ │ ├── README.md
│ │ │ │ ├── test_clickzetta.py
│ │ │ │ └── test_docker_integration.py
│ │ │ ├── couchbase/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_couchbase.py
│ │ │ ├── elasticsearch/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_elasticsearch.py
│ │ │ ├── hologres/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_hologres.py
│ │ │ ├── huawei/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_huawei_cloud.py
│ │ │ ├── iris/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_iris.py
│ │ │ ├── lindorm/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_lindorm.py
│ │ │ ├── matrixone/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_matrixone.py
│ │ │ ├── milvus/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_milvus.py
│ │ │ ├── myscale/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_myscale.py
│ │ │ ├── oceanbase/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bench_oceanbase.py
│ │ │ │ └── test_oceanbase.py
│ │ │ ├── opengauss/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opengauss.py
│ │ │ ├── opensearch/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opensearch.py
│ │ │ ├── oracle/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_oraclevector.py
│ │ │ ├── pgvecto_rs/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pgvecto_rs.py
│ │ │ ├── pgvector/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pgvector.py
│ │ │ ├── pyvastbase/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_vastbase_vector.py
│ │ │ ├── qdrant/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_qdrant.py
│ │ │ ├── tablestore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tablestore.py
│ │ │ ├── tcvectordb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tencent.py
│ │ │ ├── test_vector_store.py
│ │ │ ├── tidb_vector/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── check_tiflash_ready.py
│ │ │ │ └── test_tidb_vector.py
│ │ │ ├── upstash/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_upstash_vector.py
│ │ │ ├── vikingdb/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_vikingdb.py
│ │ │ └── weaviate/
│ │ │ ├── __init__.py
│ │ │ └── test_weaviate.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ ├── nodes/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── code_executor.py
│ │ │ │ ├── http.py
│ │ │ │ └── model.py
│ │ │ ├── code_executor/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_code_executor.py
│ │ │ │ ├── test_code_javascript.py
│ │ │ │ ├── test_code_jinja2.py
│ │ │ │ └── test_code_python3.py
│ │ │ ├── knowledge_index/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_knowledge_index_node_integration.py
│ │ │ ├── knowledge_retrieval/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_knowledge_retrieval_node_integration.py
│ │ │ ├── test_code.py
│ │ │ ├── test_http.py
│ │ │ ├── test_llm.py
│ │ │ ├── test_parameter_extractor.py
│ │ │ ├── test_template_transform.py
│ │ │ └── test_tool.py
│ │ └── test_sync_workflow.py
│ ├── test_containers_integration_tests/
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ ├── console/
│ │ │ │ ├── app/
│ │ │ │ │ ├── test_app_apis.py
│ │ │ │ │ ├── test_app_import_api.py
│ │ │ │ │ ├── test_chat_conversation_status_count_api.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_statistic.py
│ │ │ │ │ └── test_workflow_draft_variable.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── test_data_source_bearer_auth.py
│ │ │ │ │ ├── test_data_source_oauth.py
│ │ │ │ │ ├── test_email_register.py
│ │ │ │ │ ├── test_forgot_password.py
│ │ │ │ │ ├── test_oauth.py
│ │ │ │ │ ├── test_oauth_server.py
│ │ │ │ │ └── test_password_reset.py
│ │ │ │ ├── datasets/
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── test_rag_pipeline.py
│ │ │ │ │ │ ├── test_rag_pipeline_datasets.py
│ │ │ │ │ │ ├── test_rag_pipeline_import.py
│ │ │ │ │ │ └── test_rag_pipeline_workflow.py
│ │ │ │ │ └── test_data_source.py
│ │ │ │ ├── explore/
│ │ │ │ │ └── test_conversation.py
│ │ │ │ ├── helpers.py
│ │ │ │ ├── test_apikey.py
│ │ │ │ └── workspace/
│ │ │ │ ├── test_tool_provider.py
│ │ │ │ ├── test_trigger_providers.py
│ │ │ │ └── test_workspace_wraps.py
│ │ │ ├── mcp/
│ │ │ │ └── test_mcp.py
│ │ │ └── web/
│ │ │ ├── test_conversation.py
│ │ │ ├── test_web_forgot_password.py
│ │ │ └── test_wraps.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── layers/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_pause_state_persist_layer.py
│ │ │ ├── rag/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_queue_integration.py
│ │ │ │ └── retrieval/
│ │ │ │ └── test_dataset_retrieval_integration.py
│ │ │ ├── repositories/
│ │ │ │ └── test_human_input_form_repository_impl.py
│ │ │ └── workflow/
│ │ │ └── test_human_input_resume_node_execution.py
│ │ ├── factories/
│ │ │ ├── __init__.py
│ │ │ └── test_storage_key_loader.py
│ │ ├── helpers/
│ │ │ ├── __init__.py
│ │ │ └── execution_extra_content.py
│ │ ├── libs/
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ ├── test_channel.py
│ │ │ │ ├── test_sharded_channel.py
│ │ │ │ └── test_streams_channel.py
│ │ │ ├── test_auto_renew_redis_lock_integration.py
│ │ │ └── test_rate_limiter_integration.py
│ │ ├── models/
│ │ │ ├── test_account.py
│ │ │ ├── test_app_model_config.py
│ │ │ ├── test_dataset_models.py
│ │ │ └── test_types_enum_text.py
│ │ ├── repositories/
│ │ │ ├── test_sqlalchemy_api_workflow_node_execution_repository.py
│ │ │ ├── test_sqlalchemy_api_workflow_run_repository.py
│ │ │ ├── test_sqlalchemy_execution_extra_content_repository.py
│ │ │ ├── test_sqlalchemy_workflow_trigger_log_repository.py
│ │ │ └── test_workflow_run_repository.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_key_auth_service.py
│ │ │ │ └── test_auth_integration.py
│ │ │ ├── dataset_collection_binding.py
│ │ │ ├── dataset_service_update_delete.py
│ │ │ ├── document_service_status.py
│ │ │ ├── enterprise/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_account_deletion_sync.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_plugin_parameter_service.py
│ │ │ │ └── test_plugin_service.py
│ │ │ ├── recommend_app/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_database_retrieval.py
│ │ │ ├── test_account_service.py
│ │ │ ├── test_advanced_prompt_template_service.py
│ │ │ ├── test_agent_service.py
│ │ │ ├── test_annotation_service.py
│ │ │ ├── test_api_based_extension_service.py
│ │ │ ├── test_api_token_service.py
│ │ │ ├── test_app_dsl_service.py
│ │ │ ├── test_app_generate_service.py
│ │ │ ├── test_app_service.py
│ │ │ ├── test_attachment_service.py
│ │ │ ├── test_billing_service.py
│ │ │ ├── test_conversation_service.py
│ │ │ ├── test_conversation_variable_updater.py
│ │ │ ├── test_credit_pool_service.py
│ │ │ ├── test_dataset_permission_service.py
│ │ │ ├── test_dataset_service.py
│ │ │ ├── test_dataset_service_batch_update_document_status.py
│ │ │ ├── test_dataset_service_create_dataset.py
│ │ │ ├── test_dataset_service_delete_dataset.py
│ │ │ ├── test_dataset_service_get_segments.py
│ │ │ ├── test_dataset_service_retrieval.py
│ │ │ ├── test_dataset_service_update_dataset.py
│ │ │ ├── test_delete_archived_workflow_run.py
│ │ │ ├── test_document_service_display_status.py
│ │ │ ├── test_document_service_rename_document.py
│ │ │ ├── test_end_user_service.py
│ │ │ ├── test_feature_service.py
│ │ │ ├── test_feedback_service.py
│ │ │ ├── test_file_service.py
│ │ │ ├── test_file_service_zip_and_lookup.py
│ │ │ ├── test_human_input_delivery_test.py
│ │ │ ├── test_human_input_delivery_test_service.py
│ │ │ ├── test_message_export_service.py
│ │ │ ├── test_message_service.py
│ │ │ ├── test_message_service_execution_extra_content.py
│ │ │ ├── test_message_service_extra_contents.py
│ │ │ ├── test_messages_clean_service.py
│ │ │ ├── test_metadata_partial_update.py
│ │ │ ├── test_metadata_service.py
│ │ │ ├── test_model_load_balancing_service.py
│ │ │ ├── test_model_provider_service.py
│ │ │ ├── test_oauth_server_service.py
│ │ │ ├── test_restore_archived_workflow_run.py
│ │ │ ├── test_saved_message_service.py
│ │ │ ├── test_tag_service.py
│ │ │ ├── test_trigger_provider_service.py
│ │ │ ├── test_web_conversation_service.py
│ │ │ ├── test_webapp_auth_service.py
│ │ │ ├── test_webhook_service.py
│ │ │ ├── test_workflow_app_service.py
│ │ │ ├── test_workflow_draft_variable_service.py
│ │ │ ├── test_workflow_run_service.py
│ │ │ ├── test_workflow_service.py
│ │ │ ├── test_workspace_service.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_tools_manage_service.py
│ │ │ │ ├── test_mcp_tools_manage_service.py
│ │ │ │ ├── test_tools_transform_service.py
│ │ │ │ └── test_workflow_tools_manage_service.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── test_workflow_converter.py
│ │ │ ├── test_workflow_deletion.py
│ │ │ └── test_workflow_node_execution_service_repository.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── test_add_document_to_index_task.py
│ │ │ ├── test_batch_clean_document_task.py
│ │ │ ├── test_batch_create_segment_to_index_task.py
│ │ │ ├── test_clean_dataset_task.py
│ │ │ ├── test_clean_notion_document_task.py
│ │ │ ├── test_create_segment_to_index_task.py
│ │ │ ├── test_dataset_indexing_task.py
│ │ │ ├── test_deal_dataset_vector_index_task.py
│ │ │ ├── test_delete_segment_from_index_task.py
│ │ │ ├── test_disable_segment_from_index_task.py
│ │ │ ├── test_disable_segments_from_index_task.py
│ │ │ ├── test_document_indexing_sync_task.py
│ │ │ ├── test_document_indexing_task.py
│ │ │ ├── test_document_indexing_update_task.py
│ │ │ ├── test_duplicate_document_indexing_task.py
│ │ │ ├── test_enable_segments_to_index_task.py
│ │ │ ├── test_mail_account_deletion_task.py
│ │ │ ├── test_mail_change_mail_task.py
│ │ │ ├── test_mail_email_code_login_task.py
│ │ │ ├── test_mail_human_input_delivery_task.py
│ │ │ ├── test_mail_inner_task.py
│ │ │ ├── test_mail_invite_member_task.py
│ │ │ ├── test_mail_owner_transfer_task.py
│ │ │ ├── test_mail_register_task.py
│ │ │ ├── test_rag_pipeline_run_tasks.py
│ │ │ └── test_remove_app_and_related_data_task.py
│ │ ├── test_opendal_fs_default_root.py
│ │ ├── test_workflow_pause_integration.py
│ │ ├── trigger/
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ └── test_trigger_e2e.py
│ │ └── workflow/
│ │ ├── __init__.py
│ │ └── nodes/
│ │ ├── __init__.py
│ │ └── code_executor/
│ │ ├── __init__.py
│ │ ├── test_code_executor.py
│ │ ├── test_code_javascript.py
│ │ ├── test_code_jinja2.py
│ │ ├── test_code_python3.py
│ │ └── test_utils.py
│ ├── unit_tests/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── commands/
│ │ │ ├── test_clean_expired_messages.py
│ │ │ └── test_upgrade_db.py
│ │ ├── configs/
│ │ │ └── test_dify_config.py
│ │ ├── conftest.py
│ │ ├── controllers/
│ │ │ ├── __init__.py
│ │ │ ├── common/
│ │ │ │ ├── test_errors.py
│ │ │ │ ├── test_fields.py
│ │ │ │ ├── test_file_response.py
│ │ │ │ ├── test_helpers.py
│ │ │ │ └── test_schema.py
│ │ │ ├── console/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_annotation_api.py
│ │ │ │ │ ├── test_annotation_security.py
│ │ │ │ │ ├── test_app_response_models.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_audio_api.py
│ │ │ │ │ ├── test_conversation_api.py
│ │ │ │ │ ├── test_conversation_read_timestamp.py
│ │ │ │ │ ├── test_description_validation.py
│ │ │ │ │ ├── test_generator_api.py
│ │ │ │ │ ├── test_message_api.py
│ │ │ │ │ ├── test_model_config_api.py
│ │ │ │ │ ├── test_statistic_api.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ ├── test_workflow_human_input_debug_api.py
│ │ │ │ │ ├── test_workflow_pause_details_api.py
│ │ │ │ │ ├── test_wraps.py
│ │ │ │ │ └── workflow_draft_variables_test.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── test_account_activation.py
│ │ │ │ │ ├── test_authentication_security.py
│ │ │ │ │ ├── test_email_verification.py
│ │ │ │ │ ├── test_login_logout.py
│ │ │ │ │ └── test_token_refresh.py
│ │ │ │ ├── billing/
│ │ │ │ │ └── test_billing.py
│ │ │ │ ├── datasets/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_datasource_auth.py
│ │ │ │ │ │ ├── test_datasource_content_preview.py
│ │ │ │ │ │ └── test_rag_pipeline_draft_variable.py
│ │ │ │ │ ├── test_datasets.py
│ │ │ │ │ ├── test_datasets_document.py
│ │ │ │ │ ├── test_datasets_document_download.py
│ │ │ │ │ ├── test_datasets_segments.py
│ │ │ │ │ ├── test_external.py
│ │ │ │ │ ├── test_external_dataset_payload.py
│ │ │ │ │ ├── test_hit_testing.py
│ │ │ │ │ ├── test_hit_testing_base.py
│ │ │ │ │ ├── test_metadata.py
│ │ │ │ │ ├── test_website.py
│ │ │ │ │ └── test_wraps.py
│ │ │ │ ├── explore/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_banner.py
│ │ │ │ │ ├── test_completion.py
│ │ │ │ │ ├── test_installed_app.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_parameter.py
│ │ │ │ │ ├── test_recommended_app.py
│ │ │ │ │ ├── test_saved_message.py
│ │ │ │ │ ├── test_trial.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ └── test_wraps.py
│ │ │ │ ├── tag/
│ │ │ │ │ └── test_tags.py
│ │ │ │ ├── test_admin.py
│ │ │ │ ├── test_document_detail_api_data_source_info.py
│ │ │ │ ├── test_extension.py
│ │ │ │ ├── test_fastopenapi_ping.py
│ │ │ │ ├── test_fastopenapi_setup.py
│ │ │ │ ├── test_fastopenapi_version.py
│ │ │ │ ├── test_feature.py
│ │ │ │ ├── test_files.py
│ │ │ │ ├── test_files_security.py
│ │ │ │ ├── test_human_input_form.py
│ │ │ │ ├── test_init_validate.py
│ │ │ │ ├── test_remote_files.py
│ │ │ │ ├── test_spec.py
│ │ │ │ ├── test_version.py
│ │ │ │ ├── test_workspace_account.py
│ │ │ │ ├── test_workspace_members.py
│ │ │ │ ├── test_wraps.py
│ │ │ │ └── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_accounts.py
│ │ │ │ ├── test_agent_providers.py
│ │ │ │ ├── test_endpoint.py
│ │ │ │ ├── test_load_balancing_config.py
│ │ │ │ ├── test_members.py
│ │ │ │ ├── test_model_providers.py
│ │ │ │ ├── test_models.py
│ │ │ │ ├── test_plugin.py
│ │ │ │ ├── test_tool_providers.py
│ │ │ │ └── test_workspace.py
│ │ │ ├── files/
│ │ │ │ ├── test_image_preview.py
│ │ │ │ ├── test_tool_files.py
│ │ │ │ └── test_upload.py
│ │ │ ├── inner_api/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_dsl.py
│ │ │ │ ├── plugin/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_plugin.py
│ │ │ │ │ └── test_plugin_wraps.py
│ │ │ │ ├── test_auth_wraps.py
│ │ │ │ ├── test_mail.py
│ │ │ │ └── workspace/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_workspace.py
│ │ │ ├── service_api/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── app/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_annotation.py
│ │ │ │ │ ├── test_app.py
│ │ │ │ │ ├── test_audio.py
│ │ │ │ │ ├── test_chat_request_payload.py
│ │ │ │ │ ├── test_completion.py
│ │ │ │ │ ├── test_conversation.py
│ │ │ │ │ ├── test_file.py
│ │ │ │ │ ├── test_file_preview.py
│ │ │ │ │ ├── test_message.py
│ │ │ │ │ ├── test_workflow.py
│ │ │ │ │ └── test_workflow_fields.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── dataset/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── rag_pipeline/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_rag_pipeline_workflow.py
│ │ │ │ │ ├── test_dataset.py
│ │ │ │ │ ├── test_dataset_segment.py
│ │ │ │ │ ├── test_document.py
│ │ │ │ │ ├── test_hit_testing.py
│ │ │ │ │ ├── test_metadata.py
│ │ │ │ │ ├── test_rag_pipeline_file_upload_serialization.py
│ │ │ │ │ └── test_rag_pipeline_route_registration.py
│ │ │ │ ├── end_user/
│ │ │ │ │ └── test_end_user.py
│ │ │ │ ├── test_index.py
│ │ │ │ ├── test_site.py
│ │ │ │ └── test_wraps.py
│ │ │ ├── test_compare_versions.py
│ │ │ ├── test_conversation_rename_payload.py
│ │ │ ├── trigger/
│ │ │ │ ├── test_trigger.py
│ │ │ │ └── test_webhook.py
│ │ │ └── web/
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_app.py
│ │ │ ├── test_audio.py
│ │ │ ├── test_completion.py
│ │ │ ├── test_error.py
│ │ │ ├── test_feature.py
│ │ │ ├── test_files.py
│ │ │ ├── test_human_input_form.py
│ │ │ ├── test_message_endpoints.py
│ │ │ ├── test_message_list.py
│ │ │ ├── test_passport.py
│ │ │ ├── test_pydantic_models.py
│ │ │ ├── test_remote_files.py
│ │ │ ├── test_saved_message.py
│ │ │ ├── test_site.py
│ │ │ ├── test_web_login.py
│ │ │ ├── test_web_passport.py
│ │ │ ├── test_workflow.py
│ │ │ └── test_workflow_events.py
│ │ ├── core/
│ │ │ ├── __init__.py
│ │ │ ├── agent/
│ │ │ │ ├── conftest.py
│ │ │ │ ├── output_parser/
│ │ │ │ │ └── test_cot_output_parser.py
│ │ │ │ ├── strategy/
│ │ │ │ │ ├── test_base.py
│ │ │ │ │ └── test_plugin.py
│ │ │ │ ├── test_base_agent_runner.py
│ │ │ │ ├── test_cot_agent_runner.py
│ │ │ │ ├── test_cot_chat_agent_runner.py
│ │ │ │ ├── test_cot_completion_agent_runner.py
│ │ │ │ ├── test_fc_agent_runner.py
│ │ │ │ └── test_plugin_entities.py
│ │ │ ├── app/
│ │ │ │ ├── app_config/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── common/
│ │ │ │ │ │ ├── test_parameters_mapping.py
│ │ │ │ │ │ └── test_sensitive_word_avoidance_manager.py
│ │ │ │ │ ├── easy_ui_based_app/
│ │ │ │ │ │ ├── test_agent_manager.py
│ │ │ │ │ │ ├── test_dataset_manager.py
│ │ │ │ │ │ ├── test_model_config_converter.py
│ │ │ │ │ │ ├── test_model_config_manager.py
│ │ │ │ │ │ ├── test_prompt_template_manager.py
│ │ │ │ │ │ └── test_variables_manager.py
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── file_upload/
│ │ │ │ │ │ │ └── test_manager.py
│ │ │ │ │ │ └── test_additional_feature_managers.py
│ │ │ │ │ ├── test_base_app_config_manager.py
│ │ │ │ │ ├── test_entities.py
│ │ │ │ │ └── workflow_ui_based_app/
│ │ │ │ │ └── test_workflow_ui_based_app_manager.py
│ │ │ │ ├── apps/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── advanced_chat/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ │ ├── test_app_generator.py
│ │ │ │ │ │ ├── test_app_runner_conversation_variables.py
│ │ │ │ │ │ ├── test_app_runner_input_moderation.py
│ │ │ │ │ │ ├── test_generate_response_converter.py
│ │ │ │ │ │ ├── test_generate_task_pipeline.py
│ │ │ │ │ │ └── test_generate_task_pipeline_core.py
│ │ │ │ │ ├── agent_chat/
│ │ │ │ │ │ ├── test_agent_chat_app_config_manager.py
│ │ │ │ │ │ ├── test_agent_chat_app_generator.py
│ │ │ │ │ │ ├── test_agent_chat_app_runner.py
│ │ │ │ │ │ └── test_agent_chat_generate_response_converter.py
│ │ │ │ │ ├── chat/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ │ ├── test_app_generator_and_runner.py
│ │ │ │ │ │ ├── test_base_app_runner_multimodal.py
│ │ │ │ │ │ └── test_generate_response_converter.py
│ │ │ │ │ ├── common/
│ │ │ │ │ │ ├── test_graph_runtime_state_support.py
│ │ │ │ │ │ ├── test_workflow_response_converter.py
│ │ │ │ │ │ ├── test_workflow_response_converter_human_input.py
│ │ │ │ │ │ ├── test_workflow_response_converter_resumption.py
│ │ │ │ │ │ └── test_workflow_response_converter_truncation.py
│ │ │ │ │ ├── completion/
│ │ │ │ │ │ ├── test_app_runner.py
│ │ │ │ │ │ ├── test_completion_app_config_manager.py
│ │ │ │ │ │ ├── test_completion_completion_app_generator.py
│ │ │ │ │ │ └── test_completion_generate_response_converter.py
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ ├── test_pipeline_config_manager.py
│ │ │ │ │ │ ├── test_pipeline_generate_response_converter.py
│ │ │ │ │ │ ├── test_pipeline_generator.py
│ │ │ │ │ │ ├── test_pipeline_queue_manager.py
│ │ │ │ │ │ └── test_pipeline_runner.py
│ │ │ │ │ ├── test_advanced_chat_app_generator.py
│ │ │ │ │ ├── test_base_app_generator.py
│ │ │ │ │ ├── test_base_app_queue_manager.py
│ │ │ │ │ ├── test_base_app_runner.py
│ │ │ │ │ ├── test_exc.py
│ │ │ │ │ ├── test_message_based_app_generator.py
│ │ │ │ │ ├── test_message_based_app_queue_manager.py
│ │ │ │ │ ├── test_message_generator.py
│ │ │ │ │ ├── test_pause_resume.py
│ │ │ │ │ ├── test_streaming_utils.py
│ │ │ │ │ ├── test_workflow_app_generator.py
│ │ │ │ │ ├── test_workflow_app_runner_core.py
│ │ │ │ │ ├── test_workflow_app_runner_notifications.py
│ │ │ │ │ ├── test_workflow_app_runner_single_node.py
│ │ │ │ │ ├── test_workflow_pause_events.py
│ │ │ │ │ └── workflow/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_app_config_manager.py
│ │ │ │ │ ├── test_app_generator_extra.py
│ │ │ │ │ ├── test_app_queue_manager.py
│ │ │ │ │ ├── test_errors.py
│ │ │ │ │ ├── test_generate_response_converter.py
│ │ │ │ │ ├── test_generate_task_pipeline.py
│ │ │ │ │ └── test_generate_task_pipeline_core.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── test_app_invoke_entities.py
│ │ │ │ │ ├── test_queue_entities.py
│ │ │ │ │ ├── test_rag_pipeline_invoke_entities.py
│ │ │ │ │ └── test_task_entities.py
│ │ │ │ ├── features/
│ │ │ │ │ ├── rate_limiting/
│ │ │ │ │ │ ├── conftest.py
│ │ │ │ │ │ └── test_rate_limit.py
│ │ │ │ │ ├── test_annotation_reply.py
│ │ │ │ │ └── test_hosting_moderation.py
│ │ │ │ ├── layers/
│ │ │ │ │ ├── test_conversation_variable_persist_layer.py
│ │ │ │ │ ├── test_pause_state_persist_layer.py
│ │ │ │ │ ├── test_suspend_layer.py
│ │ │ │ │ ├── test_timeslice_layer.py
│ │ │ │ │ └── test_trigger_post_layer.py
│ │ │ │ ├── task_pipeline/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_based_generate_task_pipeline.py
│ │ │ │ │ ├── test_easy_ui_based_generate_task_pipeline.py
│ │ │ │ │ ├── test_easy_ui_based_generate_task_pipeline_core.py
│ │ │ │ │ ├── test_easy_ui_message_end_files.py
│ │ │ │ │ ├── test_exc.py
│ │ │ │ │ └── test_message_cycle_manager_optimization.py
│ │ │ │ ├── test_easy_ui_model_config_manager.py
│ │ │ │ └── workflow/
│ │ │ │ ├── layers/
│ │ │ │ │ └── test_persistence.py
│ │ │ │ ├── test_file_runtime.py
│ │ │ │ ├── test_node_factory.py
│ │ │ │ ├── test_observability_layer_extra.py
│ │ │ │ └── test_persistence_layer.py
│ │ │ ├── base/
│ │ │ │ └── test_app_generator_tts_publisher.py
│ │ │ ├── callback_handler/
│ │ │ │ ├── test_agent_tool_callback_handler.py
│ │ │ │ ├── test_index_tool_callback_handler.py
│ │ │ │ └── test_workflow_tool_callback_handler.py
│ │ │ ├── datasource/
│ │ │ │ ├── __base/
│ │ │ │ │ ├── test_datasource_plugin.py
│ │ │ │ │ ├── test_datasource_provider.py
│ │ │ │ │ └── test_datasource_runtime.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── test_api_entities.py
│ │ │ │ │ ├── test_common_entities.py
│ │ │ │ │ └── test_datasource_entities.py
│ │ │ │ ├── local_file/
│ │ │ │ │ ├── test_local_file_plugin.py
│ │ │ │ │ └── test_local_file_provider.py
│ │ │ │ ├── online_document/
│ │ │ │ │ ├── test_online_document_plugin.py
│ │ │ │ │ └── test_online_document_provider.py
│ │ │ │ ├── online_drive/
│ │ │ │ │ ├── test_online_drive_plugin.py
│ │ │ │ │ └── test_online_drive_provider.py
│ │ │ │ ├── test_datasource_file_manager.py
│ │ │ │ ├── test_datasource_manager.py
│ │ │ │ ├── test_errors.py
│ │ │ │ ├── test_file_upload.py
│ │ │ │ ├── test_notion_provider.py
│ │ │ │ ├── test_website_crawl.py
│ │ │ │ ├── utils/
│ │ │ │ │ └── test_message_transformer.py
│ │ │ │ └── website_crawl/
│ │ │ │ ├── test_website_crawl_plugin.py
│ │ │ │ └── test_website_crawl_provider.py
│ │ │ ├── entities/
│ │ │ │ ├── test_entities_agent_entities.py
│ │ │ │ ├── test_entities_document_task.py
│ │ │ │ ├── test_entities_embedding_type.py
│ │ │ │ ├── test_entities_execution_extra_content.py
│ │ │ │ ├── test_entities_knowledge_entities.py
│ │ │ │ ├── test_entities_mcp_provider.py
│ │ │ │ ├── test_entities_model_entities.py
│ │ │ │ ├── test_entities_parameter_entities.py
│ │ │ │ ├── test_entities_provider_configuration.py
│ │ │ │ └── test_entities_provider_entities.py
│ │ │ ├── extension/
│ │ │ │ ├── test_api_based_extension_requestor.py
│ │ │ │ ├── test_extensible.py
│ │ │ │ └── test_extension.py
│ │ │ ├── external_data_tool/
│ │ │ │ ├── api/
│ │ │ │ │ └── test_api.py
│ │ │ │ ├── test_base.py
│ │ │ │ ├── test_external_data_fetch.py
│ │ │ │ └── test_factory.py
│ │ │ ├── file/
│ │ │ │ └── test_models.py
│ │ │ ├── helper/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── code_executor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── javascript/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_javascript_transformer.py
│ │ │ │ │ └── python3/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_python3_transformer.py
│ │ │ │ ├── test_csv_sanitizer.py
│ │ │ │ ├── test_encrypter.py
│ │ │ │ ├── test_ssrf_proxy.py
│ │ │ │ └── test_trace_id_helper.py
│ │ │ ├── llm_generator/
│ │ │ │ ├── output_parser/
│ │ │ │ │ ├── test_rule_config_generator.py
│ │ │ │ │ └── test_structured_output.py
│ │ │ │ └── test_llm_generator.py
│ │ │ ├── logging/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_context.py
│ │ │ │ ├── test_filters.py
│ │ │ │ ├── test_structured_formatter.py
│ │ │ │ └── test_trace_helpers.py
│ │ │ ├── mcp/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── auth/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_auth_flow.py
│ │ │ │ ├── client/
│ │ │ │ │ ├── test_session.py
│ │ │ │ │ ├── test_sse.py
│ │ │ │ │ └── test_streamable_http.py
│ │ │ │ ├── server/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_streamable_http.py
│ │ │ │ ├── session/
│ │ │ │ │ ├── test_base_session.py
│ │ │ │ │ └── test_client_session.py
│ │ │ │ ├── test_auth_client_inheritance.py
│ │ │ │ ├── test_entities.py
│ │ │ │ ├── test_error.py
│ │ │ │ ├── test_mcp_client.py
│ │ │ │ ├── test_types.py
│ │ │ │ └── test_utils.py
│ │ │ ├── memory/
│ │ │ │ └── test_token_buffer_memory.py
│ │ │ ├── model_runtime/
│ │ │ │ └── test_model_provider_factory.py
│ │ │ ├── moderation/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── api/
│ │ │ │ │ └── test_api.py
│ │ │ │ ├── test_content_moderation.py
│ │ │ │ ├── test_input_moderation.py
│ │ │ │ ├── test_output_moderation.py
│ │ │ │ └── test_sensitive_word_filter.py
│ │ │ ├── ops/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_trace/
│ │ │ │ │ ├── data_exporter/
│ │ │ │ │ │ └── test_traceclient.py
│ │ │ │ │ ├── entities/
│ │ │ │ │ │ ├── test_aliyun_trace_entity.py
│ │ │ │ │ │ └── test_semconv.py
│ │ │ │ │ ├── test_aliyun_trace.py
│ │ │ │ │ └── test_aliyun_trace_utils.py
│ │ │ │ ├── arize_phoenix_trace/
│ │ │ │ │ └── test_arize_phoenix_trace.py
│ │ │ │ ├── langfuse_trace/
│ │ │ │ │ └── test_langfuse_trace.py
│ │ │ │ ├── langsmith_trace/
│ │ │ │ │ └── test_langsmith_trace.py
│ │ │ │ ├── mlflow_trace/
│ │ │ │ │ └── test_mlflow_trace.py
│ │ │ │ ├── opik_trace/
│ │ │ │ │ └── test_opik_trace.py
│ │ │ │ ├── tencent_trace/
│ │ │ │ │ ├── test_client.py
│ │ │ │ │ ├── test_span_builder.py
│ │ │ │ │ ├── test_tencent_trace.py
│ │ │ │ │ └── test_tencent_trace_utils.py
│ │ │ │ ├── test_arize_phoenix_trace.py
│ │ │ │ ├── test_base_trace_instance.py
│ │ │ │ ├── test_config_entity.py
│ │ │ │ ├── test_lookup_helpers.py
│ │ │ │ ├── test_opik_trace.py
│ │ │ │ ├── test_ops_trace_manager.py
│ │ │ │ ├── test_trace_queue_manager.py
│ │ │ │ ├── test_utils.py
│ │ │ │ └── weave_trace/
│ │ │ │ └── test_weave_trace.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── impl/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_agent_client.py
│ │ │ │ │ ├── test_asset_manager.py
│ │ │ │ │ ├── test_base_client_impl.py
│ │ │ │ │ ├── test_datasource_manager.py
│ │ │ │ │ ├── test_debugging_client.py
│ │ │ │ │ ├── test_endpoint_client_impl.py
│ │ │ │ │ ├── test_exc_impl.py
│ │ │ │ │ ├── test_model_client.py
│ │ │ │ │ ├── test_model_runtime_factory.py
│ │ │ │ │ ├── test_oauth_handler.py
│ │ │ │ │ ├── test_tool_manager.py
│ │ │ │ │ └── test_trigger_client.py
│ │ │ │ ├── test_backwards_invocation_app.py
│ │ │ │ ├── test_backwards_invocation_model.py
│ │ │ │ ├── test_endpoint_client.py
│ │ │ │ ├── test_model_runtime_adapter.py
│ │ │ │ ├── test_plugin_entities.py
│ │ │ │ ├── test_plugin_manager.py
│ │ │ │ ├── test_plugin_runtime.py
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_chunk_merger.py
│ │ │ │ └── test_http_parser.py
│ │ │ ├── prompt/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_advanced_prompt_transform.py
│ │ │ │ ├── test_agent_history_prompt_transform.py
│ │ │ │ ├── test_extract_thread_messages.py
│ │ │ │ ├── test_prompt_message.py
│ │ │ │ ├── test_prompt_transform.py
│ │ │ │ └── test_simple_prompt_transform.py
│ │ │ ├── rag/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cleaner/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_clean_processor.py
│ │ │ │ ├── data_post_processor/
│ │ │ │ │ └── test_data_post_processor.py
│ │ │ │ ├── datasource/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── keyword/
│ │ │ │ │ │ ├── jieba/
│ │ │ │ │ │ │ ├── test_jieba.py
│ │ │ │ │ │ │ ├── test_jieba_keyword_table_handler.py
│ │ │ │ │ │ │ └── test_stopwords.py
│ │ │ │ │ │ ├── test_keyword_base.py
│ │ │ │ │ │ └── test_keyword_factory.py
│ │ │ │ │ ├── test_datasource_retrieval.py
│ │ │ │ │ └── vdb/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── alibabacloud_mysql/
│ │ │ │ │ │ ├── test_alibabacloud_mysql_factory.py
│ │ │ │ │ │ └── test_alibabacloud_mysql_vector.py
│ │ │ │ │ ├── analyticdb/
│ │ │ │ │ │ ├── test_analyticdb_vector.py
│ │ │ │ │ │ ├── test_analyticdb_vector_openapi.py
│ │ │ │ │ │ └── test_analyticdb_vector_sql.py
│ │ │ │ │ ├── baidu/
│ │ │ │ │ │ └── test_baidu_vector.py
│ │ │ │ │ ├── chroma/
│ │ │ │ │ │ └── test_chroma_vector.py
│ │ │ │ │ ├── clickzetta/
│ │ │ │ │ │ └── test_clickzetta_vector.py
│ │ │ │ │ ├── couchbase/
│ │ │ │ │ │ └── test_couchbase_vector.py
│ │ │ │ │ ├── elasticsearch/
│ │ │ │ │ │ ├── test_elasticsearch_ja_vector.py
│ │ │ │ │ │ └── test_elasticsearch_vector.py
│ │ │ │ │ ├── hologres/
│ │ │ │ │ │ └── test_hologres_vector.py
│ │ │ │ │ ├── huawei/
│ │ │ │ │ │ └── test_huawei_cloud_vector.py
│ │ │ │ │ ├── iris/
│ │ │ │ │ │ └── test_iris_vector.py
│ │ │ │ │ ├── lindorm/
│ │ │ │ │ │ └── test_lindorm_vector.py
│ │ │ │ │ ├── matrixone/
│ │ │ │ │ │ └── test_matrixone_vector.py
│ │ │ │ │ ├── milvus/
│ │ │ │ │ │ └── test_milvus.py
│ │ │ │ │ ├── myscale/
│ │ │ │ │ │ └── test_myscale_vector.py
│ │ │ │ │ ├── oceanbase/
│ │ │ │ │ │ └── test_oceanbase_vector.py
│ │ │ │ │ ├── opengauss/
│ │ │ │ │ │ └── test_opengauss.py
│ │ │ │ │ ├── opensearch/
│ │ │ │ │ │ └── test_opensearch_vector.py
│ │ │ │ │ ├── oracle/
│ │ │ │ │ │ └── test_oraclevector.py
│ │ │ │ │ ├── pgvecto_rs/
│ │ │ │ │ │ └── test_pgvecto_rs.py
│ │ │ │ │ ├── pgvector/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_pgvector.py
│ │ │ │ │ ├── pyvastbase/
│ │ │ │ │ │ └── test_vastbase_vector.py
│ │ │ │ │ ├── qdrant/
│ │ │ │ │ │ └── test_qdrant_vector.py
│ │ │ │ │ ├── relyt/
│ │ │ │ │ │ └── test_relyt_vector.py
│ │ │ │ │ ├── tablestore/
│ │ │ │ │ │ └── test_tablestore_vector.py
│ │ │ │ │ ├── tencent/
│ │ │ │ │ │ └── test_tencent_vector.py
│ │ │ │ │ ├── test_field.py
│ │ │ │ │ ├── test_vector_base.py
│ │ │ │ │ ├── test_vector_factory.py
│ │ │ │ │ ├── tidb_on_qdrant/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_tidb_on_qdrant_vector.py
│ │ │ │ │ ├── tidb_vector/
│ │ │ │ │ │ └── test_tidb_vector.py
│ │ │ │ │ ├── upstash/
│ │ │ │ │ │ └── test_upstash_vector.py
│ │ │ │ │ ├── vikingdb/
│ │ │ │ │ │ └── test_vikingdb_vector.py
│ │ │ │ │ └── weaviate/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_weavaite.py
│ │ │ │ │ └── test_weaviate_vector.py
│ │ │ │ ├── docstore/
│ │ │ │ │ └── test_dataset_docstore.py
│ │ │ │ ├── embedding/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_cached_embedding.py
│ │ │ │ │ ├── test_embedding_base.py
│ │ │ │ │ └── test_embedding_service.py
│ │ │ │ ├── extractor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── blob/
│ │ │ │ │ │ └── test_blob.py
│ │ │ │ │ ├── firecrawl/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── test_firecrawl.py
│ │ │ │ │ ├── test_csv_extractor.py
│ │ │ │ │ ├── test_excel_extractor.py
│ │ │ │ │ ├── test_extract_processor.py
│ │ │ │ │ ├── test_extractor_base.py
│ │ │ │ │ ├── test_helpers.py
│ │ │ │ │ ├── test_html_extractor.py
│ │ │ │ │ ├── test_jina_reader_extractor.py
│ │ │ │ │ ├── test_markdown_extractor.py
│ │ │ │ │ ├── test_notion_extractor.py
│ │ │ │ │ ├── test_pdf_extractor.py
│ │ │ │ │ ├── test_text_extractor.py
│ │ │ │ │ ├── test_word_extractor.py
│ │ │ │ │ ├── unstructured/
│ │ │ │ │ │ └── test_unstructured_extractors.py
│ │ │ │ │ └── watercrawl/
│ │ │ │ │ └── test_watercrawl.py
│ │ │ │ ├── indexing/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── processor/
│ │ │ │ │ │ ├── conftest.py
│ │ │ │ │ │ ├── test_paragraph_index_processor.py
│ │ │ │ │ │ ├── test_parent_child_index_processor.py
│ │ │ │ │ │ └── test_qa_index_processor.py
│ │ │ │ │ ├── test_index_processor.py
│ │ │ │ │ ├── test_index_processor_base.py
│ │ │ │ │ ├── test_index_processor_factory.py
│ │ │ │ │ └── test_indexing_runner.py
│ │ │ │ ├── pipeline/
│ │ │ │ │ └── test_queue.py
│ │ │ │ ├── rerank/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_reranker.py
│ │ │ │ ├── retrieval/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_dataset_retrieval.py
│ │ │ │ │ ├── test_dataset_retrieval_methods.py
│ │ │ │ │ ├── test_multi_dataset_function_call_router.py
│ │ │ │ │ ├── test_multi_dataset_react_route.py
│ │ │ │ │ └── test_structured_chat_output_parser.py
│ │ │ │ └── splitter/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_text_splitter.py
│ │ │ ├── repositories/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_celery_workflow_execution_repository.py
│ │ │ │ ├── test_celery_workflow_node_execution_repository.py
│ │ │ │ ├── test_factory.py
│ │ │ │ ├── test_human_input_form_repository_impl.py
│ │ │ │ ├── test_human_input_repository.py
│ │ │ │ ├── test_sqlalchemy_workflow_execution_repository.py
│ │ │ │ ├── test_sqlalchemy_workflow_node_execution_repository.py
│ │ │ │ ├── test_workflow_node_execution_conflict_handling.py
│ │ │ │ └── test_workflow_node_execution_truncation.py
│ │ │ ├── schemas/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_registry.py
│ │ │ │ ├── test_resolver.py
│ │ │ │ └── test_schema_manager.py
│ │ │ ├── telemetry/
│ │ │ │ ├── test_facade.py
│ │ │ │ └── test_gateway_integration.py
│ │ │ ├── test_file.py
│ │ │ ├── test_model_manager.py
│ │ │ ├── test_provider_configuration.py
│ │ │ ├── test_provider_manager.py
│ │ │ ├── test_trigger_debug_event_selectors.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── entities/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_api_entities.py
│ │ │ │ ├── test_base_tool.py
│ │ │ │ ├── test_builtin_tool_base.py
│ │ │ │ ├── test_builtin_tool_provider.py
│ │ │ │ ├── test_builtin_tools_extra.py
│ │ │ │ ├── test_custom_tool.py
│ │ │ │ ├── test_custom_tool_provider.py
│ │ │ │ ├── test_dataset_retriever_tool.py
│ │ │ │ ├── test_mcp_tool.py
│ │ │ │ ├── test_mcp_tool_provider.py
│ │ │ │ ├── test_plugin_tool.py
│ │ │ │ ├── test_plugin_tool_provider.py
│ │ │ │ ├── test_signature.py
│ │ │ │ ├── test_tool_engine.py
│ │ │ │ ├── test_tool_entities.py
│ │ │ │ ├── test_tool_file_manager.py
│ │ │ │ ├── test_tool_label_manager.py
│ │ │ │ ├── test_tool_manager.py
│ │ │ │ ├── test_tool_parameter_type.py
│ │ │ │ ├── test_tool_provider_controller.py
│ │ │ │ ├── utils/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_configuration.py
│ │ │ │ │ ├── test_encryption.py
│ │ │ │ │ ├── test_message_transformer.py
│ │ │ │ │ ├── test_misc_utils_extra.py
│ │ │ │ │ ├── test_model_invocation_utils.py
│ │ │ │ │ ├── test_parser.py
│ │ │ │ │ ├── test_system_oauth_encryption.py
│ │ │ │ │ ├── test_tool_engine_serialization.py
│ │ │ │ │ ├── test_web_reader_tool.py
│ │ │ │ │ └── test_workflow_configuration_sync.py
│ │ │ │ └── workflow_as_tool/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_provider.py
│ │ │ │ └── test_tool.py
│ │ │ ├── trigger/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── debug/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_debug_event_bus.py
│ │ │ │ │ └── test_debug_event_selectors.py
│ │ │ │ ├── test_provider.py
│ │ │ │ ├── test_trigger_manager.py
│ │ │ │ └── utils/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_utils_encryption.py
│ │ │ │ ├── test_utils_endpoint.py
│ │ │ │ └── test_utils_locks.py
│ │ │ ├── variables/
│ │ │ │ ├── test_segment.py
│ │ │ │ ├── test_segment_type.py
│ │ │ │ ├── test_segment_type_validation.py
│ │ │ │ └── test_variables.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── context/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_execution_context.py
│ │ │ │ └── test_flask_app_context.py
│ │ │ ├── entities/
│ │ │ │ └── test_private_workflow_pause.py
│ │ │ ├── graph_engine/
│ │ │ │ ├── README.md
│ │ │ │ ├── __init__.py
│ │ │ │ ├── layers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── conftest.py
│ │ │ │ │ ├── test_llm_quota.py
│ │ │ │ │ └── test_observability.py
│ │ │ │ ├── test_mock_config.py
│ │ │ │ ├── test_mock_factory.py
│ │ │ │ ├── test_mock_nodes.py
│ │ │ │ ├── test_parallel_human_input_join_resume.py
│ │ │ │ ├── test_table_runner.py
│ │ │ │ └── test_tool_in_chatflow.py
│ │ │ ├── nodes/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_message_transformer.py
│ │ │ │ │ └── test_runtime_support.py
│ │ │ │ ├── answer/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_answer.py
│ │ │ │ ├── base/
│ │ │ │ │ ├── test_base_node.py
│ │ │ │ │ └── test_get_node_type_classes_mapping.py
│ │ │ │ ├── code/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── code_node_spec.py
│ │ │ │ ├── datasource/
│ │ │ │ │ └── test_datasource_node.py
│ │ │ │ ├── http_request/
│ │ │ │ │ ├── test_http_request_executor.py
│ │ │ │ │ └── test_http_request_node.py
│ │ │ │ ├── human_input/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_email_delivery_config.py
│ │ │ │ │ ├── test_entities.py
│ │ │ │ │ └── test_human_input_form_filled_event.py
│ │ │ │ ├── iteration/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_iteration_child_engine_errors.py
│ │ │ │ ├── knowledge_index/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_knowledge_index_node.py
│ │ │ │ ├── knowledge_retrieval/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_knowledge_retrieval_node.py
│ │ │ │ ├── list_operator/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── node_spec.py
│ │ │ │ ├── llm/
│ │ │ │ │ ├── test_llm_utils.py
│ │ │ │ │ └── test_node.py
│ │ │ │ ├── parameter_extractor/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_parameter_extractor_node.py
│ │ │ │ ├── template_transform/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── template_transform_node_spec.py
│ │ │ │ │ └── test_template_transform_node.py
│ │ │ │ ├── test_base_node.py
│ │ │ │ ├── test_document_extractor_node.py
│ │ │ │ ├── test_if_else.py
│ │ │ │ ├── test_list_operator.py
│ │ │ │ ├── test_start_node_json_object.py
│ │ │ │ ├── tool/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_tool_node.py
│ │ │ │ │ └── test_tool_node_runtime.py
│ │ │ │ ├── trigger_plugin/
│ │ │ │ │ └── test_trigger_event_node.py
│ │ │ │ └── webhook/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_entities.py
│ │ │ │ ├── test_exceptions.py
│ │ │ │ ├── test_webhook_file_conversion.py
│ │ │ │ └── test_webhook_node.py
│ │ │ ├── test_human_input_compat.py
│ │ │ ├── test_human_input_forms.py
│ │ │ ├── test_node_factory.py
│ │ │ ├── test_node_mapping_bootstrap.py
│ │ │ ├── test_node_runtime.py
│ │ │ ├── test_system_variable.py
│ │ │ ├── test_variable_pool.py
│ │ │ ├── test_variable_pool_conver.py
│ │ │ ├── test_workflow_entry.py
│ │ │ ├── test_workflow_entry_helpers.py
│ │ │ └── test_workflow_entry_redis_channel.py
│ │ ├── enterprise/
│ │ │ └── telemetry/
│ │ │ ├── __init__.py
│ │ │ ├── test_contracts.py
│ │ │ ├── test_draft_trace.py
│ │ │ ├── test_enterprise_trace.py
│ │ │ ├── test_event_handlers.py
│ │ │ ├── test_exporter.py
│ │ │ ├── test_gateway.py
│ │ │ ├── test_id_generator.py
│ │ │ ├── test_metric_handler.py
│ │ │ └── test_telemetry_log.py
│ │ ├── events/
│ │ │ └── test_app_event_signals.py
│ │ ├── extensions/
│ │ │ ├── logstore/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_sql_escape.py
│ │ │ ├── otel/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── decorators/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── handlers/
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── test_generate_handler.py
│ │ │ │ │ │ └── test_workflow_app_runner_handler.py
│ │ │ │ │ ├── test_base.py
│ │ │ │ │ └── test_handler.py
│ │ │ │ └── test_celery_sqlcommenter.py
│ │ │ ├── storage/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_supabase_storage.py
│ │ │ ├── test_celery_ssl.py
│ │ │ ├── test_ext_request_logging.py
│ │ │ ├── test_pubsub_channel.py
│ │ │ └── test_redis.py
│ │ ├── factories/
│ │ │ ├── test_build_from_mapping.py
│ │ │ ├── test_file_factory.py
│ │ │ └── test_variable_factory.py
│ │ ├── fields/
│ │ │ └── test_file_fields.py
│ │ ├── libs/
│ │ │ ├── _human_input/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── support.py
│ │ │ │ ├── test_form_service.py
│ │ │ │ └── test_models.py
│ │ │ ├── broadcast_channel/
│ │ │ │ └── redis/
│ │ │ │ ├── test_channel_unit_tests.py
│ │ │ │ └── test_streams_channel_unit_tests.py
│ │ │ ├── test_api_token_cache.py
│ │ │ ├── test_archive_storage.py
│ │ │ ├── test_cron_compatibility.py
│ │ │ ├── test_custom_inputs.py
│ │ │ ├── test_datetime_utils.py
│ │ │ ├── test_email.py
│ │ │ ├── test_email_i18n.py
│ │ │ ├── test_encryption.py
│ │ │ ├── test_external_api.py
│ │ │ ├── test_file_utils.py
│ │ │ ├── test_flask_utils.py
│ │ │ ├── test_helper.py
│ │ │ ├── test_json_in_md_parser.py
│ │ │ ├── test_jwt_imports.py
│ │ │ ├── test_login.py
│ │ │ ├── test_oauth_base.py
│ │ │ ├── test_oauth_clients.py
│ │ │ ├── test_orjson.py
│ │ │ ├── test_pandas.py
│ │ │ ├── test_passport.py
│ │ │ ├── test_password.py
│ │ │ ├── test_pyrefly_diagnostics.py
│ │ │ ├── test_rate_limiter.py
│ │ │ ├── test_rsa.py
│ │ │ ├── test_schedule_utils_enhanced.py
│ │ │ ├── test_sendgrid_client.py
│ │ │ ├── test_smtp_client.py
│ │ │ ├── test_time_parser.py
│ │ │ ├── test_token.py
│ │ │ ├── test_uuid_utils.py
│ │ │ ├── test_workspace_permission.py
│ │ │ └── test_yarl.py
│ │ ├── models/
│ │ │ ├── __init__.py
│ │ │ ├── test_account.py
│ │ │ ├── test_account_models.py
│ │ │ ├── test_app_models.py
│ │ │ ├── test_base.py
│ │ │ ├── test_conversation_variable.py
│ │ │ ├── test_dataset_models.py
│ │ │ ├── test_enums_creator_user_role.py
│ │ │ ├── test_model.py
│ │ │ ├── test_plugin_entities.py
│ │ │ ├── test_provider_models.py
│ │ │ ├── test_tool_models.py
│ │ │ ├── test_workflow.py
│ │ │ ├── test_workflow_models.py
│ │ │ ├── test_workflow_node_execution_offload.py
│ │ │ └── test_workflow_trigger_log.py
│ │ ├── oss/
│ │ │ ├── __init__.py
│ │ │ ├── __mock/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aliyun_oss.py
│ │ │ │ ├── base.py
│ │ │ │ ├── local.py
│ │ │ │ ├── tencent_cos.py
│ │ │ │ └── volcengine_tos.py
│ │ │ ├── aliyun_oss/
│ │ │ │ └── aliyun_oss/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_aliyun_oss.py
│ │ │ ├── opendal/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_opendal.py
│ │ │ ├── tencent_cos/
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_tencent_cos.py
│ │ │ └── volcengine_tos/
│ │ │ ├── __init__.py
│ │ │ └── test_volcengine_tos.py
│ │ ├── repositories/
│ │ │ ├── __init__.py
│ │ │ └── workflow_node_execution/
│ │ │ ├── __init__.py
│ │ │ ├── test_sqlalchemy_repository.py
│ │ │ └── test_sqlalchemy_workflow_node_execution_repository.py
│ │ ├── services/
│ │ │ ├── __init__.py
│ │ │ ├── auth/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_api_key_auth_base.py
│ │ │ │ ├── test_api_key_auth_factory.py
│ │ │ │ ├── test_auth_type.py
│ │ │ │ ├── test_firecrawl_auth.py
│ │ │ │ ├── test_jina_auth.py
│ │ │ │ ├── test_jina_auth_standalone_module.py
│ │ │ │ └── test_watercrawl_auth.py
│ │ │ ├── controller_api.py
│ │ │ ├── dataset_metadata.py
│ │ │ ├── dataset_permission_service.py
│ │ │ ├── dataset_service_test_helpers.py
│ │ │ ├── dataset_service_update_delete.py
│ │ │ ├── document_indexing_task_proxy.py
│ │ │ ├── document_service_status.py
│ │ │ ├── document_service_validation.py
│ │ │ ├── enterprise/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_enterprise_service.py
│ │ │ │ ├── test_plugin_manager_service.py
│ │ │ │ └── test_traceparent_propagation.py
│ │ │ ├── external_dataset_service.py
│ │ │ ├── hit_service.py
│ │ │ ├── plugin/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_dependencies_analysis.py
│ │ │ │ ├── test_endpoint_service.py
│ │ │ │ ├── test_oauth_service.py
│ │ │ │ ├── test_plugin_auto_upgrade_service.py
│ │ │ │ └── test_plugin_permission_service.py
│ │ │ ├── recommend_app/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_buildin_retrieval.py
│ │ │ │ ├── test_recommend_app_factory.py
│ │ │ │ ├── test_recommend_app_type.py
│ │ │ │ └── test_remote_retrieval.py
│ │ │ ├── retention/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_messages_clean_policy.py
│ │ │ │ └── workflow_run/
│ │ │ │ ├── test_clear_free_plan_expired_workflow_run_logs.py
│ │ │ │ └── test_restore_archived_workflow_run.py
│ │ │ ├── segment_service.py
│ │ │ ├── services_test_help.py
│ │ │ ├── test_account_service.py
│ │ │ ├── test_annotation_service.py
│ │ │ ├── test_app_dsl_service.py
│ │ │ ├── test_app_dsl_service_import_yaml_url.py
│ │ │ ├── test_app_generate_service.py
│ │ │ ├── test_app_generate_service_streaming_integration.py
│ │ │ ├── test_app_model_config_service.py
│ │ │ ├── test_app_task_service.py
│ │ │ ├── test_archive_workflow_run_logs.py
│ │ │ ├── test_async_workflow_service.py
│ │ │ ├── test_audio_service.py
│ │ │ ├── test_batch_indexing_base.py
│ │ │ ├── test_billing_service.py
│ │ │ ├── test_clear_free_plan_expired_workflow_run_logs.py
│ │ │ ├── test_clear_free_plan_tenant_expired_logs.py
│ │ │ ├── test_code_based_extension_service.py
│ │ │ ├── test_conversation_service.py
│ │ │ ├── test_dataset_service_dataset.py
│ │ │ ├── test_dataset_service_document.py
│ │ │ ├── test_dataset_service_lock_not_owned.py
│ │ │ ├── test_dataset_service_segment.py
│ │ │ ├── test_datasource_provider_service.py
│ │ │ ├── test_document_indexing_task_proxy.py
│ │ │ ├── test_duplicate_document_indexing_task_proxy.py
│ │ │ ├── test_export_app_messages.py
│ │ │ ├── test_external_dataset_service.py
│ │ │ ├── test_feature_service_human_input_email_delivery.py
│ │ │ ├── test_file_service.py
│ │ │ ├── test_hit_testing_service.py
│ │ │ ├── test_human_input_service.py
│ │ │ ├── test_knowledge_service.py
│ │ │ ├── test_message_service.py
│ │ │ ├── test_messages_clean_service.py
│ │ │ ├── test_metadata_bug_complete.py
│ │ │ ├── test_metadata_nullable_bug.py
│ │ │ ├── test_model_load_balancing_service.py
│ │ │ ├── test_model_provider_service_sanitization.py
│ │ │ ├── test_operation_service.py
│ │ │ ├── test_ops_service.py
│ │ │ ├── test_rag_pipeline_task_proxy.py
│ │ │ ├── test_recommended_app_service.py
│ │ │ ├── test_schedule_service.py
│ │ │ ├── test_summary_index_service.py
│ │ │ ├── test_trigger_provider_service.py
│ │ │ ├── test_variable_truncator.py
│ │ │ ├── test_vector_service.py
│ │ │ ├── test_webhook_service.py
│ │ │ ├── test_website_service.py
│ │ │ ├── test_workflow_run_service_pause.py
│ │ │ ├── test_workflow_service.py
│ │ │ ├── tools/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_builtin_tools_manage_service.py
│ │ │ │ ├── test_mcp_tools_transform.py
│ │ │ │ ├── test_tool_labels_service.py
│ │ │ │ ├── test_tools_manage_service.py
│ │ │ │ └── test_tools_transform_service.py
│ │ │ ├── vector_service.py
│ │ │ └── workflow/
│ │ │ ├── __init__.py
│ │ │ ├── test_draft_var_loader_simple.py
│ │ │ ├── test_queue_dispatcher.py
│ │ │ ├── test_scheduler.py
│ │ │ ├── test_workflow_draft_variable_service.py
│ │ │ ├── test_workflow_event_snapshot_service.py
│ │ │ ├── test_workflow_human_input_delivery.py
│ │ │ └── test_workflow_restore.py
│ │ ├── tasks/
│ │ │ ├── __init__.py
│ │ │ ├── test_async_workflow_tasks.py
│ │ │ ├── test_clean_dataset_task.py
│ │ │ ├── test_dataset_indexing_task.py
│ │ │ ├── test_delete_account_task.py
│ │ │ ├── test_document_indexing_sync_task.py
│ │ │ ├── test_duplicate_document_indexing_task.py
│ │ │ ├── test_enterprise_telemetry_task.py
│ │ │ ├── test_human_input_timeout_tasks.py
│ │ │ ├── test_mail_human_input_delivery_task.py
│ │ │ ├── test_mail_send_task.py
│ │ │ ├── test_remove_app_and_related_data_task.py
│ │ │ ├── test_summary_queue_isolation.py
│ │ │ ├── test_workflow_execute_task.py
│ │ │ └── test_workflow_node_execution_tasks.py
│ │ ├── tools/
│ │ │ ├── __init__.py
│ │ │ ├── test_api_tool.py
│ │ │ └── test_mcp_tool.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── http_parser/
│ │ │ └── test_oauth_convert_request_to_raw_data.py
│ │ ├── oauth_encryption/
│ │ │ └── test_system_oauth_encryption.py
│ │ ├── position_helper/
│ │ │ └── test_position_helper.py
│ │ ├── structured_output_parser/
│ │ │ ├── __init__.py
│ │ │ └── test_structured_output_parser.py
│ │ ├── test_text_processing.py
│ │ └── yaml/
│ │ ├── __init__.py
│ │ └── test_yaml_utils.py
│ └── workflow_test_utils.py
├── codecov.yml
├── dev/
│ ├── basedpyright-check
│ ├── pyrefly-check-local
│ ├── pytest/
│ │ ├── pytest_config_tests.py
│ │ ├── pytest_full.sh
│ │ ├── pytest_unit_tests.sh
│ │ └── pytest_vdb.sh
│ ├── reformat
│ ├── setup
│ ├── start-api
│ ├── start-beat
│ ├── start-docker-compose
│ ├── start-web
│ ├── start-worker
│ ├── sync-uv
│ ├── ty-check
│ └── update-uv
├── docker/
│ ├── README.md
│ ├── certbot/
│ │ ├── README.md
│ │ ├── docker-entrypoint.sh
│ │ └── update-cert.template.txt
│ ├── couchbase-server/
│ │ ├── Dockerfile
│ │ └── init-cbserver.sh
│ ├── dify-env-sync.py
│ ├── dify-env-sync.sh
│ ├── docker-compose-template.yaml
│ ├── docker-compose.middleware.yaml
│ ├── docker-compose.yaml
│ ├── elasticsearch/
│ │ └── docker-entrypoint.sh
│ ├── generate_docker_compose
│ ├── iris/
│ │ ├── docker-entrypoint.sh
│ │ └── iris-init.script
│ ├── middleware.env.example
│ ├── nginx/
│ │ ├── conf.d/
│ │ │ └── default.conf.template
│ │ ├── docker-entrypoint.sh
│ │ ├── https.conf.template
│ │ ├── nginx.conf.template
│ │ ├── proxy.conf.template
│ │ └── ssl/
│ │ └── .gitkeep
│ ├── pgvector/
│ │ └── docker-entrypoint.sh
│ ├── ssrf_proxy/
│ │ ├── docker-entrypoint.sh
│ │ └── squid.conf.template
│ ├── startupscripts/
│ │ ├── init.sh
│ │ └── init_user.script
│ ├── tidb/
│ │ ├── config/
│ │ │ ├── pd.toml
│ │ │ ├── tiflash-learner.toml
│ │ │ └── tiflash.toml
│ │ └── docker-compose.yaml
│ └── volumes/
│ ├── myscale/
│ │ └── config/
│ │ └── users.d/
│ │ └── custom_users_config.xml
│ ├── oceanbase/
│ │ └── init.d/
│ │ └── vec_memory.sql
│ ├── opensearch/
│ │ └── opensearch_dashboards.yml
│ └── sandbox/
│ └── conf/
│ ├── config.yaml
│ └── config.yaml.example
├── docs/
│ ├── ar-SA/
│ │ └── README.md
│ ├── bn-BD/
│ │ └── README.md
│ ├── de-DE/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── es-ES/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── eu-ai-act-compliance.md
│ ├── fr-FR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── hi-IN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── it-IT/
│ │ └── README.md
│ ├── ja-JP/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── ko-KR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── pt-BR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── sl-SI/
│ │ └── README.md
│ ├── suggested-questions-configuration.md
│ ├── tlh/
│ │ └── README.md
│ ├── tr-TR/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── vi-VN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ ├── weaviate/
│ │ └── WEAVIATE_MIGRATION_GUIDE/
│ │ └── README.md
│ ├── zh-CN/
│ │ ├── CONTRIBUTING.md
│ │ └── README.md
│ └── zh-TW/
│ ├── CONTRIBUTING.md
│ └── README.md
├── e2e/
│ ├── .gitignore
│ ├── AGENTS.md
│ ├── README.md
│ ├── cucumber.config.ts
│ ├── features/
│ │ ├── apps/
│ │ │ └── create-app.feature
│ │ ├── smoke/
│ │ │ ├── authenticated-entry.feature
│ │ │ └── install.feature
│ │ ├── step-definitions/
│ │ │ ├── apps/
│ │ │ │ └── create-app.steps.ts
│ │ │ ├── common/
│ │ │ │ ├── auth.steps.ts
│ │ │ │ └── navigation.steps.ts
│ │ │ └── smoke/
│ │ │ └── install.steps.ts
│ │ └── support/
│ │ ├── hooks.ts
│ │ └── world.ts
│ ├── fixtures/
│ │ └── auth.ts
│ ├── package.json
│ ├── scripts/
│ │ ├── common.ts
│ │ ├── run-cucumber.ts
│ │ └── setup.ts
│ ├── support/
│ │ ├── process.ts
│ │ └── web-server.ts
│ ├── test-env.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── package.json
├── pnpm-workspace.yaml
├── scripts/
│ └── stress-test/
│ ├── README.md
│ ├── cleanup.py
│ ├── common/
│ │ ├── __init__.py
│ │ ├── config_helper.py
│ │ └── logger_helper.py
│ ├── locust.conf
│ ├── run_locust_stress_test.sh
│ ├── setup/
│ │ ├── configure_openai_plugin.py
│ │ ├── create_api_key.py
│ │ ├── dsl/
│ │ │ └── workflow_llm.yml
│ │ ├── import_workflow_app.py
│ │ ├── install_openai_plugin.py
│ │ ├── login_admin.py
│ │ ├── mock_openai_server.py
│ │ ├── publish_workflow.py
│ │ ├── run_workflow.py
│ │ └── setup_admin.py
│ ├── setup_all.py
│ └── sse_benchmark.py
├── sdks/
│ ├── README.md
│ ├── nodejs-client/
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── eslint.config.js
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ └── publish.sh
│ │ ├── src/
│ │ │ ├── client/
│ │ │ │ ├── base.test.ts
│ │ │ │ ├── base.ts
│ │ │ │ ├── chat.test.ts
│ │ │ │ ├── chat.ts
│ │ │ │ ├── completion.test.ts
│ │ │ │ ├── completion.ts
│ │ │ │ ├── knowledge-base.test.ts
│ │ │ │ ├── knowledge-base.ts
│ │ │ │ ├── validation.test.ts
│ │ │ │ ├── validation.ts
│ │ │ │ ├── workflow.test.ts
│ │ │ │ ├── workflow.ts
│ │ │ │ ├── workspace.test.ts
│ │ │ │ └── workspace.ts
│ │ │ ├── errors/
│ │ │ │ ├── dify-error.test.ts
│ │ │ │ └── dify-error.ts
│ │ │ ├── http/
│ │ │ │ ├── client.test.ts
│ │ │ │ ├── client.ts
│ │ │ │ ├── form-data.test.ts
│ │ │ │ ├── form-data.ts
│ │ │ │ ├── retry.test.ts
│ │ │ │ ├── retry.ts
│ │ │ │ ├── sse.test.ts
│ │ │ │ └── sse.ts
│ │ │ ├── index.test.ts
│ │ │ ├── index.ts
│ │ │ ├── internal/
│ │ │ │ └── type-guards.ts
│ │ │ └── types/
│ │ │ ├── annotation.ts
│ │ │ ├── chat.ts
│ │ │ ├── common.ts
│ │ │ ├── completion.ts
│ │ │ ├── knowledge-base.ts
│ │ │ ├── workflow.ts
│ │ │ └── workspace.ts
│ │ ├── tests/
│ │ │ ├── http.integration.test.ts
│ │ │ └── test-utils.ts
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.ts
│ └── php-client/
│ ├── .gitignore
│ ├── README.md
│ ├── composer.json
│ └── dify-client.php
├── taze.config.js
├── vite.config.ts
└── web/
├── .gitignore
├── .npmrc
├── .storybook/
│ ├── __mocks__/
│ │ ├── context-block.tsx
│ │ ├── history-block.tsx
│ │ └── query-block.tsx
│ ├── main.ts
│ ├── preview.tsx
│ ├── storybook.css
│ └── utils/
│ ├── audio-player-manager.mock.ts
│ └── form-story-wrapper.tsx
├── .vscode/
│ ├── extensions.json
│ ├── launch.json
│ └── settings.example.json
├── AGENTS.md
├── Dockerfile
├── Dockerfile.dockerignore
├── README.md
├── __mocks__/
│ ├── provider-context.ts
│ └── zustand.ts
├── __tests__/
│ ├── apps/
│ │ ├── app-card-operations-flow.test.tsx
│ │ ├── app-list-browsing-flow.test.tsx
│ │ └── create-app-flow.test.tsx
│ ├── billing/
│ │ ├── billing-integration.test.tsx
│ │ ├── cloud-plan-payment-flow.test.tsx
│ │ ├── education-verification-flow.test.tsx
│ │ ├── partner-stack-flow.test.tsx
│ │ ├── pricing-modal-flow.test.tsx
│ │ └── self-hosted-plan-flow.test.tsx
│ ├── datasets/
│ │ ├── create-dataset-flow.test.tsx
│ │ ├── dataset-settings-flow.test.tsx
│ │ ├── document-management.test.tsx
│ │ ├── external-knowledge-base.test.tsx
│ │ ├── hit-testing-flow.test.tsx
│ │ ├── metadata-management-flow.test.tsx
│ │ ├── pipeline-datasource-flow.test.tsx
│ │ └── segment-crud.test.tsx
│ ├── description-validation.test.tsx
│ ├── develop/
│ │ ├── api-key-management-flow.test.tsx
│ │ └── develop-page-flow.test.tsx
│ ├── document-detail-navigation-fix.test.tsx
│ ├── document-list-sorting.test.tsx
│ ├── embedded-user-id-auth.test.tsx
│ ├── embedded-user-id-store.test.tsx
│ ├── explore/
│ │ ├── explore-app-list-flow.test.tsx
│ │ ├── installed-app-flow.test.tsx
│ │ └── sidebar-lifecycle-flow.test.tsx
│ ├── goto-anything/
│ │ ├── command-selector.test.tsx
│ │ ├── match-action.test.ts
│ │ ├── scope-command-tags.test.tsx
│ │ ├── search-error-handling.test.ts
│ │ └── slash-command-modes.test.tsx
│ ├── i18n-upload-features.test.ts
│ ├── instrumentation-client.spec.ts
│ ├── navigation-utils.test.ts
│ ├── plugin-tool-workflow-error.test.tsx
│ ├── plugins/
│ │ ├── plugin-auth-flow.test.tsx
│ │ ├── plugin-card-rendering.test.tsx
│ │ ├── plugin-data-utilities.test.ts
│ │ ├── plugin-install-flow.test.ts
│ │ ├── plugin-marketplace-to-install.test.tsx
│ │ └── plugin-page-filter-management.test.tsx
│ ├── rag-pipeline/
│ │ ├── chunk-preview-formatting.test.ts
│ │ ├── dsl-export-import-flow.test.ts
│ │ ├── input-field-crud-flow.test.ts
│ │ ├── input-field-editor-flow.test.ts
│ │ └── test-run-flow.test.ts
│ ├── real-browser-flicker.test.tsx
│ ├── share/
│ │ ├── text-generation-index-flow.test.tsx
│ │ ├── text-generation-run-batch-flow.test.tsx
│ │ └── text-generation-run-once-flow.test.tsx
│ ├── tools/
│ │ ├── tool-browsing-and-filtering.test.tsx
│ │ ├── tool-data-processing.test.ts
│ │ └── tool-provider-detail-flow.test.tsx
│ ├── unified-tags-logic.test.ts
│ ├── workflow-onboarding-integration.test.tsx
│ └── xss-prevention.test.tsx
├── app/
│ ├── (commonLayout)/
│ │ ├── app/
│ │ │ └── (appDetailLayout)/
│ │ │ ├── [appId]/
│ │ │ │ ├── annotations/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── configuration/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── develop/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout-main.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── logs/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── overview/
│ │ │ │ │ ├── card-view.tsx
│ │ │ │ │ ├── chart-view.tsx
│ │ │ │ │ ├── long-time-range-picker.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── time-range-picker/
│ │ │ │ │ │ ├── date-picker.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── range-selector.tsx
│ │ │ │ │ └── tracing/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── svg-attribute-error-reproduction.spec.tsx
│ │ │ │ │ ├── config-button.tsx
│ │ │ │ │ ├── config-popup.tsx
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── field.tsx
│ │ │ │ │ ├── panel.tsx
│ │ │ │ │ ├── provider-config-modal.tsx
│ │ │ │ │ ├── provider-panel.tsx
│ │ │ │ │ ├── tracing-icon.tsx
│ │ │ │ │ └── type.ts
│ │ │ │ ├── style.module.css
│ │ │ │ └── workflow/
│ │ │ │ └── page.tsx
│ │ │ └── layout.tsx
│ │ ├── apps/
│ │ │ └── page.tsx
│ │ ├── datasets/
│ │ │ ├── (datasetDetailLayout)/
│ │ │ │ ├── [datasetId]/
│ │ │ │ │ ├── api/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── documents/
│ │ │ │ │ │ ├── [documentId]/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── settings/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── create/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── create-from-pipeline/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ ├── hitTesting/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── layout-main.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── pipeline/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── settings/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── layout.tsx
│ │ │ ├── connect/
│ │ │ │ └── page.tsx
│ │ │ ├── create/
│ │ │ │ └── page.tsx
│ │ │ ├── create-from-pipeline/
│ │ │ │ └── page.tsx
│ │ │ ├── layout.spec.tsx
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ ├── education-apply/
│ │ │ └── page.tsx
│ │ ├── explore/
│ │ │ ├── apps/
│ │ │ │ └── page.tsx
│ │ │ ├── installed/
│ │ │ │ └── [appId]/
│ │ │ │ └── page.tsx
│ │ │ └── layout.tsx
│ │ ├── layout.tsx
│ │ ├── plugins/
│ │ │ └── page.tsx
│ │ ├── role-route-guard.spec.tsx
│ │ ├── role-route-guard.tsx
│ │ └── tools/
│ │ └── page.tsx
│ ├── (humanInputLayout)/
│ │ └── form/
│ │ └── [token]/
│ │ ├── form.tsx
│ │ └── page.tsx
│ ├── (shareLayout)/
│ │ ├── chat/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── chatbot/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── completion/
│ │ │ └── [token]/
│ │ │ └── page.tsx
│ │ ├── components/
│ │ │ ├── authenticated-layout.tsx
│ │ │ └── splash.tsx
│ │ ├── layout.tsx
│ │ ├── webapp-reset-password/
│ │ │ ├── check-code/
│ │ │ │ └── page.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ └── set-password/
│ │ │ └── page.tsx
│ │ ├── webapp-signin/
│ │ │ ├── check-code/
│ │ │ │ └── page.tsx
│ │ │ ├── components/
│ │ │ │ ├── external-member-sso-auth.tsx
│ │ │ │ ├── mail-and-code-auth.tsx
│ │ │ │ ├── mail-and-password-auth.tsx
│ │ │ │ └── sso-auth.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── normalForm.tsx
│ │ │ └── page.tsx
│ │ └── workflow/
│ │ └── [token]/
│ │ └── page.tsx
│ ├── account/
│ │ ├── (commonLayout)/
│ │ │ ├── account-page/
│ │ │ │ ├── AvatarWithEdit.tsx
│ │ │ │ ├── email-change-modal.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── delete-account/
│ │ │ │ ├── components/
│ │ │ │ │ ├── check-email.tsx
│ │ │ │ │ ├── feed-back.tsx
│ │ │ │ │ └── verify-email.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── state.tsx
│ │ │ ├── header.tsx
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ └── oauth/
│ │ └── authorize/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── activate/
│ │ ├── activateForm.tsx
│ │ └── page.tsx
│ ├── components/
│ │ ├── app/
│ │ │ ├── annotation/
│ │ │ │ ├── add-annotation-modal/
│ │ │ │ │ ├── edit-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── batch-action.spec.tsx
│ │ │ │ ├── batch-action.tsx
│ │ │ │ ├── batch-add-annotation-modal/
│ │ │ │ │ ├── csv-downloader.spec.tsx
│ │ │ │ │ ├── csv-downloader.tsx
│ │ │ │ │ ├── csv-uploader.spec.tsx
│ │ │ │ │ ├── csv-uploader.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── clear-all-annotations-confirm-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── edit-annotation-modal/
│ │ │ │ │ ├── edit-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── empty-element.spec.tsx
│ │ │ │ ├── empty-element.tsx
│ │ │ │ ├── filter.spec.tsx
│ │ │ │ ├── filter.tsx
│ │ │ │ ├── header-opts/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ ├── remove-annotation-confirm-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── type.ts
│ │ │ │ └── view-annotation-modal/
│ │ │ │ ├── hit-history-no-data.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-access-control/
│ │ │ │ ├── access-control-dialog.tsx
│ │ │ │ ├── access-control-item.tsx
│ │ │ │ ├── access-control.spec.tsx
│ │ │ │ ├── add-member-or-group-pop.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── specific-groups-or-members.tsx
│ │ │ ├── app-publisher/
│ │ │ │ ├── features-wrapper.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── publish-with-multiple-model.tsx
│ │ │ │ ├── suggested-action.tsx
│ │ │ │ └── version-info-modal.tsx
│ │ │ ├── configuration/
│ │ │ │ ├── base/
│ │ │ │ │ ├── feature-panel/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── group-name/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── operation-btn/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── var-highlight/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ └── warning-mask/
│ │ │ │ │ ├── cannot-query-dataset.spec.tsx
│ │ │ │ │ ├── cannot-query-dataset.tsx
│ │ │ │ │ ├── formatting-changed.spec.tsx
│ │ │ │ │ ├── formatting-changed.tsx
│ │ │ │ │ ├── has-not-set-api.spec.tsx
│ │ │ │ │ ├── has-not-set-api.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── config/
│ │ │ │ │ ├── agent/
│ │ │ │ │ │ ├── agent-setting/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── item-panel.spec.tsx
│ │ │ │ │ │ │ └── item-panel.tsx
│ │ │ │ │ │ ├── agent-tools/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── setting-built-in-tool.spec.tsx
│ │ │ │ │ │ │ └── setting-built-in-tool.tsx
│ │ │ │ │ │ └── prompt-editor.tsx
│ │ │ │ │ ├── agent-setting-button.spec.tsx
│ │ │ │ │ ├── agent-setting-button.tsx
│ │ │ │ │ ├── assistant-type-picker/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── automatic/
│ │ │ │ │ │ ├── automatic-btn.spec.tsx
│ │ │ │ │ │ ├── automatic-btn.tsx
│ │ │ │ │ │ ├── get-automatic-res.tsx
│ │ │ │ │ │ ├── idea-output.tsx
│ │ │ │ │ │ ├── instruction-editor-in-workflow.tsx
│ │ │ │ │ │ ├── instruction-editor.tsx
│ │ │ │ │ │ ├── prompt-res-in-workflow.tsx
│ │ │ │ │ │ ├── prompt-res.tsx
│ │ │ │ │ │ ├── prompt-toast.tsx
│ │ │ │ │ │ ├── res-placeholder.tsx
│ │ │ │ │ │ ├── result.tsx
│ │ │ │ │ │ ├── style.module.css
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ ├── use-gen-data.ts
│ │ │ │ │ │ └── version-selector.tsx
│ │ │ │ │ ├── code-generator/
│ │ │ │ │ │ └── get-code-generator-res.tsx
│ │ │ │ │ ├── config-audio.spec.tsx
│ │ │ │ │ ├── config-audio.tsx
│ │ │ │ │ ├── config-document.spec.tsx
│ │ │ │ │ ├── config-document.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── config-prompt/
│ │ │ │ │ ├── advanced-prompt-input.tsx
│ │ │ │ │ ├── confirm-add-var/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── conversation-history/
│ │ │ │ │ │ ├── edit-modal.spec.tsx
│ │ │ │ │ │ ├── edit-modal.tsx
│ │ │ │ │ │ ├── history-panel.spec.tsx
│ │ │ │ │ │ └── history-panel.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── message-type-selector.spec.tsx
│ │ │ │ │ ├── message-type-selector.tsx
│ │ │ │ │ ├── prompt-editor-height-resize-wrap.spec.tsx
│ │ │ │ │ ├── prompt-editor-height-resize-wrap.tsx
│ │ │ │ │ ├── simple-prompt-input.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── config-var/
│ │ │ │ │ ├── config-modal/
│ │ │ │ │ │ ├── config.ts
│ │ │ │ │ │ ├── field.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── type-select.tsx
│ │ │ │ │ ├── config-select/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── config-string/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── input-type-icon.tsx
│ │ │ │ │ ├── modal-foot.tsx
│ │ │ │ │ ├── select-type-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── select-var-type.tsx
│ │ │ │ │ └── var-item.tsx
│ │ │ │ ├── config-vision/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── param-config-content.tsx
│ │ │ │ │ └── param-config.tsx
│ │ │ │ ├── ctrl-btn-group/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── dataset-config/
│ │ │ │ │ ├── card-item/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── context-var/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── var-picker.spec.tsx
│ │ │ │ │ │ └── var-picker.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── params-config/
│ │ │ │ │ │ ├── config-content.spec.tsx
│ │ │ │ │ │ ├── config-content.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── weighted-score.spec.tsx
│ │ │ │ │ │ └── weighted-score.tsx
│ │ │ │ │ ├── select-dataset/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── settings-modal/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── retrieval-section.spec.tsx
│ │ │ │ │ └── retrieval-section.tsx
│ │ │ │ ├── debug/
│ │ │ │ │ ├── chat-user-input.spec.tsx
│ │ │ │ │ ├── chat-user-input.tsx
│ │ │ │ │ ├── debug-with-multiple-model/
│ │ │ │ │ │ ├── chat-item.spec.tsx
│ │ │ │ │ │ ├── chat-item.tsx
│ │ │ │ │ │ ├── context-provider.tsx
│ │ │ │ │ │ ├── context.spec.tsx
│ │ │ │ │ │ ├── context.ts
│ │ │ │ │ │ ├── debug-item.spec.tsx
│ │ │ │ │ │ ├── debug-item.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── model-parameter-trigger.spec.tsx
│ │ │ │ │ │ ├── model-parameter-trigger.tsx
│ │ │ │ │ │ ├── text-generation-item.spec.tsx
│ │ │ │ │ │ └── text-generation-item.tsx
│ │ │ │ │ ├── debug-with-single-model/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ └── use-advanced-prompt-config.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── prompt-value-panel/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── utils.spec.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── style.module.css
│ │ │ │ └── tools/
│ │ │ │ ├── external-data-tool-modal.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-app-dialog/
│ │ │ │ ├── app-card/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── app-list/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── sidebar.spec.tsx
│ │ │ │ │ └── sidebar.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-app-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── create-from-dsl-modal/
│ │ │ │ ├── dsl-confirm-modal.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── uploader.tsx
│ │ │ ├── duplicate-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── in-site-message/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── notification.spec.tsx
│ │ │ │ └── notification.tsx
│ │ │ ├── log/
│ │ │ │ ├── empty-element.spec.tsx
│ │ │ │ ├── empty-element.tsx
│ │ │ │ ├── filter.spec.tsx
│ │ │ │ ├── filter.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ ├── model-info.spec.tsx
│ │ │ │ ├── model-info.tsx
│ │ │ │ ├── var-panel.spec.tsx
│ │ │ │ └── var-panel.tsx
│ │ │ ├── log-annotation/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── overview/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── toggle-logic.test.ts
│ │ │ │ ├── apikey-info-panel/
│ │ │ │ │ ├── apikey-info-panel.test-utils.tsx
│ │ │ │ │ ├── cloud.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── app-card.tsx
│ │ │ │ ├── app-chart.tsx
│ │ │ │ ├── customize/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── embedded/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.module.css
│ │ │ │ ├── settings/
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── style.module.css
│ │ │ │ ├── trigger-card.spec.tsx
│ │ │ │ └── trigger-card.tsx
│ │ │ ├── store.ts
│ │ │ ├── switch-app-modal/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── text-generate/
│ │ │ │ ├── item/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── result-tab.tsx
│ │ │ │ └── saved-items/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── no-data/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── type-selector/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ └── workflow-log/
│ │ │ ├── detail.spec.tsx
│ │ │ ├── detail.tsx
│ │ │ ├── filter.spec.tsx
│ │ │ ├── filter.tsx
│ │ │ ├── index.spec.tsx
│ │ │ ├── index.tsx
│ │ │ ├── list.spec.tsx
│ │ │ ├── list.tsx
│ │ │ ├── trigger-by-display.spec.tsx
│ │ │ └── trigger-by-display.tsx
│ │ ├── app-initializer.tsx
│ │ ├── app-sidebar/
│ │ │ ├── __tests__/
│ │ │ │ ├── app-sidebar-dropdown.spec.tsx
│ │ │ │ ├── basic.spec.tsx
│ │ │ │ ├── dataset-sidebar-dropdown.spec.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── sidebar-animation-issues.spec.tsx
│ │ │ │ ├── text-squeeze-fix-verification.spec.tsx
│ │ │ │ └── toggle-button.spec.tsx
│ │ │ ├── app-info/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── app-info-detail-panel.spec.tsx
│ │ │ │ │ ├── app-info-modals.spec.tsx
│ │ │ │ │ ├── app-info-trigger.spec.tsx
│ │ │ │ │ ├── app-mode-labels.spec.ts
│ │ │ │ │ ├── app-operations.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── use-app-info-actions.spec.ts
│ │ │ │ ├── app-info-detail-panel.tsx
│ │ │ │ ├── app-info-modals.tsx
│ │ │ │ ├── app-info-trigger.tsx
│ │ │ │ ├── app-mode-labels.ts
│ │ │ │ ├── app-operations.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── use-app-info-actions.ts
│ │ │ ├── app-sidebar-dropdown.tsx
│ │ │ ├── basic.tsx
│ │ │ ├── dataset-info/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── dropdown-callbacks.spec.tsx
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── dropdown.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── menu-item.tsx
│ │ │ │ └── menu.tsx
│ │ │ ├── dataset-sidebar-dropdown.tsx
│ │ │ ├── index.tsx
│ │ │ ├── nav-link/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ └── toggle-button.tsx
│ │ ├── apps/
│ │ │ ├── __tests__/
│ │ │ │ ├── app-card.spec.tsx
│ │ │ │ ├── empty.spec.tsx
│ │ │ │ ├── footer.spec.tsx
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── list.spec.tsx
│ │ │ │ └── new-app-card.spec.tsx
│ │ │ ├── app-card-skeleton.tsx
│ │ │ ├── app-card.tsx
│ │ │ ├── empty.tsx
│ │ │ ├── footer.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── use-apps-query-state.spec.tsx
│ │ │ │ │ └── use-dsl-drag-drop.spec.ts
│ │ │ │ ├── use-apps-query-state.ts
│ │ │ │ └── use-dsl-drag-drop.ts
│ │ │ ├── index.tsx
│ │ │ ├── list.tsx
│ │ │ └── new-app-card.tsx
│ │ ├── base/
│ │ │ ├── __tests__/
│ │ │ │ ├── alert.spec.tsx
│ │ │ │ ├── app-unavailable.spec.tsx
│ │ │ │ ├── badge.spec.tsx
│ │ │ │ ├── theme-selector.spec.tsx
│ │ │ │ └── theme-switcher.spec.tsx
│ │ │ ├── action-button/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── agent-log-modal/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── detail.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ ├── iteration.spec.tsx
│ │ │ │ │ ├── result.spec.tsx
│ │ │ │ │ ├── tool-call.spec.tsx
│ │ │ │ │ └── tracing.spec.tsx
│ │ │ │ ├── detail.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── iteration.tsx
│ │ │ │ ├── result.tsx
│ │ │ │ ├── tool-call.tsx
│ │ │ │ └── tracing.tsx
│ │ │ ├── alert.tsx
│ │ │ ├── amplitude/
│ │ │ │ ├── AmplitudeProvider.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── AmplitudeProvider.spec.tsx
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── lazy-amplitude-provider.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── answer-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── app-icon-picker/
│ │ │ │ ├── ImageInput.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── ImageInput.spec.tsx
│ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── hooks.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── style.module.css
│ │ │ │ └── utils.ts
│ │ │ ├── app-unavailable.tsx
│ │ │ ├── audio-btn/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── audio.player.manager.spec.ts
│ │ │ │ │ ├── audio.spec.ts
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── audio.player.manager.ts
│ │ │ │ ├── audio.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.css
│ │ │ ├── audio-gallery/
│ │ │ │ ├── AudioPlayer.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── AudioPlayer.spec.tsx
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── auto-height-textarea/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.scss
│ │ │ ├── avatar/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── badge/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── block-input/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── button/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── add-button.spec.tsx
│ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ └── sync-button.spec.tsx
│ │ │ │ ├── add-button.stories.tsx
│ │ │ │ ├── add-button.tsx
│ │ │ │ ├── index.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── sync-button.stories.tsx
│ │ │ │ └── sync-button.tsx
│ │ │ ├── carousel/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── chat/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── utils.spec.ts.snap
│ │ │ │ │ ├── branchedTestMessages.json
│ │ │ │ │ ├── legacyTestMessages.json
│ │ │ │ │ ├── mixedTestMessages.json
│ │ │ │ │ ├── multiRootNodesMessages.json
│ │ │ │ │ ├── multiRootNodesWithLegacyTestMessages.json
│ │ │ │ │ ├── partialMessages.json
│ │ │ │ │ ├── realWorldMessages.json
│ │ │ │ │ └── utils.spec.ts
│ │ │ │ ├── chat/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── check-input-forms-hooks.spec.tsx
│ │ │ │ │ │ ├── content-switch.spec.tsx
│ │ │ │ │ │ ├── context.spec.tsx
│ │ │ │ │ │ ├── hooks.multimodal.spec.ts
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── question.spec.tsx
│ │ │ │ │ │ ├── try-to-ask.spec.tsx
│ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ ├── answer/
│ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ ├── markdownContent.ts
│ │ │ │ │ │ │ ├── markdownContentSVG.ts
│ │ │ │ │ │ │ └── workflowProcess.ts
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── agent-content.spec.tsx
│ │ │ │ │ │ │ ├── basic-content.spec.tsx
│ │ │ │ │ │ │ ├── human-input-filled-form-list.spec.tsx
│ │ │ │ │ │ │ ├── human-input-form-list.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── more.spec.tsx
│ │ │ │ │ │ │ ├── operation.spec.tsx
│ │ │ │ │ │ │ ├── suggested-questions.spec.tsx
│ │ │ │ │ │ │ ├── tool-detail.spec.tsx
│ │ │ │ │ │ │ └── workflow-process.spec.tsx
│ │ │ │ │ │ ├── agent-content.tsx
│ │ │ │ │ │ ├── basic-content.tsx
│ │ │ │ │ │ ├── human-input-content/
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ ├── content-item.spec.tsx
│ │ │ │ │ │ │ │ ├── content-wrapper.spec.tsx
│ │ │ │ │ │ │ │ ├── executed-action.spec.tsx
│ │ │ │ │ │ │ │ ├── expiration-time.spec.tsx
│ │ │ │ │ │ │ │ ├── human-input-form.spec.tsx
│ │ │ │ │ │ │ │ ├── submitted-content.spec.tsx
│ │ │ │ │ │ │ │ ├── submitted.spec.tsx
│ │ │ │ │ │ │ │ ├── tips.spec.tsx
│ │ │ │ │ │ │ │ ├── unsubmitted.spec.tsx
│ │ │ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ │ │ ├── content-item.tsx
│ │ │ │ │ │ │ ├── content-wrapper.tsx
│ │ │ │ │ │ │ ├── executed-action.tsx
│ │ │ │ │ │ │ ├── expiration-time.tsx
│ │ │ │ │ │ │ ├── human-input-form.tsx
│ │ │ │ │ │ │ ├── submitted-content.tsx
│ │ │ │ │ │ │ ├── submitted.tsx
│ │ │ │ │ │ │ ├── tips.tsx
│ │ │ │ │ │ │ ├── type.ts
│ │ │ │ │ │ │ ├── unsubmitted.tsx
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── human-input-filled-form-list.tsx
│ │ │ │ │ │ ├── human-input-form-list.tsx
│ │ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── more.tsx
│ │ │ │ │ │ ├── operation.tsx
│ │ │ │ │ │ ├── suggested-questions.tsx
│ │ │ │ │ │ ├── tool-detail.tsx
│ │ │ │ │ │ └── workflow-process.tsx
│ │ │ │ │ ├── chat-input-area/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── hooks.spec.ts
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── operation.spec.tsx
│ │ │ │ │ │ ├── hooks.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── operation.tsx
│ │ │ │ │ ├── check-input-forms-hooks.ts
│ │ │ │ │ ├── citation/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── popup.spec.tsx
│ │ │ │ │ │ │ ├── progress-tooltip.spec.tsx
│ │ │ │ │ │ │ └── tooltip.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── popup.tsx
│ │ │ │ │ │ ├── progress-tooltip.tsx
│ │ │ │ │ │ └── tooltip.tsx
│ │ │ │ │ ├── content-switch.tsx
│ │ │ │ │ ├── context-provider.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── hooks.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── loading-anim/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── style.module.css
│ │ │ │ │ ├── log/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── question.stories.tsx
│ │ │ │ │ ├── question.tsx
│ │ │ │ │ ├── thought/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── try-to-ask.tsx
│ │ │ │ │ ├── type.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── chat-with-history/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── chat-wrapper.spec.tsx
│ │ │ │ │ │ ├── header-in-mobile.spec.tsx
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ ├── chat-wrapper.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── header/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ ├── mobile-operation-dropdown.spec.tsx
│ │ │ │ │ │ │ └── operation.spec.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── mobile-operation-dropdown.tsx
│ │ │ │ │ │ └── operation.tsx
│ │ │ │ │ ├── header-in-mobile.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── inputs-form/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── content.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── view-form-dropdown.spec.tsx
│ │ │ │ │ │ ├── content.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── view-form-dropdown.tsx
│ │ │ │ │ └── sidebar/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ ├── item.spec.tsx
│ │ │ │ │ │ ├── list.spec.tsx
│ │ │ │ │ │ ├── operation.spec.tsx
│ │ │ │ │ │ └── rename-modal.spec.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── item.tsx
│ │ │ │ │ ├── list.tsx
│ │ │ │ │ ├── operation.tsx
│ │ │ │ │ └── rename-modal.tsx
│ │ │ │ ├── constants.ts
│ │ │ │ ├── embedded-chatbot/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── chat-wrapper.spec.tsx
│ │ │ │ │ │ ├── hooks.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ ├── chat-wrapper.tsx
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── header/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── hooks.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── inputs-form/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── content.spec.tsx
│ │ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ │ └── view-form-dropdown.spec.tsx
│ │ │ │ │ │ ├── content.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── view-form-dropdown.tsx
│ │ │ │ │ ├── theme/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── theme-context.spec.ts
│ │ │ │ │ │ │ └── utils.spec.ts
│ │ │ │ │ │ ├── theme-context.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ ├── checkbox/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── assets/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── indeterminate-icon.spec.tsx
│ │ │ │ │ └── indeterminate-icon.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── checkbox-list/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── chip/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── confirm/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── content-dialog/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── copy-feedback/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.module.css
│ │ │ ├── copy-icon/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── corner-label/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── index.spec.tsx
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── date-and-time-picker/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── hooks.spec.ts
│ │ │ │ ├── calendar/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── days-of-week.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── item.spec.tsx
│ │ │ │ │ ├── days-of-week.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── item.tsx
│ │ │ │ ├── common/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── option-list-item.spec.tsx
│ │ │ │ │ └── option-list-item.tsx
│ │ │ │ ├── date-picker/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── footer.spec.tsx
│ │ │ │ │ │ ├── header.spec.tsx
│ │ │ │ │ │ └── index.spec.tsx
│ │ │ │ │ ├── footer.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── hooks.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── time-picker/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── footer.spec.tsx
│ │ │ │ │ │ ├── header.spec.tsx
│ │ │ │ │ │ ├── index.spec.tsx
│ │ │ │ │ │ └── options.spec.tsx
│ │ │ │ │ ├── footer.tsx
│ │ │ │ │ ├── header.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── options.tsx
│ │ │ │ ├── types.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── dayjs-extended.spec.ts
Copy disabled (too large)
Download .txt
Showing preview only (84,954K chars total). Download the full file to get everything.
SYMBOL INDEX (62475 symbols across 5032 files)
FILE: api/app.py
function is_db_command (line 12) | def is_db_command() -> bool:
FILE: api/app_factory.py
function create_flask_app_with_configs (line 47) | def create_flask_app_with_configs() -> DifyApp:
function create_app (line 125) | def create_app() -> DifyApp:
function initialize_extensions (line 135) | def initialize_extensions(app: DifyApp):
function create_migrations_app (line 216) | def create_migrations_app() -> DifyApp:
FILE: api/commands/account.py
function reset_password (line 18) | def reset_password(email, new_password, password_confirm):
function reset_email (line 58) | def reset_email(email, new_email, email_confirm):
function create_tenant (line 89) | def create_tenant(email: str, language: str | None = None, name: str | N...
FILE: api/commands/plugin.py
function setup_system_tool_oauth_client (line 31) | def setup_system_tool_oauth_client(provider, client_params):
function setup_system_trigger_oauth_client (line 78) | def setup_system_trigger_oauth_client(provider, client_params):
function setup_datasource_oauth_client (line 128) | def setup_datasource_oauth_client(provider, client_params):
function transform_datasource_credentials (line 176) | def transform_datasource_credentials(environment: str):
function migrate_data_for_plugin (line 394) | def migrate_data_for_plugin():
function extract_plugins (line 408) | def extract_plugins(output_file: str, workers: int):
function extract_unique_plugins (line 429) | def extract_unique_plugins(output_file: str, input_file: str):
function install_plugins (line 448) | def install_plugins(input_file: str, output_file: str, workers: int):
function install_rag_pipeline_plugins (line 467) | def install_rag_pipeline_plugins(input_file, output_file, workers):
FILE: api/commands/retention.py
function clear_free_plan_tenant_expired_logs (line 29) | def clear_free_plan_tenant_expired_logs(days: int, batch: int, tenant_id...
function clean_workflow_runs (line 79) | def clean_workflow_runs(
function archive_workflow_runs (line 177) | def archive_workflow_runs(
function restore_workflow_runs (line 296) | def restore_workflow_runs(
function delete_archived_workflow_runs (line 397) | def delete_archived_workflow_runs(
function _find_orphaned_draft_variables (line 482) | def _find_orphaned_draft_variables(batch_size: int = 1000) -> list[str]:
function _count_orphaned_draft_variables (line 506) | def _count_orphaned_draft_variables() -> dict[str, Any]:
function cleanup_orphaned_draft_variables (line 553) | def cleanup_orphaned_draft_variables(
function clean_expired_messages (line 663) | def clean_expired_messages(
function export_app_messages (line 808) | def export_app_messages(
FILE: api/commands/storage.py
function clear_orphaned_file_records (line 19) | def clear_orphaned_file_records(force: bool):
function remove_orphaned_files_on_storage (line 241) | def remove_orphaned_files_on_storage(force: bool):
function file_usage (line 360) | def file_usage(
function migrate_oss (line 593) | def migrate_oss(
FILE: api/commands/system.py
function reset_encrypt_key_pair (line 35) | def reset_encrypt_key_pair():
function convert_to_agent_apps (line 65) | def convert_to_agent_apps():
function upgrade_db (line 125) | def upgrade_db():
function fix_app_site_missing (line 159) | def fix_app_site_missing():
FILE: api/commands/vector.py
function vdb_migrate (line 24) | def vdb_migrate(scope: str):
function migrate_annotation_vector_database (line 31) | def migrate_annotation_vector_database():
function migrate_knowledge_vector_database (line 141) | def migrate_knowledge_vector_database():
function add_qdrant_index (line 333) | def add_qdrant_index(field: str):
function old_metadata_migration (line 399) | def old_metadata_migration():
FILE: api/configs/app_config.py
class RemoteSettingsSourceFactory (line 24) | class RemoteSettingsSourceFactory(PydanticBaseSettingsSource):
method __init__ (line 25) | def __init__(self, settings_cls: type[BaseSettings]):
method get_field_value (line 28) | def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[...
method __call__ (line 31) | def __call__(self) -> dict[str, Any]:
class DifyConfig (line 58) | class DifyConfig(
method settings_customise_sources (line 93) | def settings_customise_sources(
FILE: api/configs/deploy/__init__.py
class DeploymentConfig (line 5) | class DeploymentConfig(BaseSettings):
FILE: api/configs/enterprise/__init__.py
class EnterpriseFeatureConfig (line 5) | class EnterpriseFeatureConfig(BaseSettings):
class EnterpriseTelemetryConfig (line 27) | class EnterpriseTelemetryConfig(BaseSettings):
FILE: api/configs/extra/__init__.py
class ExtraServiceConfig (line 6) | class ExtraServiceConfig(
FILE: api/configs/extra/archive_config.py
class ArchiveStorageConfig (line 5) | class ArchiveStorageConfig(BaseSettings):
FILE: api/configs/extra/notion_config.py
class NotionConfig (line 5) | class NotionConfig(BaseSettings):
FILE: api/configs/extra/sentry_config.py
class SentryConfig (line 5) | class SentryConfig(BaseSettings):
FILE: api/configs/feature/__init__.py
class SecurityConfig (line 20) | class SecurityConfig(BaseSettings):
class AppExecutionConfig (line 78) | class AppExecutionConfig(BaseSettings):
class CodeExecutionSandboxConfig (line 103) | class CodeExecutionSandboxConfig(BaseSettings):
class TriggerConfig (line 194) | class TriggerConfig(BaseSettings):
class AsyncWorkflowConfig (line 205) | class AsyncWorkflowConfig(BaseSettings):
class PluginConfig (line 221) | class PluginConfig(BaseSettings):
class MarketplaceConfig (line 274) | class MarketplaceConfig(BaseSettings):
class EndpointConfig (line 290) | class EndpointConfig(BaseSettings):
class FileAccessConfig (line 323) | class FileAccessConfig(BaseSettings):
class FileUploadConfig (line 350) | class FileUploadConfig(BaseSettings):
method UPLOAD_FILE_EXTENSION_BLACKLIST (line 453) | def UPLOAD_FILE_EXTENSION_BLACKLIST(self) -> set[str]:
class HttpConfig (line 467) | class HttpConfig(BaseSettings):
method CONSOLE_CORS_ALLOW_ORIGINS (line 489) | def CONSOLE_CORS_ALLOW_ORIGINS(self) -> list[str]:
method WEB_API_CORS_ALLOW_ORIGINS (line 499) | def WEB_API_CORS_ALLOW_ORIGINS(self) -> list[str]:
class InnerAPIConfig (line 591) | class InnerAPIConfig(BaseSettings):
class LoggingConfig (line 607) | class LoggingConfig(BaseSettings):
class ModelLoadBalanceConfig (line 656) | class ModelLoadBalanceConfig(BaseSettings):
class BillingConfig (line 672) | class BillingConfig(BaseSettings):
class UpdateConfig (line 683) | class UpdateConfig(BaseSettings):
class WorkflowVariableTruncationConfig (line 694) | class WorkflowVariableTruncationConfig(BaseSettings):
class WorkflowConfig (line 710) | class WorkflowConfig(BaseSettings):
class WorkflowNodeExecutionConfig (line 763) | class WorkflowNodeExecutionConfig(BaseSettings):
class RepositoryConfig (line 779) | class RepositoryConfig(BaseSettings):
class AuthConfig (line 812) | class AuthConfig(BaseSettings):
class ModerationConfig (line 878) | class ModerationConfig(BaseSettings):
class ToolConfig (line 889) | class ToolConfig(BaseSettings):
class TemplateMode (line 900) | class TemplateMode(StrEnum):
class MailConfig (line 912) | class MailConfig(BaseSettings):
class RagEtlConfig (line 1006) | class RagEtlConfig(BaseSettings):
class DataSetConfig (line 1039) | class DataSetConfig(BaseSettings):
class WorkspaceConfig (line 1085) | class WorkspaceConfig(BaseSettings):
class IndexingConfig (line 1096) | class IndexingConfig(BaseSettings):
class MultiModalTransferConfig (line 1112) | class MultiModalTransferConfig(BaseSettings):
class CeleryBeatConfig (line 1119) | class CeleryBeatConfig(BaseSettings):
class CeleryScheduleTasksConfig (line 1126) | class CeleryScheduleTasksConfig(BaseSettings):
class PositionConfig (line 1221) | class PositionConfig(BaseSettings):
method POSITION_PROVIDER_PINS_LIST (line 1253) | def POSITION_PROVIDER_PINS_LIST(self) -> list[str]:
method POSITION_PROVIDER_INCLUDES_SET (line 1257) | def POSITION_PROVIDER_INCLUDES_SET(self) -> set[str]:
method POSITION_PROVIDER_EXCLUDES_SET (line 1261) | def POSITION_PROVIDER_EXCLUDES_SET(self) -> set[str]:
method POSITION_TOOL_PINS_LIST (line 1265) | def POSITION_TOOL_PINS_LIST(self) -> list[str]:
method POSITION_TOOL_INCLUDES_SET (line 1269) | def POSITION_TOOL_INCLUDES_SET(self) -> set[str]:
method POSITION_TOOL_EXCLUDES_SET (line 1273) | def POSITION_TOOL_EXCLUDES_SET(self) -> set[str]:
class LoginConfig (line 1277) | class LoginConfig(BaseSettings):
class AccountConfig (line 1304) | class AccountConfig(BaseSettings):
class WorkflowLogConfig (line 1316) | class WorkflowLogConfig(BaseSettings):
class SwaggerUIConfig (line 1327) | class SwaggerUIConfig(BaseSettings):
class TenantIsolatedTaskQueueConfig (line 1339) | class TenantIsolatedTaskQueueConfig(BaseSettings):
class SandboxExpiredRecordsCleanConfig (line 1346) | class SandboxExpiredRecordsCleanConfig(BaseSettings):
class FeatureConfig (line 1369) | class FeatureConfig(
FILE: api/configs/feature/hosted_service/__init__.py
class HostedCreditConfig (line 5) | class HostedCreditConfig(BaseSettings):
method get_model_credits (line 16) | def get_model_credits(self, model_name: str) -> int:
class HostedOpenAiConfig (line 41) | class HostedOpenAiConfig(BaseSettings):
class HostedGeminiConfig (line 160) | class HostedGeminiConfig(BaseSettings):
class HostedXAIConfig (line 201) | class HostedXAIConfig(BaseSettings):
class HostedDeepseekConfig (line 242) | class HostedDeepseekConfig(BaseSettings):
class HostedAzureOpenAiConfig (line 283) | class HostedAzureOpenAiConfig(BaseSettings):
class HostedAnthropicConfig (line 309) | class HostedAnthropicConfig(BaseSettings):
class HostedTongyiConfig (line 354) | class HostedTongyiConfig(BaseSettings):
class HostedMinmaxConfig (line 390) | class HostedMinmaxConfig(BaseSettings):
class HostedSparkConfig (line 401) | class HostedSparkConfig(BaseSettings):
class HostedZhipuAIConfig (line 412) | class HostedZhipuAIConfig(BaseSettings):
class HostedModerationConfig (line 423) | class HostedModerationConfig(BaseSettings):
class HostedFetchAppTemplateConfig (line 439) | class HostedFetchAppTemplateConfig(BaseSettings):
class HostedFetchPipelineTemplateConfig (line 455) | class HostedFetchPipelineTemplateConfig(BaseSettings):
class HostedServiceConfig (line 471) | class HostedServiceConfig(
FILE: api/configs/middleware/__init__.py
class StorageConfig (line 54) | class StorageConfig(BaseSettings):
class VectorStoreConfig (line 84) | class VectorStoreConfig(BaseSettings):
class KeywordStoreConfig (line 102) | class KeywordStoreConfig(BaseSettings):
class DatabaseConfig (line 110) | class DatabaseConfig(BaseSettings):
method SQLALCHEMY_DATABASE_URI_SCHEME (line 154) | def SQLALCHEMY_DATABASE_URI_SCHEME(self) -> str:
method SQLALCHEMY_DATABASE_URI (line 159) | def SQLALCHEMY_DATABASE_URI(self) -> str:
method SQLALCHEMY_ENGINE_OPTIONS (line 212) | def SQLALCHEMY_ENGINE_OPTIONS(self) -> dict[str, Any]:
class CeleryConfig (line 238) | class CeleryConfig(DatabaseConfig):
method CELERY_RESULT_BACKEND (line 278) | def CELERY_RESULT_BACKEND(self) -> str | None:
method BROKER_USE_SSL (line 287) | def BROKER_USE_SSL(self) -> bool:
class InternalTestConfig (line 291) | class InternalTestConfig(BaseSettings):
class DatasetQueueMonitorConfig (line 307) | class DatasetQueueMonitorConfig(BaseSettings):
class MiddlewareConfig (line 326) | class MiddlewareConfig(
FILE: api/configs/middleware/cache/redis_config.py
class RedisConfig (line 5) | class RedisConfig(BaseSettings):
method _empty_string_to_none_for_max_conns (line 122) | def _empty_string_to_none_for_max_conns(cls, v):
FILE: api/configs/middleware/cache/redis_pubsub_config.py
class RedisConfigDefaults (line 8) | class RedisConfigDefaults(Protocol):
function _redis_defaults (line 17) | def _redis_defaults(config: object) -> RedisConfigDefaults:
class RedisPubSubConfig (line 21) | class RedisPubSubConfig(BaseSettings):
method _build_default_pubsub_url (line 73) | def _build_default_pubsub_url(self) -> str:
method normalized_pubsub_redis_url (line 97) | def normalized_pubsub_redis_url(self) -> str:
FILE: api/configs/middleware/storage/aliyun_oss_storage_config.py
class AliyunOSSStorageConfig (line 5) | class AliyunOSSStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/amazon_s3_storage_config.py
class S3StorageConfig (line 7) | class S3StorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/azure_blob_storage_config.py
class AzureBlobStorageConfig (line 5) | class AzureBlobStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/baidu_obs_storage_config.py
class BaiduOBSStorageConfig (line 5) | class BaiduOBSStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/clickzetta_volume_storage_config.py
class ClickZettaVolumeStorageConfig (line 7) | class ClickZettaVolumeStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/google_cloud_storage_config.py
class GoogleCloudStorageConfig (line 5) | class GoogleCloudStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/huawei_obs_storage_config.py
class HuaweiCloudOBSStorageConfig (line 5) | class HuaweiCloudOBSStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/oci_storage_config.py
class OCIStorageConfig (line 5) | class OCIStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/opendal_storage_config.py
class OpenDALStorageConfig (line 5) | class OpenDALStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/supabase_storage_config.py
class SupabaseStorageConfig (line 5) | class SupabaseStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/tencent_cos_storage_config.py
class TencentCloudCOSStorageConfig (line 5) | class TencentCloudCOSStorageConfig(BaseSettings):
FILE: api/configs/middleware/storage/volcengine_tos_storage_config.py
class VolcengineTOSStorageConfig (line 5) | class VolcengineTOSStorageConfig(BaseSettings):
FILE: api/configs/middleware/vdb/alibabacloud_mysql_config.py
class AlibabaCloudMySQLConfig (line 5) | class AlibabaCloudMySQLConfig(BaseSettings):
FILE: api/configs/middleware/vdb/analyticdb_config.py
class AnalyticdbConfig (line 5) | class AnalyticdbConfig(BaseSettings):
FILE: api/configs/middleware/vdb/baidu_vector_config.py
class BaiduVectorDBConfig (line 5) | class BaiduVectorDBConfig(BaseSettings):
FILE: api/configs/middleware/vdb/chroma_config.py
class ChromaConfig (line 5) | class ChromaConfig(BaseSettings):
FILE: api/configs/middleware/vdb/clickzetta_config.py
class ClickzettaConfig (line 5) | class ClickzettaConfig(BaseSettings):
FILE: api/configs/middleware/vdb/couchbase_config.py
class CouchbaseConfig (line 5) | class CouchbaseConfig(BaseSettings):
FILE: api/configs/middleware/vdb/elasticsearch_config.py
class ElasticsearchConfig (line 5) | class ElasticsearchConfig(BaseSettings):
method validate_elasticsearch_config (line 59) | def validate_elasticsearch_config(self):
FILE: api/configs/middleware/vdb/hologres_config.py
class HologresConfig (line 6) | class HologresConfig(BaseSettings):
FILE: api/configs/middleware/vdb/huawei_cloud_config.py
class HuaweiCloudConfig (line 5) | class HuaweiCloudConfig(BaseSettings):
FILE: api/configs/middleware/vdb/iris_config.py
class IrisVectorConfig (line 7) | class IrisVectorConfig(BaseSettings):
method validate_config (line 67) | def validate_config(cls, values: dict) -> dict:
FILE: api/configs/middleware/vdb/lindorm_config.py
class LindormConfig (line 5) | class LindormConfig(BaseSettings):
FILE: api/configs/middleware/vdb/matrixone_config.py
class MatrixoneConfig (line 5) | class MatrixoneConfig(BaseSettings):
FILE: api/configs/middleware/vdb/milvus_config.py
class MilvusConfig (line 5) | class MilvusConfig(BaseSettings):
FILE: api/configs/middleware/vdb/myscale_config.py
class MyScaleConfig (line 5) | class MyScaleConfig(BaseSettings):
FILE: api/configs/middleware/vdb/oceanbase_config.py
class OceanBaseVectorConfig (line 7) | class OceanBaseVectorConfig(BaseSettings):
FILE: api/configs/middleware/vdb/opengauss_config.py
class OpenGaussConfig (line 5) | class OpenGaussConfig(BaseSettings):
FILE: api/configs/middleware/vdb/opensearch_config.py
class AuthMethod (line 8) | class AuthMethod(StrEnum):
class OpenSearchConfig (line 17) | class OpenSearchConfig(BaseSettings):
FILE: api/configs/middleware/vdb/oracle_config.py
class OracleConfig (line 5) | class OracleConfig(BaseSettings):
FILE: api/configs/middleware/vdb/pgvector_config.py
class PGVectorConfig (line 5) | class PGVectorConfig(BaseSettings):
FILE: api/configs/middleware/vdb/pgvectors_config.py
class PGVectoRSConfig (line 5) | class PGVectoRSConfig(BaseSettings):
FILE: api/configs/middleware/vdb/qdrant_config.py
class QdrantConfig (line 5) | class QdrantConfig(BaseSettings):
FILE: api/configs/middleware/vdb/relyt_config.py
class RelytConfig (line 5) | class RelytConfig(BaseSettings):
FILE: api/configs/middleware/vdb/tablestore_config.py
class TableStoreConfig (line 5) | class TableStoreConfig(BaseSettings):
FILE: api/configs/middleware/vdb/tencent_vector_config.py
class TencentVectorDBConfig (line 5) | class TencentVectorDBConfig(BaseSettings):
FILE: api/configs/middleware/vdb/tidb_on_qdrant_config.py
class TidbOnQdrantConfig (line 5) | class TidbOnQdrantConfig(BaseSettings):
FILE: api/configs/middleware/vdb/tidb_vector_config.py
class TiDBVectorConfig (line 5) | class TiDBVectorConfig(BaseSettings):
FILE: api/configs/middleware/vdb/upstash_config.py
class UpstashConfig (line 5) | class UpstashConfig(BaseSettings):
FILE: api/configs/middleware/vdb/vastbase_vector_config.py
class VastbaseVectorConfig (line 5) | class VastbaseVectorConfig(BaseSettings):
FILE: api/configs/middleware/vdb/vikingdb_config.py
class VikingDBConfig (line 5) | class VikingDBConfig(BaseSettings):
FILE: api/configs/middleware/vdb/weaviate_config.py
class WeaviateConfig (line 5) | class WeaviateConfig(BaseSettings):
FILE: api/configs/observability/__init__.py
class ObservabilityConfig (line 4) | class ObservabilityConfig(OTelConfig):
FILE: api/configs/observability/otel/otel_config.py
class OTelConfig (line 5) | class OTelConfig(BaseSettings):
FILE: api/configs/packaging/__init__.py
class PackagingInfo (line 6) | class PackagingInfo(PyProjectTomlConfig):
FILE: api/configs/packaging/pyproject.py
class PyProjectConfig (line 5) | class PyProjectConfig(BaseModel):
class PyProjectTomlConfig (line 9) | class PyProjectTomlConfig(BaseSettings):
FILE: api/configs/remote_settings_sources/__init__.py
class RemoteSettingsSourceConfig (line 8) | class RemoteSettingsSourceConfig(ApolloSettingsSourceInfo):
FILE: api/configs/remote_settings_sources/apollo/__init__.py
class ApolloSettingsSourceInfo (line 13) | class ApolloSettingsSourceInfo(BaseSettings):
class ApolloSettingsSource (line 39) | class ApolloSettingsSource(RemoteSettingsSource):
method __init__ (line 40) | def __init__(self, configs: Mapping[str, Any]):
method get_field_value (line 51) | def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[...
FILE: api/configs/remote_settings_sources/apollo/client.py
class ApolloClient (line 26) | class ApolloClient:
method __init__ (line 27) | def __init__(
method get_json_from_net (line 72) | def get_json_from_net(self, namespace: str = "application") -> dict[st...
method get_value (line 92) | def get_value(self, key: str, default_val: Any = None, namespace: str ...
method _set_local_cache_none (line 131) | def _set_local_cache_none(self, namespace: str, key: str) -> None:
method _start_hot_update (line 135) | def _start_hot_update(self) -> None:
method stop (line 142) | def stop(self) -> None:
method _call_listener (line 147) | def _call_listener(self, namespace: str, old_kv: dict[str, Any] | None...
method _path_checker (line 173) | def _path_checker(self) -> None:
method _update_cache_and_file (line 178) | def _update_cache_and_file(self, namespace_data: dict[str, Any], names...
method _get_local_cache (line 192) | def _get_local_cache(self, namespace: str = "application") -> dict[str...
method _long_poll (line 200) | def _long_poll(self) -> None:
method _get_net_and_set_local (line 241) | def _get_net_and_set_local(self, namespace: str, n_id: int, call_chang...
method _listener (line 253) | def _listener(self) -> None:
method _sign_headers (line 261) | def _sign_headers(self, url: str) -> Mapping[str, str]:
method _heart_beat (line 271) | def _heart_beat(self) -> None:
method _do_heart_beat (line 277) | def _do_heart_beat(self, namespace: str) -> None:
method get_all_dicts (line 297) | def get_all_dicts(self, namespace: str) -> dict[str, Any] | None:
FILE: api/configs/remote_settings_sources/apollo/python_3x.py
function http_request (line 24) | def http_request(url: str, timeout: int | float, headers: Mapping[str, s...
function url_encode (line 38) | def url_encode(params: dict[str, Any]) -> str:
function makedirs_wrapper (line 42) | def makedirs_wrapper(path: str) -> None:
FILE: api/configs/remote_settings_sources/apollo/utils.py
function signature (line 14) | def signature(timestamp: str, uri: str, secret: str) -> str:
function url_encode_wrapper (line 23) | def url_encode_wrapper(params: dict[str, Any]) -> str:
function no_key_cache_key (line 27) | def no_key_cache_key(namespace: str, key: str) -> str:
function get_value_from_dict (line 32) | def get_value_from_dict(namespace_cache: dict[str, Any] | None, key: str...
function init_ip (line 42) | def init_ip() -> str:
FILE: api/configs/remote_settings_sources/base.py
class RemoteSettingsSource (line 7) | class RemoteSettingsSource:
method __init__ (line 8) | def __init__(self, configs: Mapping[str, Any]):
method get_field_value (line 11) | def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[...
method prepare_field_value (line 14) | def prepare_field_value(self, field_name: str, field: FieldInfo, value...
FILE: api/configs/remote_settings_sources/enums.py
class RemoteSettingsSourceName (line 4) | class RemoteSettingsSourceName(StrEnum):
FILE: api/configs/remote_settings_sources/nacos/__init__.py
class NacosSettingsSource (line 17) | class NacosSettingsSource(RemoteSettingsSource):
method __init__ (line 18) | def __init__(self, configs: Mapping[str, Any]):
method async_init (line 23) | def async_init(self) -> None:
method _parse_config (line 36) | def _parse_config(self, content: str) -> dict[str, str]:
method get_field_value (line 44) | def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[...
FILE: api/configs/remote_settings_sources/nacos/http_request.py
class NacosHttpClient (line 13) | class NacosHttpClient:
method __init__ (line 14) | def __init__(self):
method http_request (line 24) | def http_request(
method _inject_auth_info (line 39) | def _inject_auth_info(self, headers: dict[str, str], params: dict[str,...
method __do_sign (line 57) | def __do_sign(self, sign_str: str, sk: str) -> str:
method get_sign_str (line 64) | def get_sign_str(self, group: str, tenant: str, ts: str) -> str:
method get_access_token (line 73) | def get_access_token(self, force_refresh: bool = False) -> str | None:
FILE: api/configs/remote_settings_sources/nacos/utils.py
function parse_config (line 1) | def parse_config(content: str) -> dict[str, str]:
FILE: api/constants/languages.py
function supported_language (line 30) | def supported_language(lang):
function get_valid_language (line 38) | def get_valid_language(lang: str | None) -> str:
FILE: api/context/execution_context.py
class AppContext (line 18) | class AppContext(ABC):
method get_config (line 27) | def get_config(self, key: str, default: Any = None) -> Any:
method get_extension (line 32) | def get_extension(self, name: str) -> Any:
method enter (line 37) | def enter(self) -> AbstractContextManager[None]:
class IExecutionContext (line 43) | class IExecutionContext(Protocol):
method __enter__ (line 51) | def __enter__(self) -> "IExecutionContext":
method __exit__ (line 55) | def __exit__(self, *args: Any) -> None:
method user (line 60) | def user(self) -> Any:
class ExecutionContext (line 66) | class ExecutionContext:
method __init__ (line 74) | def __init__(
method app_context (line 86) | def app_context(self) -> AppContext | None:
method context_vars (line 91) | def context_vars(self) -> contextvars.Context | None:
method user (line 96) | def user(self) -> Any:
method enter (line 101) | def enter(self) -> Generator[None, None, None]:
method __enter__ (line 113) | def __enter__(self) -> "ExecutionContext":
method __exit__ (line 120) | def __exit__(self, *args: Any) -> None:
class NullAppContext (line 127) | class NullAppContext(AppContext):
method __init__ (line 132) | def __init__(self, config: dict[str, Any] | None = None) -> None:
method get_config (line 136) | def get_config(self, key: str, default: Any = None) -> Any:
method get_extension (line 140) | def get_extension(self, name: str) -> Any:
method set_extension (line 144) | def set_extension(self, name: str, extension: Any) -> None:
method enter (line 149) | def enter(self) -> Generator[None, None, None]:
class ExecutionContextBuilder (line 154) | class ExecutionContextBuilder:
method __init__ (line 159) | def __init__(self) -> None:
method with_app_context (line 164) | def with_app_context(self, app_context: AppContext) -> "ExecutionConte...
method with_context_vars (line 169) | def with_context_vars(self, context_vars: contextvars.Context) -> "Exe...
method with_user (line 174) | def with_user(self, user: Any) -> "ExecutionContextBuilder":
method build (line 179) | def build(self) -> ExecutionContext:
class ContextProviderNotFoundError (line 194) | class ContextProviderNotFoundError(KeyError):
function register_context_capturer (line 200) | def register_context_capturer(capturer: Callable[[], IExecutionContext])...
function register_context (line 206) | def register_context(name: str, tenant_id: str, provider: Callable[[], B...
function read_context (line 211) | def read_context(name: str, *, tenant_id: str) -> BaseModel:
function capture_current_context (line 219) | def capture_current_context() -> IExecutionContext:
function reset_context_provider (line 234) | def reset_context_provider() -> None:
FILE: api/context/flask_app_context.py
class FlaskAppContext (line 17) | class FlaskAppContext(AppContext):
method __init__ (line 24) | def __init__(self, flask_app: Flask) -> None:
method get_config (line 33) | def get_config(self, key: str, default: Any = None) -> Any:
method get_extension (line 37) | def get_extension(self, name: str) -> Any:
method enter (line 42) | def enter(self) -> Generator[None, None, None]:
method flask_app (line 48) | def flask_app(self) -> Flask:
function capture_flask_context (line 53) | def capture_flask_context(user: Any = None) -> IExecutionContext:
class FlaskExecutionContext (line 91) | class FlaskExecutionContext:
method __init__ (line 100) | def __init__(
method app_context (line 121) | def app_context(self) -> FlaskAppContext:
method context_vars (line 126) | def context_vars(self) -> contextvars.Context:
method user (line 131) | def user(self) -> Any:
method __enter__ (line 135) | def __enter__(self) -> "FlaskExecutionContext":
method __exit__ (line 152) | def __exit__(self, *args: Any) -> None:
method enter (line 159) | def enter(self) -> Generator[None, None, None]:
function init_flask_context (line 173) | def init_flask_context() -> None:
FILE: api/context/models.py
class SandboxContext (line 6) | class SandboxContext(BaseModel):
FILE: api/contexts/wrapper.py
class HiddenValue (line 7) | class HiddenValue:
class RecyclableContextVar (line 14) | class RecyclableContextVar(Generic[T]):
method increment_thread_recycles (line 25) | def increment_thread_recycles(cls):
method __init__ (line 32) | def __init__(self, context_var: ContextVar[T]):
method get (line 36) | def get(self, default: T | HiddenValue = _default) -> T:
method set (line 52) | def set(self, value: T):
FILE: api/controllers/common/errors.py
class FilenameNotExistsError (line 6) | class FilenameNotExistsError(HTTPException):
class RemoteFileUploadError (line 11) | class RemoteFileUploadError(HTTPException):
class FileTooLargeError (line 16) | class FileTooLargeError(BaseHTTPException):
class UnsupportedFileTypeError (line 22) | class UnsupportedFileTypeError(BaseHTTPException):
class BlockedFileExtensionError (line 28) | class BlockedFileExtensionError(BaseHTTPException):
class TooManyFilesError (line 34) | class TooManyFilesError(BaseHTTPException):
class NoFileUploadedError (line 40) | class NoFileUploadedError(BaseHTTPException):
FILE: api/controllers/common/fields.py
class SystemParameters (line 14) | class SystemParameters(BaseModel):
class Parameters (line 22) | class Parameters(BaseModel):
class Site (line 37) | class Site(BaseModel):
method icon_url (line 56) | def icon_url(self) -> str | None:
FILE: api/controllers/common/file_response.py
function _normalize_mime_type (line 11) | def _normalize_mime_type(mime_type: str | None) -> str:
function _is_html_extension (line 19) | def _is_html_extension(extension: str | None) -> bool:
function is_html_content (line 25) | def is_html_content(mime_type: str | None, filename: str | None, extensi...
function enforce_download_for_html (line 39) | def enforce_download_for_html(
FILE: api/controllers/common/helpers.py
class FileInfo (line 32) | class FileInfo(BaseModel):
function guess_file_info_from_response (line 39) | def guess_file_info_from_response(response: httpx.Response):
FILE: api/controllers/common/schema.py
function register_schema_model (line 11) | def register_schema_model(namespace: Namespace, model: type[BaseModel]) ...
function register_schema_models (line 17) | def register_schema_models(namespace: Namespace, *models: type[BaseModel...
function get_or_create_model (line 24) | def get_or_create_model(model_name: str, field_def):
function register_enum_models (line 34) | def register_enum_models(namespace: Namespace, *models: type[StrEnum]) -...
FILE: api/controllers/console/admin.py
class InsertExploreAppPayload (line 29) | class InsertExploreAppPayload(BaseModel):
method validate_language (line 43) | def validate_language(cls, value: str) -> str:
class InsertExploreBannerPayload (line 47) | class InsertExploreBannerPayload(BaseModel):
method validate_language (line 58) | def validate_language(cls, value: str) -> str:
function admin_required (line 75) | def admin_required(view: Callable[P, R]):
class InsertExploreAppListApi (line 93) | class InsertExploreAppListApi(Resource):
method post (line 102) | def post(self):
class InsertExploreAppApi (line 189) | class InsertExploreAppApi(Resource):
method delete (line 196) | def delete(self, app_id):
class InsertExploreBannerApi (line 239) | class InsertExploreBannerApi(Resource):
method post (line 246) | def post(self):
class DeleteExploreBannerApi (line 267) | class DeleteExploreBannerApi(Resource):
method delete (line 274) | def delete(self, banner_id):
class LangContentPayload (line 285) | class LangContentPayload(BaseModel):
class UpsertNotificationPayload (line 293) | class UpsertNotificationPayload(BaseModel):
class BatchAddNotificationAccountsPayload (line 302) | class BatchAddNotificationAccountsPayload(BaseModel):
class UpsertNotificationApi (line 319) | class UpsertNotificationApi(Resource):
method post (line 332) | def post(self):
class BatchAddNotificationAccountsApi (line 346) | class BatchAddNotificationAccountsApi(Resource):
method post (line 360) | def post(self):
method _parse_emails_from_file (line 406) | def _parse_emails_from_file() -> list[str]:
FILE: api/controllers/console/apikey.py
function _get_resource (line 36) | def _get_resource(resource_id, tenant_id, resource_model):
class BaseApiKeyListResource (line 48) | class BaseApiKeyListResource(Resource):
method get (line 58) | def get(self, resource_id):
method post (line 73) | def post(self, resource_id):
class BaseApiKeyResource (line 106) | class BaseApiKeyResource(Resource):
method delete (line 113) | def delete(self, resource_id: str, api_key_id: str):
class AppApiKeyListResource (line 146) | class AppApiKeyListResource(BaseApiKeyListResource):
method get (line 151) | def get(self, resource_id): # type: ignore
method post (line 160) | def post(self, resource_id): # type: ignore
class AppApiKeyResource (line 171) | class AppApiKeyResource(BaseApiKeyResource):
method delete (line 176) | def delete(self, resource_id, api_key_id):
class DatasetApiKeyListResource (line 186) | class DatasetApiKeyListResource(BaseApiKeyListResource):
method get (line 191) | def get(self, resource_id): # type: ignore
method post (line 200) | def post(self, resource_id): # type: ignore
class DatasetApiKeyResource (line 211) | class DatasetApiKeyResource(BaseApiKeyResource):
method delete (line 216) | def delete(self, resource_id, api_key_id):
FILE: api/controllers/console/app/advanced_prompt_template.py
class AdvancedPromptTemplateQuery (line 11) | class AdvancedPromptTemplateQuery(BaseModel):
class AdvancedPromptTemplateList (line 25) | class AdvancedPromptTemplateList(Resource):
method get (line 36) | def get(self):
FILE: api/controllers/console/app/agent.py
class AgentLogQuery (line 16) | class AgentLogQuery(BaseModel):
method validate_uuid (line 22) | def validate_uuid(cls, value: str) -> str:
class AgentLogApi (line 32) | class AgentLogApi(Resource):
method get (line 45) | def get(self, app_model):
FILE: api/controllers/console/app/annotation.py
class AnnotationReplyPayload (line 33) | class AnnotationReplyPayload(BaseModel):
class AnnotationSettingUpdatePayload (line 39) | class AnnotationSettingUpdatePayload(BaseModel):
class AnnotationListQuery (line 43) | class AnnotationListQuery(BaseModel):
class CreateAnnotationPayload (line 49) | class CreateAnnotationPayload(BaseModel):
method validate_message_id (line 58) | def validate_message_id(cls, value: str | None) -> str | None:
class UpdateAnnotationPayload (line 64) | class UpdateAnnotationPayload(BaseModel):
class AnnotationReplyStatusQuery (line 71) | class AnnotationReplyStatusQuery(BaseModel):
class AnnotationFilePayload (line 75) | class AnnotationFilePayload(BaseModel):
method validate_message_id (line 80) | def validate_message_id(cls, value: str) -> str:
function reg (line 84) | def reg(model: type[BaseModel]) -> None:
class AnnotationReplyActionApi (line 106) | class AnnotationReplyActionApi(Resource):
method post (line 118) | def post(self, app_id, action: Literal["enable", "disable"]):
class AppAnnotationSettingDetailApi (line 130) | class AppAnnotationSettingDetailApi(Resource):
method get (line 140) | def get(self, app_id):
class AppAnnotationSettingUpdateApi (line 147) | class AppAnnotationSettingUpdateApi(Resource):
method post (line 158) | def post(self, app_id, annotation_setting_id):
class AnnotationReplyActionStatusApi (line 169) | class AnnotationReplyActionStatusApi(Resource):
method get (line 180) | def get(self, app_id, job_id, action):
class AnnotationApi (line 197) | class AnnotationApi(Resource):
method get (line 208) | def get(self, app_id):
method post (line 237) | def post(self, app_id):
method delete (line 248) | def delete(self, app_id):
class AnnotationExportApi (line 272) | class AnnotationExportApi(Resource):
method get (line 286) | def get(self, app_id):
class AnnotationUpdateDeleteApi (line 301) | class AnnotationUpdateDeleteApi(Resource):
method post (line 314) | def post(self, app_id, annotation_id):
method delete (line 327) | def delete(self, app_id, annotation_id):
class AnnotationBatchImportApi (line 335) | class AnnotationBatchImportApi(Resource):
method post (line 351) | def post(self, app_id):
class AnnotationBatchImportStatusApi (line 390) | class AnnotationBatchImportStatusApi(Resource):
method get (line 401) | def get(self, app_id, job_id):
class AnnotationHitHistoryListApi (line 417) | class AnnotationHitHistoryListApi(Resource):
method get (line 436) | def get(self, app_id, annotation_id):
FILE: api/controllers/console/app/app.py
class AppListQuery (line 62) | class AppListQuery(BaseModel):
method validate_tag_ids (line 74) | def validate_tag_ids(cls, value: str | list[str] | None) -> list[str] ...
class CreateAppPayload (line 94) | class CreateAppPayload(BaseModel):
class UpdateAppPayload (line 103) | class UpdateAppPayload(BaseModel):
class CopyAppPayload (line 113) | class CopyAppPayload(BaseModel):
class AppExportQuery (line 121) | class AppExportQuery(BaseModel):
class AppNamePayload (line 126) | class AppNamePayload(BaseModel):
class AppIconPayload (line 130) | class AppIconPayload(BaseModel):
class AppSiteStatusPayload (line 135) | class AppSiteStatusPayload(BaseModel):
class AppApiStatusPayload (line 139) | class AppApiStatusPayload(BaseModel):
class AppTracePayload (line 143) | class AppTracePayload(BaseModel):
method validate_tracing_provider (line 149) | def validate_tracing_provider(cls, value: str | None, info) -> str | N...
class ResponseModel (line 158) | class ResponseModel(BaseModel):
function _to_timestamp (line 168) | def _to_timestamp(value: datetime | int | None) -> int | None:
function _build_icon_url (line 174) | def _build_icon_url(icon_type: str | IconType | None, icon: str | None) ...
class Tag (line 183) | class Tag(ResponseModel):
class WorkflowPartial (line 189) | class WorkflowPartial(ResponseModel):
method _normalize_timestamp (line 198) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class ModelConfigPartial (line 202) | class ModelConfigPartial(ResponseModel):
method _normalize_timestamp (line 212) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class ModelConfig (line 216) | class ModelConfig(ResponseModel):
method _normalize_timestamp (line 273) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class Site (line 277) | class Site(ResponseModel):
method icon_url (line 304) | def icon_url(self) -> str | None:
method _normalize_icon_type (line 309) | def _normalize_icon_type(cls, value: str | IconType | None) -> str | N...
method _normalize_timestamp (line 316) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class DeletedTool (line 320) | class DeletedTool(ResponseModel):
class AppPartial (line 326) | class AppPartial(ResponseModel):
method icon_url (line 354) | def icon_url(self) -> str | None:
method _normalize_timestamp (line 359) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class AppDetail (line 363) | class AppDetail(ResponseModel):
method _normalize_timestamp (line 389) | def _normalize_timestamp(cls, value: datetime | int | None) -> int | N...
class AppDetailWithSite (line 393) | class AppDetailWithSite(AppDetail):
method icon_url (line 402) | def icon_url(self) -> str | None:
class AppPagination (line 406) | class AppPagination(ResponseModel):
class AppExportResponse (line 414) | class AppExportResponse(ResponseModel):
class AppListApi (line 463) | class AppListApi(Resource):
method get (line 472) | def get(self):
method post (line 541) | def post(self):
class AppApi (line 553) | class AppApi(Resource):
method get (line 563) | def get(self, app_model):
method put (line 588) | def put(self, app_model):
method delete (line 617) | def delete(self, app_model):
class AppCopyApi (line 626) | class AppCopyApi(Resource):
method post (line 638) | def post(self, app_model):
class AppExportApi (line 680) | class AppExportApi(Resource):
method get (line 692) | def get(self, app_model):
class AppNameApi (line 707) | class AppNameApi(Resource):
method post (line 718) | def post(self, app_model):
class AppIconApi (line 728) | class AppIconApi(Resource):
method post (line 740) | def post(self, app_model):
class AppSiteStatus (line 750) | class AppSiteStatus(Resource):
method post (line 762) | def post(self, app_model):
class AppApiStatus (line 772) | class AppApiStatus(Resource):
method post (line 784) | def post(self, app_model):
class AppTraceApi (line 794) | class AppTraceApi(Resource):
method get (line 802) | def get(self, app_id):
method post (line 818) | def post(self, app_id):
FILE: api/controllers/console/app/app_import.py
class AppImportPayload (line 42) | class AppImportPayload(BaseModel):
class AppImportApi (line 60) | class AppImportApi(Resource):
method post (line 68) | def post(self):
class AppImportConfirmApi (line 103) | class AppImportConfirmApi(Resource):
method post (line 109) | def post(self, import_id):
class AppImportCheckDependenciesApi (line 127) | class AppImportCheckDependenciesApi(Resource):
method get (line 134) | def get(self, app_model: App):
FILE: api/controllers/console/app/audio.py
class TextToSpeechPayload (line 39) | class TextToSpeechPayload(BaseModel):
class TextToSpeechVoiceQuery (line 46) | class TextToSpeechVoiceQuery(BaseModel):
class AudioTranscriptResponse (line 50) | class AudioTranscriptResponse(BaseModel):
class ChatMessageAudioApi (line 58) | class ChatMessageAudioApi(Resource):
method post (line 73) | def post(self, app_model):
class ChatMessageTextApi (line 111) | class ChatMessageTextApi(Resource):
method post (line 122) | def post(self, app_model: App):
class TextModesApi (line 161) | class TextModesApi(Resource):
method get (line 174) | def get(self, app_model):
FILE: api/controllers/console/app/completion.py
class BaseMessagePayload (line 43) | class BaseMessagePayload(BaseModel):
class CompletionMessagePayload (line 51) | class CompletionMessagePayload(BaseMessagePayload):
class ChatMessagePayload (line 55) | class ChatMessagePayload(BaseMessagePayload):
method validate_uuid (line 62) | def validate_uuid(cls, value: str | None) -> str | None:
class CompletionMessageApi (line 79) | class CompletionMessageApi(Resource):
method post (line 91) | def post(self, app_model):
class CompletionMessageStopApi (line 129) | class CompletionMessageStopApi(Resource):
method post (line 138) | def post(self, app_model, task_id):
class ChatMessageApi (line 153) | class ChatMessageApi(Resource):
method post (line 166) | def post(self, app_model):
class ChatMessageStopApi (line 210) | class ChatMessageStopApi(Resource):
method post (line 219) | def post(self, app_model, task_id):
FILE: api/controllers/console/app/conversation.py
class BaseConversationQuery (line 28) | class BaseConversationQuery(BaseModel):
method blank_to_none (line 40) | def blank_to_none(cls, value: str | None) -> str | None:
class CompletionConversationQuery (line 46) | class CompletionConversationQuery(BaseConversationQuery):
class ChatConversationQuery (line 50) | class ChatConversationQuery(BaseConversationQuery):
class MessageTextField (line 181) | class MessageTextField(fields.Raw):
method format (line 182) | def format(self, value):
class CompletionConversationApi (line 330) | class CompletionConversationApi(Resource):
method get (line 343) | def get(self, app_model):
class CompletionConversationDetailApi (line 401) | class CompletionConversationDetailApi(Resource):
method get (line 414) | def get(self, app_model, conversation_id):
method delete (line 430) | def delete(self, app_model, conversation_id):
class ChatConversationApi (line 443) | class ChatConversationApi(Resource):
method get (line 456) | def get(self, app_model):
class ChatConversationDetailApi (line 553) | class ChatConversationDetailApi(Resource):
method get (line 566) | def get(self, app_model, conversation_id):
method delete (line 582) | def delete(self, app_model, conversation_id):
function _get_conversation (line 594) | def _get_conversation(app_model, conversation_id):
FILE: api/controllers/console/app/conversation_variables.py
class ConversationVariablesQuery (line 22) | class ConversationVariablesQuery(BaseModel):
class ConversationVariablesApi (line 46) | class ConversationVariablesApi(Resource):
method get (line 57) | def get(self, app_model):
FILE: api/controllers/console/app/error.py
class AppNotFoundError (line 4) | class AppNotFoundError(BaseHTTPException):
class ProviderNotInitializeError (line 10) | class ProviderNotInitializeError(BaseHTTPException):
class ProviderQuotaExceededError (line 19) | class ProviderQuotaExceededError(BaseHTTPException):
class ProviderModelCurrentlyNotSupportError (line 28) | class ProviderModelCurrentlyNotSupportError(BaseHTTPException):
class ConversationCompletedError (line 34) | class ConversationCompletedError(BaseHTTPException):
class AppUnavailableError (line 40) | class AppUnavailableError(BaseHTTPException):
class CompletionRequestError (line 46) | class CompletionRequestError(BaseHTTPException):
class AppMoreLikeThisDisabledError (line 52) | class AppMoreLikeThisDisabledError(BaseHTTPException):
class NoAudioUploadedError (line 58) | class NoAudioUploadedError(BaseHTTPException):
class AudioTooLargeError (line 64) | class AudioTooLargeError(BaseHTTPException):
class UnsupportedAudioTypeError (line 70) | class UnsupportedAudioTypeError(BaseHTTPException):
class ProviderNotSupportSpeechToTextError (line 76) | class ProviderNotSupportSpeechToTextError(BaseHTTPException):
class DraftWorkflowNotExist (line 82) | class DraftWorkflowNotExist(BaseHTTPException):
class DraftWorkflowNotSync (line 88) | class DraftWorkflowNotSync(BaseHTTPException):
class TracingConfigNotExist (line 94) | class TracingConfigNotExist(BaseHTTPException):
class TracingConfigIsExist (line 100) | class TracingConfigIsExist(BaseHTTPException):
class TracingConfigCheckError (line 106) | class TracingConfigCheckError(BaseHTTPException):
class InvokeRateLimitError (line 112) | class InvokeRateLimitError(BaseHTTPException):
class NeedAddIdsError (line 120) | class NeedAddIdsError(BaseHTTPException):
FILE: api/controllers/console/app/generator.py
class InstructionGeneratePayload (line 30) | class InstructionGeneratePayload(BaseModel):
class InstructionTemplatePayload (line 40) | class InstructionTemplatePayload(BaseModel):
function reg (line 44) | def reg(cls: type[BaseModel]):
class RuleGenerateApi (line 57) | class RuleGenerateApi(Resource):
method post (line 67) | def post(self):
class RuleCodeGenerateApi (line 86) | class RuleCodeGenerateApi(Resource):
method post (line 96) | def post(self):
class RuleStructuredOutputGenerateApi (line 118) | class RuleStructuredOutputGenerateApi(Resource):
method post (line 128) | def post(self):
class InstructionGenerateApi (line 150) | class InstructionGenerateApi(Resource):
method post (line 160) | def post(self):
class InstructionGenerationTemplateApi (line 244) | class InstructionGenerationTemplateApi(Resource):
method post (line 253) | def post(self):
FILE: api/controllers/console/app/mcp_server.py
class MCPServerCreatePayload (line 23) | class MCPServerCreatePayload(BaseModel):
class MCPServerUpdatePayload (line 28) | class MCPServerUpdatePayload(BaseModel):
class AppMCPServerController (line 40) | class AppMCPServerController(Resource):
method get (line 50) | def get(self, app_model):
method post (line 66) | def post(self, app_model):
method put (line 100) | def put(self, app_model):
class AppMCPServerRefreshController (line 125) | class AppMCPServerRefreshController(Resource):
method get (line 137) | def get(self, server_id):
FILE: api/controllers/console/app/message.py
class ChatMessagesQuery (line 42) | class ChatMessagesQuery(BaseModel):
method empty_to_none (line 49) | def empty_to_none(cls, value: str | None) -> str | None:
method validate_uuid (line 56) | def validate_uuid(cls, value: str | None) -> str | None:
class MessageFeedbackPayload (line 62) | class MessageFeedbackPayload(BaseModel):
method validate_message_id (line 69) | def validate_message_id(cls, value: str) -> str:
class FeedbackExportQuery (line 73) | class FeedbackExportQuery(BaseModel):
method parse_bool (line 83) | def parse_bool(cls, value: bool | str | None) -> bool | None:
class AnnotationCountResponse (line 94) | class AnnotationCountResponse(BaseModel):
class SuggestedQuestionsResponse (line 98) | class SuggestedQuestionsResponse(BaseModel):
class ChatMessageListApi (line 231) | class ChatMessageListApi(Resource):
method get (line 244) | def get(self, app_model):
class MessageFeedbackApi (line 306) | class MessageFeedbackApi(Resource):
method post (line 318) | def post(self, app_model):
class MessageAnnotationCountApi (line 362) | class MessageAnnotationCountApi(Resource):
method get (line 375) | def get(self, app_model):
class MessageSuggestedQuestionApi (line 384) | class MessageSuggestedQuestionApi(Resource):
method get (line 398) | def get(self, app_model, message_id):
class MessageFeedbackExportApi (line 428) | class MessageFeedbackExportApi(Resource):
method get (line 440) | def get(self, app_model):
class MessageApi (line 468) | class MessageApi(Resource):
method get (line 479) | def get(self, app_model, message_id: str):
FILE: api/controllers/console/app/model_config.py
class ModelConfigResource (line 22) | class ModelConfigResource(Resource):
method post (line 53) | def post(self, app_model):
FILE: api/controllers/console/app/ops_trace.py
class TraceProviderQuery (line 17) | class TraceProviderQuery(BaseModel):
class TraceConfigPayload (line 21) | class TraceConfigPayload(BaseModel):
class TraceAppConfigApi (line 36) | class TraceAppConfigApi(Resource):
method get (line 52) | def get(self, app_id):
method post (line 74) | def post(self, app_id):
method patch (line 99) | def patch(self, app_id):
method delete (line 122) | def delete(self, app_id):
FILE: api/controllers/console/app/site.py
class AppSiteUpdatePayload (line 26) | class AppSiteUpdatePayload(BaseModel):
method validate_language (line 46) | def validate_language(cls, value: str | None) -> str | None:
class AppSite (line 62) | class AppSite(Resource):
method post (line 76) | def post(self, app_model):
class AppSiteAccessTokenReset (line 113) | class AppSiteAccessTokenReset(Resource):
method post (line 126) | def post(self, app_model):
FILE: api/controllers/console/app/statistic.py
class StatisticTimeRangeQuery (line 21) | class StatisticTimeRangeQuery(BaseModel):
method empty_string_to_none (line 27) | def empty_string_to_none(cls, value: str | None) -> str | None:
class DailyMessageStatistic (line 40) | class DailyMessageStatistic(Resource):
method get (line 54) | def get(self, app_model):
class DailyConversationStatistic (line 97) | class DailyConversationStatistic(Resource):
method get (line 111) | def get(self, app_model):
class DailyTerminalsStatistic (line 153) | class DailyTerminalsStatistic(Resource):
method get (line 167) | def get(self, app_model):
class DailyTokenCostStatistic (line 210) | class DailyTokenCostStatistic(Resource):
method get (line 224) | def get(self, app_model):
class AverageSessionInteractionStatistic (line 270) | class AverageSessionInteractionStatistic(Resource):
method get (line 284) | def get(self, app_model):
class UserSatisfactionRateStatistic (line 346) | class UserSatisfactionRateStatistic(Resource):
method get (line 360) | def get(self, app_model):
class AverageResponseTimeStatistic (line 412) | class AverageResponseTimeStatistic(Resource):
method get (line 426) | def get(self, app_model):
class TokensPerSecondStatistic (line 469) | class TokensPerSecondStatistic(Resource):
method get (line 483) | def get(self, app_model):
FILE: api/controllers/console/app/workflow.py
class SyncDraftWorkflowPayload (line 97) | class SyncDraftWorkflowPayload(BaseModel):
class BaseWorkflowRunPayload (line 105) | class BaseWorkflowRunPayload(BaseModel):
class AdvancedChatWorkflowRunPayload (line 109) | class AdvancedChatWorkflowRunPayload(BaseWorkflowRunPayload):
method validate_uuid (line 117) | def validate_uuid(cls, value: str | None) -> str | None:
class IterationNodeRunPayload (line 123) | class IterationNodeRunPayload(BaseModel):
class LoopNodeRunPayload (line 127) | class LoopNodeRunPayload(BaseModel):
class DraftWorkflowRunPayload (line 131) | class DraftWorkflowRunPayload(BaseWorkflowRunPayload):
class DraftWorkflowNodeRunPayload (line 135) | class DraftWorkflowNodeRunPayload(BaseWorkflowRunPayload):
class PublishWorkflowPayload (line 140) | class PublishWorkflowPayload(BaseModel):
class DefaultBlockConfigQuery (line 145) | class DefaultBlockConfigQuery(BaseModel):
class ConvertToWorkflowPayload (line 149) | class ConvertToWorkflowPayload(BaseModel):
class WorkflowListQuery (line 156) | class WorkflowListQuery(BaseModel):
class WorkflowUpdatePayload (line 163) | class WorkflowUpdatePayload(BaseModel):
class DraftWorkflowTriggerRunPayload (line 168) | class DraftWorkflowTriggerRunPayload(BaseModel):
class DraftWorkflowTriggerRunAllPayload (line 172) | class DraftWorkflowTriggerRunAllPayload(BaseModel):
function reg (line 176) | def reg(cls: type[BaseModel]):
function _parse_file (line 198) | def _parse_file(workflow: Workflow, files: list[dict] | None = None) -> ...
class DraftWorkflowApi (line 215) | class DraftWorkflowApi(Resource):
method get (line 227) | def get(self, app_model: App):
method post (line 263) | def post(self, app_model: App):
class AdvancedChatDraftWorkflowRunApi (line 317) | class AdvancedChatDraftWorkflowRunApi(Resource):
method post (line 330) | def post(self, app_model: App):
class AdvancedChatDraftRunIterationNodeApi (line 363) | class AdvancedChatDraftRunIterationNodeApi(Resource):
method post (line 376) | def post(self, app_model: App, node_id: str):
class WorkflowDraftRunIterationNodeApi (line 401) | class WorkflowDraftRunIterationNodeApi(Resource):
method post (line 414) | def post(self, app_model: App, node_id: str):
class AdvancedChatDraftRunLoopNodeApi (line 439) | class AdvancedChatDraftRunLoopNodeApi(Resource):
method post (line 452) | def post(self, app_model: App, node_id: str):
class WorkflowDraftRunLoopNodeApi (line 477) | class WorkflowDraftRunLoopNodeApi(Resource):
method post (line 490) | def post(self, app_model: App, node_id: str):
class HumanInputFormPreviewPayload (line 514) | class HumanInputFormPreviewPayload(BaseModel):
class HumanInputFormSubmitPayload (line 521) | class HumanInputFormSubmitPayload(BaseModel):
class HumanInputDeliveryTestPayload (line 530) | class HumanInputDeliveryTestPayload(BaseModel):
class AdvancedChatDraftHumanInputFormPreviewApi (line 544) | class AdvancedChatDraftHumanInputFormPreviewApi(Resource):
method post (line 554) | def post(self, app_model: App, node_id: str):
class AdvancedChatDraftHumanInputFormRunApi (line 573) | class AdvancedChatDraftHumanInputFormRunApi(Resource):
method post (line 583) | def post(self, app_model: App, node_id: str):
class WorkflowDraftHumanInputFormPreviewApi (line 602) | class WorkflowDraftHumanInputFormPreviewApi(Resource):
method post (line 612) | def post(self, app_model: App, node_id: str):
class WorkflowDraftHumanInputFormRunApi (line 631) | class WorkflowDraftHumanInputFormRunApi(Resource):
method post (line 641) | def post(self, app_model: App, node_id: str):
class WorkflowDraftHumanInputDeliveryTestApi (line 660) | class WorkflowDraftHumanInputDeliveryTestApi(Resource):
method post (line 670) | def post(self, app_model: App, node_id: str):
class DraftWorkflowRunApi (line 688) | class DraftWorkflowRunApi(Resource):
method post (line 700) | def post(self, app_model: App):
class WorkflowTaskStopApi (line 726) | class WorkflowTaskStopApi(Resource):
method post (line 738) | def post(self, app_model: App, task_id: str):
class DraftWorkflowNodeRunApi (line 753) | class DraftWorkflowNodeRunApi(Resource):
method post (line 767) | def post(self, app_model: App, node_id: str):
class PublishedWorkflowApi (line 801) | class PublishedWorkflowApi(Resource):
method get (line 813) | def get(self, app_model: App):
method post (line 830) | def post(self, app_model: App):
class DefaultBlockConfigsApi (line 864) | class DefaultBlockConfigsApi(Resource):
method get (line 874) | def get(self, app_model: App):
class DefaultBlockConfigApi (line 884) | class DefaultBlockConfigApi(Resource):
method get (line 896) | def get(self, app_model: App, block_type: str):
class ConvertToWorkflowApi (line 915) | class ConvertToWorkflowApi(Resource):
method post (line 928) | def post(self, app_model: App):
class PublishedAllWorkflowApi (line 950) | class PublishedAllWorkflowApi(Resource):
method get (line 962) | def get(self, app_model: App):
class DraftWorkflowRestoreApi (line 998) | class DraftWorkflowRestoreApi(Resource):
method post (line 1010) | def post(self, app_model: App, workflow_id: str):
class WorkflowByIdApi (line 1035) | class WorkflowByIdApi(Resource):
method patch (line 1049) | def patch(self, app_model: App, workflow_id: str):
method delete (line 1088) | def delete(self, app_model: App, workflow_id: str):
class DraftWorkflowNodeLastRunApi (line 1111) | class DraftWorkflowNodeLastRunApi(Resource):
method get (line 1123) | def get(self, app_model: App, node_id: str):
class DraftWorkflowTriggerRunApi (line 1139) | class DraftWorkflowTriggerRunApi(Resource):
method post (line 1164) | def post(self, app_model: App):
class DraftWorkflowTriggerNodeApi (line 1211) | class DraftWorkflowTriggerNodeApi(Resource):
method post (line 1228) | def post(self, app_model: App, node_id: str):
class DraftWorkflowTriggerRunAllApi (line 1290) | class DraftWorkflowTriggerRunAllApi(Resource):
method post (line 1308) | def post(self, app_model: App):
FILE: api/controllers/console/app/workflow_app_log.py
class WorkflowAppLogQuery (line 26) | class WorkflowAppLogQuery(BaseModel):
method parse_datetime (line 41) | def parse_datetime(cls, value: str | None) -> datetime | None:
method parse_bool (line 48) | def parse_bool(cls, value: bool | str | None) -> bool:
class WorkflowAppLogApi (line 71) | class WorkflowAppLogApi(Resource):
method get (line 82) | def get(self, app_model: App):
class WorkflowArchivedLogApi (line 109) | class WorkflowArchivedLogApi(Resource):
method get (line 120) | def get(self, app_model: App):
FILE: api/controllers/console/app/workflow_draft_variable.py
class WorkflowDraftVariableListQuery (line 38) | class WorkflowDraftVariableListQuery(BaseModel):
class WorkflowDraftVariableUpdatePayload (line 43) | class WorkflowDraftVariableUpdatePayload(BaseModel):
function _convert_values_to_json_serializable_object (line 58) | def _convert_values_to_json_serializable_object(value: Segment):
function _serialize_var_value (line 69) | def _serialize_var_value(variable: WorkflowDraftVariable):
function _serialize_variable_type (line 84) | def _serialize_variable_type(workflow_draft_var: WorkflowDraftVariable) ...
function _serialize_full_content (line 89) | def _serialize_full_content(variable: WorkflowDraftVariable) -> dict | N...
function _ensure_variable_access (line 105) | def _ensure_variable_access(
function _get_items (line 151) | def _get_items(var_list: WorkflowDraftVariableList) -> list[WorkflowDraf...
function _api_prerequisite (line 199) | def _api_prerequisite(f: Callable[P, R]):
class WorkflowVariableCollectionApi (line 223) | class WorkflowVariableCollectionApi(Resource):
method get (line 234) | def get(self, app_model: App):
method delete (line 264) | def delete(self, app_model: App):
function validate_node_id (line 273) | def validate_node_id(node_id: str) -> NoReturn | None:
class NodeVariableCollectionApi (line 292) | class NodeVariableCollectionApi(Resource):
method get (line 299) | def get(self, app_model: App, node_id: str):
method delete (line 313) | def delete(self, app_model: App, node_id: str):
class VariableApi (line 322) | class VariableApi(Resource):
method get (line 333) | def get(self, app_model: App, variable_id: str):
method patch (line 351) | def patch(self, app_model: App, variable_id: str):
method delete (line 419) | def delete(self, app_model: App, variable_id: str):
class VariableResetApi (line 434) | class VariableResetApi(Resource):
method put (line 442) | def put(self, app_model: App, variable_id: str):
function _get_variable_list (line 467) | def _get_variable_list(app_model: App, node_id) -> WorkflowDraftVariable...
class ConversationVariableCollectionApi (line 486) | class ConversationVariableCollectionApi(Resource):
method get (line 494) | def get(self, app_model: App):
class SystemVariableCollectionApi (line 508) | class SystemVariableCollectionApi(Resource):
method get (line 515) | def get(self, app_model: App):
class EnvironmentVariableCollectionApi (line 520) | class EnvironmentVariableCollectionApi(Resource):
method get (line 527) | def get(self, app_model: App):
FILE: api/controllers/console/app/workflow_run.py
function _build_backstage_input_url (line 42) | def _build_backstage_input_url(form_token: str | None) -> str | None:
class WorkflowRunListQuery (line 132) | class WorkflowRunListQuery(BaseModel):
method validate_last_id (line 144) | def validate_last_id(cls, value: str | None) -> str | None:
class WorkflowRunCountQuery (line 150) | class WorkflowRunCountQuery(BaseModel):
method validate_time_range (line 161) | def validate_time_range(cls, value: str | None) -> str | None:
class HumanInputPauseTypeResponse (line 176) | class HumanInputPauseTypeResponse(TypedDict):
class PausedNodeResponse (line 182) | class PausedNodeResponse(TypedDict):
class WorkflowPauseDetailsResponse (line 188) | class WorkflowPauseDetailsResponse(TypedDict):
class AdvancedChatAppWorkflowRunListApi (line 194) | class AdvancedChatAppWorkflowRunListApi(Resource):
method get (line 212) | def get(self, app_model: App):
class WorkflowRunExportApi (line 235) | class WorkflowRunExportApi(Resource):
method get (line 244) | def get(self, app_model: App, run_id: str):
class AdvancedChatAppWorkflowRunCountApi (line 285) | class AdvancedChatAppWorkflowRunCountApi(Resource):
method get (line 310) | def get(self, app_model: App):
class WorkflowRunListApi (line 336) | class WorkflowRunListApi(Resource):
method get (line 354) | def get(self, app_model: App):
class WorkflowRunCountApi (line 377) | class WorkflowRunCountApi(Resource):
method get (line 402) | def get(self, app_model: App):
class WorkflowRunDetailApi (line 428) | class WorkflowRunDetailApi(Resource):
method get (line 439) | def get(self, app_model: App, run_id):
class WorkflowRunNodeExecutionListApi (line 452) | class WorkflowRunNodeExecutionListApi(Resource):
method get (line 463) | def get(self, app_model: App, run_id):
class ConsoleWorkflowPauseDetailsApi (line 481) | class ConsoleWorkflowPauseDetailsApi(Resource):
method get (line 487) | def get(self, workflow_run_id: str):
FILE: api/controllers/console/app/workflow_statistic.py
class WorkflowStatisticQuery (line 19) | class WorkflowStatisticQuery(BaseModel):
method blank_to_none (line 25) | def blank_to_none(cls, value: str | None) -> str | None:
class WorkflowDailyRunsStatistic (line 38) | class WorkflowDailyRunsStatistic(Resource):
method __init__ (line 39) | def __init__(self, *args, **kwargs):
method get (line 53) | def get(self, app_model):
class WorkflowDailyTerminalsStatistic (line 78) | class WorkflowDailyTerminalsStatistic(Resource):
method __init__ (line 79) | def __init__(self, *args, **kwargs):
method get (line 93) | def get(self, app_model):
class WorkflowDailyTokenCostStatistic (line 118) | class WorkflowDailyTokenCostStatistic(Resource):
method __init__ (line 119) | def __init__(self, *args, **kwargs):
method get (line 133) | def get(self, app_model):
class WorkflowAverageAppInteractionStatistic (line 158) | class WorkflowAverageAppInteractionStatistic(Resource):
method __init__ (line 159) | def __init__(self, *args, **kwargs):
method get (line 173) | def get(self, app_model):
FILE: api/controllers/console/app/workflow_trigger.py
class Parser (line 35) | class Parser(BaseModel):
class ParserEnable (line 39) | class ParserEnable(BaseModel):
class WebhookTriggerApi (line 52) | class WebhookTriggerApi(Resource):
method get (line 61) | def get(self, app_model: App):
class AppTriggersApi (line 85) | class AppTriggersApi(Resource):
method get (line 93) | def get(self, app_model: App):
class AppTriggerEnableApi (line 125) | class AppTriggerEnableApi(Resource):
method post (line 133) | def post(self, app_model: App):
FILE: api/controllers/console/app/wraps.py
function _load_app_model (line 18) | def _load_app_model(app_id: str) -> App | None:
function _load_app_model_with_trial (line 26) | def _load_app_model_with_trial(app_id: str) -> App | None:
function get_app_model (line 31) | def get_app_model(view: Callable[P, R] | None = None, *, mode: Union[App...
function get_app_model_with_trial (line 72) | def get_app_model_with_trial(view: Callable[P, R] | None = None, *, mode...
FILE: api/controllers/console/auth/activate.py
class ActivateCheckQuery (line 17) | class ActivateCheckQuery(BaseModel):
class ActivatePayload (line 23) | class ActivatePayload(BaseModel):
method validate_lang (line 33) | def validate_lang(cls, value: str) -> str:
method validate_tz (line 38) | def validate_tz(cls, value: str) -> str:
class ActivateCheckApi (line 47) | class ActivateCheckApi(Resource):
method get (line 62) | def get(self):
class ActivateApi (line 91) | class ActivateApi(Resource):
method post (line 106) | def post(self):
FILE: api/controllers/console/auth/data_source_bearer_auth.py
class ApiKeyAuthBindingPayload (line 14) | class ApiKeyAuthBindingPayload(BaseModel):
class ApiKeyAuthDataSource (line 27) | class ApiKeyAuthDataSource(Resource):
method get (line 31) | def get(self):
class ApiKeyAuthDataSourceBinding (line 52) | class ApiKeyAuthDataSourceBinding(Resource):
method post (line 58) | def post(self):
class ApiKeyAuthDataSourceBindingDelete (line 72) | class ApiKeyAuthDataSourceBindingDelete(Resource):
method delete (line 77) | def delete(self, binding_id):
FILE: api/controllers/console/auth/data_source_oauth.py
class OAuthDataSourceResponse (line 19) | class OAuthDataSourceResponse(BaseModel):
class OAuthDataSourceBindingResponse (line 23) | class OAuthDataSourceBindingResponse(BaseModel):
class OAuthDataSourceSyncResponse (line 27) | class OAuthDataSourceSyncResponse(BaseModel):
function get_oauth_providers (line 39) | def get_oauth_providers():
class OAuthDataSource (line 52) | class OAuthDataSource(Resource):
method get (line 64) | def get(self, provider: str):
class OAuthDataSourceCallback (line 83) | class OAuthDataSourceCallback(Resource):
method get (line 95) | def get(self, provider: str):
class OAuthDataSourceBinding (line 114) | class OAuthDataSourceBinding(Resource):
method get (line 126) | def get(self, provider: str):
class OAuthDataSourceSync (line 148) | class OAuthDataSourceSync(Resource):
method get (line 161) | def get(self, provider, binding_id):
FILE: api/controllers/console/auth/email_register.py
class EmailRegisterSendPayload (line 31) | class EmailRegisterSendPayload(BaseModel):
class EmailRegisterValidityPayload (line 36) | class EmailRegisterValidityPayload(BaseModel):
class EmailRegisterResetPayload (line 42) | class EmailRegisterResetPayload(BaseModel):
method validate_password (line 49) | def validate_password(cls, value: str) -> str:
class EmailRegisterSendEmailApi (line 58) | class EmailRegisterSendEmailApi(Resource):
method post (line 62) | def post(self):
class EmailRegisterCheckApi (line 83) | class EmailRegisterCheckApi(Resource):
method post (line 87) | def post(self):
class EmailRegisterResetApi (line 123) | class EmailRegisterResetApi(Resource):
method post (line 127) | def post(self):
method _create_new_account (line 162) | def _create_new_account(self, email: str, password: str) -> Account | ...
FILE: api/controllers/console/auth/error.py
class ApiKeyAuthFailedError (line 4) | class ApiKeyAuthFailedError(BaseHTTPException):
class InvalidEmailError (line 10) | class InvalidEmailError(BaseHTTPException):
class PasswordMismatchError (line 16) | class PasswordMismatchError(BaseHTTPException):
class InvalidTokenError (line 22) | class InvalidTokenError(BaseHTTPException):
class PasswordResetRateLimitExceededError (line 28) | class PasswordResetRateLimitExceededError(BaseHTTPException):
method __init__ (line 33) | def __init__(self, minutes: int = 1):
class EmailRegisterRateLimitExceededError (line 38) | class EmailRegisterRateLimitExceededError(BaseHTTPException):
method __init__ (line 43) | def __init__(self, minutes: int = 1):
class EmailChangeRateLimitExceededError (line 48) | class EmailChangeRateLimitExceededError(BaseHTTPException):
method __init__ (line 53) | def __init__(self, minutes: int = 1):
class OwnerTransferRateLimitExceededError (line 58) | class OwnerTransferRateLimitExceededError(BaseHTTPException):
method __init__ (line 63) | def __init__(self, minutes: int = 1):
class EmailCodeError (line 68) | class EmailCodeError(BaseHTTPException):
class EmailOrPasswordMismatchError (line 74) | class EmailOrPasswordMismatchError(BaseHTTPException):
class AuthenticationFailedError (line 80) | class AuthenticationFailedError(BaseHTTPException):
class EmailPasswordLoginLimitError (line 86) | class EmailPasswordLoginLimitError(BaseHTTPException):
class EmailCodeLoginRateLimitExceededError (line 92) | class EmailCodeLoginRateLimitExceededError(BaseHTTPException):
method __init__ (line 97) | def __init__(self, minutes: int = 5):
class EmailCodeAccountDeletionRateLimitExceededError (line 102) | class EmailCodeAccountDeletionRateLimitExceededError(BaseHTTPException):
method __init__ (line 107) | def __init__(self, minutes: int = 5):
class EmailPasswordResetLimitError (line 112) | class EmailPasswordResetLimitError(BaseHTTPException):
class EmailRegisterLimitError (line 118) | class EmailRegisterLimitError(BaseHTTPException):
class EmailChangeLimitError (line 124) | class EmailChangeLimitError(BaseHTTPException):
class EmailAlreadyInUseError (line 130) | class EmailAlreadyInUseError(BaseHTTPException):
class OwnerTransferLimitError (line 136) | class OwnerTransferLimitError(BaseHTTPException):
class NotOwnerError (line 142) | class NotOwnerError(BaseHTTPException):
class CannotTransferOwnerToSelfError (line 148) | class CannotTransferOwnerToSelfError(BaseHTTPException):
class MemberNotInTenantError (line 154) | class MemberNotInTenantError(BaseHTTPException):
FILE: api/controllers/console/auth/forgot_password.py
class ForgotPasswordSendPayload (line 30) | class ForgotPasswordSendPayload(BaseModel):
class ForgotPasswordCheckPayload (line 35) | class ForgotPasswordCheckPayload(BaseModel):
class ForgotPasswordResetPayload (line 41) | class ForgotPasswordResetPayload(BaseModel):
method validate_password (line 48) | def validate_password(cls, value: str) -> str:
class ForgotPasswordEmailResponse (line 52) | class ForgotPasswordEmailResponse(BaseModel):
class ForgotPasswordCheckResponse (line 58) | class ForgotPasswordCheckResponse(BaseModel):
class ForgotPasswordResetResponse (line 64) | class ForgotPasswordResetResponse(BaseModel):
class ForgotPasswordSendEmailApi (line 80) | class ForgotPasswordSendEmailApi(Resource):
method post (line 92) | def post(self):
class ForgotPasswordCheckApi (line 119) | class ForgotPasswordCheckApi(Resource):
method post (line 131) | def post(self):
class ForgotPasswordResetApi (line 169) | class ForgotPasswordResetApi(Resource):
method post (line 181) | def post(self):
method _update_existing_account (line 214) | def _update_existing_account(self, account, password_hashed, salt, ses...
FILE: api/controllers/console/auth/login.py
class LoginPayload (line 54) | class LoginPayload(BaseModel):
class EmailPayload (line 61) | class EmailPayload(BaseModel):
class EmailCodeLoginPayload (line 66) | class EmailCodeLoginPayload(BaseModel):
function reg (line 73) | def reg(cls: type[BaseModel]):
class LoginApi (line 83) | class LoginApi(Resource):
method post (line 90) | def post(self):
class LogoutApi (line 152) | class LogoutApi(Resource):
method post (line 154) | def post(self):
class ResetPasswordSendEmailApi (line 173) | class ResetPasswordSendEmailApi(Resource):
method post (line 177) | def post(self):
class EmailCodeLoginSendEmailApi (line 201) | class EmailCodeLoginSendEmailApi(Resource):
method post (line 204) | def post(self):
class EmailCodeLoginApi (line 233) | class EmailCodeLoginApi(Resource):
method post (line 237) | def post(self):
class RefreshTokenApi (line 302) | class RefreshTokenApi(Resource):
method post (line 303) | def post(self):
function _get_account_with_case_fallback (line 325) | def _get_account_with_case_fallback(email: str):
function _authenticate_account_with_case_fallback (line 333) | def _authenticate_account_with_case_fallback(
FILE: api/controllers/console/auth/oauth.py
function get_oauth_providers (line 34) | def get_oauth_providers():
class OAuthLogin (line 58) | class OAuthLogin(Resource):
method get (line 66) | def get(self, provider: str):
class OAuthCallback (line 79) | class OAuthCallback(Resource):
method get (line 91) | def get(self, provider: str):
function _get_account_by_openid_or_email (line 179) | def _get_account_by_openid_or_email(provider: str, user_info: OAuthUserI...
function _generate_account (line 189) | def _generate_account(provider: str, user_info: OAuthUserInfo) -> tuple[...
FILE: api/controllers/console/auth/oauth_server.py
class OAuthClientPayload (line 24) | class OAuthClientPayload(BaseModel):
class OAuthProviderRequest (line 28) | class OAuthProviderRequest(BaseModel):
class OAuthTokenRequest (line 33) | class OAuthTokenRequest(BaseModel):
function oauth_server_client_id_required (line 42) | def oauth_server_client_id_required(view: Callable[Concatenate[T, OAuthP...
function oauth_server_access_token_required (line 61) | def oauth_server_access_token_required(view: Callable[Concatenate[T, OAu...
class OAuthServerAppApi (line 108) | class OAuthServerAppApi(Resource):
method post (line 111) | def post(self, oauth_provider_app: OAuthProviderApp):
class OAuthServerUserAuthorizeApi (line 129) | class OAuthServerUserAuthorizeApi(Resource):
method post (line 134) | def post(self, oauth_provider_app: OAuthProviderApp):
class OAuthServerUserTokenApi (line 148) | class OAuthServerUserTokenApi(Resource):
method post (line 151) | def post(self, oauth_provider_app: OAuthProviderApp):
class OAuthServerUserAccountApi (line 198) | class OAuthServerUserAccountApi(Resource):
method post (line 202) | def post(self, oauth_provider_app: OAuthProviderApp, account: Account):
FILE: api/controllers/console/billing/billing.py
class SubscriptionQuery (line 18) | class SubscriptionQuery(BaseModel):
class PartnerTenantsPayload (line 23) | class PartnerTenantsPayload(BaseModel):
class Subscription (line 32) | class Subscription(Resource):
method get (line 37) | def get(self):
class Invoices (line 45) | class Invoices(Resource):
method get (line 50) | def get(self):
class PartnerTenants (line 57) | class PartnerTenants(Resource):
method put (line 73) | def put(self, partner_key: str):
FILE: api/controllers/console/billing/compliance.py
class ComplianceDownloadQuery (line 13) | class ComplianceDownloadQuery(BaseModel):
class ComplianceApi (line 24) | class ComplianceApi(Resource):
method get (line 32) | def get(self):
FILE: api/controllers/console/datasets/data_source.py
class NotionEstimatePayload (line 39) | class NotionEstimatePayload(BaseModel):
class DataSourceNotionListQuery (line 46) | class DataSourceNotionListQuery(BaseModel):
class DataSourceNotionPreviewQuery (line 52) | class DataSourceNotionPreviewQuery(BaseModel):
class DataSourceApi (line 106) | class DataSourceApi(Resource):
method get (line 111) | def get(self):
method patch (line 160) | def patch(self, binding_id, action: Literal["enable", "disable"]):
class DataSourceNotionListApi (line 191) | class DataSourceNotionListApi(Resource):
method get (line 196) | def get(self):
class DataSourceNotionApi (line 285) | class DataSourceNotionApi(Resource):
method get (line 289) | def get(self, page_id, page_type):
method post (line 319) | def post(self):
class DataSourceNotionDatasetSyncApi (line 358) | class DataSourceNotionDatasetSyncApi(Resource):
method get (line 362) | def get(self, dataset_id):
class DataSourceNotionDocumentSyncApi (line 375) | class DataSourceNotionDocumentSyncApi(Resource):
method get (line 379) | def get(self, dataset_id, document_id):
FILE: api/controllers/console/datasets/datasets.py
function _validate_indexing_technique (line 116) | def _validate_indexing_technique(value: str | None) -> str | None:
function _validate_doc_form (line 124) | def _validate_doc_form(value: str | None) -> str | None:
class DatasetCreatePayload (line 132) | class DatasetCreatePayload(BaseModel):
method validate_indexing (line 143) | def validate_indexing(cls, value: str | None) -> str | None:
method validate_provider (line 148) | def validate_provider(cls, value: str) -> str:
class DatasetUpdatePayload (line 154) | class DatasetUpdatePayload(BaseModel):
method validate_indexing (line 172) | def validate_indexing(cls, value: str | None) -> str | None:
class IndexingEstimatePayload (line 176) | class IndexingEstimatePayload(BaseModel):
method validate_indexing (line 186) | def validate_indexing(cls, value: str) -> str:
method validate_doc_form (line 194) | def validate_doc_form(cls, value: str) -> str:
class ConsoleDatasetListQuery (line 201) | class ConsoleDatasetListQuery(BaseModel):
function _get_retrieval_methods_by_vector_type (line 215) | def _get_retrieval_methods_by_vector_type(vector_type: str | None, is_mo...
class DatasetListApi (line 292) | class DatasetListApi(Resource):
method get (line 310) | def get(self):
method post (line 392) | def post(self):
class DatasetApi (line 419) | class DatasetApi(Resource):
method get (line 429) | def get(self, dataset_id):
method patch (line 479) | def patch(self, dataset_id):
method delete (line 526) | def delete(self, dataset_id):
class DatasetUseCheckApi (line 544) | class DatasetUseCheckApi(Resource):
method get (line 552) | def get(self, dataset_id):
class DatasetQueryApi (line 560) | class DatasetQueryApi(Resource):
method get (line 568) | def get(self, dataset_id):
class DatasetIndexingEstimateApi (line 596) | class DatasetIndexingEstimateApi(Resource):
method post (line 604) | def post(self):
class DatasetRelatedAppListApi (line 692) | class DatasetRelatedAppListApi(Resource):
method get (line 701) | def get(self, dataset_id):
class DatasetIndexingStatusApi (line 725) | class DatasetIndexingStatusApi(Resource):
method get (line 733) | def get(self, dataset_id):
class DatasetApiKeyApi (line 781) | class DatasetApiKeyApi(Resource):
method get (line 793) | def get(self):
method post (line 805) | def post(self):
class DatasetApiDeleteApi (line 835) | class DatasetApiDeleteApi(Resource):
method delete (line 846) | def delete(self, api_key_id):
class DatasetEnableApiApi (line 874) | class DatasetEnableApiApi(Resource):
method post (line 878) | def post(self, dataset_id, status):
class DatasetApiBaseUrlApi (line 887) | class DatasetApiBaseUrlApi(Resource):
method get (line 894) | def get(self):
class DatasetRetrievalSettingApi (line 899) | class DatasetRetrievalSettingApi(Resource):
method get (line 906) | def get(self):
class DatasetRetrievalSettingMockApi (line 912) | class DatasetRetrievalSettingMockApi(Resource):
method get (line 920) | def get(self, vector_type):
class DatasetErrorDocs (line 925) | class DatasetErrorDocs(Resource):
method get (line 934) | def get(self, dataset_id):
class DatasetPermissionUserListApi (line 945) | class DatasetPermissionUserListApi(Resource):
method get (line 955) | def get(self, dataset_id):
class DatasetAutoDisableLogApi (line 974) | class DatasetAutoDisableLogApi(Resource):
method get (line 983) | def get(self, dataset_id):
FILE: api/controllers/console/datasets/datasets_document.py
class DocumentRetryPayload (line 101) | class DocumentRetryPayload(BaseModel):
class DocumentRenamePayload (line 105) | class DocumentRenamePayload(BaseModel):
class GenerateSummaryPayload (line 109) | class GenerateSummaryPayload(BaseModel):
class DocumentBatchDownloadZipPayload (line 113) | class DocumentBatchDownloadZipPayload(BaseModel):
class DocumentDatasetListParam (line 119) | class DocumentDatasetListParam(BaseModel):
class DocumentResource (line 140) | class DocumentResource(Resource):
method get_document (line 141) | def get_document(self, dataset_id: str, document_id: str) -> Document:
method get_batch_documents (line 162) | def get_batch_documents(self, dataset_id: str, batch: str) -> Sequence...
class GetProcessRuleApi (line 182) | class GetProcessRuleApi(Resource):
method get (line 190) | def get(self):
class DatasetDocumentListApi (line 229) | class DatasetDocumentListApi(Resource):
method get (line 247) | def get(self, dataset_id):
method post (line 373) | def post(self, dataset_id):
method delete (line 416) | def delete(self, dataset_id):
class DatasetInitApi (line 434) | class DatasetInitApi(Resource):
method post (line 446) | def post(self):
class DocumentIndexingEstimateApi (line 497) | class DocumentIndexingEstimateApi(DocumentResource):
method get (line 507) | def get(self, dataset_id, document_id):
class DocumentBatchIndexingEstimateApi (line 568) | class DocumentBatchIndexingEstimateApi(DocumentResource):
method get (line 572) | def get(self, dataset_id, batch):
class DocumentBatchIndexingStatusApi (line 666) | class DocumentBatchIndexingStatusApi(DocumentResource):
method get (line 670) | def get(self, dataset_id, batch):
class DocumentIndexingStatusApi (line 716) | class DocumentIndexingStatusApi(DocumentResource):
method get (line 725) | def get(self, dataset_id, document_id):
class DocumentApi (line 769) | class DocumentApi(DocumentResource):
method get (line 786) | def get(self, dataset_id, document_id):
method delete (line 874) | def delete(self, dataset_id, document_id):
class DocumentDownloadApi (line 894) | class DocumentDownloadApi(DocumentResource):
method get (line 903) | def get(self, dataset_id: str, document_id: str) -> dict[str, Any]:
class DocumentBatchDownloadZipApi (line 910) | class DocumentBatchDownloadZipApi(DocumentResource):
method post (line 920) | def post(self, dataset_id: str):
class DocumentProcessingApi (line 950) | class DocumentProcessingApi(DocumentResource):
method patch (line 963) | def patch(self, dataset_id, document_id, action: Literal["pause", "res...
class DocumentMetadataApi (line 996) | class DocumentMetadataApi(DocumentResource):
method put (line 1015) | def put(self, dataset_id, document_id):
class DocumentStatusApi (line 1057) | class DocumentStatusApi(DocumentResource):
method patch (line 1063) | def patch(self, dataset_id, action: Literal["enable", "disable", "arch...
class DocumentPauseApi (line 1095) | class DocumentPauseApi(DocumentResource):
method patch (line 1100) | def patch(self, dataset_id, document_id):
class DocumentRecoverApi (line 1129) | class DocumentRecoverApi(DocumentResource):
method patch (line 1134) | def patch(self, dataset_id, document_id):
class DocumentRetryApi (line 1160) | class DocumentRetryApi(DocumentResource):
method post (line 1166) | def post(self, dataset_id):
class DocumentRenameApi (line 1202) | class DocumentRenameApi(DocumentResource):
method post (line 1208) | def post(self, dataset_id, document_id):
class WebsiteDocumentSyncApi (line 1228) | class WebsiteDocumentSyncApi(DocumentResource):
method get (line 1232) | def get(self, dataset_id, document_id):
class DocumentPipelineExecutionLogApi (line 1257) | class DocumentPipelineExecutionLogApi(DocumentResource):
method get (line 1261) | def get(self, dataset_id, document_id):
class DocumentGenerateSummaryApi (line 1293) | class DocumentGenerateSummaryApi(Resource):
method post (line 1306) | def post(self, dataset_id):
class DocumentSummaryStatusApi (line 1390) | class DocumentSummaryStatusApi(DocumentResource):
method get (line 1399) | def get(self, dataset_id, document_id):
FILE: api/controllers/console/datasets/datasets_segments.py
function _get_segment_with_summary (line 45) | def _get_segment_with_summary(segment, dataset_id):
class SegmentListQuery (line 56) | class SegmentListQuery(BaseModel):
class SegmentCreatePayload (line 65) | class SegmentCreatePayload(BaseModel):
class SegmentUpdatePayload (line 72) | class SegmentUpdatePayload(BaseModel):
class BatchImportPayload (line 81) | class BatchImportPayload(BaseModel):
class ChildChunkCreatePayload (line 85) | class ChildChunkCreatePayload(BaseModel):
class ChildChunkUpdatePayload (line 89) | class ChildChunkUpdatePayload(BaseModel):
class ChildChunkBatchUpdatePayload (line 93) | class ChildChunkBatchUpdatePayload(BaseModel):
class DatasetDocumentSegmentListApi (line 111) | class DatasetDocumentSegmentListApi(Resource):
method get (line 115) | def get(self, dataset_id, document_id):
method delete (line 227) | def delete(self, dataset_id, document_id):
class DatasetDocumentSegmentApi (line 256) | class DatasetDocumentSegmentApi(Resource):
method patch (line 262) | def patch(self, dataset_id, document_id, action):
class DatasetDocumentSegmentAddApi (line 313) | class DatasetDocumentSegmentAddApi(Resource):
method post (line 321) | def post(self, dataset_id, document_id):
class DatasetDocumentSegmentUpdateApi (line 365) | class DatasetDocumentSegmentUpdateApi(Resource):
method patch (line 372) | def patch(self, dataset_id, document_id, segment_id):
method delete (line 434) | def delete(self, dataset_id, document_id, segment_id):
class DatasetDocumentSegmentBatchImportApi (line 473) | class DatasetDocumentSegmentBatchImportApi(Resource):
method post (line 481) | def post(self, dataset_id, document_id):
method get (line 527) | def get(self, job_id=None, dataset_id=None, document_id=None):
class ChildChunkAddApi (line 540) | class ChildChunkAddApi(Resource):
method post (line 548) | def post(self, dataset_id, document_id, segment_id):
method get (line 603) | def get(self, dataset_id, document_id, segment_id):
method patch (line 653) | def patch(self, dataset_id, document_id, segment_id):
class ChildChunkUpdateApi (line 696) | class ChildChunkUpdateApi(Resource):
method delete (line 701) | def delete(self, dataset_id, document_id, segment_id, child_chunk_id):
method patch (line 758) | def patch(self, dataset_id, document_id, segment_id, child_chunk_id):
FILE: api/controllers/console/datasets/error.py
class DatasetNotInitializedError (line 4) | class DatasetNotInitializedError(BaseHTTPException):
class ArchivedDocumentImmutableError (line 10) | class ArchivedDocumentImmutableError(BaseHTTPException):
class DatasetNameDuplicateError (line 16) | class DatasetNameDuplicateError(BaseHTTPException):
class InvalidActionError (line 22) | class InvalidActionError(BaseHTTPException):
class DocumentAlreadyFinishedError (line 28) | class DocumentAlreadyFinishedError(BaseHTTPException):
class DocumentIndexingError (line 34) | class DocumentIndexingError(BaseHTTPException):
class InvalidMetadataError (line 40) | class InvalidMetadataError(BaseHTTPException):
class WebsiteCrawlError (line 46) | class WebsiteCrawlError(BaseHTTPException):
class DatasetInUseError (line 52) | class DatasetInUseError(BaseHTTPException):
class IndexingEstimateError (line 58) | class IndexingEstimateError(BaseHTTPException):
class ChildChunkIndexingError (line 64) | class ChildChunkIndexingError(BaseHTTPException):
class ChildChunkDeleteIndexError (line 70) | class ChildChunkDeleteIndexError(BaseHTTPException):
class PipelineNotFoundError (line 76) | class PipelineNotFoundError(BaseHTTPException):
FILE: api/controllers/console/datasets/external.py
function _build_dataset_detail_model (line 31) | def _build_dataset_detail_model():
class ExternalKnowledgeApiPayload (line 69) | class ExternalKnowledgeApiPayload(BaseModel):
class ExternalDatasetCreatePayload (line 74) | class ExternalDatasetCreatePayload(BaseModel):
class ExternalHitTestingPayload (line 82) | class ExternalHitTestingPayload(BaseModel):
class BedrockRetrievalPayload (line 88) | class BedrockRetrievalPayload(BaseModel):
class ExternalApiTemplateListQuery (line 94) | class ExternalApiTemplateListQuery(BaseModel):
class ExternalApiTemplateListApi (line 111) | class ExternalApiTemplateListApi(Resource):
method get (line 125) | def get(self):
method post (line 145) | def post(self):
class ExternalApiTemplateApi (line 166) | class ExternalApiTemplateApi(Resource):
method get (line 175) | def get(self, external_knowledge_api_id):
method patch (line 187) | def patch(self, external_knowledge_api_id):
method delete (line 206) | def delete(self, external_knowledge_api_id):
class ExternalApiUseCheckApi (line 218) | class ExternalApiUseCheckApi(Resource):
method get (line 226) | def get(self, external_knowledge_api_id):
class ExternalDatasetCreateApi (line 236) | class ExternalDatasetCreateApi(Resource):
method post (line 247) | def post(self):
class ExternalKnowledgeHitTestingApi (line 270) | class ExternalKnowledgeHitTestingApi(Resource):
method post (line 281) | def post(self, dataset_id):
class BedrockRetrievalApi (line 311) | class BedrockRetrievalApi(Resource):
method post (line 317) | def post(self):
FILE: api/controllers/console/datasets/hit_testing.py
function _get_or_create_model (line 24) | def _get_or_create_model(model_name: str, field_def):
class HitTestingApi (line 57) | class HitTestingApi(Resource, DatasetsHitTestingBase):
method post (line 69) | def post(self, dataset_id):
FILE: api/controllers/console/datasets/hit_testing_base.py
class HitTestingPayload (line 33) | class HitTestingPayload(BaseModel):
class DatasetsHitTestingBase (line 40) | class DatasetsHitTestingBase:
method get_and_validate_dataset (line 42) | def get_and_validate_dataset(dataset_id: str):
method hit_testing_args_check (line 56) | def hit_testing_args_check(args: dict[str, Any]):
method parse_args (line 60) | def parse_args(payload: dict[str, Any]) -> dict[str, Any]:
method perform_hit_testing (line 66) | def perform_hit_testing(dataset, args):
FILE: api/controllers/console/datasets/metadata.py
class MetadataUpdatePayload (line 22) | class MetadataUpdatePayload(BaseModel):
class DatasetMetadataCreateApi (line 32) | class DatasetMetadataCreateApi(Resource):
method post (line 39) | def post(self, dataset_id):
method get (line 56) | def get(self, dataset_id):
class DatasetMetadataApi (line 65) | class DatasetMetadataApi(Resource):
method patch (line 72) | def patch(self, dataset_id, metadata_id):
method delete (line 91) | def delete(self, dataset_id, metadata_id):
class DatasetMetadataBuiltInFieldApi (line 105) | class DatasetMetadataBuiltInFieldApi(Resource):
method get (line 110) | def get(self):
class DatasetMetadataBuiltInFieldActionApi (line 116) | class DatasetMetadataBuiltInFieldActionApi(Resource):
method post (line 121) | def post(self, dataset_id, action: Literal["enable", "disable"]):
class DocumentMetadataEditApi (line 138) | class DocumentMetadataEditApi(Resource):
method post (line 144) | def post(self, dataset_id):
FILE: api/controllers/console/datasets/rag_pipeline/datasource_auth.py
class DatasourceCredentialPayload (line 21) | class DatasourceCredentialPayload(BaseModel):
class DatasourceCredentialDeletePayload (line 26) | class DatasourceCredentialDeletePayload(BaseModel):
class DatasourceCredentialUpdatePayload (line 30) | class DatasourceCredentialUpdatePayload(BaseModel):
class DatasourceCustomClientPayload (line 36) | class DatasourceCustomClientPayload(BaseModel):
class DatasourceDefaultPayload (line 41) | class DatasourceDefaultPayload(BaseModel):
class DatasourceUpdateNamePayload (line 45) | class DatasourceUpdateNamePayload(BaseModel):
class DatasourcePluginOAuthAuthorizationUrl (line 62) | class DatasourcePluginOAuthAuthorizationUrl(Resource):
method get (line 67) | def get(self, provider_id: str):
class DatasourceOAuthCallback (line 112) | class DatasourceOAuthCallback(Resource):
method get (line 114) | def get(self, provider_id: str):
class DatasourceAuth (line 169) | class DatasourceAuth(Resource):
method post (line 175) | def post(self, provider_id: str):
method get (line 196) | def get(self, provider_id: str):
class DatasourceAuthDeleteApi (line 210) | class DatasourceAuthDeleteApi(Resource):
method post (line 216) | def post(self, provider_id: str):
class DatasourceAuthUpdateApi (line 235) | class DatasourceAuthUpdateApi(Resource):
method post (line 241) | def post(self, provider_id: str):
class DatasourceAuthListApi (line 260) | class DatasourceAuthListApi(Resource):
method get (line 264) | def get(self):
class DatasourceHardCodeAuthListApi (line 273) | class DatasourceHardCodeAuthListApi(Resource):
method get (line 277) | def get(self):
class DatasourceAuthOauthCustomClient (line 286) | class DatasourceAuthOauthCustomClient(Resource):
method post (line 292) | def post(self, provider_id: str):
method delete (line 309) | def delete(self, provider_id: str):
class DatasourceAuthDefaultApi (line 322) | class DatasourceAuthDefaultApi(Resource):
method post (line 328) | def post(self, provider_id: str):
class DatasourceUpdateProviderNameApi (line 343) | class DatasourceUpdateProviderNameApi(Resource):
method post (line 349) | def post(self, provider_id: str):
FILE: api/controllers/console/datasets/rag_pipeline/datasource_content_preview.py
class Parser (line 18) | class Parser(BaseModel):
class DataSourceContentPreviewApi (line 28) | class DataSourceContentPreviewApi(Resource):
method post (line 34) | def post(self, pipeline: Pipeline, node_id: str):
FILE: api/controllers/console/datasets/rag_pipeline/rag_pipeline.py
class PipelineTemplateListApi (line 26) | class PipelineTemplateListApi(Resource):
method get (line 31) | def get(self):
class PipelineTemplateDetailApi (line 40) | class PipelineTemplateDetailApi(Resource):
method get (line 45) | def get(self, template_id: str):
class Payload (line 54) | class Payload(BaseModel):
class CustomizedPipelineTemplateApi (line 64) | class CustomizedPipelineTemplateApi(Resource):
method patch (line 69) | def patch(self, template_id: str):
method delete (line 79) | def delete(self, template_id: str):
method post (line 87) | def post(self, template_id: str):
class PublishCustomizedPipelineTemplateApi (line 99) | class PublishCustomizedPipelineTemplateApi(Resource):
method post (line 106) | def post(self, pipeline_id: str):
FILE: api/controllers/console/datasets/rag_pipeline/rag_pipeline_datasets.py
class RagPipelineDatasetImportPayload (line 24) | class RagPipelineDatasetImportPayload(BaseModel):
class CreateRagPipelineDatasetApi (line 32) | class CreateRagPipelineDatasetApi(Resource):
method post (line 38) | def post(self):
class CreateEmptyRagPipelineDatasetApi (line 76) | class CreateEmptyRagPipelineDatasetApi(Resource):
method post (line 81) | def post(self):
FILE: api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py
function _create_pagination_parser (line 40) | def _create_pagination_parser():
class WorkflowDraftVariablePatchPayload (line 50) | class WorkflowDraftVariablePatchPayload(BaseModel):
function _api_prerequisite (line 58) | def _api_prerequisite(f):
class RagPipelineVariableCollectionApi (line 82) | class RagPipelineVariableCollectionApi(Resource):
method get (line 85) | def get(self, pipeline: Pipeline):
method delete (line 113) | def delete(self, pipeline: Pipeline):
function validate_node_id (line 122) | def validate_node_id(node_id: str) -> NoReturn | None:
class RagPipelineNodeVariableCollectionApi (line 141) | class RagPipelineNodeVariableCollectionApi(Resource):
method get (line 144) | def get(self, pipeline: Pipeline, node_id: str):
method delete (line 155) | def delete(self, pipeline: Pipeline, node_id: str):
class RagPipelineVariableApi (line 164) | class RagPipelineVariableApi(Resource):
method get (line 170) | def get(self, pipeline: Pipeline, variable_id: str):
method patch (line 184) | def patch(self, pipeline: Pipeline, variable_id: str):
method delete (line 249) | def delete(self, pipeline: Pipeline, variable_id: str):
class RagPipelineVariableResetApi (line 264) | class RagPipelineVariableResetApi(Resource):
method put (line 266) | def put(self, pipeline: Pipeline, variable_id: str):
function _get_variable_list (line 291) | def _get_variable_list(pipeline: Pipeline, node_id) -> WorkflowDraftVari...
class RagPipelineSystemVariableCollectionApi (line 306) | class RagPipelineSystemVariableCollectionApi(Resource):
method get (line 309) | def get(self, pipeline: Pipeline):
class RagPipelineEnvironmentVariableCollectionApi (line 314) | class RagPipelineEnvironmentVariableCollectionApi(Resource):
method get (line 316) | def get(self, pipeline: Pipeline):
FILE: api/controllers/console/datasets/rag_pipeline/rag_pipeline_import.py
class RagPipelineImportPayload (line 26) | class RagPipelineImportPayload(BaseModel):
class IncludeSecretQuery (line 38) | class IncludeSecretQuery(BaseModel):
class RagPipelineImportApi (line 58) | class RagPipelineImportApi(Resource):
method post (line 65) | def post(self):
class RagPipelineImportConfirmApi (line 94) | class RagPipelineImportConfirmApi(Resource):
method post (line 100) | def post(self, import_id):
class RagPipelineImportCheckDependenciesApi (line 117) | class RagPipelineImportCheckDependenciesApi(Resource):
method get (line 124) | def get(self, pipeline: Pipeline):
class RagPipelineExportApi (line 133) | class RagPipelineExportApi(Resource):
method get (line 139) | def get(self, pipeline: Pipeline):
FILE: api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py
class DraftWorkflowSyncPayload (line 61) | class DraftWorkflowSyncPayload(BaseModel):
class NodeRunPayload (line 70) | class NodeRunPayload(BaseModel):
class NodeRunRequiredPayload (line 74) | class NodeRunRequiredPayload(BaseModel):
class DatasourceNodeRunPayload (line 78) | class DatasourceNodeRunPayload(BaseModel):
class DraftWorkflowRunPayload (line 84) | class DraftWorkflowRunPayload(BaseModel):
class PublishedWorkflowRunPayload (line 91) | class PublishedWorkflowRunPayload(DraftWorkflowRunPayload):
class DefaultBlockConfigQuery (line 97) | class DefaultBlockConfigQuery(BaseModel):
class WorkflowListQuery (line 101) | class WorkflowListQuery(BaseModel):
class WorkflowUpdatePayload (line 108) | class WorkflowUpdatePayload(BaseModel):
class NodeIdQuery (line 113) | class NodeIdQuery(BaseModel):
class WorkflowRunQuery (line 117) | class WorkflowRunQuery(BaseModel):
class DatasourceVariablesPayload (line 122) | class DatasourceVariablesPayload(BaseModel):
class RagPipelineRecommendedPluginQuery (line 129) | class RagPipelineRecommendedPluginQuery(BaseModel):
class DraftRagPipelineApi (line 152) | class DraftRagPipelineApi(Resource):
method get (line 159) | def get(self, pipeline: Pipeline):
method post (line 178) | def post(self, pipeline: Pipeline):
class RagPipelineDraftRunIterationNodeApi (line 230) | class RagPipelineDraftRunIterationNodeApi(Resource):
method post (line 237) | def post(self, pipeline: Pipeline, node_id: str):
class RagPipelineDraftRunLoopNodeApi (line 265) | class RagPipelineDraftRunLoopNodeApi(Resource):
method post (line 272) | def post(self, pipeline: Pipeline, node_id: str):
class DraftRagPipelineRunApi (line 300) | class DraftRagPipelineRunApi(Resource):
method post (line 307) | def post(self, pipeline: Pipeline):
class PublishedRagPipelineRunApi (line 332) | class PublishedRagPipelineRunApi(Resource):
method post (line 339) | def post(self, pipeline: Pipeline):
class RagPipelinePublishedDatasourceNodeRunApi (line 448) | class RagPipelinePublishedDatasourceNodeRunApi(Resource):
method post (line 455) | def post(self, pipeline: Pipeline, node_id: str):
class RagPipelineDraftDatasourceNodeRunApi (line 481) | class RagPipelineDraftDatasourceNodeRunApi(Resource):
method post (line 488) | def post(self, pipeline: Pipeline, node_id: str):
class RagPipelineDraftNodeRunApi (line 514) | class RagPipelineDraftNodeRunApi(Resource):
method post (line 522) | def post(self, pipeline: Pipeline, node_id: str):
class RagPipelineTaskStopApi (line 544) | class RagPipelineTaskStopApi(Resource):
method post (line 550) | def post(self, pipeline: Pipeline, task_id: str):
class PublishedRagPipelineApi (line 563) | class PublishedRagPipelineApi(Resource):
method get (line 570) | def get(self, pipeline: Pipeline):
method post (line 589) | def post(self, pipeline: Pipeline):
class DefaultRagPipelineBlockConfigsApi (line 613) | class DefaultRagPipelineBlockConfigsApi(Resource):
method get (line 619) | def get(self, pipeline: Pipeline):
class DefaultRagPipelineBlockConfigApi (line 629) | class DefaultRagPipelineBlockConfigApi(Resource):
method get (line 635) | def get(self, pipeline: Pipeline, block_type: str):
class PublishedAllRagPipelineApi (line 654) | class PublishedAllRagPipelineApi(Resource):
method get (line 661) | def get(self, pipeline: Pipeline):
class RagPipelineDraftWorkflowRestoreApi (line 698) | class RagPipelineDraftWorkflowRestoreApi(Resource):
method post (line 704) | def post(self, pipeline: Pipeline, workflow_id: str):
class RagPipelineByIdApi (line 728) | class RagPipelineByIdApi(Resource):
method patch (line 735) | def patch(self, pipeline: Pipeline, workflow_id: str):
method delete (line 770) | def delete(self, pipeline: Pipeline, workflow_id: str):
class PublishedRagPipelineSecondStepApi (line 797) | class PublishedRagPipelineSecondStepApi(Resource):
method get (line 803) | def get(self, pipeline: Pipeline):
class PublishedRagPipelineFirstStepApi (line 817) | class PublishedRagPipelineFirstStepApi(Resource):
method get (line 823) | def get(self, pipeline: Pipeline):
class DraftRagPipelineFirstStepApi (line 837) | class DraftRagPipelineFirstStepApi(Resource):
method get (line 843) | def get(self, pipeline: Pipeline):
class DraftRagPipelineSecondStepApi (line 857) | class DraftRagPipelineSecondStepApi(Resource):
method get (line 863) | def get(self, pipeline: Pipeline):
class RagPipelineWorkflowRunListApi (line 878) | class RagPipelineWorkflowRunListApi(Resource):
method get (line 884) | def get(self, pipeline: Pipeline):
class RagPipelineWorkflowRunDetailApi (line 906) | class RagPipelineWorkflowRunDetailApi(Resource):
method get (line 912) | def get(self, pipeline: Pipeline, run_id):
class RagPipelineWorkflowRunNodeExecutionListApi (line 925) | class RagPipelineWorkflowRunNodeExecutionListApi(Resource):
method get (line 931) | def get(self, pipeline: Pipeline, run_id: str):
class DatasourceListApi (line 949) | class DatasourceListApi(Resource):
method get (line 953) | def get(self):
class RagPipelineWorkflowLastRunApi (line 959) | class RagPipelineWorkflowLastRunApi(Resource):
method get (line 965) | def get(self, pipeline: Pipeline, node_id: str):
class RagPipelineTransformApi (line 981) | class RagPipelineTransformApi(Resource):
method post (line 985) | def post(self, dataset_id: str):
class RagPipelineDatasourceVariableApi (line 998) | class RagPipelineDatasourceVariableApi(Resource):
method post (line 1006) | def post(self, pipeline: Pipeline):
class RagPipelineRecommendedPluginApi (line 1023) | class RagPipelineRecommendedPluginApi(Resource):
method get (line 1027) | def get(self):
FILE: api/controllers/console/datasets/website.py
class WebsiteCrawlPayload (line 15) | class WebsiteCrawlPayload(BaseModel):
class WebsiteCrawlStatusQuery (line 21) | class WebsiteCrawlStatusQuery(BaseModel):
class WebsiteCrawlApi (line 29) | class WebsiteCrawlApi(Resource):
method post (line 38) | def post(self):
class WebsiteCrawlStatusApi (line 56) | class WebsiteCrawlStatusApi(Resource):
method get (line 67) | def get(self, job_id: str):
FILE: api/controllers/console/datasets/wraps.py
function get_rag_pipeline (line 16) | def get_rag_pipeline(view_func: Callable[P, R]):
FILE: api/controllers/console/error.py
class AlreadySetupError (line 4) | class AlreadySetupError(BaseHTTPException):
class NotSetupError (line 10) | class NotSetupError(BaseHTTPException):
class NotInitValidateError (line 19) | class NotInitValidateError(BaseHTTPException):
class InitValidateFailedError (line 25) | class InitValidateFailedError(BaseHTTPException):
class AccountNotLinkTenantError (line 31) | class AccountNotLinkTenantError(BaseHTTPException):
class AlreadyActivateError (line 37) | class AlreadyActivateError(BaseHTTPException):
class NotAllowedCreateWorkspace (line 43) | class NotAllowedCreateWorkspace(BaseHTTPException):
class WorkspaceMembersLimitExceeded (line 49) | class WorkspaceMembersLimitExceeded(BaseHTTPException):
class WorkspacesLimitExceeded (line 55) | class WorkspacesLimitExceeded(BaseHTTPException):
class AccountBannedError (line 61) | class AccountBannedError(BaseHTTPException):
class AccountNotFound (line 67) | class AccountNotFound(BaseHTTPException):
class EmailSendIpLimitError (line 73) | class EmailSendIpLimitError(BaseHTTPException):
class UnauthorizedAndForceLogout (line 79) | class UnauthorizedAndForceLogout(BaseHTTPException):
class AccountInFreezeError (line 85) | class AccountInFreezeError(BaseHTTPException):
class EducationVerifyLimitError (line 94) | class EducationVerifyLimitError(BaseHTTPException):
class EducationActivateLimitError (line 100) | class EducationActivateLimitError(BaseHTTPException):
class ComplianceRateLimitError (line 106) | class ComplianceRateLimitError(BaseHTTPException):
FILE: api/controllers/console/explore/audio.py
class TextToAudioPayload (line 36) | class TextToAudioPayload(BaseModel):
class ChatAudioApi (line 50) | class ChatAudioApi(InstalledAppResource):
method post (line 51) | def post(self, installed_app):
class ChatTextApi (line 90) | class ChatTextApi(InstalledAppResource):
method post (line 92) | def post(self, installed_app):
FILE: api/controllers/console/explore/banner.py
class BannerApi (line 12) | class BannerApi(Resource):
method get (line 16) | def get(self):
FILE: api/controllers/console/explore/completion.py
class CompletionMessageExplorePayload (line 43) | class CompletionMessageExplorePayload(BaseModel):
class ChatMessagePayload (line 51) | class ChatMessagePayload(BaseModel):
method normalize_uuid (line 61) | def normalize_uuid(cls, value: str | UUID | None) -> str | None:
class CompletionApi (line 82) | class CompletionApi(InstalledAppResource):
method post (line 84) | def post(self, installed_app):
class CompletionStopApi (line 132) | class CompletionStopApi(InstalledAppResource):
method post (line 133) | def post(self, installed_app, task_id):
class ChatApi (line 155) | class ChatApi(InstalledAppResource):
method post (line 157) | def post(self, installed_app):
class ChatStopApi (line 207) | class ChatStopApi(InstalledAppResource):
method post (line 208) | def post(self, installed_app, task_id):
FILE: api/controllers/console/explore/conversation.py
class ConversationListQuery (line 29) | class ConversationListQuery(BaseModel):
class ConversationRenamePayload (line 35) | class ConversationRenamePayload(BaseModel):
method validate_name_requirement (line 40) | def validate_name_requirement(self):
class ConversationListApi (line 54) | class ConversationListApi(InstalledAppResource):
method get (line 56) | def get(self, installed_app):
class ConversationApi (line 102) | class ConversationApi(InstalledAppResource):
method delete (line 103) | def delete(self, installed_app, c_id):
class ConversationRenameApi (line 124) | class ConversationRenameApi(InstalledAppResource):
method post (line 126) | def post(self, installed_app, c_id):
class ConversationPinApi (line 155) | class ConversationPinApi(InstalledAppResource):
method patch (line 156) | def patch(self, installed_app, c_id):
class ConversationUnPinApi (line 178) | class ConversationUnPinApi(InstalledAppResource):
method patch (line 179) | def patch(self, installed_app, c_id):
FILE: api/controllers/console/explore/error.py
class NotCompletionAppError (line 4) | class NotCompletionAppError(BaseHTTPException):
class NotChatAppError (line 10) | class NotChatAppError(BaseHTTPException):
class NotWorkflowAppError (line 16) | class NotWorkflowAppError(BaseHTTPException):
class AppSuggestedQuestionsAfterAnswerDisabledError (line 22) | class AppSuggestedQuestionsAfterAnswerDisabledError(BaseHTTPException):
class AppAccessDeniedError (line 28) | class AppAccessDeniedError(BaseHTTPException):
class TrialAppNotAllowed (line 34) | class TrialAppNotAllowed(BaseHTTPException):
class TrialAppLimitExceeded (line 45) | class TrialAppLimitExceeded(BaseHTTPException):
FILE: api/controllers/console/explore/installed_app.py
class InstalledAppCreatePayload (line 24) | class InstalledAppCreatePayload(BaseModel):
class InstalledAppUpdatePayload (line 28) | class InstalledAppUpdatePayload(BaseModel):
class InstalledAppsListQuery (line 32) | class InstalledAppsListQuery(BaseModel):
class InstalledAppsListApi (line 51) | class InstalledAppsListApi(Resource):
method get (line 55) | def get(self):
method post (line 133) | def post(self):
class InstalledAppApi (line 176) | class InstalledAppApi(InstalledAppResource):
method delete (line 182) | def delete(self, installed_app):
method patch (line 192) | def patch(self, installed_app):
FILE: api/controllers/console/explore/message.py
class MessageListQuery (line 47) | class MessageListQuery(BaseModel):
class MessageFeedbackPayload (line 53) | class MessageFeedbackPayload(BaseModel):
class MoreLikeThisQuery (line 58) | class MoreLikeThisQuery(BaseModel):
class MessageListApi (line 69) | class MessageListApi(InstalledAppResource):
method get (line 71) | def get(self, installed_app):
class MessageFeedbackApi (line 105) | class MessageFeedbackApi(InstalledAppResource):
method post (line 107) | def post(self, installed_app, message_id):
class MessageMoreLikeThisApi (line 133) | class MessageMoreLikeThisApi(InstalledAppResource):
method get (line 135) | def get(self, installed_app, message_id):
class MessageSuggestedQuestionApi (line 179) | class MessageSuggestedQuestionApi(InstalledAppResource):
method get (line 180) | def get(self, installed_app, message_id):
FILE: api/controllers/console/explore/parameter.py
class AppParameterApi (line 13) | class AppParameterApi(InstalledAppResource):
method get (line 16) | def get(self, installed_app: InstalledApp):
class ExploreAppMetaApi (line 44) | class ExploreAppMetaApi(InstalledAppResource):
method get (line 45) | def get(self, installed_app: InstalledApp):
FILE: api/controllers/console/explore/recommended_app.py
class RecommendedAppsQuery (line 48) | class RecommendedAppsQuery(BaseModel):
class RecommendedAppListApi (line 59) | class RecommendedAppListApi(Resource):
method get (line 64) | def get(self):
class RecommendedAppApi (line 79) | class RecommendedAppApi(Resource):
method get (line 82) | def get(self, app_id):
FILE: api/controllers/console/explore/saved_message.py
class SavedMessageListQuery (line 17) | class SavedMessageListQuery(BaseModel):
class SavedMessageCreatePayload (line 22) | class SavedMessageCreatePayload(BaseModel):
class SavedMessageListApi (line 30) | class SavedMessageListApi(InstalledAppResource):
method get (line 32) | def get(self, installed_app):
method post (line 55) | def post(self, installed_app):
class SavedMessageApi (line 74) | class SavedMessageApi(InstalledAppResource):
method delete (line 75) | def delete(self, installed_app, message_id):
FILE: api/controllers/console/explore/trial.py
class WorkflowRunRequest (line 127) | class WorkflowRunRequest(BaseModel):
class ChatRequest (line 132) | class ChatRequest(BaseModel):
class TextToSpeechRequest (line 141) | class TextToSpeechRequest(BaseModel):
class CompletionRequest (line 148) | class CompletionRequest(BaseModel):
class TrialAppWorkflowRunApi (line 171) | class TrialAppWorkflowRunApi(TrialAppResource):
method post (line 173) | def post(self, trial_app):
class TrialAppWorkflowTaskStopApi (line 212) | class TrialAppWorkflowTaskStopApi(TrialAppResource):
method post (line 213) | def post(self, trial_app, task_id: str):
class TrialChatApi (line 235) | class TrialChatApi(TrialAppResource):
method post (line 238) | def post(self, trial_app):
class TrialMessageSuggestedQuestionApi (line 292) | class TrialMessageSuggestedQuestionApi(TrialAppResource):
method get (line 294) | def get(self, trial_app, message_id):
class TrialChatAudioApi (line 329) | class TrialChatAudioApi(TrialAppResource):
method post (line 331) | def post(self, trial_app):
class TrialChatTextApi (line 373) | class TrialChatTextApi(TrialAppResource):
method post (line 376) | def post(self, trial_app):
class TrialCompletionApi (line 420) | class TrialCompletionApi(TrialAppResource):
method post (line 423) | def post(self, trial_app):
class TrialSitApi (line 470) | class TrialSitApi(Resource):
method get (line 475) | def get(self, app_model):
class TrialAppParameterApi (line 492) | class TrialAppParameterApi(Resource):
method get (line 497) | def get(self, app_model):
class AppApi (line 523) | class AppApi(Resource):
method get (line 527) | def get(self, app_model):
class AppWorkflowApi (line 536) | class AppWorkflowApi(Resource):
method get (line 540) | def get(self, app_model):
class DatasetListApi (line 549) | class DatasetListApi(Resource):
method get (line 552) | def get(self, app_model):
FILE: api/controllers/console/explore/workflow.py
class WorkflowRunPayload (line 38) | class WorkflowRunPayload(BaseModel):
class InstalledAppWorkflowRunApi (line 47) | class InstalledAppWorkflowRunApi(InstalledAppResource):
method post (line 49) | def post(self, installed_app: InstalledApp):
class InstalledAppWorkflowTaskStopApi (line 87) | class InstalledAppWorkflowTaskStopApi(InstalledAppResource):
method post (line 88) | def post(self, installed_app: InstalledApp, task_id: str):
FILE: api/controllers/console/explore/wraps.py
function installed_app_required (line 23) | def installed_app_required(view: Callable[Concatenate[InstalledApp, P], ...
function user_allowed_to_access_app (line 52) | def user_allowed_to_access_app(view: Callable[Concatenate[InstalledApp, ...
function trial_app_required (line 76) | def trial_app_required(view: Callable[Concatenate[App, P], R] | None = N...
function trial_feature_enable (line 109) | def trial_feature_enable(view: Callable[P, R]):
function explore_banner_enabled (line 120) | def explore_banner_enabled(view: Callable[P, R]):
class InstalledAppResource (line 131) | class InstalledAppResource(Resource):
class TrialAppResource (line 142) | class TrialAppResource(Resource):
FILE: api/controllers/console/extension.py
class CodeBasedExtensionQuery (line 17) | class CodeBasedExtensionQuery(BaseModel):
class APIBasedExtensionPayload (line 21) | class APIBasedExtensionPayload(BaseModel):
class CodeBasedExtensionAPI (line 36) | class CodeBasedExtensionAPI(Resource):
method get (line 51) | def get(self):
class APIBasedExtensionAPI (line 58) | class APIBasedExtensionAPI(Resource):
method get (line 66) | def get(self):
method post (line 78) | def post(self):
class APIBasedExtensionDetailAPI (line 93) | class APIBasedExtensionDetailAPI(Resource):
method get (line 102) | def get(self, id):
method post (line 117) | def post(self, id):
method delete (line 140) | def delete(self, id):
FILE: api/controllers/console/feature.py
class FeatureApi (line 12) | class FeatureApi(Resource):
method get (line 24) | def get(self):
class SystemFeatureApi (line 32) | class SystemFeatureApi(Resource):
method get (line 42) | def get(self):
FILE: api/controllers/console/files.py
class FileApi (line 37) | class FileApi(Resource):
method get (line 42) | def get(self):
method post (line 62) | def post(self):
class FilePreviewApi (line 102) | class FilePreviewApi(Resource):
method get (line 106) | def get(self, file_id):
class FileSupportTypeApi (line 113) | class FileSupportTypeApi(Resource):
method get (line 117) | def get(self):
FILE: api/controllers/console/human_input_form.py
function _jsonify_form_definition (line 36) | def _jsonify_form_definition(form: Form) -> Response:
class ConsoleHumanInputFormApi (line 43) | class ConsoleHumanInputFormApi(Resource):
method _ensure_console_access (line 47) | def _ensure_console_access(form: Form):
method get (line 56) | def get(self, form_token: str):
method post (line 73) | def post(self, form_token: str):
class ConsoleWorkflowEventsApi (line 119) | class ConsoleWorkflowEventsApi(Resource):
method get (line 124) | def get(self, workflow_run_id: str):
function _retrieve_app_for_workflow_run (line 207) | def _retrieve_app_for_workflow_run(session: Session, workflow_run: Workf...
FILE: api/controllers/console/init_validate.py
class InitValidatePayload (line 19) | class InitValidatePayload(BaseModel):
class InitStatusResponse (line 23) | class InitStatusResponse(BaseModel):
class InitValidateResponse (line 27) | class InitValidateResponse(BaseModel):
function get_init_status (line 36) | def get_init_status() -> InitStatusResponse:
function validate_init_password (line 51) | def validate_init_password(payload: InitValidatePayload) -> InitValidate...
function get_init_validate_status (line 65) | def get_init_validate_status() -> bool:
FILE: api/controllers/console/notification.py
function _pick_lang_content (line 14) | def _pick_lang_content(contents: dict, lang: str) -> dict:
class DismissNotificationPayload (line 19) | class DismissNotificationPayload(BaseModel):
class NotificationApi (line 24) | class NotificationApi(Resource):
method get (line 42) | def get(self):
class NotificationDismissApi (line 73) | class NotificationDismissApi(Resource):
method post (line 83) | def post(self):
FILE: api/controllers/console/ping.py
class PingResponse (line 6) | class PingResponse(BaseModel):
function ping (line 15) | def ping() -> PingResponse:
FILE: api/controllers/console/remote_files.py
class RemoteFileUploadPayload (line 23) | class RemoteFileUploadPayload(BaseModel):
class GetRemoteFileInfo (line 28) | class GetRemoteFileInfo(Resource):
method get (line 30) | def get(self, url: str):
class RemoteFileUpload (line 43) | class RemoteFileUpload(Resource):
method post (line 45) | def post(self):
FILE: api/controllers/console/setup.py
class SetupRequestPayload (line 19) | class SetupRequestPayload(BaseModel):
method validate_password (line 27) | def validate_password(cls, value: str) -> str:
class SetupStatusResponse (line 31) | class SetupStatusResponse(BaseModel):
class SetupResponse (line 36) | class SetupResponse(BaseModel):
function get_setup_status_api (line 45) | def get_setup_status_api() -> SetupStatusResponse:
function setup_system (line 72) | def setup_system(payload: SetupRequestPayload) -> SetupResponse:
function get_setup_status (line 102) | def get_setup_status() -> DifySetup | bool | None:
FILE: api/controllers/console/spec.py
class SpecSchemaDefinitionsApi (line 18) | class SpecSchemaDefinitionsApi(Resource):
method get (line 22) | def get(self):
FILE: api/controllers/console/tag/tags.py
function build_dataset_tag_fields (line 22) | def build_dataset_tag_fields(api_or_ns: Namespace):
class TagBasePayload (line 26) | class TagBasePayload(BaseModel):
class TagBindingPayload (line 31) | class TagBindingPayload(BaseModel):
class TagBindingRemovePayload (line 37) | class TagBindingRemovePayload(BaseModel):
class TagListQueryParam (line 43) | class TagListQueryParam(BaseModel):
class TagListApi (line 58) | class TagListApi(Resource):
method get (line 66) | def get(self):
method post (line 78) | def post(self):
class TagUpdateDeleteApi (line 93) | class TagUpdateDeleteApi(Resource):
method patch (line 98) | def patch(self, tag_id):
method delete (line 118) | def delete(self, tag_id):
class TagBindingCreateApi (line 127) | class TagBindingCreateApi(Resource):
method post (line 132) | def post(self):
class TagBindingDeleteApi (line 145) | class TagBindingDeleteApi(Resource):
method post (line 150) | def post(self):
FILE: api/controllers/console/version.py
class VersionQuery (line 13) | class VersionQuery(BaseModel):
class VersionFeatures (line 17) | class VersionFeatures(BaseModel):
class VersionResponse (line 22) | class VersionResponse(BaseModel):
function check_version_update (line 35) | def check_version_update(query: VersionQuery) -> VersionResponse:
function _has_new_version (line 73) | def _has_new_version(*, latest_version: str, current_version: str) -> bool:
FILE: api/controllers/console/workspace/__init__.py
function plugin_permission_required (line 16) | def plugin_permission_required(
FILE: api/controllers/console/workspace/account.py
class AccountInitPayload (line 54) | class AccountInitPayload(BaseModel):
method validate_language (line 61) | def validate_language(cls, value: str) -> str:
method validate_timezone (line 66) | def validate_timezone(cls, value: str) -> str:
class AccountNamePayload (line 70) | class AccountNamePayload(BaseModel):
class AccountAvatarPayload (line 74) | class AccountAvatarPayload(BaseModel):
class AccountInterfaceLanguagePayload (line 78) | class AccountInterfaceLanguagePayload(BaseModel):
method validate_language (line 83) | def validate_language(cls, value: str) -> str:
class AccountInterfaceThemePayload (line 87) | class AccountInterfaceThemePayload(BaseModel):
class AccountTimezonePayload (line 91) | class AccountTimezonePayload(BaseModel):
method validate_timezone (line 96) | def validate_timezone(cls, value: str) -> str:
class AccountPasswordPayload (line 100) | class AccountPasswordPayload(BaseModel):
method check_passwords_match (line 106) | def check_passwords_match(self) -> AccountPasswordPayload:
class AccountDeletePayload (line 112) | class AccountDeletePayload(BaseModel):
class AccountDeletionFeedbackPayload (line 117) | class AccountDeletionFeedbackPayload(BaseModel):
class EducationActivatePayload (line 122) | class EducationActivatePayload(BaseModel):
class EducationAutocompleteQuery (line 128) | class EducationAutocompleteQuery(BaseModel):
class ChangeEmailSendPayload (line 134) | class ChangeEmailSendPayload(BaseModel):
class ChangeEmailValidityPayload (line 141) | class ChangeEmailValidityPayload(BaseModel):
class ChangeEmailResetPayload (line 147) | class ChangeEmailResetPayload(BaseModel):
class CheckEmailUniquePayload (line 152) | class CheckEmailUniquePayload(BaseModel):
function reg (line 156) | def reg(cls: type[BaseModel]):
function _serialize_account (line 178) | def _serialize_account(account) -> dict:
class AccountInitApi (line 197) | class AccountInitApi(Resource):
method post (line 201) | def post(self):
class AccountProfileApi (line 243) | class AccountProfileApi(Resource):
method get (line 249) | def get(self):
class AccountNameApi (line 255) | class AccountNameApi(Resource):
method post (line 261) | def post(self):
class AccountAvatarApi (line 271) | class AccountAvatarApi(Resource):
method post (line 277) | def post(self):
class AccountInterfaceLanguageApi (line 288) | class AccountInterfaceLanguageApi(Resource):
method post (line 294) | def post(self):
class AccountInterfaceThemeApi (line 305) | class AccountInterfaceThemeApi(Resource):
method post (line 311) | def post(self):
class AccountTimezoneApi (line 322) | class AccountTimezoneApi(Resource):
method post (line 328) | def post(self):
class AccountPasswordApi (line 339) | class AccountPasswordApi(Resource):
method post (line 345) | def post(self):
class AccountIntegrateApi (line 359) | class AccountIntegrateApi(Resource):
method get (line 364) | def get(self):
class AccountDeleteVerifyApi (line 403) | class AccountDeleteVerifyApi(Resource):
method get (line 407) | def get(self):
class AccountDeleteApi (line 417) | class AccountDeleteApi(Resource):
method post (line 422) | def post(self):
class AccountDeleteUpdateFeedbackApi (line 437) | class AccountDeleteUpdateFeedbackApi(Resource):
method post (line 440) | def post(self):
class EducationVerifyApi (line 450) | class EducationVerifyApi(Resource):
method get (line 461) | def get(self):
class EducationApi (line 468) | class EducationApi(Resource):
method post (line 482) | def post(self):
method get (line 496) | def get(self):
class EducationAutoCompleteApi (line 507) | class EducationAutoCompleteApi(Resource):
method get (line 521) | def get(self):
class ChangeEmailSendEmailApi (line 529) | class ChangeEmailSendEmailApi(Resource):
method post (line 535) | def post(self):
class ChangeEmailCheckApi (line 583) | class ChangeEmailCheckApi(Resource):
method post (line 589) | def post(self):
class ChangeEmailResetApi (line 625) | class ChangeEmailResetApi(Resource):
method post (line 632) | def post(self):
class CheckEmailUnique (line 664) | class CheckEmailUnique(Resource):
method post (line 667) | def post(self):
FILE: api/controllers/console/workspace/agent_providers.py
class AgentProviderListApi (line 11) | class AgentProviderListApi(Resource):
method get (line 22) | def get(self):
class AgentProviderApi (line 33) | class AgentProviderApi(Resource):
method get (line 45) | def get(self, provider_name: str):
FILE: api/controllers/console/workspace/endpoint.py
class EndpointCreatePayload (line 18) | class EndpointCreatePayload(BaseModel):
class EndpointIdPayload (line 24) | class EndpointIdPayload(BaseModel):
class EndpointUpdatePayload (line 28) | class EndpointUpdatePayload(EndpointIdPayload):
class EndpointListQuery (line 33) | class EndpointListQuery(BaseModel):
class EndpointListForPluginQuery (line 38) | class EndpointListForPluginQuery(EndpointListQuery):
class EndpointCreateResponse (line 42) | class EndpointCreateResponse(BaseModel):
class EndpointListResponse (line 46) | class EndpointListResponse(BaseModel):
class PluginEndpointListResponse (line 50) | class PluginEndpointListResponse(BaseModel):
class EndpointDeleteResponse (line 54) | class EndpointDeleteResponse(BaseModel):
class EndpointUpdateResponse (line 58) | class EndpointUpdateResponse(BaseModel):
class EndpointEnableResponse (line 62) | class EndpointEnableResponse(BaseModel):
class EndpointDisableResponse (line 66) | class EndpointDisableResponse(BaseModel):
function reg (line 70) | def reg(cls: type[BaseModel]):
class EndpointCreateApi (line 92) | class EndpointCreateApi(Resource):
method post (line 106) | def post(self):
class EndpointListApi (line 126) | class EndpointListApi(Resource):
method get (line 138) | def get(self):
class EndpointListForSinglePluginApi (line 159) | class EndpointListForSinglePluginApi(Resource):
method get (line 171) | def get(self):
class EndpointDeleteApi (line 194) | class EndpointDeleteApi(Resource):
method post (line 208) | def post(self):
class EndpointUpdateApi (line 221) | class EndpointUpdateApi(Resource):
method post (line 235) | def post(self):
class EndpointEnableApi (line 252) | class EndpointEnableApi(Resource):
method post (line 266) | def post(self):
class EndpointDisableApi (line 279) | class EndpointDisableApi(Resource):
method post (line 293) | def post(self):
FILE: api/controllers/console/workspace/error.py
class RepeatPasswordNotMatchError (line 4) | class RepeatPasswordNotMatchError(BaseHTTPException):
class CurrentPasswordIncorrectError (line 10) | class CurrentPasswordIncorrectError(BaseHTTPException):
class InvalidInvitationCodeError (line 16) | class InvalidInvitationCodeError(BaseHTTPException):
class AccountAlreadyInitedError (line 22) | class AccountAlreadyInitedError(BaseHTTPException):
class AccountNotInitializedError (line 28) | class AccountNotInitializedError(BaseHTTPException):
class InvalidAccountDeletionCodeError (line 34) | class InvalidAccountDeletionCodeError(BaseHTTPException):
FILE: api/controllers/console/workspace/load_balancing_config.py
class LoadBalancingCredentialPayload (line 15) | class LoadBalancingCredentialPayload(BaseModel):
class LoadBalancingCredentialsValidateApi (line 27) | class LoadBalancingCredentialsValidateApi(Resource):
method post (line 32) | def post(self, provider: str):
class LoadBalancingConfigCredentialsValidateApi (line 70) | class LoadBalancingConfigCredentialsValidateApi(Resource):
method post (line 75) | def post(self, provider: str, config_id: str):
FILE: api/controllers/console/workspace/members.py
class MemberInvitePayload (line 39) | class MemberInvitePayload(BaseModel):
class MemberRoleUpdatePayload (line 45) | class MemberRoleUpdatePayload(BaseModel):
class OwnerTransferEmailPayload (line 49) | class OwnerTransferEmailPayload(BaseModel):
class OwnerTransferCheckPayload (line 53) | class OwnerTransferCheckPayload(BaseModel):
class OwnerTransferPayload (line 58) | class OwnerTransferPayload(BaseModel):
function reg (line 62) | def reg(cls: type[BaseModel]):
class MemberListApi (line 76) | class MemberListApi(Resource):
method get (line 83) | def get(self):
class MemberInviteEmailApi (line 94) | class MemberInviteEmailApi(Resource):
method post (line 102) | def post(self):
class MemberCancelInviteApi (line 164) | class MemberCancelInviteApi(Resource):
method delete (line 170) | def delete(self, member_id):
class MemberUpdateRoleApi (line 196) | class MemberUpdateRoleApi(Resource):
method put (line 203) | def put(self, member_id):
class DatasetOperatorMemberListApi (line 229) | class DatasetOperatorMemberListApi(Resource):
method get (line 236) | def get(self):
class SendOwnerTransferEmailApi (line 247) | class SendOwnerTransferEmailApi(Resource):
method post (line 255) | def post(self):
class OwnerTransferCheckApi (line 286) | class OwnerTransferCheckApi(Resource):
method post (line 292) | def post(self):
class OwnerTransfer (line 330) | class OwnerTransfer(Resource):
method post (line 336) | def post(self, member_id):
FILE: api/controllers/console/workspace/model_providers.py
class ParserModelList (line 21) | class ParserModelList(BaseModel):
class ParserCredentialId (line 25) | class ParserCredentialId(BaseModel):
method validate_optional_credential_id (line 30) | def validate_optional_credential_id(cls, value: str | None) -> str | N...
class ParserCredentialCreate (line 36) | class ParserCredentialCreate(BaseModel):
class ParserCredentialUpdate (line 41) | class ParserCredentialUpdate(BaseModel):
method validate_update_credential_id (line 48) | def validate_update_credential_id(cls, value: str) -> str:
class ParserCredentialDelete (line 52) | class ParserCredentialDelete(BaseModel):
method validate_delete_credential_id (line 57) | def validate_delete_credential_id(cls, value: str) -> str:
class ParserCredentialSwitch (line 61) | class ParserCredentialSwitch(BaseModel):
method validate_switch_credential_id (line 66) | def validate_switch_credential_id(cls, value: str) -> str:
class ParserCredentialValidate (line 70) | class ParserCredentialValidate(BaseModel):
class ParserPreferredProviderType (line 74) | class ParserPreferredProviderType(BaseModel):
function reg (line 78) | def reg(cls: type[BaseModel]):
class ModelProviderListApi (line 93) | class ModelProviderListApi(Resource):
method get (line 98) | def get(self):
class ModelProviderCredentialApi (line 112) | class ModelProviderCredentialApi(Resource):
method get (line 117) | def get(self, provider: str):
method post (line 136) | def post(self, provider: str):
method put (line 160) | def put(self, provider: str):
method delete (line 186) | def delete(self, provider: str):
class ModelProviderCredentialSwitchApi (line 200) | class ModelProviderCredentialSwitchApi(Resource):
method post (line 206) | def post(self, provider: str):
class ModelProviderValidateApi (line 221) | class ModelProviderValidateApi(Resource):
method post (line 226) | def post(self, provider: str):
class ModelProviderIconApi (line 255) | class ModelProviderIconApi(Resource):
method get (line 260) | def get(self, tenant_id: str, provider: str, icon_type: str, lang: str):
class PreferredProviderTypeUpdateApi (line 274) | class PreferredProviderTypeUpdateApi(Resource):
method post (line 280) | def post(self, provider: str):
class ModelProviderPaymentCheckoutUrlApi (line 297) | class ModelProviderPaymentCheckoutUrlApi(Resource):
method get (line 301) | def get(self, provider: str):
FILE: api/controllers/console/workspace/models.py
class ParserGetDefault (line 23) | class ParserGetDefault(BaseModel):
class Inner (line 27) | class Inner(BaseModel):
class ParserPostDefault (line 33) | class ParserPostDefault(BaseModel):
class ParserDeleteModels (line 37) | class ParserDeleteModels(BaseModel):
class LoadBalancingPayload (line 42) | class LoadBalancingPayload(BaseModel):
class ParserPostModels (line 47) | class ParserPostModels(BaseModel):
method validate_credential_id (line 56) | def validate_credential_id(cls, value: str | None) -> str | None:
class ParserGetCredentials (line 62) | class ParserGetCredentials(BaseModel):
method validate_get_credential_id (line 70) | def validate_get_credential_id(cls, value: str | None) -> str | None:
class ParserCredentialBase (line 76) | class ParserCredentialBase(BaseModel):
class ParserCreateCredential (line 81) | class ParserCreateCredential(ParserCredentialBase):
class ParserUpdateCredential (line 86) | class ParserUpdateCredential(ParserCredentialBase):
method validate_update_credential_id (line 93) | def validate_update_credential_id(cls, value: str) -> str:
class ParserDeleteCredential (line 97) | class ParserDeleteCredential(ParserCredentialBase):
method validate_delete_credential_id (line 102) | def validate_delete_credential_id(cls, value: str) -> str:
class ParserParameter (line 106) | class ParserParameter(BaseModel):
class DefaultModelApi (line 128) | class DefaultModelApi(Resource):
method get (line 133) | def get(self):
method post (line 150) | def post(self):
class ModelProviderModelApi (line 179) | class ModelProviderModelApi(Resource):
method get (line 183) | def get(self, provider):
method post (line 196) | def post(self, provider: str):
method delete (line 242) | def delete(self, provider: str):
class ModelProviderModelCredentialApi (line 256) | class ModelProviderModelCredentialApi(Resource):
method get (line 261) | def get(self, provider: str):
method post (line 316) | def post(self, provider: str):
method put (line 348) | def put(self, provider: str):
method delete (line 374) | def delete(self, provider: str):
class ParserSwitch (line 390) | class ParserSwitch(BaseModel):
class ModelProviderModelCredentialSwitchApi (line 402) | class ModelProviderModelCredentialSwitchApi(Resource):
method post (line 408) | def post(self, provider: str):
class ModelProviderModelEnableApi (line 426) | class ModelProviderModelEnableApi(Resource):
method patch (line 431) | def patch(self, provider: str):
class ModelProviderModelDisableApi (line 447) | class ModelProviderModelDisableApi(Resource):
method patch (line 452) | def patch(self, provider: str):
class ParserValidate (line 465) | class ParserValidate(BaseModel):
class ModelProviderModelValidateApi (line 477) | class ModelProviderModelValidateApi(Resource):
method post (line 482) | def post(self, provider: str):
class ModelProviderModelParameterRuleApi (line 512) | class ModelProviderModelParameterRuleApi(Resource):
method get (line 517) | def get(self, provider: str):
class ModelProviderAvailableModelApi (line 530) | class ModelProviderAvailableModelApi(Resource):
method get (line 534) | def get(self, model_type):
FILE: api/controllers/console/workspace/plugin.py
class ParserList (line 26) | class ParserList(BaseModel):
class ParserLatest (line 31) | class ParserLatest(BaseModel):
class ParserIcon (line 35) | class ParserIcon(BaseModel):
class ParserAsset (line 40) | class ParserAsset(BaseModel):
class ParserGithubUpload (line 45) | class ParserGithubUpload(BaseModel):
class ParserPluginIdentifiers (line 51) | class ParserPluginIdentifiers(BaseModel):
class ParserGithubInstall (line 55) | class ParserGithubInstall(BaseModel):
class ParserPluginIdentifierQuery (line 62) | class ParserPluginIdentifierQuery(BaseModel):
class ParserTasks (line 66) | class ParserTasks(BaseModel):
class ParserMarketplaceUpgrade (line 71) | class ParserMarketplaceUpgrade(BaseModel):
class ParserGithubUpgrade (line 76) | class ParserGithubUpgrade(BaseModel):
class ParserUninstall (line 84) | class ParserUninstall(BaseModel):
class ParserPermissionChange (line 88) | class ParserPermissionChange(BaseModel):
class ParserDynamicOptions (line 93) | class ParserDynamicOptions(BaseModel):
class ParserDynamicOptionsWithCredentials (line 102) | class ParserDynamicOptionsWithCredentials(BaseModel):
class PluginPermissionSettingsPayload (line 111) | class PluginPermissionSettingsPayload(BaseModel):
class PluginAutoUpgradeSettingsPayload (line 116) | class PluginAutoUpgradeSettingsPayload(BaseModel):
class ParserPreferencesChange (line 126) | class ParserPreferencesChange(BaseModel):
class ParserExcludePlugin (line 131) | class ParserExcludePlugin(BaseModel):
class ParserReadme (line 135) | class ParserReadme(BaseModel):
function _read_upload_content (line 173) | def _read_upload_content(file: FileStorage, max_size: int) -> bytes:
class PluginDebuggingKeyApi (line 188) | class PluginDebuggingKeyApi(Resource):
method get (line 193) | def get(self):
class PluginListApi (line 207) | class PluginListApi(Resource):
method get (line 212) | def get(self):
class PluginListLatestVersionsApi (line 224) | class PluginListLatestVersionsApi(Resource):
method post (line 229) | def post(self):
class PluginListInstallationsFromIdsApi (line 241) | class PluginListInstallationsFromIdsApi(Resource):
method post (line 246) | def post(self):
class PluginIconApi (line 260) | class PluginIconApi(Resource):
method get (line 263) | def get(self):
class PluginAssetApi (line 276) | class PluginAssetApi(Resource):
method get (line 281) | def get(self):
class PluginUploadFromPkgApi (line 293) | class PluginUploadFromPkgApi(Resource):
method post (line 298) | def post(self):
class PluginUploadFromGithubApi (line 312) | class PluginUploadFromGithubApi(Resource):
method post (line 318) | def post(self):
class PluginUploadFromBundleApi (line 332) | class PluginUploadFromBundleApi(Resource):
method post (line 337) | def post(self):
class PluginInstallFromPkgApi (line 351) | class PluginInstallFromPkgApi(Resource):
method post (line 357) | def post(self):
class PluginInstallFromGithubApi (line 370) | class PluginInstallFromGithubApi(Resource):
method post (line 376) | def post(self):
class PluginInstallFromMarketplaceApi (line 396) | class PluginInstallFromMarketplaceApi(Resource):
method post (line 402) | def post(self):
class PluginFetchMarketplacePkgApi (line 416) | class PluginFetchMarketplacePkgApi(Resource):
method get (line 422) | def get(self):
class PluginFetchManifestApi (line 440) | class PluginFetchManifestApi(Resource):
method get (line 446) | def get(self):
class PluginFetchInstallTasksApi (line 460) | class PluginFetchInstallTasksApi(Resource):
method get (line 466) | def get(self):
class PluginFetchInstallTaskApi (line 478) | class PluginFetchInstallTaskApi(Resource):
method get (line 483) | def get(self, task_id: str):
class PluginDeleteInstallTaskApi (line 493) | class PluginDeleteInstallTaskApi(Resource):
method post (line 498) | def post(self, task_id: str):
class PluginDeleteAllInstallTaskItemsApi (line 508) | class PluginDeleteAllInstallTaskItemsApi(Resource):
method post (line 513) | def post(self):
class PluginDeleteInstallTaskItemApi (line 523) | class PluginDeleteInstallTaskItemApi(Resource):
method post (line 528) | def post(self, task_id: str, identifier: str):
class PluginUpgradeFromMarketplaceApi (line 538) | class PluginUpgradeFromMarketplaceApi(Resource):
method post (line 544) | def post(self):
class PluginUpgradeFromGithubApi (line 560) | class PluginUpgradeFromGithubApi(Resource):
method post (line 566) | def post(self):
class PluginUninstallApi (line 587) | class PluginUninstallApi(Resource):
method post (line 593) | def post(self):
class PluginChangePermissionApi (line 605) | class PluginChangePermissionApi(Resource):
method post (line 610) | def post(self):
class PluginFetchPermissionApi (line 628) | class PluginFetchPermissionApi(Resource):
method get (line 632) | def get(self):
class PluginFetchDynamicSelectOptionsApi (line 653) | class PluginFetchDynamicSelectOptionsApi(Resource):
method get (line 659) | def get(self):
class PluginFetchDynamicSelectOptionsWithCredentialsApi (line 683) | class PluginFetchDynamicSelectOptionsWithCredentialsApi(Resource):
method post (line 689) | def post(self):
class PluginChangePreferencesApi (line 714) | class PluginChangePreferencesApi(Resource):
method post (line 719) | def post(self):
class PluginFetchPreferencesApi (line 764) | class PluginFetchPreferencesApi(Resource):
method get (line 768) | def get(self):
class PluginAutoUpgradeExcludePluginApi (line 803) | class PluginAutoUpgradeExcludePluginApi(Resource):
method post (line 808) | def post(self):
class PluginReadmeApi (line 818) | class PluginReadmeApi(Resource):
method get (line 823) | def get(self):
FILE: api/controllers/console/workspace/tool_providers.py
function is_valid_url (line 48) | def is_valid_url(url: str) -> bool:
class ToolProviderListQuery (line 59) | class ToolProviderListQuery(BaseModel):
class BuiltinToolCredentialDeletePayload (line 63) | class BuiltinToolCredentialDeletePayload(BaseModel):
class BuiltinToolAddPayload (line 67) | class BuiltinToolAddPayload(BaseModel):
class BuiltinToolUpdatePayload (line 73) | class BuiltinToolUpdatePayload(BaseModel):
class ApiToolProviderBasePayload (line 79) | class ApiToolProviderBasePayload(BaseModel):
class ApiToolProviderAddPayload (line 90) | class ApiToolProviderAddPayload(ApiToolProviderBasePayload):
class ApiToolProviderUpdatePayload (line 94) | class ApiToolProviderUpdatePayload(ApiToolProviderBasePayload):
class UrlQuery (line 98) | class UrlQuery(BaseModel):
class ProviderQuery (line 102) | class ProviderQuery(BaseModel):
class ApiToolProviderDeletePayload (line 106) | class ApiToolProviderDeletePayload(BaseModel):
class ApiToolSchemaPayload (line 110) | class ApiToolSchemaPayload(BaseModel):
class ApiToolTestPayload (line 114) | class ApiToolTestPayload(BaseModel):
class WorkflowToolBasePayload (line 123) | class WorkflowToolBasePayload(BaseModel):
method validate_name (line 134) | def validate_name(cls, value: str) -> str:
class WorkflowToolCreatePayload (line 138) | class WorkflowToolCreatePayload(WorkflowToolBasePayload):
method validate_workflow_app_id (line 143) | def validate_workflow_app_id(cls, value: str) -> str:
class WorkflowToolUpdatePayload (line 147) | class WorkflowToolUpdatePayload(WorkflowToolBasePayload):
method validate_workflow_tool_id (line 152) | def validate_workflow_tool_id(cls, value: str) -> str:
class WorkflowToolDeletePayload (line 156) | class WorkflowToolDeletePayload(BaseModel):
method validate_workflow_tool_id (line 161) | def validate_workflow_tool_id(cls, value: str) -> str:
class WorkflowToolGetQuery (line 165) | class WorkflowToolGetQuery(BaseModel):
method validate_ids (line 171) | def validate_ids(cls, value: str | None) -> str | None:
method ensure_one (line 177) | def ensure_one(self) -> "WorkflowToolGetQuery":
class WorkflowToolListQuery (line 183) | class WorkflowToolListQuery(BaseModel):
method validate_workflow_tool_id (line 188) | def validate_workflow_tool_id(cls, value: str) -> str:
class BuiltinProviderDefaultCredentialPayload (line 192) | class BuiltinProviderDefaultCredentialPayload(BaseModel):
class ToolOAuthCustomClientPayload (line 196) | class ToolOAuthCustomClientPayload(BaseModel):
class MCPProviderBasePayload (line 201) | class MCPProviderBasePayload(BaseModel):
class MCPProviderCreatePayload (line 213) | class MCPProviderCreatePayload(MCPProviderBasePayload):
class MCPProviderUpdatePayload (line 217) | class MCPProviderUpdatePayload(MCPProviderBasePayload):
class MCPProviderDeletePayload (line 221) | class MCPProviderDeletePayload(BaseModel):
class MCPAuthPayload (line 225) | class MCPAuthPayload(BaseModel):
class MCPCallbackQuery (line 230) | class MCPCallbackQuery(BaseModel):
class ToolProviderListApi (line 258) | class ToolProviderListApi(Resource):
method get (line 262) | def get(self):
class ToolBuiltinProviderListToolsApi (line 274) | class ToolBuiltinProviderListToolsApi(Resource):
method get (line 278) | def get(self, provider):
class ToolBuiltinProviderInfoApi (line 290) | class ToolBuiltinProviderInfoApi(Resource):
method get (line 294) | def get(self, provider):
class ToolBuiltinProviderDeleteApi (line 301) | class ToolBuiltinProviderDeleteApi(Resource):
method post (line 307) | def post(self, provider):
class ToolBuiltinProviderAddApi (line 320) | class ToolBuiltinProviderAddApi(Resource):
method post (line 325) | def post(self, provider):
class ToolBuiltinProviderUpdateApi (line 343) | class ToolBuiltinProviderUpdateApi(Resource):
method post (line 349) | def post(self, provider):
class ToolBuiltinProviderGetCredentialsApi (line 367) | class ToolBuiltinProviderGetCredentialsApi(Resource):
method get (line 371) | def get(self, provider):
class ToolBuiltinProviderIconApi (line 383) | class ToolBuiltinProviderIconApi(Resource):
method get (line 385) | def get(self, provider):
class ToolApiProviderAddApi (line 392) | class ToolApiProviderAddApi(Resource):
method post (line 398) | def post(self):
class ToolApiProviderGetRemoteSchemaApi (line 420) | class ToolApiProviderGetRemoteSchemaApi(Resource):
method get (line 424) | def get(self):
class ToolApiProviderListToolsApi (line 440) | class ToolApiProviderListToolsApi(Resource):
method get (line 444) | def get(self):
class ToolApiProviderUpdateApi (line 462) | class ToolApiProviderUpdateApi(Resource):
method post (line 468) | def post(self):
class ToolApiProviderDeleteApi (line 491) | class ToolApiProviderDeleteApi(Resource):
method post (line 497) | def post(self):
class ToolApiProviderGetApi (line 512) | class ToolApiProviderGetApi(Resource):
method get (line 516) | def get(self):
class ToolBuiltinProviderCredentialsSchemaApi (line 532) | class ToolBuiltinProviderCredentialsSchemaApi(Resource):
method get (line 536) | def get(self, provider, credential_type):
class ToolApiProviderSchemaApi (line 547) | class ToolApiProviderSchemaApi(Resource):
method post (line 552) | def post(self):
class ToolApiProviderPreviousTestApi (line 561) | class ToolApiProviderPreviousTestApi(Resource):
method post (line 566) | def post(self):
class ToolWorkflowProviderCreateApi (line 581) | class ToolWorkflowProviderCreateApi(Resource):
method post (line 587) | def post(self):
class ToolWorkflowProviderUpdateApi (line 609) | class ToolWorkflowProviderUpdateApi(Resource):
method post (line 615) | def post(self):
class ToolWorkflowProviderDeleteApi (line 636) | class ToolWorkflowProviderDeleteApi(Resource):
method post (line 642) | def post(self):
class ToolWorkflowProviderGetApi (line 657) | class ToolWorkflowProviderGetApi(Resource):
method get (line 661) | def get(self):
class ToolWorkflowProviderListToolApi (line 688) | class ToolWorkflowProviderListToolApi(Resource):
method get (line 692) | def get(self):
class ToolBuiltinListApi (line 710) | class ToolBuiltinListApi(Resource):
method get (line 714) | def get(self):
class ToolApiListApi (line 731) | class ToolApiListApi(Resource):
method get (line 735) | def get(self):
class ToolWorkflowListApi (line 749) | class ToolWorkflowListApi(Resource):
method get (line 753) | def get(self):
class ToolLabelsApi (line 770) | class ToolLabelsApi(Resource):
method get (line 775) | def get(self):
class ToolPluginOAuthApi (line 780) | class ToolPluginOAuthApi(Resource):
method get (line 785) | def get(self, provider):
class ToolOAuthCallback (line 821) | class ToolOAuthCallback(Resource):
method get (line 823) | def get(self, provider):
class ToolBuiltinProviderSetDefaultApi (line 873) | class ToolBuiltinProviderSetDefaultApi(Resource):
method post (line 878) | def post(self, provider):
class ToolOAuthCustomClient (line 887) | class ToolOAuthCustomClient(Resource):
method post (line 893) | def post(self, provider: str):
method get (line 910) | def get(self, provider):
method delete (line 919) | def delete(self, provider):
class ToolBuiltinProviderGetOauthClientSchemaApi (line 927) | class ToolBuiltinProviderGetOauthClientSchemaApi(Resource):
method get (line 931) | def get(self, provider):
class ToolBuiltinProviderGetCredentialInfoApi (line 941) | class ToolBuiltinProviderGetCredentialInfoApi(Resource):
method get (line 945) | def get(self, provider):
class ToolProviderMCPApi (line 957) | class ToolProviderMCPApi(Resource):
method post (line 962) | def post(self):
method put (line 1014) | def put(self):
method delete (line 1060) | def delete(self):
class ToolMCPAuthApi (line 1072) | class ToolMCPAuthApi(Resource):
method post (line 1077) | def post(self):
class ToolMCPDetailApi (line 1138) | class ToolMCPDetailApi(Resource):
method get (line 1142) | def get(self, provider_id):
class ToolMCPListAllApi (line 1151) | class ToolMCPListAllApi(Resource):
method get (line 1155) | def get(self):
class ToolMCPUpdateApi (line 1167) | class ToolMCPUpdateApi(Resource):
method get (line 1171) | def get(self, provider_id):
class ToolMCPCallbackApi (line 1183) | class ToolMCPCallbackApi(Resource):
method get (line 1184) | def get(self):
FILE: api/controllers/console/workspace/trigger_providers.py
class TriggerSubscriptionBuilderCreatePayload (line 38) | class TriggerSubscriptionBuilderCreatePayload(BaseModel):
class TriggerSubscriptionBuilderVerifyPayload (line 42) | class TriggerSubscriptionBuilderVerifyPayload(BaseModel):
class TriggerSubscriptionBuilderUpdatePayload (line 46) | class TriggerSubscriptionBuilderUpdatePayload(BaseModel):
method check_at_least_one_field (line 53) | def check_at_least_one_field(self):
class TriggerOAuthClientPayload (line 59) | class TriggerOAuthClientPayload(BaseModel):
class TriggerProviderIconApi (line 74) | class TriggerProviderIconApi(Resource):
method get (line 78) | def get(self, provider):
class TriggerProviderListApi (line 87) | class TriggerProviderListApi(Resource):
method get (line 91) | def get(self):
class TriggerProviderInfoApi (line 100) | class TriggerProviderInfoApi(Resource):
method get (line 104) | def get(self, provider):
class TriggerSubscriptionListApi (line 115) | class TriggerSubscriptionListApi(Resource):
method get (line 120) | def get(self, provider):
class TriggerSubscriptionBuilderCreateApi (line 141) | class TriggerSubscriptionBuilderCreateApi(Resource):
method post (line 147) | def post(self, provider):
class TriggerSubscriptionBuilderGetApi (line 171) | class TriggerSubscriptionBuilderGetApi(Resource):
method get (line 176) | def get(self, provider, subscription_builder_id):
class TriggerSubscriptionBuilderVerifyApi (line 186) | class TriggerSubscriptionBuilderVerifyApi(Resource):
method post (line 192) | def post(self, provider, subscription_builder_id):
class TriggerSubscriptionBuilderUpdateApi (line 218) | class TriggerSubscriptionBuilderUpdateApi(Resource):
method post (line 224) | def post(self, provider, subscription_builder_id):
class TriggerSubscriptionBuilderLogsApi (line 253) | class TriggerSubscriptionBuilderLogsApi(Resource):
method get (line 258) | def get(self, provider, subscription_builder_id):
class TriggerSubscriptionBuilderBuildApi (line 275) | class TriggerSubscriptionBuilderBuildApi(Resource):
method post (line 281) | def post(self, provider, subscription_builder_id):
class TriggerSubscriptionUpdateApi (line 308) | class TriggerSubscriptionUpdateApi(Resource):
method post (line 314) | def post(self, subscription_id: str):
class TriggerSubscriptionDeleteApi (line 367) | class TriggerSubscriptionDeleteApi(Resource):
method post (line 372) | def post(self, subscription_id: str):
class TriggerOAuthAuthorizeApi (line 400) | class TriggerOAuthAuthorizeApi(Resource):
method get (line 404) | def get(self, provider):
class TriggerOAuthCallbackApi (line 484) | class TriggerOAuthCallbackApi(Resource):
method get (line 486) | def get(self, provider):
class TriggerOAuthClientManageApi (line 549) | class TriggerOAuthClientManageApi(Resource):
method get (line 554) | def get(self, provider):
method post (line 600) | def post(self, provider):
method delete (line 626) | def delete(self, provider):
class TriggerSubscriptionVerifyApi (line 648) | class TriggerSubscriptionVerifyApi(Resource):
method post (line 654) | def post(self, provider, subscription_id):
FILE: api/controllers/console/workspace/workspace.py
class WorkspaceListQuery (line 43) | class WorkspaceListQuery(BaseModel):
class SwitchWorkspacePayload (line 48) | class SwitchWorkspacePayload(BaseModel):
class WorkspaceCustomConfigPayload (line 52) | class WorkspaceCustomConfigPayload(BaseModel):
class WorkspaceInfoPayload (line 57) | class WorkspaceInfoPayload(BaseModel):
function reg (line 61) | def reg(cls: type[BaseModel]):
class TenantListApi (line 105) | class TenantListApi(Resource):
method get (line 109) | def get(self):
class WorkspaceListApi (line 153) | class WorkspaceListApi(Resource):
method get (line 157) | def get(self):
class TenantApi (line 179) | class TenantApi(Resource):
method post (line 184) | def post(self):
class SwitchWorkspaceApi (line 207) | class SwitchWorkspaceApi(Resource):
method post (line 212) | def post(self):
class CustomConfigWorkspaceApi (line 231) | class CustomConfigWorkspaceApi(Resource):
method post (line 237) | def post(self):
class WebappLogoWorkspaceApi (line 257) | class WebappLogoWorkspaceApi(Resource):
method post (line 262) | def post(self):
class WorkspaceInfoApi (line 297) | class WorkspaceInfoApi(Resource):
method post (line 303) | def post(self):
class WorkspacePermissionApi (line 318) | class WorkspacePermissionApi(Resource):
method get (line 325) | def get(self):
FILE: api/controllers/console/wraps.py
function account_initialization_required (line 40) | def account_initialization_required(view: Callable[P, R]) -> Callable[P,...
function only_edition_cloud (line 53) | def only_edition_cloud(view: Callable[P, R]):
function only_edition_enterprise (line 64) | def only_edition_enterprise(view: Callable[P, R]):
function only_edition_self_hosted (line 75) | def only_edition_self_hosted(view: Callable[P, R]):
function cloud_edition_billing_enabled (line 86) | def cloud_edition_billing_enabled(view: Callable[P, R]):
function cloud_edition_billing_resource_check (line 98) | def cloud_edition_billing_resource_check(resource: str):
function cloud_edition_billing_knowledge_limit_check (line 140) | def cloud_edition_billing_knowledge_limit_check(resource: str):
function cloud_edition_billing_rate_limit_check (line 163) | def cloud_edition_billing_rate_limit_check(resource: str):
function cloud_utm_record (line 199) | def cloud_utm_record(view: Callable[P, R]):
function setup_required (line 218) | def setup_required(view: Callable[P, R]) -> Callable[P, R]:
function enterprise_license_required (line 232) | def enterprise_license_required(view: Callable[P, R]):
function email_password_login_enabled (line 244) | def email_password_login_enabled(view: Callable[P, R]):
function email_register_enabled (line 257) | def email_register_enabled(view: Callable[P, R]):
function enable_change_email (line 270) | def enable_change_email(view: Callable[P, R]):
function is_allow_transfer_owner (line 283) | def is_allow_transfer_owner(view: Callable[P, R]):
function knowledge_pipeline_publish_enabled (line 296) | def knowledge_pipeline_publish_enabled(view: Callable[P, R]):
function edit_permission_required (line 308) | def edit_permission_required(f: Callable[P, R]):
function is_admin_or_owner_required (line 326) | def is_admin_or_owner_required(f: Callable[P, R]):
function annotation_import_rate_limit (line 342) | def annotation_import_rate_limit(view: Callable[P, R]):
function annotation_import_concurrency_limit (line 391) | def annotation_import_concurrency_limit(view: Callable[P, R]):
function _decrypt_field (line 430) | def _decrypt_field(field_name: str, error_class: type[Exception], error_...
function decrypt_password_field (line 458) | def decrypt_password_field(view: Callable[P, R]):
function decrypt_code_field (line 480) | def decrypt_code_field(view: Callable[P, R]):
FILE: api/controllers/files/image_preview.py
class FileSignatureQuery (line 19) | class FileSignatureQuery(BaseModel):
class FilePreviewQuery (line 25) | class FilePreviewQuery(FileSignatureQuery):
class ImagePreviewApi (line 38) | class ImagePreviewApi(Resource):
method get (line 58) | def get(self, file_id):
class FilePreviewApi (line 80) | class FilePreviewApi(Resource):
method get (line 100) | def get(self, file_id):
class WorkspaceWebappLogoApi (line 153) | class WorkspaceWebappLogoApi(Resource):
method get (line 168) | def get(self, workspace_id):
FILE: api/controllers/files/tool_files.py
class ToolFileQuery (line 17) | class ToolFileQuery(BaseModel):
class ToolFileApi (line 30) | class ToolFileApi(Resource):
method get (line 51) | def get(self, file_id, extension):
FILE: api/controllers/files/upload.py
class PluginUploadQuery (line 26) | class PluginUploadQuery(BaseModel):
class PluginUploadFileApi (line 42) | class PluginUploadFileApi(Resource):
method post (line 57) | def post(self):
FILE: api/controllers/inner_api/app/dsl.py
class InnerAppDSLImportPayload (line 24) | class InnerAppDSLImportPayload(BaseModel):
class EnterpriseAppDSLImport (line 35) | class EnterpriseAppDSLImport(Resource):
method post (line 48) | def post(self, workspace_id: str):
class EnterpriseAppDSLExport (line 77) | class EnterpriseAppDSLExport(Resource):
method get (line 87) | def get(self, app_id: str):
function _get_active_account (line 103) | def _get_active_account(email: str) -> Account | None:
FILE: api/controllers/inner_api/mail.py
class InnerMailPayload (line 13) | class InnerMailPayload(BaseModel):
class BaseMail (line 23) | class BaseMail(Resource):
method post (line 29) | def post(self):
class EnterpriseMail (line 41) | class EnterpriseMail(BaseMail):
method post (line 50) | def post(self):
class BillingMail (line 63) | class BillingMail(BaseMail):
method post (line 72) | def post(self):
FILE: api/controllers/inner_api/plugin/plugin.py
class PluginInvokeLLMApi (line 39) | class PluginInvokeLLMApi(Resource):
method post (line 53) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeLLMWithStructuredOutputApi (line 62) | class PluginInvokeLLMWithStructuredOutputApi(Resource):
method post (line 76) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeTextEmbeddingApi (line 87) | class PluginInvokeTextEmbeddingApi(Resource):
method post (line 101) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeRerankApi (line 117) | class PluginInvokeRerankApi(Resource):
method post (line 127) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeTTSApi (line 143) | class PluginInvokeTTSApi(Resource):
method post (line 157) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeSpeech2TextApi (line 170) | class PluginInvokeSpeech2TextApi(Resource):
method post (line 180) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeModerationApi (line 196) | class PluginInvokeModerationApi(Resource):
method post (line 206) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeToolApi (line 222) | class PluginInvokeToolApi(Resource):
method post (line 236) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeParameterExtractorNodeApi (line 254) | class PluginInvokeParameterExtractorNodeApi(Resource):
method post (line 268) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeQuestionClassifierNodeApi (line 287) | class PluginInvokeQuestionClassifierNodeApi(Resource):
method post (line 301) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeAppApi (line 320) | class PluginInvokeAppApi(Resource):
method post (line 334) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeEncryptApi (line 350) | class PluginInvokeEncryptApi(Resource):
method post (line 364) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginInvokeSummaryApi (line 377) | class PluginInvokeSummaryApi(Resource):
method post (line 391) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginUploadFileRequestApi (line 407) | class PluginUploadFileRequestApi(Resource):
method post (line 421) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
class PluginFetchAppInfoApi (line 433) | class PluginFetchAppInfoApi(Resource):
method post (line 447) | def post(self, user_model: Account | EndUser, tenant_model: Tenant, pa...
FILE: api/controllers/inner_api/plugin/wraps.py
class TenantUserPayload (line 20) | class TenantUserPayload(BaseModel):
function get_user (line 25) | def get_user(tenant_id: str, user_id: str | None) -> EndUser:
function get_user_tenant (line 68) | def get_user_tenant(view_func: Callable[P, R]):
function plugin_data (line 100) | def plugin_data(view: Callable[P, R] | None = None, *, payload_type: typ...
FILE: api/controllers/inner_api/workspace/workspace.py
class WorkspaceCreatePayload (line 17) | class WorkspaceCreatePayload(BaseModel):
class WorkspaceOwnerlessPayload (line 22) | class WorkspaceOwnerlessPayload(BaseModel):
class EnterpriseWorkspace (line 30) | class EnterpriseWorkspace(Resource):
method post (line 43) | def post(self):
class EnterpriseWorkspaceNoOwnerEmail (line 71) | class EnterpriseWorkspaceNoOwnerEmail(Resource):
method post (line 84) | def post(self):
FILE: api/controllers/inner_api/wraps.py
function billing_inner_api_only (line 17) | def billing_inner_api_only(view: Callable[P, R]):
function enterprise_inner_api_only (line 33) | def enterprise_inner_api_only(view: Callable[P, R]):
function enterprise_inner_api_user_auth (line 49) | def enterprise_inner_api_user_auth(view: Callable[P, R]):
function plugin_inner_api_only (line 85) | def plugin_inner_api_only(view: Callable[P, R]):
FILE: api/controllers/mcp/mcp.py
class MCPRequestError (line 19) | class MCPRequestError(Exception):
method __init__ (line 22) | def __init__(self, error_code: int, message: str):
class MCPRequestPayload (line 28) | class MCPRequestPayload(BaseModel):
class MCPAppApi (line 39) | class MCPAppApi(Resource):
method post (line 51) | def post(self, server_code: str):
method _get_mcp_server_and_app (line 81) | def _get_mcp_server_and_app(self, server_code: str, session: Session) ...
method _validate_server_status (line 93) | def _validate_server_status(self, mcp_server: AppMCPServer):
method _process_mcp_message (line 98) | def _process_mcp_message(
method _handle_notification (line 113) | def _handle_notification(self, mcp_request: mcp_types.ClientNotificati...
method _handle_request (line 121) | def _handle_request(
method _get_user_input_form (line 141) | def _get_user_input_form(self, app: App) -> list[VariableEntity]:
method _convert_user_input_form (line 160) | def _convert_user_input_form(self, raw_form: list[dict]) -> list[Varia...
method _create_variable_entity (line 164) | def _create_variable_entity(self, item: dict) -> VariableEntity:
method _parse_mcp_request (line 180) | def _parse_mcp_request(self, args: dict) -> mcp_types.ClientRequest | ...
method _retrieve_end_user (line 190) | def _retrieve_end_user(self, tenant_id: str, mcp_server_id: str) -> En...
method _create_end_user (line 201) | def _create_end_user(
method _handle_mcp_request (line 217) | def _handle_mcp_request(
FILE: api/controllers/service_api/app/annotation.py
class AnnotationCreatePayload (line 18) | class AnnotationCreatePayload(BaseModel):
class AnnotationReplyActionPayload (line 23) | class AnnotationReplyActionPayload(BaseModel):
class AnnotationReplyActionApi (line 35) | class AnnotationReplyActionApi(Resource):
method post (line 47) | def post(self, app_model: App, action: Literal["enable", "disable"]):
class AnnotationReplyActionStatusApi (line 59) | class AnnotationReplyActionStatusApi(Resource):
method get (line 71) | def get(self, app_model: App, job_id, action):
class AnnotationListApi (line 89) | class AnnotationListApi(Resource):
method get (line 104) | def get(self, app_model: App):
method post (line 136) | def post(self, app_model: App):
class AnnotationUpdateDeleteApi (line 145) | class AnnotationUpdateDeleteApi(Resource):
method put (line 165) | def put(self, app_model: App, annotation_id: str):
method delete (line 185) | def delete(self, app_model: App, annotation_id: str):
FILE: api/controllers/service_api/app/app.py
class AppParameterApi (line 15) | class AppParameterApi(Resource):
method get (line 28) | def get(self, app_model: App):
class AppMetaApi (line 54) | class AppMetaApi(Resource):
method get (line 65) | def get(self, app_model: App):
class AppInfoApi (line 74) | class AppInfoApi(Resource):
method get (line 85) | def get(self, app_model: App):
FILE: api/controllers/service_api/app/audio.py
class AudioApi (line 38) | class AudioApi(Resource):
method post (line 52) | def post(self, app_model: App, end_user: EndUser):
class TextToAudioPayload (line 89) | class TextToAudioPayload(BaseModel):
class TextApi (line 100) | class TextApi(Resource):
method post (line 113) | def post(self, app_model: App, end_user: EndUser):
FILE: api/controllers/service_api/app/completion.py
class CompletionRequestPayload (line 43) | class CompletionRequestPayload(BaseModel):
class ChatRequestPayload (line 51) | class ChatRequestPayload(BaseModel):
method normalize_conversation_id (line 63) | def normalize_conversation_id(cls, value: str | UUID | None) -> str | ...
class CompletionApi (line 81) | class CompletionApi(Resource):
method post (line 95) | def post(self, app_model: App, end_user: EndUser):
class CompletionStopApi (line 147) | class CompletionStopApi(Resource):
method post (line 159) | def post(self, app_model: App, end_user: EndUser, task_id: str):
class ChatApi (line 175) | class ChatApi(Resource):
method post (line 190) | def post(self, app_model: App, end_user: EndUser):
class ChatStopApi (line 246) | class ChatStopApi(Resource):
method post (line 258) | def post(self, app_model: App, end_user: EndUser, task_id: str):
FILE: api/controllers/service_api/app/conversation.py
class ConversationListQuery (line 29) | class ConversationListQuery(BaseModel):
class ConversationRenamePayload (line 37) | class ConversationRenamePayload(BaseModel):
method validate_name_requirement (line 42) | def validate_name_requirement(self):
class ConversationVariablesQuery (line 49) | class ConversationVariablesQuery(BaseModel):
method validate_variable_name (line 58) | def validate_variable_name(cls, v: str | None) -> str | None:
class ConversationVariableUpdatePayload (line 80) | class ConversationVariableUpdatePayload(BaseModel):
class ConversationApi (line 94) | class ConversationApi(Resource):
method get (line 106) | def get(self, app_model: App, end_user: EndUser):
class ConversationDetailApi (line 141) | class ConversationDetailApi(Resource):
method delete (line 153) | def delete(self, app_model: App, end_user: EndUser, c_id):
class ConversationRenameApi (line 169) | class ConversationRenameApi(Resource):
method post (line 182) | def post(self, app_model: App, end_user: EndUser, c_id):
class ConversationVariablesApi (line 206) | class ConversationVariablesApi(Resource):
method get (line 220) | def get(self, app_model: App, end_user: EndUser, c_id):
class ConversationVariableDetailApi (line 244) | class ConversationVariableDetailApi(Resource):
method put (line 259) | def put(self, app_model: App, end_user: EndUser, c_id, variable_id):
FILE: api/controllers/service_api/app/error.py
class AppUnavailableError (line 4) | class AppUnavailableError(BaseHTTPException):
class NotCompletionAppError (line 10) | class NotCompletionAppError(BaseHTTPException):
class NotChatAppError (line 16) | class NotChatAppError(BaseHTTPException):
class NotWorkflowAppError (line 22) | class NotWorkflowAppError(BaseHTTPException):
class ConversationCompletedError (line 28) | class ConversationCompletedError(BaseHTTPException):
class ProviderNotInitializeError (line 34) | class ProviderNotInitializeError(BaseHTTPException):
class ProviderQuotaExceededError (line 43) | class ProviderQuotaExceededError(BaseHTTPException):
class ProviderModelCurrentlyNotSupportError (line 52) | class ProviderModelCurrentlyNotSupportError(BaseHTTPException):
class CompletionRequestError (line 58) | class CompletionRequestError(BaseHTTPException):
class NoAudioUploadedError (line 64) | class NoAudioUploadedError(BaseHTTPException):
class AudioTooLargeError (line 70) | class AudioTooLargeError(BaseHTTPException):
class UnsupportedAudioTypeError (line 76) | class UnsupportedAudioTypeError(BaseHTTPException):
class ProviderNotSupportSpeechToTextError (line 82) | class ProviderNotSupportSpeechToTextError(BaseHTTPException):
class FileNotFoundError (line 88) | class FileNotFoundError(BaseHTTPException):
class FileAccessDeniedError (line 94) | class FileAccessDeniedError(BaseHTTPException):
FILE: api/controllers/service_api/app/file.py
class FileApi (line 25) | class FileApi(Resource):
method post (line 39) | def post(self, app_model: App, end_user: EndUser):
FILE: api/controllers/service_api/app/file_preview.py
class FilePreviewQuery (line 24) | class FilePreviewQuery(BaseModel):
class FilePreviewApi (line 32) | class FilePreviewApi(Resource):
method get (line 53) | def get(self, app_model: App, end_user: EndUser, file_id: str):
method _validate_file_ownership (line 79) | def _validate_file_ownership(self, file_id: str, app_id: str) -> tuple...
method _build_file_response (line 143) | def _build_file_response(self, generator, upload_file: UploadFile, as_...
FILE: api/controllers/service_api/app/message.py
class MessageListQuery (line 30) | class MessageListQuery(BaseModel):
class MessageFeedbackPayload (line 36) | class MessageFeedbackPayload(BaseModel):
class FeedbackListQuery (line 41) | class FeedbackListQuery(BaseModel):
class MessageListApi (line 50) | class MessageListApi(Resource):
method get (line 62) | def get(self, app_model: App, end_user: EndUser):
class MessageFeedbackApi (line 93) | class MessageFeedbackApi(Resource):
method post (line 106) | def post(self, app_model: App, end_user: EndUser, message_id):
class AppGetFeedbacksApi (line 130) | class AppGetFeedbacksApi(Resource):
method get (line 141) | def get(self, app_model: App):
class MessageSuggestedApi (line 152) | class MessageSuggestedApi(Resource):
method get (line 166) | def get(self, app_model: App, end_user: EndUser, message_id):
FILE: api/controllers/service_api/app/site.py
class AppSiteApi (line 14) | class AppSiteApi(Resource):
method get (line 27) | def get(self, app_model: App):
FILE: api/controllers/service_api/app/workflow.py
class WorkflowRunPayload (line 49) | class WorkflowRunPayload(BaseModel):
class WorkflowLogQuery (line 55) | class WorkflowLogQuery(BaseModel):
class WorkflowRunStatusField (line 69) | class WorkflowRunStatusField(fields.Raw):
method output (line 70) | def output(self, key, obj: WorkflowRun, **kwargs):
class WorkflowRunOutputsField (line 74) | class WorkflowRunOutputsField(fields.Raw):
method output (line 75) | def output(self, key, obj: WorkflowRun, **kwargs):
function build_workflow_run_model (line 98) | def build_workflow_run_model(api_or_ns: Namespace):
class WorkflowRunDetailApi (line 104) | class WorkflowRunDetailApi(Resource):
method get (line 117) | def get(self, app_model: App, workflow_run_id: str):
class WorkflowRunApi (line 141) | class WorkflowRunApi(Resource):
method post (line 156) | def post(self, app_model: App, end_user: EndUser):
class WorkflowRunByIdApi (line 197) | class WorkflowRunByIdApi(Resource):
method post (line 213) | def post(self, app_model: App, end_user: EndUser, workflow_id: str):
class WorkflowTaskStopApi (line 263) | class WorkflowTaskStopApi(Resource):
method post (line 275) | def post(self, app_model: App, end_user: EndUser, task_id: str):
class WorkflowAppLogApi (line 292) | class WorkflowAppLogApi(Resource):
method get (line 304) | def get(self, app_model: App):
FILE: api/controllers/service_api/dataset/dataset.py
class DatasetCreatePayload (line 39) | class DatasetCreatePayload(BaseModel):
class DatasetUpdatePayload (line 53) | class DatasetUpdatePayload(BaseModel):
class TagNamePayload (line 67) | class TagNamePayload(BaseModel):
class TagCreatePayload (line 71) | class TagCreatePayload(TagNamePayload):
class TagUpdatePayload (line 75) | class TagUpdatePayload(TagNamePayload):
class TagDeletePayload (line 79) | class TagDeletePayload(BaseModel):
class TagBindingPayload (line 83) | class TagBindingPayload(BaseModel):
method validate_tag_ids (line 89) | def validate_tag_ids(cls, value: list[str]) -> list[str]:
class TagUnbindingPayload (line 95) | class TagUnbindingPayload(BaseModel):
class DatasetListQuery (line 100) | class DatasetListQuery(BaseModel):
class DatasetListApi (line 123) | class DatasetListApi(DatasetApiResource):
method get (line 134) | def get(self, tenant_id):
method post (line 191) | def post(self, tenant_id):
class DatasetApi (line 237) | class DatasetApi(DatasetApiResource):
method get (line 251) | def get(self, _, dataset_id):
method patch (line 307) | def patch(self, _, dataset_id):
method delete (line 383) | def delete(self, _, dataset_id):
class DocumentStatusApi (line 413) | class DocumentStatusApi(DatasetApiResource):
method patch (line 433) | def patch(self, tenant_id, dataset_id, action: Literal["enable", "disa...
class DatasetTagsApi (line 481) | class DatasetTagsApi(DatasetApiResource):
method get (line 490) | def get(self, _):
method post (line 509) | def post(self, _):
method patch (line 533) | def patch(self, _):
method delete (line 561) | def delete(self, _):
class DatasetTagBindingApi (line 570) | class DatasetTagBindingApi(DatasetApiResource):
method post (line 581) | def post(self, _):
class DatasetTagUnbindingApi (line 594) | class DatasetTagUnbindingApi(DatasetApiResource):
method post (line 605) | def post(self, _):
class DatasetTagsBindingStatusApi (line 618) | class DatasetTagsBindingStatusApi(DatasetApiResource):
method get (line 628) | def get(self, _, *args, **kwargs):
FILE: api/controllers/service_api/dataset/document.py
class DocumentTextCreatePayload (line 53) | class DocumentTextCreatePayload(BaseModel):
method validate_doc_form (line 67) | def validate_doc_form(cls, value: str) -> str:
class DocumentTextUpdate (line 76) | class DocumentTextUpdate(BaseModel):
method validate_doc_form (line 86) | def validate_doc_form(cls, value: str) -> str:
method check_text_and_name (line 92) | def check_text_and_name(self) -> Self:
class DocumentListQuery (line 98) | class DocumentListQuery(BaseModel):
class DocumentBatchDownloadZipPayload (line 108) | class DocumentBatchDownloadZipPayload(BaseModel):
class DocumentAddByTextApi (line 134) | class DocumentAddByTextApi(DatasetApiResource):
method post (line 151) | def post(self, tenant_id, dataset_id):
class DocumentUpdateByTextApi (line 224) | class DocumentUpdateByTextApi(DatasetApiResource):
method post (line 240) | def post(self, tenant_id: str, dataset_id: UUID, document_id: UUID):
class DocumentAddByFileApi (line 304) | class DocumentAddByFileApi(DatasetApiResource):
method post (line 320) | def post(self, tenant_id, dataset_id):
class DocumentUpdateByFileApi (line 417) | class DocumentUpdateByFileApi(DatasetApiResource):
method post (line 432) | def post(self, tenant_id, dataset_id, document_id):
class DocumentListApi (line 511) | class DocumentListApi(DatasetApiResource):
method get (line 522) | def get(self, tenant_id, dataset_id):
class DocumentBatchDownloadZipApi (line 566) | class DocumentBatchDownloadZipApi(DatasetApiResource):
method post (line 582) | def post(self, tenant_id, dataset_id):
class DocumentIndexingStatusApi (line 606) | class DocumentIndexingStatusApi(DatasetApiResource):
method get (line 617) | def get(self, tenant_id, dataset_id, batch):
class DocumentDownloadApi (line 673) | class DocumentDownloadApi(DatasetApiResource):
method get (line 688) | def get(self, tenant_id, dataset_id, document_id):
class DocumentApi (line 702) | class DocumentApi(DatasetApiResource):
method get (line 716) | def get(self, tenant_id, dataset_id, document_id):
method delete (line 833) | def delete(self, tenant_id, dataset_id, document_id):
FILE: api/controllers/service_api/dataset/error.py
class DatasetNotInitializedError (line 4) | class DatasetNotInitializedError(BaseHTTPException):
class ArchivedDocumentImmutableError (line 10) | class ArchivedDocumentImmutableError(BaseHTTPException):
class DatasetNameDuplicateError (line 16) | class DatasetNameDuplicateError(BaseHTTPException):
class InvalidActionError (line 22) | class InvalidActionError(BaseHTTPException):
class DocumentAlreadyFinishedError (line 28) | class DocumentAlreadyFinishedError(BaseHTTPException):
class DocumentIndexingError (line 34) | class DocumentIndexingError(BaseHTTPException):
class InvalidMetadataError (line 40) | class InvalidMetadataError(BaseHTTPException):
class DatasetInUseError (line 46) | class DatasetInUseError(BaseHTTPException):
class PipelineRunError (line 52) | class PipelineRunError(BaseHTTPException):
FILE: api/controllers/service_api/dataset/hit_testing.py
class HitTestingApi (line 10) | class HitTestingApi(DatasetApiResource, DatasetsHitTestingBase):
method post (line 23) | def post(self, tenant_id, dataset_id):
FILE: api/controllers/service_api/dataset/metadata.py
class MetadataUpdatePayload (line 22) | class MetadataUpdatePayload(BaseModel):
class DatasetMetadataCreateServiceApi (line 37) | class DatasetMetadataCreateServiceApi(DatasetApiResource):
method post (line 50) | def post(self, tenant_id, dataset_id):
method get (line 73) | def get(self, tenant_id, dataset_id):
class DatasetMetadataServiceApi (line 83) | class DatasetMetadataServiceApi(DatasetApiResource):
method patch (line 96) | def patch(self, tenant_id, dataset_id, metadata_id):
method delete (line 121) | def delete(self, tenant_id, dataset_id, metadata_id):
class DatasetMetadataBuiltInFieldServiceApi (line 135) | class DatasetMetadataBuiltInFieldServiceApi(DatasetApiResource):
method get (line 144) | def get(self, tenant_id, dataset_id):
class DatasetMetadataBuiltInFieldActionServiceApi (line 151) | class DatasetMetadataBuiltInFieldActionServiceApi(DatasetApiResource):
method post (line 163) | def post(self, tenant_id, dataset_id, action: Literal["enable", "disab...
class DocumentMetadataEditServiceApi (line 180) | class DocumentMetadataEditServiceApi(DatasetApiResource):
method post (line 193) | def post(self, tenant_id, dataset_id):
FILE: api/controllers/service_api/dataset/rag_pipeline/rag_pipeline_workflow.py
class DatasourceNodeRunPayload (line 33) | class DatasourceNodeRunPayload(BaseModel):
class DatasourcePluginsApi (line 45) | class DatasourcePluginsApi(DatasetApiResource):
method get (line 67) | def get(self, tenant_id: str, dataset_id: str):
class DatasourceNodeRunApi (line 86) | class DatasourceNodeRunApi(DatasetApiResource):
method post (line 112) | def post(self, tenant_id: str, dataset_id: str, node_id: str):
class PipelineRunApi (line 147) | class PipelineRunApi(DatasetApiResource):
method post (line 175) | def post(self, tenant_id: str, dataset_id: str):
class KnowledgebasePipelineFileUploadApi (line 205) | class KnowledgebasePipelineFileUploadApi(DatasetApiResource):
method post (line 219) | def post(self, tenant_id: str):
FILE: api/controllers/service_api/dataset/rag_pipeline/serializers.py
function serialize_upload_file (line 13) | def serialize_upload_file(upload_file: UploadFile) -> dict[str, Any]:
FILE: api/controllers/service_api/dataset/segment.py
function _marshal_segment_with_summary (line 35) | def _marshal_segment_with_summary(segment, dataset_id: str) -> dict:
function _marshal_segments_with_summary (line 43) | def _marshal_segments_with_summary(segments, dataset_id: str) -> list[di...
class SegmentCreatePayload (line 59) | class SegmentCreatePayload(BaseModel):
class SegmentListQuery (line 63) | class SegmentListQuery(BaseModel):
class SegmentUpdatePayload (line 68) | class SegmentUpdatePayload(BaseModel):
class ChildChunkCreatePayload (line 72) | class ChildChunkCreatePayload(BaseModel):
class ChildChunkListQuery (line 76) | class ChildChunkListQuery(BaseModel):
class ChildChunkUpdatePayload (line 82) | class ChildChunkUpdatePayload(BaseModel):
class SegmentApi (line 99) | class SegmentApi(DatasetApiResource):
method post (line 117) | def post(self, tenant_id: str, dataset_id: str, document_id: str):
method get (line 175) | def get(self, tenant_id: str, dataset_id: str, document_id: str):
class DatasetSegmentApi (line 236) | class DatasetSegmentApi(DatasetApiResource):
method delete (line 250) | def delete(self, tenant_id: str, dataset_id: str, document_id: str, se...
method post (line 286) | def post(self, tenant_id: str, dataset_id: str, document_id: str, segm...
method get (line 335) | def get(self, tenant_id: str, dataset_id: str, document_id: str, segme...
class ChildChunkApi (line 360) | class ChildChunkApi(DatasetApiResource):
method post (line 379) | def post(self, tenant_id: str, dataset_id: str, document_id: str, segm...
method get (line 439) | def get(self, tenant_id: str, dataset_id: str, document_id: str, segme...
class DatasetChildChunkApi (line 485) | class DatasetChildChunkApi(DatasetApiResource):
method delete (line 507) | def delete(self, tenant_id: str, dataset_id: str, document_id: str, se...
method patch (line 568) | def patch(self, tenant_id: str, dataset_id: str, document_id: str, seg...
FILE: api/controllers/service_api/end_user/end_user.py
class EndUserApi (line 14) | class EndUserApi(Resource):
method get (line 28) | def get(self, app_model: App, end_user_id: UUID):
FILE: api/controllers/service_api/end_user/error.py
class EndUserNotFoundError (line 4) | class EndUserNotFoundError(BaseHTTPException):
FILE: api/controllers/service_api/index.py
class IndexApi (line 8) | class IndexApi(Resource):
method get (line 9) | def get(self):
FILE: api/controllers/service_api/workspace/models.py
class ModelProviderAvailableModelApi (line 11) | class ModelProviderAvailableModelApi(Resource):
method get (line 22) | def get(self, _, model_type: str):
FILE: api/controllers/service_api/wraps.py
class WhereisUserArg (line 33) | class WhereisUserArg(StrEnum):
class FetchUserArg (line 43) | class FetchUserArg(BaseModel):
function validate_app_token (line 49) | def validate_app_token(view: Callable[P, R]) -> Callable[P, R]: ...
function validate_app_token (line 53) | def validate_app_token(
function validate_app_token (line 58) | def validate_app_token(
function cloud_edition_billing_resource_check (line 139) | def cloud_edition_billing_resource_check(resource: str, api_token_type: ...
function cloud_edition_billing_knowledge_limit_check (line 169) | def cloud_edition_billing_knowledge_limit_check(resource: str, api_token...
function cloud_edition_billing_rate_limit_check (line 191) | def cloud_edition_billing_rate_limit_check(resource: str, api_token_type...
function validate_dataset_token (line 229) | def validate_dataset_token(view: Callable[Concatenate[T, P], R]) -> Call...
function validate_dataset_token (line 233) | def validate_dataset_token(view: None = None) -> Callable[[Callable[Conc...
function validate_dataset_token (line 236) | def validate_dataset_token(
function validate_and_get_api_token (line 323) | def validate_and_get_api_token(scope: str | None = None):
class DatasetApiResource (line 358) | class DatasetApiResource(Resource):
method get_dataset (line 361) | def get_dataset(self, dataset_id: str, tenant_id: str) -> Dataset:
FILE: api/controllers/trigger/trigger.py
function trigger_endpoint (line 18) | def trigger_endpoint(endpoint_id: str):
FILE: api/controllers/trigger/webhook.py
function _prepare_webhook_execution (line 15) | def _prepare_webhook_execution(webhook_id: str, is_debug: bool = False):
function handle_webhook (line 43) | def handle_webhook(webhook_id: str):
function handle_webhook_debug (line 72) | def handle_webhook_debug(webhook_id: str):
FILE: api/controllers/web/app.py
class AppAccessModeQuery (line 28) | class AppAccessModeQuery(BaseModel):
class AppParameterApi (line 39) | class AppParameterApi(WebApiResource):
method get (line 54) | def get(self, app_model: App, end_user):
class AppMeta (line 77) | class AppMeta(WebApiResource):
method get (line 90) | def get(self, app_model: App, end_user):
class AppAccessMode (line 96) | class AppAccessMode(Resource):
method get (line 112) | def get(self):
class AppWebAuthPermission (line 133) | class AppWebAuthPermission(Resource):
method get (line 145) | def get(self):
FILE: api/controllers/web/audio.py
class TextToAudioPayload (line 37) | class TextToAudioPayload(BaseModel):
method validate_message_id (line 45) | def validate_message_id(cls, value: str | None) -> str | None:
class AudioApi (line 57) | class AudioApi(WebApiResource):
method post (line 76) | def post(self, app_model: App, end_user):
class TextApi (line 111) | class TextApi(WebApiResource):
method post (line 124) | def post(self, app_model: App, end_user):
FILE: api/controllers/web/completion.py
class CompletionMessagePayload (line 39) | class CompletionMessagePayload(BaseModel):
class ChatMessagePayload (line 49) | class ChatMessagePayload(BaseModel):
method validate_uuid (line 62) | def validate_uuid(cls, value: str | None) -> str | None:
class CompletionApi (line 73) | class CompletionApi(WebApiResource):
method post (line 87) | def post(self, app_model, end_user):
class CompletionStopApi (line 126) | class CompletionStopApi(WebApiResource):
method post (line 140) | def post(self, app_model, end_user, task_id):
class ChatApi (line 155) | class ChatApi(WebApiResource):
method post (line 169) | def post(self, app_model, end_user):
class ChatStopApi (line 211) | class ChatStopApi(WebApiResource):
method post (line 225) | def post(self, app_model, end_user, task_id):
FILE: api/controllers/web/conversation.py
class ConversationListQuery (line 26) | class ConversationListQuery(BaseModel):
method validate_last_id (line 34) | def validate_last_id(cls, value: str | None) -> str | None:
class ConversationRenamePayload (line 40) | class ConversationRenamePayload(BaseModel):
method validate_name_requirement (line 45) | def validate_name_requirement(self):
class ConversationListApi (line 56) | class ConversationListApi(WebApiResource):
method get (line 93) | def get(self, app_model, end_user):
class ConversationApi (line 125) | class ConversationApi(WebApiResource):
method delete (line 139) | def delete(self, app_model, end_user, c_id):
class ConversationRenameApi (line 153) | class ConversationRenameApi(WebApiResource):
method post (line 178) | def post(self, app_model, end_user, c_id):
class ConversationPinApi (line 201) | class ConversationPinApi(WebApiResource):
method patch (line 215) | def patch(self, app_model, end_user, c_id):
class ConversationUnPinApi (line 231) | class ConversationUnPinApi(WebApiResource):
method patch (line 245) | def patch(self, app_model, end_user, c_id):
FILE: api/controllers/web/error.py
class AppUnavailableError (line 4) | class AppUnavailableError(BaseHTTPException):
class NotCompletionAppError (line 10) | class NotCompletionAppError(BaseHTTPException):
class NotChatAppError (line 16) | class NotChatAppError(BaseHTTPException):
class NotWorkflowAppError (line 22) | class NotWorkflowAppError(BaseHTTPException):
class ConversationCompletedError (line 28) | class ConversationCompletedError(BaseHTTPException):
class ProviderNotInitializeError (line 34) | class ProviderNotInitializeError(BaseHTTPException):
class ProviderQuotaExceededError (line 43) | class ProviderQuotaExceededError(BaseHTTPException):
class ProviderModelCurrentlyNotSupportError (line 52) | class ProviderModelCurrentlyNotSupportError(BaseHTTPException):
class CompletionRequestError (line 58) | class CompletionRequestError(BaseHTTPException):
class AppMoreLikeThisDisabledError (line 64) | class AppMoreLikeThisDisabledError(BaseHTTPException):
class AppSuggestedQuestionsAfterAnswerDisabledError (line 70) | class AppSuggestedQuestionsAfterAnswerDisabledError(BaseHTTPException):
class NoAudioUploadedError (line 76) | class NoAudioUploadedError(BaseHTTPException):
class AudioTooLargeError (line 82) | class AudioTooLargeError(BaseHTTPException):
class UnsupportedAudioTypeError (line 88) | class UnsupportedAudioTypeError(BaseHTTPException):
class ProviderNotSupportSpeechToTextError (line 94) | class ProviderNotSupportSpeechToTextError(BaseHTTPException):
class WebAppAuthRequiredError (line 100) | class WebAppAuthRequiredError(BaseHTTPException):
class WebAppAuthAccessDeniedError (line 106) | class WebAppAuthAccessDeniedError(BaseHTTPException):
class InvokeRateLimitError (line 112) | class InvokeRateLimitError(BaseHTTPException):
class WebFormRateLimitExceededError (line 120) | class WebFormRateLimitExceededError(BaseHTTPException):
class NotFoundError (line 126) | class NotFoundError(BaseHTTPException):
class InvalidArgumentError (line 131) | class InvalidArgumentError(BaseHTTPException):
FILE: api/controllers/web/feature.py
class SystemFeatureApi (line 8) | class SystemFeatureApi(Resource):
method get (line 12) | def get(self):
FILE: api/controllers/web/files.py
class FileApi (line 22) | class FileApi(WebApiResource):
method post (line 34) | def post(self, app_model, end_user):
FILE: api/controllers/web/forgot_password.py
class ForgotPasswordSendPayload (line 28) | class ForgotPasswordSendPayload(BaseModel):
class ForgotPasswordCheckPayload (line 33) | class ForgotPasswordCheckPayload(BaseModel):
class ForgotPasswordResetPayload (line 39) | class ForgotPasswordResetPayload(BaseModel):
method validate_password (line 46) | def validate_password(cls, value: str) -> str:
class ForgotPasswordSendEmailApi (line 54) | class ForgotPasswordSendEmailApi(Resource):
method post (line 69) | def post(self):
class ForgotPasswordCheckApi (line 96) | class ForgotPasswordCheckApi(Resource):
method post (line 106) | def post(self):
class ForgotPasswordResetApi (line 144) | class ForgotPasswordResetApi(Resource):
method post (line 159) | def post(self):
method _update_existing_account (line 193) | def _update_existing_account(self, account: Account, password_hashed, ...
FILE: api/controllers/web/human_input_form.py
function _stringify_default_values (line 38) | def _stringify_default_values(values: dict[str, object]) -> dict[str, str]:
function _to_timestamp (line 50) | def _to_timestamp(value: datetime) -> int:
function _jsonify_form_definition (line 54) | def _jsonify_form_definition(form: Form, site_payload: dict | None = Non...
class HumanInputFormApi (line 70) | class HumanInputFormApi(Resource):
method get (line 76) | def get(self, form_token: str):
method post (line 101) | def post(self, form_token: str):
function _get_app_site_from_form (line 149) | def _get_app_site_from_form(form: Form) -> tuple[App, Site]:
FILE: api/controllers/web/login.py
class LoginPayload (line 35) | class LoginPayload(BaseModel):
method validate_password (line 41) | def validate_password(cls, value: str) -> str:
class EmailCodeLoginSendPayload (line 45) | class EmailCodeLoginSendPayload(BaseModel):
class EmailCodeLoginVerifyPayload (line 50) | class EmailCodeLoginVerifyPayload(BaseModel):
class LoginApi (line 60) | class LoginApi(Resource):
method post (line 78) | def post(self):
class LoginStatusApi (line 100) | class LoginStatusApi(Resource):
method get (line 110) | def get(self):
class LogoutApi (line 147) | class LogoutApi(Resource):
method post (line 156) | def post(self):
class EmailCodeLoginSendEmailApi (line 165) | class EmailCodeLoginSendEmailApi(Resource):
method post (line 178) | def post(self):
class EmailCodeLoginApi (line 195) | class EmailCodeLoginApi(Resource):
method post (line 210) | def post(self):
FILE: api/controllers/web/message.py
class MessageListQuery (line 43) | class MessageListQuery(BaseModel):
method validate_uuid (line 50) | def validate_uuid(cls, value: str | None) -> str | None:
class MessageFeedbackPayload (line 56) | class MessageFeedbackPayload(BaseModel):
class MessageMoreLikeThisQuery (line 61) | class MessageMoreLikeThisQuery(BaseModel):
class MessageListApi (line 71) | class MessageListApi(WebApiResource):
method get (line 100) | def get(self, app_model, end_user):
class MessageFeedbackApi (line 126) | class MessageFeedbackApi(WebApiResource):
method post (line 151) | def post(self, app_model, end_user, message_id):
class MessageMoreLikeThisApi (line 171) | class MessageMoreLikeThisApi(WebApiResource):
method get (line 185) | def get(self, app_model, end_user, message_id):
class MessageSuggestedQuestionApi (line 226) | class MessageSuggestedQuestionApi(WebApiResource):
method get (line 240) | def get(self, app_model, end_user, message_id):
FILE: api/controllers/web/passport.py
class PassportResource (line 22) | class PassportResource(Resource):
method get (line 34) | def get(self):
function decode_enterprise_webapp_user_id (line 106) | def decode_enterprise_webapp_user_id(jwt_token: str | None):
function exchange_token_for_existing_web_user (line 120) | def exchange_token_for_existing_web_user(app_code: str, enterprise_user_...
function _exchange_for_public_app_token (line 197) | def _exchange_for_public_app_token(app_model, site, token_decoded):
function generate_session_id (line 235) | def generate_session_id():
FILE: api/controllers/web/remote_files.py
class RemoteFileUploadPayload (line 24) | class RemoteFileUploadPayload(BaseModel):
class RemoteFileInfoApi (line 32) | class RemoteFileInfoApi(WebApiResource):
method get (line 44) | def get(self, app_model, end_user, url):
class RemoteFileUploadApi (line 75) | class R
Copy disabled (too large)
Download .json
Condensed preview — 9937 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (86,151K chars).
[
{
"path": ".agents/skills/backend-code-review/SKILL.md",
"chars": 6101,
"preview": "---\nname: backend-code-review\ndescription: Review backend code for quality, security, maintainability, and best practice"
},
{
"path": ".agents/skills/backend-code-review/references/architecture-rule.md",
"chars": 3844,
"preview": "# Rule Catalog — Architecture\n\n## Scope\n- Covers: controller/service/core-domain/libs/model layering, dependency directi"
},
{
"path": ".agents/skills/backend-code-review/references/db-schema-rule.md",
"chars": 6980,
"preview": "# Rule Catalog — DB Schema Design\n\n## Scope\n- Covers: model/base inheritance, schema boundaries in model properties, ten"
},
{
"path": ".agents/skills/backend-code-review/references/repositories-rule.md",
"chars": 3276,
"preview": "# Rule Catalog - Repositories Abstraction\n\n## Scope\n- Covers: when to reuse existing repository abstractions, when to in"
},
{
"path": ".agents/skills/backend-code-review/references/sqlalchemy-rule.md",
"chars": 6029,
"preview": "# Rule Catalog — SQLAlchemy Patterns\n\n## Scope\n- Covers: SQLAlchemy session and transaction lifecycle, query constructio"
},
{
"path": ".agents/skills/component-refactoring/SKILL.md",
"chars": 13319,
"preview": "---\nname: component-refactoring\ndescription: Refactor high-complexity React components in Dify frontend. Use when `pnpm "
},
{
"path": ".agents/skills/component-refactoring/references/complexity-patterns.md",
"chars": 11886,
"preview": "# Complexity Reduction Patterns\n\nThis document provides patterns for reducing cognitive complexity in Dify React compone"
},
{
"path": ".agents/skills/component-refactoring/references/component-splitting.md",
"chars": 11369,
"preview": "# Component Splitting Patterns\n\nThis document provides detailed guidance on splitting large components into smaller, foc"
},
{
"path": ".agents/skills/component-refactoring/references/hook-extraction.md",
"chars": 7901,
"preview": "# Hook Extraction Patterns\n\nThis document provides detailed guidance on extracting custom hooks from complex components "
},
{
"path": ".agents/skills/frontend-code-review/SKILL.md",
"chars": 2842,
"preview": "---\nname: frontend-code-review\ndescription: \"Trigger when the user requests a review of frontend files (e.g., `.tsx`, `."
},
{
"path": ".agents/skills/frontend-code-review/references/business-logic.md",
"chars": 617,
"preview": "# Rule Catalog — Business Logic\n\n## Can't use workflowStore in Node components\n\nIsUrgent: True\n\n### Description\n\nFile pa"
},
{
"path": ".agents/skills/frontend-code-review/references/code-quality.md",
"chars": 1403,
"preview": "# Rule Catalog — Code Quality\n\n## Conditional class names use utility function\n\nIsUrgent: True\nCategory: Code Quality\n\n#"
},
{
"path": ".agents/skills/frontend-code-review/references/performance.md",
"chars": 926,
"preview": "# Rule Catalog — Performance\n\n## React Flow data usage\n\nIsUrgent: True\nCategory: Performance\n\n### Description\n\nWhen rend"
},
{
"path": ".agents/skills/frontend-query-mutation/SKILL.md",
"chars": 2558,
"preview": "---\nname: frontend-query-mutation\ndescription: Guide for implementing Dify frontend query and mutation patterns with Tan"
},
{
"path": ".agents/skills/frontend-query-mutation/agents/openai.yaml",
"chars": 310,
"preview": "interface:\n display_name: \"Frontend Query & Mutation\"\n short_description: \"Dify TanStack Query and oRPC patterns\"\n de"
},
{
"path": ".agents/skills/frontend-query-mutation/references/contract-patterns.md",
"chars": 3498,
"preview": "# Contract Patterns\n\n## Table of Contents\n\n- Intent\n- Minimal structure\n- Core workflow\n- Query usage decision rule\n- Mu"
},
{
"path": ".agents/skills/frontend-query-mutation/references/runtime-rules.md",
"chars": 4149,
"preview": "# Runtime Rules\n\n## Table of Contents\n\n- Conditional queries\n- Cache invalidation\n- Key API guide\n- `mutate` vs `mutateA"
},
{
"path": ".agents/skills/frontend-testing/SKILL.md",
"chars": 11028,
"preview": "---\nname: frontend-testing\ndescription: Generate Vitest + React Testing Library tests for Dify frontend components, hook"
},
{
"path": ".agents/skills/frontend-testing/assets/component-test.template.tsx",
"chars": 11967,
"preview": "/**\n * Test Template for React Components\n *\n * WHY THIS STRUCTURE?\n * - Organized sections make tests easy to navigate "
},
{
"path": ".agents/skills/frontend-testing/assets/hook-test.template.ts",
"chars": 6778,
"preview": "/**\n * Test Template for Custom Hooks\n *\n * Instructions:\n * 1. Replace `useHookName` with your hook name\n * 2. Update i"
},
{
"path": ".agents/skills/frontend-testing/assets/utility-test.template.ts",
"chars": 5147,
"preview": "/**\n * Test Template for Utility Functions\n *\n * Instructions:\n * 1. Replace `utilityFunction` with your function name\n "
},
{
"path": ".agents/skills/frontend-testing/references/async-testing.md",
"chars": 8453,
"preview": "# Async Testing Guide\n\n## Core Async Patterns\n\n### 1. waitFor - Wait for Condition\n\n```typescript\nimport { render, scree"
},
{
"path": ".agents/skills/frontend-testing/references/checklist.md",
"chars": 6209,
"preview": "# Test Generation Checklist\n\nUse this checklist when generating or reviewing tests for Dify frontend components.\n\n## Pre"
},
{
"path": ".agents/skills/frontend-testing/references/common-patterns.md",
"chars": 11722,
"preview": "# Common Testing Patterns\n\n## Query Priority\n\nUse queries in this order (most to least preferred):\n\n```typescript\n// 1. "
},
{
"path": ".agents/skills/frontend-testing/references/domain-components.md",
"chars": 15261,
"preview": "# Domain-Specific Component Testing\n\nThis guide covers testing patterns for Dify's domain-specific components.\n\n## Workf"
},
{
"path": ".agents/skills/frontend-testing/references/mocking.md",
"chars": 15116,
"preview": "# Mocking Guide for Dify Frontend Tests\n\n## ⚠️ Important: What NOT to Mock\n\n### DO NOT Mock Base Components\n\n**Never moc"
},
{
"path": ".agents/skills/frontend-testing/references/workflow.md",
"chars": 7676,
"preview": "# Testing Workflow Guide\n\nThis guide defines the workflow for generating tests, especially for complex components or dir"
},
{
"path": ".claude/settings.json",
"chars": 228,
"preview": "{\n \"hooks\": {\n \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hooks\": [\n {\n \"type\":"
},
{
"path": ".coveragerc",
"chars": 84,
"preview": "[run]\nomit =\n api/tests/*\n api/migrations/*\n api/core/rag/datasource/vdb/*\n"
},
{
"path": ".devcontainer/Dockerfile",
"chars": 182,
"preview": "FROM mcr.microsoft.com/devcontainers/python:3.12-bookworm\n\nRUN apt-get update && export DEBIAN_FRONTEND=noninteractive \\"
},
{
"path": ".devcontainer/README.md",
"chars": 2505,
"preview": "# Development with devcontainer\n\nThis project includes a devcontainer configuration that allows you to open the project "
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 1522,
"preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
},
{
"path": ".devcontainer/noop.txt",
"chars": 199,
"preview": "This file copied into the container along with environment.yml* from the parent\nfolder. This file is included to prevent"
},
{
"path": ".devcontainer/post_create_command.sh",
"chars": 1186,
"preview": "#!/bin/bash\nWORKSPACE_ROOT=$(pwd)\n\nexport COREPACK_ENABLE_DOWNLOAD_PROMPT=0\ncorepack enable\ncd web && pnpm install\npipx "
},
{
"path": ".devcontainer/post_start_command.sh",
"chars": 31,
"preview": "#!/bin/bash\n\ncd api && uv sync\n"
},
{
"path": ".editorconfig",
"chars": 758,
"preview": "# EditorConfig is awesome: https://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines wit"
},
{
"path": ".gemini/config.yaml",
"chars": 268,
"preview": "have_fun: false\nmemory_config:\n disabled: false\ncode_review:\n disable: true\n comment_severity_threshold: MEDIUM\n max"
},
{
"path": ".gitattributes",
"chars": 338,
"preview": "# Ensure that .sh scripts use LF as line separator, even if they are checked out\n# to Windows(NTFS) file-system, by a us"
},
{
"path": ".github/CODEOWNERS",
"chars": 10086,
"preview": "# CODEOWNERS\n# This file defines code ownership for the Dify project.\n# Each line is a file pattern followed by one or m"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 1786,
"preview": "# Dify Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncomm"
},
{
"path": ".github/DISCUSSION_TEMPLATE/general.yml",
"chars": 1011,
"preview": "title: \"General Discussion\"\nbody:\n - type: checkboxes\n attributes:\n label: Self Checks\n description: \"To m"
},
{
"path": ".github/DISCUSSION_TEMPLATE/help.yml",
"chars": 1534,
"preview": "title: \"Help\"\nbody:\n - type: checkboxes\n attributes:\n label: Self Checks\n description: \"To make sure we ge"
},
{
"path": ".github/DISCUSSION_TEMPLATE/suggestion.yml",
"chars": 1849,
"preview": "title: Suggestions for New Features\nbody:\n - type: checkboxes\n attributes:\n label: Self Checks\n descriptio"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 2531,
"preview": "name: \"🕷️ Bug report\"\ndescription: Report errors or unexpected behavior\nlabels:\n - bug\nbody:\n - type: checkboxes\n a"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 1056,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: \"\\U0001F510 Security Vulnerabilities\"\n url: \"https://github.com/"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1986,
"preview": "name: \"⭐ Feature or enhancement request\"\ndescription: Propose something new.\nlabels:\n - enhancement\nbody:\n - type: che"
},
{
"path": ".github/ISSUE_TEMPLATE/refactor.yml",
"chars": 1854,
"preview": "name: \"✨ Refactor or Chore\"\ndescription: Refactor existing code or perform maintenance chores to improve readability and"
},
{
"path": ".github/actions/setup-web/action.yml",
"chars": 263,
"preview": "name: Setup Web Environment\n\nruns:\n using: composite\n steps:\n - name: Setup Vite+\n uses: voidzero-dev/setup-vp"
},
{
"path": ".github/dependabot.yml",
"chars": 4743,
"preview": "version: 2\n\nupdates:\n - package-ecosystem: \"pip\"\n directory: \"/api\"\n open-pull-requests-limit: 10\n schedule:\n "
},
{
"path": ".github/labeler.yml",
"chars": 63,
"preview": "web:\n - changed-files:\n - any-glob-to-any-file: 'web/**'\n"
},
{
"path": ".github/linters/.hadolint.yaml",
"chars": 27,
"preview": "failure-threshold: \"error\"\n"
},
{
"path": ".github/linters/.isort.cfg",
"chars": 27,
"preview": "[settings]\nline_length=120\n"
},
{
"path": ".github/linters/.yaml-lint.yml",
"chars": 166,
"preview": "---\n\nextends: default\n\nrules:\n brackets:\n max-spaces-inside: 1\n comments-indentation: disable\n document-start: dis"
},
{
"path": ".github/linters/editorconfig-checker.json",
"chars": 545,
"preview": "{\n \"Verbose\": false,\n \"Debug\": false,\n \"IgnoreDefaults\": false,\n \"SpacesAfterTabs\": false,\n \"NoColor\": fa"
},
{
"path": ".github/pull_request_template.md",
"chars": 1109,
"preview": "> [!IMPORTANT]\n>\n> 1. Make sure you have read our [contribution guidelines](https://github.com/langgenius/dify/blob/main"
},
{
"path": ".github/workflows/anti-slop.yml",
"chars": 430,
"preview": "name: Anti-Slop PR Check\n\non:\n pull_request_target:\n types: [opened, edited, synchronize]\n\npermissions:\n pull-reque"
},
{
"path": ".github/workflows/api-tests.yml",
"chars": 6352,
"preview": "name: Run Pytest\n\non:\n workflow_call:\n secrets:\n CODECOV_TOKEN:\n required: false\n\npermissions:\n content"
},
{
"path": ".github/workflows/autofix.yml",
"chars": 4996,
"preview": "name: autofix.ci\non:\n pull_request:\n branches: [\"main\"]\n merge_group:\n branches: [\"main\"]\n types: [checks_req"
},
{
"path": ".github/workflows/build-push.yml",
"chars": 5839,
"preview": "name: Build and Push API & Web\n\non:\n push:\n branches:\n - \"main\"\n - \"deploy/**\"\n - \"build/**\"\n - "
},
{
"path": ".github/workflows/db-migration-test.yml",
"chars": 3481,
"preview": "name: DB Migration Test\n\non:\n workflow_call:\n\nconcurrency:\n group: db-migration-test-${{ github.ref }}\n cancel-in-pro"
},
{
"path": ".github/workflows/deploy-agent-dev.yml",
"chars": 725,
"preview": "name: Deploy Agent Dev\n\npermissions:\n contents: read\n\non:\n workflow_run:\n workflows: [\"Build and Push API & Web\"]\n "
},
{
"path": ".github/workflows/deploy-dev.yml",
"chars": 666,
"preview": "name: Deploy Dev\n\non:\n workflow_run:\n workflows: [\"Build and Push API & Web\"]\n branches:\n - \"deploy/dev\"\n "
},
{
"path": ".github/workflows/deploy-enterprise.yml",
"chars": 1155,
"preview": "name: Deploy Enterprise\n\npermissions:\n contents: read\n\non:\n workflow_run:\n workflows: [\"Build and Push API & Web\"]\n"
},
{
"path": ".github/workflows/deploy-hitl.yml",
"chars": 682,
"preview": "name: Deploy HITL\n\non:\n workflow_run:\n workflows: [\"Build and Push API & Web\"]\n branches:\n - \"build/feat/hit"
},
{
"path": ".github/workflows/docker-build.yml",
"chars": 1674,
"preview": "name: Build docker image\n\non:\n pull_request:\n branches:\n - \"main\"\n paths:\n - api/Dockerfile\n - web"
},
{
"path": ".github/workflows/expose_service_ports.sh",
"chars": 1292,
"preview": "#!/bin/bash\n\nyq eval '.services.weaviate.ports += [\"8080:8080\"]' -i docker/docker-compose.yaml\nyq eval '.services.weavia"
},
{
"path": ".github/workflows/labeler.yml",
"chars": 299,
"preview": "name: \"Pull Request Labeler\"\non:\n pull_request_target:\n\njobs:\n labeler:\n permissions:\n contents: read\n pu"
},
{
"path": ".github/workflows/main-ci.yml",
"chars": 14223,
"preview": "name: Main CI Pipeline\n\non:\n pull_request:\n branches: [\"main\"]\n merge_group:\n branches: [\"main\"]\n types: [che"
},
{
"path": ".github/workflows/pyrefly-diff-comment.yml",
"chars": 3207,
"preview": "name: Comment with Pyrefly Diff\n\non:\n workflow_run:\n workflows:\n - Pyrefly Diff Check\n types:\n - comple"
},
{
"path": ".github/workflows/pyrefly-diff.yml",
"chars": 3593,
"preview": "name: Pyrefly Diff Check\n\non:\n pull_request:\n paths:\n - 'api/**/*.py'\n\npermissions:\n contents: read\n\njobs:\n p"
},
{
"path": ".github/workflows/semantic-pull-request.yml",
"chars": 724,
"preview": "name: Semantic Pull Request\n\non:\n pull_request:\n types:\n - opened\n - edited\n - reopened\n - synch"
},
{
"path": ".github/workflows/stale.yml",
"chars": 1105,
"preview": "# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.\n#\n# You c"
},
{
"path": ".github/workflows/style.yml",
"chars": 5538,
"preview": "name: Style check\n\non:\n workflow_call:\n\nconcurrency:\n group: style-${{ github.head_ref || github.run_id }}\n cancel-in"
},
{
"path": ".github/workflows/tool-test-sdks.yaml",
"chars": 915,
"preview": "name: Run Unit Test For SDKs\n\non:\n pull_request:\n branches:\n - main\n paths:\n - sdks/**\n - package."
},
{
"path": ".github/workflows/translate-i18n-claude.yml",
"chars": 19804,
"preview": "name: Translate i18n Files with Claude Code\n\n# Note: claude-code-action doesn't support push events directly.\n# Push eve"
},
{
"path": ".github/workflows/trigger-i18n-sync.yml",
"chars": 5892,
"preview": "name: Trigger i18n Sync on Push\n\non:\n push:\n branches: [main]\n paths:\n - 'web/i18n/en-US/*.json'\n\npermission"
},
{
"path": ".github/workflows/vdb-tests-full.yml",
"chars": 2615,
"preview": "name: Run Full VDB Tests\n\non:\n schedule:\n - cron: '0 3 * * 1'\n workflow_dispatch:\n\npermissions:\n contents: read\n\nc"
},
{
"path": ".github/workflows/vdb-tests.yml",
"chars": 2655,
"preview": "name: Run VDB Smoke Tests\n\non:\n workflow_call:\n\npermissions:\n contents: read\n\nconcurrency:\n group: vdb-tests-${{ gith"
},
{
"path": ".github/workflows/web-e2e.yml",
"chars": 1836,
"preview": "name: Web Full-Stack E2E\n\non:\n workflow_call:\n\npermissions:\n contents: read\n\nconcurrency:\n group: web-e2e-${{ github."
},
{
"path": ".github/workflows/web-tests.yml",
"chars": 2430,
"preview": "name: Web Tests\n\non:\n workflow_call:\n secrets:\n CODECOV_TOKEN:\n required: false\n\npermissions:\n contents"
},
{
"path": ".gitignore",
"chars": 3857,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# *db files\n*.db\n\n# Dist"
},
{
"path": ".nvmrc",
"chars": 3,
"preview": "22\n"
},
{
"path": ".vite-hooks/pre-commit",
"chars": 3252,
"preview": "#!/bin/sh\n# get the list of modified files\nfiles=$(git diff --cached --name-only)\n\n# check if api or web directory is mo"
},
{
"path": ".vscode/README.md",
"chars": 1006,
"preview": "# Debugging with VS Code\n\nThis `launch.json.template` file provides various debug configurations for the Dify project wi"
},
{
"path": ".vscode/launch.json.template",
"chars": 2208,
"preview": "{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"Python: Flask API\",\n \"type\":"
},
{
"path": "AGENTS.md",
"chars": 1911,
"preview": "# AGENTS.md\n\n## Project Overview\n\nDify is an open-source platform for developing LLM applications with an intuitive inte"
},
{
"path": "AUTHORS",
"chars": 56,
"preview": "nite-knite\ngoocarlos\ncrazywoola\niamjoel\nidsong\ntakatost\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 5278,
"preview": "# CONTRIBUTING\n\nSo you're looking to contribute to Dify - that's awesome, we can't wait to see what you do. As a startup"
},
{
"path": "LICENSE",
"chars": 1800,
"preview": "# Open Source License\n\nDify is licensed under a modified version of the Apache License 2.0, with the following additiona"
},
{
"path": "Makefile",
"chars": 5774,
"preview": "# Variables\nDOCKER_REGISTRY=langgenius\nWEB_IMAGE=$(DOCKER_REGISTRY)/dify-web\nAPI_IMAGE=$(DOCKER_REGISTRY)/dify-api\nVERSI"
},
{
"path": "README.md",
"chars": 15207,
"preview": "\n\n<p align=\"center\">\n <a href=\"https://cloud.dify.ai\">Dify Cloud</a"
},
{
"path": "api/.dockerignore",
"chars": 174,
"preview": ".env\n*.env.*\n\nstorage/generate_files/*\nstorage/privkeys/*\nstorage/tools/*\nstorage/upload_files/*\n\n# Logs\nlogs\n*.log*\n\n# "
},
{
"path": "api/.importlinter",
"chars": 199,
"preview": "[importlinter]\nroot_packages =\n core\n constants\n context\n configs\n controllers\n extensions\n factori"
},
{
"path": "api/.ruff.toml",
"chars": 4294,
"preview": "exclude = [\n \"migrations/*\",\n \".git\",\n \".git/**\",\n]\nline-length = 120\n\n[format]\nquote-style = \"double\"\n\n[lint]\n"
},
{
"path": "api/AGENTS.md",
"chars": 9036,
"preview": "# API Agent Guide\n\n## Notes for Agent (must-check)\n\nBefore changing any backend code under `api/`, you MUST read the sur"
},
{
"path": "api/Dockerfile",
"chars": 3717,
"preview": "# base image\nFROM python:3.12-slim-bookworm AS base\n\nWORKDIR /app/api\n\n# Install uv\nENV UV_VERSION=0.8.9\n\nRUN pip instal"
},
{
"path": "api/README.md",
"chars": 2617,
"preview": "# Dify Backend API\n\n## Setup and Run\n\n> [!IMPORTANT]\n>\n> In the v1.3.0 release, `poetry` has been replaced with\n> [`uv`]"
},
{
"path": "api/app.py",
"chars": 963,
"preview": "from __future__ import annotations\n\nimport sys\nfrom typing import TYPE_CHECKING, cast\n\nif TYPE_CHECKING:\n from celery"
},
{
"path": "api/app_factory.py",
"chars": 8131,
"preview": "import logging\nimport time\n\nfrom flask import request\nfrom opentelemetry.trace import get_current_span\nfrom opentelemetr"
},
{
"path": "api/celery_entrypoint.py",
"chars": 392,
"preview": "import psycogreen.gevent as pscycogreen_gevent # type: ignore\nfrom grpc.experimental import gevent as grpc_gevent # ty"
},
{
"path": "api/cnt_base.sh",
"chars": 199,
"preview": "#!/bin/bash\nset -euxo pipefail\n\nfor pattern in \"Base\" \"TypeBase\"; do\n printf \"%s \" \"$pattern\"\n grep \"($pattern):\" "
},
{
"path": "api/commands/__init__.py",
"chars": 2090,
"preview": "\"\"\"\nCLI command modules extracted from `commands.py`.\n\"\"\"\n\nfrom .account import create_tenant, reset_email, reset_passwo"
},
{
"path": "api/commands/account.py",
"chars": 4665,
"preview": "import base64\nimport secrets\n\nimport click\nfrom sqlalchemy.orm import sessionmaker\n\nfrom constants.languages import lang"
},
{
"path": "api/commands/plugin.py",
"chars": 22842,
"preview": "import json\nimport logging\nfrom typing import Any, cast\n\nimport click\nfrom pydantic import TypeAdapter\nfrom sqlalchemy i"
},
{
"path": "api/commands/retention.py",
"chars": 30846,
"preview": "import datetime\nimport logging\nimport time\nfrom typing import Any\n\nimport click\nimport sqlalchemy as sa\n\nfrom extensions"
},
{
"path": "api/commands/storage.py",
"chars": 33591,
"preview": "import json\nfrom typing import cast\n\nimport click\nimport sqlalchemy as sa\nfrom sqlalchemy import update\nfrom sqlalchemy."
},
{
"path": "api/commands/system.py",
"chars": 7437,
"preview": "import logging\n\nimport click\nimport sqlalchemy as sa\nfrom sqlalchemy import delete, select, update\nfrom sqlalchemy.orm i"
},
{
"path": "api/commands/vector.py",
"chars": 21397,
"preview": "import json\n\nimport click\nfrom flask import current_app\nfrom sqlalchemy import select\nfrom sqlalchemy.exc import SQLAlch"
},
{
"path": "api/configs/__init__.py",
"chars": 79,
"preview": "from .app_config import DifyConfig\n\ndify_config = DifyConfig() # type: ignore\n"
},
{
"path": "api/configs/app_config.py",
"chars": 4155,
"preview": "import logging\nfrom pathlib import Path\nfrom typing import Any\n\nfrom pydantic.fields import FieldInfo\nfrom pydantic_sett"
},
{
"path": "api/configs/deploy/__init__.py",
"chars": 993,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass DeploymentConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/enterprise/__init__.py",
"chars": 2230,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass EnterpriseFeatureConfig(BaseSettings):\n "
},
{
"path": "api/configs/extra/__init__.py",
"chars": 312,
"preview": "from configs.extra.archive_config import ArchiveStorageConfig\nfrom configs.extra.notion_config import NotionConfig\nfrom "
},
{
"path": "api/configs/extra/archive_config.py",
"chars": 1312,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass ArchiveStorageConfig(BaseSettings):\n \"\""
},
{
"path": "api/configs/extra/notion_config.py",
"chars": 1113,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass NotionConfig(BaseSettings):\n \"\"\"\n Co"
},
{
"path": "api/configs/extra/sentry_config.py",
"chars": 934,
"preview": "from pydantic import Field, NonNegativeFloat\nfrom pydantic_settings import BaseSettings\n\n\nclass SentryConfig(BaseSetting"
},
{
"path": "api/configs/feature/__init__.py",
"chars": 44603,
"preview": "from datetime import timedelta\nfrom enum import StrEnum\nfrom typing import Literal\n\nfrom pydantic import (\n AliasChoi"
},
{
"path": "api/configs/feature/hosted_service/__init__.py",
"chars": 13838,
"preview": "from pydantic import Field, NonNegativeInt\nfrom pydantic_settings import BaseSettings\n\n\nclass HostedCreditConfig(BaseSet"
},
{
"path": "api/configs/middleware/__init__.py",
"chars": 12866,
"preview": "import os\nfrom typing import Any, Literal\nfrom urllib.parse import parse_qsl, quote_plus\n\nfrom pydantic import Field, No"
},
{
"path": "api/configs/middleware/cache/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "api/configs/middleware/cache/redis_config.py",
"chars": 3840,
"preview": "from pydantic import Field, NonNegativeInt, PositiveFloat, PositiveInt, field_validator\nfrom pydantic_settings import Ba"
},
{
"path": "api/configs/middleware/cache/redis_pubsub_config.py",
"chars": 4153,
"preview": "from typing import Literal, Protocol, cast\nfrom urllib.parse import quote_plus, urlunparse\n\nfrom pydantic import AliasCh"
},
{
"path": "api/configs/middleware/storage/aliyun_oss_storage_config.py",
"chars": 1451,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass AliyunOSSStorageConfig(BaseSettings):\n "
},
{
"path": "api/configs/middleware/storage/amazon_s3_storage_config.py",
"chars": 1300,
"preview": "from typing import Literal\n\nfrom pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass S3StorageConfi"
},
{
"path": "api/configs/middleware/storage/azure_blob_storage_config.py",
"chars": 867,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass AzureBlobStorageConfig(BaseSettings):\n "
},
{
"path": "api/configs/middleware/storage/baidu_obs_storage_config.py",
"chars": 857,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass BaiduOBSStorageConfig(BaseSettings):\n \""
},
{
"path": "api/configs/middleware/storage/clickzetta_volume_storage_config.py",
"chars": 1783,
"preview": "\"\"\"ClickZetta Volume Storage Configuration\"\"\"\n\nfrom pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nc"
},
{
"path": "api/configs/middleware/storage/google_cloud_storage_config.py",
"chars": 581,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass GoogleCloudStorageConfig(BaseSettings):\n "
},
{
"path": "api/configs/middleware/storage/huawei_obs_storage_config.py",
"chars": 1051,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass HuaweiCloudOBSStorageConfig(BaseSettings):"
},
{
"path": "api/configs/middleware/storage/oci_storage_config.py",
"chars": 1078,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass OCIStorageConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/storage/opendal_storage_config.py",
"chars": 214,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass OpenDALStorageConfig(BaseSettings):\n OP"
},
{
"path": "api/configs/middleware/storage/supabase_storage_config.py",
"chars": 617,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass SupabaseStorageConfig(BaseSettings):\n \""
},
{
"path": "api/configs/middleware/storage/tencent_cos_storage_config.py",
"chars": 1203,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass TencentCloudCOSStorageConfig(BaseSettings)"
},
{
"path": "api/configs/middleware/storage/volcengine_tos_storage_config.py",
"chars": 1063,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass VolcengineTOSStorageConfig(BaseSettings):\n"
},
{
"path": "api/configs/middleware/vdb/alibabacloud_mysql_config.py",
"chars": 1867,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass AlibabaCloudMySQLConfig(BaseS"
},
{
"path": "api/configs/middleware/vdb/analyticdb_config.py",
"chars": 2455,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass AnalyticdbConfig(BaseSettings"
},
{
"path": "api/configs/middleware/vdb/baidu_vector_config.py",
"chars": 2404,
"preview": "from pydantic import Field, NonNegativeInt, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass BaiduVectorDB"
},
{
"path": "api/configs/middleware/vdb/chroma_config.py",
"chars": 1158,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass ChromaConfig(BaseSettings):\n "
},
{
"path": "api/configs/middleware/vdb/clickzetta_config.py",
"chars": 2049,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass ClickzettaConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/vdb/couchbase_config.py",
"chars": 742,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass CouchbaseConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/vdb/elasticsearch_config.py",
"chars": 3213,
"preview": "from pydantic import Field, PositiveInt, model_validator\nfrom pydantic_settings import BaseSettings\n\n\nclass Elasticsearc"
},
{
"path": "api/configs/middleware/vdb/hologres_config.py",
"chars": 2173,
"preview": "from holo_search_sdk.types import BaseQuantizationType, DistanceType, TokenizerType\nfrom pydantic import Field\nfrom pyda"
},
{
"path": "api/configs/middleware/vdb/huawei_cloud_config.py",
"chars": 665,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass HuaweiCloudConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/vdb/iris_config.py",
"chars": 2861,
"preview": "\"\"\"Configuration for InterSystems IRIS vector database.\"\"\"\n\nfrom pydantic import Field, PositiveInt, model_validator\nfro"
},
{
"path": "api/configs/middleware/vdb/lindorm_config.py",
"chars": 1069,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass LindormConfig(BaseSettings):\n \"\"\"\n L"
},
{
"path": "api/configs/middleware/vdb/matrixone_config.py",
"chars": 832,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass MatrixoneConfig(BaseSettings):\n \"\"\"Matr"
},
{
"path": "api/configs/middleware/vdb/milvus_config.py",
"chars": 1493,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass MilvusConfig(BaseSettings):\n \"\"\"\n Co"
},
{
"path": "api/configs/middleware/vdb/myscale_config.py",
"chars": 1143,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass MyScaleConfig(BaseSettings):\n"
},
{
"path": "api/configs/middleware/vdb/oceanbase_config.py",
"chars": 3188,
"preview": "from typing import Literal\n\nfrom pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass O"
},
{
"path": "api/configs/middleware/vdb/opengauss_config.py",
"chars": 1359,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass OpenGaussConfig(BaseSettings)"
},
{
"path": "api/configs/middleware/vdb/opensearch_config.py",
"chars": 1891,
"preview": "from enum import StrEnum\nfrom typing import Literal\n\nfrom pydantic import Field, PositiveInt\nfrom pydantic_settings impo"
},
{
"path": "api/configs/middleware/vdb/oracle_config.py",
"chars": 1414,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass OracleConfig(BaseSettings):\n \"\"\"\n Co"
},
{
"path": "api/configs/middleware/vdb/pgvector_config.py",
"chars": 1424,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass PGVectorConfig(BaseSettings):"
},
{
"path": "api/configs/middleware/vdb/pgvectors_config.py",
"chars": 1103,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass PGVectoRSConfig(BaseSettings)"
},
{
"path": "api/configs/middleware/vdb/qdrant_config.py",
"chars": 1194,
"preview": "from pydantic import Field, NonNegativeInt, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass QdrantConfig("
},
{
"path": "api/configs/middleware/vdb/relyt_config.py",
"chars": 957,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass RelytConfig(BaseSettings):\n "
},
{
"path": "api/configs/middleware/vdb/tablestore_config.py",
"chars": 984,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass TableStoreConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/vdb/tencent_vector_config.py",
"chars": 1755,
"preview": "from pydantic import Field, NonNegativeInt, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass TencentVector"
},
{
"path": "api/configs/middleware/vdb/tidb_on_qdrant_config.py",
"chars": 1658,
"preview": "from pydantic import Field, NonNegativeInt, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass TidbOnQdrantC"
},
{
"path": "api/configs/middleware/vdb/tidb_vector_config.py",
"chars": 1006,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass TiDBVectorConfig(BaseSettings"
},
{
"path": "api/configs/middleware/vdb/upstash_config.py",
"chars": 483,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass UpstashConfig(BaseSettings):\n \"\"\"\n C"
},
{
"path": "api/configs/middleware/vdb/vastbase_vector_config.py",
"chars": 1270,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass VastbaseVectorConfig(BaseSett"
},
{
"path": "api/configs/middleware/vdb/vikingdb_config.py",
"chars": 1676,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass VikingDBConfig(BaseSettings):\n \"\"\"\n "
},
{
"path": "api/configs/middleware/vdb/weaviate_config.py",
"chars": 1051,
"preview": "from pydantic import Field, PositiveInt\nfrom pydantic_settings import BaseSettings\n\n\nclass WeaviateConfig(BaseSettings):"
},
{
"path": "api/configs/observability/__init__.py",
"chars": 170,
"preview": "from configs.observability.otel.otel_config import OTelConfig\n\n\nclass ObservabilityConfig(OTelConfig):\n \"\"\"\n Obser"
},
{
"path": "api/configs/observability/otel/otel_config.py",
"chars": 1764,
"preview": "from pydantic import Field\nfrom pydantic_settings import BaseSettings\n\n\nclass OTelConfig(BaseSettings):\n \"\"\"\n Open"
},
{
"path": "api/configs/packaging/__init__.py",
"chars": 314,
"preview": "from pydantic import Field\n\nfrom configs.packaging.pyproject import PyProjectTomlConfig\n\n\nclass PackagingInfo(PyProjectT"
},
{
"path": "api/configs/packaging/pyproject.py",
"chars": 427,
"preview": "from pydantic import BaseModel, Field\nfrom pydantic_settings import BaseSettings\n\n\nclass PyProjectConfig(BaseModel):\n "
},
{
"path": "api/configs/remote_settings_sources/__init__.py",
"chars": 464,
"preview": "from pydantic import Field\n\nfrom .apollo import ApolloSettingsSourceInfo\nfrom .base import RemoteSettingsSource\nfrom .en"
},
{
"path": "api/configs/remote_settings_sources/apollo/__init__.py",
"chars": 1669,
"preview": "from collections.abc import Mapping\nfrom typing import Any\n\nfrom pydantic import Field\nfrom pydantic.fields import Field"
},
{
"path": "api/configs/remote_settings_sources/apollo/client.py",
"chars": 12351,
"preview": "import hashlib\nimport json\nimport logging\nimport os\nimport threading\nimport time\nfrom collections.abc import Callable, M"
},
{
"path": "api/configs/remote_settings_sources/apollo/python_3x.py",
"chars": 1389,
"preview": "import logging\nimport os\nimport ssl\nimport urllib.request\nfrom collections.abc import Mapping\nfrom typing import Any\nfro"
},
{
"path": "api/configs/remote_settings_sources/apollo/utils.py",
"chars": 1328,
"preview": "import hashlib\nimport socket\nfrom typing import Any\n\nfrom .python_3x import url_encode\n\n# define constants\nCONFIGURATION"
},
{
"path": "api/configs/remote_settings_sources/base.py",
"chars": 447,
"preview": "from collections.abc import Mapping\nfrom typing import Any\n\nfrom pydantic.fields import FieldInfo\n\n\nclass RemoteSettings"
},
{
"path": "api/configs/remote_settings_sources/enums.py",
"chars": 110,
"preview": "from enum import StrEnum\n\n\nclass RemoteSettingsSourceName(StrEnum):\n APOLLO = \"apollo\"\n NACOS = \"nacos\"\n"
},
{
"path": "api/configs/remote_settings_sources/nacos/__init__.py",
"chars": 1663,
"preview": "import logging\nimport os\nfrom collections.abc import Mapping\nfrom typing import Any\n\nfrom pydantic.fields import FieldIn"
},
{
"path": "api/configs/remote_settings_sources/nacos/http_request.py",
"chars": 3406,
"preview": "import base64\nimport hashlib\nimport hmac\nimport logging\nimport os\nimport time\n\nimport httpx\n\nlogger = logging.getLogger("
},
{
"path": "api/configs/remote_settings_sources/nacos/utils.py",
"chars": 975,
"preview": "def parse_config(content: str) -> dict[str, str]:\n config: dict[str, str] = {}\n if not content:\n return con"
},
{
"path": "api/constants/__init__.py",
"chars": 2204,
"preview": "from configs import dify_config\nfrom libs.collection_utils import convert_to_lower_and_upper_set\n\nHIDDEN_VALUE = \"[__HID"
},
{
"path": "api/constants/languages.py",
"chars": 1064,
"preview": "language_timezone_mapping = {\n \"en-US\": \"America/New_York\",\n \"zh-Hans\": \"Asia/Shanghai\",\n \"zh-Hant\": \"Asia/Taip"
},
{
"path": "api/constants/mimetypes.py",
"chars": 318,
"preview": "# The two constants below should keep in sync.\n# Default content type for files which have no explicit content type.\n\nDE"
},
{
"path": "api/constants/model_template.py",
"chars": 2190,
"preview": "import json\nfrom collections.abc import Mapping\n\nfrom models.model import AppMode\n\ndefault_app_templates: Mapping[AppMod"
},
{
"path": "api/constants/pipeline_templates.json",
"chars": 852944,
"preview": "{\n \"pipeline_templates\": {\n \"en-US\": {\n \"pipeline_templates\": [\n {\n \"id\": \"9f5ea5a7-7796-49f3-9"
},
{
"path": "api/constants/recommended_apps.json",
"chars": 344753,
"preview": "{\n \"recommended_apps\": {\n \"en-US\": {\n \"categories\": [\n \"Agent\",\n \"Wor"
},
{
"path": "api/constants/tts_auto_play_timeout.py",
"chars": 137,
"preview": "TTS_AUTO_PLAY_TIMEOUT = 5\n\n# sleep 20 ms ( 40ms => 1280 byte audio file,20ms => 640 byte audio file)\nTTS_AUTO_PLAY_YIELD"
},
{
"path": "api/context/__init__.py",
"chars": 878,
"preview": "\"\"\"\nApplication-layer context adapters.\n\nConcrete execution-context implementations live here so `graphon` only\ndepends "
},
{
"path": "api/context/execution_context.py",
"chars": 7348,
"preview": "\"\"\"\nApplication-layer execution context adapters.\n\nConcrete context capture lives outside `graphon` so the graph package"
},
{
"path": "api/context/flask_app_context.py",
"chars": 5422,
"preview": "\"\"\"\nFlask App Context - Flask implementation of AppContext interface.\n\"\"\"\n\nimport contextvars\nimport threading\nfrom coll"
},
{
"path": "api/context/models.py",
"chars": 343,
"preview": "from __future__ import annotations\n\nfrom pydantic import AnyHttpUrl, BaseModel\n\n\nclass SandboxContext(BaseModel):\n \"\""
},
{
"path": "api/contexts/__init__.py",
"chars": 1404,
"preview": "from contextvars import ContextVar\nfrom threading import Lock\nfrom typing import TYPE_CHECKING\n\nfrom contexts.wrapper im"
},
{
"path": "api/contexts/wrapper.py",
"chars": 2154,
"preview": "from contextvars import ContextVar\nfrom typing import Generic, TypeVar\n\nT = TypeVar(\"T\")\n\n\nclass HiddenValue:\n pass\n\n"
},
{
"path": "api/controllers/__init__.py",
"chars": 1,
"preview": "\n"
},
{
"path": "api/controllers/common/errors.py",
"chars": 1088,
"preview": "from werkzeug.exceptions import HTTPException\n\nfrom libs.exception import BaseHTTPException\n\n\nclass FilenameNotExistsErr"
},
{
"path": "api/controllers/common/fields.py",
"chars": 1754,
"preview": "from __future__ import annotations\n\nfrom typing import Any, TypeAlias\n\nfrom graphon.file import helpers as file_helpers\n"
},
{
"path": "api/controllers/common/file_response.py",
"chars": 1638,
"preview": "import os\nfrom email.message import Message\nfrom urllib.parse import quote\n\nfrom flask import Response\n\nHTML_MIME_TYPES:"
},
{
"path": "api/controllers/common/helpers.py",
"chars": 2772,
"preview": "import contextlib\nimport mimetypes\nimport os\nimport platform\nimport re\nimport urllib.parse\nimport warnings\nfrom uuid imp"
},
{
"path": "api/controllers/common/schema.py",
"chars": 1567,
"preview": "\"\"\"Helpers for registering Pydantic models with Flask-RESTX namespaces.\"\"\"\n\nfrom enum import StrEnum\n\nfrom flask_restx i"
},
{
"path": "api/controllers/console/__init__.py",
"chars": 4274,
"preview": "from importlib import import_module\n\nfrom flask import Blueprint\nfrom flask_restx import Namespace\n\nfrom libs.external_a"
},
{
"path": "api/controllers/console/admin.py",
"chars": 16892,
"preview": "import csv\nimport io\nfrom collections.abc import Callable\nfrom functools import wraps\nfrom typing import ParamSpec, Type"
},
{
"path": "api/controllers/console/apikey.py",
"chars": 8590,
"preview": "import flask_restx\nfrom flask_restx import Resource, fields, marshal_with\nfrom flask_restx._http import HTTPStatus\nfrom "
}
]
// ... and 9737 more files (download for full content)
About this extraction
This page contains the full source code of the langgenius/dify GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9937 files (76.5 MB), approximately 20.7M tokens, and a symbol index with 62475 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.