From 1a339038875f240f80e2e1da3c42519f1ae33a4c Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:59:56 +0800 Subject: [PATCH 001/159] feat(web): add root isolation layer for portal stacking context (#32807) --- web/app/layout.tsx | 62 ++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/web/app/layout.tsx b/web/app/layout.tsx index a19d5e1e57..64f0e5ac3b 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -57,38 +57,40 @@ const LocaleLayout = async ({ - - - - - - - - - - - - {children} - - - - - - - - - - - +
+ + + + + + + + + + + + {children} + + + + + + + + + + + +
) From 8cc775d9f2a40b20b11f8c8af675fb9559e76cf6 Mon Sep 17 00:00:00 2001 From: hj24 Date: Mon, 2 Mar 2026 11:01:11 +0800 Subject: [PATCH 002/159] fix: optimize workflow_run iter query (#32815) --- .../sqlalchemy_api_workflow_run_repository.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/repositories/sqlalchemy_api_workflow_run_repository.py b/api/repositories/sqlalchemy_api_workflow_run_repository.py index 7935dfb225..5ba7a7e7e8 100644 --- a/api/repositories/sqlalchemy_api_workflow_run_repository.py +++ b/api/repositories/sqlalchemy_api_workflow_run_repository.py @@ -29,7 +29,7 @@ from typing import Any, cast import sqlalchemy as sa from pydantic import ValidationError -from sqlalchemy import and_, delete, func, null, or_, select +from sqlalchemy import and_, delete, func, null, or_, select, tuple_ from sqlalchemy.engine import CursorResult from sqlalchemy.orm import Session, selectinload, sessionmaker @@ -423,9 +423,10 @@ class DifyAPISQLAlchemyWorkflowRunRepository(APIWorkflowRunRepository): if last_seen: stmt = stmt.where( - or_( - WorkflowRun.created_at > last_seen[0], - and_(WorkflowRun.created_at == last_seen[0], WorkflowRun.id > last_seen[1]), + tuple_(WorkflowRun.created_at, WorkflowRun.id) + > tuple_( + sa.literal(last_seen[0], type_=sa.DateTime()), + sa.literal(last_seen[1], type_=WorkflowRun.id.type), ) ) From 335b500aea58b62ea61d9b398a1a8ae2049bcec5 Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Mon, 2 Mar 2026 11:40:43 +0800 Subject: [PATCH 003/159] test: add unit tests for base components (#32818) Co-authored-by: CodingOnStar --- .../base/{ => __tests__}/alert.spec.tsx | 2 +- .../{ => __tests__}/app-unavailable.spec.tsx | 2 +- .../base/{ => __tests__}/badge.spec.tsx | 2 +- .../{ => __tests__}/theme-selector.spec.tsx | 2 +- .../{ => __tests__}/theme-switcher.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/detail.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/iteration.spec.tsx | 2 +- .../{ => __tests__}/result.spec.tsx | 2 +- .../{ => __tests__}/tool-call.spec.tsx | 2 +- .../{ => __tests__}/tracing.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/ImageInput.spec.tsx | 2 +- .../{ => __tests__}/hooks.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/utils.spec.ts | 2 +- .../app-icon/{ => __tests__}/index.spec.tsx | 2 +- .../audio-btn/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/AudioPlayer.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../avatar/{ => __tests__}/index.spec.tsx | 2 +- .../base/badge/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/add-button.spec.tsx | 2 +- .../button/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/sync-button.spec.tsx | 2 +- .../carousel/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/chat-wrapper.spec.tsx | 18 ++++++++--------- .../{ => __tests__}/header-in-mobile.spec.tsx | 12 +++++------ .../{ => __tests__}/hooks.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 10 +++++----- .../header/{ => __tests__}/index.spec.tsx | 8 ++++---- .../mobile-operation-dropdown.spec.tsx | 2 +- .../header/{ => __tests__}/operation.spec.tsx | 2 +- .../{ => __tests__}/content.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../view-form-dropdown.spec.tsx | 8 ++++---- .../sidebar/{ => __tests__}/index.spec.tsx | 10 +++++----- .../sidebar/{ => __tests__}/item.spec.tsx | 2 +- .../sidebar/{ => __tests__}/list.spec.tsx | 4 ++-- .../{ => __tests__}/operation.spec.tsx | 2 +- .../{ => __tests__}/rename-modal.spec.tsx | 2 +- .../{ => __tests__}/content-switch.spec.tsx | 2 +- .../chat/{ => __tests__}/context.spec.tsx | 6 +++--- .../{ => __tests__}/hooks.multimodal.spec.ts | 0 .../chat/chat/{ => __tests__}/index.spec.tsx | 12 +++++------ .../chat/{ => __tests__}/question.spec.tsx | 12 +++++------ .../chat/{ => __tests__}/try-to-ask.spec.tsx | 4 ++-- .../{ => __tests__}/agent-content.spec.tsx | 4 ++-- .../{ => __tests__}/basic-content.spec.tsx | 4 ++-- .../human-input-filled-form-list.spec.tsx | 2 +- .../human-input-form-list.spec.tsx | 6 +++--- .../chat/answer/{ => __tests__}/more.spec.tsx | 2 +- .../answer/{ => __tests__}/operation.spec.tsx | 8 ++++---- .../suggested-questions.spec.tsx | 8 ++++---- .../{ => __tests__}/tool-detail.spec.tsx | 4 ++-- .../{ => __tests__}/workflow-process.spec.tsx | 4 ++-- .../{ => __tests__}/content-item.spec.tsx | 2 +- .../{ => __tests__}/content-wrapper.spec.tsx | 2 +- .../{ => __tests__}/executed-action.spec.tsx | 2 +- .../{ => __tests__}/expiration-time.spec.tsx | 8 ++++---- .../{ => __tests__}/human-input-form.spec.tsx | 4 ++-- .../submitted-content.spec.tsx | 2 +- .../{ => __tests__}/submitted.spec.tsx | 2 +- .../{ => __tests__}/tips.spec.tsx | 2 +- .../{ => __tests__}/unsubmitted.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/operation.spec.tsx | 6 +++--- .../citation/{ => __tests__}/index.spec.tsx | 6 +++--- .../citation/{ => __tests__}/popup.spec.tsx | 8 ++++---- .../{ => __tests__}/progress-tooltip.spec.tsx | 2 +- .../citation/{ => __tests__}/tooltip.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../chat/log/{ => __tests__}/index.spec.tsx | 2 +- .../thought/{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/chat-wrapper.spec.tsx | 20 +++++++++---------- .../{ => __tests__}/hooks.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 16 +++++++-------- .../header/{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/content.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../view-form-dropdown.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../checkbox/{ => __tests__}/index.spec.tsx | 2 +- .../indeterminate-icon.spec.tsx | 2 +- .../base/chip/{ => __tests__}/index.spec.tsx | 4 ++-- .../confirm/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../copy-icon/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/hooks.spec.ts | 6 +++--- .../{ => __tests__}/days-of-week.spec.tsx | 2 +- .../calendar/{ => __tests__}/index.spec.tsx | 6 +++--- .../calendar/{ => __tests__}/item.spec.tsx | 6 +++--- .../{ => __tests__}/option-list-item.spec.tsx | 2 +- .../{ => __tests__}/footer.spec.tsx | 6 +++--- .../{ => __tests__}/header.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/footer.spec.tsx | 4 ++-- .../{ => __tests__}/header.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/options.spec.tsx | 6 +++--- .../{ => __tests__}/dayjs-extended.spec.ts | 2 +- .../utils/{ => __tests__}/dayjs.spec.ts | 2 +- .../{ => __tests__}/footer.spec.tsx | 4 ++-- .../{ => __tests__}/header.spec.tsx | 4 ++-- .../{ => __tests__}/options.spec.tsx | 4 ++-- .../dialog/{ => __tests__}/index.spec.tsx | 2 +- .../divider/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../drawer/{ => __tests__}/index.spec.tsx | 4 ++-- .../dropdown/{ => __tests__}/index.spec.tsx | 2 +- .../effect/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/Inner.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../features/{ => __tests__}/context.spec.tsx | 2 +- .../features/{ => __tests__}/hooks.spec.ts | 6 +++--- .../features/{ => __tests__}/store.spec.ts | 2 +- .../{ => __tests__}/citation.spec.tsx | 6 +++--- .../{ => __tests__}/dialog-wrapper.spec.tsx | 2 +- .../{ => __tests__}/feature-bar.spec.tsx | 6 +++--- .../{ => __tests__}/feature-card.spec.tsx | 2 +- .../{ => __tests__}/follow-up.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/more-like-this.spec.tsx | 6 +++--- .../{ => __tests__}/speech-to-text.spec.tsx | 6 +++--- .../annotation-ctrl-button.spec.tsx | 2 +- .../config-param-modal.spec.tsx | 2 +- .../{ => __tests__}/config-param.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/type.spec.ts | 2 +- .../use-annotation-config.spec.ts | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/modal.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/setting-content.spec.tsx | 6 +++--- .../{ => __tests__}/setting-modal.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/form-generation.spec.tsx | 2 +- .../moderation/{ => __tests__}/index.spec.tsx | 6 +++--- .../moderation-content.spec.tsx | 2 +- .../moderation-setting-modal.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../param-config-content.spec.tsx | 6 +++--- .../{ => __tests__}/voice-settings.spec.tsx | 6 +++--- .../file-icon/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/image-render.spec.tsx | 2 +- .../file-thumb/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/audio-preview.spec.tsx | 2 +- .../{ => __tests__}/constants.spec.ts | 2 +- .../file-image-render.spec.tsx | 2 +- .../{ => __tests__}/file-input.spec.tsx | 8 ++++---- .../{ => __tests__}/file-list-in-log.spec.tsx | 4 ++-- .../{ => __tests__}/file-type-icon.spec.tsx | 4 ++-- .../{ => __tests__}/hooks.spec.ts | 8 ++++---- .../{ => __tests__}/pdf-preview.spec.tsx | 4 ++-- .../{ => __tests__}/store.spec.tsx | 4 ++-- .../{ => __tests__}/utils.spec.ts | 12 +++++------ .../{ => __tests__}/video-preview.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/file-item.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/file-image-item.spec.tsx | 4 ++-- .../{ => __tests__}/file-item.spec.tsx | 6 +++--- .../{ => __tests__}/file-list.spec.tsx | 8 ++++---- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/form/{ => __tests__}/index.spec.tsx | 2 +- .../base/form/{ => __tests__}/types.spec.ts | 2 +- .../components/{ => __tests__}/label.spec.tsx | 2 +- .../base/{ => __tests__}/base-field.spec.tsx | 2 +- .../base/{ => __tests__}/base-form.spec.tsx | 2 +- .../base/{ => __tests__}/index.spec.tsx | 2 +- .../field/{ => __tests__}/checkbox.spec.tsx | 4 ++-- .../{ => __tests__}/custom-select.spec.tsx | 4 ++-- .../field/{ => __tests__}/file-types.spec.tsx | 4 ++-- .../{ => __tests__}/file-uploader.spec.tsx | 4 ++-- .../{ => __tests__}/number-input.spec.tsx | 4 ++-- .../{ => __tests__}/number-slider.spec.tsx | 4 ++-- .../field/{ => __tests__}/options.spec.tsx | 4 ++-- .../field/{ => __tests__}/select.spec.tsx | 4 ++-- .../field/{ => __tests__}/text-area.spec.tsx | 4 ++-- .../field/{ => __tests__}/text.spec.tsx | 4 ++-- .../{ => __tests__}/upload-method.spec.tsx | 4 ++-- .../variable-or-constant-input.spec.tsx | 2 +- .../variable-selector.spec.tsx | 2 +- .../{ => __tests__}/hooks.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/option.spec.tsx | 2 +- .../{ => __tests__}/trigger.spec.tsx | 2 +- .../{ => __tests__}/types.spec.ts | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/placeholder.spec.tsx | 2 +- .../form/{ => __tests__}/actions.spec.tsx | 8 ++++---- .../auth/{ => __tests__}/index.spec.tsx | 2 +- .../base/{ => __tests__}/field.spec.tsx | 8 ++++---- .../base/{ => __tests__}/index.spec.tsx | 4 ++-- .../base/{ => __tests__}/types.spec.ts | 2 +- .../base/{ => __tests__}/utils.spec.ts | 4 ++-- .../{ => __tests__}/contact-fields.spec.tsx | 6 +++--- .../demo/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/shared-options.spec.tsx | 2 +- .../demo/{ => __tests__}/types.spec.ts | 2 +- .../{ => __tests__}/field.spec.tsx | 8 ++++---- .../input-field/{ => __tests__}/types.spec.ts | 2 +- .../input-field/{ => __tests__}/utils.spec.ts | 4 ++-- .../node-panel/{ => __tests__}/field.spec.tsx | 8 ++++---- .../node-panel/{ => __tests__}/types.spec.ts | 2 +- .../form/hooks/{ => __tests__}/index.spec.ts | 8 ++++---- .../use-check-validated.spec.ts | 4 ++-- .../use-get-form-values.spec.ts | 8 ++++---- .../use-get-validators.spec.ts | 4 ++-- .../zod-submit-validator.spec.ts | 2 +- .../{ => __tests__}/index.spec.ts | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/ga/{ => __tests__}/index.spec.tsx | 2 +- .../grid-mask/{ => __tests__}/index.spec.tsx | 4 ++-- .../icons/{ => __tests__}/IconBase.spec.tsx | 8 ++++---- .../base/icons/{ => __tests__}/utils.spec.ts | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/audio-preview.spec.tsx | 2 +- .../chat-image-uploader.spec.tsx | 6 +++--- .../{ => __tests__}/hooks.spec.ts | 4 ++-- .../{ => __tests__}/image-link-input.spec.tsx | 2 +- .../{ => __tests__}/image-list.spec.tsx | 2 +- .../{ => __tests__}/image-preview.spec.tsx | 2 +- .../text-generation-image-uploader.spec.tsx | 6 +++--- .../{ => __tests__}/uploader.spec.tsx | 6 +++--- .../{ => __tests__}/utils.spec.ts | 2 +- .../{ => __tests__}/video-preview.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/input/{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/horizontal-line.spec.tsx | 2 +- .../list-empty/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/vertical-line.spec.tsx | 2 +- .../loading/{ => __tests__}/index.spec.tsx | 2 +- .../logo/{ => __tests__}/dify-logo.spec.tsx | 2 +- .../logo-embedded-chat-avatar.spec.tsx | 2 +- .../logo-embedded-chat-header.spec.tsx | 2 +- .../logo/{ => __tests__}/logo-site.spec.tsx | 2 +- .../{ => __tests__}/audio-block.spec.tsx | 2 +- .../{ => __tests__}/button.spec.tsx | 4 ++-- .../{ => __tests__}/code-block.spec.tsx | 2 +- .../{ => __tests__}/form.spec.tsx | 2 +- .../{ => __tests__}/link.spec.tsx | 4 ++-- .../{ => __tests__}/music.spec.tsx | 2 +- .../{ => __tests__}/paragraph.spec.tsx | 2 +- .../{ => __tests__}/plugin-img.spec.tsx | 4 ++-- .../{ => __tests__}/plugin-paragraph.spec.tsx | 6 +++--- .../{ => __tests__}/pre-code.spec.tsx | 2 +- .../{ => __tests__}/script-block.spec.tsx | 2 +- .../{ => __tests__}/think-block.spec.tsx | 2 +- .../{ => __tests__}/video-block.spec.tsx | 4 ++-- .../{ => __tests__}/error-boundary.spec.tsx | 2 +- .../markdown/{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/markdown-utils.spec.ts | 6 +++--- .../react-markdown-wrapper.spec.tsx | 2 +- .../mermaid/{ => __tests__}/index.spec.tsx | 10 +++++----- .../mermaid/{ => __tests__}/utils.spec.ts | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/modal/{ => __tests__}/index.spec.tsx | 2 +- .../base/modal/{ => __tests__}/modal.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/base.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../pagination/{ => __tests__}/hook.spec.ts | 2 +- .../pagination/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/pagination.spec.tsx | 2 +- .../{ => __tests__}/index-slider.spec.tsx | 2 +- .../param-item/{ => __tests__}/index.spec.tsx | 4 ++-- .../score-threshold-item.spec.tsx | 2 +- .../{ => __tests__}/top-k-item.spec.tsx | 2 +- .../popover/{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/progress-circle.spec.tsx | 2 +- .../{ => __tests__}/constants.spec.tsx | 4 ++-- .../{ => __tests__}/hooks.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/utils.spec.ts | 8 ++++---- .../on-blur-or-focus-block.spec.tsx | 6 +++--- .../{ => __tests__}/placeholder.spec.tsx | 2 +- .../{ => __tests__}/tree-view.spec.tsx | 4 ++-- .../{ => __tests__}/update-block.spec.tsx | 8 ++++---- .../{ => __tests__}/hooks.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 16 +++++++-------- .../{ => __tests__}/menu.spec.tsx | 2 +- .../{ => __tests__}/prompt-option.spec.tsx | 2 +- .../{ => __tests__}/variable-option.spec.tsx | 2 +- .../{ => __tests__}/component.spec.tsx | 6 +++--- .../context-block-replacement-block.spec.tsx | 8 ++++---- .../{ => __tests__}/index.spec.tsx | 12 +++++------ .../{ => __tests__}/node.spec.tsx | 4 ++-- .../{ => __tests__}/component.spec.tsx | 8 ++++---- .../current-block-replacement-block.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/node.spec.tsx | 6 +++--- .../custom-text/{ => __tests__}/node.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/component.spec.tsx | 8 ++++---- ...r-message-block-replacement-block.spec.tsx | 14 ++++++------- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/node.spec.tsx | 2 +- .../{ => __tests__}/component.spec.tsx | 10 +++++----- .../history-block-replacement-block.spec.tsx | 12 +++++------ .../{ => __tests__}/index.spec.tsx | 10 +++++----- .../{ => __tests__}/node.spec.tsx | 8 ++++---- .../{ => __tests__}/component.spec.tsx | 6 +++--- ...itl-input-block-replacement-block.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/input-field.spec.tsx | 2 +- .../{ => __tests__}/node.spec.tsx | 6 +++--- .../{ => __tests__}/pre-populate.spec.tsx | 2 +- .../{ => __tests__}/tag-label.spec.tsx | 2 +- .../{ => __tests__}/type-switch.spec.tsx | 2 +- .../{ => __tests__}/variable-block.spec.tsx | 10 +++++----- .../{ => __tests__}/component.spec.tsx | 8 ++++---- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../last-run-block-replacement-block.spec.tsx | 10 +++++----- .../{ => __tests__}/node.spec.tsx | 6 +++--- .../{ => __tests__}/component.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../query-block/{ => __tests__}/node.spec.tsx | 6 +++--- .../query-block-replacement-block.spec.tsx | 10 +++++----- .../{ => __tests__}/component.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/node.spec.tsx | 6 +++--- ...quest-url-block-replacement-block.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../{ => __tests__}/index.spec.tsx | 10 +++++----- .../{ => __tests__}/node.spec.tsx | 2 +- .../{ => __tests__}/component.spec.tsx | 10 +++++----- .../{ => __tests__}/index.spec.tsx | 8 ++++---- .../{ => __tests__}/node.spec.tsx | 2 +- ...-variable-block-replacement-block.spec.tsx | 16 +++++++-------- .../{ => __tests__}/card.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../qrcode/{ => __tests__}/index.spec.tsx | 2 +- .../radio-card/{ => __tests__}/index.spec.tsx | 2 +- .../simple/{ => __tests__}/index.spec.tsx | 2 +- .../base/radio/{ => __tests__}/index.spec.tsx | 4 ++-- .../base/radio/{ => __tests__}/ui.spec.tsx | 2 +- .../group/{ => __tests__}/index.spec.tsx | 4 ++-- .../radio/{ => __tests__}/index.spec.tsx | 4 ++-- .../context/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../select/{ => __tests__}/custom.spec.tsx | 4 ++-- .../select/{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/locale-signin.spec.tsx | 2 +- .../select/{ => __tests__}/locale.spec.tsx | 2 +- .../base/select/{ => __tests__}/pure.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 2 +- .../skeleton/{ => __tests__}/index.spec.tsx | 2 +- .../slider/{ => __tests__}/index.spec.tsx | 2 +- .../base/sort/{ => __tests__}/index.spec.tsx | 2 +- .../spinner/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/svg/{ => __tests__}/index.spec.tsx | 2 +- .../switch/{ => __tests__}/index.spec.tsx | 2 +- .../tab-header/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../tab-slider/{ => __tests__}/index.spec.tsx | 2 +- .../tag-input/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/filter.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/panel.spec.tsx | 4 ++-- .../{ => __tests__}/selector.spec.tsx | 5 +++-- .../{ => __tests__}/tag-item-editor.spec.tsx | 4 ++-- .../{ => __tests__}/tag-remove-modal.spec.tsx | 4 ++-- .../{ => __tests__}/trigger.spec.tsx | 2 +- .../base/tag/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/hooks.spec.ts | 2 +- .../textarea/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../base/toast/{ => __tests__}/index.spec.tsx | 2 +- .../tooltip/{ => __tests__}/content.spec.tsx | 2 +- .../tooltip/{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/VideoPlayer.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 2 +- .../{ => __tests__}/index.spec.tsx | 4 ++-- .../{ => __tests__}/index.spec.tsx | 6 +++--- .../zendesk/{ => __tests__}/index.spec.tsx | 2 +- 401 files changed, 820 insertions(+), 819 deletions(-) rename web/app/components/base/{ => __tests__}/alert.spec.tsx (99%) rename web/app/components/base/{ => __tests__}/app-unavailable.spec.tsx (98%) rename web/app/components/base/{ => __tests__}/badge.spec.tsx (99%) rename web/app/components/base/{ => __tests__}/theme-selector.spec.tsx (98%) rename web/app/components/base/{ => __tests__}/theme-switcher.spec.tsx (98%) rename web/app/components/base/action-button/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/agent-log-modal/{ => __tests__}/detail.spec.tsx (99%) rename web/app/components/base/agent-log-modal/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/agent-log-modal/{ => __tests__}/iteration.spec.tsx (98%) rename web/app/components/base/agent-log-modal/{ => __tests__}/result.spec.tsx (98%) rename web/app/components/base/agent-log-modal/{ => __tests__}/tool-call.spec.tsx (99%) rename web/app/components/base/agent-log-modal/{ => __tests__}/tracing.spec.tsx (97%) rename web/app/components/base/answer-icon/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/app-icon-picker/{ => __tests__}/ImageInput.spec.tsx (99%) rename web/app/components/base/app-icon-picker/{ => __tests__}/hooks.spec.tsx (98%) rename web/app/components/base/app-icon-picker/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/app-icon-picker/{ => __tests__}/utils.spec.ts (99%) rename web/app/components/base/app-icon/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/audio-btn/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/audio-gallery/{ => __tests__}/AudioPlayer.spec.tsx (99%) rename web/app/components/base/audio-gallery/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/auto-height-textarea/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/avatar/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/badge/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/block-input/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/button/{ => __tests__}/add-button.spec.tsx (97%) rename web/app/components/base/button/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/button/{ => __tests__}/sync-button.spec.tsx (97%) rename web/app/components/base/carousel/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/chat/chat-with-history/{ => __tests__}/chat-wrapper.spec.tsx (99%) rename web/app/components/base/chat/chat-with-history/{ => __tests__}/header-in-mobile.spec.tsx (98%) rename web/app/components/base/chat/chat-with-history/{ => __tests__}/hooks.spec.tsx (97%) rename web/app/components/base/chat/chat-with-history/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/chat/chat-with-history/header/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/chat/chat-with-history/header/{ => __tests__}/mobile-operation-dropdown.spec.tsx (97%) rename web/app/components/base/chat/chat-with-history/header/{ => __tests__}/operation.spec.tsx (98%) rename web/app/components/base/chat/chat-with-history/inputs-form/{ => __tests__}/content.spec.tsx (98%) rename web/app/components/base/chat/chat-with-history/inputs-form/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/chat/chat-with-history/inputs-form/{ => __tests__}/view-form-dropdown.spec.tsx (94%) rename web/app/components/base/chat/chat-with-history/sidebar/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/chat/chat-with-history/sidebar/{ => __tests__}/item.spec.tsx (99%) rename web/app/components/base/chat/chat-with-history/sidebar/{ => __tests__}/list.spec.tsx (96%) rename web/app/components/base/chat/chat-with-history/sidebar/{ => __tests__}/operation.spec.tsx (99%) rename web/app/components/base/chat/chat-with-history/sidebar/{ => __tests__}/rename-modal.spec.tsx (98%) rename web/app/components/base/chat/chat/{ => __tests__}/content-switch.spec.tsx (98%) rename web/app/components/base/chat/chat/{ => __tests__}/context.spec.tsx (94%) rename web/app/components/base/chat/chat/{ => __tests__}/hooks.multimodal.spec.ts (100%) rename web/app/components/base/chat/chat/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/chat/chat/{ => __tests__}/question.spec.tsx (97%) rename web/app/components/base/chat/chat/{ => __tests__}/try-to-ask.spec.tsx (97%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/agent-content.spec.tsx (97%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/basic-content.spec.tsx (97%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/human-input-filled-form-list.spec.tsx (96%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/human-input-form-list.spec.tsx (96%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/more.spec.tsx (98%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/operation.spec.tsx (99%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/suggested-questions.spec.tsx (93%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/tool-detail.spec.tsx (96%) rename web/app/components/base/chat/chat/answer/{ => __tests__}/workflow-process.spec.tsx (98%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/content-item.spec.tsx (98%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/content-wrapper.spec.tsx (97%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/executed-action.spec.tsx (94%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/expiration-time.spec.tsx (87%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/human-input-form.spec.tsx (98%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/submitted-content.spec.tsx (92%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/submitted.spec.tsx (95%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/tips.spec.tsx (98%) rename web/app/components/base/chat/chat/answer/human-input-content/{ => __tests__}/unsubmitted.spec.tsx (99%) rename web/app/components/base/chat/chat/chat-input-area/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/chat/chat/chat-input-area/{ => __tests__}/operation.spec.tsx (96%) rename web/app/components/base/chat/chat/citation/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/chat/chat/citation/{ => __tests__}/popup.spec.tsx (99%) rename web/app/components/base/chat/chat/citation/{ => __tests__}/progress-tooltip.spec.tsx (99%) rename web/app/components/base/chat/chat/citation/{ => __tests__}/tooltip.spec.tsx (99%) rename web/app/components/base/chat/chat/loading-anim/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/chat/chat/log/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/chat/chat/thought/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/chat/embedded-chatbot/{ => __tests__}/chat-wrapper.spec.tsx (97%) rename web/app/components/base/chat/embedded-chatbot/{ => __tests__}/hooks.spec.tsx (97%) rename web/app/components/base/chat/embedded-chatbot/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/chat/embedded-chatbot/header/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/chat/embedded-chatbot/inputs-form/{ => __tests__}/content.spec.tsx (98%) rename web/app/components/base/chat/embedded-chatbot/inputs-form/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/chat/embedded-chatbot/inputs-form/{ => __tests__}/view-form-dropdown.spec.tsx (95%) rename web/app/components/base/checkbox-list/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/checkbox/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/checkbox/assets/{ => __tests__}/indeterminate-icon.spec.tsx (90%) rename web/app/components/base/chip/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/confirm/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/content-dialog/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/copy-feedback/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/copy-icon/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/corner-label/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/date-and-time-picker/{ => __tests__}/hooks.spec.ts (97%) rename web/app/components/base/date-and-time-picker/calendar/{ => __tests__}/days-of-week.spec.tsx (93%) rename web/app/components/base/date-and-time-picker/calendar/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/date-and-time-picker/calendar/{ => __tests__}/item.spec.tsx (97%) rename web/app/components/base/date-and-time-picker/common/{ => __tests__}/option-list-item.spec.tsx (98%) rename web/app/components/base/date-and-time-picker/date-picker/{ => __tests__}/footer.spec.tsx (96%) rename web/app/components/base/date-and-time-picker/date-picker/{ => __tests__}/header.spec.tsx (95%) rename web/app/components/base/date-and-time-picker/date-picker/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/date-and-time-picker/time-picker/{ => __tests__}/footer.spec.tsx (94%) rename web/app/components/base/date-and-time-picker/time-picker/{ => __tests__}/header.spec.tsx (96%) rename web/app/components/base/date-and-time-picker/time-picker/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/date-and-time-picker/time-picker/{ => __tests__}/options.spec.tsx (96%) rename web/app/components/base/date-and-time-picker/utils/{ => __tests__}/dayjs-extended.spec.ts (99%) rename web/app/components/base/date-and-time-picker/utils/{ => __tests__}/dayjs.spec.ts (99%) rename web/app/components/base/date-and-time-picker/year-and-month-picker/{ => __tests__}/footer.spec.tsx (94%) rename web/app/components/base/date-and-time-picker/year-and-month-picker/{ => __tests__}/header.spec.tsx (92%) rename web/app/components/base/date-and-time-picker/year-and-month-picker/{ => __tests__}/options.spec.tsx (95%) rename web/app/components/base/dialog/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/divider/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/drawer-plus/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/drawer/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/dropdown/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/effect/{ => __tests__}/index.spec.tsx (91%) rename web/app/components/base/emoji-picker/{ => __tests__}/Inner.spec.tsx (99%) rename web/app/components/base/emoji-picker/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/encrypted-bottom/{ => __tests__}/index.spec.tsx (94%) rename web/app/components/base/error-boundary/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/features/{ => __tests__}/context.spec.tsx (96%) rename web/app/components/base/features/{ => __tests__}/hooks.spec.ts (92%) rename web/app/components/base/features/{ => __tests__}/store.spec.ts (99%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/citation.spec.tsx (90%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/dialog-wrapper.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/feature-bar.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/feature-card.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/follow-up.spec.tsx (90%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/more-like-this.spec.tsx (91%) rename web/app/components/base/features/new-feature-panel/{ => __tests__}/speech-to-text.spec.tsx (89%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/annotation-ctrl-button.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/config-param-modal.spec.tsx (99%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/config-param.spec.tsx (96%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/type.spec.ts (83%) rename web/app/components/base/features/new-feature-panel/annotation-reply/{ => __tests__}/use-annotation-config.spec.ts (99%) rename web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/conversation-opener/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/conversation-opener/{ => __tests__}/modal.spec.tsx (99%) rename web/app/components/base/features/new-feature-panel/file-upload/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/file-upload/{ => __tests__}/setting-content.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/file-upload/{ => __tests__}/setting-modal.spec.tsx (96%) rename web/app/components/base/features/new-feature-panel/image-upload/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/features/new-feature-panel/moderation/{ => __tests__}/form-generation.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/moderation/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/moderation/{ => __tests__}/moderation-content.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/moderation/{ => __tests__}/moderation-setting-modal.spec.tsx (99%) rename web/app/components/base/features/new-feature-panel/text-to-speech/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/features/new-feature-panel/text-to-speech/{ => __tests__}/param-config-content.spec.tsx (98%) rename web/app/components/base/features/new-feature-panel/text-to-speech/{ => __tests__}/voice-settings.spec.tsx (95%) rename web/app/components/base/file-icon/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/file-thumb/{ => __tests__}/image-render.spec.tsx (92%) rename web/app/components/base/file-thumb/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/file-uploader/{ => __tests__}/audio-preview.spec.tsx (98%) rename web/app/components/base/file-uploader/{ => __tests__}/constants.spec.ts (99%) rename web/app/components/base/file-uploader/{ => __tests__}/file-image-render.spec.tsx (97%) rename web/app/components/base/file-uploader/{ => __tests__}/file-input.spec.tsx (97%) rename web/app/components/base/file-uploader/{ => __tests__}/file-list-in-log.spec.tsx (98%) rename web/app/components/base/file-uploader/{ => __tests__}/file-type-icon.spec.tsx (96%) rename web/app/components/base/file-uploader/{ => __tests__}/hooks.spec.ts (99%) rename web/app/components/base/file-uploader/{ => __tests__}/pdf-preview.spec.tsx (98%) rename web/app/components/base/file-uploader/{ => __tests__}/store.spec.tsx (98%) rename web/app/components/base/file-uploader/{ => __tests__}/utils.spec.ts (98%) rename web/app/components/base/file-uploader/{ => __tests__}/video-preview.spec.tsx (98%) rename web/app/components/base/file-uploader/file-from-link-or-local/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/file-uploader/file-uploader-in-attachment/{ => __tests__}/file-item.spec.tsx (99%) rename web/app/components/base/file-uploader/file-uploader-in-attachment/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/file-uploader/file-uploader-in-chat-input/{ => __tests__}/file-image-item.spec.tsx (99%) rename web/app/components/base/file-uploader/file-uploader-in-chat-input/{ => __tests__}/file-item.spec.tsx (98%) rename web/app/components/base/file-uploader/file-uploader-in-chat-input/{ => __tests__}/file-list.spec.tsx (95%) rename web/app/components/base/file-uploader/file-uploader-in-chat-input/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/float-right-container/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/form/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/form/{ => __tests__}/types.spec.ts (88%) rename web/app/components/base/form/components/{ => __tests__}/label.spec.tsx (98%) rename web/app/components/base/form/components/base/{ => __tests__}/base-field.spec.tsx (99%) rename web/app/components/base/form/components/base/{ => __tests__}/base-form.spec.tsx (98%) rename web/app/components/base/form/components/base/{ => __tests__}/index.spec.tsx (83%) rename web/app/components/base/form/components/field/{ => __tests__}/checkbox.spec.tsx (92%) rename web/app/components/base/form/components/field/{ => __tests__}/custom-select.spec.tsx (93%) rename web/app/components/base/form/components/field/{ => __tests__}/file-types.spec.tsx (98%) rename web/app/components/base/form/components/field/{ => __tests__}/file-uploader.spec.tsx (96%) rename web/app/components/base/form/components/field/{ => __tests__}/number-input.spec.tsx (90%) rename web/app/components/base/form/components/field/{ => __tests__}/number-slider.spec.tsx (93%) rename web/app/components/base/form/components/field/{ => __tests__}/options.spec.tsx (94%) rename web/app/components/base/form/components/field/{ => __tests__}/select.spec.tsx (94%) rename web/app/components/base/form/components/field/{ => __tests__}/text-area.spec.tsx (92%) rename web/app/components/base/form/components/field/{ => __tests__}/text.spec.tsx (92%) rename web/app/components/base/form/components/field/{ => __tests__}/upload-method.spec.tsx (95%) rename web/app/components/base/form/components/field/{ => __tests__}/variable-or-constant-input.spec.tsx (96%) rename web/app/components/base/form/components/field/{ => __tests__}/variable-selector.spec.tsx (94%) rename web/app/components/base/form/components/field/input-type-select/{ => __tests__}/hooks.spec.tsx (93%) rename web/app/components/base/form/components/field/input-type-select/{ => __tests__}/index.spec.tsx (93%) rename web/app/components/base/form/components/field/input-type-select/{ => __tests__}/option.spec.tsx (94%) rename web/app/components/base/form/components/field/input-type-select/{ => __tests__}/trigger.spec.tsx (95%) rename web/app/components/base/form/components/field/input-type-select/{ => __tests__}/types.spec.ts (89%) rename web/app/components/base/form/components/field/mixed-variable-text-input/{ => __tests__}/index.spec.tsx (93%) rename web/app/components/base/form/components/field/mixed-variable-text-input/{ => __tests__}/placeholder.spec.tsx (98%) rename web/app/components/base/form/components/form/{ => __tests__}/actions.spec.tsx (92%) rename web/app/components/base/form/form-scenarios/auth/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/form/form-scenarios/base/{ => __tests__}/field.spec.tsx (96%) rename web/app/components/base/form/form-scenarios/base/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/form/form-scenarios/base/{ => __tests__}/types.spec.ts (87%) rename web/app/components/base/form/form-scenarios/base/{ => __tests__}/utils.spec.ts (94%) rename web/app/components/base/form/form-scenarios/demo/{ => __tests__}/contact-fields.spec.tsx (83%) rename web/app/components/base/form/form-scenarios/demo/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/form/form-scenarios/demo/{ => __tests__}/shared-options.spec.tsx (86%) rename web/app/components/base/form/form-scenarios/demo/{ => __tests__}/types.spec.ts (94%) rename web/app/components/base/form/form-scenarios/input-field/{ => __tests__}/field.spec.tsx (96%) rename web/app/components/base/form/form-scenarios/input-field/{ => __tests__}/types.spec.ts (89%) rename web/app/components/base/form/form-scenarios/input-field/{ => __tests__}/utils.spec.ts (97%) rename web/app/components/base/form/form-scenarios/node-panel/{ => __tests__}/field.spec.tsx (96%) rename web/app/components/base/form/form-scenarios/node-panel/{ => __tests__}/types.spec.ts (81%) rename web/app/components/base/form/hooks/{ => __tests__}/index.spec.ts (57%) rename web/app/components/base/form/hooks/{ => __tests__}/use-check-validated.spec.ts (96%) rename web/app/components/base/form/hooks/{ => __tests__}/use-get-form-values.spec.ts (91%) rename web/app/components/base/form/hooks/{ => __tests__}/use-get-validators.spec.ts (96%) rename web/app/components/base/form/utils/{ => __tests__}/zod-submit-validator.spec.ts (94%) rename web/app/components/base/form/utils/secret-input/{ => __tests__}/index.spec.ts (95%) rename web/app/components/base/fullscreen-modal/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/ga/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/grid-mask/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/icons/{ => __tests__}/IconBase.spec.tsx (92%) rename web/app/components/base/icons/{ => __tests__}/utils.spec.ts (95%) rename web/app/components/base/image-gallery/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/image-uploader/{ => __tests__}/audio-preview.spec.tsx (98%) rename web/app/components/base/image-uploader/{ => __tests__}/chat-image-uploader.spec.tsx (98%) rename web/app/components/base/image-uploader/{ => __tests__}/hooks.spec.ts (99%) rename web/app/components/base/image-uploader/{ => __tests__}/image-link-input.spec.tsx (99%) rename web/app/components/base/image-uploader/{ => __tests__}/image-list.spec.tsx (99%) rename web/app/components/base/image-uploader/{ => __tests__}/image-preview.spec.tsx (99%) rename web/app/components/base/image-uploader/{ => __tests__}/text-generation-image-uploader.spec.tsx (98%) rename web/app/components/base/image-uploader/{ => __tests__}/uploader.spec.tsx (97%) rename web/app/components/base/image-uploader/{ => __tests__}/utils.spec.ts (98%) rename web/app/components/base/image-uploader/{ => __tests__}/video-preview.spec.tsx (98%) rename web/app/components/base/inline-delete-confirm/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/input-number/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/input-with-copy/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/input/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/linked-apps-panel/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/list-empty/{ => __tests__}/horizontal-line.spec.tsx (95%) rename web/app/components/base/list-empty/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/list-empty/{ => __tests__}/vertical-line.spec.tsx (96%) rename web/app/components/base/loading/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/logo/{ => __tests__}/dify-logo.spec.tsx (98%) rename web/app/components/base/logo/{ => __tests__}/logo-embedded-chat-avatar.spec.tsx (93%) rename web/app/components/base/logo/{ => __tests__}/logo-embedded-chat-header.spec.tsx (94%) rename web/app/components/base/logo/{ => __tests__}/logo-site.spec.tsx (94%) rename web/app/components/base/markdown-blocks/{ => __tests__}/audio-block.spec.tsx (98%) rename web/app/components/base/markdown-blocks/{ => __tests__}/button.spec.tsx (98%) rename web/app/components/base/markdown-blocks/{ => __tests__}/code-block.spec.tsx (99%) rename web/app/components/base/markdown-blocks/{ => __tests__}/form.spec.tsx (99%) rename web/app/components/base/markdown-blocks/{ => __tests__}/link.spec.tsx (98%) rename web/app/components/base/markdown-blocks/{ => __tests__}/music.spec.tsx (97%) rename web/app/components/base/markdown-blocks/{ => __tests__}/paragraph.spec.tsx (98%) rename web/app/components/base/markdown-blocks/{ => __tests__}/plugin-img.spec.tsx (97%) rename web/app/components/base/markdown-blocks/{ => __tests__}/plugin-paragraph.spec.tsx (97%) rename web/app/components/base/markdown-blocks/{ => __tests__}/pre-code.spec.tsx (98%) rename web/app/components/base/markdown-blocks/{ => __tests__}/script-block.spec.tsx (97%) rename web/app/components/base/markdown-blocks/{ => __tests__}/think-block.spec.tsx (99%) rename web/app/components/base/markdown-blocks/{ => __tests__}/video-block.spec.tsx (96%) rename web/app/components/base/markdown/{ => __tests__}/error-boundary.spec.tsx (96%) rename web/app/components/base/markdown/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/markdown/{ => __tests__}/markdown-utils.spec.ts (97%) rename web/app/components/base/markdown/{ => __tests__}/react-markdown-wrapper.spec.tsx (98%) rename web/app/components/base/mermaid/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/mermaid/{ => __tests__}/utils.spec.ts (99%) rename web/app/components/base/message-log-modal/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/modal-like-wrap/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/modal/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/modal/{ => __tests__}/modal.spec.tsx (99%) rename web/app/components/base/new-audio-button/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/node-status/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/notion-connector/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/notion-icon/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/notion-page-selector/{ => __tests__}/base.spec.tsx (98%) rename web/app/components/base/notion-page-selector/credential-selector/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/notion-page-selector/page-selector/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/notion-page-selector/search-input/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/pagination/{ => __tests__}/hook.spec.ts (99%) rename web/app/components/base/pagination/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/pagination/{ => __tests__}/pagination.spec.tsx (99%) rename web/app/components/base/param-item/{ => __tests__}/index-slider.spec.tsx (97%) rename web/app/components/base/param-item/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/param-item/{ => __tests__}/score-threshold-item.spec.tsx (98%) rename web/app/components/base/param-item/{ => __tests__}/top-k-item.spec.tsx (99%) rename web/app/components/base/popover/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/portal-to-follow-elem/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/premium-badge/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/progress-bar/{ => __tests__}/progress-circle.spec.tsx (98%) rename web/app/components/base/prompt-editor/{ => __tests__}/constants.spec.tsx (97%) rename web/app/components/base/prompt-editor/{ => __tests__}/hooks.spec.tsx (97%) rename web/app/components/base/prompt-editor/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/prompt-editor/{ => __tests__}/utils.spec.ts (98%) rename web/app/components/base/prompt-editor/plugins/{ => __tests__}/on-blur-or-focus-block.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/{ => __tests__}/placeholder.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/{ => __tests__}/tree-view.spec.tsx (95%) rename web/app/components/base/prompt-editor/plugins/{ => __tests__}/update-block.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/component-picker-block/{ => __tests__}/hooks.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/component-picker-block/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/component-picker-block/{ => __tests__}/menu.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/component-picker-block/{ => __tests__}/prompt-option.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/component-picker-block/{ => __tests__}/variable-option.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/context-block/{ => __tests__}/component.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/context-block/{ => __tests__}/context-block-replacement-block.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/context-block/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/context-block/{ => __tests__}/node.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/current-block/{ => __tests__}/component.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/current-block/{ => __tests__}/current-block-replacement-block.spec.tsx (93%) rename web/app/components/base/prompt-editor/plugins/current-block/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/current-block/{ => __tests__}/node.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/custom-text/{ => __tests__}/node.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/draggable-plugin/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/error-message-block/{ => __tests__}/component.spec.tsx (95%) rename web/app/components/base/prompt-editor/plugins/error-message-block/{ => __tests__}/error-message-block-replacement-block.spec.tsx (93%) rename web/app/components/base/prompt-editor/plugins/error-message-block/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/error-message-block/{ => __tests__}/node.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/history-block/{ => __tests__}/component.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/history-block/{ => __tests__}/history-block-replacement-block.spec.tsx (91%) rename web/app/components/base/prompt-editor/plugins/history-block/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/prompt-editor/plugins/history-block/{ => __tests__}/node.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/component.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/hitl-input-block-replacement-block.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/input-field.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/node.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/pre-populate.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/tag-label.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/type-switch.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/hitl-input-block/{ => __tests__}/variable-block.spec.tsx (95%) rename web/app/components/base/prompt-editor/plugins/last-run-block/{ => __tests__}/component.spec.tsx (93%) rename web/app/components/base/prompt-editor/plugins/last-run-block/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/last-run-block/{ => __tests__}/last-run-block-replacement-block.spec.tsx (91%) rename web/app/components/base/prompt-editor/plugins/last-run-block/{ => __tests__}/node.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/query-block/{ => __tests__}/component.spec.tsx (92%) rename web/app/components/base/prompt-editor/plugins/query-block/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/query-block/{ => __tests__}/node.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/query-block/{ => __tests__}/query-block-replacement-block.spec.tsx (91%) rename web/app/components/base/prompt-editor/plugins/request-url-block/{ => __tests__}/component.spec.tsx (92%) rename web/app/components/base/prompt-editor/plugins/request-url-block/{ => __tests__}/index.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/request-url-block/{ => __tests__}/node.spec.tsx (96%) rename web/app/components/base/prompt-editor/plugins/request-url-block/{ => __tests__}/request-url-block-replacement-block.spec.tsx (90%) rename web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/variable-block/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/prompt-editor/plugins/variable-value-block/{ => __tests__}/index.spec.tsx (94%) rename web/app/components/base/prompt-editor/plugins/variable-value-block/{ => __tests__}/node.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/workflow-variable-block/{ => __tests__}/component.spec.tsx (98%) rename web/app/components/base/prompt-editor/plugins/workflow-variable-block/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/prompt-editor/plugins/workflow-variable-block/{ => __tests__}/node.spec.tsx (99%) rename web/app/components/base/prompt-editor/plugins/workflow-variable-block/{ => __tests__}/workflow-variable-block-replacement-block.spec.tsx (94%) rename web/app/components/base/prompt-log-modal/{ => __tests__}/card.spec.tsx (96%) rename web/app/components/base/prompt-log-modal/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/qrcode/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/radio-card/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/radio-card/simple/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/radio/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/radio/{ => __tests__}/ui.spec.tsx (98%) rename web/app/components/base/radio/component/group/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/radio/component/radio/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/radio/context/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/search-input/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/segmented-control/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/select/{ => __tests__}/custom.spec.tsx (98%) rename web/app/components/base/select/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/select/{ => __tests__}/locale-signin.spec.tsx (98%) rename web/app/components/base/select/{ => __tests__}/locale.spec.tsx (98%) rename web/app/components/base/select/{ => __tests__}/pure.spec.tsx (98%) rename web/app/components/base/simple-pie-chart/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/skeleton/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/slider/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/sort/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/spinner/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/svg-gallery/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/svg/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/switch/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tab-header/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tab-slider-new/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/tab-slider-plain/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tab-slider/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tag-input/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tag-management/{ => __tests__}/filter.spec.tsx (99%) rename web/app/components/base/tag-management/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/tag-management/{ => __tests__}/panel.spec.tsx (99%) rename web/app/components/base/tag-management/{ => __tests__}/selector.spec.tsx (98%) rename web/app/components/base/tag-management/{ => __tests__}/tag-item-editor.spec.tsx (98%) rename web/app/components/base/tag-management/{ => __tests__}/tag-remove-modal.spec.tsx (97%) rename web/app/components/base/tag-management/{ => __tests__}/trigger.spec.tsx (98%) rename web/app/components/base/tag/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/text-generation/{ => __tests__}/hooks.spec.ts (99%) rename web/app/components/base/textarea/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/timezone-label/{ => __tests__}/index.spec.tsx (97%) rename web/app/components/base/toast/{ => __tests__}/index.spec.tsx (98%) rename web/app/components/base/tooltip/{ => __tests__}/content.spec.tsx (97%) rename web/app/components/base/tooltip/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/video-gallery/{ => __tests__}/VideoPlayer.spec.tsx (99%) rename web/app/components/base/video-gallery/{ => __tests__}/index.spec.tsx (95%) rename web/app/components/base/voice-input/{ => __tests__}/index.spec.tsx (99%) rename web/app/components/base/with-input-validation/{ => __tests__}/index.spec.tsx (85%) rename web/app/components/base/zendesk/{ => __tests__}/index.spec.tsx (99%) diff --git a/web/app/components/base/alert.spec.tsx b/web/app/components/base/__tests__/alert.spec.tsx similarity index 99% rename from web/app/components/base/alert.spec.tsx rename to web/app/components/base/__tests__/alert.spec.tsx index 1ad52ea201..10c1a6bbfa 100644 --- a/web/app/components/base/alert.spec.tsx +++ b/web/app/components/base/__tests__/alert.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import Alert from './alert' +import Alert from '../alert' describe('Alert', () => { const defaultProps = { diff --git a/web/app/components/base/app-unavailable.spec.tsx b/web/app/components/base/__tests__/app-unavailable.spec.tsx similarity index 98% rename from web/app/components/base/app-unavailable.spec.tsx rename to web/app/components/base/__tests__/app-unavailable.spec.tsx index 27fb359781..cce3240d20 100644 --- a/web/app/components/base/app-unavailable.spec.tsx +++ b/web/app/components/base/__tests__/app-unavailable.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import AppUnavailable from './app-unavailable' +import AppUnavailable from '../app-unavailable' describe('AppUnavailable', () => { beforeEach(() => { diff --git a/web/app/components/base/badge.spec.tsx b/web/app/components/base/__tests__/badge.spec.tsx similarity index 99% rename from web/app/components/base/badge.spec.tsx rename to web/app/components/base/__tests__/badge.spec.tsx index 5ca5cfe789..8da348ec90 100644 --- a/web/app/components/base/badge.spec.tsx +++ b/web/app/components/base/__tests__/badge.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Badge from './badge' +import Badge from '../badge' describe('Badge', () => { describe('Rendering', () => { diff --git a/web/app/components/base/theme-selector.spec.tsx b/web/app/components/base/__tests__/theme-selector.spec.tsx similarity index 98% rename from web/app/components/base/theme-selector.spec.tsx rename to web/app/components/base/__tests__/theme-selector.spec.tsx index 8cd0028acf..1286ee73be 100644 --- a/web/app/components/base/theme-selector.spec.tsx +++ b/web/app/components/base/__tests__/theme-selector.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import ThemeSelector from './theme-selector' +import ThemeSelector from '../theme-selector' // Mock next-themes with controllable state let mockTheme = 'system' diff --git a/web/app/components/base/theme-switcher.spec.tsx b/web/app/components/base/__tests__/theme-switcher.spec.tsx similarity index 98% rename from web/app/components/base/theme-switcher.spec.tsx rename to web/app/components/base/__tests__/theme-switcher.spec.tsx index e19fbd3835..d8ed427d95 100644 --- a/web/app/components/base/theme-switcher.spec.tsx +++ b/web/app/components/base/__tests__/theme-switcher.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import ThemeSwitcher from './theme-switcher' +import ThemeSwitcher from '../theme-switcher' let mockTheme = 'system' const mockSetTheme = vi.fn() diff --git a/web/app/components/base/action-button/index.spec.tsx b/web/app/components/base/action-button/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/action-button/index.spec.tsx rename to web/app/components/base/action-button/__tests__/index.spec.tsx index 839cd9dcc3..949a980272 100644 --- a/web/app/components/base/action-button/index.spec.tsx +++ b/web/app/components/base/action-button/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import { ActionButton, ActionButtonState } from './index' +import { ActionButton, ActionButtonState } from '../index' describe('ActionButton', () => { it('renders button with default props', () => { diff --git a/web/app/components/base/agent-log-modal/detail.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/detail.spec.tsx similarity index 99% rename from web/app/components/base/agent-log-modal/detail.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/detail.spec.tsx index dd663ac892..c77f144da2 100644 --- a/web/app/components/base/agent-log-modal/detail.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/detail.spec.tsx @@ -4,7 +4,7 @@ import type { AgentLogDetailResponse } from '@/models/log' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { ToastContext } from '@/app/components/base/toast' import { fetchAgentLogDetail } from '@/service/log' -import AgentLogDetail from './detail' +import AgentLogDetail from '../detail' vi.mock('@/service/log', () => ({ fetchAgentLogDetail: vi.fn(), diff --git a/web/app/components/base/agent-log-modal/index.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/agent-log-modal/index.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/index.spec.tsx index 17c9bc8cf1..6b59e90c77 100644 --- a/web/app/components/base/agent-log-modal/index.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/index.spec.tsx @@ -3,7 +3,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { useClickAway } from 'ahooks' import { ToastContext } from '@/app/components/base/toast' import { fetchAgentLogDetail } from '@/service/log' -import AgentLogModal from './index' +import AgentLogModal from '../index' vi.mock('@/service/log', () => ({ fetchAgentLogDetail: vi.fn(), diff --git a/web/app/components/base/agent-log-modal/iteration.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/iteration.spec.tsx similarity index 98% rename from web/app/components/base/agent-log-modal/iteration.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/iteration.spec.tsx index 15d5b815fb..8266d2f460 100644 --- a/web/app/components/base/agent-log-modal/iteration.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/iteration.spec.tsx @@ -1,6 +1,6 @@ import type { AgentIteration } from '@/models/log' import { render, screen } from '@testing-library/react' -import Iteration from './iteration' +import Iteration from '../iteration' vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({ default: ({ title, value }: { title: React.ReactNode, value: string | object }) => ( diff --git a/web/app/components/base/agent-log-modal/result.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/result.spec.tsx similarity index 98% rename from web/app/components/base/agent-log-modal/result.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/result.spec.tsx index 846d433cab..6fcf4c1859 100644 --- a/web/app/components/base/agent-log-modal/result.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/result.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' -import ResultPanel from './result' +import ResultPanel from '../result' vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({ default: ({ title, value }: { title: React.ReactNode, value: string | object }) => ( diff --git a/web/app/components/base/agent-log-modal/tool-call.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/tool-call.spec.tsx similarity index 99% rename from web/app/components/base/agent-log-modal/tool-call.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/tool-call.spec.tsx index 496049a8a8..a5d6aa8d81 100644 --- a/web/app/components/base/agent-log-modal/tool-call.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/tool-call.spec.tsx @@ -2,7 +2,7 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' import { describe, expect, it, vi } from 'vitest' import { BlockEnum } from '@/app/components/workflow/types' -import ToolCallItem from './tool-call' +import ToolCallItem from '../tool-call' vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({ default: ({ title, value }: { title: React.ReactNode, value: string | object }) => ( diff --git a/web/app/components/base/agent-log-modal/tracing.spec.tsx b/web/app/components/base/agent-log-modal/__tests__/tracing.spec.tsx similarity index 97% rename from web/app/components/base/agent-log-modal/tracing.spec.tsx rename to web/app/components/base/agent-log-modal/__tests__/tracing.spec.tsx index e0f4a81f99..0e2bb38476 100644 --- a/web/app/components/base/agent-log-modal/tracing.spec.tsx +++ b/web/app/components/base/agent-log-modal/__tests__/tracing.spec.tsx @@ -1,7 +1,7 @@ import type { AgentIteration } from '@/models/log' import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import TracingPanel from './tracing' +import TracingPanel from '../tracing' vi.mock('@/app/components/workflow/block-icon', () => ({ default: () =>
, diff --git a/web/app/components/base/answer-icon/index.spec.tsx b/web/app/components/base/answer-icon/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/answer-icon/index.spec.tsx rename to web/app/components/base/answer-icon/__tests__/index.spec.tsx index 72573fca5b..5bfb672202 100644 --- a/web/app/components/base/answer-icon/index.spec.tsx +++ b/web/app/components/base/answer-icon/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import AnswerIcon from '.' +import AnswerIcon from '..' describe('AnswerIcon', () => { it('renders default emoji when no icon or image is provided', () => { diff --git a/web/app/components/base/app-icon-picker/ImageInput.spec.tsx b/web/app/components/base/app-icon-picker/__tests__/ImageInput.spec.tsx similarity index 99% rename from web/app/components/base/app-icon-picker/ImageInput.spec.tsx rename to web/app/components/base/app-icon-picker/__tests__/ImageInput.spec.tsx index 8e0476823a..19825b4a1c 100644 --- a/web/app/components/base/app-icon-picker/ImageInput.spec.tsx +++ b/web/app/components/base/app-icon-picker/__tests__/ImageInput.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import ImageInput from './ImageInput' +import ImageInput from '../ImageInput' const createObjectURLMock = vi.fn(() => 'blob:mock-url') const revokeObjectURLMock = vi.fn() diff --git a/web/app/components/base/app-icon-picker/hooks.spec.tsx b/web/app/components/base/app-icon-picker/__tests__/hooks.spec.tsx similarity index 98% rename from web/app/components/base/app-icon-picker/hooks.spec.tsx rename to web/app/components/base/app-icon-picker/__tests__/hooks.spec.tsx index 58741a3ecf..e2aa203d23 100644 --- a/web/app/components/base/app-icon-picker/hooks.spec.tsx +++ b/web/app/components/base/app-icon-picker/__tests__/hooks.spec.tsx @@ -1,5 +1,5 @@ import { act, renderHook } from '@testing-library/react' -import { useDraggableUploader } from './hooks' +import { useDraggableUploader } from '../hooks' type MockDragEventOverrides = { dataTransfer?: { files: File[] } diff --git a/web/app/components/base/app-icon-picker/index.spec.tsx b/web/app/components/base/app-icon-picker/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/app-icon-picker/index.spec.tsx rename to web/app/components/base/app-icon-picker/__tests__/index.spec.tsx index 63d447e289..8334512047 100644 --- a/web/app/components/base/app-icon-picker/index.spec.tsx +++ b/web/app/components/base/app-icon-picker/__tests__/index.spec.tsx @@ -3,7 +3,7 @@ import type { ImageFile } from '@/types/app' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { TransferMethod } from '@/types/app' -import AppIconPicker from './index' +import AppIconPicker from '../index' import 'vitest-canvas-mock' type LocalFileUploaderOptions = { @@ -93,7 +93,7 @@ vi.mock('react-easy-crop', () => ({ ), })) -vi.mock('../image-uploader/hooks', () => ({ +vi.mock('../../image-uploader/hooks', () => ({ useLocalFileUploader: (options: LocalFileUploaderOptions) => { mocks.onUpload = options.onUpload return { handleLocalFileUpload: mocks.handleLocalFileUpload } diff --git a/web/app/components/base/app-icon-picker/utils.spec.ts b/web/app/components/base/app-icon-picker/__tests__/utils.spec.ts similarity index 99% rename from web/app/components/base/app-icon-picker/utils.spec.ts rename to web/app/components/base/app-icon-picker/__tests__/utils.spec.ts index 778d384910..6b706417cf 100644 --- a/web/app/components/base/app-icon-picker/utils.spec.ts +++ b/web/app/components/base/app-icon-picker/__tests__/utils.spec.ts @@ -1,4 +1,4 @@ -import getCroppedImg, { checkIsAnimatedImage, createImage, getMimeType, getRadianAngle, rotateSize } from './utils' +import getCroppedImg, { checkIsAnimatedImage, createImage, getMimeType, getRadianAngle, rotateSize } from '../utils' type ImageLoadEventType = 'load' | 'error' diff --git a/web/app/components/base/app-icon/index.spec.tsx b/web/app/components/base/app-icon/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/app-icon/index.spec.tsx rename to web/app/components/base/app-icon/__tests__/index.spec.tsx index a4895332cd..de59780d7a 100644 --- a/web/app/components/base/app-icon/index.spec.tsx +++ b/web/app/components/base/app-icon/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import AppIcon from './index' +import AppIcon from '../index' // Mock emoji-mart initialization vi.mock('emoji-mart', () => ({ diff --git a/web/app/components/base/audio-btn/index.spec.tsx b/web/app/components/base/audio-btn/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/audio-btn/index.spec.tsx rename to web/app/components/base/audio-btn/__tests__/index.spec.tsx index 5b30f5f737..c8d8ee851b 100644 --- a/web/app/components/base/audio-btn/index.spec.tsx +++ b/web/app/components/base/audio-btn/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { act, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import i18next from 'i18next' import { useParams, usePathname } from 'next/navigation' -import AudioBtn from './index' +import AudioBtn from '../index' const mockPlayAudio = vi.fn() const mockPauseAudio = vi.fn() diff --git a/web/app/components/base/audio-gallery/AudioPlayer.spec.tsx b/web/app/components/base/audio-gallery/__tests__/AudioPlayer.spec.tsx similarity index 99% rename from web/app/components/base/audio-gallery/AudioPlayer.spec.tsx rename to web/app/components/base/audio-gallery/__tests__/AudioPlayer.spec.tsx index fca106867e..cd4371db2c 100644 --- a/web/app/components/base/audio-gallery/AudioPlayer.spec.tsx +++ b/web/app/components/base/audio-gallery/__tests__/AudioPlayer.spec.tsx @@ -4,7 +4,7 @@ import { vi } from 'vitest' import useThemeMock from '@/hooks/use-theme' import { Theme } from '@/types/app' -import AudioPlayer from './AudioPlayer' +import AudioPlayer from '../AudioPlayer' vi.mock('@/hooks/use-theme', () => ({ default: vi.fn(() => ({ theme: 'light' })), diff --git a/web/app/components/base/audio-gallery/index.spec.tsx b/web/app/components/base/audio-gallery/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/audio-gallery/index.spec.tsx rename to web/app/components/base/audio-gallery/__tests__/index.spec.tsx index 9039d4995c..51d707a06e 100644 --- a/web/app/components/base/audio-gallery/index.spec.tsx +++ b/web/app/components/base/audio-gallery/__tests__/index.spec.tsx @@ -3,12 +3,12 @@ import * as React from 'react' // AudioGallery.spec.tsx import { describe, expect, it, vi } from 'vitest' -import AudioGallery from './index' +import AudioGallery from '../index' // Mock AudioPlayer so we only assert prop forwarding const audioPlayerMock = vi.fn() -vi.mock('./AudioPlayer', () => ({ +vi.mock('../AudioPlayer', () => ({ default: (props: { srcs: string[] }) => { audioPlayerMock(props) return
diff --git a/web/app/components/base/auto-height-textarea/index.spec.tsx b/web/app/components/base/auto-height-textarea/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/auto-height-textarea/index.spec.tsx rename to web/app/components/base/auto-height-textarea/__tests__/index.spec.tsx index f6ac0670df..08828d4752 100644 --- a/web/app/components/base/auto-height-textarea/index.spec.tsx +++ b/web/app/components/base/auto-height-textarea/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { sleep } from '@/utils' -import AutoHeightTextarea from './index' +import AutoHeightTextarea from '../index' vi.mock('@/utils', async () => { const actual = await vi.importActual('@/utils') diff --git a/web/app/components/base/avatar/index.spec.tsx b/web/app/components/base/avatar/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/avatar/index.spec.tsx rename to web/app/components/base/avatar/__tests__/index.spec.tsx index e85690880b..5fad1d0a90 100644 --- a/web/app/components/base/avatar/index.spec.tsx +++ b/web/app/components/base/avatar/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import Avatar from './index' +import Avatar from '../index' describe('Avatar', () => { beforeEach(() => { diff --git a/web/app/components/base/badge/index.spec.tsx b/web/app/components/base/badge/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/badge/index.spec.tsx rename to web/app/components/base/badge/__tests__/index.spec.tsx index 74162841cf..49e8bf4037 100644 --- a/web/app/components/base/badge/index.spec.tsx +++ b/web/app/components/base/badge/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import Badge, { BadgeState, BadgeVariants } from './index' +import Badge, { BadgeState, BadgeVariants } from '../index' describe('Badge', () => { describe('Rendering', () => { diff --git a/web/app/components/base/block-input/index.spec.tsx b/web/app/components/base/block-input/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/block-input/index.spec.tsx rename to web/app/components/base/block-input/__tests__/index.spec.tsx index 8d8729287d..3e1a6a9b90 100644 --- a/web/app/components/base/block-input/index.spec.tsx +++ b/web/app/components/base/block-input/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' import * as React from 'react' import Toast from '@/app/components/base/toast' -import BlockInput, { getInputKeys } from './index' +import BlockInput, { getInputKeys } from '../index' vi.mock('@/utils/var', () => ({ checkKeys: vi.fn((_keys: string[]) => ({ diff --git a/web/app/components/base/button/add-button.spec.tsx b/web/app/components/base/button/__tests__/add-button.spec.tsx similarity index 97% rename from web/app/components/base/button/add-button.spec.tsx rename to web/app/components/base/button/__tests__/add-button.spec.tsx index ad27753211..1ad999ec49 100644 --- a/web/app/components/base/button/add-button.spec.tsx +++ b/web/app/components/base/button/__tests__/add-button.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import AddButton from './add-button' +import AddButton from '../add-button' describe('AddButton', () => { describe('Rendering', () => { diff --git a/web/app/components/base/button/index.spec.tsx b/web/app/components/base/button/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/button/index.spec.tsx rename to web/app/components/base/button/__tests__/index.spec.tsx index 0377fa334f..b43ae89403 100644 --- a/web/app/components/base/button/index.spec.tsx +++ b/web/app/components/base/button/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { cleanup, fireEvent, render } from '@testing-library/react' import * as React from 'react' -import Button from './index' +import Button from '../index' afterEach(cleanup) // https://testing-library.com/docs/queries/about diff --git a/web/app/components/base/button/sync-button.spec.tsx b/web/app/components/base/button/__tests__/sync-button.spec.tsx similarity index 97% rename from web/app/components/base/button/sync-button.spec.tsx rename to web/app/components/base/button/__tests__/sync-button.spec.tsx index 116aaaa7b0..c86a3c4314 100644 --- a/web/app/components/base/button/sync-button.spec.tsx +++ b/web/app/components/base/button/__tests__/sync-button.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SyncButton from './sync-button' +import SyncButton from '../sync-button' describe('SyncButton', () => { describe('Rendering', () => { diff --git a/web/app/components/base/carousel/index.spec.tsx b/web/app/components/base/carousel/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/carousel/index.spec.tsx rename to web/app/components/base/carousel/__tests__/index.spec.tsx index 6bce414ee7..a10d25d016 100644 --- a/web/app/components/base/carousel/index.spec.tsx +++ b/web/app/components/base/carousel/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { Mock } from 'vitest' import { act, fireEvent, render, screen } from '@testing-library/react' import useEmblaCarousel from 'embla-carousel-react' -import { Carousel, useCarousel } from './index' +import { Carousel, useCarousel } from '../index' vi.mock('embla-carousel-react', () => ({ default: vi.fn(), diff --git a/web/app/components/base/chat/chat-with-history/chat-wrapper.spec.tsx b/web/app/components/base/chat/chat-with-history/__tests__/chat-wrapper.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat-with-history/chat-wrapper.spec.tsx rename to web/app/components/base/chat/chat-with-history/__tests__/chat-wrapper.spec.tsx index 22d450b82d..bcaab17fef 100644 --- a/web/app/components/base/chat/chat-with-history/chat-wrapper.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/__tests__/chat-wrapper.spec.tsx @@ -1,5 +1,5 @@ -import type { ChatConfig, ChatItemInTree } from '../types' -import type { ChatWithHistoryContextValue } from './context' +import type { ChatConfig, ChatItemInTree } from '../../types' +import type { ChatWithHistoryContextValue } from '../context' import type { FileEntity } from '@/app/components/base/file-uploader/types' import type { AppData, AppMeta, ConversationItem } from '@/models/share' import type { HumanInputFormData } from '@/types/workflow' @@ -12,17 +12,17 @@ import { stopChatMessageResponding, } from '@/service/share' import { TransferMethod } from '@/types/app' -import { useChat } from '../chat/hooks' +import { useChat } from '../../chat/hooks' -import { isValidGeneratedAnswer } from '../utils' -import ChatWrapper from './chat-wrapper' -import { useChatWithHistoryContext } from './context' +import { isValidGeneratedAnswer } from '../../utils' +import ChatWrapper from '../chat-wrapper' +import { useChatWithHistoryContext } from '../context' -vi.mock('../chat/hooks', () => ({ +vi.mock('../../chat/hooks', () => ({ useChat: vi.fn(), })) -vi.mock('./context', () => ({ +vi.mock('../context', () => ({ useChatWithHistoryContext: vi.fn(), })) @@ -37,7 +37,7 @@ vi.mock('next/navigation', () => ({ useParams: vi.fn(() => ({ token: 'test-token' })), })) -vi.mock('../utils', () => ({ +vi.mock('../../utils', () => ({ isValidGeneratedAnswer: vi.fn(), getLastAnswer: vi.fn(), })) diff --git a/web/app/components/base/chat/chat-with-history/header-in-mobile.spec.tsx b/web/app/components/base/chat/chat-with-history/__tests__/header-in-mobile.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat-with-history/header-in-mobile.spec.tsx rename to web/app/components/base/chat/chat-with-history/__tests__/header-in-mobile.spec.tsx index 6addaf30a8..5f14128742 100644 --- a/web/app/components/base/chat/chat-with-history/header-in-mobile.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/__tests__/header-in-mobile.spec.tsx @@ -1,12 +1,12 @@ -import type { ChatConfig } from '../types' -import type { ChatWithHistoryContextValue } from './context' +import type { ChatConfig } from '../../types' +import type { ChatWithHistoryContextValue } from '../context' import type { AppData, AppMeta, ConversationItem } from '@/models/share' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' -import { useChatWithHistoryContext } from './context' -import HeaderInMobile from './header-in-mobile' +import { useChatWithHistoryContext } from '../context' +import HeaderInMobile from '../header-in-mobile' vi.mock('@/hooks/use-breakpoints', () => ({ default: vi.fn(), @@ -17,7 +17,7 @@ vi.mock('@/hooks/use-breakpoints', () => ({ }, })) -vi.mock('./context', () => ({ +vi.mock('../context', () => ({ useChatWithHistoryContext: vi.fn(), ChatWithHistoryContext: { Provider: ({ children }: { children: React.ReactNode }) =>
{children}
}, })) @@ -33,7 +33,7 @@ vi.mock('next/navigation', () => ({ useParams: vi.fn(() => ({})), })) -vi.mock('../embedded-chatbot/theme/theme-context', () => ({ +vi.mock('../../embedded-chatbot/theme/theme-context', () => ({ useThemeContext: vi.fn(() => ({ buildTheme: vi.fn(), })), diff --git a/web/app/components/base/chat/chat-with-history/hooks.spec.tsx b/web/app/components/base/chat/chat-with-history/__tests__/hooks.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat-with-history/hooks.spec.tsx rename to web/app/components/base/chat/chat-with-history/__tests__/hooks.spec.tsx index 399f16716d..711c3c88f9 100644 --- a/web/app/components/base/chat/chat-with-history/hooks.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/__tests__/hooks.spec.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from 'react' -import type { ChatConfig } from '../types' +import type { ChatConfig } from '../../types' import type { AppConversationData, AppData, AppMeta, ConversationItem } from '@/models/share' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, renderHook, waitFor } from '@testing-library/react' @@ -11,8 +11,8 @@ import { generationConversationName, } from '@/service/share' import { shareQueryKeys } from '@/service/use-share' -import { CONVERSATION_ID_INFO } from '../constants' -import { useChatWithHistory } from './hooks' +import { CONVERSATION_ID_INFO } from '../../constants' +import { useChatWithHistory } from '../hooks' vi.mock('@/hooks/use-app-favicon', () => ({ useAppFavicon: vi.fn(), @@ -40,8 +40,8 @@ vi.mock('@/context/web-app-context', () => ({ useWebAppStore: (selector?: (state: typeof mockStoreState) => unknown) => useWebAppStoreMock(selector), })) -vi.mock('../utils', async () => { - const actual = await vi.importActual('../utils') +vi.mock('../../utils', async () => { + const actual = await vi.importActual('../../utils') return { ...actual, getProcessedSystemVariablesFromUrlParams: vi.fn().mockResolvedValue({ user_id: 'user-1' }), diff --git a/web/app/components/base/chat/chat-with-history/index.spec.tsx b/web/app/components/base/chat/chat-with-history/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat-with-history/index.spec.tsx rename to web/app/components/base/chat/chat-with-history/__tests__/index.spec.tsx index a02d05b427..452639f4b7 100644 --- a/web/app/components/base/chat/chat-with-history/index.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import type { RefObject } from 'react' -import type { ChatConfig } from '../types' +import type { ChatConfig } from '../../types' import type { InstalledApp } from '@/models/explore' import type { AppConversationData, AppData, AppMeta, ConversationItem } from '@/models/share' import { fireEvent, render, screen } from '@testing-library/react' @@ -7,11 +7,11 @@ import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import useDocumentTitle from '@/hooks/use-document-title' -import { useChatWithHistory } from './hooks' -import ChatWithHistory from './index' +import { useChatWithHistory } from '../hooks' +import ChatWithHistory from '../index' // --- Mocks --- -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useChatWithHistory: vi.fn(), })) @@ -40,7 +40,7 @@ vi.mock('next/navigation', () => ({ })) const mockBuildTheme = vi.fn() -vi.mock('../embedded-chatbot/theme/theme-context', () => ({ +vi.mock('../../embedded-chatbot/theme/theme-context', () => ({ useThemeContext: vi.fn(() => ({ buildTheme: mockBuildTheme, })), diff --git a/web/app/components/base/chat/chat-with-history/header/index.spec.tsx b/web/app/components/base/chat/chat-with-history/header/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat-with-history/header/index.spec.tsx rename to web/app/components/base/chat/chat-with-history/header/__tests__/index.spec.tsx index 8ed5c96f61..2b428ac32f 100644 --- a/web/app/components/base/chat/chat-with-history/header/index.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/header/__tests__/index.spec.tsx @@ -1,13 +1,13 @@ -import type { ChatWithHistoryContextValue } from '../context' +import type { ChatWithHistoryContextValue } from '../../context' import type { AppData, ConversationItem } from '@/models/share' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { useChatWithHistoryContext } from '../context' -import Header from './index' +import { useChatWithHistoryContext } from '../../context' +import Header from '../index' // Mock context module -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatWithHistoryContext: vi.fn(), })) diff --git a/web/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.spec.tsx b/web/app/components/base/chat/chat-with-history/header/__tests__/mobile-operation-dropdown.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.spec.tsx rename to web/app/components/base/chat/chat-with-history/header/__tests__/mobile-operation-dropdown.spec.tsx index 594b1353c9..295bebecac 100644 --- a/web/app/components/base/chat/chat-with-history/header/mobile-operation-dropdown.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/header/__tests__/mobile-operation-dropdown.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import MobileOperationDropdown from './mobile-operation-dropdown' +import MobileOperationDropdown from '../mobile-operation-dropdown' describe('MobileOperationDropdown Component', () => { const defaultProps = { diff --git a/web/app/components/base/chat/chat-with-history/header/operation.spec.tsx b/web/app/components/base/chat/chat-with-history/header/__tests__/operation.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat-with-history/header/operation.spec.tsx rename to web/app/components/base/chat/chat-with-history/header/__tests__/operation.spec.tsx index 0c37b0d2fd..454f20066e 100644 --- a/web/app/components/base/chat/chat-with-history/header/operation.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/header/__tests__/operation.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import Operation from './operation' +import Operation from '../operation' describe('Operation Component', () => { const defaultProps = { diff --git a/web/app/components/base/chat/chat-with-history/inputs-form/content.spec.tsx b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/content.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat-with-history/inputs-form/content.spec.tsx rename to web/app/components/base/chat/chat-with-history/inputs-form/__tests__/content.spec.tsx index 9d55e6df10..c1a0f3e294 100644 --- a/web/app/components/base/chat/chat-with-history/inputs-form/content.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/content.spec.tsx @@ -1,10 +1,10 @@ -import type { ChatWithHistoryContextValue } from '../context' +import type { ChatWithHistoryContextValue } from '../../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { InputVarType } from '@/app/components/workflow/types' -import InputsFormContent from './content' +import InputsFormContent from '../content' // Keep lightweight mocks for non-base project components vi.mock('@/app/components/workflow/nodes/_base/components/before-run-form/bool-input', () => ({ @@ -90,7 +90,7 @@ const createMockContext = (overrides: Partial = {}) // Create a real context for testing to support controlled component behavior const MockContext = React.createContext(createMockContext()) -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatWithHistoryContext: () => React.useContext(MockContext), })) diff --git a/web/app/components/base/chat/chat-with-history/inputs-form/index.spec.tsx b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat-with-history/inputs-form/index.spec.tsx rename to web/app/components/base/chat/chat-with-history/inputs-form/__tests__/index.spec.tsx index 90deb4e02d..0ba41afd8a 100644 --- a/web/app/components/base/chat/chat-with-history/inputs-form/index.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/index.spec.tsx @@ -1,11 +1,11 @@ -import type { ChatWithHistoryContextValue } from '../context' +import type { ChatWithHistoryContextValue } from '../../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { InputVarType } from '@/app/components/workflow/types' -import { useChatWithHistoryContext } from '../context' -import InputsFormNode from './index' +import { useChatWithHistoryContext } from '../../context' +import InputsFormNode from '../index' // Mocks for components used by InputsFormContent (the real sibling) vi.mock('@/app/components/workflow/nodes/_base/components/before-run-form/bool-input', () => ({ @@ -31,7 +31,7 @@ vi.mock('@/app/components/base/file-uploader', () => ({ ), })) -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatWithHistoryContext: vi.fn(), })) diff --git a/web/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.spec.tsx b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/view-form-dropdown.spec.tsx similarity index 94% rename from web/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.spec.tsx rename to web/app/components/base/chat/chat-with-history/inputs-form/__tests__/view-form-dropdown.spec.tsx index 517828003d..64d3e67b8f 100644 --- a/web/app/components/base/chat/chat-with-history/inputs-form/view-form-dropdown.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/inputs-form/__tests__/view-form-dropdown.spec.tsx @@ -1,11 +1,11 @@ -import type { ChatWithHistoryContextValue } from '../context' +import type { ChatWithHistoryContextValue } from '../../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { InputVarType } from '@/app/components/workflow/types' -import { useChatWithHistoryContext } from '../context' -import ViewFormDropdown from './view-form-dropdown' +import { useChatWithHistoryContext } from '../../context' +import ViewFormDropdown from '../view-form-dropdown' // Mocks for components used by InputsFormContent (the real sibling) vi.mock('@/app/components/workflow/nodes/_base/components/before-run-form/bool-input', () => ({ @@ -31,7 +31,7 @@ vi.mock('@/app/components/base/file-uploader', () => ({ ), })) -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatWithHistoryContext: vi.fn(), })) diff --git a/web/app/components/base/chat/chat-with-history/sidebar/index.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat-with-history/sidebar/index.spec.tsx rename to web/app/components/base/chat/chat-with-history/sidebar/__tests__/index.spec.tsx index f1378f5553..768bbe9284 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/index.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/index.spec.tsx @@ -1,13 +1,13 @@ -import type { ChatWithHistoryContextValue } from '../context' +import type { ChatWithHistoryContextValue } from '../../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { useChatWithHistoryContext } from '../context' -import Sidebar from './index' +import { useChatWithHistoryContext } from '../../context' +import Sidebar from '../index' // Mock List to allow us to trigger operations -vi.mock('./list', () => ({ +vi.mock('../list', () => ({ default: ({ list, onOperate, title }: { list: Array<{ id: string, name: string }>, onOperate: (type: string, item: { id: string, name: string }) => void, title?: string }) => (
{title &&
{title}
} @@ -25,7 +25,7 @@ vi.mock('./list', () => ({ })) // Mock context hook -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatWithHistoryContext: vi.fn(), })) diff --git a/web/app/components/base/chat/chat-with-history/sidebar/item.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/item.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat-with-history/sidebar/item.spec.tsx rename to web/app/components/base/chat/chat-with-history/sidebar/__tests__/item.spec.tsx index 1388d1b5ed..075b5b6b1c 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/item.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/item.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import Item from './item' +import Item from '../item' // Mock Operation to verify its usage vi.mock('@/app/components/base/chat/chat-with-history/sidebar/operation', () => ({ diff --git a/web/app/components/base/chat/chat-with-history/sidebar/list.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/list.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat-with-history/sidebar/list.spec.tsx rename to web/app/components/base/chat/chat-with-history/sidebar/__tests__/list.spec.tsx index 7324a72aa6..a0d04fb271 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/list.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/list.spec.tsx @@ -1,10 +1,10 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' import { describe, expect, it, vi } from 'vitest' -import List from './list' +import List from '../list' // Mock Item to verify its usage -vi.mock('./item', () => ({ +vi.mock('../item', () => ({ default: ({ item }: { item: { name: string } }) => (
{item.name} diff --git a/web/app/components/base/chat/chat-with-history/sidebar/operation.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat-with-history/sidebar/operation.spec.tsx rename to web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx index 3f7d11a837..e46b54872e 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/operation.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/operation.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import Operation from './operation' +import Operation from '../operation' // Mock PortalToFollowElem components to render children in place vi.mock('@/app/components/base/portal-to-follow-elem', () => ({ diff --git a/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.spec.tsx b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/rename-modal.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat-with-history/sidebar/rename-modal.spec.tsx rename to web/app/components/base/chat/chat-with-history/sidebar/__tests__/rename-modal.spec.tsx index 4feecd72b6..e20caa98da 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/__tests__/rename-modal.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import RenameModal from './rename-modal' +import RenameModal from '../rename-modal' describe('RenameModal', () => { const defaultProps = { diff --git a/web/app/components/base/chat/chat/content-switch.spec.tsx b/web/app/components/base/chat/chat/__tests__/content-switch.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/content-switch.spec.tsx rename to web/app/components/base/chat/chat/__tests__/content-switch.spec.tsx index 5f87ceb6f2..e05151464a 100644 --- a/web/app/components/base/chat/chat/content-switch.spec.tsx +++ b/web/app/components/base/chat/chat/__tests__/content-switch.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import ContentSwitch from './content-switch' +import ContentSwitch from '../content-switch' describe('ContentSwitch', () => { const defaultProps = { diff --git a/web/app/components/base/chat/chat/context.spec.tsx b/web/app/components/base/chat/chat/__tests__/context.spec.tsx similarity index 94% rename from web/app/components/base/chat/chat/context.spec.tsx rename to web/app/components/base/chat/chat/__tests__/context.spec.tsx index de65a4d606..fd00156e59 100644 --- a/web/app/components/base/chat/chat/context.spec.tsx +++ b/web/app/components/base/chat/chat/__tests__/context.spec.tsx @@ -1,9 +1,9 @@ -import type { ChatItem } from '../types' -import type { ChatContextValue } from './context' +import type { ChatItem } from '../../types' +import type { ChatContextValue } from '../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { vi } from 'vitest' -import { ChatContextProvider, useChatContext } from './context' +import { ChatContextProvider, useChatContext } from '../context' const TestConsumer = () => { const context = useChatContext() diff --git a/web/app/components/base/chat/chat/hooks.multimodal.spec.ts b/web/app/components/base/chat/chat/__tests__/hooks.multimodal.spec.ts similarity index 100% rename from web/app/components/base/chat/chat/hooks.multimodal.spec.ts rename to web/app/components/base/chat/chat/__tests__/hooks.multimodal.spec.ts diff --git a/web/app/components/base/chat/chat/index.spec.tsx b/web/app/components/base/chat/chat/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/index.spec.tsx rename to web/app/components/base/chat/chat/__tests__/index.spec.tsx index 73c4aa8207..ba5bbaba6b 100644 --- a/web/app/components/base/chat/chat/index.spec.tsx +++ b/web/app/components/base/chat/chat/__tests__/index.spec.tsx @@ -1,10 +1,10 @@ -import type { ChatConfig, ChatItem, OnSend } from '../types' -import type { ChatProps } from './index' +import type { ChatConfig, ChatItem, OnSend } from '../../types' +import type { ChatProps } from '../index' import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { useStore as useAppStore } from '@/app/components/app/store' -import Chat from './index' +import Chat from '../index' // ─── Why each mock exists ───────────────────────────────────────────────────── // @@ -24,7 +24,7 @@ import Chat from './index' // TryToAsk – only uses Button (base), Divider (base), i18n (global mock). // ───────────────────────────────────────────────────────────────────────────── -vi.mock('./answer', () => ({ +vi.mock('../answer', () => ({ default: ({ item, responding }: { item: ChatItem, responding?: boolean }) => (
({ ), })) -vi.mock('./question', () => ({ +vi.mock('../question', () => ({ default: ({ item }: { item: ChatItem }) => (
{item.content}
), })) -vi.mock('./chat-input-area', () => ({ +vi.mock('../chat-input-area', () => ({ default: ({ disabled, readonly }: { disabled?: boolean, readonly?: boolean }) => (
({ diff --git a/web/app/components/base/chat/chat/try-to-ask.spec.tsx b/web/app/components/base/chat/chat/__tests__/try-to-ask.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat/try-to-ask.spec.tsx rename to web/app/components/base/chat/chat/__tests__/try-to-ask.spec.tsx index caeae028c6..e59e0865c1 100644 --- a/web/app/components/base/chat/chat/try-to-ask.spec.tsx +++ b/web/app/components/base/chat/chat/__tests__/try-to-ask.spec.tsx @@ -1,7 +1,7 @@ -import type { OnSend } from '../types' +import type { OnSend } from '../../types' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TryToAsk from './try-to-ask' +import TryToAsk from '../try-to-ask' describe('TryToAsk', () => { const mockOnSend: OnSend = vi.fn() diff --git a/web/app/components/base/chat/chat/answer/agent-content.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/agent-content.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat/answer/agent-content.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/agent-content.spec.tsx index ef4143fa6f..57c1eefa1f 100644 --- a/web/app/components/base/chat/chat/answer/agent-content.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/agent-content.spec.tsx @@ -1,9 +1,9 @@ -import type { ChatItem } from '../../types' +import type { ChatItem } from '../../../types' import type { IThoughtProps } from '@/app/components/base/chat/chat/thought' import type { FileEntity } from '@/app/components/base/file-uploader/types' import type { MarkdownProps } from '@/app/components/base/markdown' import { render, screen } from '@testing-library/react' -import AgentContent from './agent-content' +import AgentContent from '../agent-content' // Mock Markdown component used only in tests vi.mock('@/app/components/base/markdown', () => ({ diff --git a/web/app/components/base/chat/chat/answer/basic-content.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/basic-content.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat/answer/basic-content.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/basic-content.spec.tsx index 9a03ea9d40..77c1ea23cf 100644 --- a/web/app/components/base/chat/chat/answer/basic-content.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/basic-content.spec.tsx @@ -1,7 +1,7 @@ -import type { ChatItem } from '../../types' +import type { ChatItem } from '../../../types' import type { MarkdownProps } from '@/app/components/base/markdown' import { render, screen } from '@testing-library/react' -import BasicContent from './basic-content' +import BasicContent from '../basic-content' // Mock Markdown component used only in tests vi.mock('@/app/components/base/markdown', () => ({ diff --git a/web/app/components/base/chat/chat/answer/human-input-filled-form-list.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/human-input-filled-form-list.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat/answer/human-input-filled-form-list.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/human-input-filled-form-list.spec.tsx index 5eceddd444..37556550ca 100644 --- a/web/app/components/base/chat/chat/answer/human-input-filled-form-list.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/human-input-filled-form-list.spec.tsx @@ -1,7 +1,7 @@ import type { HumanInputFilledFormData } from '@/types/workflow' import { render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' -import HumanInputFilledFormList from './human-input-filled-form-list' +import HumanInputFilledFormList from '../human-input-filled-form-list' /** * Type-safe factory. diff --git a/web/app/components/base/chat/chat/answer/human-input-form-list.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/human-input-form-list.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat/answer/human-input-form-list.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/human-input-form-list.spec.tsx index 4bfd3a7d97..cc8fdfffd0 100644 --- a/web/app/components/base/chat/chat/answer/human-input-form-list.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/human-input-form-list.spec.tsx @@ -1,10 +1,10 @@ import type { HumanInputFormData } from '@/types/workflow' import { render, screen } from '@testing-library/react' import { DeliveryMethodType } from '@/app/components/workflow/nodes/human-input/types' -import HumanInputFormList from './human-input-form-list' +import HumanInputFormList from '../human-input-form-list' // Mock child components -vi.mock('./human-input-content/content-wrapper', () => ({ +vi.mock('../human-input-content/content-wrapper', () => ({ default: ({ children, nodeTitle }: { children: React.ReactNode, nodeTitle: string }) => (
{children} @@ -12,7 +12,7 @@ vi.mock('./human-input-content/content-wrapper', () => ({ ), })) -vi.mock('./human-input-content/unsubmitted', () => ({ +vi.mock('../human-input-content/unsubmitted', () => ({ UnsubmittedHumanInputContent: ({ showEmailTip, isEmailDebugMode, showDebugModeTip }: { showEmailTip: boolean, isEmailDebugMode: boolean, showDebugModeTip: boolean }) => (
{showEmailTip ? 'true' : 'false'} diff --git a/web/app/components/base/chat/chat/answer/more.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/more.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/answer/more.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/more.spec.tsx index 551c15e659..6ff162f09f 100644 --- a/web/app/components/base/chat/chat/answer/more.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/more.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import More from './more' +import More from '../more' describe('More', () => { const mockMoreData = { diff --git a/web/app/components/base/chat/chat/answer/operation.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/answer/operation.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx index eb52dffe8f..0c5a43e62a 100644 --- a/web/app/components/base/chat/chat/answer/operation.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/operation.spec.tsx @@ -1,5 +1,5 @@ -import type { ChatConfig, ChatItem } from '../../types' -import type { ChatContextValue } from '../context' +import type { ChatConfig, ChatItem } from '../../../types' +import type { ChatContextValue } from '../../context' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import copy from 'copy-to-clipboard' @@ -7,7 +7,7 @@ import * as React from 'react' import { vi } from 'vitest' import { useModalContext } from '@/context/modal-context' import { useProviderContext } from '@/context/provider-context' -import Operation from './operation' +import Operation from '../operation' const { mockSetShowAnnotationFullModal, @@ -158,7 +158,7 @@ const mockContextValue: ChatContextValue = { onAnnotationRemoved: vi.fn(), } -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatContext: () => mockContextValue, })) diff --git a/web/app/components/base/chat/chat/answer/suggested-questions.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/suggested-questions.spec.tsx similarity index 93% rename from web/app/components/base/chat/chat/answer/suggested-questions.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/suggested-questions.spec.tsx index 85a8a28609..16128759bd 100644 --- a/web/app/components/base/chat/chat/answer/suggested-questions.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/suggested-questions.spec.tsx @@ -1,12 +1,12 @@ import type { Mock } from 'vitest' // Or 'jest' if using Jest -import type { IChatItem } from '../type' +import type { IChatItem } from '../../type' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { useChatContext } from '../context' -import SuggestedQuestions from './suggested-questions' +import { useChatContext } from '../../context' +import SuggestedQuestions from '../suggested-questions' // Mock the chat context -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useChatContext: vi.fn(), })) diff --git a/web/app/components/base/chat/chat/answer/tool-detail.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/tool-detail.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat/answer/tool-detail.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/tool-detail.spec.tsx index 774adcc6e4..7ddeceeb83 100644 --- a/web/app/components/base/chat/chat/answer/tool-detail.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/tool-detail.spec.tsx @@ -1,7 +1,7 @@ -import type { ToolInfoInThought } from '../type' +import type { ToolInfoInThought } from '../../type' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ToolDetail from './tool-detail' +import ToolDetail from '../tool-detail' describe('ToolDetail', () => { const mockPayload: ToolInfoInThought = { diff --git a/web/app/components/base/chat/chat/answer/workflow-process.spec.tsx b/web/app/components/base/chat/chat/answer/__tests__/workflow-process.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/answer/workflow-process.spec.tsx rename to web/app/components/base/chat/chat/answer/__tests__/workflow-process.spec.tsx index 30fdb954ea..1e7d9f012e 100644 --- a/web/app/components/base/chat/chat/answer/workflow-process.spec.tsx +++ b/web/app/components/base/chat/chat/answer/__tests__/workflow-process.spec.tsx @@ -1,8 +1,8 @@ -import type { WorkflowProcess } from '../../types' +import type { WorkflowProcess } from '../../../types' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { WorkflowRunningStatus } from '@/app/components/workflow/types' -import WorkflowProcessItem from './workflow-process' +import WorkflowProcessItem from '../workflow-process' // Mock TracingPanel as it's a complex child component vi.mock('@/app/components/workflow/run/tracing-panel', () => ({ diff --git a/web/app/components/base/chat/chat/answer/human-input-content/content-item.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-item.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/answer/human-input-content/content-item.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-item.spec.tsx index 2c762f37b5..b1a6ec51ae 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/content-item.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-item.spec.tsx @@ -2,7 +2,7 @@ import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import ContentItem from './content-item' +import ContentItem from '../content-item' vi.mock('@/app/components/base/markdown', () => ({ Markdown: ({ content }: { content: string }) =>
{content}
, diff --git a/web/app/components/base/chat/chat/answer/human-input-content/content-wrapper.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-wrapper.spec.tsx similarity index 97% rename from web/app/components/base/chat/chat/answer/human-input-content/content-wrapper.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-wrapper.spec.tsx index 36f264a834..9e50c9c18b 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/content-wrapper.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/content-wrapper.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it } from 'vitest' -import ContentWrapper from './content-wrapper' +import ContentWrapper from '../content-wrapper' describe('ContentWrapper', () => { const defaultProps = { diff --git a/web/app/components/base/chat/chat/answer/human-input-content/executed-action.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/executed-action.spec.tsx similarity index 94% rename from web/app/components/base/chat/chat/answer/human-input-content/executed-action.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/executed-action.spec.tsx index 3f2e6e4beb..8c24209a0b 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/executed-action.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/executed-action.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' -import ExecutedAction from './executed-action' +import ExecutedAction from '../executed-action' describe('ExecutedAction', () => { it('should render the triggered action information', () => { diff --git a/web/app/components/base/chat/chat/answer/human-input-content/expiration-time.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/expiration-time.spec.tsx similarity index 87% rename from web/app/components/base/chat/chat/answer/human-input-content/expiration-time.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/expiration-time.spec.tsx index fdf3a3244b..b2ed03e71c 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/expiration-time.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/expiration-time.spec.tsx @@ -1,11 +1,11 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import ExpirationTime from './expiration-time' -import * as utils from './utils' +import ExpirationTime from '../expiration-time' +import * as utils from '../utils' // Mock utils to control time-based logic -vi.mock('./utils', async (importOriginal) => { - const actual = await importOriginal() +vi.mock('../utils', async (importOriginal) => { + const actual = await importOriginal() return { ...actual, getRelativeTime: vi.fn(), diff --git a/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/human-input-form.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/answer/human-input-content/human-input-form.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/human-input-form.spec.tsx index e9d6fdee3c..89ba71b2d9 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/human-input-form.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/human-input-form.spec.tsx @@ -4,9 +4,9 @@ import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types' -import HumanInputForm from './human-input-form' +import HumanInputForm from '../human-input-form' -vi.mock('./content-item', () => ({ +vi.mock('../content-item', () => ({ default: ({ content, onInputChange }: { content: string, onInputChange: (name: string, value: string) => void }) => (
{content} diff --git a/web/app/components/base/chat/chat/answer/human-input-content/submitted-content.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted-content.spec.tsx similarity index 92% rename from web/app/components/base/chat/chat/answer/human-input-content/submitted-content.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted-content.spec.tsx index f56b081370..172c1238a7 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/submitted-content.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted-content.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import SubmittedContent from './submitted-content' +import SubmittedContent from '../submitted-content' vi.mock('@/app/components/base/markdown', () => ({ Markdown: ({ content }: { content: string }) =>
{content}
, diff --git a/web/app/components/base/chat/chat/answer/human-input-content/submitted.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted.spec.tsx similarity index 95% rename from web/app/components/base/chat/chat/answer/human-input-content/submitted.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted.spec.tsx index 3ea4a25fcd..69f5054704 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/submitted.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/submitted.spec.tsx @@ -1,7 +1,7 @@ import type { HumanInputFilledFormData } from '@/types/workflow' import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { SubmittedHumanInputContent } from './submitted' +import { SubmittedHumanInputContent } from '../submitted' vi.mock('@/app/components/base/markdown', () => ({ Markdown: ({ content }: { content: string }) =>
{content}
, diff --git a/web/app/components/base/chat/chat/answer/human-input-content/tips.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/tips.spec.tsx similarity index 98% rename from web/app/components/base/chat/chat/answer/human-input-content/tips.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/tips.spec.tsx index 44a92f0e0b..2c212fe3fa 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/tips.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/tips.spec.tsx @@ -2,7 +2,7 @@ import type { AppContextValue } from '@/context/app-context' import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' import { useSelector } from '@/context/app-context' -import Tips from './tips' +import Tips from '../tips' // Mock AppContext's useSelector to control user profile data vi.mock('@/context/app-context', async (importOriginal) => { diff --git a/web/app/components/base/chat/chat/answer/human-input-content/unsubmitted.spec.tsx b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/unsubmitted.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/answer/human-input-content/unsubmitted.spec.tsx rename to web/app/components/base/chat/chat/answer/human-input-content/__tests__/unsubmitted.spec.tsx index 192b4f08b4..046890157b 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/unsubmitted.spec.tsx +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/unsubmitted.spec.tsx @@ -6,7 +6,7 @@ import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types' import { useSelector } from '@/context/app-context' -import { UnsubmittedHumanInputContent } from './unsubmitted' +import { UnsubmittedHumanInputContent } from '../unsubmitted' // Mock AppContext's useSelector to control user profile data vi.mock('@/context/app-context', async (importOriginal) => { diff --git a/web/app/components/base/chat/chat/chat-input-area/index.spec.tsx b/web/app/components/base/chat/chat/chat-input-area/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/chat-input-area/index.spec.tsx rename to web/app/components/base/chat/chat/chat-input-area/__tests__/index.spec.tsx index 11827f5291..a6d4570fcb 100644 --- a/web/app/components/base/chat/chat/chat-input-area/index.spec.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/__tests__/index.spec.tsx @@ -5,7 +5,7 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { vi } from 'vitest' -import ChatInputArea from './index' +import ChatInputArea from '../index' // --------------------------------------------------------------------------- // Hoist shared mock references so they are available inside vi.mock factories @@ -106,7 +106,7 @@ vi.mock('@/app/components/base/toast', async () => { // --------------------------------------------------------------------------- let mockIsMultipleLine = false -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useTextAreaHeight: () => ({ wrapperRef: { current: document.createElement('div') }, textareaRef: { current: document.createElement('textarea') }, @@ -122,7 +122,7 @@ vi.mock('./hooks', () => ({ // --------------------------------------------------------------------------- // Input-forms validation hook – always passes by default // --------------------------------------------------------------------------- -vi.mock('../check-input-forms-hooks', () => ({ +vi.mock('../../check-input-forms-hooks', () => ({ useCheckInputsForms: () => ({ checkInputsForm: vi.fn().mockReturnValue(true), }), diff --git a/web/app/components/base/chat/chat/chat-input-area/operation.spec.tsx b/web/app/components/base/chat/chat/chat-input-area/__tests__/operation.spec.tsx similarity index 96% rename from web/app/components/base/chat/chat/chat-input-area/operation.spec.tsx rename to web/app/components/base/chat/chat/chat-input-area/__tests__/operation.spec.tsx index 914811015f..096b18d047 100644 --- a/web/app/components/base/chat/chat/chat-input-area/operation.spec.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/__tests__/operation.spec.tsx @@ -1,9 +1,9 @@ -import type { EnableType } from '../../types' +import type { EnableType } from '../../../types' import type { FileUpload } from '@/app/components/base/features/types' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { Theme } from '../../embedded-chatbot/theme/theme-context' -import Operation from './operation' +import { Theme } from '../../../embedded-chatbot/theme/theme-context' +import Operation from '../operation' vi.mock('@/app/components/base/file-uploader', () => ({ FileUploaderInChatInput: ({ readonly }: { readonly?: boolean }) => ( diff --git a/web/app/components/base/chat/chat/citation/index.spec.tsx b/web/app/components/base/chat/chat/citation/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/citation/index.spec.tsx rename to web/app/components/base/chat/chat/citation/__tests__/index.spec.tsx index dbf90d005c..affd473538 100644 --- a/web/app/components/base/chat/chat/citation/index.spec.tsx +++ b/web/app/components/base/chat/chat/citation/__tests__/index.spec.tsx @@ -1,10 +1,10 @@ -import type { CitationItem } from '../type' +import type { CitationItem } from '../../type' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' -import Citation from './index' +import Citation from '../index' -vi.mock('./popup', () => ({ +vi.mock('../popup', () => ({ default: ({ data, showHitInfo }: { data: { documentName: string }, showHitInfo?: boolean }) => (
{data.documentName} diff --git a/web/app/components/base/chat/chat/citation/popup.spec.tsx b/web/app/components/base/chat/chat/citation/__tests__/popup.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/citation/popup.spec.tsx rename to web/app/components/base/chat/chat/citation/__tests__/popup.spec.tsx index 4e211eafed..69304ffb59 100644 --- a/web/app/components/base/chat/chat/citation/popup.spec.tsx +++ b/web/app/components/base/chat/chat/citation/__tests__/popup.spec.tsx @@ -1,11 +1,11 @@ -import type { Resources } from './index' +import type { Resources } from '../index' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' import { useDocumentDownload } from '@/service/knowledge/use-document' import { downloadUrl } from '@/utils/download' -import Popup from './popup' +import Popup from '../popup' vi.mock('@/service/knowledge/use-document', () => ({ useDocumentDownload: vi.fn(), @@ -19,11 +19,11 @@ vi.mock('@/app/components/base/file-icon', () => ({ default: ({ type }: { type: string }) =>
, })) -vi.mock('./progress-tooltip', () => ({ +vi.mock('../progress-tooltip', () => ({ default: ({ data }: { data: number }) =>
{data}
, })) -vi.mock('./tooltip', () => ({ +vi.mock('../tooltip', () => ({ default: ({ text, data }: { text: string, data: number | string }) => (
{data}
), diff --git a/web/app/components/base/chat/chat/citation/progress-tooltip.spec.tsx b/web/app/components/base/chat/chat/citation/__tests__/progress-tooltip.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/citation/progress-tooltip.spec.tsx rename to web/app/components/base/chat/chat/citation/__tests__/progress-tooltip.spec.tsx index a24c60c614..a47123aafd 100644 --- a/web/app/components/base/chat/chat/citation/progress-tooltip.spec.tsx +++ b/web/app/components/base/chat/chat/citation/__tests__/progress-tooltip.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import ProgressTooltip from './progress-tooltip' +import ProgressTooltip from '../progress-tooltip' describe('ProgressTooltip', () => { describe('Rendering', () => { diff --git a/web/app/components/base/chat/chat/citation/tooltip.spec.tsx b/web/app/components/base/chat/chat/citation/__tests__/tooltip.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/citation/tooltip.spec.tsx rename to web/app/components/base/chat/chat/citation/__tests__/tooltip.spec.tsx index d5c1b57d76..45ac4b4fb4 100644 --- a/web/app/components/base/chat/chat/citation/tooltip.spec.tsx +++ b/web/app/components/base/chat/chat/citation/__tests__/tooltip.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it } from 'vitest' -import Tooltip from './tooltip' +import Tooltip from '../tooltip' const renderTooltip = (data: number | string = 42, text = 'Characters', icon = icon) => render() diff --git a/web/app/components/base/chat/chat/loading-anim/index.spec.tsx b/web/app/components/base/chat/chat/loading-anim/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/chat/chat/loading-anim/index.spec.tsx rename to web/app/components/base/chat/chat/loading-anim/__tests__/index.spec.tsx index ddba3e38ca..48005f6949 100644 --- a/web/app/components/base/chat/chat/loading-anim/index.spec.tsx +++ b/web/app/components/base/chat/chat/loading-anim/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import LoadingAnim from './index' +import LoadingAnim from '../index' describe('LoadingAnim', () => { it('should render correctly with text type', () => { diff --git a/web/app/components/base/chat/chat/log/index.spec.tsx b/web/app/components/base/chat/chat/log/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/log/index.spec.tsx rename to web/app/components/base/chat/chat/log/__tests__/index.spec.tsx index b74195bccb..b59f439f16 100644 --- a/web/app/components/base/chat/chat/log/index.spec.tsx +++ b/web/app/components/base/chat/chat/log/__tests__/index.spec.tsx @@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { vi } from 'vitest' import { useStore as useAppStore } from '@/app/components/app/store' -import Log from './index' +import Log from '../index' vi.mock('@/app/components/app/store', () => ({ useStore: vi.fn(), diff --git a/web/app/components/base/chat/chat/thought/index.spec.tsx b/web/app/components/base/chat/chat/thought/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/chat/chat/thought/index.spec.tsx rename to web/app/components/base/chat/chat/thought/__tests__/index.spec.tsx index d6a2993f0a..8a4ea5717d 100644 --- a/web/app/components/base/chat/chat/thought/index.spec.tsx +++ b/web/app/components/base/chat/chat/thought/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { ThoughtItem } from '../type' +import type { ThoughtItem } from '../../type' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import Thought from './index' +import Thought from '../index' describe('Thought', () => { const createThought = (overrides?: Partial): ThoughtItem => ({ diff --git a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.spec.tsx b/web/app/components/base/chat/embedded-chatbot/__tests__/chat-wrapper.spec.tsx similarity index 97% rename from web/app/components/base/chat/embedded-chatbot/chat-wrapper.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/__tests__/chat-wrapper.spec.tsx index d0b23627f0..b9485bde60 100644 --- a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/__tests__/chat-wrapper.spec.tsx @@ -1,5 +1,5 @@ -import type { ChatConfig, ChatItem, ChatItemInTree } from '../types' -import type { EmbeddedChatbotContextValue } from './context' +import type { ChatConfig, ChatItem, ChatItemInTree } from '../../types' +import type { EmbeddedChatbotContextValue } from '../context' import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' import { vi } from 'vitest' import { InputVarType } from '@/app/components/workflow/types' @@ -9,24 +9,24 @@ import { submitHumanInputForm, } from '@/service/share' import { submitHumanInputForm as submitHumanInputFormService } from '@/service/workflow' -import { useChat } from '../chat/hooks' -import ChatWrapper from './chat-wrapper' -import { useEmbeddedChatbotContext } from './context' +import { useChat } from '../../chat/hooks' +import ChatWrapper from '../chat-wrapper' +import { useEmbeddedChatbotContext } from '../context' -vi.mock('./context', () => ({ +vi.mock('../context', () => ({ useEmbeddedChatbotContext: vi.fn(), })) -vi.mock('../chat/hooks', () => ({ +vi.mock('../../chat/hooks', () => ({ useChat: vi.fn(), })) -vi.mock('./inputs-form', () => ({ +vi.mock('../inputs-form', () => ({ __esModule: true, default: () =>
inputs form
, })) -vi.mock('../chat', () => ({ +vi.mock('../../chat', () => ({ __esModule: true, default: ({ chatNode, @@ -87,7 +87,7 @@ vi.mock('@/service/workflow', () => ({ })) const mockIsDify = vi.fn(() => false) -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ isDify: () => mockIsDify(), })) diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx b/web/app/components/base/chat/embedded-chatbot/__tests__/hooks.spec.tsx similarity index 97% rename from web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/__tests__/hooks.spec.tsx index 06563832f1..9a3340b2af 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/__tests__/hooks.spec.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from 'react' -import type { ChatConfig } from '../types' +import type { ChatConfig } from '../../types' import type { AppConversationData, AppData, AppMeta, ConversationItem } from '@/models/share' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, renderHook, waitFor } from '@testing-library/react' @@ -11,8 +11,8 @@ import { generationConversationName, } from '@/service/share' import { shareQueryKeys } from '@/service/use-share' -import { CONVERSATION_ID_INFO } from '../constants' -import { useEmbeddedChatbot } from './hooks' +import { CONVERSATION_ID_INFO } from '../../constants' +import { useEmbeddedChatbot } from '../hooks' vi.mock('@/i18n-config/client', () => ({ changeLanguage: vi.fn().mockResolvedValue(undefined), @@ -40,8 +40,8 @@ vi.mock('@/context/web-app-context', () => ({ useWebAppStore: (selector?: (state: typeof mockStoreState) => unknown) => useWebAppStoreMock(selector), })) -vi.mock('../utils', async () => { - const actual = await vi.importActual('../utils') +vi.mock('../../utils', async () => { + const actual = await vi.importActual('../../utils') return { ...actual, getProcessedInputsFromUrlParams: vi.fn().mockResolvedValue({}), diff --git a/web/app/components/base/chat/embedded-chatbot/index.spec.tsx b/web/app/components/base/chat/embedded-chatbot/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/chat/embedded-chatbot/index.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/__tests__/index.spec.tsx index 48fe16f7b3..a87c206412 100644 --- a/web/app/components/base/chat/embedded-chatbot/index.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/__tests__/index.spec.tsx @@ -1,15 +1,15 @@ import type { RefObject } from 'react' -import type { ChatConfig } from '../types' +import type { ChatConfig } from '../../types' import type { AppData, AppMeta, ConversationItem } from '@/models/share' import { render, screen } from '@testing-library/react' import { vi } from 'vitest' import { useGlobalPublicStore } from '@/context/global-public-context' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import { defaultSystemFeatures } from '@/types/feature' -import { useEmbeddedChatbot } from './hooks' -import EmbeddedChatbot from './index' +import { useEmbeddedChatbot } from '../hooks' +import EmbeddedChatbot from '../index' -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useEmbeddedChatbot: vi.fn(), })) @@ -30,17 +30,17 @@ vi.mock('@/context/global-public-context', () => ({ useGlobalPublicStore: vi.fn(), })) -vi.mock('./chat-wrapper', () => ({ +vi.mock('../chat-wrapper', () => ({ __esModule: true, default: () =>
chat area
, })) -vi.mock('./header', () => ({ +vi.mock('../header', () => ({ __esModule: true, default: () =>
chat header
, })) -vi.mock('./theme/theme-context', () => ({ +vi.mock('../theme/theme-context', () => ({ useThemeContext: vi.fn(() => ({ buildTheme: vi.fn(), theme: { @@ -50,7 +50,7 @@ vi.mock('./theme/theme-context', () => ({ })) const mockIsDify = vi.fn(() => false) -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ isDify: () => mockIsDify(), })) diff --git a/web/app/components/base/chat/embedded-chatbot/header/index.spec.tsx b/web/app/components/base/chat/embedded-chatbot/header/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/chat/embedded-chatbot/header/index.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/header/__tests__/index.spec.tsx index 31323c7196..0ebcc647ac 100644 --- a/web/app/components/base/chat/embedded-chatbot/header/index.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/header/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ /* eslint-disable next/no-img-element */ import type { ImgHTMLAttributes } from 'react' -import type { EmbeddedChatbotContextValue } from '../context' +import type { EmbeddedChatbotContextValue } from '../../context' import type { AppData } from '@/models/share' import type { SystemFeatures } from '@/types/feature' import { render, screen, waitFor } from '@testing-library/react' @@ -8,10 +8,10 @@ import userEvent from '@testing-library/user-event' import { vi } from 'vitest' import { useGlobalPublicStore } from '@/context/global-public-context' import { InstallationScope, LicenseStatus } from '@/types/feature' -import { useEmbeddedChatbotContext } from '../context' -import Header from './index' +import { useEmbeddedChatbotContext } from '../../context' +import Header from '../index' -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useEmbeddedChatbotContext: vi.fn(), })) diff --git a/web/app/components/base/chat/embedded-chatbot/inputs-form/content.spec.tsx b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/content.spec.tsx similarity index 98% rename from web/app/components/base/chat/embedded-chatbot/inputs-form/content.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/content.spec.tsx index de7f810fcb..08c9a035e7 100644 --- a/web/app/components/base/chat/embedded-chatbot/inputs-form/content.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/content.spec.tsx @@ -2,10 +2,10 @@ import { fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { InputVarType } from '@/app/components/workflow/types' -import { useEmbeddedChatbotContext } from '../context' -import InputsFormContent from './content' +import { useEmbeddedChatbotContext } from '../../context' +import InputsFormContent from '../content' -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useEmbeddedChatbotContext: vi.fn(), })) diff --git a/web/app/components/base/chat/embedded-chatbot/inputs-form/index.spec.tsx b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/chat/embedded-chatbot/inputs-form/index.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/index.spec.tsx index 7568f606df..7ffedc581a 100644 --- a/web/app/components/base/chat/embedded-chatbot/inputs-form/index.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/index.spec.tsx @@ -2,15 +2,15 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { AppSourceType } from '@/service/share' -import { useEmbeddedChatbotContext } from '../context' -import InputsFormNode from './index' +import { useEmbeddedChatbotContext } from '../../context' +import InputsFormNode from '../index' -vi.mock('../context', () => ({ +vi.mock('../../context', () => ({ useEmbeddedChatbotContext: vi.fn(), })) // Mock InputsFormContent to avoid complex integration in this test -vi.mock('./content', () => ({ +vi.mock('../content', () => ({ default: () =>
, })) diff --git a/web/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.spec.tsx b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/view-form-dropdown.spec.tsx similarity index 95% rename from web/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.spec.tsx rename to web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/view-form-dropdown.spec.tsx index 9f7fa727fd..8e0ddedbe7 100644 --- a/web/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/inputs-form/__tests__/view-form-dropdown.spec.tsx @@ -1,9 +1,9 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ViewFormDropdown from './view-form-dropdown' +import ViewFormDropdown from '../view-form-dropdown' // Mock InputsFormContent to avoid complex integration in this test -vi.mock('./content', () => ({ +vi.mock('../content', () => ({ default: () =>
, })) diff --git a/web/app/components/base/checkbox-list/index.spec.tsx b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/checkbox-list/index.spec.tsx rename to web/app/components/base/checkbox-list/__tests__/index.spec.tsx index 59ddfb69fc..17f3704666 100644 --- a/web/app/components/base/checkbox-list/index.spec.tsx +++ b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import type { ImgHTMLAttributes } from 'react' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import CheckboxList from '.' +import CheckboxList from '..' vi.mock('next/image', () => ({ default: (props: ImgHTMLAttributes) => , diff --git a/web/app/components/base/checkbox/index.spec.tsx b/web/app/components/base/checkbox/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/checkbox/index.spec.tsx rename to web/app/components/base/checkbox/__tests__/index.spec.tsx index e817f05afd..551f29c854 100644 --- a/web/app/components/base/checkbox/index.spec.tsx +++ b/web/app/components/base/checkbox/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import Checkbox from './index' +import Checkbox from '../index' describe('Checkbox Component', () => { const mockProps = { diff --git a/web/app/components/base/checkbox/assets/indeterminate-icon.spec.tsx b/web/app/components/base/checkbox/assets/__tests__/indeterminate-icon.spec.tsx similarity index 90% rename from web/app/components/base/checkbox/assets/indeterminate-icon.spec.tsx rename to web/app/components/base/checkbox/assets/__tests__/indeterminate-icon.spec.tsx index 3f39dd836f..e226562da7 100644 --- a/web/app/components/base/checkbox/assets/indeterminate-icon.spec.tsx +++ b/web/app/components/base/checkbox/assets/__tests__/indeterminate-icon.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import IndeterminateIcon from './indeterminate-icon' +import IndeterminateIcon from '../indeterminate-icon' describe('IndeterminateIcon', () => { describe('Rendering', () => { diff --git a/web/app/components/base/chip/index.spec.tsx b/web/app/components/base/chip/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/chip/index.spec.tsx rename to web/app/components/base/chip/__tests__/index.spec.tsx index c19cc77b39..24c04b51a5 100644 --- a/web/app/components/base/chip/index.spec.tsx +++ b/web/app/components/base/chip/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { Item } from './index' +import type { Item } from '../index' import { cleanup, fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import Chip from './index' +import Chip from '../index' afterEach(cleanup) diff --git a/web/app/components/base/confirm/index.spec.tsx b/web/app/components/base/confirm/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/confirm/index.spec.tsx rename to web/app/components/base/confirm/__tests__/index.spec.tsx index c2f67cc35e..29be2d617e 100644 --- a/web/app/components/base/confirm/index.spec.tsx +++ b/web/app/components/base/confirm/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen } from '@testing-library/react' -import Confirm from '.' +import Confirm from '..' vi.mock('react-dom', async () => { const actual = await vi.importActual('react-dom') diff --git a/web/app/components/base/content-dialog/index.spec.tsx b/web/app/components/base/content-dialog/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/content-dialog/index.spec.tsx rename to web/app/components/base/content-dialog/__tests__/index.spec.tsx index a047fdf062..e987d306a1 100644 --- a/web/app/components/base/content-dialog/index.spec.tsx +++ b/web/app/components/base/content-dialog/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ContentDialog from './index' +import ContentDialog from '../index' describe('ContentDialog', () => { it('renders children when show is true', async () => { diff --git a/web/app/components/base/copy-feedback/index.spec.tsx b/web/app/components/base/copy-feedback/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/copy-feedback/index.spec.tsx rename to web/app/components/base/copy-feedback/__tests__/index.spec.tsx index f89331c1bb..a7bc5bbbc2 100644 --- a/web/app/components/base/copy-feedback/index.spec.tsx +++ b/web/app/components/base/copy-feedback/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import CopyFeedback, { CopyFeedbackNew } from '.' +import CopyFeedback, { CopyFeedbackNew } from '..' const mockCopy = vi.fn() const mockReset = vi.fn() diff --git a/web/app/components/base/copy-icon/index.spec.tsx b/web/app/components/base/copy-icon/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/copy-icon/index.spec.tsx rename to web/app/components/base/copy-icon/__tests__/index.spec.tsx index b4cf192174..f25f0940c6 100644 --- a/web/app/components/base/copy-icon/index.spec.tsx +++ b/web/app/components/base/copy-icon/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render } from '@testing-library/react' -import CopyIcon from '.' +import CopyIcon from '..' const copy = vi.fn() const reset = vi.fn() diff --git a/web/app/components/base/corner-label/index.spec.tsx b/web/app/components/base/corner-label/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/corner-label/index.spec.tsx rename to web/app/components/base/corner-label/__tests__/index.spec.tsx index 479eaeff0d..11a2c0c877 100644 --- a/web/app/components/base/corner-label/index.spec.tsx +++ b/web/app/components/base/corner-label/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import CornerLabel from '.' +import CornerLabel from '..' describe('CornerLabel', () => { it('renders the label correctly', () => { diff --git a/web/app/components/base/date-and-time-picker/hooks.spec.ts b/web/app/components/base/date-and-time-picker/__tests__/hooks.spec.ts similarity index 97% rename from web/app/components/base/date-and-time-picker/hooks.spec.ts rename to web/app/components/base/date-and-time-picker/__tests__/hooks.spec.ts index c3675b9d84..3595cb6600 100644 --- a/web/app/components/base/date-and-time-picker/hooks.spec.ts +++ b/web/app/components/base/date-and-time-picker/__tests__/hooks.spec.ts @@ -1,7 +1,7 @@ import { renderHook } from '@testing-library/react' -import { useDaysOfWeek, useMonths, useTimeOptions, useYearOptions } from './hooks' -import { Period } from './types' -import dayjs from './utils/dayjs' +import { useDaysOfWeek, useMonths, useTimeOptions, useYearOptions } from '../hooks' +import { Period } from '../types' +import dayjs from '../utils/dayjs' describe('date-and-time-picker hooks', () => { // Tests for useDaysOfWeek hook diff --git a/web/app/components/base/date-and-time-picker/calendar/days-of-week.spec.tsx b/web/app/components/base/date-and-time-picker/calendar/__tests__/days-of-week.spec.tsx similarity index 93% rename from web/app/components/base/date-and-time-picker/calendar/days-of-week.spec.tsx rename to web/app/components/base/date-and-time-picker/calendar/__tests__/days-of-week.spec.tsx index 334b6fdbe9..44d79c1fee 100644 --- a/web/app/components/base/date-and-time-picker/calendar/days-of-week.spec.tsx +++ b/web/app/components/base/date-and-time-picker/calendar/__tests__/days-of-week.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import { DaysOfWeek } from './days-of-week' +import { DaysOfWeek } from '../days-of-week' describe('DaysOfWeek', () => { // Rendering test diff --git a/web/app/components/base/date-and-time-picker/calendar/index.spec.tsx b/web/app/components/base/date-and-time-picker/calendar/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/date-and-time-picker/calendar/index.spec.tsx rename to web/app/components/base/date-and-time-picker/calendar/__tests__/index.spec.tsx index 51104864bb..d8e00780b1 100644 --- a/web/app/components/base/date-and-time-picker/calendar/index.spec.tsx +++ b/web/app/components/base/date-and-time-picker/calendar/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { CalendarProps, Day } from '../types' +import type { CalendarProps, Day } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import dayjs from '../utils/dayjs' -import Calendar from './index' +import dayjs from '../../utils/dayjs' +import Calendar from '../index' // Mock scrollIntoView since jsdom doesn't implement it beforeAll(() => { diff --git a/web/app/components/base/date-and-time-picker/calendar/item.spec.tsx b/web/app/components/base/date-and-time-picker/calendar/__tests__/item.spec.tsx similarity index 97% rename from web/app/components/base/date-and-time-picker/calendar/item.spec.tsx rename to web/app/components/base/date-and-time-picker/calendar/__tests__/item.spec.tsx index 7fcfcaae1f..8bf8ac68b5 100644 --- a/web/app/components/base/date-and-time-picker/calendar/item.spec.tsx +++ b/web/app/components/base/date-and-time-picker/calendar/__tests__/item.spec.tsx @@ -1,7 +1,7 @@ -import type { CalendarItemProps, Day } from '../types' +import type { CalendarItemProps, Day } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import dayjs from '../utils/dayjs' -import Item from './item' +import dayjs from '../../utils/dayjs' +import Item from '../item' const createMockDay = (overrides: Partial = {}): Day => ({ date: dayjs('2024-06-15'), diff --git a/web/app/components/base/date-and-time-picker/common/option-list-item.spec.tsx b/web/app/components/base/date-and-time-picker/common/__tests__/option-list-item.spec.tsx similarity index 98% rename from web/app/components/base/date-and-time-picker/common/option-list-item.spec.tsx rename to web/app/components/base/date-and-time-picker/common/__tests__/option-list-item.spec.tsx index 760ba62ddc..8ccf8fab73 100644 --- a/web/app/components/base/date-and-time-picker/common/option-list-item.spec.tsx +++ b/web/app/components/base/date-and-time-picker/common/__tests__/option-list-item.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import OptionListItem from './option-list-item' +import OptionListItem from '../option-list-item' describe('OptionListItem', () => { let originalScrollIntoView: Element['scrollIntoView'] diff --git a/web/app/components/base/date-and-time-picker/date-picker/footer.spec.tsx b/web/app/components/base/date-and-time-picker/date-picker/__tests__/footer.spec.tsx similarity index 96% rename from web/app/components/base/date-and-time-picker/date-picker/footer.spec.tsx rename to web/app/components/base/date-and-time-picker/date-picker/__tests__/footer.spec.tsx index c164044484..b7ada71ca2 100644 --- a/web/app/components/base/date-and-time-picker/date-picker/footer.spec.tsx +++ b/web/app/components/base/date-and-time-picker/date-picker/__tests__/footer.spec.tsx @@ -1,7 +1,7 @@ -import type { DatePickerFooterProps } from '../types' +import type { DatePickerFooterProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import { ViewType } from '../types' -import Footer from './footer' +import { ViewType } from '../../types' +import Footer from '../footer' // Factory for Footer props const createFooterProps = (overrides: Partial = {}): DatePickerFooterProps => ({ diff --git a/web/app/components/base/date-and-time-picker/date-picker/header.spec.tsx b/web/app/components/base/date-and-time-picker/date-picker/__tests__/header.spec.tsx similarity index 95% rename from web/app/components/base/date-and-time-picker/date-picker/header.spec.tsx rename to web/app/components/base/date-and-time-picker/date-picker/__tests__/header.spec.tsx index 353b662eeb..dedb2ef68d 100644 --- a/web/app/components/base/date-and-time-picker/date-picker/header.spec.tsx +++ b/web/app/components/base/date-and-time-picker/date-picker/__tests__/header.spec.tsx @@ -1,7 +1,7 @@ -import type { DatePickerHeaderProps } from '../types' +import type { DatePickerHeaderProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import dayjs from '../utils/dayjs' -import Header from './header' +import dayjs from '../../utils/dayjs' +import Header from '../header' // Factory for Header props const createHeaderProps = (overrides: Partial = {}): DatePickerHeaderProps => ({ diff --git a/web/app/components/base/date-and-time-picker/date-picker/index.spec.tsx b/web/app/components/base/date-and-time-picker/date-picker/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/date-and-time-picker/date-picker/index.spec.tsx rename to web/app/components/base/date-and-time-picker/date-picker/__tests__/index.spec.tsx index 26ca3db1e1..5760a301dc 100644 --- a/web/app/components/base/date-and-time-picker/date-picker/index.spec.tsx +++ b/web/app/components/base/date-and-time-picker/date-picker/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { DatePickerProps } from '../types' +import type { DatePickerProps } from '../../types' import { act, fireEvent, render, screen, within } from '@testing-library/react' -import dayjs from '../utils/dayjs' -import DatePicker from './index' +import dayjs from '../../utils/dayjs' +import DatePicker from '../index' // Mock scrollIntoView beforeAll(() => { diff --git a/web/app/components/base/date-and-time-picker/time-picker/footer.spec.tsx b/web/app/components/base/date-and-time-picker/time-picker/__tests__/footer.spec.tsx similarity index 94% rename from web/app/components/base/date-and-time-picker/time-picker/footer.spec.tsx rename to web/app/components/base/date-and-time-picker/time-picker/__tests__/footer.spec.tsx index a11e6b94d6..d1060ffcfc 100644 --- a/web/app/components/base/date-and-time-picker/time-picker/footer.spec.tsx +++ b/web/app/components/base/date-and-time-picker/time-picker/__tests__/footer.spec.tsx @@ -1,6 +1,6 @@ -import type { TimePickerFooterProps } from '../types' +import type { TimePickerFooterProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import Footer from './footer' +import Footer from '../footer' // Factory for TimePickerFooter props const createFooterProps = (overrides: Partial = {}): TimePickerFooterProps => ({ diff --git a/web/app/components/base/date-and-time-picker/time-picker/header.spec.tsx b/web/app/components/base/date-and-time-picker/time-picker/__tests__/header.spec.tsx similarity index 96% rename from web/app/components/base/date-and-time-picker/time-picker/header.spec.tsx rename to web/app/components/base/date-and-time-picker/time-picker/__tests__/header.spec.tsx index 7f9872ff0f..afdadfda13 100644 --- a/web/app/components/base/date-and-time-picker/time-picker/header.spec.tsx +++ b/web/app/components/base/date-and-time-picker/time-picker/__tests__/header.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Header from './header' +import Header from '../header' describe('TimePicker Header', () => { beforeEach(() => { diff --git a/web/app/components/base/date-and-time-picker/time-picker/index.spec.tsx b/web/app/components/base/date-and-time-picker/time-picker/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/date-and-time-picker/time-picker/index.spec.tsx rename to web/app/components/base/date-and-time-picker/time-picker/__tests__/index.spec.tsx index ee4e08f988..81e065c827 100644 --- a/web/app/components/base/date-and-time-picker/time-picker/index.spec.tsx +++ b/web/app/components/base/date-and-time-picker/time-picker/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { TimePickerProps } from '../types' +import type { TimePickerProps } from '../../types' import { fireEvent, render, screen, within } from '@testing-library/react' -import dayjs, { isDayjsObject } from '../utils/dayjs' -import TimePicker from './index' +import dayjs, { isDayjsObject } from '../../utils/dayjs' +import TimePicker from '../index' // Mock scrollIntoView since jsdom doesn't implement it beforeAll(() => { diff --git a/web/app/components/base/date-and-time-picker/time-picker/options.spec.tsx b/web/app/components/base/date-and-time-picker/time-picker/__tests__/options.spec.tsx similarity index 96% rename from web/app/components/base/date-and-time-picker/time-picker/options.spec.tsx rename to web/app/components/base/date-and-time-picker/time-picker/__tests__/options.spec.tsx index 9f169eb010..9d945dcf2e 100644 --- a/web/app/components/base/date-and-time-picker/time-picker/options.spec.tsx +++ b/web/app/components/base/date-and-time-picker/time-picker/__tests__/options.spec.tsx @@ -1,7 +1,7 @@ -import type { TimeOptionsProps } from '../types' +import type { TimeOptionsProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import dayjs from '../utils/dayjs' -import Options from './options' +import dayjs from '../../utils/dayjs' +import Options from '../options' beforeAll(() => { Element.prototype.scrollIntoView = vi.fn() diff --git a/web/app/components/base/date-and-time-picker/utils/dayjs-extended.spec.ts b/web/app/components/base/date-and-time-picker/utils/__tests__/dayjs-extended.spec.ts similarity index 99% rename from web/app/components/base/date-and-time-picker/utils/dayjs-extended.spec.ts rename to web/app/components/base/date-and-time-picker/utils/__tests__/dayjs-extended.spec.ts index a5c80ff35c..f5332e1917 100644 --- a/web/app/components/base/date-and-time-picker/utils/dayjs-extended.spec.ts +++ b/web/app/components/base/date-and-time-picker/utils/__tests__/dayjs-extended.spec.ts @@ -7,7 +7,7 @@ import dayjs, { getHourIn12Hour, parseDateWithFormat, toDayjs, -} from './dayjs' +} from '../dayjs' describe('dayjs extended utilities', () => { // Tests for cloneTime diff --git a/web/app/components/base/date-and-time-picker/utils/dayjs.spec.ts b/web/app/components/base/date-and-time-picker/utils/__tests__/dayjs.spec.ts similarity index 99% rename from web/app/components/base/date-and-time-picker/utils/dayjs.spec.ts rename to web/app/components/base/date-and-time-picker/utils/__tests__/dayjs.spec.ts index 5457fa13fb..e36fecd0b6 100644 --- a/web/app/components/base/date-and-time-picker/utils/dayjs.spec.ts +++ b/web/app/components/base/date-and-time-picker/utils/__tests__/dayjs.spec.ts @@ -3,7 +3,7 @@ import dayjs, { getDateWithTimezone, isDayjsObject, toDayjs, -} from './dayjs' +} from '../dayjs' describe('dayjs utilities', () => { const timezone = 'UTC' diff --git a/web/app/components/base/date-and-time-picker/year-and-month-picker/footer.spec.tsx b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/footer.spec.tsx similarity index 94% rename from web/app/components/base/date-and-time-picker/year-and-month-picker/footer.spec.tsx rename to web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/footer.spec.tsx index 7c3815d22f..f3d69461c9 100644 --- a/web/app/components/base/date-and-time-picker/year-and-month-picker/footer.spec.tsx +++ b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/footer.spec.tsx @@ -1,6 +1,6 @@ -import type { YearAndMonthPickerFooterProps } from '../types' +import type { YearAndMonthPickerFooterProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import Footer from './footer' +import Footer from '../footer' // Factory for Footer props const createFooterProps = (overrides: Partial = {}): YearAndMonthPickerFooterProps => ({ diff --git a/web/app/components/base/date-and-time-picker/year-and-month-picker/header.spec.tsx b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/header.spec.tsx similarity index 92% rename from web/app/components/base/date-and-time-picker/year-and-month-picker/header.spec.tsx rename to web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/header.spec.tsx index 91c0bc6947..fc30c8f221 100644 --- a/web/app/components/base/date-and-time-picker/year-and-month-picker/header.spec.tsx +++ b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/header.spec.tsx @@ -1,6 +1,6 @@ -import type { YearAndMonthPickerHeaderProps } from '../types' +import type { YearAndMonthPickerHeaderProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import Header from './header' +import Header from '../header' // Factory for Header props const createHeaderProps = (overrides: Partial = {}): YearAndMonthPickerHeaderProps => ({ diff --git a/web/app/components/base/date-and-time-picker/year-and-month-picker/options.spec.tsx b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/options.spec.tsx similarity index 95% rename from web/app/components/base/date-and-time-picker/year-and-month-picker/options.spec.tsx rename to web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/options.spec.tsx index 2ca448fed0..977462dfb6 100644 --- a/web/app/components/base/date-and-time-picker/year-and-month-picker/options.spec.tsx +++ b/web/app/components/base/date-and-time-picker/year-and-month-picker/__tests__/options.spec.tsx @@ -1,6 +1,6 @@ -import type { YearAndMonthPickerOptionsProps } from '../types' +import type { YearAndMonthPickerOptionsProps } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import Options from './options' +import Options from '../options' beforeAll(() => { Element.prototype.scrollIntoView = vi.fn() diff --git a/web/app/components/base/dialog/index.spec.tsx b/web/app/components/base/dialog/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/dialog/index.spec.tsx rename to web/app/components/base/dialog/__tests__/index.spec.tsx index c58724595f..241e89be26 100644 --- a/web/app/components/base/dialog/index.spec.tsx +++ b/web/app/components/base/dialog/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import CustomDialog from './index' +import CustomDialog from '../index' describe('CustomDialog Component', () => { const setup = () => userEvent.setup() diff --git a/web/app/components/base/divider/index.spec.tsx b/web/app/components/base/divider/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/divider/index.spec.tsx rename to web/app/components/base/divider/__tests__/index.spec.tsx index 7c7c52cd16..2630a0f6f6 100644 --- a/web/app/components/base/divider/index.spec.tsx +++ b/web/app/components/base/divider/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import Divider from './index' +import Divider from '../index' describe('Divider', () => { it('renders with default props', () => { diff --git a/web/app/components/base/drawer-plus/index.spec.tsx b/web/app/components/base/drawer-plus/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/drawer-plus/index.spec.tsx rename to web/app/components/base/drawer-plus/__tests__/index.spec.tsx index e2d5c88df8..e6a530c299 100644 --- a/web/app/components/base/drawer-plus/index.spec.tsx +++ b/web/app/components/base/drawer-plus/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import DrawerPlus from '.' +import DrawerPlus from '..' vi.mock('@/hooks/use-breakpoints', () => ({ default: () => 'desktop', diff --git a/web/app/components/base/drawer/index.spec.tsx b/web/app/components/base/drawer/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/drawer/index.spec.tsx rename to web/app/components/base/drawer/__tests__/index.spec.tsx index 51cf0fa55c..83338b5630 100644 --- a/web/app/components/base/drawer/index.spec.tsx +++ b/web/app/components/base/drawer/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { IDrawerProps } from './index' +import type { IDrawerProps } from '../index' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import Drawer from './index' +import Drawer from '../index' // Capture dialog onClose for testing let capturedDialogOnClose: (() => void) | null = null diff --git a/web/app/components/base/dropdown/index.spec.tsx b/web/app/components/base/dropdown/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/dropdown/index.spec.tsx rename to web/app/components/base/dropdown/__tests__/index.spec.tsx index 7d61b332d4..9820554e3d 100644 --- a/web/app/components/base/dropdown/index.spec.tsx +++ b/web/app/components/base/dropdown/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' -import Dropdown from './index' +import Dropdown from '../index' describe('Dropdown Component', () => { const mockItems = [ diff --git a/web/app/components/base/effect/index.spec.tsx b/web/app/components/base/effect/__tests__/index.spec.tsx similarity index 91% rename from web/app/components/base/effect/index.spec.tsx rename to web/app/components/base/effect/__tests__/index.spec.tsx index 38410f6987..298abc3189 100644 --- a/web/app/components/base/effect/index.spec.tsx +++ b/web/app/components/base/effect/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import Effect from '.' +import Effect from '..' describe('Effect', () => { it('applies custom class names', () => { diff --git a/web/app/components/base/emoji-picker/Inner.spec.tsx b/web/app/components/base/emoji-picker/__tests__/Inner.spec.tsx similarity index 99% rename from web/app/components/base/emoji-picker/Inner.spec.tsx rename to web/app/components/base/emoji-picker/__tests__/Inner.spec.tsx index cd993af9e8..eac18dd48a 100644 --- a/web/app/components/base/emoji-picker/Inner.spec.tsx +++ b/web/app/components/base/emoji-picker/__tests__/Inner.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' -import EmojiPickerInner from './Inner' +import EmojiPickerInner from '../Inner' vi.mock('@emoji-mart/data', () => ({ default: { diff --git a/web/app/components/base/emoji-picker/index.spec.tsx b/web/app/components/base/emoji-picker/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/emoji-picker/index.spec.tsx rename to web/app/components/base/emoji-picker/__tests__/index.spec.tsx index f554549cee..5eb6593213 100644 --- a/web/app/components/base/emoji-picker/index.spec.tsx +++ b/web/app/components/base/emoji-picker/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen } from '@testing-library/react' -import EmojiPicker from './index' +import EmojiPicker from '../index' vi.mock('@emoji-mart/data', () => ({ default: { diff --git a/web/app/components/base/encrypted-bottom/index.spec.tsx b/web/app/components/base/encrypted-bottom/__tests__/index.spec.tsx similarity index 94% rename from web/app/components/base/encrypted-bottom/index.spec.tsx rename to web/app/components/base/encrypted-bottom/__tests__/index.spec.tsx index aeeb546fe9..914cc7fcda 100644 --- a/web/app/components/base/encrypted-bottom/index.spec.tsx +++ b/web/app/components/base/encrypted-bottom/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import { EncryptedBottom } from '.' +import { EncryptedBottom } from '..' describe('EncryptedBottom', () => { it('applies custom class names', () => { diff --git a/web/app/components/base/error-boundary/index.spec.tsx b/web/app/components/base/error-boundary/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/error-boundary/index.spec.tsx rename to web/app/components/base/error-boundary/__tests__/index.spec.tsx index 1caca84d79..234f22833d 100644 --- a/web/app/components/base/error-boundary/index.spec.tsx +++ b/web/app/components/base/error-boundary/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import * as React from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import ErrorBoundary, { ErrorFallback, useAsyncError, useErrorHandler, withErrorBoundary } from './index' +import ErrorBoundary, { ErrorFallback, useAsyncError, useErrorHandler, withErrorBoundary } from '../index' const mockConfig = vi.hoisted(() => ({ isDev: false, diff --git a/web/app/components/base/features/context.spec.tsx b/web/app/components/base/features/__tests__/context.spec.tsx similarity index 96% rename from web/app/components/base/features/context.spec.tsx rename to web/app/components/base/features/__tests__/context.spec.tsx index e57cbd82c2..64bfb256f2 100644 --- a/web/app/components/base/features/context.spec.tsx +++ b/web/app/components/base/features/__tests__/context.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' import { useContext } from 'react' -import { FeaturesContext, FeaturesProvider } from './context' +import { FeaturesContext, FeaturesProvider } from '../context' const TestConsumer = () => { const store = useContext(FeaturesContext) diff --git a/web/app/components/base/features/hooks.spec.ts b/web/app/components/base/features/__tests__/hooks.spec.ts similarity index 92% rename from web/app/components/base/features/hooks.spec.ts rename to web/app/components/base/features/__tests__/hooks.spec.ts index aa0aa1e85e..52f3e846ce 100644 --- a/web/app/components/base/features/hooks.spec.ts +++ b/web/app/components/base/features/__tests__/hooks.spec.ts @@ -1,8 +1,8 @@ import { renderHook } from '@testing-library/react' import * as React from 'react' -import { FeaturesContext } from './context' -import { useFeatures, useFeaturesStore } from './hooks' -import { createFeaturesStore } from './store' +import { FeaturesContext } from '../context' +import { useFeatures, useFeaturesStore } from '../hooks' +import { createFeaturesStore } from '../store' describe('useFeatures', () => { it('should return selected state from the store when useFeatures is called with selector', () => { diff --git a/web/app/components/base/features/store.spec.ts b/web/app/components/base/features/__tests__/store.spec.ts similarity index 99% rename from web/app/components/base/features/store.spec.ts rename to web/app/components/base/features/__tests__/store.spec.ts index fc2cf8822e..0a4f03d76a 100644 --- a/web/app/components/base/features/store.spec.ts +++ b/web/app/components/base/features/__tests__/store.spec.ts @@ -1,5 +1,5 @@ import { Resolution, TransferMethod } from '@/types/app' -import { createFeaturesStore } from './store' +import { createFeaturesStore } from '../store' describe('createFeaturesStore', () => { describe('Default State', () => { diff --git a/web/app/components/base/features/new-feature-panel/citation.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/citation.spec.tsx similarity index 90% rename from web/app/components/base/features/new-feature-panel/citation.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/citation.spec.tsx index ed50ea9337..a6ad863071 100644 --- a/web/app/components/base/features/new-feature-panel/citation.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/citation.spec.tsx @@ -1,8 +1,8 @@ -import type { OnFeaturesChange } from '../types' +import type { OnFeaturesChange } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import { FeaturesProvider } from '../context' -import Citation from './citation' +import { FeaturesProvider } from '../../context' +import Citation from '../citation' const renderWithProvider = (props: { disabled?: boolean, onChange?: OnFeaturesChange } = {}) => { return render( diff --git a/web/app/components/base/features/new-feature-panel/dialog-wrapper.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/dialog-wrapper.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/dialog-wrapper.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/dialog-wrapper.spec.tsx index b5f8f71d60..374976c366 100644 --- a/web/app/components/base/features/new-feature-panel/dialog-wrapper.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/dialog-wrapper.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import DialogWrapper from './dialog-wrapper' +import DialogWrapper from '../dialog-wrapper' describe('DialogWrapper', () => { beforeEach(() => { diff --git a/web/app/components/base/features/new-feature-panel/feature-bar.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/feature-bar.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/feature-bar.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/feature-bar.spec.tsx index a02b70c01e..48b91c4836 100644 --- a/web/app/components/base/features/new-feature-panel/feature-bar.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/feature-bar.spec.tsx @@ -1,7 +1,7 @@ -import type { Features } from '../types' +import type { Features } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../context' -import FeatureBar from './feature-bar' +import { FeaturesProvider } from '../../context' +import FeatureBar from '../feature-bar' const defaultFeatures: Features = { moreLikeThis: { enabled: false }, diff --git a/web/app/components/base/features/new-feature-panel/feature-card.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/feature-card.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/feature-card.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/feature-card.spec.tsx index 1f4f1b9fad..0e925d9d02 100644 --- a/web/app/components/base/features/new-feature-panel/feature-card.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/feature-card.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import FeatureCard from './feature-card' +import FeatureCard from '../feature-card' describe('FeatureCard', () => { const defaultProps = { diff --git a/web/app/components/base/features/new-feature-panel/follow-up.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/follow-up.spec.tsx similarity index 90% rename from web/app/components/base/features/new-feature-panel/follow-up.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/follow-up.spec.tsx index 56df44df8f..0e7c6aa558 100644 --- a/web/app/components/base/features/new-feature-panel/follow-up.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/follow-up.spec.tsx @@ -1,8 +1,8 @@ -import type { OnFeaturesChange } from '../types' +import type { OnFeaturesChange } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import { FeaturesProvider } from '../context' -import FollowUp from './follow-up' +import { FeaturesProvider } from '../../context' +import FollowUp from '../follow-up' const renderWithProvider = (props: { disabled?: boolean, onChange?: OnFeaturesChange } = {}) => { return render( diff --git a/web/app/components/base/features/new-feature-panel/index.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/index.spec.tsx index 0122a148d3..20632c4954 100644 --- a/web/app/components/base/features/new-feature-panel/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { Features } from '../types' +import type { Features } from '../../types' import { render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../context' -import NewFeaturePanel from './index' +import { FeaturesProvider } from '../../context' +import NewFeaturePanel from '../index' vi.mock('next/navigation', () => ({ useRouter: () => ({ push: vi.fn() }), diff --git a/web/app/components/base/features/new-feature-panel/more-like-this.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/more-like-this.spec.tsx similarity index 91% rename from web/app/components/base/features/new-feature-panel/more-like-this.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/more-like-this.spec.tsx index 592e08a995..1d39b62f10 100644 --- a/web/app/components/base/features/new-feature-panel/more-like-this.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/more-like-this.spec.tsx @@ -1,8 +1,8 @@ -import type { OnFeaturesChange } from '../types' +import type { OnFeaturesChange } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import { FeaturesProvider } from '../context' -import MoreLikeThis from './more-like-this' +import { FeaturesProvider } from '../../context' +import MoreLikeThis from '../more-like-this' const renderWithProvider = (props: { disabled?: boolean, onChange?: OnFeaturesChange } = {}) => { return render( diff --git a/web/app/components/base/features/new-feature-panel/speech-to-text.spec.tsx b/web/app/components/base/features/new-feature-panel/__tests__/speech-to-text.spec.tsx similarity index 89% rename from web/app/components/base/features/new-feature-panel/speech-to-text.spec.tsx rename to web/app/components/base/features/new-feature-panel/__tests__/speech-to-text.spec.tsx index 341065fe21..75e0962745 100644 --- a/web/app/components/base/features/new-feature-panel/speech-to-text.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/__tests__/speech-to-text.spec.tsx @@ -1,8 +1,8 @@ -import type { OnFeaturesChange } from '../types' +import type { OnFeaturesChange } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import { FeaturesProvider } from '../context' -import SpeechToText from './speech-to-text' +import { FeaturesProvider } from '../../context' +import SpeechToText from '../speech-to-text' const renderWithProvider = (props: { disabled?: boolean, onChange?: OnFeaturesChange } = {}) => { return render( diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/annotation-ctrl-button.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/annotation-ctrl-button.spec.tsx index 65f45d10de..e48bedff96 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/annotation-ctrl-button.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import AnnotationCtrlButton from './annotation-ctrl-button' +import AnnotationCtrlButton from '../annotation-ctrl-button' const mockSetShowAnnotationFullModal = vi.fn() vi.mock('@/context/modal-context', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param-modal.spec.tsx similarity index 99% rename from web/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param-modal.spec.tsx index d541c006f6..1ef95e9e2d 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param-modal.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import Toast from '@/app/components/base/toast' -import ConfigParamModal from './config-param-modal' +import ConfigParamModal from '../config-param-modal' let mockHooksReturn: { modelList: { provider: { provider: string }, models: { model: string }[] }[] diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/config-param.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param.spec.tsx similarity index 96% rename from web/app/components/base/features/new-feature-panel/annotation-reply/config-param.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param.spec.tsx index 8d8a8e55cb..35adef0a7d 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/config-param.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import { Item } from './config-param' +import { Item } from '../config-param' describe('ConfigParam Item', () => { it('should render title text', () => { diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/index.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/annotation-reply/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/index.spec.tsx index ce9e2f7cf2..b7cf84a3a8 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import AnnotationReply from './index' +import { FeaturesProvider } from '../../../context' +import AnnotationReply from '../index' const mockPush = vi.fn() vi.mock('next/navigation', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/type.spec.ts b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/type.spec.ts similarity index 83% rename from web/app/components/base/features/new-feature-panel/annotation-reply/type.spec.ts rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/type.spec.ts index 0bbb6d695b..6d22b4d42f 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/type.spec.ts +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/type.spec.ts @@ -1,4 +1,4 @@ -import { PageType } from './type' +import { PageType } from '../type' describe('PageType', () => { it('should have log and annotation values', () => { diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.spec.ts b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/use-annotation-config.spec.ts similarity index 99% rename from web/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.spec.ts rename to web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/use-annotation-config.spec.ts index f7ea3a0117..7c1d94aea6 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.spec.ts +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/__tests__/use-annotation-config.spec.ts @@ -1,6 +1,6 @@ import type { AnnotationReplyConfig } from '@/models/debug' import { act, renderHook } from '@testing-library/react' -import useAnnotationConfig from './use-annotation-config' +import useAnnotationConfig from '../use-annotation-config' let mockIsAnnotationFull = false vi.mock('@/context/provider-context', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/__tests__/index.spec.tsx index 008c6369e1..2bc30e4ead 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import ScoreSlider from './index' +import ScoreSlider from '../index' vi.mock('@/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider', () => ({ default: ({ value, onChange, min, max }: { value: number, onChange: (v: number) => void, min: number, max: number }) => ( diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.spec.tsx b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/__tests__/index.spec.tsx index 21e187091c..815e8ffe49 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Slider from './index' +import Slider from '../index' describe('BaseSlider', () => { beforeEach(() => { diff --git a/web/app/components/base/features/new-feature-panel/conversation-opener/index.spec.tsx b/web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/conversation-opener/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/index.spec.tsx index 20e85c9378..a21b34e4ea 100644 --- a/web/app/components/base/features/new-feature-panel/conversation-opener/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import ConversationOpener from './index' +import { FeaturesProvider } from '../../../context' +import ConversationOpener from '../index' const mockSetShowOpeningModal = vi.fn() vi.mock('@/context/modal-context', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/conversation-opener/modal.spec.tsx b/web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/modal.spec.tsx similarity index 99% rename from web/app/components/base/features/new-feature-panel/conversation-opener/modal.spec.tsx rename to web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/modal.spec.tsx index c5acda4bd5..f03763d192 100644 --- a/web/app/components/base/features/new-feature-panel/conversation-opener/modal.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/conversation-opener/__tests__/modal.spec.tsx @@ -3,7 +3,7 @@ import type { InputVar } from '@/app/components/workflow/types' import { act, fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { InputVarType } from '@/app/components/workflow/types' -import OpeningSettingModal from './modal' +import OpeningSettingModal from '../modal' const getPromptEditor = () => { const editor = document.querySelector('[data-lexical-editor="true"]') diff --git a/web/app/components/base/features/new-feature-panel/file-upload/index.spec.tsx b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/file-upload/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/file-upload/__tests__/index.spec.tsx index b39156c196..cc3ab3fcc0 100644 --- a/web/app/components/base/features/new-feature-panel/file-upload/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import FileUpload from './index' +import { FeaturesProvider } from '../../../context' +import FileUpload from '../index' vi.mock('@/service/use-common', () => ({ useFileUploadConfig: () => ({ data: undefined }), diff --git a/web/app/components/base/features/new-feature-panel/file-upload/setting-content.spec.tsx b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-content.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/file-upload/setting-content.spec.tsx rename to web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-content.spec.tsx index ca5b4677bf..37a0f38838 100644 --- a/web/app/components/base/features/new-feature-panel/file-upload/setting-content.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-content.spec.tsx @@ -1,10 +1,10 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { TransferMethod } from '@/types/app' -import { FeaturesProvider } from '../../context' -import SettingContent from './setting-content' +import { FeaturesProvider } from '../../../context' +import SettingContent from '../setting-content' vi.mock('@/app/components/workflow/nodes/_base/components/file-upload-setting', () => ({ default: ({ payload, onChange }: { payload: Record, onChange: (p: Record) => void }) => ( diff --git a/web/app/components/base/features/new-feature-panel/file-upload/setting-modal.spec.tsx b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-modal.spec.tsx similarity index 96% rename from web/app/components/base/features/new-feature-panel/file-upload/setting-modal.spec.tsx rename to web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-modal.spec.tsx index b3a78c438f..afa690f31a 100644 --- a/web/app/components/base/features/new-feature-panel/file-upload/setting-modal.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/file-upload/__tests__/setting-modal.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import { FeaturesProvider } from '../../context' -import FileUploadSettings from './setting-modal' +import { FeaturesProvider } from '../../../context' +import FileUploadSettings from '../setting-modal' vi.mock('@/service/use-common', () => ({ useFileUploadConfig: () => ({ data: undefined }), diff --git a/web/app/components/base/features/new-feature-panel/image-upload/index.spec.tsx b/web/app/components/base/features/new-feature-panel/image-upload/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/features/new-feature-panel/image-upload/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/image-upload/__tests__/index.spec.tsx index 1590efdd75..321c0c353d 100644 --- a/web/app/components/base/features/new-feature-panel/image-upload/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/image-upload/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import ImageUpload from './index' +import { FeaturesProvider } from '../../../context' +import ImageUpload from '../index' vi.mock('@/service/use-common', () => ({ useFileUploadConfig: () => ({ data: undefined }), diff --git a/web/app/components/base/features/new-feature-panel/moderation/form-generation.spec.tsx b/web/app/components/base/features/new-feature-panel/moderation/__tests__/form-generation.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/moderation/form-generation.spec.tsx rename to web/app/components/base/features/new-feature-panel/moderation/__tests__/form-generation.spec.tsx index 14f35dc6b4..c0d2594f28 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/form-generation.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/__tests__/form-generation.spec.tsx @@ -1,7 +1,7 @@ import type { I18nText } from '@/i18n-config/language' import type { CodeBasedExtensionForm } from '@/models/common' import { fireEvent, render, screen } from '@testing-library/react' -import FormGeneration from './form-generation' +import FormGeneration from '../form-generation' const i18n = (en: string, zh = en): I18nText => ({ 'en-US': en, 'zh-Hans': zh }) as unknown as I18nText diff --git a/web/app/components/base/features/new-feature-panel/moderation/index.spec.tsx b/web/app/components/base/features/new-feature-panel/moderation/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/moderation/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/moderation/__tests__/index.spec.tsx index 5c829f3560..0a8ba930ee 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import Moderation from './index' +import { FeaturesProvider } from '../../../context' +import Moderation from '../index' const mockSetShowModerationSettingModal = vi.fn() vi.mock('@/context/modal-context', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/moderation/moderation-content.spec.tsx b/web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-content.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/moderation/moderation-content.spec.tsx rename to web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-content.spec.tsx index ef9bb8ebd4..9caa38d5d4 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/moderation-content.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-content.spec.tsx @@ -1,6 +1,6 @@ import type { ModerationContentConfig } from '@/models/debug' import { fireEvent, render, screen } from '@testing-library/react' -import ModerationContent from './moderation-content' +import ModerationContent from '../moderation-content' const defaultConfig: ModerationContentConfig = { enabled: false, diff --git a/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.spec.tsx b/web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-setting-modal.spec.tsx similarity index 99% rename from web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.spec.tsx rename to web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-setting-modal.spec.tsx index 79098f6816..3c690635da 100644 --- a/web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/moderation/__tests__/moderation-setting-modal.spec.tsx @@ -1,6 +1,6 @@ import type { ModerationConfig } from '@/models/debug' import { fireEvent, render, screen } from '@testing-library/react' -import ModerationSettingModal from './moderation-setting-modal' +import ModerationSettingModal from '../moderation-setting-modal' const mockNotify = vi.fn() vi.mock('@/app/components/base/toast', () => ({ diff --git a/web/app/components/base/features/new-feature-panel/text-to-speech/index.spec.tsx b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/features/new-feature-panel/text-to-speech/index.spec.tsx rename to web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/index.spec.tsx index a9623a8215..62d1a43925 100644 --- a/web/app/components/base/features/new-feature-panel/text-to-speech/index.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/index.spec.tsx @@ -1,9 +1,9 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' import { TtsAutoPlay } from '@/types/app' -import { FeaturesProvider } from '../../context' -import TextToSpeech from './index' +import { FeaturesProvider } from '../../../context' +import TextToSpeech from '../index' vi.mock('@/i18n-config/language', () => ({ languages: [ diff --git a/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.spec.tsx b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/param-config-content.spec.tsx similarity index 98% rename from web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.spec.tsx rename to web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/param-config-content.spec.tsx index b4a0dafd91..66d870f28f 100644 --- a/web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/param-config-content.spec.tsx @@ -1,10 +1,10 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import type { OnFeaturesChange } from '@/app/components/base/features/types' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { TtsAutoPlay } from '@/types/app' -import { FeaturesProvider } from '../../context' -import ParamConfigContent from './param-config-content' +import { FeaturesProvider } from '../../../context' +import ParamConfigContent from '../param-config-content' let mockLanguages = [ { value: 'en-US', name: 'English', example: 'Hello world' }, diff --git a/web/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.spec.tsx b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/voice-settings.spec.tsx similarity index 95% rename from web/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.spec.tsx rename to web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/voice-settings.spec.tsx index d88d302f92..ce67d7a8d5 100644 --- a/web/app/components/base/features/new-feature-panel/text-to-speech/voice-settings.spec.tsx +++ b/web/app/components/base/features/new-feature-panel/text-to-speech/__tests__/voice-settings.spec.tsx @@ -1,7 +1,7 @@ -import type { Features } from '../../types' +import type { Features } from '../../../types' import { fireEvent, render, screen } from '@testing-library/react' -import { FeaturesProvider } from '../../context' -import VoiceSettings from './voice-settings' +import { FeaturesProvider } from '../../../context' +import VoiceSettings from '../voice-settings' vi.mock('next/navigation', () => ({ usePathname: () => '/app/test-app-id/configuration', diff --git a/web/app/components/base/file-icon/index.spec.tsx b/web/app/components/base/file-icon/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/file-icon/index.spec.tsx rename to web/app/components/base/file-icon/__tests__/index.spec.tsx index 526a889f34..7061b51627 100644 --- a/web/app/components/base/file-icon/index.spec.tsx +++ b/web/app/components/base/file-icon/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import FileIcon from '.' +import FileIcon from '..' describe('File icon component', () => { const testCases = [ diff --git a/web/app/components/base/file-thumb/image-render.spec.tsx b/web/app/components/base/file-thumb/__tests__/image-render.spec.tsx similarity index 92% rename from web/app/components/base/file-thumb/image-render.spec.tsx rename to web/app/components/base/file-thumb/__tests__/image-render.spec.tsx index cef41b912c..7ccd3391df 100644 --- a/web/app/components/base/file-thumb/image-render.spec.tsx +++ b/web/app/components/base/file-thumb/__tests__/image-render.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import ImageRender from './image-render' +import ImageRender from '../image-render' describe('ImageRender Component', () => { const mockProps = { diff --git a/web/app/components/base/file-thumb/index.spec.tsx b/web/app/components/base/file-thumb/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/file-thumb/index.spec.tsx rename to web/app/components/base/file-thumb/__tests__/index.spec.tsx index 205e6f8d6f..368f14ae75 100644 --- a/web/app/components/base/file-thumb/index.spec.tsx +++ b/web/app/components/base/file-thumb/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import type { ImgHTMLAttributes } from 'react' import { fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import FileThumb from './index' +import FileThumb from '../index' vi.mock('next/image', () => ({ __esModule: true, diff --git a/web/app/components/base/file-uploader/audio-preview.spec.tsx b/web/app/components/base/file-uploader/__tests__/audio-preview.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/audio-preview.spec.tsx rename to web/app/components/base/file-uploader/__tests__/audio-preview.spec.tsx index a2034b202a..5a5740ef0d 100644 --- a/web/app/components/base/file-uploader/audio-preview.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/audio-preview.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import AudioPreview from './audio-preview' +import AudioPreview from '../audio-preview' describe('AudioPreview', () => { beforeEach(() => { diff --git a/web/app/components/base/file-uploader/constants.spec.ts b/web/app/components/base/file-uploader/__tests__/constants.spec.ts similarity index 99% rename from web/app/components/base/file-uploader/constants.spec.ts rename to web/app/components/base/file-uploader/__tests__/constants.spec.ts index abe44aa842..7225fbcf04 100644 --- a/web/app/components/base/file-uploader/constants.spec.ts +++ b/web/app/components/base/file-uploader/__tests__/constants.spec.ts @@ -5,7 +5,7 @@ import { IMG_SIZE_LIMIT, MAX_FILE_UPLOAD_LIMIT, VIDEO_SIZE_LIMIT, -} from './constants' +} from '../constants' describe('file-uploader constants', () => { describe('size limit constants', () => { diff --git a/web/app/components/base/file-uploader/file-image-render.spec.tsx b/web/app/components/base/file-uploader/__tests__/file-image-render.spec.tsx similarity index 97% rename from web/app/components/base/file-uploader/file-image-render.spec.tsx rename to web/app/components/base/file-uploader/__tests__/file-image-render.spec.tsx index fa85011f5c..84c3b06e85 100644 --- a/web/app/components/base/file-uploader/file-image-render.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/file-image-render.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import FileImageRender from './file-image-render' +import FileImageRender from '../file-image-render' describe('FileImageRender', () => { beforeEach(() => { diff --git a/web/app/components/base/file-uploader/file-input.spec.tsx b/web/app/components/base/file-uploader/__tests__/file-input.spec.tsx similarity index 97% rename from web/app/components/base/file-uploader/file-input.spec.tsx rename to web/app/components/base/file-uploader/__tests__/file-input.spec.tsx index 73c7690e29..ac0070f9df 100644 --- a/web/app/components/base/file-uploader/file-input.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/file-input.spec.tsx @@ -1,12 +1,12 @@ -import type { FileEntity } from './types' +import type { FileEntity } from '../types' import type { FileUpload } from '@/app/components/base/features/types' import { fireEvent, render } from '@testing-library/react' -import FileInput from './file-input' -import { FileContextProvider } from './store' +import FileInput from '../file-input' +import { FileContextProvider } from '../store' const mockHandleLocalFileUpload = vi.fn() -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useFile: () => ({ handleLocalFileUpload: mockHandleLocalFileUpload, }), diff --git a/web/app/components/base/file-uploader/file-list-in-log.spec.tsx b/web/app/components/base/file-uploader/__tests__/file-list-in-log.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/file-list-in-log.spec.tsx rename to web/app/components/base/file-uploader/__tests__/file-list-in-log.spec.tsx index 0c1dff8759..f184850936 100644 --- a/web/app/components/base/file-uploader/file-list-in-log.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/file-list-in-log.spec.tsx @@ -1,7 +1,7 @@ -import type { FileEntity } from './types' +import type { FileEntity } from '../types' import { fireEvent, render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import FileListInLog from './file-list-in-log' +import FileListInLog from '../file-list-in-log' const createFile = (overrides: Partial = {}): FileEntity => ({ id: `file-${Math.random()}`, diff --git a/web/app/components/base/file-uploader/file-type-icon.spec.tsx b/web/app/components/base/file-uploader/__tests__/file-type-icon.spec.tsx similarity index 96% rename from web/app/components/base/file-uploader/file-type-icon.spec.tsx rename to web/app/components/base/file-uploader/__tests__/file-type-icon.spec.tsx index 89b42b489d..1da3804878 100644 --- a/web/app/components/base/file-uploader/file-type-icon.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/file-type-icon.spec.tsx @@ -1,6 +1,6 @@ -import type { FileAppearanceTypeEnum } from './types' +import type { FileAppearanceTypeEnum } from '../types' import { render } from '@testing-library/react' -import FileTypeIcon from './file-type-icon' +import FileTypeIcon from '../file-type-icon' describe('FileTypeIcon', () => { beforeEach(() => { diff --git a/web/app/components/base/file-uploader/hooks.spec.ts b/web/app/components/base/file-uploader/__tests__/hooks.spec.ts similarity index 99% rename from web/app/components/base/file-uploader/hooks.spec.ts rename to web/app/components/base/file-uploader/__tests__/hooks.spec.ts index 5577b87649..00c64224aa 100644 --- a/web/app/components/base/file-uploader/hooks.spec.ts +++ b/web/app/components/base/file-uploader/__tests__/hooks.spec.ts @@ -1,8 +1,8 @@ -import type { FileEntity } from './types' +import type { FileEntity } from '../types' import type { FileUpload } from '@/app/components/base/features/types' import type { FileUploadConfigResponse } from '@/models/common' import { act, renderHook } from '@testing-library/react' -import { useFile, useFileSizeLimit } from './hooks' +import { useFile, useFileSizeLimit } from '../hooks' const mockNotify = vi.fn() @@ -19,7 +19,7 @@ vi.mock('@/app/components/base/toast', () => ({ const mockSetFiles = vi.fn() let mockStoreFiles: FileEntity[] = [] -vi.mock('./store', () => ({ +vi.mock('../store', () => ({ useFileStore: () => ({ getState: () => ({ files: mockStoreFiles, @@ -31,7 +31,7 @@ vi.mock('./store', () => ({ const mockFileUpload = vi.fn() const mockIsAllowedFileExtension = vi.fn().mockReturnValue(true) const mockGetSupportFileType = vi.fn().mockReturnValue('document') -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ fileUpload: (...args: unknown[]) => mockFileUpload(...args), getFileUploadErrorMessage: vi.fn().mockReturnValue('Upload error'), getSupportFileType: (...args: unknown[]) => mockGetSupportFileType(...args), diff --git a/web/app/components/base/file-uploader/pdf-preview.spec.tsx b/web/app/components/base/file-uploader/__tests__/pdf-preview.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/pdf-preview.spec.tsx rename to web/app/components/base/file-uploader/__tests__/pdf-preview.spec.tsx index df07a592ef..b3c48a7061 100644 --- a/web/app/components/base/file-uploader/pdf-preview.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/pdf-preview.spec.tsx @@ -1,8 +1,8 @@ import type { ReactNode } from 'react' import { fireEvent, render, screen } from '@testing-library/react' -import PdfPreview from './pdf-preview' +import PdfPreview from '../pdf-preview' -vi.mock('./pdf-highlighter-adapter', () => ({ +vi.mock('../pdf-highlighter-adapter', () => ({ PdfLoader: ({ children, beforeLoad }: { children: (doc: unknown) => ReactNode, beforeLoad: ReactNode }) => (
{beforeLoad} diff --git a/web/app/components/base/file-uploader/store.spec.tsx b/web/app/components/base/file-uploader/__tests__/store.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/store.spec.tsx rename to web/app/components/base/file-uploader/__tests__/store.spec.tsx index 96053498d9..89516873cc 100644 --- a/web/app/components/base/file-uploader/store.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/store.spec.tsx @@ -1,7 +1,7 @@ -import type { FileEntity } from './types' +import type { FileEntity } from '../types' import { render, renderHook, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import { createFileStore, FileContext, FileContextProvider, useFileStore, useStore } from './store' +import { createFileStore, FileContext, FileContextProvider, useFileStore, useStore } from '../store' const createMockFile = (overrides: Partial = {}): FileEntity => ({ id: 'file-1', diff --git a/web/app/components/base/file-uploader/utils.spec.ts b/web/app/components/base/file-uploader/__tests__/utils.spec.ts similarity index 98% rename from web/app/components/base/file-uploader/utils.spec.ts rename to web/app/components/base/file-uploader/__tests__/utils.spec.ts index 358fc586eb..7a4956307d 100644 --- a/web/app/components/base/file-uploader/utils.spec.ts +++ b/web/app/components/base/file-uploader/__tests__/utils.spec.ts @@ -1,9 +1,9 @@ -import type { FileEntity } from './types' +import type { FileEntity } from '../types' import { SupportUploadFileTypes } from '@/app/components/workflow/types' import { upload } from '@/service/base' import { TransferMethod } from '@/types/app' -import { FILE_EXTS } from '../prompt-editor/constants' -import { FileAppearanceTypeEnum } from './types' +import { FILE_EXTS } from '../../prompt-editor/constants' +import { FileAppearanceTypeEnum } from '../types' import { fileIsUploaded, fileUpload, @@ -17,7 +17,7 @@ import { getSupportFileExtensionList, getSupportFileType, isAllowedFileExtension, -} from './utils' +} from '../utils' vi.mock('@/service/base', () => ({ upload: vi.fn(), @@ -866,14 +866,14 @@ describe('file-uploader utils', () => { expect(fileIsUploaded({ uploadedId: '123', progress: 100, - } as any)).toBe(true) + } as Partial as FileEntity)).toBe(true) }) it('should identify remote files as uploaded', () => { expect(fileIsUploaded({ transferMethod: TransferMethod.remote_url, progress: 100, - } as any)).toBe(true) + } as Partial as FileEntity)).toBe(true) }) }) }) diff --git a/web/app/components/base/file-uploader/video-preview.spec.tsx b/web/app/components/base/file-uploader/__tests__/video-preview.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/video-preview.spec.tsx rename to web/app/components/base/file-uploader/__tests__/video-preview.spec.tsx index 2384281c8e..c95455caf3 100644 --- a/web/app/components/base/file-uploader/video-preview.spec.tsx +++ b/web/app/components/base/file-uploader/__tests__/video-preview.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render } from '@testing-library/react' -import VideoPreview from './video-preview' +import VideoPreview from '../video-preview' describe('VideoPreview', () => { beforeEach(() => { diff --git a/web/app/components/base/file-uploader/file-from-link-or-local/index.spec.tsx b/web/app/components/base/file-uploader/file-from-link-or-local/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/file-uploader/file-from-link-or-local/index.spec.tsx rename to web/app/components/base/file-uploader/file-from-link-or-local/__tests__/index.spec.tsx index 5227b9b2b2..9847aa863e 100644 --- a/web/app/components/base/file-uploader/file-from-link-or-local/index.spec.tsx +++ b/web/app/components/base/file-uploader/file-from-link-or-local/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import type { FileUpload } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' -import { FileContextProvider } from '../store' -import FileFromLinkOrLocal from './index' +import { FileContextProvider } from '../../store' +import FileFromLinkOrLocal from '../index' let mockFiles: FileEntity[] = [] @@ -11,7 +11,7 @@ function createStubFile(id: string): FileEntity { } const mockHandleLoadFileFromLink = vi.fn() -vi.mock('../hooks', () => ({ +vi.mock('../../hooks', () => ({ useFile: () => ({ handleLoadFileFromLink: mockHandleLoadFileFromLink, }), diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/file-item.spec.tsx similarity index 99% rename from web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/file-item.spec.tsx index 72d4643955..b2198680f5 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/file-item.spec.tsx @@ -1,8 +1,8 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import { PreviewMode } from '@/app/components/base/features/types' import { TransferMethod } from '@/types/app' -import FileInAttachmentItem from './file-item' +import FileInAttachmentItem from '../file-item' vi.mock('@/utils/download', () => ({ downloadUrl: vi.fn(), diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/file-uploader/file-uploader-in-attachment/index.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx index 81946e0d1c..895c960ae9 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx @@ -1,12 +1,12 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import type { FileUpload } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import FileUploaderInAttachmentWrapper from './index' +import FileUploaderInAttachmentWrapper from '../index' const mockHandleRemoveFile = vi.fn() const mockHandleReUploadFile = vi.fn() -vi.mock('../hooks', () => ({ +vi.mock('../../hooks', () => ({ useFile: () => ({ handleRemoveFile: mockHandleRemoveFile, handleReUploadFile: mockHandleReUploadFile, diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-image-item.spec.tsx similarity index 99% rename from web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-image-item.spec.tsx index e30c6c886c..2bc418cf1d 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-image-item.spec.tsx @@ -1,7 +1,7 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import FileImageItem from './file-image-item' +import FileImageItem from '../file-image-item' vi.mock('@/utils/download', () => ({ downloadUrl: vi.fn(), diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-item.spec.tsx similarity index 98% rename from web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-item.spec.tsx index 92ce1a5e9e..c03f009cee 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-item.spec.tsx @@ -1,7 +1,7 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import { fireEvent, render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import FileItem from './file-item' +import FileItem from '../file-item' vi.mock('@/utils/download', () => ({ downloadUrl: vi.fn(), @@ -11,7 +11,7 @@ vi.mock('@/utils/format', () => ({ formatFileSize: (size: number) => `${size}B`, })) -vi.mock('../dynamic-pdf-preview', () => ({ +vi.mock('../../dynamic-pdf-preview', () => ({ default: ({ url, onCancel }: { url: string, onCancel: () => void }) => (
diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-list.spec.tsx similarity index 95% rename from web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-list.spec.tsx index cae64eb6cb..de0ae72e35 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-list.spec.tsx @@ -1,11 +1,11 @@ -import type { FileEntity } from '../types' +import type { FileEntity } from '../../types' import type { FileUpload } from '@/app/components/base/features/types' import { render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import { FileContextProvider } from '../store' -import { FileList, FileListInChatInput } from './file-list' +import { FileContextProvider } from '../../store' +import { FileList, FileListInChatInput } from '../file-list' -vi.mock('../hooks', () => ({ +vi.mock('../../hooks', () => ({ useFile: () => ({ handleRemoveFile: vi.fn(), handleReUploadFile: vi.fn(), diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/index.spec.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/file-uploader/file-uploader-in-chat-input/index.spec.tsx rename to web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/index.spec.tsx index 0cdde4835d..233dba7c8e 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/index.spec.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { FileUpload } from '@/app/components/base/features/types' import { fireEvent, render, screen } from '@testing-library/react' -import { FileContextProvider } from '../store' -import FileUploaderInChatInput from './index' +import { FileContextProvider } from '../../store' +import FileUploaderInChatInput from '../index' vi.mock('@/types/app', async (importOriginal) => { const actual = await importOriginal() @@ -14,7 +14,7 @@ vi.mock('@/types/app', async (importOriginal) => { } }) -vi.mock('../hooks', () => ({ +vi.mock('../../hooks', () => ({ useFile: () => ({ handleLoadFileFromLink: vi.fn(), }), diff --git a/web/app/components/base/float-right-container/index.spec.tsx b/web/app/components/base/float-right-container/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/float-right-container/index.spec.tsx rename to web/app/components/base/float-right-container/__tests__/index.spec.tsx index 4cf87b189c..ee820230d8 100644 --- a/web/app/components/base/float-right-container/index.spec.tsx +++ b/web/app/components/base/float-right-container/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import FloatRightContainer from './index' +import FloatRightContainer from '../index' describe('FloatRightContainer', () => { beforeEach(() => { diff --git a/web/app/components/base/form/index.spec.tsx b/web/app/components/base/form/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/form/index.spec.tsx rename to web/app/components/base/form/__tests__/index.spec.tsx index 27dab0c9dc..683c43a8db 100644 --- a/web/app/components/base/form/index.spec.tsx +++ b/web/app/components/base/form/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import { useAppForm, withForm } from './index' +import { useAppForm, withForm } from '../index' const FormHarness = ({ onSubmit }: { onSubmit: (value: Record) => void }) => { const form = useAppForm({ diff --git a/web/app/components/base/form/types.spec.ts b/web/app/components/base/form/__tests__/types.spec.ts similarity index 88% rename from web/app/components/base/form/types.spec.ts rename to web/app/components/base/form/__tests__/types.spec.ts index 38d032bac7..baf76f99b1 100644 --- a/web/app/components/base/form/types.spec.ts +++ b/web/app/components/base/form/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { FormItemValidateStatusEnum, FormTypeEnum } from './types' +import { FormItemValidateStatusEnum, FormTypeEnum } from '../types' describe('form types', () => { it('should expose expected form type values', () => { diff --git a/web/app/components/base/form/components/label.spec.tsx b/web/app/components/base/form/components/__tests__/label.spec.tsx similarity index 98% rename from web/app/components/base/form/components/label.spec.tsx rename to web/app/components/base/form/components/__tests__/label.spec.tsx index ebda6d5039..a3f564dafe 100644 --- a/web/app/components/base/form/components/label.spec.tsx +++ b/web/app/components/base/form/components/__tests__/label.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import Label from './label' +import Label from '../label' describe('Label', () => { const defaultProps = { diff --git a/web/app/components/base/form/components/base/base-field.spec.tsx b/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx similarity index 99% rename from web/app/components/base/form/components/base/base-field.spec.tsx rename to web/app/components/base/form/components/base/__tests__/base-field.spec.tsx index 7c50b524a5..898dc8a821 100644 --- a/web/app/components/base/form/components/base/base-field.spec.tsx +++ b/web/app/components/base/form/components/base/__tests__/base-field.spec.tsx @@ -3,7 +3,7 @@ import type { FormSchema } from '@/app/components/base/form/types' import { useForm } from '@tanstack/react-form' import { fireEvent, render, screen } from '@testing-library/react' import { FormItemValidateStatusEnum, FormTypeEnum } from '@/app/components/base/form/types' -import BaseField from './base-field' +import BaseField from '../base-field' const mockDynamicOptions = vi.fn() diff --git a/web/app/components/base/form/components/base/base-form.spec.tsx b/web/app/components/base/form/components/base/__tests__/base-form.spec.tsx similarity index 98% rename from web/app/components/base/form/components/base/base-form.spec.tsx rename to web/app/components/base/form/components/base/__tests__/base-form.spec.tsx index 5d2c662aa3..f887aaea64 100644 --- a/web/app/components/base/form/components/base/base-form.spec.tsx +++ b/web/app/components/base/form/components/base/__tests__/base-form.spec.tsx @@ -1,7 +1,7 @@ import type { FormRefObject, FormSchema } from '@/app/components/base/form/types' import { act, fireEvent, render, screen } from '@testing-library/react' import { FormTypeEnum } from '@/app/components/base/form/types' -import BaseForm from './base-form' +import BaseForm from '../base-form' vi.mock('@/service/use-triggers', () => ({ useTriggerPluginDynamicOptions: () => ({ diff --git a/web/app/components/base/form/components/base/index.spec.tsx b/web/app/components/base/form/components/base/__tests__/index.spec.tsx similarity index 83% rename from web/app/components/base/form/components/base/index.spec.tsx rename to web/app/components/base/form/components/base/__tests__/index.spec.tsx index 16f9806b27..81190d75bd 100644 --- a/web/app/components/base/form/components/base/index.spec.tsx +++ b/web/app/components/base/form/components/base/__tests__/index.spec.tsx @@ -1,4 +1,4 @@ -import { BaseField, BaseForm } from '.' +import { BaseField, BaseForm } from '..' describe('base component exports', () => { it('should export BaseField', () => { diff --git a/web/app/components/base/form/components/field/checkbox.spec.tsx b/web/app/components/base/form/components/field/__tests__/checkbox.spec.tsx similarity index 92% rename from web/app/components/base/form/components/field/checkbox.spec.tsx rename to web/app/components/base/form/components/field/__tests__/checkbox.spec.tsx index ee7d8ee6ab..6005d9261b 100644 --- a/web/app/components/base/form/components/field/checkbox.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/checkbox.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import CheckboxField from './checkbox' +import CheckboxField from '../checkbox' const mockField = { name: 'checkbox-field', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/custom-select.spec.tsx b/web/app/components/base/form/components/field/__tests__/custom-select.spec.tsx similarity index 93% rename from web/app/components/base/form/components/field/custom-select.spec.tsx rename to web/app/components/base/form/components/field/__tests__/custom-select.spec.tsx index 97f13758ec..5470df58a3 100644 --- a/web/app/components/base/form/components/field/custom-select.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/custom-select.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import CustomSelectField from './custom-select' +import CustomSelectField from '../custom-select' const mockField = { name: 'custom-select-field', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/file-types.spec.tsx b/web/app/components/base/form/components/field/__tests__/file-types.spec.tsx similarity index 98% rename from web/app/components/base/form/components/field/file-types.spec.tsx rename to web/app/components/base/form/components/field/__tests__/file-types.spec.tsx index 0c2a95c655..971e04f258 100644 --- a/web/app/components/base/form/components/field/file-types.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/file-types.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react' import { SupportUploadFileTypes } from '@/app/components/workflow/types' -import FileTypesField from './file-types' +import FileTypesField from '../file-types' type FileTypeValue = { allowedFileTypes: string[] @@ -18,7 +18,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/file-uploader.spec.tsx b/web/app/components/base/form/components/field/__tests__/file-uploader.spec.tsx similarity index 96% rename from web/app/components/base/form/components/field/file-uploader.spec.tsx rename to web/app/components/base/form/components/field/__tests__/file-uploader.spec.tsx index c32d370346..dee7c97222 100644 --- a/web/app/components/base/form/components/field/file-uploader.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/file-uploader.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen } from '@testing-library/react' import { SupportUploadFileTypes } from '@/app/components/workflow/types' import { TransferMethod } from '@/types/app' -import FileUploaderField from './file-uploader' +import FileUploaderField from '../file-uploader' const mockField = { name: 'files', @@ -23,7 +23,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/number-input.spec.tsx b/web/app/components/base/form/components/field/__tests__/number-input.spec.tsx similarity index 90% rename from web/app/components/base/form/components/field/number-input.spec.tsx rename to web/app/components/base/form/components/field/__tests__/number-input.spec.tsx index 85c46f1df2..049e19d75e 100644 --- a/web/app/components/base/form/components/field/number-input.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/number-input.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import NumberInputField from './number-input' +import NumberInputField from '../number-input' const mockField = { name: 'number-field', @@ -10,7 +10,7 @@ const mockField = { handleBlur: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/number-slider.spec.tsx b/web/app/components/base/form/components/field/__tests__/number-slider.spec.tsx similarity index 93% rename from web/app/components/base/form/components/field/number-slider.spec.tsx rename to web/app/components/base/form/components/field/__tests__/number-slider.spec.tsx index a9676c4338..ca0e83462f 100644 --- a/web/app/components/base/form/components/field/number-slider.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/number-slider.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import NumberSliderField from './number-slider' +import NumberSliderField from '../number-slider' const mockField = { name: 'slider-field', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/options.spec.tsx b/web/app/components/base/form/components/field/__tests__/options.spec.tsx similarity index 94% rename from web/app/components/base/form/components/field/options.spec.tsx rename to web/app/components/base/form/components/field/__tests__/options.spec.tsx index a7860079c6..93f956a4c5 100644 --- a/web/app/components/base/form/components/field/options.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/options.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import OptionsField from './options' +import OptionsField from '../options' const mockField = { name: 'options-field', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/select.spec.tsx b/web/app/components/base/form/components/field/__tests__/select.spec.tsx similarity index 94% rename from web/app/components/base/form/components/field/select.spec.tsx rename to web/app/components/base/form/components/field/__tests__/select.spec.tsx index d38a9ac511..0bf6b4e022 100644 --- a/web/app/components/base/form/components/field/select.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/select.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SelectField from './select' +import SelectField from '../select' const mockField = { name: 'select-field', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/text-area.spec.tsx b/web/app/components/base/form/components/field/__tests__/text-area.spec.tsx similarity index 92% rename from web/app/components/base/form/components/field/text-area.spec.tsx rename to web/app/components/base/form/components/field/__tests__/text-area.spec.tsx index 78b1be14e5..00033cdad5 100644 --- a/web/app/components/base/form/components/field/text-area.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/text-area.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import TextAreaField from './text-area' +import TextAreaField from '../text-area' const mockField = { name: 'text-area-field', @@ -10,7 +10,7 @@ const mockField = { handleBlur: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/text.spec.tsx b/web/app/components/base/form/components/field/__tests__/text.spec.tsx similarity index 92% rename from web/app/components/base/form/components/field/text.spec.tsx rename to web/app/components/base/form/components/field/__tests__/text.spec.tsx index 5a3010c6b4..5ebc82e858 100644 --- a/web/app/components/base/form/components/field/text.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/text.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import TextField from './text' +import TextField from '../text' const mockField = { name: 'text-field', @@ -10,7 +10,7 @@ const mockField = { handleBlur: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/upload-method.spec.tsx b/web/app/components/base/form/components/field/__tests__/upload-method.spec.tsx similarity index 95% rename from web/app/components/base/form/components/field/upload-method.spec.tsx rename to web/app/components/base/form/components/field/__tests__/upload-method.spec.tsx index 27d937ffb2..652f1e9171 100644 --- a/web/app/components/base/form/components/field/upload-method.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/upload-method.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react' import { TransferMethod } from '@/types/app' -import UploadMethodField from './upload-method' +import UploadMethodField from '../upload-method' const mockField = { name: 'upload-method', @@ -10,7 +10,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../..', () => ({ +vi.mock('../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/variable-or-constant-input.spec.tsx b/web/app/components/base/form/components/field/__tests__/variable-or-constant-input.spec.tsx similarity index 96% rename from web/app/components/base/form/components/field/variable-or-constant-input.spec.tsx rename to web/app/components/base/form/components/field/__tests__/variable-or-constant-input.spec.tsx index 57db5ec0d6..5842f5c75b 100644 --- a/web/app/components/base/form/components/field/variable-or-constant-input.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/variable-or-constant-input.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import VariableOrConstantInputField from './variable-or-constant-input' +import VariableOrConstantInputField from '../variable-or-constant-input' vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({ default: ({ onChange }: { onChange?: () => void }) => ( diff --git a/web/app/components/base/form/components/field/variable-selector.spec.tsx b/web/app/components/base/form/components/field/__tests__/variable-selector.spec.tsx similarity index 94% rename from web/app/components/base/form/components/field/variable-selector.spec.tsx rename to web/app/components/base/form/components/field/__tests__/variable-selector.spec.tsx index ba9e0e9ca7..df6f6b2531 100644 --- a/web/app/components/base/form/components/field/variable-selector.spec.tsx +++ b/web/app/components/base/form/components/field/__tests__/variable-selector.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import VariableSelectorField from './variable-selector' +import VariableSelectorField from '../variable-selector' vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({ default: ({ onChange }: { onChange?: () => void }) => ( diff --git a/web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx b/web/app/components/base/form/components/field/input-type-select/__tests__/hooks.spec.tsx similarity index 93% rename from web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx rename to web/app/components/base/form/components/field/input-type-select/__tests__/hooks.spec.tsx index a556697db1..236bcc95ea 100644 --- a/web/app/components/base/form/components/field/input-type-select/hooks.spec.tsx +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/hooks.spec.tsx @@ -1,5 +1,5 @@ import { renderHook } from '@testing-library/react' -import { useInputTypeOptions } from './hooks' +import { useInputTypeOptions } from '../hooks' describe('useInputTypeOptions', () => { it('should include file options when supportFile is true', () => { diff --git a/web/app/components/base/form/components/field/input-type-select/index.spec.tsx b/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx similarity index 93% rename from web/app/components/base/form/components/field/input-type-select/index.spec.tsx rename to web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx index e31cf17af5..bb7ae80a34 100644 --- a/web/app/components/base/form/components/field/input-type-select/index.spec.tsx +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import InputTypeSelectField from './index' +import InputTypeSelectField from '../index' const mockField = { name: 'input-type', @@ -9,7 +9,7 @@ const mockField = { handleChange: vi.fn(), } -vi.mock('../../..', () => ({ +vi.mock('../../../..', () => ({ useFieldContext: () => mockField, })) diff --git a/web/app/components/base/form/components/field/input-type-select/option.spec.tsx b/web/app/components/base/form/components/field/input-type-select/__tests__/option.spec.tsx similarity index 94% rename from web/app/components/base/form/components/field/input-type-select/option.spec.tsx rename to web/app/components/base/form/components/field/input-type-select/__tests__/option.spec.tsx index 475ef20410..a3dc91193b 100644 --- a/web/app/components/base/form/components/field/input-type-select/option.spec.tsx +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/option.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Option from './option' +import Option from '../option' const MockIcon = () => diff --git a/web/app/components/base/form/components/field/input-type-select/trigger.spec.tsx b/web/app/components/base/form/components/field/input-type-select/__tests__/trigger.spec.tsx similarity index 95% rename from web/app/components/base/form/components/field/input-type-select/trigger.spec.tsx rename to web/app/components/base/form/components/field/input-type-select/__tests__/trigger.spec.tsx index 0bd2274703..0957ac41c1 100644 --- a/web/app/components/base/form/components/field/input-type-select/trigger.spec.tsx +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/trigger.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Trigger from './trigger' +import Trigger from '../trigger' const MockIcon = () => diff --git a/web/app/components/base/form/components/field/input-type-select/types.spec.ts b/web/app/components/base/form/components/field/input-type-select/__tests__/types.spec.ts similarity index 89% rename from web/app/components/base/form/components/field/input-type-select/types.spec.ts rename to web/app/components/base/form/components/field/input-type-select/__tests__/types.spec.ts index 3260f54ce4..5d2215f1fa 100644 --- a/web/app/components/base/form/components/field/input-type-select/types.spec.ts +++ b/web/app/components/base/form/components/field/input-type-select/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { InputTypeEnum } from './types' +import { InputTypeEnum } from '../types' describe('InputTypeEnum', () => { it('should accept valid input types', () => { diff --git a/web/app/components/base/form/components/field/mixed-variable-text-input/index.spec.tsx b/web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/index.spec.tsx similarity index 93% rename from web/app/components/base/form/components/field/mixed-variable-text-input/index.spec.tsx rename to web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/index.spec.tsx index 94a0c8746f..3a6be12c58 100644 --- a/web/app/components/base/form/components/field/mixed-variable-text-input/index.spec.tsx +++ b/web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import MixedVariableTextInput from './index' +import MixedVariableTextInput from '../index' describe('MixedVariableTextInput', () => { it('should render placeholder guidance and data type badge', () => { diff --git a/web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.spec.tsx b/web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/placeholder.spec.tsx similarity index 98% rename from web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.spec.tsx rename to web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/placeholder.spec.tsx index 6ce68c3b47..093131d01f 100644 --- a/web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.spec.tsx +++ b/web/app/components/base/form/components/field/mixed-variable-text-input/__tests__/placeholder.spec.tsx @@ -5,7 +5,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { $getRoot } from 'lexical' import { CustomTextNode } from '@/app/components/base/prompt-editor/plugins/custom-text/node' -import Placeholder from './placeholder' +import Placeholder from '../placeholder' const config = { namespace: 'placeholder-test', diff --git a/web/app/components/base/form/components/form/actions.spec.tsx b/web/app/components/base/form/components/form/__tests__/actions.spec.tsx similarity index 92% rename from web/app/components/base/form/components/form/actions.spec.tsx rename to web/app/components/base/form/components/form/__tests__/actions.spec.tsx index eb4a6ea146..0bd6655cb5 100644 --- a/web/app/components/base/form/components/form/actions.spec.tsx +++ b/web/app/components/base/form/components/form/__tests__/actions.spec.tsx @@ -1,8 +1,8 @@ -import type { FormType } from '../..' -import type { CustomActionsProps } from './actions' +import type { FormType } from '../../..' +import type { CustomActionsProps } from '../actions' import { fireEvent, render, screen } from '@testing-library/react' -import { formContext } from '../..' -import Actions from './actions' +import { formContext } from '../../..' +import Actions from '../actions' const renderWithForm = ({ canSubmit, diff --git a/web/app/components/base/form/form-scenarios/auth/index.spec.tsx b/web/app/components/base/form/form-scenarios/auth/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/form/form-scenarios/auth/index.spec.tsx rename to web/app/components/base/form/form-scenarios/auth/__tests__/index.spec.tsx index 5560e7eada..e12397ed60 100644 --- a/web/app/components/base/form/form-scenarios/auth/index.spec.tsx +++ b/web/app/components/base/form/form-scenarios/auth/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import { FormTypeEnum } from '@/app/components/base/form/types' -import AuthForm from './index' +import AuthForm from '../index' const formSchemas = [{ type: FormTypeEnum.textInput, diff --git a/web/app/components/base/form/form-scenarios/base/field.spec.tsx b/web/app/components/base/form/form-scenarios/base/__tests__/field.spec.tsx similarity index 96% rename from web/app/components/base/form/form-scenarios/base/field.spec.tsx rename to web/app/components/base/form/form-scenarios/base/__tests__/field.spec.tsx index c05f291103..7de473e4c8 100644 --- a/web/app/components/base/form/form-scenarios/base/field.spec.tsx +++ b/web/app/components/base/form/form-scenarios/base/__tests__/field.spec.tsx @@ -1,10 +1,10 @@ -import type { BaseConfiguration } from './types' +import type { BaseConfiguration } from '../types' import { render, screen } from '@testing-library/react' import { useMemo } from 'react' import { TransferMethod } from '@/types/app' -import { useAppForm } from '../..' -import BaseField from './field' -import { BaseFieldType } from './types' +import { useAppForm } from '../../..' +import BaseField from '../field' +import { BaseFieldType } from '../types' vi.mock('next/navigation', () => ({ useParams: () => ({}), diff --git a/web/app/components/base/form/form-scenarios/base/index.spec.tsx b/web/app/components/base/form/form-scenarios/base/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/form/form-scenarios/base/index.spec.tsx rename to web/app/components/base/form/form-scenarios/base/__tests__/index.spec.tsx index fc1aa325f2..c8d215b1d7 100644 --- a/web/app/components/base/form/form-scenarios/base/index.spec.tsx +++ b/web/app/components/base/form/form-scenarios/base/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import BaseForm from './index' -import { BaseFieldType } from './types' +import BaseForm from '../index' +import { BaseFieldType } from '../types' const baseConfigurations = [{ type: BaseFieldType.textInput, diff --git a/web/app/components/base/form/form-scenarios/base/types.spec.ts b/web/app/components/base/form/form-scenarios/base/__tests__/types.spec.ts similarity index 87% rename from web/app/components/base/form/form-scenarios/base/types.spec.ts rename to web/app/components/base/form/form-scenarios/base/__tests__/types.spec.ts index b565b5cd2a..33e402b78e 100644 --- a/web/app/components/base/form/form-scenarios/base/types.spec.ts +++ b/web/app/components/base/form/form-scenarios/base/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { BaseFieldType } from './types' +import { BaseFieldType } from '../types' describe('base scenario types', () => { it('should include all supported base field types', () => { diff --git a/web/app/components/base/form/form-scenarios/base/utils.spec.ts b/web/app/components/base/form/form-scenarios/base/__tests__/utils.spec.ts similarity index 94% rename from web/app/components/base/form/form-scenarios/base/utils.spec.ts rename to web/app/components/base/form/form-scenarios/base/__tests__/utils.spec.ts index 2c11acd205..36a2cc1dd4 100644 --- a/web/app/components/base/form/form-scenarios/base/utils.spec.ts +++ b/web/app/components/base/form/form-scenarios/base/__tests__/utils.spec.ts @@ -1,5 +1,5 @@ -import { BaseFieldType } from './types' -import { generateZodSchema } from './utils' +import { BaseFieldType } from '../types' +import { generateZodSchema } from '../utils' describe('base scenario schema generator', () => { it('should validate required text fields with max length', () => { diff --git a/web/app/components/base/form/form-scenarios/demo/contact-fields.spec.tsx b/web/app/components/base/form/form-scenarios/demo/__tests__/contact-fields.spec.tsx similarity index 83% rename from web/app/components/base/form/form-scenarios/demo/contact-fields.spec.tsx rename to web/app/components/base/form/form-scenarios/demo/__tests__/contact-fields.spec.tsx index 7a97d3a48b..b8f67d58b9 100644 --- a/web/app/components/base/form/form-scenarios/demo/contact-fields.spec.tsx +++ b/web/app/components/base/form/form-scenarios/demo/__tests__/contact-fields.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' -import { useAppForm } from '../..' -import ContactFields from './contact-fields' -import { demoFormOpts } from './shared-options' +import { useAppForm } from '../../..' +import ContactFields from '../contact-fields' +import { demoFormOpts } from '../shared-options' const ContactFieldsHarness = () => { const form = useAppForm({ diff --git a/web/app/components/base/form/form-scenarios/demo/index.spec.tsx b/web/app/components/base/form/form-scenarios/demo/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/form/form-scenarios/demo/index.spec.tsx rename to web/app/components/base/form/form-scenarios/demo/__tests__/index.spec.tsx index d6534e8df7..e2a83b7ad4 100644 --- a/web/app/components/base/form/form-scenarios/demo/index.spec.tsx +++ b/web/app/components/base/form/form-scenarios/demo/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import DemoForm from './index' +import DemoForm from '../index' describe('DemoForm', () => { const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) diff --git a/web/app/components/base/form/form-scenarios/demo/shared-options.spec.tsx b/web/app/components/base/form/form-scenarios/demo/__tests__/shared-options.spec.tsx similarity index 86% rename from web/app/components/base/form/form-scenarios/demo/shared-options.spec.tsx rename to web/app/components/base/form/form-scenarios/demo/__tests__/shared-options.spec.tsx index 5e44747612..70e078fcf5 100644 --- a/web/app/components/base/form/form-scenarios/demo/shared-options.spec.tsx +++ b/web/app/components/base/form/form-scenarios/demo/__tests__/shared-options.spec.tsx @@ -1,4 +1,4 @@ -import { demoFormOpts } from './shared-options' +import { demoFormOpts } from '../shared-options' describe('demoFormOpts', () => { it('should provide expected default values', () => { diff --git a/web/app/components/base/form/form-scenarios/demo/types.spec.ts b/web/app/components/base/form/form-scenarios/demo/__tests__/types.spec.ts similarity index 94% rename from web/app/components/base/form/form-scenarios/demo/types.spec.ts rename to web/app/components/base/form/form-scenarios/demo/__tests__/types.spec.ts index 8e81f24c1c..e164a190c8 100644 --- a/web/app/components/base/form/form-scenarios/demo/types.spec.ts +++ b/web/app/components/base/form/form-scenarios/demo/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { ContactMethods, UserSchema } from './types' +import { ContactMethods, UserSchema } from '../types' describe('demo scenario types', () => { it('should expose contact methods with capitalized labels', () => { diff --git a/web/app/components/base/form/form-scenarios/input-field/field.spec.tsx b/web/app/components/base/form/form-scenarios/input-field/__tests__/field.spec.tsx similarity index 96% rename from web/app/components/base/form/form-scenarios/input-field/field.spec.tsx rename to web/app/components/base/form/form-scenarios/input-field/__tests__/field.spec.tsx index 0416c1532c..d89952f569 100644 --- a/web/app/components/base/form/form-scenarios/input-field/field.spec.tsx +++ b/web/app/components/base/form/form-scenarios/input-field/__tests__/field.spec.tsx @@ -1,9 +1,9 @@ -import type { InputFieldConfiguration } from './types' +import type { InputFieldConfiguration } from '../types' import { render, screen } from '@testing-library/react' import { useMemo } from 'react' -import { useAppForm } from '../..' -import InputField from './field' -import { InputFieldType } from './types' +import { useAppForm } from '../../..' +import InputField from '../field' +import { InputFieldType } from '../types' const createConfig = (overrides: Partial = {}): InputFieldConfiguration => ({ type: InputFieldType.textInput, diff --git a/web/app/components/base/form/form-scenarios/input-field/types.spec.ts b/web/app/components/base/form/form-scenarios/input-field/__tests__/types.spec.ts similarity index 89% rename from web/app/components/base/form/form-scenarios/input-field/types.spec.ts rename to web/app/components/base/form/form-scenarios/input-field/__tests__/types.spec.ts index b9328b2089..9347d1bb58 100644 --- a/web/app/components/base/form/form-scenarios/input-field/types.spec.ts +++ b/web/app/components/base/form/form-scenarios/input-field/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { InputFieldType } from './types' +import { InputFieldType } from '../types' describe('input-field scenario types', () => { it('should include expected input field types', () => { diff --git a/web/app/components/base/form/form-scenarios/input-field/utils.spec.ts b/web/app/components/base/form/form-scenarios/input-field/__tests__/utils.spec.ts similarity index 97% rename from web/app/components/base/form/form-scenarios/input-field/utils.spec.ts rename to web/app/components/base/form/form-scenarios/input-field/__tests__/utils.spec.ts index 7f91d3cd70..fdb958b4ae 100644 --- a/web/app/components/base/form/form-scenarios/input-field/utils.spec.ts +++ b/web/app/components/base/form/form-scenarios/input-field/__tests__/utils.spec.ts @@ -1,5 +1,5 @@ -import { InputFieldType } from './types' -import { generateZodSchema } from './utils' +import { InputFieldType } from '../types' +import { generateZodSchema } from '../utils' describe('input-field scenario schema generator', () => { it('should validate required text input with max length', () => { diff --git a/web/app/components/base/form/form-scenarios/node-panel/field.spec.tsx b/web/app/components/base/form/form-scenarios/node-panel/__tests__/field.spec.tsx similarity index 96% rename from web/app/components/base/form/form-scenarios/node-panel/field.spec.tsx rename to web/app/components/base/form/form-scenarios/node-panel/__tests__/field.spec.tsx index b8388206c0..25808cfdda 100644 --- a/web/app/components/base/form/form-scenarios/node-panel/field.spec.tsx +++ b/web/app/components/base/form/form-scenarios/node-panel/__tests__/field.spec.tsx @@ -1,12 +1,12 @@ import type { ReactNode } from 'react' -import type { InputFieldConfiguration } from './types' +import type { InputFieldConfiguration } from '../types' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import { useMemo } from 'react' import { ReactFlowProvider } from 'reactflow' -import { useAppForm } from '../..' -import NodePanelField from './field' -import { InputFieldType } from './types' +import { useAppForm } from '../../..' +import NodePanelField from '../field' +import { InputFieldType } from '../types' vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({ default: () =>
Variable Picker
, diff --git a/web/app/components/base/form/form-scenarios/node-panel/types.spec.ts b/web/app/components/base/form/form-scenarios/node-panel/__tests__/types.spec.ts similarity index 81% rename from web/app/components/base/form/form-scenarios/node-panel/types.spec.ts rename to web/app/components/base/form/form-scenarios/node-panel/__tests__/types.spec.ts index 8cd27eab08..b80e29652d 100644 --- a/web/app/components/base/form/form-scenarios/node-panel/types.spec.ts +++ b/web/app/components/base/form/form-scenarios/node-panel/__tests__/types.spec.ts @@ -1,4 +1,4 @@ -import { InputFieldType } from './types' +import { InputFieldType } from '../types' describe('node-panel scenario types', () => { it('should include variableOrConstant field type', () => { diff --git a/web/app/components/base/form/hooks/index.spec.ts b/web/app/components/base/form/hooks/__tests__/index.spec.ts similarity index 57% rename from web/app/components/base/form/hooks/index.spec.ts rename to web/app/components/base/form/hooks/__tests__/index.spec.ts index d76743702a..9c0ced74a7 100644 --- a/web/app/components/base/form/hooks/index.spec.ts +++ b/web/app/components/base/form/hooks/__tests__/index.spec.ts @@ -1,7 +1,7 @@ -import * as hookExports from './index' -import { useCheckValidated } from './use-check-validated' -import { useGetFormValues } from './use-get-form-values' -import { useGetValidators } from './use-get-validators' +import * as hookExports from '../index' +import { useCheckValidated } from '../use-check-validated' +import { useGetFormValues } from '../use-get-form-values' +import { useGetValidators } from '../use-get-validators' describe('hooks index exports', () => { it('should re-export all hook modules', () => { diff --git a/web/app/components/base/form/hooks/use-check-validated.spec.ts b/web/app/components/base/form/hooks/__tests__/use-check-validated.spec.ts similarity index 96% rename from web/app/components/base/form/hooks/use-check-validated.spec.ts rename to web/app/components/base/form/hooks/__tests__/use-check-validated.spec.ts index a8f15b403e..b9d60594f7 100644 --- a/web/app/components/base/form/hooks/use-check-validated.spec.ts +++ b/web/app/components/base/form/hooks/__tests__/use-check-validated.spec.ts @@ -1,7 +1,7 @@ import type { AnyFormApi } from '@tanstack/react-form' import { renderHook } from '@testing-library/react' -import { FormTypeEnum } from '../types' -import { useCheckValidated } from './use-check-validated' +import { FormTypeEnum } from '../../types' +import { useCheckValidated } from '../use-check-validated' const mockNotify = vi.fn() diff --git a/web/app/components/base/form/hooks/use-get-form-values.spec.ts b/web/app/components/base/form/hooks/__tests__/use-get-form-values.spec.ts similarity index 91% rename from web/app/components/base/form/hooks/use-get-form-values.spec.ts rename to web/app/components/base/form/hooks/__tests__/use-get-form-values.spec.ts index 163f959eff..8457bdcb8c 100644 --- a/web/app/components/base/form/hooks/use-get-form-values.spec.ts +++ b/web/app/components/base/form/hooks/__tests__/use-get-form-values.spec.ts @@ -1,18 +1,18 @@ import type { AnyFormApi } from '@tanstack/react-form' import { renderHook } from '@testing-library/react' -import { FormTypeEnum } from '../types' -import { useGetFormValues } from './use-get-form-values' +import { FormTypeEnum } from '../../types' +import { useGetFormValues } from '../use-get-form-values' const mockCheckValidated = vi.fn() const mockTransform = vi.fn() -vi.mock('./use-check-validated', () => ({ +vi.mock('../use-check-validated', () => ({ useCheckValidated: () => ({ checkValidated: mockCheckValidated, }), })) -vi.mock('../utils/secret-input', () => ({ +vi.mock('../../utils/secret-input', () => ({ getTransformedValuesWhenSecretInputPristine: (...args: unknown[]) => mockTransform(...args), })) diff --git a/web/app/components/base/form/hooks/use-get-validators.spec.ts b/web/app/components/base/form/hooks/__tests__/use-get-validators.spec.ts similarity index 96% rename from web/app/components/base/form/hooks/use-get-validators.spec.ts rename to web/app/components/base/form/hooks/__tests__/use-get-validators.spec.ts index 73c7b3f86d..b99056e44f 100644 --- a/web/app/components/base/form/hooks/use-get-validators.spec.ts +++ b/web/app/components/base/form/hooks/__tests__/use-get-validators.spec.ts @@ -1,7 +1,7 @@ import { renderHook } from '@testing-library/react' import { createElement } from 'react' -import { FormTypeEnum } from '../types' -import { useGetValidators } from './use-get-validators' +import { FormTypeEnum } from '../../types' +import { useGetValidators } from '../use-get-validators' vi.mock('@/hooks/use-i18n', () => ({ useRenderI18nObject: () => (obj: Record) => obj.en_US, diff --git a/web/app/components/base/form/utils/zod-submit-validator.spec.ts b/web/app/components/base/form/utils/__tests__/zod-submit-validator.spec.ts similarity index 94% rename from web/app/components/base/form/utils/zod-submit-validator.spec.ts rename to web/app/components/base/form/utils/__tests__/zod-submit-validator.spec.ts index 74635ae844..81bc77c7c3 100644 --- a/web/app/components/base/form/utils/zod-submit-validator.spec.ts +++ b/web/app/components/base/form/utils/__tests__/zod-submit-validator.spec.ts @@ -1,5 +1,5 @@ import * as z from 'zod' -import { zodSubmitValidator } from './zod-submit-validator' +import { zodSubmitValidator } from '../zod-submit-validator' describe('zodSubmitValidator', () => { it('should return undefined for valid values', () => { diff --git a/web/app/components/base/form/utils/secret-input/index.spec.ts b/web/app/components/base/form/utils/secret-input/__tests__/index.spec.ts similarity index 95% rename from web/app/components/base/form/utils/secret-input/index.spec.ts rename to web/app/components/base/form/utils/secret-input/__tests__/index.spec.ts index c5722007b6..c7e683841c 100644 --- a/web/app/components/base/form/utils/secret-input/index.spec.ts +++ b/web/app/components/base/form/utils/secret-input/__tests__/index.spec.ts @@ -1,6 +1,6 @@ import type { AnyFormApi } from '@tanstack/react-form' -import { FormTypeEnum } from '../../types' -import { getTransformedValuesWhenSecretInputPristine, transformFormSchemasSecretInput } from './index' +import { FormTypeEnum } from '../../../types' +import { getTransformedValuesWhenSecretInputPristine, transformFormSchemasSecretInput } from '../index' describe('secret input utilities', () => { it('should mask only selected truthy values in transformFormSchemasSecretInput', () => { diff --git a/web/app/components/base/fullscreen-modal/index.spec.tsx b/web/app/components/base/fullscreen-modal/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/fullscreen-modal/index.spec.tsx rename to web/app/components/base/fullscreen-modal/__tests__/index.spec.tsx index cf1484fc63..8affae3d57 100644 --- a/web/app/components/base/fullscreen-modal/index.spec.tsx +++ b/web/app/components/base/fullscreen-modal/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { act, fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import FullScreenModal from './index' +import FullScreenModal from '../index' describe('FullScreenModal Component', () => { it('should not render anything when open is false', () => { diff --git a/web/app/components/base/ga/index.spec.tsx b/web/app/components/base/ga/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/ga/index.spec.tsx rename to web/app/components/base/ga/__tests__/index.spec.tsx index 954e0eba83..ee7f7a2a9d 100644 --- a/web/app/components/base/ga/index.spec.tsx +++ b/web/app/components/base/ga/__tests__/index.spec.tsx @@ -61,7 +61,7 @@ vi.mock('next/script', () => ({ })) const loadComponent = async () => { - const mod = await import('./index') + const mod = await import('../index') // mod.default is either an async function (server component) or // a React.memo object whose .type is the async function. const rawExport = mod.default as unknown diff --git a/web/app/components/base/grid-mask/index.spec.tsx b/web/app/components/base/grid-mask/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/grid-mask/index.spec.tsx rename to web/app/components/base/grid-mask/__tests__/index.spec.tsx index 28d806a69b..5aa4868c33 100644 --- a/web/app/components/base/grid-mask/index.spec.tsx +++ b/web/app/components/base/grid-mask/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' -import GridMask from './index' -import Style from './style.module.css' +import GridMask from '../index' +import Style from '../style.module.css' function renderGridMask(props: Partial> = {}, children: React.ReactNode = Child) { const { container } = render({children}) diff --git a/web/app/components/base/icons/IconBase.spec.tsx b/web/app/components/base/icons/__tests__/IconBase.spec.tsx similarity index 92% rename from web/app/components/base/icons/IconBase.spec.tsx rename to web/app/components/base/icons/__tests__/IconBase.spec.tsx index ba5efd8429..e833d5355b 100644 --- a/web/app/components/base/icons/IconBase.spec.tsx +++ b/web/app/components/base/icons/__tests__/IconBase.spec.tsx @@ -1,11 +1,11 @@ -import type { IconData } from './IconBase' +import type { IconData } from '../IconBase' import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import IconBase from './IconBase' -import * as utils from './utils' +import IconBase from '../IconBase' +import * as utils from '../utils' // Mock the utils module -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ generate: vi.fn((icon, key, props) => ( { describe('normalizeAttrs', () => { diff --git a/web/app/components/base/image-gallery/index.spec.tsx b/web/app/components/base/image-gallery/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/image-gallery/index.spec.tsx rename to web/app/components/base/image-gallery/__tests__/index.spec.tsx index 96967b541c..61187f1c5f 100644 --- a/web/app/components/base/image-gallery/index.spec.tsx +++ b/web/app/components/base/image-gallery/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ImageGallery, { ImageGalleryTest } from '.' +import ImageGallery, { ImageGalleryTest } from '..' const getImages = (container: HTMLElement) => container.querySelectorAll('img') diff --git a/web/app/components/base/image-uploader/audio-preview.spec.tsx b/web/app/components/base/image-uploader/__tests__/audio-preview.spec.tsx similarity index 98% rename from web/app/components/base/image-uploader/audio-preview.spec.tsx rename to web/app/components/base/image-uploader/__tests__/audio-preview.spec.tsx index 72cfa7621d..0c92afba0a 100644 --- a/web/app/components/base/image-uploader/audio-preview.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/audio-preview.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import AudioPreview from './audio-preview' +import AudioPreview from '../audio-preview' describe('AudioPreview', () => { const defaultProps = { diff --git a/web/app/components/base/image-uploader/chat-image-uploader.spec.tsx b/web/app/components/base/image-uploader/__tests__/chat-image-uploader.spec.tsx similarity index 98% rename from web/app/components/base/image-uploader/chat-image-uploader.spec.tsx rename to web/app/components/base/image-uploader/__tests__/chat-image-uploader.spec.tsx index 80ef06410d..97954f79b0 100644 --- a/web/app/components/base/image-uploader/chat-image-uploader.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/chat-image-uploader.spec.tsx @@ -1,9 +1,9 @@ -import type { useLocalFileUploader } from './hooks' +import type { useLocalFileUploader } from '../hooks' import type { ImageFile, VisionSettings } from '@/types/app' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Resolution, TransferMethod } from '@/types/app' -import ChatImageUploader from './chat-image-uploader' +import ChatImageUploader from '../chat-image-uploader' type LocalUploaderArgs = Parameters[0] @@ -12,7 +12,7 @@ const mocks = vi.hoisted(() => ({ handleLocalFileUpload: vi.fn<(file: File) => void>(), })) -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useLocalFileUploader: (args: LocalUploaderArgs) => { mocks.hookArgs = args return { diff --git a/web/app/components/base/image-uploader/hooks.spec.ts b/web/app/components/base/image-uploader/__tests__/hooks.spec.ts similarity index 99% rename from web/app/components/base/image-uploader/hooks.spec.ts rename to web/app/components/base/image-uploader/__tests__/hooks.spec.ts index 1de5691690..4d150830d0 100644 --- a/web/app/components/base/image-uploader/hooks.spec.ts +++ b/web/app/components/base/image-uploader/__tests__/hooks.spec.ts @@ -2,7 +2,7 @@ import type { ClipboardEvent, DragEvent } from 'react' import type { ImageFile, VisionSettings } from '@/types/app' import { act, renderHook } from '@testing-library/react' import { Resolution, TransferMethod } from '@/types/app' -import { useClipboardUploader, useDraggableUploader, useImageFiles, useLocalFileUploader } from './hooks' +import { useClipboardUploader, useDraggableUploader, useImageFiles, useLocalFileUploader } from '../hooks' const mockNotify = vi.fn() vi.mock('@/app/components/base/toast', () => ({ @@ -17,7 +17,7 @@ const { mockImageUpload, mockGetImageUploadErrorMessage } = vi.hoisted(() => ({ mockImageUpload: vi.fn(), mockGetImageUploadErrorMessage: vi.fn(() => 'Upload error'), })) -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ imageUpload: mockImageUpload, getImageUploadErrorMessage: mockGetImageUploadErrorMessage, })) diff --git a/web/app/components/base/image-uploader/image-link-input.spec.tsx b/web/app/components/base/image-uploader/__tests__/image-link-input.spec.tsx similarity index 99% rename from web/app/components/base/image-uploader/image-link-input.spec.tsx rename to web/app/components/base/image-uploader/__tests__/image-link-input.spec.tsx index 209c5d4c0c..0e8fdaf72d 100644 --- a/web/app/components/base/image-uploader/image-link-input.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/image-link-input.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { TransferMethod } from '@/types/app' -import ImageLinkInput from './image-link-input' +import ImageLinkInput from '../image-link-input' describe('ImageLinkInput', () => { const defaultProps = { diff --git a/web/app/components/base/image-uploader/image-list.spec.tsx b/web/app/components/base/image-uploader/__tests__/image-list.spec.tsx similarity index 99% rename from web/app/components/base/image-uploader/image-list.spec.tsx rename to web/app/components/base/image-uploader/__tests__/image-list.spec.tsx index a00d6551f6..44353ca19f 100644 --- a/web/app/components/base/image-uploader/image-list.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/image-list.spec.tsx @@ -2,7 +2,7 @@ import type { ImageFile } from '@/types/app' import { fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { TransferMethod } from '@/types/app' -import ImageList from './image-list' +import ImageList from '../image-list' const createLocalFile = (overrides: Partial = {}): ImageFile => ({ type: TransferMethod.local_file, diff --git a/web/app/components/base/image-uploader/image-preview.spec.tsx b/web/app/components/base/image-uploader/__tests__/image-preview.spec.tsx similarity index 99% rename from web/app/components/base/image-uploader/image-preview.spec.tsx rename to web/app/components/base/image-uploader/__tests__/image-preview.spec.tsx index 949ce01842..f7641f071f 100644 --- a/web/app/components/base/image-uploader/image-preview.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/image-preview.spec.tsx @@ -1,6 +1,6 @@ import { act, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ImagePreview from './image-preview' +import ImagePreview from '../image-preview' type HotkeyHandler = () => void diff --git a/web/app/components/base/image-uploader/text-generation-image-uploader.spec.tsx b/web/app/components/base/image-uploader/__tests__/text-generation-image-uploader.spec.tsx similarity index 98% rename from web/app/components/base/image-uploader/text-generation-image-uploader.spec.tsx rename to web/app/components/base/image-uploader/__tests__/text-generation-image-uploader.spec.tsx index 5bba9135b7..90f5a96169 100644 --- a/web/app/components/base/image-uploader/text-generation-image-uploader.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/text-generation-image-uploader.spec.tsx @@ -1,9 +1,9 @@ -import type { useLocalFileUploader } from './hooks' +import type { useLocalFileUploader } from '../hooks' import type { ImageFile, VisionSettings } from '@/types/app' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Resolution, TransferMethod } from '@/types/app' -import TextGenerationImageUploader from './text-generation-image-uploader' +import TextGenerationImageUploader from '../text-generation-image-uploader' type LocalUploaderArgs = Parameters[0] @@ -18,7 +18,7 @@ const mocks = vi.hoisted(() => ({ localUploaderArgs: undefined as LocalUploaderArgs | undefined, })) -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useImageFiles: () => ({ files: mocks.files, onUpload: mocks.onUpload, diff --git a/web/app/components/base/image-uploader/uploader.spec.tsx b/web/app/components/base/image-uploader/__tests__/uploader.spec.tsx similarity index 97% rename from web/app/components/base/image-uploader/uploader.spec.tsx rename to web/app/components/base/image-uploader/__tests__/uploader.spec.tsx index 7fd916a497..416a56fec5 100644 --- a/web/app/components/base/image-uploader/uploader.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/uploader.spec.tsx @@ -1,9 +1,9 @@ import type { ComponentProps } from 'react' -import type { useLocalFileUploader } from './hooks' +import type { useLocalFileUploader } from '../hooks' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { ALLOW_FILE_EXTENSIONS } from '@/types/app' -import Uploader from './uploader' +import Uploader from '../uploader' type LocalUploaderArgs = Parameters[0] @@ -12,7 +12,7 @@ const mocks = vi.hoisted(() => ({ handleLocalFileUpload: vi.fn<(file: File) => void>(), })) -vi.mock('./hooks', () => ({ +vi.mock('../hooks', () => ({ useLocalFileUploader: (args: LocalUploaderArgs) => { mocks.hookArgs = args return { diff --git a/web/app/components/base/image-uploader/utils.spec.ts b/web/app/components/base/image-uploader/__tests__/utils.spec.ts similarity index 98% rename from web/app/components/base/image-uploader/utils.spec.ts rename to web/app/components/base/image-uploader/__tests__/utils.spec.ts index dff7fa25c3..0596287654 100644 --- a/web/app/components/base/image-uploader/utils.spec.ts +++ b/web/app/components/base/image-uploader/__tests__/utils.spec.ts @@ -1,7 +1,7 @@ import type { TFunction } from 'i18next' import { waitFor } from '@testing-library/react' import { upload } from '@/service/base' -import { getImageUploadErrorMessage, imageUpload } from './utils' +import { getImageUploadErrorMessage, imageUpload } from '../utils' vi.mock('@/service/base', () => ({ upload: vi.fn(), diff --git a/web/app/components/base/image-uploader/video-preview.spec.tsx b/web/app/components/base/image-uploader/__tests__/video-preview.spec.tsx similarity index 98% rename from web/app/components/base/image-uploader/video-preview.spec.tsx rename to web/app/components/base/image-uploader/__tests__/video-preview.spec.tsx index c9501b9059..f56a4b82e4 100644 --- a/web/app/components/base/image-uploader/video-preview.spec.tsx +++ b/web/app/components/base/image-uploader/__tests__/video-preview.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import VideoPreview from './video-preview' +import VideoPreview from '../video-preview' const getOverlay = () => screen.getByTestId('video-preview') const getCloseButton = () => screen.getByTestId('close-button') diff --git a/web/app/components/base/inline-delete-confirm/index.spec.tsx b/web/app/components/base/inline-delete-confirm/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/inline-delete-confirm/index.spec.tsx rename to web/app/components/base/inline-delete-confirm/__tests__/index.spec.tsx index b770fccc88..6d615554dc 100644 --- a/web/app/components/base/inline-delete-confirm/index.spec.tsx +++ b/web/app/components/base/inline-delete-confirm/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { cleanup, fireEvent, render } from '@testing-library/react' import * as React from 'react' import { createReactI18nextMock } from '@/test/i18n-mock' -import InlineDeleteConfirm from './index' +import InlineDeleteConfirm from '../index' // Mock react-i18next with custom translations for test assertions vi.mock('react-i18next', () => createReactI18nextMock({ diff --git a/web/app/components/base/input-number/index.spec.tsx b/web/app/components/base/input-number/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/input-number/index.spec.tsx rename to web/app/components/base/input-number/__tests__/index.spec.tsx index 0d6c8ac59b..7c4d7c512e 100644 --- a/web/app/components/base/input-number/index.spec.tsx +++ b/web/app/components/base/input-number/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import { InputNumber } from './index' +import { InputNumber } from '../index' describe('InputNumber Component', () => { const defaultProps = { diff --git a/web/app/components/base/input-with-copy/index.spec.tsx b/web/app/components/base/input-with-copy/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/input-with-copy/index.spec.tsx rename to web/app/components/base/input-with-copy/__tests__/index.spec.tsx index a5628c473f..2fcee9021c 100644 --- a/web/app/components/base/input-with-copy/index.spec.tsx +++ b/web/app/components/base/input-with-copy/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' import { createReactI18nextMock } from '@/test/i18n-mock' -import InputWithCopy from './index' +import InputWithCopy from '../index' // Create a controllable mock for useClipboard const mockCopy = vi.fn() diff --git a/web/app/components/base/input/index.spec.tsx b/web/app/components/base/input/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/input/index.spec.tsx rename to web/app/components/base/input/__tests__/index.spec.tsx index 0aaaf51af5..e62d2701d0 100644 --- a/web/app/components/base/input/index.spec.tsx +++ b/web/app/components/base/input/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' import { createReactI18nextMock } from '@/test/i18n-mock' -import Input, { inputVariants } from './index' +import Input, { inputVariants } from '../index' // Mock the i18n hook with custom translations for test assertions vi.mock('react-i18next', () => createReactI18nextMock({ @@ -103,7 +103,7 @@ describe('Input component', () => { }) it('applies large size variant correctly', () => { - render() + render() const input = screen.getByPlaceholderText('Please input') expect(input.className).toContain(inputVariants({ size: 'large' })) }) diff --git a/web/app/components/base/linked-apps-panel/index.spec.tsx b/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/linked-apps-panel/index.spec.tsx rename to web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx index fb7e2e7e2b..27408531c4 100644 --- a/web/app/components/base/linked-apps-panel/index.spec.tsx +++ b/web/app/components/base/linked-apps-panel/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' import { vi } from 'vitest' import { AppModeEnum } from '@/types/app' -import LinkedAppsPanel from './index' +import LinkedAppsPanel from '../index' vi.mock('next/link', () => ({ default: ({ children, href, className }: { children: React.ReactNode, href: string, className: string }) => ( diff --git a/web/app/components/base/list-empty/horizontal-line.spec.tsx b/web/app/components/base/list-empty/__tests__/horizontal-line.spec.tsx similarity index 95% rename from web/app/components/base/list-empty/horizontal-line.spec.tsx rename to web/app/components/base/list-empty/__tests__/horizontal-line.spec.tsx index 934183f1d3..c0d7178274 100644 --- a/web/app/components/base/list-empty/horizontal-line.spec.tsx +++ b/web/app/components/base/list-empty/__tests__/horizontal-line.spec.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react' import * as React from 'react' -import HorizontalLine from './horizontal-line' +import HorizontalLine from '../horizontal-line' describe('HorizontalLine', () => { describe('Render', () => { diff --git a/web/app/components/base/list-empty/index.spec.tsx b/web/app/components/base/list-empty/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/list-empty/index.spec.tsx rename to web/app/components/base/list-empty/__tests__/index.spec.tsx index aac1480a60..60523b29fa 100644 --- a/web/app/components/base/list-empty/index.spec.tsx +++ b/web/app/components/base/list-empty/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' -import ListEmpty from './index' +import ListEmpty from '../index' describe('ListEmpty Component', () => { describe('Render', () => { diff --git a/web/app/components/base/list-empty/vertical-line.spec.tsx b/web/app/components/base/list-empty/__tests__/vertical-line.spec.tsx similarity index 96% rename from web/app/components/base/list-empty/vertical-line.spec.tsx rename to web/app/components/base/list-empty/__tests__/vertical-line.spec.tsx index 47e071d7fa..2ff9934725 100644 --- a/web/app/components/base/list-empty/vertical-line.spec.tsx +++ b/web/app/components/base/list-empty/__tests__/vertical-line.spec.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react' import * as React from 'react' -import VerticalLine from './vertical-line' +import VerticalLine from '../vertical-line' describe('VerticalLine', () => { describe('Render', () => { diff --git a/web/app/components/base/loading/index.spec.tsx b/web/app/components/base/loading/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/loading/index.spec.tsx rename to web/app/components/base/loading/__tests__/index.spec.tsx index 5140f1216b..06847e453a 100644 --- a/web/app/components/base/loading/index.spec.tsx +++ b/web/app/components/base/loading/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react' import * as React from 'react' -import Loading from './index' +import Loading from '../index' describe('Loading Component', () => { it('renders correctly with default props', () => { diff --git a/web/app/components/base/logo/dify-logo.spec.tsx b/web/app/components/base/logo/__tests__/dify-logo.spec.tsx similarity index 98% rename from web/app/components/base/logo/dify-logo.spec.tsx rename to web/app/components/base/logo/__tests__/dify-logo.spec.tsx index 834fb8f28e..f465c47e03 100644 --- a/web/app/components/base/logo/dify-logo.spec.tsx +++ b/web/app/components/base/logo/__tests__/dify-logo.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import useTheme from '@/hooks/use-theme' import { Theme } from '@/types/app' -import DifyLogo from './dify-logo' +import DifyLogo from '../dify-logo' vi.mock('@/hooks/use-theme', () => ({ default: vi.fn(), diff --git a/web/app/components/base/logo/logo-embedded-chat-avatar.spec.tsx b/web/app/components/base/logo/__tests__/logo-embedded-chat-avatar.spec.tsx similarity index 93% rename from web/app/components/base/logo/logo-embedded-chat-avatar.spec.tsx rename to web/app/components/base/logo/__tests__/logo-embedded-chat-avatar.spec.tsx index f3c374dbd9..bfb15c1389 100644 --- a/web/app/components/base/logo/logo-embedded-chat-avatar.spec.tsx +++ b/web/app/components/base/logo/__tests__/logo-embedded-chat-avatar.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import LogoEmbeddedChatAvatar from './logo-embedded-chat-avatar' +import LogoEmbeddedChatAvatar from '../logo-embedded-chat-avatar' vi.mock('@/utils/var', () => ({ basePath: '/test-base-path', diff --git a/web/app/components/base/logo/logo-embedded-chat-header.spec.tsx b/web/app/components/base/logo/__tests__/logo-embedded-chat-header.spec.tsx similarity index 94% rename from web/app/components/base/logo/logo-embedded-chat-header.spec.tsx rename to web/app/components/base/logo/__tests__/logo-embedded-chat-header.spec.tsx index 74247036d3..66184ef46e 100644 --- a/web/app/components/base/logo/logo-embedded-chat-header.spec.tsx +++ b/web/app/components/base/logo/__tests__/logo-embedded-chat-header.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import LogoEmbeddedChatHeader from './logo-embedded-chat-header' +import LogoEmbeddedChatHeader from '../logo-embedded-chat-header' vi.mock('@/utils/var', () => ({ basePath: '/test-base-path', diff --git a/web/app/components/base/logo/logo-site.spec.tsx b/web/app/components/base/logo/__tests__/logo-site.spec.tsx similarity index 94% rename from web/app/components/base/logo/logo-site.spec.tsx rename to web/app/components/base/logo/__tests__/logo-site.spec.tsx index 956485305b..0ea8f42800 100644 --- a/web/app/components/base/logo/logo-site.spec.tsx +++ b/web/app/components/base/logo/__tests__/logo-site.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import LogoSite from './logo-site' +import LogoSite from '../logo-site' vi.mock('@/utils/var', () => ({ basePath: '/test-base-path', diff --git a/web/app/components/base/markdown-blocks/audio-block.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/audio-block.spec.tsx similarity index 98% rename from web/app/components/base/markdown-blocks/audio-block.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/audio-block.spec.tsx index 166de39a16..b24bc9a074 100644 --- a/web/app/components/base/markdown-blocks/audio-block.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/audio-block.spec.tsx @@ -5,7 +5,7 @@ import * as React from 'react' // AudioBlock.integration.spec.tsx import { beforeEach, describe, expect, it, vi } from 'vitest' -import AudioBlock from './audio-block' +import AudioBlock from '../audio-block' // Mock the nested AudioPlayer used by AudioGallery (do not mock AudioGallery itself) const audioPlayerMock = vi.fn() diff --git a/web/app/components/base/markdown-blocks/button.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/button.spec.tsx similarity index 98% rename from web/app/components/base/markdown-blocks/button.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/button.spec.tsx index 7a1b8e5827..305896f4f1 100644 --- a/web/app/components/base/markdown-blocks/button.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/button.spec.tsx @@ -7,11 +7,11 @@ import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { ChatContextProvider } from '@/app/components/base/chat/chat/context' -import MarkdownButton from './button' +import MarkdownButton from '../button' // Only mock the URL utility so behavior is deterministic const isValidUrlSpy = vi.fn() -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ isValidUrl: (u: string) => isValidUrlSpy(u), })) // test subject diff --git a/web/app/components/base/markdown-blocks/code-block.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/code-block.spec.tsx similarity index 99% rename from web/app/components/base/markdown-blocks/code-block.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/code-block.spec.tsx index c0e4434f9a..190825647a 100644 --- a/web/app/components/base/markdown-blocks/code-block.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/code-block.spec.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { Theme } from '@/types/app' -import CodeBlock from './code-block' +import CodeBlock from '../code-block' type UseThemeReturn = { theme: Theme diff --git a/web/app/components/base/markdown-blocks/form.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/form.spec.tsx similarity index 99% rename from web/app/components/base/markdown-blocks/form.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/form.spec.tsx index 0331c3653d..91c7da702d 100644 --- a/web/app/components/base/markdown-blocks/form.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/form.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import dayjs from '@/app/components/base/date-and-time-picker/utils/dayjs' -import MarkdownForm from './form' +import MarkdownForm from '../form' type TextNode = { type: 'text' diff --git a/web/app/components/base/markdown-blocks/link.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/link.spec.tsx similarity index 98% rename from web/app/components/base/markdown-blocks/link.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/link.spec.tsx index 6fb0915cd9..ca68b2839d 100644 --- a/web/app/components/base/markdown-blocks/link.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/link.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import Link from './link' +import Link from '../link' // ---- mocks ---- const mockOnSend = vi.fn() @@ -13,7 +13,7 @@ vi.mock('@/app/components/base/chat/chat/context', () => ({ })) const mockIsValidUrl = vi.fn() -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ isValidUrl: (url: string) => mockIsValidUrl(url), })) diff --git a/web/app/components/base/markdown-blocks/music.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/music.spec.tsx similarity index 97% rename from web/app/components/base/markdown-blocks/music.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/music.spec.tsx index 450c0b1c2c..111148cab0 100644 --- a/web/app/components/base/markdown-blocks/music.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/music.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import ErrorBoundary from '@/app/components/base/markdown/error-boundary' -import MarkdownMusic from './music' +import MarkdownMusic from '../music' describe('MarkdownMusic', () => { beforeEach(() => { diff --git a/web/app/components/base/markdown-blocks/paragraph.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/paragraph.spec.tsx similarity index 98% rename from web/app/components/base/markdown-blocks/paragraph.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/paragraph.spec.tsx index 1abfe246ba..557eb96197 100644 --- a/web/app/components/base/markdown-blocks/paragraph.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/paragraph.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import Paragraph from './paragraph' +import Paragraph from '../paragraph' vi.mock('@/app/components/base/image-gallery', () => ({ default: ({ srcs }: { srcs: string[] }) => ( diff --git a/web/app/components/base/markdown-blocks/plugin-img.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/plugin-img.spec.tsx similarity index 97% rename from web/app/components/base/markdown-blocks/plugin-img.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/plugin-img.spec.tsx index 0022542edb..a16699ccf4 100644 --- a/web/app/components/base/markdown-blocks/plugin-img.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/plugin-img.spec.tsx @@ -2,7 +2,7 @@ import { cleanup, render, screen } from '@testing-library/react' import * as React from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { PluginImg } from './plugin-img' +import { PluginImg } from '../plugin-img' /* -------------------- Mocks -------------------- */ @@ -19,7 +19,7 @@ vi.mock('@/service/use-plugins', () => ({ })) const mockGetMarkdownImageURL = vi.fn() -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ getMarkdownImageURL: (src: string, pluginId?: string) => mockGetMarkdownImageURL(src, pluginId), })) diff --git a/web/app/components/base/markdown-blocks/plugin-paragraph.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/plugin-paragraph.spec.tsx similarity index 97% rename from web/app/components/base/markdown-blocks/plugin-paragraph.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/plugin-paragraph.spec.tsx index 5479ab81ac..4e6637d337 100644 --- a/web/app/components/base/markdown-blocks/plugin-paragraph.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/plugin-paragraph.spec.tsx @@ -3,15 +3,15 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' import { usePluginReadmeAsset } from '@/service/use-plugins' -import { PluginParagraph } from './plugin-paragraph' -import { getMarkdownImageURL } from './utils' +import { PluginParagraph } from '../plugin-paragraph' +import { getMarkdownImageURL } from '../utils' // Mock dependencies vi.mock('@/service/use-plugins', () => ({ usePluginReadmeAsset: vi.fn(), })) -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ getMarkdownImageURL: vi.fn(), })) diff --git a/web/app/components/base/markdown-blocks/pre-code.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/pre-code.spec.tsx similarity index 98% rename from web/app/components/base/markdown-blocks/pre-code.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/pre-code.spec.tsx index a3cc234e8f..fa3d37301d 100644 --- a/web/app/components/base/markdown-blocks/pre-code.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/pre-code.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' import { describe, expect, it } from 'vitest' -import PreCode from './pre-code' +import PreCode from '../pre-code' describe('PreCode Component', () => { it('renders children correctly inside the pre tag', () => { diff --git a/web/app/components/base/markdown-blocks/script-block.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/script-block.spec.tsx similarity index 97% rename from web/app/components/base/markdown-blocks/script-block.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/script-block.spec.tsx index 4bf0abc301..02db3205b7 100644 --- a/web/app/components/base/markdown-blocks/script-block.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/script-block.spec.tsx @@ -1,7 +1,7 @@ import { cleanup, render } from '@testing-library/react' import * as React from 'react' import { afterEach, describe, expect, it } from 'vitest' -import ScriptBlock from './script-block' +import ScriptBlock from '../script-block' afterEach(() => { cleanup() diff --git a/web/app/components/base/markdown-blocks/think-block.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/think-block.spec.tsx similarity index 99% rename from web/app/components/base/markdown-blocks/think-block.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/think-block.spec.tsx index a155b240b9..2cd31f9a49 100644 --- a/web/app/components/base/markdown-blocks/think-block.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/think-block.spec.tsx @@ -1,7 +1,7 @@ import { act, render, screen } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { ChatContextProvider } from '@/app/components/base/chat/chat/context' -import ThinkBlock from './think-block' +import ThinkBlock from '../think-block' // Mock react-i18next vi.mock('react-i18next', () => ({ diff --git a/web/app/components/base/markdown-blocks/video-block.spec.tsx b/web/app/components/base/markdown-blocks/__tests__/video-block.spec.tsx similarity index 96% rename from web/app/components/base/markdown-blocks/video-block.spec.tsx rename to web/app/components/base/markdown-blocks/__tests__/video-block.spec.tsx index 46f810453f..eabeb1fca1 100644 --- a/web/app/components/base/markdown-blocks/video-block.spec.tsx +++ b/web/app/components/base/markdown-blocks/__tests__/video-block.spec.tsx @@ -2,8 +2,8 @@ import { render } from '@testing-library/react' import * as React from 'react' import { describe, expect, it } from 'vitest' -import VideoGallery from '../video-gallery' -import VideoBlock from './video-block' +import VideoGallery from '../../video-gallery' +import VideoBlock from '../video-block' type ChildNode = { properties?: { diff --git a/web/app/components/base/markdown/error-boundary.spec.tsx b/web/app/components/base/markdown/__tests__/error-boundary.spec.tsx similarity index 96% rename from web/app/components/base/markdown/error-boundary.spec.tsx rename to web/app/components/base/markdown/__tests__/error-boundary.spec.tsx index 40a37d4504..f9afed4e94 100644 --- a/web/app/components/base/markdown/error-boundary.spec.tsx +++ b/web/app/components/base/markdown/__tests__/error-boundary.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import * as React from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import ErrorBoundary from './error-boundary' +import ErrorBoundary from '../error-boundary' import '@testing-library/jest-dom' describe('ErrorBoundary', () => { diff --git a/web/app/components/base/markdown/index.spec.tsx b/web/app/components/base/markdown/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/markdown/index.spec.tsx rename to web/app/components/base/markdown/__tests__/index.spec.tsx index bf315360ca..9a87811e30 100644 --- a/web/app/components/base/markdown/index.spec.tsx +++ b/web/app/components/base/markdown/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ -import type { SimplePluginInfo } from './react-markdown-wrapper' +import type { SimplePluginInfo } from '../react-markdown-wrapper' import { render, screen } from '@testing-library/react' -import { Markdown } from './index' +import { Markdown } from '../index' const { mockReactMarkdownWrapper } = vi.hoisted(() => ({ mockReactMarkdownWrapper: vi.fn(), diff --git a/web/app/components/base/markdown/markdown-utils.spec.ts b/web/app/components/base/markdown/__tests__/markdown-utils.spec.ts similarity index 97% rename from web/app/components/base/markdown/markdown-utils.spec.ts rename to web/app/components/base/markdown/__tests__/markdown-utils.spec.ts index 952dd52f73..dbdc419095 100644 --- a/web/app/components/base/markdown/markdown-utils.spec.ts +++ b/web/app/components/base/markdown/__tests__/markdown-utils.spec.ts @@ -9,11 +9,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const loadModuleWithConfig = async (allowDataScheme: boolean) => { vi.resetModules() vi.doMock('@/config', () => ({ ALLOW_UNSAFE_DATA_SCHEME: allowDataScheme })) - return await import('./markdown-utils') + return await import('../markdown-utils') } describe('preprocessLaTeX', () => { - let mod: typeof import('./markdown-utils') + let mod: typeof import('../markdown-utils') beforeEach(async () => { // config value doesn't matter for LaTeX preprocessing, mock it false @@ -67,7 +67,7 @@ describe('preprocessLaTeX', () => { }) describe('preprocessThinkTag', () => { - let mod: typeof import('./markdown-utils') + let mod: typeof import('../markdown-utils') beforeEach(async () => { mod = await loadModuleWithConfig(false) diff --git a/web/app/components/base/markdown/react-markdown-wrapper.spec.tsx b/web/app/components/base/markdown/__tests__/react-markdown-wrapper.spec.tsx similarity index 98% rename from web/app/components/base/markdown/react-markdown-wrapper.spec.tsx rename to web/app/components/base/markdown/__tests__/react-markdown-wrapper.spec.tsx index 735222011b..46aa74b20a 100644 --- a/web/app/components/base/markdown/react-markdown-wrapper.spec.tsx +++ b/web/app/components/base/markdown/__tests__/react-markdown-wrapper.spec.tsx @@ -1,6 +1,6 @@ import type { PropsWithChildren, ReactNode } from 'react' import { render, screen } from '@testing-library/react' -import { ReactMarkdownWrapper } from './react-markdown-wrapper' +import { ReactMarkdownWrapper } from '../react-markdown-wrapper' vi.mock('@/app/components/base/markdown-blocks', () => ({ AudioBlock: ({ children }: PropsWithChildren) =>
{children}
, diff --git a/web/app/components/base/mermaid/index.spec.tsx b/web/app/components/base/mermaid/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/mermaid/index.spec.tsx rename to web/app/components/base/mermaid/__tests__/index.spec.tsx index 198f4de003..90f3559e63 100644 --- a/web/app/components/base/mermaid/index.spec.tsx +++ b/web/app/components/base/mermaid/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import mermaid from 'mermaid' -import Flowchart from './index' +import Flowchart from '../index' vi.mock('mermaid', () => ({ default: { @@ -12,7 +12,7 @@ vi.mock('mermaid', () => ({ }, })) -vi.mock('./utils', async (importOriginal) => { +vi.mock('../utils', async (importOriginal) => { const actual = await importOriginal() as Record return { ...actual, @@ -231,7 +231,7 @@ describe('Mermaid Flowchart Component Module Isolation', () => { describe('Error Handling', () => { it('should handle initialization failure', async () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { }) - const { default: FlowchartFresh } = await import('./index') + const { default: FlowchartFresh } = await import('../index') vi.mocked(mermaidFresh.initialize).mockImplementationOnce(() => { throw new Error('Init fail') @@ -251,7 +251,7 @@ describe('Mermaid Flowchart Component Module Isolation', () => { // @ts-expect-error need to set undefined for testing mermaidFresh.mermaidAPI = undefined - const { default: FlowchartFresh } = await import('./index') + const { default: FlowchartFresh } = await import('../index') const { container } = render() @@ -284,7 +284,7 @@ describe('Mermaid Flowchart Component Module Isolation', () => { throw new Error('Config fail') }) const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { }) - const { default: FlowchartFresh } = await import('./index') + const { default: FlowchartFresh } = await import('../index') await act(async () => { render() diff --git a/web/app/components/base/mermaid/utils.spec.ts b/web/app/components/base/mermaid/__tests__/utils.spec.ts similarity index 99% rename from web/app/components/base/mermaid/utils.spec.ts rename to web/app/components/base/mermaid/__tests__/utils.spec.ts index d698e1234c..6d237810db 100644 --- a/web/app/components/base/mermaid/utils.spec.ts +++ b/web/app/components/base/mermaid/__tests__/utils.spec.ts @@ -1,4 +1,4 @@ -import { cleanUpSvgCode, isMermaidCodeComplete, prepareMermaidCode, processSvgForTheme, sanitizeMermaidCode, svgToBase64, waitForDOMElement } from './utils' +import { cleanUpSvgCode, isMermaidCodeComplete, prepareMermaidCode, processSvgForTheme, sanitizeMermaidCode, svgToBase64, waitForDOMElement } from '../utils' describe('cleanUpSvgCode', () => { it('should replace old-style
tags with self-closing
', () => { diff --git a/web/app/components/base/message-log-modal/index.spec.tsx b/web/app/components/base/message-log-modal/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/message-log-modal/index.spec.tsx rename to web/app/components/base/message-log-modal/__tests__/index.spec.tsx index 10793c2ba0..1f01c87633 100644 --- a/web/app/components/base/message-log-modal/index.spec.tsx +++ b/web/app/components/base/message-log-modal/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { IChatItem } from '@/app/components/base/chat/chat/type' import { fireEvent, render, screen } from '@testing-library/react' import { useStore } from '@/app/components/app/store' -import MessageLogModal from './index' +import MessageLogModal from '../index' let clickAwayHandler: (() => void) | null = null vi.mock('ahooks', () => ({ diff --git a/web/app/components/base/modal-like-wrap/index.spec.tsx b/web/app/components/base/modal-like-wrap/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/modal-like-wrap/index.spec.tsx rename to web/app/components/base/modal-like-wrap/__tests__/index.spec.tsx index 60e3a4ca8c..dc7b0758fa 100644 --- a/web/app/components/base/modal-like-wrap/index.spec.tsx +++ b/web/app/components/base/modal-like-wrap/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen } from '@testing-library/react' -import ModalLikeWrap from '.' +import ModalLikeWrap from '..' describe('ModalLikeWrap', () => { const defaultProps = { diff --git a/web/app/components/base/modal/index.spec.tsx b/web/app/components/base/modal/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/modal/index.spec.tsx rename to web/app/components/base/modal/__tests__/index.spec.tsx index cab95c7cb1..da417b43ad 100644 --- a/web/app/components/base/modal/index.spec.tsx +++ b/web/app/components/base/modal/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen } from '@testing-library/react' -import Modal from '.' +import Modal from '..' describe('Modal', () => { describe('Render', () => { diff --git a/web/app/components/base/modal/modal.spec.tsx b/web/app/components/base/modal/__tests__/modal.spec.tsx similarity index 99% rename from web/app/components/base/modal/modal.spec.tsx rename to web/app/components/base/modal/__tests__/modal.spec.tsx index df2c3bd15d..c67b9a803b 100644 --- a/web/app/components/base/modal/modal.spec.tsx +++ b/web/app/components/base/modal/__tests__/modal.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import Modal from './modal' +import Modal from '../modal' describe('Modal Component', () => { const defaultProps = { diff --git a/web/app/components/base/new-audio-button/index.spec.tsx b/web/app/components/base/new-audio-button/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/new-audio-button/index.spec.tsx rename to web/app/components/base/new-audio-button/__tests__/index.spec.tsx index a30b06535a..64dd590012 100644 --- a/web/app/components/base/new-audio-button/index.spec.tsx +++ b/web/app/components/base/new-audio-button/__tests__/index.spec.tsx @@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event' import i18next from 'i18next' import { useParams, usePathname } from 'next/navigation' import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' -import AudioBtn from './index' +import AudioBtn from '../index' const mockPlayAudio = vi.fn() const mockPauseAudio = vi.fn() diff --git a/web/app/components/base/node-status/index.spec.tsx b/web/app/components/base/node-status/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/node-status/index.spec.tsx rename to web/app/components/base/node-status/__tests__/index.spec.tsx index 566a537653..f74af4965e 100644 --- a/web/app/components/base/node-status/index.spec.tsx +++ b/web/app/components/base/node-status/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import NodeStatus, { NodeStatusEnum } from '.' +import NodeStatus, { NodeStatusEnum } from '..' describe('NodeStatus', () => { it('renders with default status (warning) and default message', () => { diff --git a/web/app/components/base/notion-connector/index.spec.tsx b/web/app/components/base/notion-connector/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/notion-connector/index.spec.tsx rename to web/app/components/base/notion-connector/__tests__/index.spec.tsx index 7ee799d002..578ffffdca 100644 --- a/web/app/components/base/notion-connector/index.spec.tsx +++ b/web/app/components/base/notion-connector/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import NotionConnector from './index' +import NotionConnector from '../index' describe('NotionConnector', () => { it('should render the layout and actual sub-components (Icons & Button)', () => { diff --git a/web/app/components/base/notion-icon/index.spec.tsx b/web/app/components/base/notion-icon/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/notion-icon/index.spec.tsx rename to web/app/components/base/notion-icon/__tests__/index.spec.tsx index 582beab054..26a2c7640e 100644 --- a/web/app/components/base/notion-icon/index.spec.tsx +++ b/web/app/components/base/notion-icon/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import NotionIcon from '.' +import NotionIcon from '..' describe('Notion Icon', () => { it('applies custom class names', () => { diff --git a/web/app/components/base/notion-page-selector/base.spec.tsx b/web/app/components/base/notion-page-selector/__tests__/base.spec.tsx similarity index 98% rename from web/app/components/base/notion-page-selector/base.spec.tsx rename to web/app/components/base/notion-page-selector/__tests__/base.spec.tsx index e978056667..e06ca0a53e 100644 --- a/web/app/components/base/notion-page-selector/base.spec.tsx +++ b/web/app/components/base/notion-page-selector/__tests__/base.spec.tsx @@ -1,4 +1,4 @@ -import type { DataSourceCredential } from '../../header/account-setting/data-source-page-new/types' +import type { DataSourceCredential } from '../../../header/account-setting/data-source-page-new/types' import type { DataSourceNotionWorkspace } from '@/models/common' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' @@ -7,7 +7,7 @@ import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/con import { CredentialTypeEnum } from '@/app/components/plugins/plugin-auth/types' import { useModalContextSelector } from '@/context/modal-context' import { useInvalidPreImportNotionPages, usePreImportNotionPages } from '@/service/knowledge/use-import' -import NotionPageSelector from './base' +import NotionPageSelector from '../base' vi.mock('@/service/knowledge/use-import', () => ({ usePreImportNotionPages: vi.fn(), diff --git a/web/app/components/base/notion-page-selector/credential-selector/index.spec.tsx b/web/app/components/base/notion-page-selector/credential-selector/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/notion-page-selector/credential-selector/index.spec.tsx rename to web/app/components/base/notion-page-selector/credential-selector/__tests__/index.spec.tsx index ff194a0086..efcf015ea5 100644 --- a/web/app/components/base/notion-page-selector/credential-selector/index.spec.tsx +++ b/web/app/components/base/notion-page-selector/credential-selector/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import CredentialSelector from './index' +import CredentialSelector from '../index' // Mock CredentialIcon since it's likely a complex component or uses next/image vi.mock('@/app/components/datasets/common/credential-icon', () => ({ diff --git a/web/app/components/base/notion-page-selector/page-selector/index.spec.tsx b/web/app/components/base/notion-page-selector/page-selector/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/notion-page-selector/page-selector/index.spec.tsx rename to web/app/components/base/notion-page-selector/page-selector/__tests__/index.spec.tsx index 1b0cc6653a..bfe3e7e0ef 100644 --- a/web/app/components/base/notion-page-selector/page-selector/index.spec.tsx +++ b/web/app/components/base/notion-page-selector/page-selector/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/com import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' -import PageSelector from './index' +import PageSelector from '../index' const buildPage = (overrides: Partial): DataSourceNotionPage => ({ page_id: 'page-id', diff --git a/web/app/components/base/notion-page-selector/search-input/index.spec.tsx b/web/app/components/base/notion-page-selector/search-input/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/notion-page-selector/search-input/index.spec.tsx rename to web/app/components/base/notion-page-selector/search-input/__tests__/index.spec.tsx index ecab087d71..39e7e09cf8 100644 --- a/web/app/components/base/notion-page-selector/search-input/index.spec.tsx +++ b/web/app/components/base/notion-page-selector/search-input/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import SearchInput from './index' +import SearchInput from '../index' describe('SearchInput', () => { it('should render with placeholder', () => { diff --git a/web/app/components/base/pagination/hook.spec.ts b/web/app/components/base/pagination/__tests__/hook.spec.ts similarity index 99% rename from web/app/components/base/pagination/hook.spec.ts rename to web/app/components/base/pagination/__tests__/hook.spec.ts index 284032df47..b65feab8f3 100644 --- a/web/app/components/base/pagination/hook.spec.ts +++ b/web/app/components/base/pagination/__tests__/hook.spec.ts @@ -1,5 +1,5 @@ import { renderHook } from '@testing-library/react' -import usePagination from './hook' +import usePagination from '../hook' const defaultProps = { currentPage: 0, diff --git a/web/app/components/base/pagination/index.spec.tsx b/web/app/components/base/pagination/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/pagination/index.spec.tsx rename to web/app/components/base/pagination/__tests__/index.spec.tsx index ef924c290b..aa3cf8e5f2 100644 --- a/web/app/components/base/pagination/index.spec.tsx +++ b/web/app/components/base/pagination/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen } from '@testing-library/react' -import CustomizedPagination from './index' +import CustomizedPagination from '../index' describe('CustomizedPagination', () => { const defaultProps = { diff --git a/web/app/components/base/pagination/pagination.spec.tsx b/web/app/components/base/pagination/__tests__/pagination.spec.tsx similarity index 99% rename from web/app/components/base/pagination/pagination.spec.tsx rename to web/app/components/base/pagination/__tests__/pagination.spec.tsx index 2374f8257a..21c3b41bff 100644 --- a/web/app/components/base/pagination/pagination.spec.tsx +++ b/web/app/components/base/pagination/__tests__/pagination.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import { Pagination } from './pagination' +import { Pagination } from '../pagination' // Helper to render Pagination with common defaults function renderPagination({ diff --git a/web/app/components/base/param-item/index-slider.spec.tsx b/web/app/components/base/param-item/__tests__/index-slider.spec.tsx similarity index 97% rename from web/app/components/base/param-item/index-slider.spec.tsx rename to web/app/components/base/param-item/__tests__/index-slider.spec.tsx index b0fa28a2d5..0048b89644 100644 --- a/web/app/components/base/param-item/index-slider.spec.tsx +++ b/web/app/components/base/param-item/__tests__/index-slider.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import ParamItem from '.' +import ParamItem from '..' describe('ParamItem Slider onChange', () => { const defaultProps = { diff --git a/web/app/components/base/param-item/index.spec.tsx b/web/app/components/base/param-item/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/param-item/index.spec.tsx rename to web/app/components/base/param-item/__tests__/index.spec.tsx index 45e0c2a5b3..60bcbebcf9 100644 --- a/web/app/components/base/param-item/index.spec.tsx +++ b/web/app/components/base/param-item/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { useState } from 'react' -import ParamItem from '.' +import ParamItem from '..' describe('ParamItem', () => { const defaultProps = { @@ -95,7 +95,7 @@ describe('ParamItem', () => { { + onChange={(key: string, nextValue: number) => { defaultProps.onChange(key, nextValue) setValue(nextValue) }} diff --git a/web/app/components/base/param-item/score-threshold-item.spec.tsx b/web/app/components/base/param-item/__tests__/score-threshold-item.spec.tsx similarity index 98% rename from web/app/components/base/param-item/score-threshold-item.spec.tsx rename to web/app/components/base/param-item/__tests__/score-threshold-item.spec.tsx index ce0a396249..d59768dacb 100644 --- a/web/app/components/base/param-item/score-threshold-item.spec.tsx +++ b/web/app/components/base/param-item/__tests__/score-threshold-item.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { useState } from 'react' -import ScoreThresholdItem from './score-threshold-item' +import ScoreThresholdItem from '../score-threshold-item' describe('ScoreThresholdItem', () => { const defaultProps = { diff --git a/web/app/components/base/param-item/top-k-item.spec.tsx b/web/app/components/base/param-item/__tests__/top-k-item.spec.tsx similarity index 99% rename from web/app/components/base/param-item/top-k-item.spec.tsx rename to web/app/components/base/param-item/__tests__/top-k-item.spec.tsx index 2031e4a83e..177b51e768 100644 --- a/web/app/components/base/param-item/top-k-item.spec.tsx +++ b/web/app/components/base/param-item/__tests__/top-k-item.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TopKItem from './top-k-item' +import TopKItem from '../top-k-item' vi.mock('@/env', () => ({ env: { diff --git a/web/app/components/base/popover/index.spec.tsx b/web/app/components/base/popover/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/popover/index.spec.tsx rename to web/app/components/base/popover/__tests__/index.spec.tsx index f90a024bcf..ba86c96296 100644 --- a/web/app/components/base/popover/index.spec.tsx +++ b/web/app/components/base/popover/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import CustomPopover from '.' +import CustomPopover from '..' const CloseButtonContent = ({ onClick }: { onClick?: () => void }) => ( @@ -227,7 +227,7 @@ describe('CustomPopover', () => { render( open ? 'btn-open' : 'btn-closed'} + btnClassName={(open: boolean) => open ? 'btn-open' : 'btn-closed'} />, ) diff --git a/web/app/components/base/portal-to-follow-elem/index.spec.tsx b/web/app/components/base/portal-to-follow-elem/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/portal-to-follow-elem/index.spec.tsx rename to web/app/components/base/portal-to-follow-elem/__tests__/index.spec.tsx index f320cd2a74..3aeb1fb475 100644 --- a/web/app/components/base/portal-to-follow-elem/index.spec.tsx +++ b/web/app/components/base/portal-to-follow-elem/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { cleanup, fireEvent, render } from '@testing-library/react' import * as React from 'react' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '.' +import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '..' const useFloatingMock = vi.fn() diff --git a/web/app/components/base/premium-badge/index.spec.tsx b/web/app/components/base/premium-badge/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/premium-badge/index.spec.tsx rename to web/app/components/base/premium-badge/__tests__/index.spec.tsx index a589aef828..af8ace22f0 100644 --- a/web/app/components/base/premium-badge/index.spec.tsx +++ b/web/app/components/base/premium-badge/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import PremiumBadge from './index' +import PremiumBadge from '../index' describe('PremiumBadge', () => { it('renders with default props', () => { diff --git a/web/app/components/base/progress-bar/progress-circle.spec.tsx b/web/app/components/base/progress-bar/__tests__/progress-circle.spec.tsx similarity index 98% rename from web/app/components/base/progress-bar/progress-circle.spec.tsx rename to web/app/components/base/progress-bar/__tests__/progress-circle.spec.tsx index 9acc525d90..4a3ee2e653 100644 --- a/web/app/components/base/progress-bar/progress-circle.spec.tsx +++ b/web/app/components/base/progress-bar/__tests__/progress-circle.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import ProgressCircle from './progress-circle' +import ProgressCircle from '../progress-circle' const extractLargeArcFlag = (pathData: string): string => { const afterA = pathData.slice(pathData.indexOf('A') + 1) diff --git a/web/app/components/base/prompt-editor/constants.spec.tsx b/web/app/components/base/prompt-editor/__tests__/constants.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/constants.spec.tsx rename to web/app/components/base/prompt-editor/__tests__/constants.spec.tsx index 862c386383..9817f70487 100644 --- a/web/app/components/base/prompt-editor/constants.spec.tsx +++ b/web/app/components/base/prompt-editor/__tests__/constants.spec.tsx @@ -1,4 +1,4 @@ -import { SupportUploadFileTypes } from '../../workflow/types' +import { SupportUploadFileTypes } from '../../../workflow/types' import { checkHasContextBlock, checkHasHistoryBlock, @@ -16,7 +16,7 @@ import { REQUEST_URL_PLACEHOLDER_TEXT, UPDATE_DATASETS_EVENT_EMITTER, UPDATE_HISTORY_EVENT_EMITTER, -} from './constants' +} from '../constants' describe('prompt-editor constants', () => { describe('placeholder and event constants', () => { diff --git a/web/app/components/base/prompt-editor/hooks.spec.tsx b/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/hooks.spec.tsx rename to web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx index 4f2d6f3e0d..89d76c2709 100644 --- a/web/app/components/base/prompt-editor/hooks.spec.tsx +++ b/web/app/components/base/prompt-editor/__tests__/hooks.spec.tsx @@ -8,13 +8,13 @@ import { useLexicalTextEntity, useSelectOrDelete, useTrigger, -} from './hooks' +} from '../hooks' import { DELETE_CONTEXT_BLOCK_COMMAND, -} from './plugins/context-block' -import { ContextBlockNode } from './plugins/context-block/node' -import { DELETE_QUERY_BLOCK_COMMAND } from './plugins/query-block' -import { QueryBlockNode } from './plugins/query-block/node' +} from '../plugins/context-block' +import { ContextBlockNode } from '../plugins/context-block/node' +import { DELETE_QUERY_BLOCK_COMMAND } from '../plugins/query-block' +import { QueryBlockNode } from '../plugins/query-block/node' type MockNode = { isDecorator?: boolean diff --git a/web/app/components/base/prompt-editor/index.spec.tsx b/web/app/components/base/prompt-editor/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/index.spec.tsx rename to web/app/components/base/prompt-editor/__tests__/index.spec.tsx index a8bdc4a637..40ca8c3d76 100644 --- a/web/app/components/base/prompt-editor/index.spec.tsx +++ b/web/app/components/base/prompt-editor/__tests__/index.spec.tsx @@ -1,14 +1,14 @@ import type { FocusEvent as ReactFocusEvent, ReactNode } from 'react' -import type { PromptEditorProps } from './index' -import type { ContextBlockType, HistoryBlockType } from './types' +import type { PromptEditorProps } from '../index' +import type { ContextBlockType, HistoryBlockType } from '../types' import { render, screen, waitFor } from '@testing-library/react' import { BLUR_COMMAND, FOCUS_COMMAND } from 'lexical' import * as React from 'react' import { UPDATE_DATASETS_EVENT_EMITTER, UPDATE_HISTORY_EVENT_EMITTER, -} from './constants' -import PromptEditor from './index' +} from '../constants' +import PromptEditor from '../index' const mocks = vi.hoisted(() => { const commandHandlers = new Map boolean>() diff --git a/web/app/components/base/prompt-editor/utils.spec.ts b/web/app/components/base/prompt-editor/__tests__/utils.spec.ts similarity index 98% rename from web/app/components/base/prompt-editor/utils.spec.ts rename to web/app/components/base/prompt-editor/__tests__/utils.spec.ts index d445966057..d400e145ff 100644 --- a/web/app/components/base/prompt-editor/utils.spec.ts +++ b/web/app/components/base/prompt-editor/__tests__/utils.spec.ts @@ -5,15 +5,15 @@ import type { RangeSelection, TextNode, } from 'lexical' -import type { CustomTextNode } from './plugins/custom-text/node' -import type { MenuTextMatch } from './types' +import type { CustomTextNode } from '../plugins/custom-text/node' +import type { MenuTextMatch } from '../types' import { $splitNodeContainingQuery, decoratorTransform, getSelectedNode, registerLexicalTextEntity, textToEditorState, -} from './utils' +} from '../utils' const mockState = vi.hoisted(() => ({ isAtNodeEnd: false, @@ -36,7 +36,7 @@ vi.mock('lexical', async (importOriginal) => { } }) -vi.mock('./plugins/custom-text/node', () => ({ +vi.mock('../plugins/custom-text/node', () => ({ CustomTextNode: class MockCustomTextNode {}, })) diff --git a/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/__tests__/on-blur-or-focus-block.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/__tests__/on-blur-or-focus-block.spec.tsx index 54acb0267a..dd2f74f7e5 100644 --- a/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/__tests__/on-blur-or-focus-block.spec.tsx @@ -7,9 +7,9 @@ import { FOCUS_COMMAND, KEY_ESCAPE_COMMAND, } from 'lexical' -import OnBlurBlock from './on-blur-or-focus-block' -import { CaptureEditorPlugin } from './test-utils' -import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block' +import OnBlurBlock from '../on-blur-or-focus-block' +import { CaptureEditorPlugin } from '../test-utils' +import { CLEAR_HIDE_MENU_TIMEOUT } from '../workflow-variable-block' const renderOnBlurBlock = (props?: { onBlur?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/placeholder.spec.tsx b/web/app/components/base/prompt-editor/plugins/__tests__/placeholder.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/placeholder.spec.tsx rename to web/app/components/base/prompt-editor/plugins/__tests__/placeholder.spec.tsx index 2386b355b0..577f15bb97 100644 --- a/web/app/components/base/prompt-editor/plugins/placeholder.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/__tests__/placeholder.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Placeholder from './placeholder' +import Placeholder from '../placeholder' describe('Placeholder', () => { beforeEach(() => { diff --git a/web/app/components/base/prompt-editor/plugins/tree-view.spec.tsx b/web/app/components/base/prompt-editor/plugins/__tests__/tree-view.spec.tsx similarity index 95% rename from web/app/components/base/prompt-editor/plugins/tree-view.spec.tsx rename to web/app/components/base/prompt-editor/plugins/__tests__/tree-view.spec.tsx index cc32ab6ea3..c2c9fe9237 100644 --- a/web/app/components/base/prompt-editor/plugins/tree-view.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/__tests__/tree-view.spec.tsx @@ -1,8 +1,8 @@ import type { LexicalEditor } from 'lexical' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, screen, waitFor } from '@testing-library/react' -import { CaptureEditorPlugin } from './test-utils' -import TreeViewPlugin from './tree-view' +import { CaptureEditorPlugin } from '../test-utils' +import TreeViewPlugin from '../tree-view' const { mockTreeView } = vi.hoisted(() => ({ mockTreeView: vi.fn(), diff --git a/web/app/components/base/prompt-editor/plugins/update-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/__tests__/update-block.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/update-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/__tests__/update-block.spec.tsx index f5576c4109..8f6a72a7de 100644 --- a/web/app/components/base/prompt-editor/plugins/update-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/__tests__/update-block.spec.tsx @@ -2,13 +2,13 @@ import type { LexicalEditor } from 'lexical' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' import { $getRoot, COMMAND_PRIORITY_EDITOR } from 'lexical' -import { CustomTextNode } from './custom-text/node' -import { CaptureEditorPlugin } from './test-utils' +import { CustomTextNode } from '../custom-text/node' +import { CaptureEditorPlugin } from '../test-utils' import UpdateBlock, { PROMPT_EDITOR_INSERT_QUICKLY, PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER, -} from './update-block' -import { CLEAR_HIDE_MENU_TIMEOUT } from './workflow-variable-block' +} from '../update-block' +import { CLEAR_HIDE_MENU_TIMEOUT } from '../workflow-variable-block' const { mockUseEventEmitterContextContext } = vi.hoisted(() => ({ mockUseEventEmitterContextContext: vi.fn(), diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/hooks.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.spec.tsx rename to web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/hooks.spec.tsx index 3ed5d12a86..e28304dd15 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/hooks.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/hooks.spec.tsx @@ -12,7 +12,7 @@ import type { RequestURLBlockType, VariableBlockType, WorkflowVariableBlockType, -} from '../../types' +} from '../../../types' import type { NodeOutPutVar } from '@/app/components/workflow/types' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' @@ -20,13 +20,13 @@ import { renderHook } from '@testing-library/react' import * as React from 'react' import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types' import { VarType } from '@/app/components/workflow/types' -import { CustomTextNode } from '../custom-text/node' +import { CustomTextNode } from '../../custom-text/node' import { useExternalToolOptions, useOptions, usePromptOptions, useVariableOptions, -} from './hooks' +} from '../hooks' // ─── Helpers ───────────────────────────────────────────────────────────────── diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/component-picker-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx index fd623d39ad..2deec561e9 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx @@ -8,7 +8,7 @@ import type { QueryBlockType, VariableBlockType, WorkflowVariableBlockType, -} from '../../types' +} from '../../../types' import type { NodeOutPutVar, Var } from '@/app/components/workflow/types' import type { EventEmitterValue } from '@/context/event-emitter' import { LexicalComposer } from '@lexical/react/LexicalComposer' @@ -29,13 +29,13 @@ import * as React from 'react' import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types' import { VarType } from '@/app/components/workflow/types' import { EventEmitterContextProvider, useEventEmitterContextContext } from '@/context/event-emitter' -import { INSERT_CONTEXT_BLOCK_COMMAND } from '../context-block' -import { INSERT_CURRENT_BLOCK_COMMAND } from '../current-block' -import { INSERT_ERROR_MESSAGE_BLOCK_COMMAND } from '../error-message-block' -import { INSERT_LAST_RUN_BLOCK_COMMAND } from '../last-run-block' -import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block' -import { INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND } from '../workflow-variable-block' -import ComponentPicker from './index' +import { INSERT_CONTEXT_BLOCK_COMMAND } from '../../context-block' +import { INSERT_CURRENT_BLOCK_COMMAND } from '../../current-block' +import { INSERT_ERROR_MESSAGE_BLOCK_COMMAND } from '../../error-message-block' +import { INSERT_LAST_RUN_BLOCK_COMMAND } from '../../last-run-block' +import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../../variable-block' +import { INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND } from '../../workflow-variable-block' +import ComponentPicker from '../index' // Mock Range.getClientRects / getBoundingClientRect for Lexical menu positioning in JSDOM. // This mirrors the pattern used by other prompt-editor plugin tests in this repo. diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/menu.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/menu.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/component-picker-block/menu.spec.tsx rename to web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/menu.spec.tsx index 2ee4fb7e0b..5796589a9d 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/menu.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/menu.spec.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react' import { Fragment } from 'react' -import { PickerBlockMenuOption } from './menu' +import { PickerBlockMenuOption } from '../menu' describe('PickerBlockMenuOption', () => { // Define the render props type locally to match the component's internal type accurately diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/prompt-option.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.spec.tsx rename to web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/prompt-option.spec.tsx index c48c52a0b7..2d8356da3d 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/prompt-option.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/prompt-option.spec.tsx @@ -1,5 +1,5 @@ import { createEvent, fireEvent, render, screen } from '@testing-library/react' -import { PromptMenuItem } from './prompt-option' +import { PromptMenuItem } from '../prompt-option' describe('PromptMenuItem', () => { const defaultProps = { diff --git a/web/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.spec.tsx b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/variable-option.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.spec.tsx rename to web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/variable-option.spec.tsx index 228f2ac657..7925765e14 100644 --- a/web/app/components/base/prompt-editor/plugins/component-picker-block/variable-option.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/component-picker-block/__tests__/variable-option.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import { VariableMenuItem } from './variable-option' +import { VariableMenuItem } from '../variable-option' describe('VariableMenuItem', () => { const defaultProps = { diff --git a/web/app/components/base/prompt-editor/plugins/context-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/component.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/context-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/context-block/__tests__/component.spec.tsx index 716f4285de..3b571e9ee1 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/component.spec.tsx @@ -1,12 +1,12 @@ import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { UPDATE_DATASETS_EVENT_EMITTER } from '../../constants' -import ContextBlockComponent from './component' +import { UPDATE_DATASETS_EVENT_EMITTER } from '../../../constants' +import ContextBlockComponent from '../component' // Mock the hooks used by ContextBlockComponent const mockUseSelectOrDelete = vi.fn() const mockUseTrigger = vi.fn() -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), useTrigger: (...args: unknown[]) => mockUseTrigger(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/context-block-replacement-block.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/context-block/__tests__/context-block-replacement-block.spec.tsx index 217ff336c6..09ff3f9b90 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/context-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/context-block-replacement-block.spec.tsx @@ -5,12 +5,12 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import { render } from '@testing-library/react' import { $createParagraphNode, $getRoot, $nodesOfType } from 'lexical' import * as React from 'react' -import { ContextBlockNode } from '../context-block/node' -import { $createCustomTextNode, CustomTextNode } from '../custom-text/node' -import ContextBlockReplacementBlock from './context-block-replacement-block' +import { ContextBlockNode } from '../../context-block/node' +import { $createCustomTextNode, CustomTextNode } from '../../custom-text/node' +import ContextBlockReplacementBlock from '../context-block-replacement-block' // Mock the component rendered by ContextBlockNode.decorate() -vi.mock('./component', () => ({ +vi.mock('../component', () => ({ default: () => null, })) diff --git a/web/app/components/base/prompt-editor/plugins/context-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/context-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/context-block/__tests__/index.spec.tsx index 93be3d022a..8ca0d80ef2 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/index.spec.tsx @@ -1,18 +1,18 @@ import type { LexicalEditor } from 'lexical' import type { ReactNode } from 'react' -import type { Dataset } from './index' +import type { Dataset } from '../index' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { render } from '@testing-library/react' import { $createParagraphNode, $getRoot } from 'lexical' import * as React from 'react' -import { ContextBlock, DELETE_CONTEXT_BLOCK_COMMAND, INSERT_CONTEXT_BLOCK_COMMAND } from './index' -import { ContextBlockNode } from './node' +import { ContextBlock, DELETE_CONTEXT_BLOCK_COMMAND, INSERT_CONTEXT_BLOCK_COMMAND } from '../index' +import { ContextBlockNode } from '../node' const mockCreateContextBlockNode = vi.fn() -vi.mock('./node', async () => { - const actual = await vi.importActual('./node') +vi.mock('../node', async () => { + const actual = await vi.importActual('../node') return { ...actual, @@ -23,7 +23,7 @@ vi.mock('./node', async () => { } }) -vi.mock('./component', () => ({ +vi.mock('../component', () => ({ default: () => null, })) diff --git a/web/app/components/base/prompt-editor/plugins/context-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/node.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/context-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/context-block/__tests__/node.spec.tsx index 556f50badf..14567894e0 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/__tests__/node.spec.tsx @@ -1,6 +1,6 @@ import { $getRoot } from 'lexical' -import { createTestEditor, withEditorUpdate } from '../__tests__/utils' -import { $createContextBlockNode, $isContextBlockNode, ContextBlockNode } from './node' +import { createTestEditor, withEditorUpdate } from '../../__tests__/utils' +import { $createContextBlockNode, $isContextBlockNode, ContextBlockNode } from '../node' const mockDatasets = [ { id: '1', name: 'Dataset A', type: 'text' }, diff --git a/web/app/components/base/prompt-editor/plugins/current-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/component.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/current-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/current-block/__tests__/component.spec.tsx index e2669af862..45099bba8a 100644 --- a/web/app/components/base/prompt-editor/plugins/current-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/component.spec.tsx @@ -3,15 +3,15 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types' -import { CurrentBlockNode, DELETE_CURRENT_BLOCK_COMMAND } from '.' -import { CustomTextNode } from '../custom-text/node' -import CurrentBlockComponent from './component' +import { CurrentBlockNode, DELETE_CURRENT_BLOCK_COMMAND } from '..' +import { CustomTextNode } from '../../custom-text/node' +import CurrentBlockComponent from '../component' const { mockUseSelectOrDelete } = vi.hoisted(() => ({ mockUseSelectOrDelete: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/current-block/current-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/current-block-replacement-block.spec.tsx similarity index 93% rename from web/app/components/base/prompt-editor/plugins/current-block/current-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/current-block/__tests__/current-block-replacement-block.spec.tsx index 16b75834fe..c7bd628e48 100644 --- a/web/app/components/base/prompt-editor/plugins/current-block/current-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/current-block-replacement-block.spec.tsx @@ -3,17 +3,17 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, waitFor } from '@testing-library/react' import { $nodesOfType } from 'lexical' import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types' -import { CURRENT_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { CURRENT_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readEditorStateValue, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import CurrentBlockReplacementBlock from './current-block-replacement-block' -import { CurrentBlockNode } from './index' +} from '../../test-helpers' +import CurrentBlockReplacementBlock from '../current-block-replacement-block' +import { CurrentBlockNode } from '../index' const renderReplacementPlugin = (props?: { generatorType?: GeneratorType diff --git a/web/app/components/base/prompt-editor/plugins/current-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/current-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/current-block/__tests__/index.spec.tsx index 39085c5925..88f0e6d779 100644 --- a/web/app/components/base/prompt-editor/plugins/current-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/index.spec.tsx @@ -3,8 +3,8 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' import { $nodesOfType } from 'lexical' import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types' -import { CURRENT_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { CURRENT_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readEditorStateValue, @@ -12,13 +12,13 @@ import { renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { CurrentBlock, CurrentBlockNode, DELETE_CURRENT_BLOCK_COMMAND, INSERT_CURRENT_BLOCK_COMMAND, -} from './index' +} from '../index' const renderCurrentBlock = (props?: { generatorType?: GeneratorType diff --git a/web/app/components/base/prompt-editor/plugins/current-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/node.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/current-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/current-block/__tests__/node.spec.tsx index 26063fb8a7..23cb0421e4 100644 --- a/web/app/components/base/prompt-editor/plugins/current-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/current-block/__tests__/node.spec.tsx @@ -7,13 +7,13 @@ import { GeneratorType } from '@/app/components/app/configuration/config/automat import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import CurrentBlockComponent from './component' +} from '../../test-helpers' +import CurrentBlockComponent from '../component' import { $createCurrentBlockNode, $isCurrentBlockNode, CurrentBlockNode, -} from './node' +} from '../node' const createTestEditor = () => { return createLexicalTestEditor('current-block-node-test', [CurrentBlockNode]) diff --git a/web/app/components/base/prompt-editor/plugins/custom-text/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/custom-text/__tests__/node.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/custom-text/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/custom-text/__tests__/node.spec.tsx index 9688049950..52d2a19313 100644 --- a/web/app/components/base/prompt-editor/plugins/custom-text/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/custom-text/__tests__/node.spec.tsx @@ -1,7 +1,7 @@ import type { EditorConfig, LexicalEditor } from 'lexical' import { $createParagraphNode, $getRoot } from 'lexical' -import { createTestEditor, withEditorUpdate } from '../__tests__/utils' -import { $createCustomTextNode, CustomTextNode } from './node' +import { createTestEditor, withEditorUpdate } from '../../__tests__/utils' +import { $createCustomTextNode, CustomTextNode } from '../node' const createCustomTextTestEditor = () => createTestEditor([CustomTextNode]) diff --git a/web/app/components/base/prompt-editor/plugins/draggable-plugin/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/draggable-plugin/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/draggable-plugin/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/draggable-plugin/__tests__/index.spec.tsx index 1ee548fbcc..0e02525e17 100644 --- a/web/app/components/base/prompt-editor/plugins/draggable-plugin/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/draggable-plugin/__tests__/index.spec.tsx @@ -3,7 +3,7 @@ import { ContentEditable } from '@lexical/react/LexicalContentEditable' import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary' import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin' import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import DraggableBlockPlugin from '.' +import DraggableBlockPlugin from '..' const CONTENT_EDITABLE_TEST_ID = 'draggable-content-editable' let namespaceCounter = 0 diff --git a/web/app/components/base/prompt-editor/plugins/error-message-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/component.spec.tsx similarity index 95% rename from web/app/components/base/prompt-editor/plugins/error-message-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/component.spec.tsx index 7f03aa8ba1..b9576f35b5 100644 --- a/web/app/components/base/prompt-editor/plugins/error-message-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/component.spec.tsx @@ -4,11 +4,11 @@ import type { ReactElement } from 'react' import { LexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { useSelectOrDelete } from '../../hooks' -import ErrorMessageBlockComponent from './component' -import { DELETE_ERROR_MESSAGE_COMMAND, ErrorMessageBlockNode } from './index' +import { useSelectOrDelete } from '../../../hooks' +import ErrorMessageBlockComponent from '../component' +import { DELETE_ERROR_MESSAGE_COMMAND, ErrorMessageBlockNode } from '../index' -vi.mock('../../hooks') +vi.mock('../../../hooks') const mockHasNodes = vi.fn() diff --git a/web/app/components/base/prompt-editor/plugins/error-message-block/error-message-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/error-message-block-replacement-block.spec.tsx similarity index 93% rename from web/app/components/base/prompt-editor/plugins/error-message-block/error-message-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/error-message-block-replacement-block.spec.tsx index 30737abf36..ccef57867a 100644 --- a/web/app/components/base/prompt-editor/plugins/error-message-block/error-message-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/error-message-block-replacement-block.spec.tsx @@ -6,16 +6,16 @@ import { LexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' import { render } from '@testing-library/react' import { $applyNodeReplacement } from 'lexical' -import { ERROR_MESSAGE_PLACEHOLDER_TEXT } from '../../constants' -import { decoratorTransform } from '../../utils' -import { CustomTextNode } from '../custom-text/node' -import ErrorMessageBlockReplacementBlock from './error-message-block-replacement-block' -import { $createErrorMessageBlockNode, ErrorMessageBlockNode } from './node' +import { ERROR_MESSAGE_PLACEHOLDER_TEXT } from '../../../constants' +import { decoratorTransform } from '../../../utils' +import { CustomTextNode } from '../../custom-text/node' +import ErrorMessageBlockReplacementBlock from '../error-message-block-replacement-block' +import { $createErrorMessageBlockNode, ErrorMessageBlockNode } from '../node' vi.mock('@lexical/utils') vi.mock('lexical') -vi.mock('../../utils') -vi.mock('./node') +vi.mock('../../../utils') +vi.mock('../node') const mockHasNodes = vi.fn() const mockRegisterNodeTransform = vi.fn() diff --git a/web/app/components/base/prompt-editor/plugins/error-message-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/error-message-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/index.spec.tsx index 938fda1555..fa52df0a23 100644 --- a/web/app/components/base/prompt-editor/plugins/error-message-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/index.spec.tsx @@ -10,8 +10,8 @@ import { ErrorMessageBlock, ErrorMessageBlockNode, INSERT_ERROR_MESSAGE_BLOCK_COMMAND, -} from './index' -import { $createErrorMessageBlockNode } from './node' +} from '../index' +import { $createErrorMessageBlockNode } from '../node' vi.mock('@lexical/utils') vi.mock('lexical', async () => { @@ -23,7 +23,7 @@ vi.mock('lexical', async () => { COMMAND_PRIORITY_EDITOR: 1, } }) -vi.mock('./node') +vi.mock('../node') const mockHasNodes = vi.fn() const mockRegisterCommand = vi.fn() diff --git a/web/app/components/base/prompt-editor/plugins/error-message-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/node.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/error-message-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/node.spec.tsx index 6c28091f27..1e952d08c9 100644 --- a/web/app/components/base/prompt-editor/plugins/error-message-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/error-message-block/__tests__/node.spec.tsx @@ -1,6 +1,6 @@ import type { Klass, LexicalEditor, LexicalNode } from 'lexical' import { createEditor } from 'lexical' -import { $createErrorMessageBlockNode, $isErrorMessageBlockNode, ErrorMessageBlockNode } from './node' +import { $createErrorMessageBlockNode, $isErrorMessageBlockNode, ErrorMessageBlockNode } from '../node' describe('ErrorMessageBlockNode', () => { let editor: LexicalEditor diff --git a/web/app/components/base/prompt-editor/plugins/history-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/component.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/history-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/history-block/__tests__/component.spec.tsx index 5ba2f92b0e..4dc85a3081 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/component.spec.tsx @@ -1,10 +1,10 @@ import type { Dispatch, RefObject, SetStateAction } from 'react' -import type { RoleName } from './index' +import type { RoleName } from '../index' import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { UPDATE_HISTORY_EVENT_EMITTER } from '../../constants' -import HistoryBlockComponent from './component' -import { DELETE_HISTORY_BLOCK_COMMAND } from './index' +import { UPDATE_HISTORY_EVENT_EMITTER } from '../../../constants' +import HistoryBlockComponent from '../component' +import { DELETE_HISTORY_BLOCK_COMMAND } from '../index' type HistoryEventPayload = { type?: string @@ -19,7 +19,7 @@ const { mockUseSelectOrDelete, mockUseTrigger, mockUseEventEmitterContextContext mockUseEventEmitterContextContext: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), useTrigger: (...args: unknown[]) => mockUseTrigger(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/history-block-replacement-block.spec.tsx similarity index 91% rename from web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/history-block/__tests__/history-block-replacement-block.spec.tsx index af74f39a1d..a6e40ab6ed 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/history-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/history-block-replacement-block.spec.tsx @@ -1,19 +1,19 @@ import type { LexicalEditor } from 'lexical' -import type { RoleName } from './index' +import type { RoleName } from '../index' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, waitFor } from '@testing-library/react' import { $nodesOfType } from 'lexical' -import { HISTORY_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { HISTORY_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readEditorStateValue, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import HistoryBlockReplacementBlock from './history-block-replacement-block' -import { HistoryBlockNode } from './node' +} from '../../test-helpers' +import HistoryBlockReplacementBlock from '../history-block-replacement-block' +import { HistoryBlockNode } from '../node' const createRoleName = (overrides?: Partial): RoleName => ({ user: 'user-role', diff --git a/web/app/components/base/prompt-editor/plugins/history-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/prompt-editor/plugins/history-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/history-block/__tests__/index.spec.tsx index e41a8f7c63..682ec90a63 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/index.spec.tsx @@ -1,10 +1,10 @@ import type { LexicalEditor } from 'lexical' -import type { RoleName } from './index' +import type { RoleName } from '../index' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' import { $nodesOfType } from 'lexical' -import { HISTORY_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { HISTORY_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readEditorStateValue, @@ -12,14 +12,14 @@ import { renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { DELETE_HISTORY_BLOCK_COMMAND, HistoryBlock, HistoryBlockNode, INSERT_HISTORY_BLOCK_COMMAND, -} from './index' +} from '../index' const createRoleName = (overrides?: Partial): RoleName => ({ user: 'user-role', diff --git a/web/app/components/base/prompt-editor/plugins/history-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/node.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/history-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/history-block/__tests__/node.spec.tsx index b8603ef4fe..c7960d658e 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/__tests__/node.spec.tsx @@ -1,17 +1,17 @@ -import type { SerializedNode as SerializedHistoryBlockNode } from './node' +import type { SerializedNode as SerializedHistoryBlockNode } from '../node' import { act } from '@testing-library/react' import { $getNodeByKey, $getRoot } from 'lexical' import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import HistoryBlockComponent from './component' +} from '../../test-helpers' +import HistoryBlockComponent from '../component' import { $createHistoryBlockNode, $isHistoryBlockNode, HistoryBlockNode, -} from './node' +} from '../node' const createRoleName = (overrides?: { user?: string, assistant?: string }) => ({ user: 'user-role', diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component.spec.tsx index eb76728939..97085e694a 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component.spec.tsx @@ -3,17 +3,17 @@ import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { InputVarType } from '@/app/components/workflow/types' -import HITLInputComponent from './component' +import HITLInputComponent from '../component' const { mockUseSelectOrDelete } = vi.hoisted(() => ({ mockUseSelectOrDelete: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), })) -vi.mock('./component-ui', () => ({ +vi.mock('../component-ui', () => ({ default: ({ formInput, onChange }: { formInput?: FormInputItem, onChange: (payload: FormInputItem) => void }) => { const basePayload: FormInputItem = formInput ?? { type: InputVarType.paragraph, diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/hitl-input-block-replacement-block.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/hitl-input-block-replacement-block.spec.tsx index d01cab70c2..57f1db1fa3 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/hitl-input-block-replacement-block.spec.tsx @@ -1,5 +1,5 @@ import type { LexicalEditor } from 'lexical' -import type { GetVarType } from '../../types' +import type { GetVarType } from '../../../types' import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types' import type { NodeOutPutVar, Var } from '@/app/components/workflow/types' import { LexicalComposer } from '@lexical/react/LexicalComposer' @@ -10,16 +10,16 @@ import { BlockEnum, InputVarType, } from '@/app/components/workflow/types' -import { CustomTextNode } from '../custom-text/node' +import { CustomTextNode } from '../../custom-text/node' import { getNodesByType, readEditorStateValue, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import HITLInputReplacementBlock from './hitl-input-block-replacement-block' -import { HITLInputNode } from './node' +} from '../../test-helpers' +import HITLInputReplacementBlock from '../hitl-input-block-replacement-block' +import { HITLInputNode } from '../node' const createWorkflowNodesMap = () => ({ 'node-1': { diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/index.spec.tsx index dc94b0b319..b5f38cdd1b 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/index.spec.tsx @@ -10,21 +10,21 @@ import { BlockEnum, InputVarType, } from '@/app/components/workflow/types' -import { CustomTextNode } from '../custom-text/node' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readRootTextContent, renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { DELETE_HITL_INPUT_BLOCK_COMMAND, HITLInputBlock, HITLInputNode, INSERT_HITL_INPUT_BLOCK_COMMAND, UPDATE_WORKFLOW_NODES_MAP, -} from './index' +} from '../index' type UpdateWorkflowNodesMapPluginProps = { onUpdate: (payload: unknown) => void diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/input-field.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/input-field.spec.tsx index b7518e8895..949295a8a8 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/input-field.spec.tsx @@ -2,7 +2,7 @@ import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { InputVarType } from '@/app/components/workflow/types' -import InputField from './input-field' +import InputField from '../input-field' type VarReferencePickerProps = { onChange: (value: string[]) => void diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/node.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/node.spec.tsx index ef2a0e0c51..f4ab8ff90a 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/node.spec.tsx @@ -8,13 +8,13 @@ import { import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import HITLInputBlockComponent from './component' +} from '../../test-helpers' +import HITLInputBlockComponent from '../component' import { $createHITLInputNode, $isHITLInputNode, HITLInputNode, -} from './node' +} from '../node' const createFormInput = (): FormInputItem => ({ type: InputVarType.paragraph, diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/pre-populate.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/pre-populate.spec.tsx index be95aea062..880ad509b3 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/pre-populate.spec.tsx @@ -2,7 +2,7 @@ import type { Var } from '@/app/components/workflow/types' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { useState } from 'react' -import PrePopulate from './pre-populate' +import PrePopulate from '../pre-populate' const { mockVarReferencePicker } = vi.hoisted(() => ({ mockVarReferencePicker: vi.fn(), diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/tag-label.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/tag-label.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/tag-label.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/tag-label.spec.tsx index c39b66e545..d85224ca74 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/tag-label.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/tag-label.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TagLabel from './tag-label' +import TagLabel from '../tag-label' describe('TagLabel', () => { beforeEach(() => { diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/type-switch.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/type-switch.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/type-switch.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/type-switch.spec.tsx index b3d1376eb9..a23ef088f9 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/type-switch.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/type-switch.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TypeSwitch from './type-switch' +import TypeSwitch from '../type-switch' describe('TypeSwitch', () => { beforeEach(() => { diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/variable-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx similarity index 95% rename from web/app/components/base/prompt-editor/plugins/hitl-input-block/variable-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx index 727bc664d3..f16951aed1 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/variable-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx @@ -1,5 +1,5 @@ import type { LexicalEditor } from 'lexical' -import type { WorkflowNodesMap } from '../workflow-variable-block/node' +import type { WorkflowNodesMap } from '../../workflow-variable-block/node' import type { Var } from '@/app/components/workflow/types' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, screen, waitFor } from '@testing-library/react' @@ -10,10 +10,10 @@ import { Type } from '@/app/components/workflow/nodes/llm/types' import { BlockEnum, } from '@/app/components/workflow/types' -import { CaptureEditorPlugin } from '../test-utils' -import { UPDATE_WORKFLOW_NODES_MAP } from '../workflow-variable-block' -import { HITLInputNode } from './node' -import HITLInputVariableBlockComponent from './variable-block' +import { CaptureEditorPlugin } from '../../test-utils' +import { UPDATE_WORKFLOW_NODES_MAP } from '../../workflow-variable-block' +import { HITLInputNode } from '../node' +import HITLInputVariableBlockComponent from '../variable-block' const createWorkflowNodesMap = (title = 'Node One'): WorkflowNodesMap => ({ 'node-1': { diff --git a/web/app/components/base/prompt-editor/plugins/last-run-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/component.spec.tsx similarity index 93% rename from web/app/components/base/prompt-editor/plugins/last-run-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/component.spec.tsx index 29da9e4e9c..8a777be096 100644 --- a/web/app/components/base/prompt-editor/plugins/last-run-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/component.spec.tsx @@ -2,15 +2,15 @@ import type { RefObject } from 'react' import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { LastRunBlockNode } from '.' -import { CustomTextNode } from '../custom-text/node' -import LastRunBlockComponent from './component' +import { LastRunBlockNode } from '..' +import { CustomTextNode } from '../../custom-text/node' +import LastRunBlockComponent from '../component' const { mockUseSelectOrDelete } = vi.hoisted(() => ({ mockUseSelectOrDelete: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/last-run-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/last-run-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/index.spec.tsx index 7a28bf847d..73af3ee857 100644 --- a/web/app/components/base/prompt-editor/plugins/last-run-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/index.spec.tsx @@ -1,20 +1,20 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' -import { LAST_RUN_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { LAST_RUN_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readRootTextContent, renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { DELETE_LAST_RUN_COMMAND, INSERT_LAST_RUN_BLOCK_COMMAND, LastRunBlock, LastRunBlockNode, -} from './index' +} from '../index' const renderLastRunBlock = (props?: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/last-run-block/last-run-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/last-run-block-replacement-block.spec.tsx similarity index 91% rename from web/app/components/base/prompt-editor/plugins/last-run-block/last-run-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/last-run-block-replacement-block.spec.tsx index ba144c9e5f..c0adc2275a 100644 --- a/web/app/components/base/prompt-editor/plugins/last-run-block/last-run-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/last-run-block-replacement-block.spec.tsx @@ -1,15 +1,15 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, waitFor } from '@testing-library/react' -import { LAST_RUN_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { LAST_RUN_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import { LastRunBlockNode } from './index' -import LastRunReplacementBlock from './last-run-block-replacement-block' +} from '../../test-helpers' +import { LastRunBlockNode } from '../index' +import LastRunReplacementBlock from '../last-run-block-replacement-block' const renderReplacementPlugin = (props?: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/last-run-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/node.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/last-run-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/node.spec.tsx index dcc75b56c6..e7752b0ddc 100644 --- a/web/app/components/base/prompt-editor/plugins/last-run-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/last-run-block/__tests__/node.spec.tsx @@ -2,13 +2,13 @@ import { act } from '@testing-library/react' import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import LastRunBlockComponent from './component' +} from '../../test-helpers' +import LastRunBlockComponent from '../component' import { $createLastRunBlockNode, $isLastRunBlockNode, LastRunBlockNode, -} from './node' +} from '../node' const createTestEditor = () => { return createLexicalTestEditor('last-run-block-node-test', [LastRunBlockNode]) diff --git a/web/app/components/base/prompt-editor/plugins/query-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/component.spec.tsx similarity index 92% rename from web/app/components/base/prompt-editor/plugins/query-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/query-block/__tests__/component.spec.tsx index 28f439cafe..9b7ebf0399 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/component.spec.tsx @@ -1,13 +1,13 @@ import type { RefObject } from 'react' import { render, screen } from '@testing-library/react' -import QueryBlockComponent from './component' -import { DELETE_QUERY_BLOCK_COMMAND } from './index' +import QueryBlockComponent from '../component' +import { DELETE_QUERY_BLOCK_COMMAND } from '../index' const { mockUseSelectOrDelete } = vi.hoisted(() => ({ mockUseSelectOrDelete: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/query-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/query-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/query-block/__tests__/index.spec.tsx index 08f6109b7c..f17018f12c 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/index.spec.tsx @@ -1,20 +1,20 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' -import { QUERY_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { QUERY_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readRootTextContent, renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { DELETE_QUERY_BLOCK_COMMAND, INSERT_QUERY_BLOCK_COMMAND, QueryBlock, QueryBlockNode, -} from './index' +} from '../index' const renderQueryBlock = (props: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/query-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/node.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/query-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/query-block/__tests__/node.spec.tsx index e91714e098..e927856e1a 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/node.spec.tsx @@ -2,13 +2,13 @@ import { act } from '@testing-library/react' import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import QueryBlockComponent from './component' +} from '../../test-helpers' +import QueryBlockComponent from '../component' import { $createQueryBlockNode, $isQueryBlockNode, QueryBlockNode, -} from './node' +} from '../node' describe('QueryBlockNode', () => { const createTestEditor = () => { diff --git a/web/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/query-block-replacement-block.spec.tsx similarity index 91% rename from web/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/query-block/__tests__/query-block-replacement-block.spec.tsx index 379128df2e..9a92aba3c0 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/query-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/__tests__/query-block-replacement-block.spec.tsx @@ -1,15 +1,15 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, waitFor } from '@testing-library/react' -import { QUERY_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { QUERY_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import { QueryBlockNode } from './index' -import QueryBlockReplacementBlock from './query-block-replacement-block' +} from '../../test-helpers' +import { QueryBlockNode } from '../index' +import QueryBlockReplacementBlock from '../query-block-replacement-block' const renderReplacementPlugin = (props: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/request-url-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/component.spec.tsx similarity index 92% rename from web/app/components/base/prompt-editor/plugins/request-url-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/component.spec.tsx index f1b97d9417..811eaf462f 100644 --- a/web/app/components/base/prompt-editor/plugins/request-url-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/component.spec.tsx @@ -1,13 +1,13 @@ import type { RefObject } from 'react' import { render, screen } from '@testing-library/react' -import RequestURLBlockComponent from './component' -import { DELETE_REQUEST_URL_BLOCK_COMMAND } from './index' +import RequestURLBlockComponent from '../component' +import { DELETE_REQUEST_URL_BLOCK_COMMAND } from '../index' const { mockUseSelectOrDelete } = vi.hoisted(() => ({ mockUseSelectOrDelete: vi.fn(), })) -vi.mock('../../hooks', () => ({ +vi.mock('../../../hooks', () => ({ useSelectOrDelete: (...args: unknown[]) => mockUseSelectOrDelete(...args), })) diff --git a/web/app/components/base/prompt-editor/plugins/request-url-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/index.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/request-url-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/index.spec.tsx index 431acdb0df..2b479edd09 100644 --- a/web/app/components/base/prompt-editor/plugins/request-url-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/index.spec.tsx @@ -1,20 +1,20 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { act, render, waitFor } from '@testing-library/react' -import { REQUEST_URL_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { REQUEST_URL_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, readRootTextContent, renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import { DELETE_REQUEST_URL_BLOCK_COMMAND, INSERT_REQUEST_URL_BLOCK_COMMAND, RequestURLBlock, RequestURLBlockNode, -} from './index' +} from '../index' const renderRequestURLBlock = (props: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/request-url-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/node.spec.tsx similarity index 96% rename from web/app/components/base/prompt-editor/plugins/request-url-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/node.spec.tsx index aa8a661512..fddbff4deb 100644 --- a/web/app/components/base/prompt-editor/plugins/request-url-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/node.spec.tsx @@ -2,13 +2,13 @@ import { act } from '@testing-library/react' import { createLexicalTestEditor, expectInlineWrapperDom, -} from '../test-helpers' -import RequestURLBlockComponent from './component' +} from '../../test-helpers' +import RequestURLBlockComponent from '../component' import { $createRequestURLBlockNode, $isRequestURLBlockNode, RequestURLBlockNode, -} from './node' +} from '../node' describe('RequestURLBlockNode', () => { const createTestEditor = () => { diff --git a/web/app/components/base/prompt-editor/plugins/request-url-block/request-url-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/request-url-block-replacement-block.spec.tsx similarity index 90% rename from web/app/components/base/prompt-editor/plugins/request-url-block/request-url-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/request-url-block-replacement-block.spec.tsx index 77c78d0e50..1df74ed4e6 100644 --- a/web/app/components/base/prompt-editor/plugins/request-url-block/request-url-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/request-url-block/__tests__/request-url-block-replacement-block.spec.tsx @@ -1,15 +1,15 @@ import { LexicalComposer } from '@lexical/react/LexicalComposer' import { render, waitFor } from '@testing-library/react' -import { REQUEST_URL_PLACEHOLDER_TEXT } from '../../constants' -import { CustomTextNode } from '../custom-text/node' +import { REQUEST_URL_PLACEHOLDER_TEXT } from '../../../constants' +import { CustomTextNode } from '../../custom-text/node' import { getNodeCount, renderLexicalEditor, setEditorRootText, waitForEditorReady, -} from '../test-helpers' -import { RequestURLBlockNode } from './index' -import RequestURLBlockReplacementBlock from './request-url-block-replacement-block' +} from '../../test-helpers' +import { RequestURLBlockNode } from '../index' +import RequestURLBlockReplacementBlock from '../request-url-block-replacement-block' const renderReplacementPlugin = (props: { onInsert?: () => void diff --git a/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/__tests__/index.spec.tsx index ad44970187..6e636845a6 100644 --- a/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/__tests__/index.spec.tsx @@ -5,7 +5,7 @@ import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import * as React from 'react' import { useState } from 'react' -import ShortcutsPopupPlugin, { SHORTCUTS_EMPTY_CONTENT } from './index' +import ShortcutsPopupPlugin, { SHORTCUTS_EMPTY_CONTENT } from '../index' import '@testing-library/jest-dom' // Mock Range.getClientRects and getBoundingClientRect for JSDOM diff --git a/web/app/components/base/prompt-editor/plugins/variable-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/variable-block/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/prompt-editor/plugins/variable-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/variable-block/__tests__/index.spec.tsx index f835ec07ef..f28dcab4ba 100644 --- a/web/app/components/base/prompt-editor/plugins/variable-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/variable-block/__tests__/index.spec.tsx @@ -1,15 +1,15 @@ import { act, waitFor } from '@testing-library/react' -import { CustomTextNode } from '../custom-text/node' +import { CustomTextNode } from '../../custom-text/node' import { readRootTextContent, renderLexicalEditor, selectRootEnd, waitForEditorReady, -} from '../test-helpers' +} from '../../test-helpers' import VariableBlock, { INSERT_VARIABLE_BLOCK_COMMAND, INSERT_VARIABLE_VALUE_BLOCK_COMMAND, -} from './index' +} from '../index' const renderVariableBlock = () => { return renderLexicalEditor({ diff --git a/web/app/components/base/prompt-editor/plugins/variable-value-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/index.spec.tsx similarity index 94% rename from web/app/components/base/prompt-editor/plugins/variable-value-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/index.spec.tsx index 7398cad558..a77c62859b 100644 --- a/web/app/components/base/prompt-editor/plugins/variable-value-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/index.spec.tsx @@ -4,12 +4,12 @@ import type { LexicalEditor } from 'lexical' import type { ReactElement } from 'react' import { LexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { render } from '@testing-library/react' -import { useLexicalTextEntity } from '../../hooks' -import VariableValueBlock from './index' -import { $createVariableValueBlockNode, VariableValueBlockNode } from './node' +import { useLexicalTextEntity } from '../../../hooks' +import VariableValueBlock from '../index' +import { $createVariableValueBlockNode, VariableValueBlockNode } from '../node' -vi.mock('../../hooks') -vi.mock('./node') +vi.mock('../../../hooks') +vi.mock('../node') const mockHasNodes = vi.fn() diff --git a/web/app/components/base/prompt-editor/plugins/variable-value-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/node.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/variable-value-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/node.spec.tsx index f78a76166d..a81b59d454 100644 --- a/web/app/components/base/prompt-editor/plugins/variable-value-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/variable-value-block/__tests__/node.spec.tsx @@ -4,7 +4,7 @@ import { $createVariableValueBlockNode, $isVariableValueNodeBlock, VariableValueBlockNode, -} from './node' +} from '../node' describe('VariableValueBlockNode', () => { let editor: LexicalEditor diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.spec.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/component.spec.tsx similarity index 98% rename from web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.spec.tsx rename to web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/component.spec.tsx index b07ed7de42..ff064f2a99 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/component.spec.tsx @@ -7,10 +7,10 @@ import userEvent from '@testing-library/user-event' import { useReactFlow, useStoreApi } from 'reactflow' import { Type } from '@/app/components/workflow/nodes/llm/types' import { BlockEnum, VarType } from '@/app/components/workflow/types' -import { useSelectOrDelete } from '../../hooks' -import WorkflowVariableBlockComponent from './component' -import { UPDATE_WORKFLOW_NODES_MAP } from './index' -import { WorkflowVariableBlockNode } from './node' +import { useSelectOrDelete } from '../../../hooks' +import WorkflowVariableBlockComponent from '../component' +import { UPDATE_WORKFLOW_NODES_MAP } from '../index' +import { WorkflowVariableBlockNode } from '../node' const { mockVarLabel, mockIsExceptionVariable, mockForcedVariableKind } = vi.hoisted(() => ({ mockVarLabel: vi.fn(), @@ -21,7 +21,7 @@ const { mockVarLabel, mockIsExceptionVariable, mockForcedVariableKind } = vi.hoi vi.mock('@lexical/react/LexicalComposerContext') vi.mock('@lexical/utils') vi.mock('reactflow') -vi.mock('../../hooks') +vi.mock('../../../hooks') vi.mock('@/app/components/workflow/utils', async (importOriginal) => { const actual = await importOriginal() return { diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.spec.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.spec.tsx rename to web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/index.spec.tsx index d36f55bc47..ca4973b830 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { LexicalComposerContextWithEditor } from '@lexical/react/LexicalComposerContext' import type { LexicalEditor } from 'lexical' import type { ReactElement } from 'react' -import type { WorkflowNodesMap } from './node' +import type { WorkflowNodesMap } from '../node' import { LexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' import { render } from '@testing-library/react' @@ -15,8 +15,8 @@ import { UPDATE_WORKFLOW_NODES_MAP, WorkflowVariableBlock, WorkflowVariableBlockNode, -} from './index' -import { $createWorkflowVariableBlockNode } from './node' +} from '../index' +import { $createWorkflowVariableBlockNode } from '../node' vi.mock('@lexical/utils') vi.mock('lexical', async () => { @@ -28,7 +28,7 @@ vi.mock('lexical', async () => { COMMAND_PRIORITY_EDITOR: 1, } }) -vi.mock('./node') +vi.mock('../node') const mockHasNodes = vi.fn() const mockRegisterCommand = vi.fn() diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.spec.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/node.spec.tsx similarity index 99% rename from web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.spec.tsx rename to web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/node.spec.tsx index 6f894690ab..8d7a1cc33d 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/node.spec.tsx @@ -7,7 +7,7 @@ import { $createWorkflowVariableBlockNode, $isWorkflowVariableBlockNode, WorkflowVariableBlockNode, -} from './node' +} from '../node' describe('WorkflowVariableBlockNode', () => { let editor: LexicalEditor diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/workflow-variable-block-replacement-block.spec.tsx similarity index 94% rename from web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.spec.tsx rename to web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/workflow-variable-block-replacement-block.spec.tsx index 71ef39d02c..b9cb1faa37 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/__tests__/workflow-variable-block-replacement-block.spec.tsx @@ -2,7 +2,7 @@ import type { LexicalComposerContextWithEditor } from '@lexical/react/LexicalCom import type { EntityMatch } from '@lexical/text' import type { LexicalEditor, LexicalNode } from 'lexical' import type { ReactElement } from 'react' -import type { WorkflowNodesMap } from './node' +import type { WorkflowNodesMap } from '../node' import type { NodeOutPutVar } from '@/app/components/workflow/types' import { LexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' @@ -10,16 +10,16 @@ import { render } from '@testing-library/react' import { $applyNodeReplacement } from 'lexical' import { Type } from '@/app/components/workflow/nodes/llm/types' import { BlockEnum, VarType } from '@/app/components/workflow/types' -import { decoratorTransform } from '../../utils' -import { CustomTextNode } from '../custom-text/node' -import { WorkflowVariableBlockNode } from './index' -import { $createWorkflowVariableBlockNode } from './node' -import WorkflowVariableBlockReplacementBlock from './workflow-variable-block-replacement-block' +import { decoratorTransform } from '../../../utils' +import { CustomTextNode } from '../../custom-text/node' +import { WorkflowVariableBlockNode } from '../index' +import { $createWorkflowVariableBlockNode } from '../node' +import WorkflowVariableBlockReplacementBlock from '../workflow-variable-block-replacement-block' vi.mock('@lexical/utils') vi.mock('lexical') -vi.mock('../../utils') -vi.mock('./node') +vi.mock('../../../utils') +vi.mock('../node') const mockHasNodes = vi.fn() const mockRegisterNodeTransform = vi.fn() diff --git a/web/app/components/base/prompt-log-modal/card.spec.tsx b/web/app/components/base/prompt-log-modal/__tests__/card.spec.tsx similarity index 96% rename from web/app/components/base/prompt-log-modal/card.spec.tsx rename to web/app/components/base/prompt-log-modal/__tests__/card.spec.tsx index 500e9db941..3b312343d9 100644 --- a/web/app/components/base/prompt-log-modal/card.spec.tsx +++ b/web/app/components/base/prompt-log-modal/__tests__/card.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Card from './card' +import Card from '../card' describe('PromptLogModal Card', () => { it('renders single log entry correctly', () => { diff --git a/web/app/components/base/prompt-log-modal/index.spec.tsx b/web/app/components/base/prompt-log-modal/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/prompt-log-modal/index.spec.tsx rename to web/app/components/base/prompt-log-modal/__tests__/index.spec.tsx index c04e668026..05c1e5d093 100644 --- a/web/app/components/base/prompt-log-modal/index.spec.tsx +++ b/web/app/components/base/prompt-log-modal/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import PromptLogModal from '.' +import PromptLogModal from '..' describe('PromptLogModal', () => { const defaultProps = { diff --git a/web/app/components/base/qrcode/index.spec.tsx b/web/app/components/base/qrcode/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/qrcode/index.spec.tsx rename to web/app/components/base/qrcode/__tests__/index.spec.tsx index 3e1d5ff6d9..fbad4163c4 100644 --- a/web/app/components/base/qrcode/index.spec.tsx +++ b/web/app/components/base/qrcode/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { downloadUrl } from '@/utils/download' -import ShareQRCode from '.' +import ShareQRCode from '..' vi.mock('@/utils/download', () => ({ downloadUrl: vi.fn(), diff --git a/web/app/components/base/radio-card/index.spec.tsx b/web/app/components/base/radio-card/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/radio-card/index.spec.tsx rename to web/app/components/base/radio-card/__tests__/index.spec.tsx index f1368476bf..f4bc7a5b0e 100644 --- a/web/app/components/base/radio-card/index.spec.tsx +++ b/web/app/components/base/radio-card/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' // index.spec.tsx import { describe, expect, it, vi } from 'vitest' -import RadioCard from './index' +import RadioCard from '../index' describe('RadioCard', () => { it('renders icon, title and description', () => { diff --git a/web/app/components/base/radio-card/simple/index.spec.tsx b/web/app/components/base/radio-card/simple/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/radio-card/simple/index.spec.tsx rename to web/app/components/base/radio-card/simple/__tests__/index.spec.tsx index 42e03484e8..d04cefe61a 100644 --- a/web/app/components/base/radio-card/simple/index.spec.tsx +++ b/web/app/components/base/radio-card/simple/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' // index.spec.tsx import { describe, expect, it, vi } from 'vitest' -import RadioCard from './index' +import RadioCard from '../index' describe('RadioCard', () => { it('renders title and description', () => { diff --git a/web/app/components/base/radio/index.spec.tsx b/web/app/components/base/radio/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/radio/index.spec.tsx rename to web/app/components/base/radio/__tests__/index.spec.tsx index 838a0eb0ef..6a81648400 100644 --- a/web/app/components/base/radio/index.spec.tsx +++ b/web/app/components/base/radio/__tests__/index.spec.tsx @@ -2,8 +2,8 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' // index.spec.tsx import { describe, expect, it, vi } from 'vitest' -import Group from './component/group' -import Radio from './index' +import Group from '../component/group' +import Radio from '../index' describe('Radio (index)', () => { it('attaches Group as a property on the default export', () => { diff --git a/web/app/components/base/radio/ui.spec.tsx b/web/app/components/base/radio/__tests__/ui.spec.tsx similarity index 98% rename from web/app/components/base/radio/ui.spec.tsx rename to web/app/components/base/radio/__tests__/ui.spec.tsx index 7dec5f3660..cb8d18e0b8 100644 --- a/web/app/components/base/radio/ui.spec.tsx +++ b/web/app/components/base/radio/__tests__/ui.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' // radio-ui.spec.tsx import { describe, expect, it, vi } from 'vitest' -import RadioUI from './ui' +import RadioUI from '../ui' describe('RadioUI component', () => { it('renders with correct role and aria attributes', () => { diff --git a/web/app/components/base/radio/component/group/index.spec.tsx b/web/app/components/base/radio/component/group/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/radio/component/group/index.spec.tsx rename to web/app/components/base/radio/component/group/__tests__/index.spec.tsx index e417c2a203..32ca0f2d86 100644 --- a/web/app/components/base/radio/component/group/index.spec.tsx +++ b/web/app/components/base/radio/component/group/__tests__/index.spec.tsx @@ -3,8 +3,8 @@ import userEvent from '@testing-library/user-event' import { useContextSelector } from 'use-context-selector' // Group.test.tsx import { describe, expect, it, vi } from 'vitest' -import RadioGroupContext from '../../context' -import Group from './index' +import RadioGroupContext from '../../../context' +import Group from '../index' // small consumer that uses the same context as your component function ContextConsumer({ showButton = true }: { showButton?: boolean }) { diff --git a/web/app/components/base/radio/component/radio/index.spec.tsx b/web/app/components/base/radio/component/radio/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/radio/component/radio/index.spec.tsx rename to web/app/components/base/radio/component/radio/__tests__/index.spec.tsx index cdf0587453..bab5d64e38 100644 --- a/web/app/components/base/radio/component/radio/index.spec.tsx +++ b/web/app/components/base/radio/component/radio/__tests__/index.spec.tsx @@ -2,8 +2,8 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' // index.spec.tsx import { describe, expect, it, vi } from 'vitest' -import RadioGroupContext from '../../context' -import Radio from './index' +import RadioGroupContext from '../../../context' +import Radio from '../index' describe('Radio component', () => { it('renders label children and assigns an id to the label', () => { diff --git a/web/app/components/base/radio/context/index.spec.tsx b/web/app/components/base/radio/context/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/radio/context/index.spec.tsx rename to web/app/components/base/radio/context/__tests__/index.spec.tsx index 105bbbed3c..17b40c58e8 100644 --- a/web/app/components/base/radio/context/index.spec.tsx +++ b/web/app/components/base/radio/context/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import { useContextSelector } from 'use-context-selector' // context.spec.tsx import { describe, expect, it } from 'vitest' -import RadioGroupContext from './index' +import RadioGroupContext from '../index' function Consumer() { const value = useContextSelector(RadioGroupContext, v => v) diff --git a/web/app/components/base/search-input/index.spec.tsx b/web/app/components/base/search-input/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/search-input/index.spec.tsx rename to web/app/components/base/search-input/__tests__/index.spec.tsx index db70087d85..44c13b9d48 100644 --- a/web/app/components/base/search-input/index.spec.tsx +++ b/web/app/components/base/search-input/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SearchInput from '.' +import SearchInput from '..' describe('SearchInput', () => { describe('Render', () => { diff --git a/web/app/components/base/segmented-control/index.spec.tsx b/web/app/components/base/segmented-control/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/segmented-control/index.spec.tsx rename to web/app/components/base/segmented-control/__tests__/index.spec.tsx index d83ec58757..f92d5b29b0 100644 --- a/web/app/components/base/segmented-control/index.spec.tsx +++ b/web/app/components/base/segmented-control/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SegmentedControl from './index' +import SegmentedControl from '../index' describe('SegmentedControl', () => { const options = [ diff --git a/web/app/components/base/select/custom.spec.tsx b/web/app/components/base/select/__tests__/custom.spec.tsx similarity index 98% rename from web/app/components/base/select/custom.spec.tsx rename to web/app/components/base/select/__tests__/custom.spec.tsx index 994045610c..8868d70fc4 100644 --- a/web/app/components/base/select/custom.spec.tsx +++ b/web/app/components/base/select/__tests__/custom.spec.tsx @@ -1,7 +1,7 @@ -import type { Option } from './custom' +import type { Option } from '../custom' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import CustomSelect from './custom' +import CustomSelect from '../custom' const options: Option[] = [ { label: 'First option', value: 'first' }, diff --git a/web/app/components/base/select/index.spec.tsx b/web/app/components/base/select/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/select/index.spec.tsx rename to web/app/components/base/select/__tests__/index.spec.tsx index b30381942b..b3e518eaf1 100644 --- a/web/app/components/base/select/index.spec.tsx +++ b/web/app/components/base/select/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ -import type { Item } from './index' +import type { Item } from '../index' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import Select, { PortalSelect, SimpleSelect } from './index' +import Select, { PortalSelect, SimpleSelect } from '../index' const items: Item[] = [ { value: 'apple', name: 'Apple' }, diff --git a/web/app/components/base/select/locale-signin.spec.tsx b/web/app/components/base/select/__tests__/locale-signin.spec.tsx similarity index 98% rename from web/app/components/base/select/locale-signin.spec.tsx rename to web/app/components/base/select/__tests__/locale-signin.spec.tsx index ec08de30b6..1eca2b1aed 100644 --- a/web/app/components/base/select/locale-signin.spec.tsx +++ b/web/app/components/base/select/__tests__/locale-signin.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import LocaleSigninSelect from './locale-signin' +import LocaleSigninSelect from '../locale-signin' const localeItems = [ { value: 'en-US', name: 'English (US)' }, diff --git a/web/app/components/base/select/locale.spec.tsx b/web/app/components/base/select/__tests__/locale.spec.tsx similarity index 98% rename from web/app/components/base/select/locale.spec.tsx rename to web/app/components/base/select/__tests__/locale.spec.tsx index 10e32ff9f7..2c1c83bf95 100644 --- a/web/app/components/base/select/locale.spec.tsx +++ b/web/app/components/base/select/__tests__/locale.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import LocaleSelect from './locale' +import LocaleSelect from '../locale' const localeItems = [ { value: 'en-US', name: 'English (US)' }, diff --git a/web/app/components/base/select/pure.spec.tsx b/web/app/components/base/select/__tests__/pure.spec.tsx similarity index 98% rename from web/app/components/base/select/pure.spec.tsx rename to web/app/components/base/select/__tests__/pure.spec.tsx index fb7fc3ab07..885ee99c52 100644 --- a/web/app/components/base/select/pure.spec.tsx +++ b/web/app/components/base/select/__tests__/pure.spec.tsx @@ -1,7 +1,7 @@ -import type { Option } from './pure' +import type { Option } from '../pure' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import PureSelect from './pure' +import PureSelect from '../pure' const options: Option[] = [ { label: 'Apple', value: 'apple' }, diff --git a/web/app/components/base/simple-pie-chart/index.spec.tsx b/web/app/components/base/simple-pie-chart/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/simple-pie-chart/index.spec.tsx rename to web/app/components/base/simple-pie-chart/__tests__/index.spec.tsx index f1403ffe20..2f511e8392 100644 --- a/web/app/components/base/simple-pie-chart/index.spec.tsx +++ b/web/app/components/base/simple-pie-chart/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react' -import SimplePieChart from '.' +import SimplePieChart from '..' describe('SimplePieChart', () => { describe('Rendering', () => { diff --git a/web/app/components/base/skeleton/index.spec.tsx b/web/app/components/base/skeleton/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/skeleton/index.spec.tsx rename to web/app/components/base/skeleton/__tests__/index.spec.tsx index 8f0d9a6837..00852f7031 100644 --- a/web/app/components/base/skeleton/index.spec.tsx +++ b/web/app/components/base/skeleton/__tests__/index.spec.tsx @@ -6,7 +6,7 @@ import { SkeletonPoint, SkeletonRectangle, SkeletonRow, -} from './index' +} from '../index' describe('Skeleton Components', () => { describe('Individual Components', () => { diff --git a/web/app/components/base/slider/index.spec.tsx b/web/app/components/base/slider/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/slider/index.spec.tsx rename to web/app/components/base/slider/__tests__/index.spec.tsx index c9ebabd63e..bb1f030689 100644 --- a/web/app/components/base/slider/index.spec.tsx +++ b/web/app/components/base/slider/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { act, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import Slider from './index' +import Slider from '../index' describe('Slider Component', () => { it('should render with correct default ARIA limits and current value', () => { diff --git a/web/app/components/base/sort/index.spec.tsx b/web/app/components/base/sort/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/sort/index.spec.tsx rename to web/app/components/base/sort/__tests__/index.spec.tsx index 92ea2b44f9..e51ec23805 100644 --- a/web/app/components/base/sort/index.spec.tsx +++ b/web/app/components/base/sort/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { describe, expect, it, vi } from 'vitest' -import Sort from './index' +import Sort from '../index' const mockItems = [ { value: 'created_at', name: 'Date Created' }, diff --git a/web/app/components/base/spinner/index.spec.tsx b/web/app/components/base/spinner/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/spinner/index.spec.tsx rename to web/app/components/base/spinner/__tests__/index.spec.tsx index 652d061206..50cf2d3b04 100644 --- a/web/app/components/base/spinner/index.spec.tsx +++ b/web/app/components/base/spinner/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render } from '@testing-library/react' import * as React from 'react' -import Spinner from './index' +import Spinner from '../index' describe('Spinner component', () => { it('should render correctly when loading is true', () => { diff --git a/web/app/components/base/svg-gallery/index.spec.tsx b/web/app/components/base/svg-gallery/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/svg-gallery/index.spec.tsx rename to web/app/components/base/svg-gallery/__tests__/index.spec.tsx index 01994f0a16..c990f0211f 100644 --- a/web/app/components/base/svg-gallery/index.spec.tsx +++ b/web/app/components/base/svg-gallery/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' -import SVGRenderer from '.' +import SVGRenderer from '..' const mockClick = vi.fn() const mockSvg = vi.fn().mockReturnValue({ diff --git a/web/app/components/base/svg/index.spec.tsx b/web/app/components/base/svg/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/svg/index.spec.tsx rename to web/app/components/base/svg/__tests__/index.spec.tsx index fd05af0e70..88d5969729 100644 --- a/web/app/components/base/svg/index.spec.tsx +++ b/web/app/components/base/svg/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SVGBtn from '.' +import SVGBtn from '..' describe('SVGBtn', () => { describe('Rendering', () => { diff --git a/web/app/components/base/switch/index.spec.tsx b/web/app/components/base/switch/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/switch/index.spec.tsx rename to web/app/components/base/switch/__tests__/index.spec.tsx index d4788939c6..127efc987f 100644 --- a/web/app/components/base/switch/index.spec.tsx +++ b/web/app/components/base/switch/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import Switch from './index' +import Switch from '../index' describe('Switch', () => { it('should render in unchecked state when value is false', () => { diff --git a/web/app/components/base/tab-header/index.spec.tsx b/web/app/components/base/tab-header/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tab-header/index.spec.tsx rename to web/app/components/base/tab-header/__tests__/index.spec.tsx index df0a827e57..ee10415154 100644 --- a/web/app/components/base/tab-header/index.spec.tsx +++ b/web/app/components/base/tab-header/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import TabHeader from './index' +import TabHeader from '../index' describe('TabHeader Component', () => { const mockItems = [ diff --git a/web/app/components/base/tab-slider-new/index.spec.tsx b/web/app/components/base/tab-slider-new/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/tab-slider-new/index.spec.tsx rename to web/app/components/base/tab-slider-new/__tests__/index.spec.tsx index d47afb2aed..a8772093c3 100644 --- a/web/app/components/base/tab-slider-new/index.spec.tsx +++ b/web/app/components/base/tab-slider-new/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import TabSliderNew from './index' +import TabSliderNew from '../index' describe('TabSliderNew Component', () => { const mockOptions = [ diff --git a/web/app/components/base/tab-slider-plain/index.spec.tsx b/web/app/components/base/tab-slider-plain/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tab-slider-plain/index.spec.tsx rename to web/app/components/base/tab-slider-plain/__tests__/index.spec.tsx index 40c5b8c329..898ff99ce9 100644 --- a/web/app/components/base/tab-slider-plain/index.spec.tsx +++ b/web/app/components/base/tab-slider-plain/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import TabSlider from './index' +import TabSlider from '../index' describe('TabSlider Component', () => { const mockOptions = [ diff --git a/web/app/components/base/tab-slider/index.spec.tsx b/web/app/components/base/tab-slider/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tab-slider/index.spec.tsx rename to web/app/components/base/tab-slider/__tests__/index.spec.tsx index 373c984d59..51794a7087 100644 --- a/web/app/components/base/tab-slider/index.spec.tsx +++ b/web/app/components/base/tab-slider/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { cleanup, fireEvent, render, screen } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { useInstalledPluginList } from '@/service/use-plugins' -import TabSlider from './index' +import TabSlider from '../index' // Mock the service hook vi.mock('@/service/use-plugins', () => ({ diff --git a/web/app/components/base/tag-input/index.spec.tsx b/web/app/components/base/tag-input/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tag-input/index.spec.tsx rename to web/app/components/base/tag-input/__tests__/index.spec.tsx index 077f938570..b091d9cd03 100644 --- a/web/app/components/base/tag-input/index.spec.tsx +++ b/web/app/components/base/tag-input/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { ComponentProps } from 'react' import { createEvent, fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TagInput from './index' +import TagInput from '../index' const mockNotify = vi.fn() diff --git a/web/app/components/base/tag-management/filter.spec.tsx b/web/app/components/base/tag-management/__tests__/filter.spec.tsx similarity index 99% rename from web/app/components/base/tag-management/filter.spec.tsx rename to web/app/components/base/tag-management/__tests__/filter.spec.tsx index 0f5b4d9ac6..3cffac29b2 100644 --- a/web/app/components/base/tag-management/filter.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/filter.spec.tsx @@ -3,8 +3,8 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { act } from 'react' import * as React from 'react' -import TagFilter from './filter' -import { useStore as useTagStore } from './store' +import TagFilter from '../filter' +import { useStore as useTagStore } from '../store' const { fetchTagList } = vi.hoisted(() => ({ fetchTagList: vi.fn(), diff --git a/web/app/components/base/tag-management/index.spec.tsx b/web/app/components/base/tag-management/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tag-management/index.spec.tsx rename to web/app/components/base/tag-management/__tests__/index.spec.tsx index 846c23484b..5e01aeaf19 100644 --- a/web/app/components/base/tag-management/index.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/index.spec.tsx @@ -3,8 +3,8 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { act } from 'react' -import TagManagementModal from './index' -import { useStore as useTagStore } from './store' +import TagManagementModal from '../index' +import { useStore as useTagStore } from '../store' // Hoisted mocks const { fetchTagList, createTag } = vi.hoisted(() => ({ diff --git a/web/app/components/base/tag-management/panel.spec.tsx b/web/app/components/base/tag-management/__tests__/panel.spec.tsx similarity index 99% rename from web/app/components/base/tag-management/panel.spec.tsx rename to web/app/components/base/tag-management/__tests__/panel.spec.tsx index d3b3279c12..c91c72e583 100644 --- a/web/app/components/base/tag-management/panel.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/panel.spec.tsx @@ -4,8 +4,8 @@ import userEvent from '@testing-library/user-event' import * as React from 'react' import { act } from 'react' import { ToastContext } from '@/app/components/base/toast' -import Panel from './panel' -import { useStore as useTagStore } from './store' +import Panel from '../panel' +import { useStore as useTagStore } from '../store' // Hoisted mocks const { createTag, bindTag, unBindTag, contextOverrides } = vi.hoisted(() => ({ diff --git a/web/app/components/base/tag-management/selector.spec.tsx b/web/app/components/base/tag-management/__tests__/selector.spec.tsx similarity index 98% rename from web/app/components/base/tag-management/selector.spec.tsx rename to web/app/components/base/tag-management/__tests__/selector.spec.tsx index 6c66c83703..dc58ca37e6 100644 --- a/web/app/components/base/tag-management/selector.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/selector.spec.tsx @@ -4,8 +4,8 @@ import userEvent from '@testing-library/user-event' import * as React from 'react' import { act } from 'react' import { ToastContext } from '@/app/components/base/toast' -import TagSelector from './selector' -import { useStore as useTagStore } from './store' +import TagSelector from '../selector' +import { useStore as useTagStore } from '../store' // Hoisted mocks const { fetchTagList, createTag, bindTag, unBindTag } = vi.hoisted(() => ({ @@ -43,6 +43,7 @@ vi.mock('@/app/components/base/popover', () => { : btnClassName const content = React.isValidElement(htmlContent) + // eslint-disable-next-line react/no-clone-element ? React.cloneElement(htmlContent as React.ReactElement, { open: isOpen, onClose: () => setIsOpen(false), diff --git a/web/app/components/base/tag-management/tag-item-editor.spec.tsx b/web/app/components/base/tag-management/__tests__/tag-item-editor.spec.tsx similarity index 98% rename from web/app/components/base/tag-management/tag-item-editor.spec.tsx rename to web/app/components/base/tag-management/__tests__/tag-item-editor.spec.tsx index 5dfd90f283..3043f0327f 100644 --- a/web/app/components/base/tag-management/tag-item-editor.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/tag-item-editor.spec.tsx @@ -3,8 +3,8 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { act } from 'react' -import { useStore as useTagStore } from './store' -import TagItemEditor from './tag-item-editor' +import { useStore as useTagStore } from '../store' +import TagItemEditor from '../tag-item-editor' const { updateTag, deleteTag, mockNotify } = vi.hoisted(() => ({ updateTag: vi.fn(), diff --git a/web/app/components/base/tag-management/tag-remove-modal.spec.tsx b/web/app/components/base/tag-management/__tests__/tag-remove-modal.spec.tsx similarity index 97% rename from web/app/components/base/tag-management/tag-remove-modal.spec.tsx rename to web/app/components/base/tag-management/__tests__/tag-remove-modal.spec.tsx index 65e4879739..943b7bc8ff 100644 --- a/web/app/components/base/tag-management/tag-remove-modal.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/tag-remove-modal.spec.tsx @@ -1,7 +1,7 @@ -import type { Tag } from './constant' +import type { Tag } from '../constant' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import TagRemoveModal from './tag-remove-modal' +import TagRemoveModal from '../tag-remove-modal' const mockTag: Tag = { id: 'tag-1', diff --git a/web/app/components/base/tag-management/trigger.spec.tsx b/web/app/components/base/tag-management/__tests__/trigger.spec.tsx similarity index 98% rename from web/app/components/base/tag-management/trigger.spec.tsx rename to web/app/components/base/tag-management/__tests__/trigger.spec.tsx index d7787c503a..e188c4fed9 100644 --- a/web/app/components/base/tag-management/trigger.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/trigger.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import Trigger from './trigger' +import Trigger from '../trigger' describe('Trigger', () => { beforeEach(() => { diff --git a/web/app/components/base/tag/index.spec.tsx b/web/app/components/base/tag/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tag/index.spec.tsx rename to web/app/components/base/tag/__tests__/index.spec.tsx index 76d2915ba8..5fafa568b3 100644 --- a/web/app/components/base/tag/index.spec.tsx +++ b/web/app/components/base/tag/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' -import Tag from './index' +import Tag from '../index' import '@testing-library/jest-dom/vitest' describe('Tag Component', () => { diff --git a/web/app/components/base/text-generation/hooks.spec.ts b/web/app/components/base/text-generation/__tests__/hooks.spec.ts similarity index 99% rename from web/app/components/base/text-generation/hooks.spec.ts rename to web/app/components/base/text-generation/__tests__/hooks.spec.ts index f25dd3b945..cab06f1c8a 100644 --- a/web/app/components/base/text-generation/hooks.spec.ts +++ b/web/app/components/base/text-generation/__tests__/hooks.spec.ts @@ -1,6 +1,6 @@ import type { IOtherOptions } from '@/service/base' import { act, renderHook } from '@testing-library/react' -import { useTextGeneration } from './hooks' +import { useTextGeneration } from '../hooks' const mockNotify = vi.fn() const mockSsePost = vi.fn<(url: string, fetchOptions: { body: Record }, otherOptions: IOtherOptions) => void>() diff --git a/web/app/components/base/textarea/index.spec.tsx b/web/app/components/base/textarea/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/textarea/index.spec.tsx rename to web/app/components/base/textarea/__tests__/index.spec.tsx index 404785d2e4..7de2d7e0f9 100644 --- a/web/app/components/base/textarea/index.spec.tsx +++ b/web/app/components/base/textarea/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import TextArea from './index' +import TextArea from '../index' describe('TextArea', () => { it('should render correctly with default props', () => { diff --git a/web/app/components/base/timezone-label/index.spec.tsx b/web/app/components/base/timezone-label/__tests__/index.spec.tsx similarity index 97% rename from web/app/components/base/timezone-label/index.spec.tsx rename to web/app/components/base/timezone-label/__tests__/index.spec.tsx index c43aa61936..4beb72d165 100644 --- a/web/app/components/base/timezone-label/index.spec.tsx +++ b/web/app/components/base/timezone-label/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' -import TimezoneLabel from './index' +import TimezoneLabel from '../index' describe('TimezoneLabel', () => { it('should render correctly with various timezones', () => { diff --git a/web/app/components/base/toast/index.spec.tsx b/web/app/components/base/toast/__tests__/index.spec.tsx similarity index 98% rename from web/app/components/base/toast/index.spec.tsx rename to web/app/components/base/toast/__tests__/index.spec.tsx index cc5a1e7c6d..f526290fa1 100644 --- a/web/app/components/base/toast/index.spec.tsx +++ b/web/app/components/base/toast/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react' import { act, render, screen, waitFor } from '@testing-library/react' import { noop } from 'es-toolkit/function' import * as React from 'react' -import Toast, { ToastProvider, useToastContext } from '.' +import Toast, { ToastProvider, useToastContext } from '..' const TestComponent = () => { const { notify, close } = useToastContext() diff --git a/web/app/components/base/tooltip/content.spec.tsx b/web/app/components/base/tooltip/__tests__/content.spec.tsx similarity index 97% rename from web/app/components/base/tooltip/content.spec.tsx rename to web/app/components/base/tooltip/__tests__/content.spec.tsx index 314c773ce1..fa5d86756e 100644 --- a/web/app/components/base/tooltip/content.spec.tsx +++ b/web/app/components/base/tooltip/__tests__/content.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it, vi } from 'vitest' -import { ToolTipContent } from './content' +import { ToolTipContent } from '../content' describe('ToolTipContent', () => { it('should render children correctly', () => { diff --git a/web/app/components/base/tooltip/index.spec.tsx b/web/app/components/base/tooltip/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/tooltip/index.spec.tsx rename to web/app/components/base/tooltip/__tests__/index.spec.tsx index 66d3157ddc..7ee31b59c7 100644 --- a/web/app/components/base/tooltip/index.spec.tsx +++ b/web/app/components/base/tooltip/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' import * as React from 'react' -import Tooltip from './index' +import Tooltip from '../index' afterEach(cleanup) diff --git a/web/app/components/base/video-gallery/VideoPlayer.spec.tsx b/web/app/components/base/video-gallery/__tests__/VideoPlayer.spec.tsx similarity index 99% rename from web/app/components/base/video-gallery/VideoPlayer.spec.tsx rename to web/app/components/base/video-gallery/__tests__/VideoPlayer.spec.tsx index 04d9ccc4c8..3e1890c573 100644 --- a/web/app/components/base/video-gallery/VideoPlayer.spec.tsx +++ b/web/app/components/base/video-gallery/__tests__/VideoPlayer.spec.tsx @@ -1,7 +1,7 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' -import VideoPlayer from './VideoPlayer' +import VideoPlayer from '../VideoPlayer' describe('VideoPlayer', () => { const mockSrc = 'video.mp4' diff --git a/web/app/components/base/video-gallery/index.spec.tsx b/web/app/components/base/video-gallery/__tests__/index.spec.tsx similarity index 95% rename from web/app/components/base/video-gallery/index.spec.tsx rename to web/app/components/base/video-gallery/__tests__/index.spec.tsx index 717e57e1ff..d32f627c2c 100644 --- a/web/app/components/base/video-gallery/index.spec.tsx +++ b/web/app/components/base/video-gallery/__tests__/index.spec.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react' import { describe, expect, it } from 'vitest' -import VideoGallery from './index' +import VideoGallery from '../index' describe('VideoGallery', () => { const mockSrcs = ['video1.mp4', 'video2.mp4'] diff --git a/web/app/components/base/voice-input/index.spec.tsx b/web/app/components/base/voice-input/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/voice-input/index.spec.tsx rename to web/app/components/base/voice-input/__tests__/index.spec.tsx index fa32f0425f..8d7940fb08 100644 --- a/web/app/components/base/voice-input/index.spec.tsx +++ b/web/app/components/base/voice-input/__tests__/index.spec.tsx @@ -2,7 +2,7 @@ import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' import { audioToText } from '@/service/share' -import VoiceInput from './index' +import VoiceInput from '../index' const { mockState, MockRecorder } = vi.hoisted(() => { const state = { @@ -50,7 +50,7 @@ vi.mock('next/navigation', () => ({ usePathname: vi.fn(() => mockState.pathname), })) -vi.mock('./utils', () => ({ +vi.mock('../utils', () => ({ convertToMp3: vi.fn(() => new Blob(['test'], { type: 'audio/mp3' })), })) diff --git a/web/app/components/base/with-input-validation/index.spec.tsx b/web/app/components/base/with-input-validation/__tests__/index.spec.tsx similarity index 85% rename from web/app/components/base/with-input-validation/index.spec.tsx rename to web/app/components/base/with-input-validation/__tests__/index.spec.tsx index 3bfcbfc9e4..6c3337ba00 100644 --- a/web/app/components/base/with-input-validation/index.spec.tsx +++ b/web/app/components/base/with-input-validation/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react' import { noop } from 'es-toolkit/function' import * as z from 'zod' -import withValidation from '.' +import withValidation from '..' describe('withValidation HOC', () => { // schema for validation @@ -35,12 +35,12 @@ describe('withValidation HOC', () => { }) it('renders the component when props is invalid but not in schema ', () => { - render() + render() expect(screen.getByText('Valid Name - aaa')).toBeInTheDocument() }) it('does not render the component when validation fails', () => { - render() + render() expect(screen.queryByText('123 - 30')).toBeNull() }) }) diff --git a/web/app/components/base/zendesk/index.spec.tsx b/web/app/components/base/zendesk/__tests__/index.spec.tsx similarity index 99% rename from web/app/components/base/zendesk/index.spec.tsx rename to web/app/components/base/zendesk/__tests__/index.spec.tsx index abf0210f37..4ab84a0088 100644 --- a/web/app/components/base/zendesk/index.spec.tsx +++ b/web/app/components/base/zendesk/__tests__/index.spec.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react' import { render, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import Zendesk from './index' +import Zendesk from '../index' // Shared state for mocks let mockIsCeEdition = false From 2dc9bc00d67b3c0720470a59db84054d80eac50c Mon Sep 17 00:00:00 2001 From: Stable Genius Date: Sun, 1 Mar 2026 20:58:13 -0800 Subject: [PATCH 004/159] refactor(ci): use diff -u for pyrefly diff output (#32813) Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com> --- .github/workflows/pyrefly-diff.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyrefly-diff.yml b/.github/workflows/pyrefly-diff.yml index 1900232dce..14338e85b3 100644 --- a/.github/workflows/pyrefly-diff.yml +++ b/.github/workflows/pyrefly-diff.yml @@ -48,7 +48,7 @@ jobs: - name: Compute diff run: | - diff /tmp/pyrefly_base.txt /tmp/pyrefly_pr.txt > pyrefly_diff.txt || true + diff -u /tmp/pyrefly_base.txt /tmp/pyrefly_pr.txt > pyrefly_diff.txt || true - name: Save PR number run: | From ddc47c2f39957f8f4636e04b505f08836c8989a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:59:06 +0900 Subject: [PATCH 005/159] chore(deps): update pyjwt requirement from ~=2.10.1 to ~=2.11.0 in /api (#32804) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/pyproject.toml | 2 +- api/uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index 265addd745..a7069bff60 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -68,7 +68,7 @@ dependencies = [ "pydantic~=2.12.5", "pydantic-extra-types~=2.10.3", "pydantic-settings~=2.12.0", - "pyjwt~=2.10.1", + "pyjwt~=2.11.0", "pypdfium2==5.2.0", "python-docx~=1.2.0", "python-dotenv==1.0.1", diff --git a/api/uv.lock b/api/uv.lock index 4b18997367..46fb881001 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -1636,7 +1636,7 @@ requires-dist = [ { name = "pydantic", specifier = "~=2.12.5" }, { name = "pydantic-extra-types", specifier = "~=2.10.3" }, { name = "pydantic-settings", specifier = "~=2.12.0" }, - { name = "pyjwt", specifier = "~=2.10.1" }, + { name = "pyjwt", specifier = "~=2.11.0" }, { name = "pypdfium2", specifier = "==5.2.0" }, { name = "python-docx", specifier = "~=1.2.0" }, { name = "python-dotenv", specifier = "==1.0.1" }, @@ -4957,11 +4957,11 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.11.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, + { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, ] [package.optional-dependencies] From aca3d1900e5b9d6b79bd3e3b7aef383959ee2886 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:59:53 +0900 Subject: [PATCH 006/159] chore(deps-dev): update types-aiofiles requirement from ~=24.1.0 to ~=25.1.0 in /api (#32803) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/pyproject.toml | 2 +- api/uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index a7069bff60..f5e43f3ed1 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -124,7 +124,7 @@ dev = [ "pytest-env~=1.1.3", "pytest-mock~=3.14.0", "testcontainers~=4.13.2", - "types-aiofiles~=24.1.0", + "types-aiofiles~=25.1.0", "types-beautifulsoup4~=4.12.0", "types-cachetools~=5.5.0", "types-colorama~=0.4.15", diff --git a/api/uv.lock b/api/uv.lock index 46fb881001..b9f660ce71 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -1683,7 +1683,7 @@ dev = [ { name = "scipy-stubs", specifier = ">=1.15.3.0" }, { name = "sseclient-py", specifier = ">=1.8.0" }, { name = "testcontainers", specifier = "~=4.13.2" }, - { name = "types-aiofiles", specifier = "~=24.1.0" }, + { name = "types-aiofiles", specifier = "~=25.1.0" }, { name = "types-beautifulsoup4", specifier = "~=4.12.0" }, { name = "types-cachetools", specifier = "~=5.5.0" }, { name = "types-cffi", specifier = ">=1.17.0" }, @@ -6293,11 +6293,11 @@ wheels = [ [[package]] name = "types-aiofiles" -version = "24.1.0.20250822" +version = "25.1.0.20251011" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/48/c64471adac9206cc844afb33ed311ac5a65d2f59df3d861e0f2d0cad7414/types_aiofiles-24.1.0.20250822.tar.gz", hash = "sha256:9ab90d8e0c307fe97a7cf09338301e3f01a163e39f3b529ace82466355c84a7b", size = 14484, upload-time = "2025-08-22T03:02:23.039Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/6c/6d23908a8217e36704aa9c79d99a620f2fdd388b66a4b7f72fbc6b6ff6c6/types_aiofiles-25.1.0.20251011.tar.gz", hash = "sha256:1c2b8ab260cb3cd40c15f9d10efdc05a6e1e6b02899304d80dfa0410e028d3ff", size = 14535, upload-time = "2025-10-11T02:44:51.237Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/8e/5e6d2215e1d8f7c2a94c6e9d0059ae8109ce0f5681956d11bb0a228cef04/types_aiofiles-24.1.0.20250822-py3-none-any.whl", hash = "sha256:0ec8f8909e1a85a5a79aed0573af7901f53120dd2a29771dd0b3ef48e12328b0", size = 14322, upload-time = "2025-08-22T03:02:21.918Z" }, + { url = "https://files.pythonhosted.org/packages/71/0f/76917bab27e270bb6c32addd5968d69e558e5b6f7fb4ac4cbfa282996a96/types_aiofiles-25.1.0.20251011-py3-none-any.whl", hash = "sha256:8ff8de7f9d42739d8f0dadcceeb781ce27cd8d8c4152d4a7c52f6b20edb8149c", size = 14338, upload-time = "2025-10-11T02:44:50.054Z" }, ] [[package]] From cc127f5b6242598c285a9ca6f5be65a860764036 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Mon, 2 Mar 2026 14:05:04 +0800 Subject: [PATCH 007/159] fix: fix chat assistant response mode blocking is not work (#32394) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../easy_ui_based_generate_task_pipeline.py | 8 +-- api/services/app_generate_service.py | 69 ++++++++++++------- .../services/test_app_generate_service.py | 53 ++++++++++++++ 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index 8792e65512..a77e5abb30 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -157,7 +157,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): id=self._message_id, mode=self._conversation_mode, message_id=self._message_id, - answer=cast(str, self._task_state.llm_result.message.content), + answer=self._task_state.llm_result.message.get_text_content(), created_at=self._message_created_at, **extras, ), @@ -170,7 +170,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): mode=self._conversation_mode, conversation_id=self._conversation_id, message_id=self._message_id, - answer=cast(str, self._task_state.llm_result.message.content), + answer=self._task_state.llm_result.message.get_text_content(), created_at=self._message_created_at, **extras, ), @@ -283,7 +283,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): # handle output moderation output_moderation_answer = self.handle_output_moderation_when_task_finished( - cast(str, self._task_state.llm_result.message.content) + self._task_state.llm_result.message.get_text_content() ) if output_moderation_answer: self._task_state.llm_result.message.content = output_moderation_answer @@ -397,7 +397,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): message.message_unit_price = usage.prompt_unit_price message.message_price_unit = usage.prompt_price_unit message.answer = ( - PromptTemplateParser.remove_template_variables(cast(str, llm_result.message.content).strip()) + PromptTemplateParser.remove_template_variables(llm_result.message.get_text_content().strip()) if llm_result.message.content else "" ) diff --git a/api/services/app_generate_service.py b/api/services/app_generate_service.py index 0c27c403f8..31003cb8f7 100644 --- a/api/services/app_generate_service.py +++ b/api/services/app_generate_service.py @@ -131,33 +131,54 @@ class AppGenerateService: elif app_model.mode == AppMode.ADVANCED_CHAT: workflow_id = args.get("workflow_id") workflow = cls._get_workflow(app_model, invoke_from, workflow_id) - with rate_limit_context(rate_limit, request_id): - payload = AppExecutionParams.new( - app_model=app_model, - workflow=workflow, - user=user, - args=args, - invoke_from=invoke_from, - streaming=streaming, - call_depth=0, - ) - payload_json = payload.model_dump_json() - def on_subscribe(): - workflow_based_app_execution_task.delay(payload_json) + if streaming: + # Streaming mode: subscribe to SSE and enqueue the execution on first subscriber + with rate_limit_context(rate_limit, request_id): + payload = AppExecutionParams.new( + app_model=app_model, + workflow=workflow, + user=user, + args=args, + invoke_from=invoke_from, + streaming=True, + call_depth=0, + ) + payload_json = payload.model_dump_json() - on_subscribe = cls._build_streaming_task_on_subscribe(on_subscribe) - generator = AdvancedChatAppGenerator() - return rate_limit.generate( - generator.convert_to_event_stream( - generator.retrieve_events( - AppMode.ADVANCED_CHAT, - payload.workflow_run_id, - on_subscribe=on_subscribe, + def on_subscribe(): + workflow_based_app_execution_task.delay(payload_json) + + on_subscribe = cls._build_streaming_task_on_subscribe(on_subscribe) + generator = AdvancedChatAppGenerator() + return rate_limit.generate( + generator.convert_to_event_stream( + generator.retrieve_events( + AppMode.ADVANCED_CHAT, + payload.workflow_run_id, + on_subscribe=on_subscribe, + ), ), - ), - request_id=request_id, - ) + request_id=request_id, + ) + else: + # Blocking mode: run synchronously and return JSON instead of SSE + # Keep behaviour consistent with WORKFLOW blocking branch. + advanced_generator = AdvancedChatAppGenerator() + return rate_limit.generate( + advanced_generator.convert_to_event_stream( + advanced_generator.generate( + app_model=app_model, + workflow=workflow, + user=user, + args=args, + invoke_from=invoke_from, + workflow_run_id=str(uuid.uuid4()), + streaming=False, + ) + ), + request_id=request_id, + ) elif app_model.mode == AppMode.WORKFLOW: workflow_id = args.get("workflow_id") workflow = cls._get_workflow(app_model, invoke_from, workflow_id) diff --git a/api/tests/unit_tests/services/test_app_generate_service.py b/api/tests/unit_tests/services/test_app_generate_service.py index 71134464e6..47b759bc7d 100644 --- a/api/tests/unit_tests/services/test_app_generate_service.py +++ b/api/tests/unit_tests/services/test_app_generate_service.py @@ -63,3 +63,56 @@ def test_workflow_blocking_injects_pause_state_config(mocker, monkeypatch): pause_state_config = call_kwargs.get("pause_state_config") assert pause_state_config is not None assert pause_state_config.state_owner_user_id == "owner-id" + + +def test_advanced_chat_blocking_returns_dict_and_does_not_use_event_retrieval(mocker, monkeypatch): + """ + Regression test: ADVANCED_CHAT in blocking mode should return a plain dict + (non-streaming), and must not go through the async retrieve_events path. + Keeps behavior consistent with WORKFLOW blocking branch. + """ + # Disable billing and stub RateLimit to a no-op that just passes values through + monkeypatch.setattr(app_generate_service_module.dify_config, "BILLING_ENABLED", False) + mocker.patch("services.app_generate_service.RateLimit", _DummyRateLimit) + + # Arrange a fake workflow and wire AppGenerateService._get_workflow to return it + workflow = MagicMock() + workflow.id = "workflow-id" + mocker.patch.object(AppGenerateService, "_get_workflow", return_value=workflow) + + # Spy on the streaming retrieval path to ensure it's NOT called + retrieve_spy = mocker.patch("services.app_generate_service.AdvancedChatAppGenerator.retrieve_events") + + # Make AdvancedChatAppGenerator.generate return a plain dict when streaming=False + generate_spy = mocker.patch( + "services.app_generate_service.AdvancedChatAppGenerator.generate", + return_value={"result": "ok"}, + ) + + # Minimal app model for ADVANCED_CHAT + app_model = MagicMock() + app_model.mode = AppMode.ADVANCED_CHAT + app_model.id = "app-id" + app_model.tenant_id = "tenant-id" + app_model.max_active_requests = 0 + app_model.is_agent = False + + user = MagicMock() + user.id = "user-id" + + # Must include query and inputs for AdvancedChatAppGenerator + args = {"workflow_id": "wf-1", "query": "hello", "inputs": {}} + + # Act: call service with streaming=False (blocking mode) + result = AppGenerateService.generate( + app_model=app_model, + user=user, + args=args, + invoke_from=MagicMock(), + streaming=False, + ) + + # Assert: returns the dict from generate(), and did not call retrieve_events() + assert result == {"result": "ok"} + assert generate_spy.call_args.kwargs.get("streaming") is False + retrieve_spy.assert_not_called() From 8af110a87e22bdac7d715dce3383df37985975f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=B5=E3=82=8B=E3=81=84?= <46769295+Echo0ff@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:28:12 +0800 Subject: [PATCH 008/159] refactor: use unified diff format in pyrefly-diff workflow (#32828) From 42a8d962a0f68b2b253cbd702664587d3f97eab4 Mon Sep 17 00:00:00 2001 From: Stable Genius Date: Sun, 1 Mar 2026 22:31:29 -0800 Subject: [PATCH 009/159] refactor: remove tests and core/rag from pyrefly excludes (#32801) Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com> --- api/pyrefly.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/pyrefly.toml b/api/pyrefly.toml index 80ffba019d..01f4c5a529 100644 --- a/api/pyrefly.toml +++ b/api/pyrefly.toml @@ -1,9 +1,7 @@ project-includes = ["."] project-excludes = [ - "tests/", ".venv", "migrations/", - "core/rag", ] python-platform = "linux" python-version = "3.11.0" From 9ddbc1c0fb22dfb4264e47b0a86f05b9dc068e8d Mon Sep 17 00:00:00 2001 From: Varun Chawla <34209028+veeceey@users.noreply.github.com> Date: Sun, 1 Mar 2026 22:54:26 -0800 Subject: [PATCH 010/159] fix: map all NodeType values to span kinds in Arize Phoenix tracing (#32059) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Crazywoola <100913391+crazywoola@users.noreply.github.com> --- .../arize_phoenix_trace.py | 29 ++++++++++----- .../core/ops/test_arize_phoenix_trace.py | 36 +++++++++++++++++++ 2 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py diff --git a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py index a7b73e032e..452255f69e 100644 --- a/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py +++ b/api/core/ops/arize_phoenix_trace/arize_phoenix_trace.py @@ -155,6 +155,26 @@ def wrap_span_metadata(metadata, **kwargs): return metadata +# Mapping from NodeType string values to OpenInference span kinds. +# NodeType values not listed here default to CHAIN. +_NODE_TYPE_TO_SPAN_KIND: dict[str, OpenInferenceSpanKindValues] = { + "llm": OpenInferenceSpanKindValues.LLM, + "knowledge-retrieval": OpenInferenceSpanKindValues.RETRIEVER, + "tool": OpenInferenceSpanKindValues.TOOL, + "agent": OpenInferenceSpanKindValues.AGENT, +} + + +def _get_node_span_kind(node_type: str) -> OpenInferenceSpanKindValues: + """Return the OpenInference span kind for a given workflow node type. + + Covers every ``NodeType`` enum value. Nodes that do not have a + specialised span kind (e.g. ``start``, ``end``, ``if-else``, + ``code``, ``loop``, ``iteration``, etc.) are mapped to ``CHAIN``. + """ + return _NODE_TYPE_TO_SPAN_KIND.get(node_type, OpenInferenceSpanKindValues.CHAIN) + + class ArizePhoenixDataTrace(BaseTraceInstance): def __init__( self, @@ -289,9 +309,8 @@ class ArizePhoenixDataTrace(BaseTraceInstance): ) # Determine the correct span kind based on node type - span_kind = OpenInferenceSpanKindValues.CHAIN + span_kind = _get_node_span_kind(node_execution.node_type) if node_execution.node_type == "llm": - span_kind = OpenInferenceSpanKindValues.LLM provider = process_data.get("model_provider") model = process_data.get("model_name") if provider: @@ -306,12 +325,6 @@ class ArizePhoenixDataTrace(BaseTraceInstance): node_metadata["total_tokens"] = usage_data.get("total_tokens", 0) node_metadata["prompt_tokens"] = usage_data.get("prompt_tokens", 0) node_metadata["completion_tokens"] = usage_data.get("completion_tokens", 0) - elif node_execution.node_type == "dataset_retrieval": - span_kind = OpenInferenceSpanKindValues.RETRIEVER - elif node_execution.node_type == "tool": - span_kind = OpenInferenceSpanKindValues.TOOL - else: - span_kind = OpenInferenceSpanKindValues.CHAIN workflow_span_context = set_span_in_context(workflow_span) node_span = self.tracer.start_span( diff --git a/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py b/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py new file mode 100644 index 0000000000..4f398ce66e --- /dev/null +++ b/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py @@ -0,0 +1,36 @@ +from openinference.semconv.trace import OpenInferenceSpanKindValues + +from core.ops.arize_phoenix_trace.arize_phoenix_trace import _NODE_TYPE_TO_SPAN_KIND, _get_node_span_kind +from core.workflow.enums import NodeType + + +class TestGetNodeSpanKind: + """Tests for _get_node_span_kind helper.""" + + def test_all_node_types_are_mapped_correctly(self): + """Ensure every NodeType enum member is mapped to the correct span kind.""" + # Mappings for node types that have a specialised span kind. + special_mappings = { + NodeType.LLM: OpenInferenceSpanKindValues.LLM, + NodeType.KNOWLEDGE_RETRIEVAL: OpenInferenceSpanKindValues.RETRIEVER, + NodeType.TOOL: OpenInferenceSpanKindValues.TOOL, + NodeType.AGENT: OpenInferenceSpanKindValues.AGENT, + } + + # Test that every NodeType enum member is mapped to the correct span kind. + # Node types not in `special_mappings` should default to CHAIN. + for node_type in NodeType: + expected_span_kind = special_mappings.get(node_type, OpenInferenceSpanKindValues.CHAIN) + actual_span_kind = _get_node_span_kind(node_type) + assert actual_span_kind == expected_span_kind, ( + f"NodeType.{node_type.name} was mapped to {actual_span_kind}, but {expected_span_kind} was expected." + ) + + def test_unknown_string_defaults_to_chain(self): + """An unrecognised node type string should still return CHAIN.""" + assert _get_node_span_kind("some-future-node-type") == OpenInferenceSpanKindValues.CHAIN + + def test_stale_dataset_retrieval_not_in_mapping(self): + """The old 'dataset_retrieval' string was never a valid NodeType value; + make sure it is not present in the mapping dictionary.""" + assert "dataset_retrieval" not in _NODE_TYPE_TO_SPAN_KIND From 8a7ba8734946ae359df6d30cf60e1e853effcf22 Mon Sep 17 00:00:00 2001 From: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Date: Sun, 1 Mar 2026 23:03:37 -0800 Subject: [PATCH 011/159] fix: upgrade OpenTelemetry to 0.49b0 to fix context detach error (#32825) --- api/pyproject.toml | 49 ++++--- api/uv.lock | 322 +++++++++++++++++++++++---------------------- 2 files changed, 186 insertions(+), 185 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index f5e43f3ed1..f544cd27b2 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -22,14 +22,14 @@ dependencies = [ "flask-sqlalchemy~=3.1.1", "gevent~=25.9.1", "gmpy2~=2.3.0", - "google-api-core==2.18.0", + "google-api-core>=2.19.1", "google-api-python-client==2.189.0", - "google-auth==2.29.0", + "google-auth>=2.47.0", "google-auth-httplib2==0.2.0", - "google-cloud-aiplatform==1.49.0", - "googleapis-common-protos==1.63.0", + "google-cloud-aiplatform>=1.123.0", + "googleapis-common-protos>=1.65.0", "gunicorn~=23.0.0", - "httpx[socks]~=0.27.0", + "httpx[socks]~=0.28.0", "jieba==0.42.1", "json-repair>=0.55.1", "jsonschema>=4.25.1", @@ -41,26 +41,23 @@ dependencies = [ "openpyxl~=3.1.5", "opik~=1.8.72", "litellm==1.77.1", # Pinned to avoid madoka dependency issue - "opentelemetry-api==1.27.0", - "opentelemetry-distro==0.48b0", - "opentelemetry-exporter-otlp==1.27.0", - "opentelemetry-exporter-otlp-proto-common==1.27.0", - "opentelemetry-exporter-otlp-proto-grpc==1.27.0", - "opentelemetry-exporter-otlp-proto-http==1.27.0", - "opentelemetry-instrumentation==0.48b0", - "opentelemetry-instrumentation-celery==0.48b0", - "opentelemetry-instrumentation-flask==0.48b0", - "opentelemetry-instrumentation-httpx==0.48b0", - "opentelemetry-instrumentation-redis==0.48b0", - "opentelemetry-instrumentation-httpx==0.48b0", - "opentelemetry-instrumentation-sqlalchemy==0.48b0", - "opentelemetry-propagator-b3==1.27.0", - # opentelemetry-proto1.28.0 depends on protobuf (>=5.0,<6.0), - # which is conflict with googleapis-common-protos (1.63.0) - "opentelemetry-proto==1.27.0", - "opentelemetry-sdk==1.27.0", - "opentelemetry-semantic-conventions==0.48b0", - "opentelemetry-util-http==0.48b0", + "opentelemetry-api==1.28.0", + "opentelemetry-distro==0.49b0", + "opentelemetry-exporter-otlp==1.28.0", + "opentelemetry-exporter-otlp-proto-common==1.28.0", + "opentelemetry-exporter-otlp-proto-grpc==1.28.0", + "opentelemetry-exporter-otlp-proto-http==1.28.0", + "opentelemetry-instrumentation==0.49b0", + "opentelemetry-instrumentation-celery==0.49b0", + "opentelemetry-instrumentation-flask==0.49b0", + "opentelemetry-instrumentation-httpx==0.49b0", + "opentelemetry-instrumentation-redis==0.49b0", + "opentelemetry-instrumentation-sqlalchemy==0.49b0", + "opentelemetry-propagator-b3==1.28.0", + "opentelemetry-proto==1.28.0", + "opentelemetry-sdk==1.28.0", + "opentelemetry-semantic-conventions==0.49b0", + "opentelemetry-util-http==0.49b0", "pandas[excel,output-formatting,performance]~=2.2.2", "psycogreen~=1.0.2", "psycopg2-binary~=2.9.6", @@ -187,7 +184,7 @@ storage = [ "bce-python-sdk~=0.9.23", "cos-python-sdk-v5==1.9.38", "esdk-obs-python==3.25.8", - "google-cloud-storage==2.16.0", + "google-cloud-storage>=3.0.0", "opendal~=0.46.0", "oss2==2.18.5", "supabase~=2.18.1", diff --git a/api/uv.lock b/api/uv.lock index b9f660ce71..0121cbaab0 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -1591,14 +1591,14 @@ requires-dist = [ { name = "flask-sqlalchemy", specifier = "~=3.1.1" }, { name = "gevent", specifier = "~=25.9.1" }, { name = "gmpy2", specifier = "~=2.3.0" }, - { name = "google-api-core", specifier = "==2.18.0" }, + { name = "google-api-core", specifier = ">=2.19.1" }, { name = "google-api-python-client", specifier = "==2.189.0" }, - { name = "google-auth", specifier = "==2.29.0" }, + { name = "google-auth", specifier = ">=2.47.0" }, { name = "google-auth-httplib2", specifier = "==0.2.0" }, - { name = "google-cloud-aiplatform", specifier = "==1.49.0" }, - { name = "googleapis-common-protos", specifier = "==1.63.0" }, + { name = "google-cloud-aiplatform", specifier = ">=1.123.0" }, + { name = "googleapis-common-protos", specifier = ">=1.65.0" }, { name = "gunicorn", specifier = "~=23.0.0" }, - { name = "httpx", extras = ["socks"], specifier = "~=0.27.0" }, + { name = "httpx", extras = ["socks"], specifier = "~=0.28.0" }, { name = "httpx-sse", specifier = "~=0.4.0" }, { name = "jieba", specifier = "==0.42.1" }, { name = "json-repair", specifier = ">=0.55.1" }, @@ -1610,23 +1610,23 @@ requires-dist = [ { name = "mlflow-skinny", specifier = ">=3.0.0" }, { name = "numpy", specifier = "~=1.26.4" }, { name = "openpyxl", specifier = "~=3.1.5" }, - { name = "opentelemetry-api", specifier = "==1.27.0" }, - { name = "opentelemetry-distro", specifier = "==0.48b0" }, - { name = "opentelemetry-exporter-otlp", specifier = "==1.27.0" }, - { name = "opentelemetry-exporter-otlp-proto-common", specifier = "==1.27.0" }, - { name = "opentelemetry-exporter-otlp-proto-grpc", specifier = "==1.27.0" }, - { name = "opentelemetry-exporter-otlp-proto-http", specifier = "==1.27.0" }, - { name = "opentelemetry-instrumentation", specifier = "==0.48b0" }, - { name = "opentelemetry-instrumentation-celery", specifier = "==0.48b0" }, - { name = "opentelemetry-instrumentation-flask", specifier = "==0.48b0" }, - { name = "opentelemetry-instrumentation-httpx", specifier = "==0.48b0" }, - { name = "opentelemetry-instrumentation-redis", specifier = "==0.48b0" }, - { name = "opentelemetry-instrumentation-sqlalchemy", specifier = "==0.48b0" }, - { name = "opentelemetry-propagator-b3", specifier = "==1.27.0" }, - { name = "opentelemetry-proto", specifier = "==1.27.0" }, - { name = "opentelemetry-sdk", specifier = "==1.27.0" }, - { name = "opentelemetry-semantic-conventions", specifier = "==0.48b0" }, - { name = "opentelemetry-util-http", specifier = "==0.48b0" }, + { name = "opentelemetry-api", specifier = "==1.28.0" }, + { name = "opentelemetry-distro", specifier = "==0.49b0" }, + { name = "opentelemetry-exporter-otlp", specifier = "==1.28.0" }, + { name = "opentelemetry-exporter-otlp-proto-common", specifier = "==1.28.0" }, + { name = "opentelemetry-exporter-otlp-proto-grpc", specifier = "==1.28.0" }, + { name = "opentelemetry-exporter-otlp-proto-http", specifier = "==1.28.0" }, + { name = "opentelemetry-instrumentation", specifier = "==0.49b0" }, + { name = "opentelemetry-instrumentation-celery", specifier = "==0.49b0" }, + { name = "opentelemetry-instrumentation-flask", specifier = "==0.49b0" }, + { name = "opentelemetry-instrumentation-httpx", specifier = "==0.49b0" }, + { name = "opentelemetry-instrumentation-redis", specifier = "==0.49b0" }, + { name = "opentelemetry-instrumentation-sqlalchemy", specifier = "==0.49b0" }, + { name = "opentelemetry-propagator-b3", specifier = "==1.28.0" }, + { name = "opentelemetry-proto", specifier = "==1.28.0" }, + { name = "opentelemetry-sdk", specifier = "==1.28.0" }, + { name = "opentelemetry-semantic-conventions", specifier = "==0.49b0" }, + { name = "opentelemetry-util-http", specifier = "==0.49b0" }, { name = "opik", specifier = "~=1.8.72" }, { name = "packaging", specifier = "~=23.2" }, { name = "pandas", extras = ["excel", "output-formatting", "performance"], specifier = "~=2.2.2" }, @@ -1729,7 +1729,7 @@ storage = [ { name = "bce-python-sdk", specifier = "~=0.9.23" }, { name = "cos-python-sdk-v5", specifier = "==1.9.38" }, { name = "esdk-obs-python", specifier = "==3.25.8" }, - { name = "google-cloud-storage", specifier = "==2.16.0" }, + { name = "google-cloud-storage", specifier = ">=3.0.0" }, { name = "opendal", specifier = "~=0.46.0" }, { name = "oss2", specifier = "==2.18.5" }, { name = "supabase", specifier = "~=2.18.1" }, @@ -2294,7 +2294,7 @@ wheels = [ [[package]] name = "google-api-core" -version = "2.18.0" +version = "2.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-auth" }, @@ -2303,9 +2303,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/8f/ecd68579bd2bf5e9321df60dcdee6e575adf77fedacb1d8378760b2b16b6/google-api-core-2.18.0.tar.gz", hash = "sha256:62d97417bfc674d6cef251e5c4d639a9655e00c45528c4364fbfebb478ce72a9", size = 148047, upload-time = "2024-03-21T20:16:56.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959, upload-time = "2026-02-18T20:28:11.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/75/59a3ad90d9b4ff5b3e0537611dbe885aeb96124521c9d35aa079f1e0f2c9/google_api_core-2.18.0-py3-none-any.whl", hash = "sha256:5a63aa102e0049abe85b5b88cb9409234c1f70afcda21ce1e40b285b9629c1d6", size = 138293, upload-time = "2024-03-21T20:16:53.645Z" }, + { url = "https://files.pythonhosted.org/packages/45/27/09c33d67f7e0dcf06d7ac17d196594e66989299374bfb0d4331d1038e76b/google_api_core-2.30.0-py3-none-any.whl", hash = "sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5", size = 173288, upload-time = "2026-02-18T20:28:10.367Z" }, ] [package.optional-dependencies] @@ -2332,16 +2332,21 @@ wheels = [ [[package]] name = "google-auth" -version = "2.29.0" +version = "2.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cachetools" }, + { name = "cryptography" }, { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/b2/f14129111cfd61793609643a07ecb03651a71dd65c6974f63b0310ff4b45/google-auth-2.29.0.tar.gz", hash = "sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360", size = 244326, upload-time = "2024-03-20T17:24:27.72Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/41/242044323fbd746615884b1c16639749e73665b718209946ebad7ba8a813/google_auth-2.48.0.tar.gz", hash = "sha256:4f7e706b0cd3208a3d940a19a822c37a476ddba5450156c3e6624a71f7c841ce", size = 326522, upload-time = "2026-01-26T19:22:47.157Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/8d/ddbcf81ec751d8ee5fd18ac11ff38a0e110f39dfbf105e6d9db69d556dd0/google_auth-2.29.0-py2.py3-none-any.whl", hash = "sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415", size = 189186, upload-time = "2024-03-20T17:24:24.292Z" }, + { url = "https://files.pythonhosted.org/packages/83/1d/d6466de3a5249d35e832a52834115ca9d1d0de6abc22065f049707516d47/google_auth-2.48.0-py3-none-any.whl", hash = "sha256:2e2a537873d449434252a9632c28bfc268b0adb1e53f9fb62afc5333a975903f", size = 236499, upload-time = "2026-01-26T19:22:45.099Z" }, +] + +[package.optional-dependencies] +requests = [ + { name = "requests" }, ] [[package]] @@ -2359,7 +2364,7 @@ wheels = [ [[package]] name = "google-cloud-aiplatform" -version = "1.49.0" +version = "1.139.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docstring-parser" }, @@ -2368,15 +2373,16 @@ dependencies = [ { name = "google-cloud-bigquery" }, { name = "google-cloud-resource-manager" }, { name = "google-cloud-storage" }, + { name = "google-genai" }, { name = "packaging" }, { name = "proto-plus" }, { name = "protobuf" }, { name = "pydantic" }, - { name = "shapely" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/47/21/5930a1420f82bec246ae09e1b7cc8458544f3befe669193b33a7b5c0691c/google-cloud-aiplatform-1.49.0.tar.gz", hash = "sha256:e6e6d01079bb5def49e4be4db4d12b13c624b5c661079c869c13c855e5807429", size = 5766450, upload-time = "2024-04-29T17:25:31.646Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/40/6767bd4d694354fd55842990da66f7b6ccfdce283d10f65d4a82d9a8e8df/google_cloud_aiplatform-1.139.0.tar.gz", hash = "sha256:cfaa95375bfb79a97b8c949c3ec1600505a4a9c08ca2b01c36ed659a5e05e37c", size = 9964138, upload-time = "2026-02-25T00:51:06.976Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/6a/7d9e1c03c814e760361fe8b0ffd373ead4124ace66ed33bb16d526ae1ecf/google_cloud_aiplatform-1.49.0-py2.py3-none-any.whl", hash = "sha256:8072d9e0c18d8942c704233d1a93b8d6312fc7b278786a283247950e28ae98df", size = 4914049, upload-time = "2024-04-29T17:25:27.625Z" }, + { url = "https://files.pythonhosted.org/packages/1d/20/a8a77dfdbf2a8169a3cce2d4e9cfbbfc168454ddd435891e59908ea8bf33/google_cloud_aiplatform-1.139.0-py2.py3-none-any.whl", hash = "sha256:3190b255cf510bce9e4b1adc8162ab0b3f9eca48801657d7af058d8e1d5ad9d0", size = 8209776, upload-time = "2026-02-25T00:51:03.526Z" }, ] [[package]] @@ -2429,7 +2435,7 @@ wheels = [ [[package]] name = "google-cloud-storage" -version = "2.16.0" +version = "3.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, @@ -2439,9 +2445,9 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/c5/0bc3f97cf4c14a731ecc5a95c5cde6883aec7289dc74817f9b41f866f77e/google-cloud-storage-2.16.0.tar.gz", hash = "sha256:dda485fa503710a828d01246bd16ce9db0823dc51bbca742ce96a6817d58669f", size = 5525307, upload-time = "2024-03-18T23:55:37.102Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/b1/4f0798e88285b50dfc60ed3a7de071def538b358db2da468c2e0deecbb40/google_cloud_storage-3.9.0.tar.gz", hash = "sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc", size = 17298544, upload-time = "2026-02-02T13:36:34.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/e5/7d045d188f4ef85d94b9e3ae1bf876170c6b9f4c9a950124978efc36f680/google_cloud_storage-2.16.0-py2.py3-none-any.whl", hash = "sha256:91a06b96fb79cf9cdfb4e759f178ce11ea885c79938f89590344d079305f5852", size = 125604, upload-time = "2024-03-18T23:55:33.987Z" }, + { url = "https://files.pythonhosted.org/packages/46/0b/816a6ae3c9fd096937d2e5f9670558908811d57d59ddf69dd4b83b326fd1/google_cloud_storage-3.9.0-py3-none-any.whl", hash = "sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066", size = 321324, upload-time = "2026-02-02T13:36:32.271Z" }, ] [[package]] @@ -2464,6 +2470,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/3c/2a19a60a473de48717b4efb19398c3f914795b64a96cf3fbe82588044f78/google_crc32c-1.7.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6efb97eb4369d52593ad6f75e7e10d053cf00c48983f7a973105bc70b0ac4d82", size = 28048, upload-time = "2025-03-26T14:41:46.696Z" }, ] +[[package]] +name = "google-genai" +version = "1.65.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "google-auth", extra = ["requests"] }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "sniffio" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/f9/cc1191c2540d6a4e24609a586c4ed45d2db57cfef47931c139ee70e5874a/google_genai-1.65.0.tar.gz", hash = "sha256:d470eb600af802d58a79c7f13342d9ea0d05d965007cae8f76c7adff3d7a4750", size = 497206, upload-time = "2026-02-26T00:20:33.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/3c/3fea4e7c91357c71782d7dcaad7a2577d636c90317e003386893c25bc62c/google_genai-1.65.0-py3-none-any.whl", hash = "sha256:68c025205856919bc03edb0155c11b4b833810b7ce17ad4b7a9eeba5158f6c44", size = 724429, upload-time = "2026-02-26T00:20:32.186Z" }, +] + [[package]] name = "google-resumable-media" version = "2.8.0" @@ -2478,14 +2505,14 @@ wheels = [ [[package]] name = "googleapis-common-protos" -version = "1.63.0" +version = "1.72.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d2/dc/291cebf3c73e108ef8210f19cb83d671691354f4f7dd956445560d778715/googleapis-common-protos-1.63.0.tar.gz", hash = "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e", size = 121646, upload-time = "2024-03-11T12:33:15.765Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/a6/12a0c976140511d8bc8a16ad15793b2aef29ac927baa0786ccb7ddbb6e1c/googleapis_common_protos-1.63.0-py2.py3-none-any.whl", hash = "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632", size = 229141, upload-time = "2024-03-11T12:33:14.052Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, ] [package.optional-dependencies] @@ -2675,31 +2702,35 @@ wheels = [ [[package]] name = "grpcio-tools" -version = "1.62.3" +version = "1.71.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, { name = "protobuf" }, { name = "setuptools" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/fa/b69bd8040eafc09b88bb0ec0fea59e8aacd1a801e688af087cead213b0d0/grpcio-tools-1.62.3.tar.gz", hash = "sha256:7c7136015c3d62c3eef493efabaf9e3380e3e66d24ee8e94c01cb71377f57833", size = 4538520, upload-time = "2024-08-06T00:37:11.035Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/9a/edfefb47f11ef6b0f39eea4d8f022c5bb05ac1d14fcc7058e84a51305b73/grpcio_tools-1.71.2.tar.gz", hash = "sha256:b5304d65c7569b21270b568e404a5a843cf027c66552a6a0978b23f137679c09", size = 5330655, upload-time = "2025-06-28T04:22:00.308Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/52/2dfe0a46b63f5ebcd976570aa5fc62f793d5a8b169e211c6a5aede72b7ae/grpcio_tools-1.62.3-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:703f46e0012af83a36082b5f30341113474ed0d91e36640da713355cd0ea5d23", size = 5147623, upload-time = "2024-08-06T00:30:54.894Z" }, - { url = "https://files.pythonhosted.org/packages/f0/2e/29fdc6c034e058482e054b4a3c2432f84ff2e2765c1342d4f0aa8a5c5b9a/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7cc83023acd8bc72cf74c2edbe85b52098501d5b74d8377bfa06f3e929803492", size = 2719538, upload-time = "2024-08-06T00:30:57.928Z" }, - { url = "https://files.pythonhosted.org/packages/f9/60/abe5deba32d9ec2c76cdf1a2f34e404c50787074a2fee6169568986273f1/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ff7d58a45b75df67d25f8f144936a3e44aabd91afec833ee06826bd02b7fbe7", size = 3070964, upload-time = "2024-08-06T00:31:00.267Z" }, - { url = "https://files.pythonhosted.org/packages/bc/ad/e2b066684c75f8d9a48508cde080a3a36618064b9cadac16d019ca511444/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f2483ea232bd72d98a6dc6d7aefd97e5bc80b15cd909b9e356d6f3e326b6e43", size = 2805003, upload-time = "2024-08-06T00:31:02.565Z" }, - { url = "https://files.pythonhosted.org/packages/9c/3f/59bf7af786eae3f9d24ee05ce75318b87f541d0950190ecb5ffb776a1a58/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:962c84b4da0f3b14b3cdb10bc3837ebc5f136b67d919aea8d7bb3fd3df39528a", size = 3685154, upload-time = "2024-08-06T00:31:05.339Z" }, - { url = "https://files.pythonhosted.org/packages/f1/79/4dd62478b91e27084c67b35a2316ce8a967bd8b6cb8d6ed6c86c3a0df7cb/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ad0473af5544f89fc5a1ece8676dd03bdf160fb3230f967e05d0f4bf89620e3", size = 3297942, upload-time = "2024-08-06T00:31:08.456Z" }, - { url = "https://files.pythonhosted.org/packages/b8/cb/86449ecc58bea056b52c0b891f26977afc8c4464d88c738f9648da941a75/grpcio_tools-1.62.3-cp311-cp311-win32.whl", hash = "sha256:db3bc9fa39afc5e4e2767da4459df82b095ef0cab2f257707be06c44a1c2c3e5", size = 910231, upload-time = "2024-08-06T00:31:11.464Z" }, - { url = "https://files.pythonhosted.org/packages/45/a4/9736215e3945c30ab6843280b0c6e1bff502910156ea2414cd77fbf1738c/grpcio_tools-1.62.3-cp311-cp311-win_amd64.whl", hash = "sha256:e0898d412a434e768a0c7e365acabe13ff1558b767e400936e26b5b6ed1ee51f", size = 1052496, upload-time = "2024-08-06T00:31:13.665Z" }, - { url = "https://files.pythonhosted.org/packages/2a/a5/d6887eba415ce318ae5005e8dfac3fa74892400b54b6d37b79e8b4f14f5e/grpcio_tools-1.62.3-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d102b9b21c4e1e40af9a2ab3c6d41afba6bd29c0aa50ca013bf85c99cdc44ac5", size = 5147690, upload-time = "2024-08-06T00:31:16.436Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7c/3cde447a045e83ceb4b570af8afe67ffc86896a2fe7f59594dc8e5d0a645/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0a52cc9444df978438b8d2332c0ca99000521895229934a59f94f37ed896b133", size = 2720538, upload-time = "2024-08-06T00:31:18.905Z" }, - { url = "https://files.pythonhosted.org/packages/88/07/f83f2750d44ac4f06c07c37395b9c1383ef5c994745f73c6bfaf767f0944/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141d028bf5762d4a97f981c501da873589df3f7e02f4c1260e1921e565b376fa", size = 3071571, upload-time = "2024-08-06T00:31:21.684Z" }, - { url = "https://files.pythonhosted.org/packages/37/74/40175897deb61e54aca716bc2e8919155b48f33aafec8043dda9592d8768/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47a5c093ab256dec5714a7a345f8cc89315cb57c298b276fa244f37a0ba507f0", size = 2806207, upload-time = "2024-08-06T00:31:24.208Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/d8de915105a217cbcb9084d684abdc032030dcd887277f2ef167372287fe/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f6831fdec2b853c9daa3358535c55eed3694325889aa714070528cf8f92d7d6d", size = 3685815, upload-time = "2024-08-06T00:31:26.917Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d9/4360a6c12be3d7521b0b8c39e5d3801d622fbb81cc2721dbd3eee31e28c8/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e02d7c1a02e3814c94ba0cfe43d93e872c758bd8fd5c2797f894d0c49b4a1dfc", size = 3298378, upload-time = "2024-08-06T00:31:30.401Z" }, - { url = "https://files.pythonhosted.org/packages/29/3b/7cdf4a9e5a3e0a35a528b48b111355cd14da601413a4f887aa99b6da468f/grpcio_tools-1.62.3-cp312-cp312-win32.whl", hash = "sha256:b881fd9505a84457e9f7e99362eeedd86497b659030cf57c6f0070df6d9c2b9b", size = 910416, upload-time = "2024-08-06T00:31:33.118Z" }, - { url = "https://files.pythonhosted.org/packages/6c/66/dd3ec249e44c1cc15e902e783747819ed41ead1336fcba72bf841f72c6e9/grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl", hash = "sha256:11c625eebefd1fd40a228fc8bae385e448c7e32a6ae134e43cf13bbc23f902b7", size = 1052856, upload-time = "2024-08-06T00:31:36.519Z" }, + { url = "https://files.pythonhosted.org/packages/17/e4/0568d38b8da6237ea8ea15abb960fb7ab83eb7bb51e0ea5926dab3d865b1/grpcio_tools-1.71.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:0acb8151ea866be5b35233877fbee6445c36644c0aa77e230c9d1b46bf34b18b", size = 2385557, upload-time = "2025-06-28T04:20:54.323Z" }, + { url = "https://files.pythonhosted.org/packages/76/fb/700d46f72b0f636cf0e625f3c18a4f74543ff127471377e49a071f64f1e7/grpcio_tools-1.71.2-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:b28f8606f4123edb4e6da281547465d6e449e89f0c943c376d1732dc65e6d8b3", size = 5447590, upload-time = "2025-06-28T04:20:55.836Z" }, + { url = "https://files.pythonhosted.org/packages/12/69/d9bb2aec3de305162b23c5c884b9f79b1a195d42b1e6dabcc084cc9d0804/grpcio_tools-1.71.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:cbae6f849ad2d1f5e26cd55448b9828e678cb947fa32c8729d01998238266a6a", size = 2348495, upload-time = "2025-06-28T04:20:57.33Z" }, + { url = "https://files.pythonhosted.org/packages/d5/83/f840aba1690461b65330efbca96170893ee02fae66651bcc75f28b33a46c/grpcio_tools-1.71.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4d1027615cfb1e9b1f31f2f384251c847d68c2f3e025697e5f5c72e26ed1316", size = 2742333, upload-time = "2025-06-28T04:20:59.051Z" }, + { url = "https://files.pythonhosted.org/packages/30/34/c02cd9b37de26045190ba665ee6ab8597d47f033d098968f812d253bbf8c/grpcio_tools-1.71.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bac95662dc69338edb9eb727cc3dd92342131b84b12b3e8ec6abe973d4cbf1b", size = 2473490, upload-time = "2025-06-28T04:21:00.614Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c7/375718ae091c8f5776828ce97bdcb014ca26244296f8b7f70af1a803ed2f/grpcio_tools-1.71.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c50250c7248055040f89eb29ecad39d3a260a4b6d3696af1575945f7a8d5dcdc", size = 2850333, upload-time = "2025-06-28T04:21:01.95Z" }, + { url = "https://files.pythonhosted.org/packages/19/37/efc69345bd92a73b2bc80f4f9e53d42dfdc234b2491ae58c87da20ca0ea5/grpcio_tools-1.71.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6ab1ad955e69027ef12ace4d700c5fc36341bdc2f420e87881e9d6d02af3d7b8", size = 3300748, upload-time = "2025-06-28T04:21:03.451Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1f/15f787eb25ae42086f55ed3e4260e85f385921c788debf0f7583b34446e3/grpcio_tools-1.71.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd75dde575781262b6b96cc6d0b2ac6002b2f50882bf5e06713f1bf364ee6e09", size = 2913178, upload-time = "2025-06-28T04:21:04.879Z" }, + { url = "https://files.pythonhosted.org/packages/12/aa/69cb3a9dff7d143a05e4021c3c9b5cde07aacb8eb1c892b7c5b9fb4973e3/grpcio_tools-1.71.2-cp311-cp311-win32.whl", hash = "sha256:9a3cb244d2bfe0d187f858c5408d17cb0e76ca60ec9a274c8fd94cc81457c7fc", size = 946256, upload-time = "2025-06-28T04:21:06.518Z" }, + { url = "https://files.pythonhosted.org/packages/1e/df/fb951c5c87eadb507a832243942e56e67d50d7667b0e5324616ffd51b845/grpcio_tools-1.71.2-cp311-cp311-win_amd64.whl", hash = "sha256:00eb909997fd359a39b789342b476cbe291f4dd9c01ae9887a474f35972a257e", size = 1117661, upload-time = "2025-06-28T04:21:08.18Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d3/3ed30a9c5b2424627b4b8411e2cd6a1a3f997d3812dbc6a8630a78bcfe26/grpcio_tools-1.71.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:bfc0b5d289e383bc7d317f0e64c9dfb59dc4bef078ecd23afa1a816358fb1473", size = 2385479, upload-time = "2025-06-28T04:21:10.413Z" }, + { url = "https://files.pythonhosted.org/packages/54/61/e0b7295456c7e21ef777eae60403c06835160c8d0e1e58ebfc7d024c51d3/grpcio_tools-1.71.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b4669827716355fa913b1376b1b985855d5cfdb63443f8d18faf210180199006", size = 5431521, upload-time = "2025-06-28T04:21:12.261Z" }, + { url = "https://files.pythonhosted.org/packages/75/d7/7bcad6bcc5f5b7fab53e6bce5db87041f38ef3e740b1ec2d8c49534fa286/grpcio_tools-1.71.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:d4071f9b44564e3f75cdf0f05b10b3e8c7ea0ca5220acbf4dc50b148552eef2f", size = 2350289, upload-time = "2025-06-28T04:21:13.625Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8a/e4c1c4cb8c9ff7f50b7b2bba94abe8d1e98ea05f52a5db476e7f1c1a3c70/grpcio_tools-1.71.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a28eda8137d587eb30081384c256f5e5de7feda34776f89848b846da64e4be35", size = 2743321, upload-time = "2025-06-28T04:21:15.007Z" }, + { url = "https://files.pythonhosted.org/packages/fd/aa/95bc77fda5c2d56fb4a318c1b22bdba8914d5d84602525c99047114de531/grpcio_tools-1.71.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b19c083198f5eb15cc69c0a2f2c415540cbc636bfe76cea268e5894f34023b40", size = 2474005, upload-time = "2025-06-28T04:21:16.443Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ff/ca11f930fe1daa799ee0ce1ac9630d58a3a3deed3dd2f465edb9a32f299d/grpcio_tools-1.71.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:784c284acda0d925052be19053d35afbf78300f4d025836d424cf632404f676a", size = 2851559, upload-time = "2025-06-28T04:21:18.139Z" }, + { url = "https://files.pythonhosted.org/packages/64/10/c6fc97914c7e19c9bb061722e55052fa3f575165da9f6510e2038d6e8643/grpcio_tools-1.71.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:381e684d29a5d052194e095546eef067201f5af30fd99b07b5d94766f44bf1ae", size = 3300622, upload-time = "2025-06-28T04:21:20.291Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d6/965f36cfc367c276799b730d5dd1311b90a54a33726e561393b808339b04/grpcio_tools-1.71.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3e4b4801fabd0427fc61d50d09588a01b1cfab0ec5e8a5f5d515fbdd0891fd11", size = 2913863, upload-time = "2025-06-28T04:21:22.196Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f0/c05d5c3d0c1d79ac87df964e9d36f1e3a77b60d948af65bec35d3e5c75a3/grpcio_tools-1.71.2-cp312-cp312-win32.whl", hash = "sha256:84ad86332c44572305138eafa4cc30040c9a5e81826993eae8227863b700b490", size = 945744, upload-time = "2025-06-28T04:21:23.463Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e9/c84c1078f0b7af7d8a40f5214a9bdd8d2a567ad6c09975e6e2613a08d29d/grpcio_tools-1.71.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e1108d37eecc73b1c4a27350a6ed921b5dda25091700c1da17cfe30761cd462", size = 1117695, upload-time = "2025-06-28T04:21:25.22Z" }, ] [[package]] @@ -2856,18 +2887,17 @@ wheels = [ [[package]] name = "httpx" -version = "0.27.2" +version = "0.28.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, { name = "httpcore" }, { name = "idna" }, - { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189, upload-time = "2024-08-27T12:54:01.334Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] [package.optional-dependencies] @@ -3966,59 +3996,59 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "importlib-metadata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/83/93114b6de85a98963aec218a51509a52ed3f8de918fe91eb0f7299805c3f/opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342", size = 62693, upload-time = "2024-08-28T21:35:31.445Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/36/260eaea0f74fdd0c0d8f22ed3a3031109ea1c85531f94f4fde266c29e29a/opentelemetry_api-1.28.0.tar.gz", hash = "sha256:578610bcb8aa5cdcb11169d136cc752958548fb6ccffb0969c1036b0ee9e5353", size = 62803, upload-time = "2024-11-05T19:14:45.497Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/1f/737dcdbc9fea2fa96c1b392ae47275165a7c641663fbb08a8d252968eed2/opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7", size = 63970, upload-time = "2024-08-28T21:35:00.598Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/3b25d8b856791c04d8a62b1257b5fc09dc41a057800db06885af8ddcdce1/opentelemetry_api-1.28.0-py3-none-any.whl", hash = "sha256:8457cd2c59ea1bd0988560f021656cecd254ad7ef6be4ba09dbefeca2409ce52", size = 64314, upload-time = "2024-11-05T19:14:21.659Z" }, ] [[package]] name = "opentelemetry-distro" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/09/423e17c439ed24c45110affe84aad886a536b7871a42637d2ad14a179b47/opentelemetry_distro-0.48b0.tar.gz", hash = "sha256:5cb15915780ac4972583286a56683d43bd4ca95371d72f5f3f179c8b0b2ddc91", size = 2556, upload-time = "2024-08-28T21:27:40.455Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/75/7cb7c33899e66bb366d40a889111a78c22df0951038b6699f1663e715a9f/opentelemetry_distro-0.49b0.tar.gz", hash = "sha256:1bafa274f9e83baa0d2a5d47ed02caffcf9bcca60107b389b145400d82b07513", size = 2560, upload-time = "2024-11-05T19:21:39.379Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/cf/fa9a5fe954f1942e03b319ae0e319ebc93d9f984b548bcd9b3f232a1434d/opentelemetry_distro-0.48b0-py3-none-any.whl", hash = "sha256:b2f8fce114325b020769af3b9bf503efb8af07efc190bd1b9deac7843171664a", size = 3321, upload-time = "2024-08-28T21:26:26.584Z" }, + { url = "https://files.pythonhosted.org/packages/4c/db/806172b6a4933966eee518db814b375e620602f7fe776b74ef795690f135/opentelemetry_distro-0.49b0-py3-none-any.whl", hash = "sha256:1af4074702f605ea210753dd41947dc2fd61b39724f23cdcf15d5654867cd3c2", size = 3318, upload-time = "2024-11-05T19:20:34.065Z" }, ] [[package]] name = "opentelemetry-exporter-otlp" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-exporter-otlp-proto-grpc" }, { name = "opentelemetry-exporter-otlp-proto-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d3/8156cc14e8f4573a3572ee7f30badc7aabd02961a09acc72ab5f2c789ef1/opentelemetry_exporter_otlp-1.27.0.tar.gz", hash = "sha256:4a599459e623868cc95d933c301199c2367e530f089750e115599fccd67cb2a1", size = 6166, upload-time = "2024-08-28T21:35:33.746Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/16/14e3fc163930ea68f0980a4cdd4ae5796e60aeb898965990e13263d64baf/opentelemetry_exporter_otlp-1.28.0.tar.gz", hash = "sha256:31ae7495831681dd3da34ac457f6970f147465ae4b9aae3a888d7a581c7cd868", size = 6170, upload-time = "2024-11-05T19:14:47.349Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/6d/95e1fc2c8d945a734db32e87a5aa7a804f847c1657a21351df9338bd1c9c/opentelemetry_exporter_otlp-1.27.0-py3-none-any.whl", hash = "sha256:7688791cbdd951d71eb6445951d1cfbb7b6b2d7ee5948fac805d404802931145", size = 7001, upload-time = "2024-08-28T21:35:04.02Z" }, + { url = "https://files.pythonhosted.org/packages/c2/82/3f521b3c1f2a411ed60a24a8c9f486c1beeaf8c6c55337c87d3ae1642151/opentelemetry_exporter_otlp-1.28.0-py3-none-any.whl", hash = "sha256:1fd02d70f2c1b7ac5579c81e78de4594b188d3317c8ceb69e8b53900fb7b40fd", size = 7024, upload-time = "2024-11-05T19:14:24.534Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/2e/7eaf4ba595fb5213cf639c9158dfb64aacb2e4c7d74bfa664af89fa111f4/opentelemetry_exporter_otlp_proto_common-1.27.0.tar.gz", hash = "sha256:159d27cf49f359e3798c4c3eb8da6ef4020e292571bd8c5604a2a573231dd5c8", size = 17860, upload-time = "2024-08-28T21:35:34.896Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/8d/5d411084ac441052f4c9bae03a1aec65ae5d16b439fea7b9c5ac3842c013/opentelemetry_exporter_otlp_proto_common-1.28.0.tar.gz", hash = "sha256:5fa0419b0c8e291180b0fc8430a20dd44a3f3236f8e0827992145914f273ec4f", size = 18505, upload-time = "2024-11-05T19:14:48.204Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/27/4610ab3d9bb3cde4309b6505f98b3aabca04a26aa480aa18cede23149837/opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl", hash = "sha256:675db7fffcb60946f3a5c43e17d1168a3307a94a930ecf8d2ea1f286f3d4f79a", size = 17848, upload-time = "2024-08-28T21:35:05.412Z" }, + { url = "https://files.pythonhosted.org/packages/e1/72/3c44aabc74db325aaba09361b6a0d80f6d601f0ff86ecea8ee655c9538fc/opentelemetry_exporter_otlp_proto_common-1.28.0-py3-none-any.whl", hash = "sha256:467e6437d24e020156dffecece8c0a4471a8a60f6a34afeda7386df31a092410", size = 18403, upload-time = "2024-11-05T19:14:25.798Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, @@ -4029,14 +4059,14 @@ dependencies = [ { name = "opentelemetry-proto" }, { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/d0/c1e375b292df26e0ffebf194e82cd197e4c26cc298582bda626ce3ce74c5/opentelemetry_exporter_otlp_proto_grpc-1.27.0.tar.gz", hash = "sha256:af6f72f76bcf425dfb5ad11c1a6d6eca2863b91e63575f89bb7b4b55099d968f", size = 26244, upload-time = "2024-08-28T21:35:36.314Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4d/f215162e58041afb4bdf5dbd0d8faf0b7fc9bf7b3d3fc0e44e06f9e7e869/opentelemetry_exporter_otlp_proto_grpc-1.28.0.tar.gz", hash = "sha256:47a11c19dc7f4289e220108e113b7de90d59791cb4c37fc29f69a6a56f2c3735", size = 26237, upload-time = "2024-11-05T19:14:49.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/80/32217460c2c64c0568cea38410124ff680a9b65f6732867bbf857c4d8626/opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl", hash = "sha256:56b5bbd5d61aab05e300d9d62a6b3c134827bbd28d0b12f2649c2da368006c9e", size = 18541, upload-time = "2024-08-28T21:35:06.493Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b5/afabc8106abc0f9cfeecf5b3e682622b3e04bba1d9b967dbfcd91b9c4ebe/opentelemetry_exporter_otlp_proto_grpc-1.28.0-py3-none-any.whl", hash = "sha256:edbdc53e7783f88d4535db5807cb91bd7b1ec9e9b9cdbfee14cd378f29a3b328", size = 18532, upload-time = "2024-11-05T19:14:26.853Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, @@ -4047,28 +4077,29 @@ dependencies = [ { name = "opentelemetry-sdk" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/0a/f05c55e8913bf58a033583f2580a0ec31a5f4cf2beacc9e286dcb74d6979/opentelemetry_exporter_otlp_proto_http-1.27.0.tar.gz", hash = "sha256:2103479092d8eb18f61f3fbff084f67cc7f2d4a7d37e75304b8b56c1d09ebef5", size = 15059, upload-time = "2024-08-28T21:35:37.079Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/2a/555f2845928086cd51aa6941c7a546470805b68ed631ec139ce7d841763d/opentelemetry_exporter_otlp_proto_http-1.28.0.tar.gz", hash = "sha256:d83a9a03a8367ead577f02a64127d827c79567de91560029688dd5cfd0152a8e", size = 15051, upload-time = "2024-11-05T19:14:49.813Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/8d/4755884afc0b1db6000527cac0ca17273063b6142c773ce4ecd307a82e72/opentelemetry_exporter_otlp_proto_http-1.27.0-py3-none-any.whl", hash = "sha256:688027575c9da42e179a69fe17e2d1eba9b14d81de8d13553a21d3114f3b4d75", size = 17203, upload-time = "2024-08-28T21:35:08.141Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ce/80d5adabbf7ab4a0ca7b5e0f4039b24d273be370c3ba85fc05b13794411c/opentelemetry_exporter_otlp_proto_http-1.28.0-py3-none-any.whl", hash = "sha256:e8f3f7961b747edb6b44d51de4901a61e9c01d50debd747b120a08c4996c7e7b", size = 17228, upload-time = "2024-11-05T19:14:28.613Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, - { name = "setuptools" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0e/d9394839af5d55c8feb3b22cd11138b953b49739b20678ca96289e30f904/opentelemetry_instrumentation-0.48b0.tar.gz", hash = "sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35", size = 24724, upload-time = "2024-08-28T21:27:42.82Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/6b/6c25b15063c92a011cf3f68375971e2c58a9c764690847edc97df2d94eeb/opentelemetry_instrumentation-0.49b0.tar.gz", hash = "sha256:398a93e0b9dc2d11cc8627e1761665c506fe08c6b2df252a2ab3ade53d751c46", size = 26478, upload-time = "2024-11-05T19:21:41.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7f/405c41d4f359121376c9d5117dcf68149b8122d3f6c718996d037bd4d800/opentelemetry_instrumentation-0.48b0-py3-none-any.whl", hash = "sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44", size = 29449, upload-time = "2024-08-28T21:26:31.288Z" }, + { url = "https://files.pythonhosted.org/packages/93/61/e0d21e958d6072ce25c4f5e26a1d22835fc86f80836660adf6badb6038ce/opentelemetry_instrumentation-0.49b0-py3-none-any.whl", hash = "sha256:68364d73a1ff40894574cbc6138c5f98674790cae1f3b0865e21cf702f24dcb3", size = 30694, upload-time = "2024-11-05T19:20:38.584Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -4077,28 +4108,28 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/ac/fd3d40bab3234ec3f5c052a815100676baaae1832fa1067935f11e5c59c6/opentelemetry_instrumentation_asgi-0.48b0.tar.gz", hash = "sha256:04c32174b23c7fa72ddfe192dad874954968a6a924608079af9952964ecdf785", size = 23435, upload-time = "2024-08-28T21:27:47.276Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/55/693c3d0938ba5fead5c3aa4ac7022a992b4ff99a8e9979800d0feb843ff4/opentelemetry_instrumentation_asgi-0.49b0.tar.gz", hash = "sha256:959fd9b1345c92f20c6ef1d42f92ef6a76b3c3083fbc4104d59da6859b15b083", size = 24117, upload-time = "2024-11-05T19:21:46.769Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/74/a0e0d38622856597dd8e630f2bd793760485eb165708e11b8be1696bbb5a/opentelemetry_instrumentation_asgi-0.48b0-py3-none-any.whl", hash = "sha256:ddb1b5fc800ae66e85a4e2eca4d9ecd66367a8c7b556169d9e7b57e10676e44d", size = 15958, upload-time = "2024-08-28T21:26:38.139Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0b/7900c782a1dfaa584588d724bc3bbdf8405a32497537dd96b3fcbf8461b9/opentelemetry_instrumentation_asgi-0.49b0-py3-none-any.whl", hash = "sha256:722a90856457c81956c88f35a6db606cc7db3231046b708aae2ddde065723dbe", size = 16326, upload-time = "2024-11-05T19:20:46.176Z" }, ] [[package]] name = "opentelemetry-instrumentation-celery" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-semantic-conventions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/68/72975eff50cc22d8f65f96c425a2e8844f91488e78ffcfb603ac7cee0e5a/opentelemetry_instrumentation_celery-0.48b0.tar.gz", hash = "sha256:1d33aa6c4a1e6c5d17a64215245208a96e56c9d07611685dbae09a557704af26", size = 14445, upload-time = "2024-08-28T21:27:56.392Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/8b/9b8a9dda3ed53354c6f707a45cdb7a4730e1c109b50fc1b413525493f811/opentelemetry_instrumentation_celery-0.49b0.tar.gz", hash = "sha256:afbaee97cc9c75f29bcc9784f16f8e37c415d4fe9b334748c5b90a3d30d12473", size = 14702, upload-time = "2024-11-05T19:21:53.672Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/59/f09e8f9f596d375fd86b7677751525bbc485c8cc8c5388e39786a3d3b968/opentelemetry_instrumentation_celery-0.48b0-py3-none-any.whl", hash = "sha256:c1904e38cc58fb2a33cd657d6e296285c5ffb0dca3f164762f94b905e5abc88e", size = 13697, upload-time = "2024-08-28T21:26:50.01Z" }, + { url = "https://files.pythonhosted.org/packages/21/8c/d7d4adb36abbc0e517a69f7a069f32742122ae22d6017202f64570d9f4c5/opentelemetry_instrumentation_celery-0.49b0-py3-none-any.whl", hash = "sha256:38d4a78c78f33020032ef77ef0ead756bdf7838bcfb603de10f5925d39f14929", size = 13749, upload-time = "2024-11-05T19:20:54.98Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4107,17 +4138,16 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/20/43477da5850ef2cd3792715d442aecd051e885e0603b6ee5783b2104ba8f/opentelemetry_instrumentation_fastapi-0.48b0.tar.gz", hash = "sha256:21a72563ea412c0b535815aeed75fc580240f1f02ebc72381cfab672648637a2", size = 18497, upload-time = "2024-08-28T21:28:01.14Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/bf/8e6d2a4807360f2203192017eb4845f5628dbeaf0597adf3d141cc5c24e1/opentelemetry_instrumentation_fastapi-0.49b0.tar.gz", hash = "sha256:6d14935c41fd3e49328188b6a59dd4c37bd17a66b01c15b0c64afa9714a1f905", size = 19230, upload-time = "2024-11-05T19:21:59.361Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/50/745ab075a3041b7a5f29a579d2c28eaad54f64b4589d8f9fd364c62cf0f3/opentelemetry_instrumentation_fastapi-0.48b0-py3-none-any.whl", hash = "sha256:afeb820a59e139d3e5d96619600f11ce0187658b8ae9e3480857dd790bc024f2", size = 11777, upload-time = "2024-08-28T21:26:57.457Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f4/0895b9410c10abf987c90dee1b7688a8f2214a284fe15e575648f6a1473a/opentelemetry_instrumentation_fastapi-0.49b0-py3-none-any.whl", hash = "sha256:646e1b18523cbe6860ae9711eb2c7b9c85466c3c7697cd6b8fb5180d85d3fe6e", size = 12101, upload-time = "2024-11-05T19:21:01.805Z" }, ] [[package]] name = "opentelemetry-instrumentation-flask" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata" }, { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-instrumentation-wsgi" }, @@ -4125,29 +4155,30 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ed/2f/5c3af780a69f9ba78445fe0e5035c41f67281a31b08f3c3e7ec460bda726/opentelemetry_instrumentation_flask-0.48b0.tar.gz", hash = "sha256:e03a34428071aebf4864ea6c6a564acef64f88c13eb3818e64ea90da61266c3d", size = 19196, upload-time = "2024-08-28T21:28:01.986Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/12/dc72873fb1e35699941d8eb6a53ef25e8c5843dea37665dad33bd720f047/opentelemetry_instrumentation_flask-0.49b0.tar.gz", hash = "sha256:f7c5ab67753c4781a2e21c8f43dc5fc02ece74fdd819466c75d025db80aa7576", size = 19176, upload-time = "2024-11-05T19:22:00.816Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/3d/fcde4f8f0bf9fa1ee73a12304fa538076fb83fe0a2ae966ab0f0b7da5109/opentelemetry_instrumentation_flask-0.48b0-py3-none-any.whl", hash = "sha256:26b045420b9d76e85493b1c23fcf27517972423480dc6cf78fd6924248ba5808", size = 14588, upload-time = "2024-08-28T21:26:58.504Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fc/354da8f33ef0daebfc8e4eac995d342ae13a35097bbad512cfe0d2f3c61a/opentelemetry_instrumentation_flask-0.49b0-py3-none-any.whl", hash = "sha256:f3ef330c3cee3e2c161f27f1e7017c8800b9bfb6f9204f2f7bfb0b274874be0e", size = 14582, upload-time = "2024-11-05T19:21:02.793Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, + { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/d9/c65d818607c16d1b7ea8d2de6111c6cecadf8d2fd38c1885a72733a7c6d3/opentelemetry_instrumentation_httpx-0.48b0.tar.gz", hash = "sha256:ee977479e10398931921fb995ac27ccdeea2e14e392cb27ef012fc549089b60a", size = 16931, upload-time = "2024-08-28T21:28:03.794Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/53/8b5e05e55a513d846ead5afb0509bec37a34a1c3e82f30b13d14156334b1/opentelemetry_instrumentation_httpx-0.49b0.tar.gz", hash = "sha256:07165b624f3e58638cee47ecf1c81939a8c2beb7e42ce9f69e25a9f21dc3f4cf", size = 17750, upload-time = "2024-11-05T19:22:02.911Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/fe/f2daa9d6d988c093b8c7b1d35df675761a8ece0b600b035dc04982746c9d/opentelemetry_instrumentation_httpx-0.48b0-py3-none-any.whl", hash = "sha256:d94f9d612c82d09fe22944d1904a30a464c19bea2ba76be656c99a28ad8be8e5", size = 13900, upload-time = "2024-08-28T21:27:01.566Z" }, + { url = "https://files.pythonhosted.org/packages/3b/9f/843391c6d645cd4f6914b27bc807fc1ff52b97f84cbe3ca675641976b23f/opentelemetry_instrumentation_httpx-0.49b0-py3-none-any.whl", hash = "sha256:e59e0d2fda5ef841630c68da1d78ff9192f63590a9099f12f0eab614abdf239a", size = 14110, upload-time = "2024-11-05T19:21:04.698Z" }, ] [[package]] name = "opentelemetry-instrumentation-redis" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4155,14 +4186,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/be/92e98e4c7f275be3d373899a41b0a7d4df64266657d985dbbdb9a54de0d5/opentelemetry_instrumentation_redis-0.48b0.tar.gz", hash = "sha256:61e33e984b4120e1b980d9fba6e9f7ca0c8d972f9970654d8f6e9f27fa115a8c", size = 10511, upload-time = "2024-08-28T21:28:15.061Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/5b/1398eb2f92fd76787ccec28d24dc4c7dfaaf97a7557e7729e2f7c2c05d84/opentelemetry_instrumentation_redis-0.49b0.tar.gz", hash = "sha256:922542c3bd192ad4ba74e2c7e0a253c7c58a5cefbd6f89da2aba4d193a974703", size = 11353, upload-time = "2024-11-05T19:22:12.822Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/40/892f30d400091106309cc047fd3f6d76a828fedd984a953fd5386b78a2fb/opentelemetry_instrumentation_redis-0.48b0-py3-none-any.whl", hash = "sha256:48c7f2e25cbb30bde749dc0d8b9c74c404c851f554af832956b9630b27f5bcb7", size = 11610, upload-time = "2024-08-28T21:27:18.759Z" }, + { url = "https://files.pythonhosted.org/packages/24/e4/4f258fef0759629f2e8a0210d5533cfef3ecad69ff35be044637a3e2783e/opentelemetry_instrumentation_redis-0.49b0-py3-none-any.whl", hash = "sha256:b7d8f758bac53e77b7e7ca98ce80f91230577502dacb619ebe8e8b6058042067", size = 12453, upload-time = "2024-11-05T19:21:18.534Z" }, ] [[package]] name = "opentelemetry-instrumentation-sqlalchemy" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4171,14 +4202,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/77/3fcebbca8bd729da50dc2130d8ca869a235aa5483a85ef06c5dc8643476b/opentelemetry_instrumentation_sqlalchemy-0.48b0.tar.gz", hash = "sha256:dbf2d5a755b470e64e5e2762b56f8d56313787e4c7d71a87fe25c33f48eb3493", size = 13194, upload-time = "2024-08-28T21:28:18.122Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/a7/24f6cce3808ae1802dd1b60d752fbab877db5655198929cf4ee8ea416923/opentelemetry_instrumentation_sqlalchemy-0.49b0.tar.gz", hash = "sha256:32658e520fc8b35823c722f5d8831d3a410b76dd2724adb2887befc041ddef04", size = 13194, upload-time = "2024-11-05T19:22:14.92Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/84/4b6f1e9e9f83a52d966e91963f5a8424edc4a3d5ea32854c96c2d1618284/opentelemetry_instrumentation_sqlalchemy-0.48b0-py3-none-any.whl", hash = "sha256:625848a34aa5770cb4b1dcdbd95afce4307a0230338711101325261d739f391f", size = 13360, upload-time = "2024-08-28T21:27:22.102Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/a1a3685fed593282999cdc374ece15efbd56f8d774bd368bf7ff2cf5923c/opentelemetry_instrumentation_sqlalchemy-0.49b0-py3-none-any.whl", hash = "sha256:d854052d2b02cd0562e5628a514c8153fceada7f585137e173165dfd0a46ef6a", size = 13358, upload-time = "2024-11-05T19:21:23.654Z" }, ] [[package]] name = "opentelemetry-instrumentation-wsgi" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -4186,70 +4217,70 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/a5/f45cdfba18f22aefd2378eac8c07c1f8c9656d6bf7ce315ced48c67f3437/opentelemetry_instrumentation_wsgi-0.48b0.tar.gz", hash = "sha256:1a1e752367b0df4397e0b835839225ef5c2c3c053743a261551af13434fc4d51", size = 17974, upload-time = "2024-08-28T21:28:24.902Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/2b/91b022b004ac9e9ab0eefd10bc4257975291f88adc81b4ef2c601ddb1adf/opentelemetry_instrumentation_wsgi-0.49b0.tar.gz", hash = "sha256:0812a02e132f8fc3d5c897bba84e530c37b85c315b199bb97ca6508279e7eb23", size = 17733, upload-time = "2024-11-05T19:22:24.3Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/87/fa420007e0ba7e8cd43799ab204717ab515f000236fa2726a6be3299efdd/opentelemetry_instrumentation_wsgi-0.48b0-py3-none-any.whl", hash = "sha256:c6051124d741972090fe94b2fa302555e1e2a22e9cdda32dd39ed49a5b34e0c6", size = 13691, upload-time = "2024-08-28T21:27:33.257Z" }, + { url = "https://files.pythonhosted.org/packages/02/1d/59979665778ed8c85bc31c92b75571cd7afb8e3322fb513c87fe1bad6d78/opentelemetry_instrumentation_wsgi-0.49b0-py3-none-any.whl", hash = "sha256:8869ccf96611827e4448417718920e9eec6d25bffb5bf72c7952c7346ec33fbc", size = 13699, upload-time = "2024-11-05T19:21:35.039Z" }, ] [[package]] name = "opentelemetry-propagator-b3" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "opentelemetry-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/a3/3ceeb5ff5a1906371834d5c594e24e5b84f35528d219054833deca4ac44c/opentelemetry_propagator_b3-1.27.0.tar.gz", hash = "sha256:39377b6aa619234e08fbc6db79bf880aff36d7e2761efa9afa28b78d5937308f", size = 9590, upload-time = "2024-08-28T21:35:43.971Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/1d/225ea036785119964509e92f4e1bc0313ba6ec790fbf51bd363abafeafae/opentelemetry_propagator_b3-1.28.0.tar.gz", hash = "sha256:cf6f0d2a1881c4858898be47e8a94b11bc5b16fc73b6c37ebfa2121c4825adc6", size = 9592, upload-time = "2024-11-05T19:14:57.193Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/3f/75ba77b8d9938bae575bc457a5c56ca2246ff5367b54c7d4252a31d1c91f/opentelemetry_propagator_b3-1.27.0-py3-none-any.whl", hash = "sha256:1dd75e9801ba02e870df3830097d35771a64c123127c984d9b05c352a35aa9cc", size = 8899, upload-time = "2024-08-28T21:35:18.317Z" }, + { url = "https://files.pythonhosted.org/packages/4e/fa/438d53d73a6c45df5d416b56dc371a65d0b07859bc107ab632349a079d4a/opentelemetry_propagator_b3-1.28.0-py3-none-any.whl", hash = "sha256:9f6923a5da56d7da6724e4fdd758a67ede2a2732efb929e538cf6fea337700c5", size = 8917, upload-time = "2024-11-05T19:14:37.317Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9a/59/959f0beea798ae0ee9c979b90f220736fbec924eedbefc60ca581232e659/opentelemetry_proto-1.27.0.tar.gz", hash = "sha256:33c9345d91dafd8a74fc3d7576c5a38f18b7fdf8d02983ac67485386132aedd6", size = 34749, upload-time = "2024-08-28T21:35:45.839Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/63/ac4cef4d30ea0ca1d2153ad2fc62d91d1cf3b89b0e4e5cbd61a8c567885f/opentelemetry_proto-1.28.0.tar.gz", hash = "sha256:4a45728dfefa33f7908b828b9b7c9f2c6de42a05d5ec7b285662ddae71c4c870", size = 34331, upload-time = "2024-11-05T19:14:59.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/56/3d2d826834209b19a5141eed717f7922150224d1a982385d19a9444cbf8d/opentelemetry_proto-1.27.0-py3-none-any.whl", hash = "sha256:b133873de5581a50063e1e4b29cdcf0c5e253a8c2d8dc1229add20a4c3830ace", size = 52464, upload-time = "2024-08-28T21:35:21.434Z" }, + { url = "https://files.pythonhosted.org/packages/86/94/c0b43d16e1d96ee1e699373aa59f14a3aa2e7126af3f11d6adc5dcc531cd/opentelemetry_proto-1.28.0-py3-none-any.whl", hash = "sha256:d5ad31b997846543b8e15504657d9a8cf1ad3c71dcbbb6c4799b1ab29e38f7f9", size = 55832, upload-time = "2024-11-05T19:14:40.446Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.27.0" +version = "1.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/9a/82a6ac0f06590f3d72241a587cb8b0b751bd98728e896cc4cbd4847248e6/opentelemetry_sdk-1.27.0.tar.gz", hash = "sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f", size = 145019, upload-time = "2024-08-28T21:35:46.708Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/5b/a509ccab93eacc6044591d5ec437d8266e76f893d0389bbf7e5592c7da32/opentelemetry_sdk-1.28.0.tar.gz", hash = "sha256:41d5420b2e3fb7716ff4981b510d551eff1fc60eb5a95cf7335b31166812a893", size = 156155, upload-time = "2024-11-05T19:15:00.451Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/bd/a6602e71e315055d63b2ff07172bd2d012b4cba2d4e00735d74ba42fc4d6/opentelemetry_sdk-1.27.0-py3-none-any.whl", hash = "sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d", size = 110505, upload-time = "2024-08-28T21:35:24.769Z" }, + { url = "https://files.pythonhosted.org/packages/c3/fe/c8decbebb5660529f1d6ba65e50a45b1294022dfcba2968fc9c8697c42b2/opentelemetry_sdk-1.28.0-py3-none-any.whl", hash = "sha256:4b37da81d7fad67f6683c4420288c97f4ed0d988845d5886435f428ec4b8429a", size = 118692, upload-time = "2024-11-05T19:14:41.669Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "opentelemetry-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/89/1724ad69f7411772446067cdfa73b598694c8c91f7f8c922e344d96d81f9/opentelemetry_semantic_conventions-0.48b0.tar.gz", hash = "sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a", size = 89445, upload-time = "2024-08-28T21:35:47.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/c8/433b0e54143f8c9369f5c4a7a83e73eec7eb2ee7d0b7e81a9243e78c8e80/opentelemetry_semantic_conventions-0.49b0.tar.gz", hash = "sha256:dbc7b28339e5390b6b28e022835f9bac4e134a80ebf640848306d3c5192557e8", size = 95227, upload-time = "2024-11-05T19:15:01.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/7a/4f0063dbb0b6c971568291a8bc19a4ca70d3c185db2d956230dd67429dfc/opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl", hash = "sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f", size = 149685, upload-time = "2024-08-28T21:35:25.983Z" }, + { url = "https://files.pythonhosted.org/packages/25/05/20104df4ef07d3bf5c3fd6bcc796ef70ab4ea4309378a9ba57bc4b4d01fa/opentelemetry_semantic_conventions-0.49b0-py3-none-any.whl", hash = "sha256:0458117f6ead0b12e3221813e3e511d85698c31901cac84682052adb9c17c7cd", size = 159214, upload-time = "2024-11-05T19:14:43.047Z" }, ] [[package]] name = "opentelemetry-util-http" -version = "0.48b0" +version = "0.49b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/d7/185c494754340e0a3928fd39fde2616ee78f2c9d66253affaad62d5b7935/opentelemetry_util_http-0.48b0.tar.gz", hash = "sha256:60312015153580cc20f322e5cdc3d3ecad80a71743235bdb77716e742814623c", size = 7863, upload-time = "2024-08-28T21:28:27.266Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/99/377ef446928808211b127b9ab31c348bc465c8da4514ebeec6e4a3de3d21/opentelemetry_util_http-0.49b0.tar.gz", hash = "sha256:02928496afcffd58a7c15baf99d2cedae9b8325a8ac52b0d0877b2e8f936dd1b", size = 7863, upload-time = "2024-11-05T19:22:26.973Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/2e/36097c0a4d0115b8c7e377c90bab7783ac183bc5cb4071308f8959454311/opentelemetry_util_http-0.48b0-py3-none-any.whl", hash = "sha256:76f598af93aab50328d2a69c786beaedc8b6a7770f7a818cc307eb353debfffb", size = 6946, upload-time = "2024-08-28T21:27:37.975Z" }, + { url = "https://files.pythonhosted.org/packages/66/0e/ab0a89b315d0bacdd355a345bb69b20c50fc1f0804b52b56fe1c35a60e68/opentelemetry_util_http-0.49b0-py3-none-any.whl", hash = "sha256:8661bbd6aea1839badc44de067ec9c15c05eab05f729f496c856c50a1203caf1", size = 6945, upload-time = "2024-11-05T19:21:37.81Z" }, ] [[package]] @@ -4695,16 +4726,16 @@ wheels = [ [[package]] name = "protobuf" -version = "4.25.8" +version = "5.29.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920, upload-time = "2025-05-28T14:22:25.153Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/57/394a763c103e0edf87f0938dafcd918d53b4c011dfc5c8ae80f3b0452dbb/protobuf-5.29.6.tar.gz", hash = "sha256:da9ee6a5424b6b30fd5e45c5ea663aef540ca95f9ad99d1e887e819cdf9b8723", size = 425623, upload-time = "2026-02-04T22:54:40.584Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745, upload-time = "2025-05-28T14:22:10.524Z" }, - { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736, upload-time = "2025-05-28T14:22:13.156Z" }, - { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537, upload-time = "2025-05-28T14:22:14.768Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005, upload-time = "2025-05-28T14:22:16.052Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924, upload-time = "2025-05-28T14:22:17.105Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757, upload-time = "2025-05-28T14:22:24.135Z" }, + { url = "https://files.pythonhosted.org/packages/d4/88/9ee58ff7863c479d6f8346686d4636dd4c415b0cbeed7a6a7d0617639c2a/protobuf-5.29.6-cp310-abi3-win32.whl", hash = "sha256:62e8a3114992c7c647bce37dcc93647575fc52d50e48de30c6fcb28a6a291eb1", size = 423357, upload-time = "2026-02-04T22:54:25.805Z" }, + { url = "https://files.pythonhosted.org/packages/1c/66/2dc736a4d576847134fb6d80bd995c569b13cdc7b815d669050bf0ce2d2c/protobuf-5.29.6-cp310-abi3-win_amd64.whl", hash = "sha256:7e6ad413275be172f67fdee0f43484b6de5a904cc1c3ea9804cb6fe2ff366eda", size = 435175, upload-time = "2026-02-04T22:54:28.592Z" }, + { url = "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5a169e664b4057183a34bdc424540e86eea47560f3c123a0d64de4e137f9269", size = 418619, upload-time = "2026-02-04T22:54:30.266Z" }, + { url = "https://files.pythonhosted.org/packages/b7/d7/48cbf6b0c3c39761e47a99cb483405f0fde2be22cf00d71ef316ce52b458/protobuf-5.29.6-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:a8866b2cff111f0f863c1b3b9e7572dc7eaea23a7fae27f6fc613304046483e6", size = 320284, upload-time = "2026-02-04T22:54:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/e3/dd/cadd6ec43069247d91f6345fa7a0d2858bef6af366dbd7ba8f05d2c77d3b/protobuf-5.29.6-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:e3387f44798ac1106af0233c04fb8abf543772ff241169946f698b3a9a3d3ab9", size = 320478, upload-time = "2026-02-04T22:54:32.909Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cb/e3065b447186cb70aa65acc70c86baf482d82bf75625bf5a2c4f6919c6a3/protobuf-5.29.6-py3-none-any.whl", hash = "sha256:6b9edb641441b2da9fa8f428760fc136a49cf97a52076010cf22a2ff73438a86", size = 173126, upload-time = "2026-02-04T22:54:39.462Z" }, ] [[package]] @@ -5810,33 +5841,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, ] -[[package]] -name = "shapely" -version = "2.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8d/1ff672dea9ec6a7b5d422eb6d095ed886e2e523733329f75fdcb14ee1149/shapely-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91121757b0a36c9aac3427a651a7e6567110a4a67c97edf04f8d55d4765f6618", size = 1820038, upload-time = "2025-09-24T13:50:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ce/28fab8c772ce5db23a0d86bf0adaee0c4c79d5ad1db766055fa3dab442e2/shapely-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16a9c722ba774cf50b5d4541242b4cce05aafd44a015290c82ba8a16931ff63d", size = 1626039, upload-time = "2025-09-24T13:50:16.881Z" }, - { url = "https://files.pythonhosted.org/packages/70/8b/868b7e3f4982f5006e9395c1e12343c66a8155c0374fdc07c0e6a1ab547d/shapely-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cc4f7397459b12c0b196c9efe1f9d7e92463cbba142632b4cc6d8bbbbd3e2b09", size = 3001519, upload-time = "2025-09-24T13:50:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:136ab87b17e733e22f0961504d05e77e7be8c9b5a8184f685b4a91a84efe3c26", size = 3110842, upload-time = "2025-09-24T13:50:21.77Z" }, - { url = "https://files.pythonhosted.org/packages/af/61/8e389c97994d5f331dcffb25e2fa761aeedfb52b3ad9bcdd7b8671f4810a/shapely-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:16c5d0fc45d3aa0a69074979f4f1928ca2734fb2e0dde8af9611e134e46774e7", size = 4021316, upload-time = "2025-09-24T13:50:23.626Z" }, - { url = "https://files.pythonhosted.org/packages/d3/d4/9b2a9fe6039f9e42ccf2cb3e84f219fd8364b0c3b8e7bbc857b5fbe9c14c/shapely-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ddc759f72b5b2b0f54a7e7cde44acef680a55019eb52ac63a7af2cf17cb9cd2", size = 4178586, upload-time = "2025-09-24T13:50:25.443Z" }, - { url = "https://files.pythonhosted.org/packages/16/f6/9840f6963ed4decf76b08fd6d7fed14f8779fb7a62cb45c5617fa8ac6eab/shapely-2.1.2-cp311-cp311-win32.whl", hash = "sha256:2fa78b49485391224755a856ed3b3bd91c8455f6121fee0db0e71cefb07d0ef6", size = 1543961, upload-time = "2025-09-24T13:50:26.968Z" }, - { url = "https://files.pythonhosted.org/packages/38/1e/3f8ea46353c2a33c1669eb7327f9665103aa3a8dfe7f2e4ef714c210b2c2/shapely-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:c64d5c97b2f47e3cd9b712eaced3b061f2b71234b3fc263e0fcf7d889c6559dc", size = 1722856, upload-time = "2025-09-24T13:50:28.497Z" }, - { url = "https://files.pythonhosted.org/packages/24/c0/f3b6453cf2dfa99adc0ba6675f9aaff9e526d2224cbd7ff9c1a879238693/shapely-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe2533caae6a91a543dec62e8360fe86ffcdc42a7c55f9dfd0128a977a896b94", size = 1833550, upload-time = "2025-09-24T13:50:30.019Z" }, - { url = "https://files.pythonhosted.org/packages/86/07/59dee0bc4b913b7ab59ab1086225baca5b8f19865e6101db9ebb7243e132/shapely-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ba4d1333cc0bc94381d6d4308d2e4e008e0bd128bdcff5573199742ee3634359", size = 1643556, upload-time = "2025-09-24T13:50:32.291Z" }, - { url = "https://files.pythonhosted.org/packages/26/29/a5397e75b435b9895cd53e165083faed5d12fd9626eadec15a83a2411f0f/shapely-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bd308103340030feef6c111d3eb98d50dc13feea33affc8a6f9fa549e9458a3", size = 2988308, upload-time = "2025-09-24T13:50:33.862Z" }, - { url = "https://files.pythonhosted.org/packages/b9/37/e781683abac55dde9771e086b790e554811a71ed0b2b8a1e789b7430dd44/shapely-2.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e7d4d7ad262a48bb44277ca12c7c78cb1b0f56b32c10734ec9a1d30c0b0c54b", size = 3099844, upload-time = "2025-09-24T13:50:35.459Z" }, - { url = "https://files.pythonhosted.org/packages/d8/f3/9876b64d4a5a321b9dc482c92bb6f061f2fa42131cba643c699f39317cb9/shapely-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9eddfe513096a71896441a7c37db72da0687b34752c4e193577a145c71736fc", size = 3988842, upload-time = "2025-09-24T13:50:37.478Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a0/704c7292f7014c7e74ec84eddb7b109e1fbae74a16deae9c1504b1d15565/shapely-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:980c777c612514c0cf99bc8a9de6d286f5e186dcaf9091252fcd444e5638193d", size = 4152714, upload-time = "2025-09-24T13:50:39.9Z" }, - { url = "https://files.pythonhosted.org/packages/53/46/319c9dc788884ad0785242543cdffac0e6530e4d0deb6c4862bc4143dcf3/shapely-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9111274b88e4d7b54a95218e243282709b330ef52b7b86bc6aaf4f805306f454", size = 1542745, upload-time = "2025-09-24T13:50:41.414Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bf/cb6c1c505cb31e818e900b9312d514f381fbfa5c4363edfce0fcc4f8c1a4/shapely-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:743044b4cfb34f9a67205cee9279feaf60ba7d02e69febc2afc609047cb49179", size = 1722861, upload-time = "2025-09-24T13:50:43.35Z" }, -] - [[package]] name = "shellingham" version = "1.5.4" From 5c7a293ba75220c609faed00a7b632e97b973903 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Mon, 2 Mar 2026 16:28:31 +0800 Subject: [PATCH 012/159] feat: ensure document id is not missing (#32765) --- api/core/rag/retrieval/dataset_retrieval.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index cfea8d114a..459d7bed95 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -248,19 +248,22 @@ class DatasetRetrieval: retrieval_resource_list = [] # deal with external documents for item in external_documents: + ext_meta = item.metadata or {} + title = ext_meta.get("title") or "" + doc_id = ext_meta.get("document_id") or title source = Source( metadata=SourceMetadata( source="knowledge", - dataset_id=item.metadata.get("dataset_id"), - dataset_name=item.metadata.get("dataset_name"), - document_id=item.metadata.get("document_id"), - document_name=item.metadata.get("title"), + dataset_id=ext_meta.get("dataset_id") or "", + dataset_name=ext_meta.get("dataset_name") or "", + document_id=str(doc_id), + document_name=ext_meta.get("title") or "", data_source_type="external", retriever_from="workflow", - score=item.metadata.get("score"), - doc_metadata=item.metadata, + score=float(ext_meta.get("score") or 0.0), + doc_metadata=ext_meta, ), - title=item.metadata.get("title"), + title=title, content=item.page_content, ) retrieval_resource_list.append(source) From 68647391e7a4e93c68fd0710f49b409105789c0f Mon Sep 17 00:00:00 2001 From: Br1an <932039080@qq.com> Date: Mon, 2 Mar 2026 16:51:21 +0800 Subject: [PATCH 013/159] fix(api): add return type annotation to filter_none_values() (#32774) --- api/core/ops/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/core/ops/utils.py b/api/core/ops/utils.py index a5196d66c0..8b9a2e424a 100644 --- a/api/core/ops/utils.py +++ b/api/core/ops/utils.py @@ -1,6 +1,6 @@ from contextlib import contextmanager from datetime import datetime -from typing import Union +from typing import Any, Union from urllib.parse import urlparse from sqlalchemy import select @@ -9,7 +9,7 @@ from models.engine import db from models.model import Message -def filter_none_values(data: dict): +def filter_none_values(data: dict[str, Any]) -> dict[str, Any]: new_data = {} for key, value in data.items(): if value is None: From 707bf20c296794d073da54f37514e38d3ec9f16b Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Mon, 2 Mar 2026 17:54:33 +0800 Subject: [PATCH 014/159] refactor: knowledge index node decouples business logic (#32274) --- api/.importlinter | 8 - api/core/app/workflow/node_factory.py | 13 + .../rag/index_processor/index_processor.py | 252 +++++++ api/core/rag/summary_index/__init__.py | 0 api/core/rag/summary_index/summary_index.py | 86 +++ .../knowledge_index/knowledge_index_node.py | 502 ++----------- .../repositories/index_processor_protocol.py | 41 ++ .../summary_index_service_protocol.py | 7 + .../nodes/knowledge_index/__init__.py | 0 .../test_knowledge_index_node_integration.py | 69 ++ .../nodes/knowledge_index/__init__.py | 0 .../test_knowledge_index_node.py | 663 ++++++++++++++++++ 12 files changed, 1196 insertions(+), 445 deletions(-) create mode 100644 api/core/rag/index_processor/index_processor.py create mode 100644 api/core/rag/summary_index/__init__.py create mode 100644 api/core/rag/summary_index/summary_index.py create mode 100644 api/core/workflow/repositories/index_processor_protocol.py create mode 100644 api/core/workflow/repositories/summary_index_service_protocol.py create mode 100644 api/tests/integration_tests/workflow/nodes/knowledge_index/__init__.py create mode 100644 api/tests/integration_tests/workflow/nodes/knowledge_index/test_knowledge_index_node_integration.py create mode 100644 api/tests/unit_tests/core/workflow/nodes/knowledge_index/__init__.py create mode 100644 api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py diff --git a/api/.importlinter b/api/.importlinter index f74a1b667d..28c853bb62 100644 --- a/api/.importlinter +++ b/api/.importlinter @@ -52,7 +52,6 @@ forbidden_modules = allow_indirect_imports = True ignore_imports = core.workflow.nodes.agent.agent_node -> extensions.ext_database - core.workflow.nodes.knowledge_index.knowledge_index_node -> extensions.ext_database core.workflow.nodes.llm.file_saver -> extensions.ext_database core.workflow.nodes.llm.node -> extensions.ext_database core.workflow.nodes.tool.tool_node -> extensions.ext_database @@ -109,7 +108,6 @@ ignore_imports = core.workflow.nodes.document_extractor.node -> core.helper.ssrf_proxy core.workflow.nodes.iteration.iteration_node -> core.app.workflow.node_factory core.workflow.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota - core.workflow.nodes.knowledge_index.knowledge_index_node -> core.rag.index_processor.index_processor_factory core.workflow.nodes.llm.llm_utils -> core.model_manager core.workflow.nodes.llm.protocols -> core.model_manager core.workflow.nodes.llm.llm_utils -> core.model_runtime.model_providers.__base.large_language_model @@ -154,18 +152,12 @@ ignore_imports = core.workflow.nodes.question_classifier.entities -> core.prompt.entities.advanced_prompt_entities core.workflow.nodes.question_classifier.question_classifier_node -> core.prompt.utils.prompt_message_util core.workflow.nodes.knowledge_index.entities -> core.rag.retrieval.retrieval_methods - core.workflow.nodes.knowledge_index.knowledge_index_node -> core.rag.retrieval.retrieval_methods - core.workflow.nodes.knowledge_index.knowledge_index_node -> models.dataset - core.workflow.nodes.knowledge_index.knowledge_index_node -> services.summary_index_service - core.workflow.nodes.knowledge_index.knowledge_index_node -> tasks.generate_summary_index_task - core.workflow.nodes.knowledge_index.knowledge_index_node -> core.rag.index_processor.processor.paragraph_index_processor core.workflow.nodes.llm.node -> models.dataset core.workflow.nodes.agent.agent_node -> core.tools.utils.message_transformer core.workflow.nodes.llm.file_saver -> core.tools.signature core.workflow.nodes.llm.file_saver -> core.tools.tool_file_manager core.workflow.nodes.tool.tool_node -> core.tools.errors core.workflow.nodes.agent.agent_node -> extensions.ext_database - core.workflow.nodes.knowledge_index.knowledge_index_node -> extensions.ext_database core.workflow.nodes.llm.file_saver -> extensions.ext_database core.workflow.nodes.llm.node -> extensions.ext_database core.workflow.nodes.tool.tool_node -> extensions.ext_database diff --git a/api/core/app/workflow/node_factory.py b/api/core/app/workflow/node_factory.py index 3a82f0a45e..9a56f0fb0d 100644 --- a/api/core/app/workflow/node_factory.py +++ b/api/core/app/workflow/node_factory.py @@ -19,7 +19,9 @@ from core.model_runtime.entities.model_entities import ModelType from core.model_runtime.memory import PromptMessageMemory from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.prompt.entities.advanced_prompt_entities import MemoryConfig +from core.rag.index_processor.index_processor import IndexProcessor from core.rag.retrieval.dataset_retrieval import DatasetRetrieval +from core.rag.summary_index.summary_index import SummaryIndex from core.tools.tool_file_manager import ToolFileManager from core.workflow.entities.graph_config import NodeConfigDict from core.workflow.enums import NodeType, SystemVariableKey @@ -32,6 +34,7 @@ from core.workflow.nodes.code.limits import CodeNodeLimits from core.workflow.nodes.datasource import DatasourceNode from core.workflow.nodes.document_extractor import DocumentExtractorNode, UnstructuredApiConfig from core.workflow.nodes.http_request import HttpRequestNode, build_http_request_config +from core.workflow.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode from core.workflow.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode from core.workflow.nodes.llm.entities import ModelConfig from core.workflow.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError @@ -202,6 +205,16 @@ class DifyNodeFactory(NodeFactory): file_manager=self._http_request_file_manager, ) + if node_type == NodeType.KNOWLEDGE_INDEX: + return KnowledgeIndexNode( + id=node_id, + config=node_config, + graph_init_params=self.graph_init_params, + graph_runtime_state=self.graph_runtime_state, + index_processor=IndexProcessor(), + summary_index_service=SummaryIndex(), + ) + if node_type == NodeType.LLM: model_instance = self._build_model_instance_for_llm_node(node_data) memory = self._build_memory_for_llm_node(node_data=node_data, model_instance=model_instance) diff --git a/api/core/rag/index_processor/index_processor.py b/api/core/rag/index_processor/index_processor.py new file mode 100644 index 0000000000..95b197c874 --- /dev/null +++ b/api/core/rag/index_processor/index_processor.py @@ -0,0 +1,252 @@ +import concurrent.futures +import datetime +import logging +import time +from collections.abc import Mapping +from typing import Any + +from flask import current_app +from sqlalchemy import delete, func, select + +from core.db.session_factory import session_factory +from core.workflow.nodes.knowledge_index.exc import KnowledgeIndexNodeError +from core.workflow.repositories.index_processor_protocol import Preview, PreviewItem, QaPreview +from models.dataset import Dataset, Document, DocumentSegment + +from .index_processor_factory import IndexProcessorFactory +from .processor.paragraph_index_processor import ParagraphIndexProcessor + +logger = logging.getLogger(__name__) + + +class IndexProcessor: + def format_preview(self, chunk_structure: str, chunks: Any) -> Preview: + index_processor = IndexProcessorFactory(chunk_structure).init_index_processor() + preview = index_processor.format_preview(chunks) + data = Preview( + chunk_structure=preview["chunk_structure"], + total_segments=preview["total_segments"], + preview=[], + parent_mode=None, + qa_preview=[], + ) + if "parent_mode" in preview: + data.parent_mode = preview["parent_mode"] + + for item in preview["preview"]: + if "content" in item and "child_chunks" in item: + data.preview.append( + PreviewItem(content=item["content"], child_chunks=item["child_chunks"], summary=None) + ) + elif "question" in item and "answer" in item: + data.qa_preview.append(QaPreview(question=item["question"], answer=item["answer"])) + elif "content" in item: + data.preview.append(PreviewItem(content=item["content"], child_chunks=None, summary=None)) + return data + + def index_and_clean( + self, + dataset_id: str, + document_id: str, + original_document_id: str, + chunks: Mapping[str, Any], + batch: Any, + summary_index_setting: dict | None = None, + ): + with session_factory.create_session() as session: + document = session.query(Document).filter_by(id=document_id).first() + if not document: + raise KnowledgeIndexNodeError(f"Document {document_id} not found.") + + dataset = session.query(Dataset).filter_by(id=dataset_id).first() + if not dataset: + raise KnowledgeIndexNodeError(f"Dataset {dataset_id} not found.") + + dataset_name_value = dataset.name + document_name_value = document.name + created_at_value = document.created_at + if summary_index_setting is None: + summary_index_setting = dataset.summary_index_setting + index_node_ids = [] + + index_processor = IndexProcessorFactory(dataset.chunk_structure).init_index_processor() + if original_document_id: + segments = session.scalars( + select(DocumentSegment).where(DocumentSegment.document_id == original_document_id) + ).all() + if segments: + index_node_ids = [segment.index_node_id for segment in segments] + + indexing_start_at = time.perf_counter() + # delete from vector index + if index_node_ids: + index_processor.clean(dataset, index_node_ids, with_keywords=True, delete_child_chunks=True) + + with session_factory.create_session() as session, session.begin(): + if index_node_ids: + segment_delete_stmt = delete(DocumentSegment).where(DocumentSegment.document_id == original_document_id) + session.execute(segment_delete_stmt) + + index_processor.index(dataset, document, chunks) + indexing_end_at = time.perf_counter() + + with session_factory.create_session() as session, session.begin(): + document.indexing_latency = indexing_end_at - indexing_start_at + document.indexing_status = "completed" + document.completed_at = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) + document.word_count = ( + session.query(func.sum(DocumentSegment.word_count)) + .where( + DocumentSegment.document_id == document_id, + DocumentSegment.dataset_id == dataset_id, + ) + .scalar() + ) or 0 + # Update need_summary based on dataset's summary_index_setting + if summary_index_setting and summary_index_setting.get("enable") is True: + document.need_summary = True + else: + document.need_summary = False + session.add(document) + # update document segment status + session.query(DocumentSegment).where( + DocumentSegment.document_id == document_id, + DocumentSegment.dataset_id == dataset_id, + ).update( + { + DocumentSegment.status: "completed", + DocumentSegment.enabled: True, + DocumentSegment.completed_at: datetime.datetime.now(datetime.UTC).replace(tzinfo=None), + } + ) + + return { + "dataset_id": dataset_id, + "dataset_name": dataset_name_value, + "batch": batch, + "document_id": document_id, + "document_name": document_name_value, + "created_at": created_at_value.timestamp(), + "display_status": "completed", + } + + def get_preview_output( + self, chunks: Any, dataset_id: str, document_id: str, chunk_structure: str, summary_index_setting: dict | None + ) -> Preview: + doc_language = None + with session_factory.create_session() as session: + if document_id: + document = session.query(Document).filter_by(id=document_id).first() + else: + document = None + + dataset = session.query(Dataset).filter_by(id=dataset_id).first() + if not dataset: + raise KnowledgeIndexNodeError(f"Dataset {dataset_id} not found.") + + if summary_index_setting is None: + summary_index_setting = dataset.summary_index_setting + + if document: + doc_language = document.doc_language + indexing_technique = dataset.indexing_technique + tenant_id = dataset.tenant_id + + preview_output = self.format_preview(chunk_structure, chunks) + if indexing_technique != "high_quality": + return preview_output + + if not summary_index_setting or not summary_index_setting.get("enable"): + return preview_output + + if preview_output.preview is not None: + chunk_count = len(preview_output.preview) + logger.info( + "Generating summaries for %s chunks in preview mode (dataset: %s)", + chunk_count, + dataset_id, + ) + + flask_app = None + try: + flask_app = current_app._get_current_object() # type: ignore + except RuntimeError: + logger.warning("No Flask application context available, summary generation may fail") + + def generate_summary_for_chunk(preview_item: PreviewItem) -> None: + """Generate summary for a single chunk.""" + if flask_app: + with flask_app.app_context(): + if preview_item.content is not None: + # Set Flask application context in worker thread + summary, _ = ParagraphIndexProcessor.generate_summary( + tenant_id=tenant_id, + text=preview_item.content, + summary_index_setting=summary_index_setting, + document_language=doc_language, + ) + if summary: + preview_item.summary = summary + + else: + summary, _ = ParagraphIndexProcessor.generate_summary( + tenant_id=tenant_id, + text=preview_item.content if preview_item.content is not None else "", + summary_index_setting=summary_index_setting, + document_language=doc_language, + ) + if summary: + preview_item.summary = summary + + # Generate summaries concurrently using ThreadPoolExecutor + # Set a reasonable timeout to prevent hanging (60 seconds per chunk, max 5 minutes total) + timeout_seconds = min(300, 60 * len(preview_output.preview)) + errors: list[Exception] = [] + + with concurrent.futures.ThreadPoolExecutor(max_workers=min(10, len(preview_output.preview))) as executor: + futures = [ + executor.submit(generate_summary_for_chunk, preview_item) for preview_item in preview_output.preview + ] + # Wait for all tasks to complete with timeout + done, not_done = concurrent.futures.wait(futures, timeout=timeout_seconds) + + # Cancel tasks that didn't complete in time + if not_done: + timeout_error_msg = ( + f"Summary generation timeout: {len(not_done)} chunks did not complete within {timeout_seconds}s" + ) + logger.warning("%s. Cancelling remaining tasks...", timeout_error_msg) + # In preview mode, timeout is also an error + errors.append(TimeoutError(timeout_error_msg)) + for future in not_done: + future.cancel() + # Wait a bit for cancellation to take effect + concurrent.futures.wait(not_done, timeout=5) + + # Collect exceptions from completed futures + for future in done: + try: + future.result() # This will raise any exception that occurred + except Exception as e: + logger.exception("Error in summary generation future") + errors.append(e) + + # In preview mode, if there are any errors, fail the request + if errors: + error_messages = [str(e) for e in errors] + error_summary = ( + f"Failed to generate summaries for {len(errors)} chunk(s). " + f"Errors: {'; '.join(error_messages[:3])}" # Show first 3 errors + ) + if len(errors) > 3: + error_summary += f" (and {len(errors) - 3} more)" + logger.error("Summary generation failed in preview mode: %s", error_summary) + raise KnowledgeIndexNodeError(error_summary) + + completed_count = sum(1 for item in preview_output.preview if item.summary is not None) + logger.info( + "Completed summary generation for preview chunks: %s/%s succeeded", + completed_count, + len(preview_output.preview), + ) + return preview_output diff --git a/api/core/rag/summary_index/__init__.py b/api/core/rag/summary_index/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/core/rag/summary_index/summary_index.py b/api/core/rag/summary_index/summary_index.py new file mode 100644 index 0000000000..79d7821b4e --- /dev/null +++ b/api/core/rag/summary_index/summary_index.py @@ -0,0 +1,86 @@ +import concurrent.futures +import logging + +from core.db.session_factory import session_factory +from models.dataset import Dataset, Document, DocumentSegment, DocumentSegmentSummary +from services.summary_index_service import SummaryIndexService +from tasks.generate_summary_index_task import generate_summary_index_task + +logger = logging.getLogger(__name__) + + +class SummaryIndex: + def generate_and_vectorize_summary( + self, dataset_id: str, document_id: str, is_preview: bool, summary_index_setting: dict | None = None + ) -> None: + if is_preview: + with session_factory.create_session() as session: + dataset = session.query(Dataset).filter_by(id=dataset_id).first() + if not dataset or dataset.indexing_technique != "high_quality": + return + + if summary_index_setting is None: + summary_index_setting = dataset.summary_index_setting + + if not summary_index_setting or not summary_index_setting.get("enable"): + return + + if not document_id: + return + + document = session.query(Document).filter_by(id=document_id).first() + # Skip qa_model documents + if document is None or document.doc_form == "qa_model": + return + + query = session.query(DocumentSegment).filter_by( + dataset_id=dataset_id, + document_id=document_id, + status="completed", + enabled=True, + ) + segments = query.all() + segment_ids = [segment.id for segment in segments] + + if not segment_ids: + return + + existing_summaries = ( + session.query(DocumentSegmentSummary) + .filter( + DocumentSegmentSummary.chunk_id.in_(segment_ids), + DocumentSegmentSummary.dataset_id == dataset_id, + DocumentSegmentSummary.status == "completed", + ) + .all() + ) + completed_summary_segment_ids = {i.chunk_id for i in existing_summaries} + # Preview mode should process segments that are MISSING completed summaries + pending_segment_ids = [sid for sid in segment_ids if sid not in completed_summary_segment_ids] + + # If all segments already have completed summaries, nothing to do in preview mode + if not pending_segment_ids: + return + + max_workers = min(10, len(pending_segment_ids)) + + def process_segment(segment_id: str) -> None: + """Process a single segment in a thread with a fresh DB session.""" + with session_factory.create_session() as session: + segment = session.query(DocumentSegment).filter_by(id=segment_id).first() + if segment is None: + return + try: + SummaryIndexService.generate_and_vectorize_summary(segment, dataset, summary_index_setting) + except Exception: + logger.exception( + "Failed to generate summary for segment %s", + segment_id, + ) + # Continue processing other segments + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [executor.submit(process_segment, segment_id) for segment_id in pending_segment_ids] + concurrent.futures.wait(futures) + else: + generate_summary_index_task.delay(dataset_id, document_id, None) diff --git a/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py b/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py index 2aff953bc6..8fb5b99454 100644 --- a/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py +++ b/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py @@ -1,66 +1,66 @@ -import concurrent.futures -import datetime import logging -import time from collections.abc import Mapping -from typing import Any - -from flask import current_app -from sqlalchemy import func, select +from typing import TYPE_CHECKING, Any from core.app.entities.app_invoke_entities import InvokeFrom -from core.rag.index_processor.index_processor_factory import IndexProcessorFactory -from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import NodeExecutionType, NodeType, SystemVariableKey from core.workflow.node_events import NodeRunResult from core.workflow.nodes.base.node import Node from core.workflow.nodes.base.template import Template -from core.workflow.runtime import VariablePool -from extensions.ext_database import db -from models.dataset import Dataset, Document, DocumentSegment, DocumentSegmentSummary -from services.summary_index_service import SummaryIndexService -from tasks.generate_summary_index_task import generate_summary_index_task +from core.workflow.repositories.index_processor_protocol import IndexProcessorProtocol +from core.workflow.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol from .entities import KnowledgeIndexNodeData from .exc import ( KnowledgeIndexNodeError, ) -logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from core.workflow.entities import GraphInitParams + from core.workflow.runtime import GraphRuntimeState -default_retrieval_model = { - "search_method": RetrievalMethod.SEMANTIC_SEARCH, - "reranking_enable": False, - "reranking_model": {"reranking_provider_name": "", "reranking_model_name": ""}, - "top_k": 2, - "score_threshold_enabled": False, -} +logger = logging.getLogger(__name__) class KnowledgeIndexNode(Node[KnowledgeIndexNodeData]): node_type = NodeType.KNOWLEDGE_INDEX execution_type = NodeExecutionType.RESPONSE + def __init__( + self, + id: str, + config: Mapping[str, Any], + graph_init_params: "GraphInitParams", + graph_runtime_state: "GraphRuntimeState", + index_processor: IndexProcessorProtocol, + summary_index_service: SummaryIndexServiceProtocol, + ) -> None: + super().__init__(id, config, graph_init_params, graph_runtime_state) + self.index_processor = index_processor + self.summary_index_service = summary_index_service + def _run(self) -> NodeRunResult: # type: ignore node_data = self.node_data variable_pool = self.graph_runtime_state.variable_pool - dataset_id = variable_pool.get(["sys", SystemVariableKey.DATASET_ID]) - if not dataset_id: + + # get dataset id as string + dataset_id_segment = variable_pool.get(["sys", SystemVariableKey.DATASET_ID]) + if not dataset_id_segment: raise KnowledgeIndexNodeError("Dataset ID is required.") - dataset = db.session.query(Dataset).filter_by(id=dataset_id.value).first() - if not dataset: - raise KnowledgeIndexNodeError(f"Dataset {dataset_id.value} not found.") + dataset_id: str = dataset_id_segment.value + + # get document id as string (may be empty when not provided) + document_id_segment = variable_pool.get(["sys", SystemVariableKey.DOCUMENT_ID]) + document_id: str = document_id_segment.value if document_id_segment else "" # extract variables variable = variable_pool.get(node_data.index_chunk_variable_selector) if not variable: raise KnowledgeIndexNodeError("Index chunk variable is required.") invoke_from = variable_pool.get(["sys", SystemVariableKey.INVOKE_FROM]) - if invoke_from: - is_preview = invoke_from.value == InvokeFrom.DEBUGGER - else: - is_preview = False + is_preview = invoke_from.value == InvokeFrom.DEBUGGER if invoke_from else False + chunks = variable.value variables = {"chunks": chunks} if not chunks: @@ -68,52 +68,49 @@ class KnowledgeIndexNode(Node[KnowledgeIndexNodeData]): status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, error="Chunks is required." ) - # index knowledge try: + summary_index_setting = node_data.summary_index_setting if is_preview: # Preview mode: generate summaries for chunks directly without saving to database # Format preview and generate summaries on-the-fly # Get indexing_technique and summary_index_setting from node_data (workflow graph config) # or fallback to dataset if not available in node_data - indexing_technique = node_data.indexing_technique or dataset.indexing_technique - summary_index_setting = node_data.summary_index_setting or dataset.summary_index_setting - # Try to get document language if document_id is available - doc_language = None - document_id = variable_pool.get(["sys", SystemVariableKey.DOCUMENT_ID]) - if document_id: - document = db.session.query(Document).filter_by(id=document_id.value).first() - if document and document.doc_language: - doc_language = document.doc_language - - outputs = self._get_preview_output_with_summaries( - node_data.chunk_structure, - chunks, - dataset=dataset, - indexing_technique=indexing_technique, - summary_index_setting=summary_index_setting, - doc_language=doc_language, + outputs = self.index_processor.get_preview_output( + chunks, dataset_id, document_id, node_data.chunk_structure, summary_index_setting ) return NodeRunResult( status=WorkflowNodeExecutionStatus.SUCCEEDED, inputs=variables, - outputs=outputs, + outputs=outputs.model_dump(exclude_none=True), ) + + original_document_id_segment = variable_pool.get(["sys", SystemVariableKey.ORIGINAL_DOCUMENT_ID]) + batch = variable_pool.get(["sys", SystemVariableKey.BATCH]) + if not batch: + raise KnowledgeIndexNodeError("Batch is required.") + results = self._invoke_knowledge_index( - dataset=dataset, node_data=node_data, chunks=chunks, variable_pool=variable_pool + dataset_id=dataset_id, + document_id=document_id, + original_document_id=original_document_id_segment.value if original_document_id_segment else "", + is_preview=is_preview, + batch=batch.value, + chunks=chunks, + summary_index_setting=summary_index_setting, ) return NodeRunResult(status=WorkflowNodeExecutionStatus.SUCCEEDED, inputs=variables, outputs=results) except KnowledgeIndexNodeError as e: - logger.warning("Error when running knowledge index node") + logger.warning("Error when running knowledge index node", exc_info=True) return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, error=str(e), error_type=type(e).__name__, ) - # Temporary handle all exceptions from DatasetRetrieval class here. except Exception as e: + logger.error(e, exc_info=True) return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, @@ -123,392 +120,23 @@ class KnowledgeIndexNode(Node[KnowledgeIndexNodeData]): def _invoke_knowledge_index( self, - dataset: Dataset, - node_data: KnowledgeIndexNodeData, + dataset_id: str, + document_id: str, + original_document_id: str, + is_preview: bool, + batch: Any, chunks: Mapping[str, Any], - variable_pool: VariablePool, - ) -> Any: - document_id = variable_pool.get(["sys", SystemVariableKey.DOCUMENT_ID]) - if not document_id: - raise KnowledgeIndexNodeError("Document ID is required.") - original_document_id = variable_pool.get(["sys", SystemVariableKey.ORIGINAL_DOCUMENT_ID]) - - batch = variable_pool.get(["sys", SystemVariableKey.BATCH]) - if not batch: - raise KnowledgeIndexNodeError("Batch is required.") - document = db.session.query(Document).filter_by(id=document_id.value).first() - if not document: - raise KnowledgeIndexNodeError(f"Document {document_id.value} not found.") - doc_id_value = document.id - ds_id_value = dataset.id - dataset_name_value = dataset.name - document_name_value = document.name - created_at_value = document.created_at - # chunk nodes by chunk size - indexing_start_at = time.perf_counter() - index_processor = IndexProcessorFactory(dataset.chunk_structure).init_index_processor() - if original_document_id: - segments = db.session.scalars( - select(DocumentSegment).where(DocumentSegment.document_id == original_document_id.value) - ).all() - if segments: - index_node_ids = [segment.index_node_id for segment in segments] - - # delete from vector index - index_processor.clean(dataset, index_node_ids, with_keywords=True, delete_child_chunks=True) - - for segment in segments: - db.session.delete(segment) - db.session.commit() - index_processor.index(dataset, document, chunks) - indexing_end_at = time.perf_counter() - document.indexing_latency = indexing_end_at - indexing_start_at - # update document status - document.indexing_status = "completed" - document.completed_at = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - document.word_count = ( - db.session.query(func.sum(DocumentSegment.word_count)) - .where( - DocumentSegment.document_id == doc_id_value, - DocumentSegment.dataset_id == ds_id_value, - ) - .scalar() - ) - # Update need_summary based on dataset's summary_index_setting - if dataset.summary_index_setting and dataset.summary_index_setting.get("enable") is True: - document.need_summary = True - else: - document.need_summary = False - db.session.add(document) - # update document segment status - db.session.query(DocumentSegment).where( - DocumentSegment.document_id == doc_id_value, - DocumentSegment.dataset_id == ds_id_value, - ).update( - { - DocumentSegment.status: "completed", - DocumentSegment.enabled: True, - DocumentSegment.completed_at: datetime.datetime.now(datetime.UTC).replace(tzinfo=None), - } - ) - - db.session.commit() - - # Generate summary index if enabled - self._handle_summary_index_generation(dataset, document, variable_pool) - - return { - "dataset_id": ds_id_value, - "dataset_name": dataset_name_value, - "batch": batch.value, - "document_id": doc_id_value, - "document_name": document_name_value, - "created_at": created_at_value.timestamp(), - "display_status": "completed", - } - - def _handle_summary_index_generation( - self, - dataset: Dataset, - document: Document, - variable_pool: VariablePool, - ) -> None: - """ - Handle summary index generation based on mode (debug/preview or production). - - Args: - dataset: Dataset containing the document - document: Document to generate summaries for - variable_pool: Variable pool to check invoke_from - """ - # Only generate summary index for high_quality indexing technique - if dataset.indexing_technique != "high_quality": - return - - # Check if summary index is enabled - summary_index_setting = dataset.summary_index_setting - if not summary_index_setting or not summary_index_setting.get("enable"): - return - - # Skip qa_model documents - if document.doc_form == "qa_model": - return - - # Determine if in preview/debug mode - invoke_from = variable_pool.get(["sys", SystemVariableKey.INVOKE_FROM]) - is_preview = invoke_from and invoke_from.value == InvokeFrom.DEBUGGER - - if is_preview: - try: - # Query segments that need summary generation - query = db.session.query(DocumentSegment).filter_by( - dataset_id=dataset.id, - document_id=document.id, - status="completed", - enabled=True, - ) - segments = query.all() - - if not segments: - logger.info("No segments found for document %s", document.id) - return - - # Filter segments based on mode - segments_to_process = [] - for segment in segments: - # Skip if summary already exists - existing_summary = ( - db.session.query(DocumentSegmentSummary) - .filter_by(chunk_id=segment.id, dataset_id=dataset.id, status="completed") - .first() - ) - if existing_summary: - continue - - # For parent-child mode, all segments are parent chunks, so process all - segments_to_process.append(segment) - - if not segments_to_process: - logger.info("No segments need summary generation for document %s", document.id) - return - - # Use ThreadPoolExecutor for concurrent generation - flask_app = current_app._get_current_object() # type: ignore - max_workers = min(10, len(segments_to_process)) # Limit to 10 workers - - def process_segment(segment: DocumentSegment) -> None: - """Process a single segment in a thread with Flask app context.""" - with flask_app.app_context(): - try: - SummaryIndexService.generate_and_vectorize_summary(segment, dataset, summary_index_setting) - except Exception: - logger.exception( - "Failed to generate summary for segment %s", - segment.id, - ) - # Continue processing other segments - - with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = [executor.submit(process_segment, segment) for segment in segments_to_process] - # Wait for all tasks to complete - concurrent.futures.wait(futures) - - logger.info( - "Successfully generated summary index for %s segments in document %s", - len(segments_to_process), - document.id, - ) - except Exception: - logger.exception("Failed to generate summary index for document %s", document.id) - # Don't fail the entire indexing process if summary generation fails - else: - # Production mode: asynchronous generation - logger.info( - "Queuing summary index generation task for document %s (production mode)", - document.id, - ) - try: - generate_summary_index_task.delay(dataset.id, document.id, None) - logger.info("Summary index generation task queued for document %s", document.id) - except Exception: - logger.exception( - "Failed to queue summary index generation task for document %s", - document.id, - ) - # Don't fail the entire indexing process if task queuing fails - - def _get_preview_output_with_summaries( - self, - chunk_structure: str, - chunks: Any, - dataset: Dataset, - indexing_technique: str | None = None, summary_index_setting: dict | None = None, - doc_language: str | None = None, - ) -> Mapping[str, Any]: - """ - Generate preview output with summaries for chunks in preview mode. - This method generates summaries on-the-fly without saving to database. - - Args: - chunk_structure: Chunk structure type - chunks: Chunks to generate preview for - dataset: Dataset object (for tenant_id) - indexing_technique: Indexing technique from node config or dataset - summary_index_setting: Summary index setting from node config or dataset - doc_language: Optional document language to ensure summary is generated in the correct language - """ - index_processor = IndexProcessorFactory(chunk_structure).init_index_processor() - preview_output = index_processor.format_preview(chunks) - - # Check if summary index is enabled - if indexing_technique != "high_quality": - return preview_output - - if not summary_index_setting or not summary_index_setting.get("enable"): - return preview_output - - # Generate summaries for chunks - if "preview" in preview_output and isinstance(preview_output["preview"], list): - chunk_count = len(preview_output["preview"]) - logger.info( - "Generating summaries for %s chunks in preview mode (dataset: %s)", - chunk_count, - dataset.id, - ) - # Use ParagraphIndexProcessor's generate_summary method - from core.rag.index_processor.processor.paragraph_index_processor import ParagraphIndexProcessor - - # Get Flask app for application context in worker threads - flask_app = None - try: - flask_app = current_app._get_current_object() # type: ignore - except RuntimeError: - logger.warning("No Flask application context available, summary generation may fail") - - def generate_summary_for_chunk(preview_item: dict) -> None: - """Generate summary for a single chunk.""" - if "content" in preview_item: - # Set Flask application context in worker thread - if flask_app: - with flask_app.app_context(): - summary, _ = ParagraphIndexProcessor.generate_summary( - tenant_id=dataset.tenant_id, - text=preview_item["content"], - summary_index_setting=summary_index_setting, - document_language=doc_language, - ) - if summary: - preview_item["summary"] = summary - else: - # Fallback: try without app context (may fail) - summary, _ = ParagraphIndexProcessor.generate_summary( - tenant_id=dataset.tenant_id, - text=preview_item["content"], - summary_index_setting=summary_index_setting, - document_language=doc_language, - ) - if summary: - preview_item["summary"] = summary - - # Generate summaries concurrently using ThreadPoolExecutor - # Set a reasonable timeout to prevent hanging (60 seconds per chunk, max 5 minutes total) - timeout_seconds = min(300, 60 * len(preview_output["preview"])) - errors: list[Exception] = [] - - with concurrent.futures.ThreadPoolExecutor(max_workers=min(10, len(preview_output["preview"]))) as executor: - futures = [ - executor.submit(generate_summary_for_chunk, preview_item) - for preview_item in preview_output["preview"] - ] - # Wait for all tasks to complete with timeout - done, not_done = concurrent.futures.wait(futures, timeout=timeout_seconds) - - # Cancel tasks that didn't complete in time - if not_done: - timeout_error_msg = ( - f"Summary generation timeout: {len(not_done)} chunks did not complete within {timeout_seconds}s" - ) - logger.warning("%s. Cancelling remaining tasks...", timeout_error_msg) - # In preview mode, timeout is also an error - errors.append(TimeoutError(timeout_error_msg)) - for future in not_done: - future.cancel() - # Wait a bit for cancellation to take effect - concurrent.futures.wait(not_done, timeout=5) - - # Collect exceptions from completed futures - for future in done: - try: - future.result() # This will raise any exception that occurred - except Exception as e: - logger.exception("Error in summary generation future") - errors.append(e) - - # In preview mode, if there are any errors, fail the request - if errors: - error_messages = [str(e) for e in errors] - error_summary = ( - f"Failed to generate summaries for {len(errors)} chunk(s). " - f"Errors: {'; '.join(error_messages[:3])}" # Show first 3 errors - ) - if len(errors) > 3: - error_summary += f" (and {len(errors) - 3} more)" - logger.error("Summary generation failed in preview mode: %s", error_summary) - raise KnowledgeIndexNodeError(error_summary) - - completed_count = sum(1 for item in preview_output["preview"] if item.get("summary") is not None) - logger.info( - "Completed summary generation for preview chunks: %s/%s succeeded", - completed_count, - len(preview_output["preview"]), - ) - - return preview_output - - def _get_preview_output( - self, - chunk_structure: str, - chunks: Any, - dataset: Dataset | None = None, - variable_pool: VariablePool | None = None, - ) -> Mapping[str, Any]: - index_processor = IndexProcessorFactory(chunk_structure).init_index_processor() - preview_output = index_processor.format_preview(chunks) - - # If dataset is provided, try to enrich preview with summaries - if dataset and variable_pool: - document_id = variable_pool.get(["sys", SystemVariableKey.DOCUMENT_ID]) - if document_id: - document = db.session.query(Document).filter_by(id=document_id.value).first() - if document: - # Query summaries for this document - summaries = ( - db.session.query(DocumentSegmentSummary) - .filter_by( - dataset_id=dataset.id, - document_id=document.id, - status="completed", - enabled=True, - ) - .all() - ) - - if summaries: - # Create a map of segment content to summary for matching - # Use content matching as chunks in preview might not be indexed yet - summary_by_content = {} - for summary in summaries: - segment = ( - db.session.query(DocumentSegment) - .filter_by(id=summary.chunk_id, dataset_id=dataset.id) - .first() - ) - if segment: - # Normalize content for matching (strip whitespace) - normalized_content = segment.content.strip() - summary_by_content[normalized_content] = summary.summary_content - - # Enrich preview with summaries by content matching - if "preview" in preview_output and isinstance(preview_output["preview"], list): - matched_count = 0 - for preview_item in preview_output["preview"]: - if "content" in preview_item: - # Normalize content for matching - normalized_chunk_content = preview_item["content"].strip() - if normalized_chunk_content in summary_by_content: - preview_item["summary"] = summary_by_content[normalized_chunk_content] - matched_count += 1 - - if matched_count > 0: - logger.info( - "Enriched preview with %s existing summaries (dataset: %s, document: %s)", - matched_count, - dataset.id, - document.id, - ) - - return preview_output + ): + if not document_id: + raise KnowledgeIndexNodeError("document_id is required.") + rst = self.index_processor.index_and_clean( + dataset_id, document_id, original_document_id, chunks, batch, summary_index_setting + ) + self.summary_index_service.generate_and_vectorize_summary( + dataset_id, document_id, is_preview, summary_index_setting + ) + return rst @classmethod def version(cls) -> str: diff --git a/api/core/workflow/repositories/index_processor_protocol.py b/api/core/workflow/repositories/index_processor_protocol.py new file mode 100644 index 0000000000..feaa4ab5de --- /dev/null +++ b/api/core/workflow/repositories/index_processor_protocol.py @@ -0,0 +1,41 @@ +from collections.abc import Mapping +from typing import Any, Protocol + +from pydantic import BaseModel, Field + + +class PreviewItem(BaseModel): + content: str | None = Field(None) + child_chunks: list[str] | None = Field(None) + summary: str | None = Field(None) + + +class QaPreview(BaseModel): + answer: str | None = Field(None) + question: str | None = Field(None) + + +class Preview(BaseModel): + chunk_structure: str + parent_mode: str | None = Field(None) + preview: list[PreviewItem] = Field([]) + qa_preview: list[QaPreview] = Field([]) + total_segments: int + + +class IndexProcessorProtocol(Protocol): + def format_preview(self, chunk_structure: str, chunks: Any) -> Preview: ... + + def index_and_clean( + self, + dataset_id: str, + document_id: str, + original_document_id: str, + chunks: Mapping[str, Any], + batch: Any, + summary_index_setting: dict | None = None, + ) -> dict[str, Any]: ... + + def get_preview_output( + self, chunks: Any, dataset_id: str, document_id: str, chunk_structure: str, summary_index_setting: dict | None + ) -> Preview: ... diff --git a/api/core/workflow/repositories/summary_index_service_protocol.py b/api/core/workflow/repositories/summary_index_service_protocol.py new file mode 100644 index 0000000000..cbcfdd2a77 --- /dev/null +++ b/api/core/workflow/repositories/summary_index_service_protocol.py @@ -0,0 +1,7 @@ +from typing import Protocol + + +class SummaryIndexServiceProtocol(Protocol): + def generate_and_vectorize_summary( + self, dataset_id: str, document_id: str, is_preview: bool, summary_index_setting: dict | None = None + ): ... diff --git a/api/tests/integration_tests/workflow/nodes/knowledge_index/__init__.py b/api/tests/integration_tests/workflow/nodes/knowledge_index/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/integration_tests/workflow/nodes/knowledge_index/test_knowledge_index_node_integration.py b/api/tests/integration_tests/workflow/nodes/knowledge_index/test_knowledge_index_node_integration.py new file mode 100644 index 0000000000..4edbf2b1e9 --- /dev/null +++ b/api/tests/integration_tests/workflow/nodes/knowledge_index/test_knowledge_index_node_integration.py @@ -0,0 +1,69 @@ +""" +Integration tests for KnowledgeIndexNode. + +This module provides integration tests for KnowledgeIndexNode with real database interactions. + +Note: These tests require database setup and are more complex than unit tests. +For now, we focus on unit tests which provide better coverage for the node logic. +""" + +import pytest + + +class TestKnowledgeIndexNodeIntegration: + """ + Integration test suite for KnowledgeIndexNode. + + Note: Full integration tests require: + - Database setup with datasets and documents + - Vector store for embeddings + - Model providers for indexing and summarization + - IndexProcessor and SummaryIndexService implementations + + For now, unit tests provide comprehensive coverage of the node logic. + """ + + @pytest.mark.skip(reason="Integration tests require full database and vector store setup") + def test_end_to_end_knowledge_index_preview(self): + """Test end-to-end knowledge index workflow in preview mode.""" + # TODO: Implement with real database + # 1. Create a dataset + # 2. Create a document + # 3. Prepare chunks + # 4. Run KnowledgeIndexNode in preview mode + # 5. Verify preview output + pass + + @pytest.mark.skip(reason="Integration tests require full database and vector store setup") + def test_end_to_end_knowledge_index_production(self): + """Test end-to-end knowledge index workflow in production mode.""" + # TODO: Implement with real database + # 1. Create a dataset + # 2. Create a document + # 3. Prepare chunks + # 4. Run KnowledgeIndexNode in production mode + # 5. Verify indexing and summary generation + pass + + @pytest.mark.skip(reason="Integration tests require full database and vector store setup") + def test_knowledge_index_with_summary_enabled(self): + """Test knowledge index with summary index setting enabled.""" + # TODO: Implement with real database + # 1. Create a dataset + # 2. Create a document + # 3. Prepare chunks + # 4. Configure summary index setting + # 5. Run KnowledgeIndexNode + # 6. Verify summaries are generated and indexed + pass + + @pytest.mark.skip(reason="Integration tests require full database and vector store setup") + def test_knowledge_index_parent_child_structure(self): + """Test knowledge index with parent-child chunk structure.""" + # TODO: Implement with real database + # 1. Create a dataset + # 2. Create a document + # 3. Prepare parent-child chunks + # 4. Run KnowledgeIndexNode + # 5. Verify parent-child indexing + pass diff --git a/api/tests/unit_tests/core/workflow/nodes/knowledge_index/__init__.py b/api/tests/unit_tests/core/workflow/nodes/knowledge_index/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py b/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py new file mode 100644 index 0000000000..38e434d7d8 --- /dev/null +++ b/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py @@ -0,0 +1,663 @@ +import time +import uuid +from unittest.mock import Mock + +import pytest + +from core.app.entities.app_invoke_entities import InvokeFrom +from core.workflow.entities import GraphInitParams +from core.workflow.enums import SystemVariableKey, WorkflowNodeExecutionStatus +from core.workflow.nodes.knowledge_index.entities import KnowledgeIndexNodeData +from core.workflow.nodes.knowledge_index.exc import KnowledgeIndexNodeError +from core.workflow.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode +from core.workflow.repositories.index_processor_protocol import IndexProcessorProtocol, Preview, PreviewItem +from core.workflow.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol +from core.workflow.runtime import GraphRuntimeState, VariablePool +from core.workflow.system_variable import SystemVariable +from core.workflow.variables.segments import StringSegment +from models.enums import UserFrom + + +@pytest.fixture +def mock_graph_init_params(): + """Create mock GraphInitParams.""" + return GraphInitParams( + tenant_id=str(uuid.uuid4()), + app_id=str(uuid.uuid4()), + workflow_id=str(uuid.uuid4()), + graph_config={}, + user_id=str(uuid.uuid4()), + user_from=UserFrom.ACCOUNT, + invoke_from=InvokeFrom.DEBUGGER, + call_depth=0, + ) + + +@pytest.fixture +def mock_graph_runtime_state(): + """Create mock GraphRuntimeState.""" + variable_pool = VariablePool( + system_variables=SystemVariable(user_id=str(uuid.uuid4()), files=[]), + user_inputs={}, + environment_variables=[], + conversation_variables=[], + ) + return GraphRuntimeState(variable_pool=variable_pool, start_at=time.perf_counter()) + + +@pytest.fixture +def mock_index_processor(): + """Create mock IndexProcessorProtocol.""" + mock_processor = Mock(spec=IndexProcessorProtocol) + return mock_processor + + +@pytest.fixture +def mock_summary_index_service(): + """Create mock SummaryIndexServiceProtocol.""" + mock_service = Mock(spec=SummaryIndexServiceProtocol) + return mock_service + + +@pytest.fixture +def sample_node_data(): + """Create sample KnowledgeIndexNodeData.""" + return KnowledgeIndexNodeData( + title="Knowledge Index", + type="knowledge-index", + chunk_structure="general_structure", + index_chunk_variable_selector=["start", "chunks"], + indexing_technique="high_quality", + summary_index_setting=None, + ) + + +@pytest.fixture +def sample_chunks(): + """Create sample chunks data.""" + return { + "general_chunks": ["Chunk 1 content", "Chunk 2 content"], + "data_source_info": {"file_id": str(uuid.uuid4())}, + } + + +class TestKnowledgeIndexNode: + """ + Test suite for KnowledgeIndexNode. + """ + + def test_node_initialization( + self, mock_graph_init_params, mock_graph_runtime_state, mock_index_processor, mock_summary_index_service + ): + """Test KnowledgeIndexNode initialization.""" + # Arrange + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": { + "title": "Knowledge Index", + "type": "knowledge-index", + "chunk_structure": "general_structure", + "index_chunk_variable_selector": ["start", "chunks"], + }, + } + + # Act + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Assert + assert node.id == node_id + assert node.index_processor == mock_index_processor + assert node.summary_index_service == mock_summary_index_service + + def test_run_without_dataset_id( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + """Test _run raises KnowledgeIndexNodeError when dataset_id is not provided.""" + # Arrange + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act & Assert + with pytest.raises(KnowledgeIndexNodeError, match="Dataset ID is required"): + node._run() + + def test_run_without_index_chunk_variable( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + """Test _run raises KnowledgeIndexNodeError when index chunk variable is not provided.""" + # Arrange + dataset_id = str(uuid.uuid4()) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act & Assert + with pytest.raises(KnowledgeIndexNodeError, match="Index chunk variable is required"): + node._run() + + def test_run_with_empty_chunks( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + """Test _run fails when chunks is empty.""" + # Arrange + dataset_id = str(uuid.uuid4()) + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, StringSegment(value="")) + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.FAILED + assert "Chunks is required" in result.error + + def test_run_preview_mode_success( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + sample_chunks, + ): + """Test _run succeeds in preview mode.""" + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DOCUMENT_ID], + StringSegment(value=document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.INVOKE_FROM], + StringSegment(value=InvokeFrom.DEBUGGER), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, sample_chunks) + + # Mock preview output + mock_preview = Preview( + chunk_structure="general_structure", + preview=[PreviewItem(content="Chunk 1"), PreviewItem(content="Chunk 2")], + total_segments=2, + ) + mock_index_processor.get_preview_output.return_value = mock_preview + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED + assert result.outputs is not None + assert mock_index_processor.get_preview_output.called + + def test_run_production_mode_success( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + sample_chunks, + ): + """Test _run succeeds in production mode.""" + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + original_document_id = str(uuid.uuid4()) + batch = "batch_123" + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DOCUMENT_ID], + StringSegment(value=document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.ORIGINAL_DOCUMENT_ID], + StringSegment(value=original_document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.BATCH], + StringSegment(value=batch), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.INVOKE_FROM], + StringSegment(value=InvokeFrom.SERVICE_API), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, sample_chunks) + + # Mock index_and_clean output + mock_index_processor.index_and_clean.return_value = {"status": "indexed"} + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED + assert result.outputs is not None + assert mock_summary_index_service.generate_and_vectorize_summary.called + assert mock_index_processor.index_and_clean.called + + def test_run_production_mode_without_batch( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + sample_chunks, + ): + """Test _run fails when batch is not provided in production mode.""" + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DOCUMENT_ID], + StringSegment(value=document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.INVOKE_FROM], + StringSegment(value=InvokeFrom.SERVICE_API), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, sample_chunks) + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.FAILED + assert "Batch is required" in result.error + + def test_run_with_knowledge_index_node_error( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + sample_chunks, + ): + """Test _run handles KnowledgeIndexNodeError properly.""" + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + batch = "batch_123" + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DOCUMENT_ID], + StringSegment(value=document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.BATCH], + StringSegment(value=batch), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.INVOKE_FROM], + StringSegment(value=InvokeFrom.SERVICE_API), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, sample_chunks) + + # Mock to raise KnowledgeIndexNodeError + mock_index_processor.index_and_clean.side_effect = KnowledgeIndexNodeError("Indexing failed") + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.FAILED + assert "Indexing failed" in result.error + assert result.error_type == "KnowledgeIndexNodeError" + + def test_run_with_generic_exception( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + sample_chunks, + ): + """Test _run handles generic exceptions properly.""" + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + batch = "batch_123" + chunks_selector = ["start", "chunks"] + + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DATASET_ID], + StringSegment(value=dataset_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.DOCUMENT_ID], + StringSegment(value=document_id), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.BATCH], + StringSegment(value=batch), + ) + mock_graph_runtime_state.variable_pool.add( + ["sys", SystemVariableKey.INVOKE_FROM], + StringSegment(value=InvokeFrom.SERVICE_API), + ) + mock_graph_runtime_state.variable_pool.add(chunks_selector, sample_chunks) + + # Mock to raise generic exception + mock_index_processor.index_and_clean.side_effect = Exception("Unexpected error") + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._run() + + # Assert + assert result.status == WorkflowNodeExecutionStatus.FAILED + assert "Unexpected error" in result.error + assert result.error_type == "Exception" + + def test_invoke_knowledge_index( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + original_document_id = str(uuid.uuid4()) + batch = "batch_123" + chunks = {"general_chunks": ["content"]} + + mock_index_processor.index_and_clean.return_value = {"status": "indexed"} + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._invoke_knowledge_index( + dataset_id=dataset_id, + document_id=document_id, + original_document_id=original_document_id, + is_preview=False, + batch=batch, + chunks=chunks, + summary_index_setting=None, + ) + + # Assert + assert mock_summary_index_service.generate_and_vectorize_summary.called + assert mock_index_processor.index_and_clean.called + assert result == {"status": "indexed"} + + def test_version_method(self): + """Test version class method.""" + # Act + version = KnowledgeIndexNode.version() + + # Assert + assert version == "1" + + def test_get_streaming_template( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + """Test get_streaming_template method.""" + # Arrange + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + template = node.get_streaming_template() + + # Assert + assert template is not None + assert template.segments == [] + + +class TestInvokeKnowledgeIndex: + def test_invoke_with_summary_index_setting( + self, + mock_graph_init_params, + mock_graph_runtime_state, + mock_index_processor, + mock_summary_index_service, + sample_node_data, + ): + # Arrange + dataset_id = str(uuid.uuid4()) + document_id = str(uuid.uuid4()) + original_document_id = str(uuid.uuid4()) + batch = "batch_123" + chunks = {"general_chunks": ["content"]} + summary_setting = {"enabled": True} + + mock_index_processor.index_and_clean.return_value = {"status": "indexed"} + + node_id = str(uuid.uuid4()) + config = { + "id": node_id, + "data": sample_node_data.model_dump(), + } + + node = KnowledgeIndexNode( + id=node_id, + config=config, + graph_init_params=mock_graph_init_params, + graph_runtime_state=mock_graph_runtime_state, + index_processor=mock_index_processor, + summary_index_service=mock_summary_index_service, + ) + + # Act + result = node._invoke_knowledge_index( + dataset_id=dataset_id, + document_id=document_id, + original_document_id=original_document_id, + is_preview=False, + batch=batch, + chunks=chunks, + summary_index_setting=summary_setting, + ) + + # Assert + mock_summary_index_service.generate_and_vectorize_summary.assert_called_once_with( + dataset_id, document_id, False, summary_setting + ) + mock_index_processor.index_and_clean.assert_called_once_with( + dataset_id, document_id, original_document_id, chunks, batch, summary_setting + ) + assert result == {"status": "indexed"} From 9c33923985052b2a57b743aa1c5e76f594221539 Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Mon, 2 Mar 2026 18:24:01 +0800 Subject: [PATCH 015/159] feat(tests): add comprehensive test suite for workflow utilities and node creation (#32841) Co-authored-by: CodingOnStar Co-authored-by: Asuka Minato Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> --- .../components/workflow/__tests__/fixtures.ts | 111 +++ .../workflow/__tests__/mock-hooks-store.ts | 59 ++ .../workflow/__tests__/mock-reactflow.ts | 110 +++ .../workflow/__tests__/mock-workflow-store.ts | 199 +++++ .../workflow/utils/__tests__/common.spec.ts | 183 +++++ .../utils/__tests__/data-source.spec.ts | 116 +++ .../workflow/utils/__tests__/debug.spec.ts | 48 ++ .../workflow/utils/__tests__/edge.spec.ts | 33 + .../utils/__tests__/elk-layout.spec.ts | 665 ++++++++++++++++ .../__tests__/gen-node-meta-data.spec.ts | 70 ++ .../utils/__tests__/node-navigation.spec.ts | 161 ++++ .../workflow/utils/__tests__/node.spec.ts | 219 ++++++ .../workflow/utils/__tests__/tool.spec.ts | 191 +++++ .../workflow/utils/__tests__/trigger.spec.ts | 132 ++++ .../workflow/utils/__tests__/variable.spec.ts | 55 ++ .../utils/__tests__/workflow-entry.spec.ts | 89 +++ .../utils/__tests__/workflow-init.spec.ts | 742 ++++++++++++++++++ .../workflow/utils/__tests__/workflow.spec.ts | 423 ++++++++++ .../workflow/utils/workflow-init.spec.ts | 69 -- 19 files changed, 3606 insertions(+), 69 deletions(-) create mode 100644 web/app/components/workflow/__tests__/fixtures.ts create mode 100644 web/app/components/workflow/__tests__/mock-hooks-store.ts create mode 100644 web/app/components/workflow/__tests__/mock-reactflow.ts create mode 100644 web/app/components/workflow/__tests__/mock-workflow-store.ts create mode 100644 web/app/components/workflow/utils/__tests__/common.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/data-source.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/debug.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/edge.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/elk-layout.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/gen-node-meta-data.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/node-navigation.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/node.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/tool.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/trigger.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/variable.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/workflow-entry.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/workflow-init.spec.ts create mode 100644 web/app/components/workflow/utils/__tests__/workflow.spec.ts delete mode 100644 web/app/components/workflow/utils/workflow-init.spec.ts diff --git a/web/app/components/workflow/__tests__/fixtures.ts b/web/app/components/workflow/__tests__/fixtures.ts new file mode 100644 index 0000000000..50a42ebe3d --- /dev/null +++ b/web/app/components/workflow/__tests__/fixtures.ts @@ -0,0 +1,111 @@ +import type { CommonEdgeType, CommonNodeType, Edge, Node } from '../types' +import { Position } from 'reactflow' +import { CUSTOM_NODE } from '../constants' +import { BlockEnum, NodeRunningStatus } from '../types' + +let nodeIdCounter = 0 +let edgeIdCounter = 0 + +export function resetFixtureCounters() { + nodeIdCounter = 0 + edgeIdCounter = 0 +} + +export function createNode( + overrides: Omit, 'data'> & { data?: Partial & Record } = {}, +): Node { + const id = overrides.id ?? `node-${++nodeIdCounter}` + const { data: dataOverrides, ...rest } = overrides + return { + id, + type: CUSTOM_NODE, + position: { x: 0, y: 0 }, + targetPosition: Position.Left, + sourcePosition: Position.Right, + data: { + title: `Node ${id}`, + desc: '', + type: BlockEnum.Code, + _connectedSourceHandleIds: [], + _connectedTargetHandleIds: [], + ...dataOverrides, + } as CommonNodeType, + ...rest, + } as Node +} + +export function createStartNode(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Node { + return createNode({ + ...overrides, + data: { type: BlockEnum.Start, title: 'Start', desc: '', ...overrides.data }, + }) +} + +export function createTriggerNode( + triggerType: BlockEnum.TriggerSchedule | BlockEnum.TriggerWebhook | BlockEnum.TriggerPlugin = BlockEnum.TriggerWebhook, + overrides: Omit, 'data'> & { data?: Partial & Record } = {}, +): Node { + return createNode({ + ...overrides, + data: { type: triggerType, title: `Trigger ${triggerType}`, desc: '', ...overrides.data }, + }) +} + +export function createIterationNode(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Node { + return createNode({ + ...overrides, + data: { type: BlockEnum.Iteration, title: 'Iteration', desc: '', ...overrides.data }, + }) +} + +export function createLoopNode(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Node { + return createNode({ + ...overrides, + data: { type: BlockEnum.Loop, title: 'Loop', desc: '', ...overrides.data }, + }) +} + +export function createEdge(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Edge { + const { data: dataOverrides, ...rest } = overrides + return { + id: overrides.id ?? `edge-${overrides.source ?? 'src'}-${overrides.target ?? 'tgt'}-${++edgeIdCounter}`, + source: 'source-node', + target: 'target-node', + data: { + sourceType: BlockEnum.Start, + targetType: BlockEnum.Code, + ...dataOverrides, + } as CommonEdgeType, + ...rest, + } as Edge +} + +export function createLinearGraph(nodeCount: number): { nodes: Node[], edges: Edge[] } { + const nodes: Node[] = [] + const edges: Edge[] = [] + + for (let i = 0; i < nodeCount; i++) { + const type = i === 0 ? BlockEnum.Start : BlockEnum.Code + nodes.push(createNode({ + id: `n${i}`, + position: { x: i * 300, y: 0 }, + data: { type, title: `Node ${i}`, desc: '' }, + })) + if (i > 0) { + edges.push(createEdge({ + id: `e-n${i - 1}-n${i}`, + source: `n${i - 1}`, + target: `n${i}`, + sourceHandle: 'source', + targetHandle: 'target', + data: { + sourceType: i === 1 ? BlockEnum.Start : BlockEnum.Code, + targetType: BlockEnum.Code, + }, + })) + } + } + return { nodes, edges } +} + +export { BlockEnum, NodeRunningStatus } diff --git a/web/app/components/workflow/__tests__/mock-hooks-store.ts b/web/app/components/workflow/__tests__/mock-hooks-store.ts new file mode 100644 index 0000000000..9363b31c35 --- /dev/null +++ b/web/app/components/workflow/__tests__/mock-hooks-store.ts @@ -0,0 +1,59 @@ +import { noop } from 'es-toolkit' + +/** + * Default hooks store state. + * All function fields default to noop / vi.fn() stubs. + * Use `createHooksStoreState(overrides)` to get a customised state object. + */ +export function createHooksStoreState(overrides: Record = {}) { + return { + refreshAll: noop, + + // draft sync + doSyncWorkflowDraft: vi.fn().mockResolvedValue(undefined), + syncWorkflowDraftWhenPageClose: noop, + handleRefreshWorkflowDraft: noop, + handleBackupDraft: noop, + handleLoadBackupDraft: noop, + handleRestoreFromPublishedWorkflow: noop, + + // run + handleRun: noop, + handleStopRun: noop, + handleStartWorkflowRun: noop, + handleWorkflowStartRunInWorkflow: noop, + handleWorkflowStartRunInChatflow: noop, + handleWorkflowTriggerScheduleRunInWorkflow: noop, + handleWorkflowTriggerWebhookRunInWorkflow: noop, + handleWorkflowTriggerPluginRunInWorkflow: noop, + handleWorkflowRunAllTriggersInWorkflow: noop, + + // meta + availableNodesMetaData: undefined, + configsMap: undefined, + + // export / DSL + exportCheck: vi.fn().mockResolvedValue(undefined), + handleExportDSL: vi.fn().mockResolvedValue(undefined), + getWorkflowRunAndTraceUrl: vi.fn().mockReturnValue({ runUrl: '', traceUrl: '' }), + + // inspect vars + fetchInspectVars: vi.fn().mockResolvedValue(undefined), + hasNodeInspectVars: vi.fn().mockReturnValue(false), + hasSetInspectVar: vi.fn().mockReturnValue(false), + fetchInspectVarValue: vi.fn().mockResolvedValue(undefined), + editInspectVarValue: vi.fn().mockResolvedValue(undefined), + renameInspectVarName: vi.fn().mockResolvedValue(undefined), + appendNodeInspectVars: noop, + deleteInspectVar: vi.fn().mockResolvedValue(undefined), + deleteNodeInspectorVars: vi.fn().mockResolvedValue(undefined), + deleteAllInspectorVars: vi.fn().mockResolvedValue(undefined), + isInspectVarEdited: vi.fn().mockReturnValue(false), + resetToLastRunVar: vi.fn().mockResolvedValue(undefined), + invalidateSysVarValues: noop, + resetConversationVar: vi.fn().mockResolvedValue(undefined), + invalidateConversationVarValues: noop, + + ...overrides, + } +} diff --git a/web/app/components/workflow/__tests__/mock-reactflow.ts b/web/app/components/workflow/__tests__/mock-reactflow.ts new file mode 100644 index 0000000000..168713de4c --- /dev/null +++ b/web/app/components/workflow/__tests__/mock-reactflow.ts @@ -0,0 +1,110 @@ +/** + * ReactFlow mock factory for workflow tests. + * + * Usage — add this to the top of any test file that imports reactflow: + * + * vi.mock('reactflow', async () => (await import('../__tests__/mock-reactflow')).createReactFlowMock()) + * + * Or for more control: + * + * vi.mock('reactflow', async () => { + * const base = (await import('../__tests__/mock-reactflow')).createReactFlowMock() + * return { ...base, useReactFlow: () => ({ ...base.useReactFlow(), fitView: vi.fn() }) } + * }) + */ +import * as React from 'react' + +export function createReactFlowMock(overrides: Record = {}) { + const noopComponent: React.FC<{ children?: React.ReactNode }> = ({ children }) => + React.createElement('div', { 'data-testid': 'reactflow-mock' }, children) + noopComponent.displayName = 'ReactFlowMock' + + const backgroundComponent: React.FC = () => null + backgroundComponent.displayName = 'BackgroundMock' + + return { + // re-export the real Position enum + Position: { Left: 'left', Right: 'right', Top: 'top', Bottom: 'bottom' }, + MarkerType: { Arrow: 'arrow', ArrowClosed: 'arrowclosed' }, + ConnectionMode: { Strict: 'strict', Loose: 'loose' }, + ConnectionLineType: { Bezier: 'default', Straight: 'straight', Step: 'step', SmoothStep: 'smoothstep' }, + + // components + default: noopComponent, + ReactFlow: noopComponent, + ReactFlowProvider: ({ children }: { children?: React.ReactNode }) => + React.createElement(React.Fragment, null, children), + Background: backgroundComponent, + MiniMap: backgroundComponent, + Controls: backgroundComponent, + Handle: (props: Record) => React.createElement('div', { 'data-testid': 'handle', ...props }), + BaseEdge: (props: Record) => React.createElement('path', props), + EdgeLabelRenderer: ({ children }: { children?: React.ReactNode }) => + React.createElement('div', null, children), + + // hooks + useReactFlow: () => ({ + setCenter: vi.fn(), + fitView: vi.fn(), + zoomIn: vi.fn(), + zoomOut: vi.fn(), + zoomTo: vi.fn(), + getNodes: vi.fn().mockReturnValue([]), + getEdges: vi.fn().mockReturnValue([]), + getNode: vi.fn(), + setNodes: vi.fn(), + setEdges: vi.fn(), + addNodes: vi.fn(), + addEdges: vi.fn(), + deleteElements: vi.fn(), + getViewport: vi.fn().mockReturnValue({ x: 0, y: 0, zoom: 1 }), + setViewport: vi.fn(), + screenToFlowPosition: vi.fn().mockImplementation((pos: { x: number, y: number }) => pos), + flowToScreenPosition: vi.fn().mockImplementation((pos: { x: number, y: number }) => pos), + toObject: vi.fn().mockReturnValue({ nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } }), + viewportInitialized: true, + }), + + useStoreApi: () => ({ + getState: vi.fn().mockReturnValue({ + nodeInternals: new Map(), + edges: [], + transform: [0, 0, 1], + d3Selection: null, + d3Zoom: null, + }), + setState: vi.fn(), + subscribe: vi.fn().mockReturnValue(vi.fn()), + }), + + useNodesState: vi.fn((initial: unknown[] = []) => [initial, vi.fn(), vi.fn()]), + + useEdgesState: vi.fn((initial: unknown[] = []) => [initial, vi.fn(), vi.fn()]), + + useStore: vi.fn().mockReturnValue(null), + useNodes: vi.fn().mockReturnValue([]), + useEdges: vi.fn().mockReturnValue([]), + useViewport: vi.fn().mockReturnValue({ x: 0, y: 0, zoom: 1 }), + useOnSelectionChange: vi.fn(), + useKeyPress: vi.fn().mockReturnValue(false), + useUpdateNodeInternals: vi.fn().mockReturnValue(vi.fn()), + useOnViewportChange: vi.fn(), + useNodeId: vi.fn().mockReturnValue(null), + + // utils + getOutgoers: vi.fn().mockReturnValue([]), + getIncomers: vi.fn().mockReturnValue([]), + getConnectedEdges: vi.fn().mockReturnValue([]), + isNode: vi.fn().mockReturnValue(true), + isEdge: vi.fn().mockReturnValue(false), + addEdge: vi.fn().mockImplementation((_edge: unknown, edges: unknown[]) => edges), + applyNodeChanges: vi.fn().mockImplementation((_changes: unknown[], nodes: unknown[]) => nodes), + applyEdgeChanges: vi.fn().mockImplementation((_changes: unknown[], edges: unknown[]) => edges), + getBezierPath: vi.fn().mockReturnValue(['M 0 0', 0, 0]), + getSmoothStepPath: vi.fn().mockReturnValue(['M 0 0', 0, 0]), + getStraightPath: vi.fn().mockReturnValue(['M 0 0', 0, 0]), + internalsSymbol: Symbol('internals'), + + ...overrides, + } +} diff --git a/web/app/components/workflow/__tests__/mock-workflow-store.ts b/web/app/components/workflow/__tests__/mock-workflow-store.ts new file mode 100644 index 0000000000..112384c4f6 --- /dev/null +++ b/web/app/components/workflow/__tests__/mock-workflow-store.ts @@ -0,0 +1,199 @@ +import type { ControlMode, Node } from '../types' +import { noop } from 'es-toolkit' +import { DEFAULT_ITER_TIMES, DEFAULT_LOOP_TIMES } from '../constants' + +/** + * Default workflow store state covering all slices. + * Use `createWorkflowStoreState(overrides)` to get a state object + * that can be injected via `useWorkflowStore.setState(...)` or + * used as the return value of a mocked `useStore` selector. + */ +export function createWorkflowStoreState(overrides: Record = {}) { + return { + // --- workflow-slice --- + workflowRunningData: undefined, + isListening: false, + listeningTriggerType: null, + listeningTriggerNodeId: null, + listeningTriggerNodeIds: [], + listeningTriggerIsAll: false, + clipboardElements: [] as Node[], + selection: null, + bundleNodeSize: null, + controlMode: 'pointer' as ControlMode, + mousePosition: { pageX: 0, pageY: 0, elementX: 0, elementY: 0 }, + showConfirm: undefined, + controlPromptEditorRerenderKey: 0, + showImportDSLModal: false, + fileUploadConfig: undefined, + + // --- node-slice --- + showSingleRunPanel: false, + nodeAnimation: false, + candidateNode: undefined, + nodeMenu: undefined, + showAssignVariablePopup: undefined, + hoveringAssignVariableGroupId: undefined, + connectingNodePayload: undefined, + enteringNodePayload: undefined, + iterTimes: DEFAULT_ITER_TIMES, + loopTimes: DEFAULT_LOOP_TIMES, + iterParallelLogMap: new Map(), + pendingSingleRun: undefined, + + // --- panel-slice --- + panelWidth: 420, + showFeaturesPanel: false, + showWorkflowVersionHistoryPanel: false, + showInputsPanel: false, + showDebugAndPreviewPanel: false, + panelMenu: undefined, + selectionMenu: undefined, + showVariableInspectPanel: false, + initShowLastRunTab: false, + + // --- help-line-slice --- + helpLineHorizontal: undefined, + helpLineVertical: undefined, + + // --- history-slice --- + historyWorkflowData: undefined, + showRunHistory: false, + versionHistory: [], + + // --- chat-variable-slice --- + showChatVariablePanel: false, + showGlobalVariablePanel: false, + conversationVariables: [], + + // --- env-variable-slice --- + showEnvPanel: false, + environmentVariables: [], + envSecrets: {}, + + // --- form-slice --- + inputs: {}, + files: [], + + // --- tool-slice --- + toolPublished: false, + lastPublishedHasUserInput: false, + buildInTools: undefined, + customTools: undefined, + workflowTools: undefined, + mcpTools: undefined, + + // --- version-slice --- + draftUpdatedAt: 0, + publishedAt: 0, + currentVersion: null, + isRestoring: false, + + // --- workflow-draft-slice --- + backupDraft: undefined, + syncWorkflowDraftHash: '', + isSyncingWorkflowDraft: false, + isWorkflowDataLoaded: false, + nodes: [] as Node[], + + // --- inspect-vars-slice --- + currentFocusNodeId: null, + nodesWithInspectVars: [], + conversationVars: [], + + // --- layout-slice --- + workflowCanvasWidth: undefined, + workflowCanvasHeight: undefined, + rightPanelWidth: undefined, + nodePanelWidth: 420, + previewPanelWidth: 420, + otherPanelWidth: 420, + bottomPanelWidth: 0, + bottomPanelHeight: 0, + variableInspectPanelHeight: 300, + maximizeCanvas: false, + + // --- setters (all default to noop, override as needed) --- + setWorkflowRunningData: noop, + setIsListening: noop, + setListeningTriggerType: noop, + setListeningTriggerNodeId: noop, + setListeningTriggerNodeIds: noop, + setListeningTriggerIsAll: noop, + setClipboardElements: noop, + setSelection: noop, + setBundleNodeSize: noop, + setControlMode: noop, + setMousePosition: noop, + setShowConfirm: noop, + setControlPromptEditorRerenderKey: noop, + setShowImportDSLModal: noop, + setFileUploadConfig: noop, + setShowSingleRunPanel: noop, + setNodeAnimation: noop, + setCandidateNode: noop, + setNodeMenu: noop, + setShowAssignVariablePopup: noop, + setHoveringAssignVariableGroupId: noop, + setConnectingNodePayload: noop, + setEnteringNodePayload: noop, + setIterTimes: noop, + setLoopTimes: noop, + setIterParallelLogMap: noop, + setPendingSingleRun: noop, + setShowFeaturesPanel: noop, + setShowWorkflowVersionHistoryPanel: noop, + setShowInputsPanel: noop, + setShowDebugAndPreviewPanel: noop, + setPanelMenu: noop, + setSelectionMenu: noop, + setShowVariableInspectPanel: noop, + setInitShowLastRunTab: noop, + setHelpLineHorizontal: noop, + setHelpLineVertical: noop, + setHistoryWorkflowData: noop, + setShowRunHistory: noop, + setVersionHistory: noop, + setShowChatVariablePanel: noop, + setShowGlobalVariablePanel: noop, + setConversationVariables: noop, + setShowEnvPanel: noop, + setEnvironmentVariables: noop, + setEnvSecrets: noop, + setInputs: noop, + setFiles: noop, + setToolPublished: noop, + setLastPublishedHasUserInput: noop, + setDraftUpdatedAt: noop, + setPublishedAt: noop, + setCurrentVersion: noop, + setIsRestoring: noop, + setBackupDraft: noop, + setSyncWorkflowDraftHash: noop, + setIsSyncingWorkflowDraft: noop, + setIsWorkflowDataLoaded: noop, + setNodes: noop, + flushPendingSync: noop, + setCurrentFocusNodeId: noop, + setNodesWithInspectVars: noop, + setNodeInspectVars: noop, + deleteAllInspectVars: noop, + deleteNodeInspectVars: noop, + setInspectVarValue: noop, + resetToLastRunVar: noop, + renameInspectVarName: noop, + deleteInspectVar: noop, + setWorkflowCanvasWidth: noop, + setWorkflowCanvasHeight: noop, + setRightPanelWidth: noop, + setNodePanelWidth: noop, + setPreviewPanelWidth: noop, + setOtherPanelWidth: noop, + setBottomPanelWidth: noop, + setBottomPanelHeight: noop, + setVariableInspectPanelHeight: noop, + setMaximizeCanvas: noop, + + ...overrides, + } +} diff --git a/web/app/components/workflow/utils/__tests__/common.spec.ts b/web/app/components/workflow/utils/__tests__/common.spec.ts new file mode 100644 index 0000000000..8c84a21d09 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/common.spec.ts @@ -0,0 +1,183 @@ +import { + formatWorkflowRunIdentifier, + getKeyboardKeyCodeBySystem, + getKeyboardKeyNameBySystem, + isEventTargetInputArea, + isMac, +} from '../common' + +describe('isMac', () => { + const originalNavigator = globalThis.navigator + + afterEach(() => { + Object.defineProperty(globalThis, 'navigator', { + value: originalNavigator, + writable: true, + configurable: true, + }) + }) + + it('should return true when userAgent contains MAC', () => { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' }, + writable: true, + configurable: true, + }) + expect(isMac()).toBe(true) + }) + + it('should return false when userAgent does not contain MAC', () => { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' }, + writable: true, + configurable: true, + }) + expect(isMac()).toBe(false) + }) +}) + +describe('getKeyboardKeyNameBySystem', () => { + const originalNavigator = globalThis.navigator + + afterEach(() => { + Object.defineProperty(globalThis, 'navigator', { + value: originalNavigator, + writable: true, + configurable: true, + }) + }) + + function setMac() { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Macintosh' }, + writable: true, + configurable: true, + }) + } + + function setWindows() { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Windows NT' }, + writable: true, + configurable: true, + }) + } + + it('should map ctrl to ⌘ on Mac', () => { + setMac() + expect(getKeyboardKeyNameBySystem('ctrl')).toBe('⌘') + }) + + it('should map alt to ⌥ on Mac', () => { + setMac() + expect(getKeyboardKeyNameBySystem('alt')).toBe('⌥') + }) + + it('should map shift to ⇧ on Mac', () => { + setMac() + expect(getKeyboardKeyNameBySystem('shift')).toBe('⇧') + }) + + it('should return the original key for unmapped keys on Mac', () => { + setMac() + expect(getKeyboardKeyNameBySystem('enter')).toBe('enter') + }) + + it('should return the original key on non-Mac', () => { + setWindows() + expect(getKeyboardKeyNameBySystem('ctrl')).toBe('ctrl') + expect(getKeyboardKeyNameBySystem('alt')).toBe('alt') + }) +}) + +describe('getKeyboardKeyCodeBySystem', () => { + const originalNavigator = globalThis.navigator + + afterEach(() => { + Object.defineProperty(globalThis, 'navigator', { + value: originalNavigator, + writable: true, + configurable: true, + }) + }) + + it('should map ctrl to meta on Mac', () => { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Macintosh' }, + writable: true, + configurable: true, + }) + expect(getKeyboardKeyCodeBySystem('ctrl')).toBe('meta') + }) + + it('should return the original key on non-Mac', () => { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Windows NT' }, + writable: true, + configurable: true, + }) + expect(getKeyboardKeyCodeBySystem('ctrl')).toBe('ctrl') + }) + + it('should return the original key for unmapped keys on Mac', () => { + Object.defineProperty(globalThis, 'navigator', { + value: { userAgent: 'Macintosh' }, + writable: true, + configurable: true, + }) + expect(getKeyboardKeyCodeBySystem('alt')).toBe('alt') + }) +}) + +describe('isEventTargetInputArea', () => { + it('should return true for INPUT elements', () => { + const el = document.createElement('input') + expect(isEventTargetInputArea(el)).toBe(true) + }) + + it('should return true for TEXTAREA elements', () => { + const el = document.createElement('textarea') + expect(isEventTargetInputArea(el)).toBe(true) + }) + + it('should return true for contentEditable elements', () => { + const el = document.createElement('div') + el.contentEditable = 'true' + expect(isEventTargetInputArea(el)).toBe(true) + }) + + it('should return undefined for non-input elements', () => { + const el = document.createElement('div') + expect(isEventTargetInputArea(el)).toBeUndefined() + }) + + it('should return undefined for contentEditable=false elements', () => { + const el = document.createElement('div') + el.contentEditable = 'false' + expect(isEventTargetInputArea(el)).toBeUndefined() + }) +}) + +describe('formatWorkflowRunIdentifier', () => { + it('should return fallback text when finishedAt is undefined', () => { + expect(formatWorkflowRunIdentifier()).toBe(' (Running)') + }) + + it('should return fallback text when finishedAt is 0', () => { + expect(formatWorkflowRunIdentifier(0)).toBe(' (Running)') + }) + + it('should capitalize custom fallback text', () => { + expect(formatWorkflowRunIdentifier(undefined, 'pending')).toBe(' (Pending)') + }) + + it('should format a valid timestamp', () => { + const timestamp = 1704067200 // 2024-01-01 00:00:00 UTC + const result = formatWorkflowRunIdentifier(timestamp) + expect(result).toMatch(/^ \(\d{2}:\d{2}:\d{2}( [AP]M)?\)$/) + }) + + it('should handle single-char fallback text', () => { + expect(formatWorkflowRunIdentifier(undefined, 'x')).toBe(' (X)') + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/data-source.spec.ts b/web/app/components/workflow/utils/__tests__/data-source.spec.ts new file mode 100644 index 0000000000..2de5b7f717 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/data-source.spec.ts @@ -0,0 +1,116 @@ +import type { DataSourceNodeType } from '../../nodes/data-source/types' +import type { ToolWithProvider } from '../../types' +import { CollectionType } from '@/app/components/tools/types' +import { BlockEnum } from '../../types' +import { getDataSourceCheckParams } from '../data-source' + +vi.mock('@/app/components/tools/utils/to-form-schema', () => ({ + toolParametersToFormSchemas: vi.fn((params: Array>) => + params.map(p => ({ + variable: p.name, + label: p.label || { en_US: p.name }, + type: p.type || 'string', + required: p.required ?? false, + form: p.form ?? 'llm', + hide: p.hide ?? false, + }))), +})) + +function createDataSourceData(overrides: Partial = {}): DataSourceNodeType { + return { + title: 'DataSource', + desc: '', + type: BlockEnum.DataSource, + plugin_id: 'plugin-ds-1', + provider_type: CollectionType.builtIn, + datasource_name: 'mysql_query', + datasource_parameters: {}, + datasource_configurations: {}, + ...overrides, + } as DataSourceNodeType +} + +function createDataSourceCollection(overrides: Partial = {}): ToolWithProvider { + return { + id: 'ds-collection', + plugin_id: 'plugin-ds-1', + name: 'MySQL', + tools: [ + { + name: 'mysql_query', + parameters: [ + { name: 'query', label: { en_US: 'SQL Query', zh_Hans: 'SQL 查询' }, type: 'string', required: true }, + { name: 'limit', label: { en_US: 'Limit' }, type: 'number', required: false, hide: true }, + ], + }, + ], + allow_delete: true, + is_authorized: false, + ...overrides, + } as unknown as ToolWithProvider +} + +describe('getDataSourceCheckParams', () => { + it('should extract input schema from matching data source', () => { + const result = getDataSourceCheckParams( + createDataSourceData(), + [createDataSourceCollection()], + 'en_US', + ) + + expect(result.dataSourceInputsSchema).toEqual([ + { label: 'SQL Query', variable: 'query', type: 'string', required: true, hide: false }, + { label: 'Limit', variable: 'limit', type: 'number', required: false, hide: true }, + ]) + }) + + it('should mark notAuthed for builtin datasource without authorization', () => { + const result = getDataSourceCheckParams( + createDataSourceData(), + [createDataSourceCollection()], + 'en_US', + ) + + expect(result.notAuthed).toBe(true) + }) + + it('should mark as authed when is_authorized is true', () => { + const result = getDataSourceCheckParams( + createDataSourceData(), + [createDataSourceCollection({ is_authorized: true })], + 'en_US', + ) + + expect(result.notAuthed).toBe(false) + }) + + it('should return empty schemas when data source is not found', () => { + const result = getDataSourceCheckParams( + createDataSourceData({ plugin_id: 'non-existent' }), + [createDataSourceCollection()], + 'en_US', + ) + + expect(result.dataSourceInputsSchema).toEqual([]) + }) + + it('should return empty schemas when datasource item is not found', () => { + const result = getDataSourceCheckParams( + createDataSourceData({ datasource_name: 'non_existent_ds' }), + [createDataSourceCollection()], + 'en_US', + ) + + expect(result.dataSourceInputsSchema).toEqual([]) + }) + + it('should include language in result', () => { + const result = getDataSourceCheckParams( + createDataSourceData(), + [createDataSourceCollection()], + 'zh_Hans', + ) + + expect(result.language).toBe('zh_Hans') + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/debug.spec.ts b/web/app/components/workflow/utils/__tests__/debug.spec.ts new file mode 100644 index 0000000000..4439428e09 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/debug.spec.ts @@ -0,0 +1,48 @@ +import { VarInInspectType } from '@/types/workflow' +import { VarType } from '../../types' +import { outputToVarInInspect } from '../debug' + +describe('outputToVarInInspect', () => { + it('should create a VarInInspect object with correct fields', () => { + const result = outputToVarInInspect({ + nodeId: 'node-1', + name: 'output', + value: 'hello world', + }) + + expect(result).toMatchObject({ + type: VarInInspectType.node, + name: 'output', + description: '', + selector: ['node-1', 'output'], + value_type: VarType.string, + value: 'hello world', + edited: false, + visible: true, + is_truncated: false, + full_content: { size_bytes: 0, download_url: '' }, + }) + expect(result.id).toBeDefined() + }) + + it('should handle different value types', () => { + const result = outputToVarInInspect({ + nodeId: 'n2', + name: 'count', + value: 42, + }) + + expect(result.value).toBe(42) + expect(result.selector).toEqual(['n2', 'count']) + }) + + it('should handle null value', () => { + const result = outputToVarInInspect({ + nodeId: 'n3', + name: 'empty', + value: null, + }) + + expect(result.value).toBeNull() + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/edge.spec.ts b/web/app/components/workflow/utils/__tests__/edge.spec.ts new file mode 100644 index 0000000000..e5067d1866 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/edge.spec.ts @@ -0,0 +1,33 @@ +import { NodeRunningStatus } from '../../types' +import { getEdgeColor } from '../edge' + +describe('getEdgeColor', () => { + it('should return success color when status is Succeeded', () => { + expect(getEdgeColor(NodeRunningStatus.Succeeded)).toBe('var(--color-workflow-link-line-success-handle)') + }) + + it('should return error color when status is Failed', () => { + expect(getEdgeColor(NodeRunningStatus.Failed)).toBe('var(--color-workflow-link-line-error-handle)') + }) + + it('should return failure color when status is Exception', () => { + expect(getEdgeColor(NodeRunningStatus.Exception)).toBe('var(--color-workflow-link-line-failure-handle)') + }) + + it('should return default running color when status is Running and not fail branch', () => { + expect(getEdgeColor(NodeRunningStatus.Running)).toBe('var(--color-workflow-link-line-handle)') + }) + + it('should return failure color when status is Running and is fail branch', () => { + expect(getEdgeColor(NodeRunningStatus.Running, true)).toBe('var(--color-workflow-link-line-failure-handle)') + }) + + it('should return normal color when status is undefined', () => { + expect(getEdgeColor()).toBe('var(--color-workflow-link-line-normal)') + }) + + it('should return normal color for other statuses', () => { + expect(getEdgeColor(NodeRunningStatus.Waiting)).toBe('var(--color-workflow-link-line-normal)') + expect(getEdgeColor(NodeRunningStatus.NotStart)).toBe('var(--color-workflow-link-line-normal)') + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts b/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts new file mode 100644 index 0000000000..662b380f5d --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/elk-layout.spec.ts @@ -0,0 +1,665 @@ +import type { CommonEdgeType, CommonNodeType, Edge, Node } from '../../types' +import { createEdge, createNode, resetFixtureCounters } from '../../__tests__/fixtures' +import { CUSTOM_NODE, NODE_LAYOUT_HORIZONTAL_PADDING } from '../../constants' +import { CUSTOM_ITERATION_START_NODE } from '../../nodes/iteration-start/constants' +import { CUSTOM_LOOP_START_NODE } from '../../nodes/loop-start/constants' +import { BlockEnum } from '../../types' + +type ElkChild = Record & { id: string, width?: number, height?: number, x?: number, y?: number, children?: ElkChild[], ports?: Array<{ id: string }>, layoutOptions?: Record } +type ElkGraph = Record & { id: string, children?: ElkChild[], edges?: Array> } + +let layoutCallArgs: ElkGraph | null = null +let mockReturnOverride: ((graph: ElkGraph) => ElkGraph) | null = null + +vi.mock('elkjs/lib/elk.bundled.js', () => { + return { + default: class MockELK { + async layout(graph: ElkGraph) { + layoutCallArgs = graph + if (mockReturnOverride) + return mockReturnOverride(graph) + + const children = (graph.children || []).map((child: ElkChild, i: number) => ({ + ...child, + x: 100 + i * 300, + y: 50 + i * 100, + width: child.width || 244, + height: child.height || 100, + })) + return { ...graph, children } + } + }, + } +}) + +const { getLayoutByDagre, getLayoutForChildNodes } = await import('../elk-layout') + +function makeWorkflowNode(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Node { + return createNode({ + type: CUSTOM_NODE, + ...overrides, + }) +} + +function makeWorkflowEdge(overrides: Omit, 'data'> & { data?: Partial & Record } = {}): Edge { + return createEdge(overrides) +} + +beforeEach(() => { + resetFixtureCounters() + layoutCallArgs = null + mockReturnOverride = null +}) + +describe('getLayoutByDagre', () => { + it('should return layout for simple linear graph', async () => { + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [makeWorkflowEdge({ source: 'a', target: 'b' })] + + const result = await getLayoutByDagre(nodes, edges) + + expect(result.nodes.size).toBe(2) + expect(result.nodes.has('a')).toBe(true) + expect(result.nodes.has('b')).toBe(true) + expect(result.bounds.minX).toBe(0) + expect(result.bounds.minY).toBe(0) + }) + + it('should filter out nodes with parentId', async () => { + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'child', data: { type: BlockEnum.Code, title: '', desc: '' }, parentId: 'a' }), + ] + + const result = await getLayoutByDagre(nodes, []) + expect(result.nodes.size).toBe(1) + expect(result.nodes.has('child')).toBe(false) + }) + + it('should filter out non-CUSTOM_NODE type nodes', async () => { + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'iter-start', type: CUSTOM_ITERATION_START_NODE, data: { type: BlockEnum.IterationStart, title: '', desc: '' } }), + ] + + const result = await getLayoutByDagre(nodes, []) + expect(result.nodes.size).toBe(1) + }) + + it('should filter out iteration/loop internal edges', async () => { + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ source: 'a', target: 'b', data: { isInIteration: true, iteration_id: 'iter-1' } }), + ] + + await getLayoutByDagre(nodes, edges) + expect(layoutCallArgs!.edges).toHaveLength(0) + }) + + it('should use default dimensions when node has no width/height', async () => { + const node = makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + Reflect.deleteProperty(node, 'width') + Reflect.deleteProperty(node, 'height') + + const result = await getLayoutByDagre([node], []) + expect(result.nodes.size).toBe(1) + const info = result.nodes.get('a')! + expect(info.width).toBe(244) + expect(info.height).toBe(100) + }) + + it('should build ports for IfElse nodes with multiple branches', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { + type: BlockEnum.IfElse, + title: '', + desc: '', + cases: [{ case_id: 'case-1', logical_operator: 'and', conditions: [] }], + }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b', sourceHandle: 'case-1' }), + makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), + ] + + await getLayoutByDagre(nodes, edges) + const ifElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + expect(ifElkNode.ports).toHaveLength(2) + expect(ifElkNode.layoutOptions!['elk.portConstraints']).toBe('FIXED_ORDER') + }) + + it('should use normal node for IfElse with single branch', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { type: BlockEnum.IfElse, title: '', desc: '', cases: [{ case_id: 'case-1' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [makeWorkflowEdge({ source: 'if-1', target: 'b', sourceHandle: 'case-1' })] + + await getLayoutByDagre(nodes, edges) + const ifElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + expect(ifElkNode.ports).toBeUndefined() + }) + + it('should build ports for HumanInput nodes with multiple branches', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'hi-1', + data: { type: BlockEnum.HumanInput, title: '', desc: '', user_actions: [{ id: 'action-1' }, { id: 'action-2' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'hi-1', target: 'b', sourceHandle: 'action-1' }), + makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: '__timeout' }), + ] + + await getLayoutByDagre(nodes, edges) + const hiElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + expect(hiElkNode.ports).toHaveLength(2) + }) + + it('should use normal node for HumanInput with single branch', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'hi-1', + data: { type: BlockEnum.HumanInput, title: '', desc: '', user_actions: [{ id: 'action-1' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [makeWorkflowEdge({ source: 'hi-1', target: 'b', sourceHandle: 'action-1' })] + + await getLayoutByDagre(nodes, edges) + const hiElkNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + expect(hiElkNode.ports).toBeUndefined() + }) + + it('should normalise bounds so minX and minY start at 0', async () => { + const nodes = [makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } })] + const result = await getLayoutByDagre(nodes, []) + expect(result.bounds.minX).toBe(0) + expect(result.bounds.minY).toBe(0) + }) + + it('should return empty layout when no nodes match filter', async () => { + const result = await getLayoutByDagre([], []) + expect(result.nodes.size).toBe(0) + expect(result.bounds).toEqual({ minX: 0, minY: 0, maxX: 0, maxY: 0 }) + }) + + it('should sort IfElse edges with false (ELSE) last', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { + type: BlockEnum.IfElse, + title: '', + desc: '', + cases: [ + { case_id: 'case-a', logical_operator: 'and', conditions: [] }, + { case_id: 'case-b', logical_operator: 'and', conditions: [] }, + ], + }, + }), + makeWorkflowNode({ id: 'x', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'y', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'z', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e-else', source: 'if-1', target: 'z', sourceHandle: 'false' }), + makeWorkflowEdge({ id: 'e-a', source: 'if-1', target: 'x', sourceHandle: 'case-a' }), + makeWorkflowEdge({ id: 'e-b', source: 'if-1', target: 'y', sourceHandle: 'case-b' }), + ] + + await getLayoutByDagre(nodes, edges) + const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + const portIds = ifNode.ports!.map((p: { id: string }) => p.id) + expect(portIds[portIds.length - 1]).toContain('false') + }) + + it('should sort HumanInput edges with __timeout last', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'hi-1', + data: { type: BlockEnum.HumanInput, title: '', desc: '', user_actions: [{ id: 'a1' }, { id: 'a2' }] }, + }), + makeWorkflowNode({ id: 'x', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'y', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'z', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e-timeout', source: 'hi-1', target: 'z', sourceHandle: '__timeout' }), + makeWorkflowEdge({ id: 'e-a1', source: 'hi-1', target: 'x', sourceHandle: 'a1' }), + makeWorkflowEdge({ id: 'e-a2', source: 'hi-1', target: 'y', sourceHandle: 'a2' }), + ] + + await getLayoutByDagre(nodes, edges) + const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + const portIds = hiNode.ports!.map((p: { id: string }) => p.id) + expect(portIds[portIds.length - 1]).toContain('__timeout') + }) + + it('should assign sourcePort to edges from IfElse nodes with ports', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { type: BlockEnum.IfElse, title: '', desc: '', cases: [{ case_id: 'case-1' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b', sourceHandle: 'case-1' }), + makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), + ] + + await getLayoutByDagre(nodes, edges) + const portEdges = layoutCallArgs!.edges!.filter((e: Record) => e.sourcePort) + expect(portEdges.length).toBeGreaterThan(0) + }) + + it('should handle edges without sourceHandle for ports (use index)', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { type: BlockEnum.IfElse, title: '', desc: '', cases: [] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const e1 = makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b' }) + const e2 = makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c' }) + Reflect.deleteProperty(e1, 'sourceHandle') + Reflect.deleteProperty(e2, 'sourceHandle') + + const result = await getLayoutByDagre(nodes, [e1, e2]) + expect(result.nodes.size).toBeGreaterThan(0) + }) + + it('should handle collectLayout with null x/y/width/height values', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: (graph.children || []).map((child: ElkChild) => ({ + id: child.id, + })), + }) + + const nodes = [makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } })] + const result = await getLayoutByDagre(nodes, []) + const info = result.nodes.get('a')! + expect(info.x).toBe(0) + expect(info.y).toBe(0) + expect(info.width).toBe(244) + expect(info.height).toBe(100) + }) + + it('should parse layer index from layoutOptions', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: (graph.children || []).map((child: ElkChild, i: number) => ({ + ...child, + x: i * 300, + y: 0, + width: 244, + height: 100, + layoutOptions: { + 'org.eclipse.elk.layered.layerIndex': String(i), + }, + })), + }) + + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = await getLayoutByDagre(nodes, []) + expect(result.nodes.get('a')!.layer).toBe(0) + expect(result.nodes.get('b')!.layer).toBe(1) + }) + + it('should handle collectLayout with nested children', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: [ + { + id: 'parent-node', + x: 0, + y: 0, + width: 500, + height: 400, + children: [ + { id: 'nested-1', x: 10, y: 10, width: 200, height: 100 }, + { id: 'nested-2', x: 10, y: 120, width: 200, height: 100 }, + ], + }, + ], + }) + + const nodes = [ + makeWorkflowNode({ id: 'parent-node', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'nested-1', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'nested-2', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = await getLayoutByDagre(nodes, []) + expect(result.nodes.has('nested-1')).toBe(true) + expect(result.nodes.has('nested-2')).toBe(true) + }) + + it('should handle collectLayout with predicate filtering some children', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: [ + { id: 'visible', x: 0, y: 0, width: 200, height: 100 }, + { id: 'also-visible', x: 300, y: 0, width: 200, height: 100 }, + ], + }) + + const nodes = [ + makeWorkflowNode({ id: 'visible', data: { type: BlockEnum.Start, title: '', desc: '' } }), + makeWorkflowNode({ id: 'also-visible', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = await getLayoutByDagre(nodes, []) + expect(result.nodes.size).toBe(2) + }) + + it('should sort IfElse edges where case not found in cases array', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { type: BlockEnum.IfElse, title: '', desc: '', cases: [{ case_id: 'known-case' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b', sourceHandle: 'unknown-case' }), + makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'other-unknown' }), + ] + + await getLayoutByDagre(nodes, edges) + const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + expect(ifNode.ports).toHaveLength(2) + }) + + it('should sort HumanInput edges where action not found in user_actions', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'hi-1', + data: { type: BlockEnum.HumanInput, title: '', desc: '', user_actions: [{ id: 'known-action' }] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'hi-1', target: 'b', sourceHandle: 'unknown-action' }), + makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: 'another-unknown' }), + ] + + await getLayoutByDagre(nodes, edges) + const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + expect(hiNode.ports).toHaveLength(2) + }) + + it('should handle IfElse edges without handles (no sourceHandle)', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'if-1', + data: { type: BlockEnum.IfElse, title: '', desc: '', cases: [] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const e1 = makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b' }) + const e2 = makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c' }) + Reflect.deleteProperty(e1, 'sourceHandle') + Reflect.deleteProperty(e2, 'sourceHandle') + + await getLayoutByDagre(nodes, [e1, e2]) + const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + expect(ifNode.ports).toHaveLength(2) + }) + + it('should handle HumanInput edges without handles', async () => { + const nodes = [ + makeWorkflowNode({ + id: 'hi-1', + data: { type: BlockEnum.HumanInput, title: '', desc: '', user_actions: [] }, + }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const e1 = makeWorkflowEdge({ id: 'e1', source: 'hi-1', target: 'b' }) + const e2 = makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c' }) + Reflect.deleteProperty(e1, 'sourceHandle') + Reflect.deleteProperty(e2, 'sourceHandle') + + await getLayoutByDagre(nodes, [e1, e2]) + const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + expect(hiNode.ports).toHaveLength(2) + }) + + it('should handle IfElse with no cases property', async () => { + const nodes = [ + makeWorkflowNode({ id: 'if-1', data: { type: BlockEnum.IfElse, title: '', desc: '' } }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'if-1', target: 'b', sourceHandle: 'true' }), + makeWorkflowEdge({ id: 'e2', source: 'if-1', target: 'c', sourceHandle: 'false' }), + ] + + await getLayoutByDagre(nodes, edges) + const ifNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'if-1')! + expect(ifNode.ports).toHaveLength(2) + }) + + it('should handle HumanInput with no user_actions property', async () => { + const nodes = [ + makeWorkflowNode({ id: 'hi-1', data: { type: BlockEnum.HumanInput, title: '', desc: '' } }), + makeWorkflowNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ id: 'e1', source: 'hi-1', target: 'b', sourceHandle: 'action-1' }), + makeWorkflowEdge({ id: 'e2', source: 'hi-1', target: 'c', sourceHandle: '__timeout' }), + ] + + await getLayoutByDagre(nodes, edges) + const hiNode = layoutCallArgs!.children!.find((c: ElkChild) => c.id === 'hi-1')! + expect(hiNode.ports).toHaveLength(2) + }) + + it('should filter loop internal edges', async () => { + const nodes = [ + makeWorkflowNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ source: 'x', target: 'y', data: { isInLoop: true, loop_id: 'loop-1' } }), + ] + + await getLayoutByDagre(nodes, edges) + expect(layoutCallArgs!.edges).toHaveLength(0) + }) +}) + +describe('getLayoutForChildNodes', () => { + it('should return null when no child nodes exist', async () => { + const nodes = [ + makeWorkflowNode({ id: 'parent', data: { type: BlockEnum.Iteration, title: '', desc: '' } }), + ] + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).toBeNull() + }) + + it('should layout child nodes of an iteration', async () => { + const nodes = [ + makeWorkflowNode({ id: 'parent', data: { type: BlockEnum.Iteration, title: '', desc: '' } }), + makeWorkflowNode({ + id: 'iter-start', + type: CUSTOM_ITERATION_START_NODE, + parentId: 'parent', + data: { type: BlockEnum.IterationStart, title: '', desc: '' }, + }), + makeWorkflowNode({ id: 'child-1', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ source: 'iter-start', target: 'child-1', data: { isInIteration: true, iteration_id: 'parent' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, edges) + expect(result).not.toBeNull() + expect(result!.nodes.size).toBe(2) + expect(result!.bounds.minX).toBe(0) + }) + + it('should layout child nodes of a loop', async () => { + const nodes = [ + makeWorkflowNode({ id: 'loop-p', data: { type: BlockEnum.Loop, title: '', desc: '' } }), + makeWorkflowNode({ + id: 'loop-start', + type: CUSTOM_LOOP_START_NODE, + parentId: 'loop-p', + data: { type: BlockEnum.LoopStart, title: '', desc: '' }, + }), + makeWorkflowNode({ id: 'loop-child', parentId: 'loop-p', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ source: 'loop-start', target: 'loop-child', data: { isInLoop: true, loop_id: 'loop-p' } }), + ] + + const result = await getLayoutForChildNodes('loop-p', nodes, edges) + expect(result).not.toBeNull() + expect(result!.nodes.size).toBe(2) + }) + + it('should only include edges belonging to the parent iteration', async () => { + const nodes = [ + makeWorkflowNode({ id: 'child-a', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'child-b', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + makeWorkflowEdge({ source: 'child-a', target: 'child-b', data: { isInIteration: true, iteration_id: 'parent' } }), + makeWorkflowEdge({ source: 'x', target: 'y', data: { isInIteration: true, iteration_id: 'other-parent' } }), + ] + + await getLayoutForChildNodes('parent', nodes, edges) + expect(layoutCallArgs!.edges).toHaveLength(1) + }) + + it('should adjust start node position when x exceeds horizontal padding', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: (graph.children || []).map((child: ElkChild, i: number) => ({ + ...child, + x: 200 + i * 300, + y: 50, + width: 244, + height: 100, + })), + }) + + const nodes = [ + makeWorkflowNode({ + id: 'start', + type: CUSTOM_ITERATION_START_NODE, + parentId: 'parent', + data: { type: BlockEnum.IterationStart, title: '', desc: '' }, + }), + makeWorkflowNode({ id: 'child', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + const startInfo = result!.nodes.get('start')! + expect(startInfo.x).toBeLessThanOrEqual(NODE_LAYOUT_HORIZONTAL_PADDING / 1.5 + 1) + }) + + it('should not shift when start node x is already within padding', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: (graph.children || []).map((child: ElkChild, i: number) => ({ + ...child, + x: 10 + i * 300, + y: 50, + width: 244, + height: 100, + })), + }) + + const nodes = [ + makeWorkflowNode({ + id: 'start', + type: CUSTOM_ITERATION_START_NODE, + parentId: 'parent', + data: { type: BlockEnum.IterationStart, title: '', desc: '' }, + }), + makeWorkflowNode({ id: 'child', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + }) + + it('should handle child nodes identified by data type LoopStart', async () => { + const nodes = [ + makeWorkflowNode({ id: 'ls', parentId: 'parent', data: { type: BlockEnum.LoopStart, title: '', desc: '' } }), + makeWorkflowNode({ id: 'child', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + expect(result!.nodes.size).toBe(2) + }) + + it('should handle child nodes identified by data type IterationStart', async () => { + const nodes = [ + makeWorkflowNode({ id: 'is', parentId: 'parent', data: { type: BlockEnum.IterationStart, title: '', desc: '' } }), + makeWorkflowNode({ id: 'child', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + expect(result!.nodes.size).toBe(2) + }) + + it('should handle no start node in child layout', async () => { + const nodes = [ + makeWorkflowNode({ id: 'c1', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + makeWorkflowNode({ id: 'c2', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + expect(result!.nodes.size).toBe(2) + }) + + it('should return original layout when bounds are not finite', async () => { + mockReturnOverride = (graph: ElkGraph) => ({ + ...graph, + children: [], + }) + + const nodes = [ + makeWorkflowNode({ id: 'c1', parentId: 'parent', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const result = await getLayoutForChildNodes('parent', nodes, []) + expect(result).not.toBeNull() + expect(result!.bounds).toEqual({ minX: 0, minY: 0, maxX: 0, maxY: 0 }) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/gen-node-meta-data.spec.ts b/web/app/components/workflow/utils/__tests__/gen-node-meta-data.spec.ts new file mode 100644 index 0000000000..86203c76b1 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/gen-node-meta-data.spec.ts @@ -0,0 +1,70 @@ +import { BlockClassificationEnum } from '../../block-selector/types' +import { BlockEnum } from '../../types' +import { genNodeMetaData } from '../gen-node-meta-data' + +describe('genNodeMetaData', () => { + it('should generate metadata with all required fields', () => { + const result = genNodeMetaData({ + sort: 1, + type: BlockEnum.LLM, + title: 'LLM Node', + }) + + expect(result).toEqual({ + classification: BlockClassificationEnum.Default, + sort: 1, + type: BlockEnum.LLM, + title: 'LLM Node', + author: 'Dify', + helpLinkUri: BlockEnum.LLM, + isRequired: false, + isUndeletable: false, + isStart: false, + isSingleton: false, + isTypeFixed: false, + }) + }) + + it('should use custom values when provided', () => { + const result = genNodeMetaData({ + classification: BlockClassificationEnum.Logic, + sort: 5, + type: BlockEnum.Start, + title: 'Start', + author: 'Custom', + helpLinkUri: 'code', + isRequired: true, + isUndeletable: true, + isStart: true, + isSingleton: true, + isTypeFixed: true, + }) + + expect(result.classification).toBe(BlockClassificationEnum.Logic) + expect(result.author).toBe('Custom') + expect(result.helpLinkUri).toBe('code') + expect(result.isRequired).toBe(true) + expect(result.isUndeletable).toBe(true) + expect(result.isStart).toBe(true) + expect(result.isSingleton).toBe(true) + expect(result.isTypeFixed).toBe(true) + }) + + it('should default title to empty string', () => { + const result = genNodeMetaData({ + sort: 0, + type: BlockEnum.Code, + }) + + expect(result.title).toBe('') + }) + + it('should fall back helpLinkUri to type when not provided', () => { + const result = genNodeMetaData({ + sort: 0, + type: BlockEnum.HttpRequest, + }) + + expect(result.helpLinkUri).toBe(BlockEnum.HttpRequest) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/node-navigation.spec.ts b/web/app/components/workflow/utils/__tests__/node-navigation.spec.ts new file mode 100644 index 0000000000..8ccdff0604 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/node-navigation.spec.ts @@ -0,0 +1,161 @@ +import { + scrollToWorkflowNode, + selectWorkflowNode, + setupNodeSelectionListener, + setupScrollToNodeListener, +} from '../node-navigation' + +describe('selectWorkflowNode', () => { + it('should dispatch workflow:select-node event with correct detail', () => { + const handler = vi.fn() + document.addEventListener('workflow:select-node', handler) + + selectWorkflowNode('node-1', true) + + expect(handler).toHaveBeenCalledTimes(1) + const event = handler.mock.calls[0][0] as CustomEvent + expect(event.detail).toEqual({ nodeId: 'node-1', focus: true }) + + document.removeEventListener('workflow:select-node', handler) + }) + + it('should default focus to false', () => { + const handler = vi.fn() + document.addEventListener('workflow:select-node', handler) + + selectWorkflowNode('node-2') + + const event = handler.mock.calls[0][0] as CustomEvent + expect(event.detail.focus).toBe(false) + + document.removeEventListener('workflow:select-node', handler) + }) +}) + +describe('scrollToWorkflowNode', () => { + it('should dispatch workflow:scroll-to-node event', () => { + const handler = vi.fn() + document.addEventListener('workflow:scroll-to-node', handler) + + scrollToWorkflowNode('node-5') + + expect(handler).toHaveBeenCalledTimes(1) + const event = handler.mock.calls[0][0] as CustomEvent + expect(event.detail).toEqual({ nodeId: 'node-5' }) + + document.removeEventListener('workflow:scroll-to-node', handler) + }) +}) + +describe('setupNodeSelectionListener', () => { + it('should call handleNodeSelect when event is dispatched', () => { + const handleNodeSelect = vi.fn() + const cleanup = setupNodeSelectionListener(handleNodeSelect) + + selectWorkflowNode('node-10') + + expect(handleNodeSelect).toHaveBeenCalledWith('node-10') + + cleanup() + }) + + it('should also scroll to node when focus is true', () => { + vi.useFakeTimers() + const handleNodeSelect = vi.fn() + const scrollHandler = vi.fn() + document.addEventListener('workflow:scroll-to-node', scrollHandler) + + const cleanup = setupNodeSelectionListener(handleNodeSelect) + selectWorkflowNode('node-11', true) + + expect(handleNodeSelect).toHaveBeenCalledWith('node-11') + + vi.advanceTimersByTime(150) + expect(scrollHandler).toHaveBeenCalledTimes(1) + + cleanup() + document.removeEventListener('workflow:scroll-to-node', scrollHandler) + vi.useRealTimers() + }) + + it('should not call handler after cleanup', () => { + const handleNodeSelect = vi.fn() + const cleanup = setupNodeSelectionListener(handleNodeSelect) + + cleanup() + selectWorkflowNode('node-12') + + expect(handleNodeSelect).not.toHaveBeenCalled() + }) + + it('should ignore events with empty nodeId', () => { + const handleNodeSelect = vi.fn() + const cleanup = setupNodeSelectionListener(handleNodeSelect) + + const event = new CustomEvent('workflow:select-node', { + detail: { nodeId: '', focus: false }, + }) + document.dispatchEvent(event) + + expect(handleNodeSelect).not.toHaveBeenCalled() + + cleanup() + }) +}) + +describe('setupScrollToNodeListener', () => { + it('should call reactflow.setCenter when scroll event targets an existing node', () => { + const nodes = [{ id: 'n1', position: { x: 100, y: 200 } }] + const reactflow = { setCenter: vi.fn() } + + const cleanup = setupScrollToNodeListener(nodes, reactflow) + scrollToWorkflowNode('n1') + + expect(reactflow.setCenter).toHaveBeenCalledTimes(1) + const [targetX, targetY, options] = reactflow.setCenter.mock.calls[0] + expect(targetX).toBeGreaterThan(100) + expect(targetY).toBeGreaterThan(200) + expect(options).toEqual({ zoom: 1, duration: 800 }) + + cleanup() + }) + + it('should not call setCenter when node is not found', () => { + const nodes = [{ id: 'n1', position: { x: 0, y: 0 } }] + const reactflow = { setCenter: vi.fn() } + + const cleanup = setupScrollToNodeListener(nodes, reactflow) + scrollToWorkflowNode('non-existent') + + expect(reactflow.setCenter).not.toHaveBeenCalled() + + cleanup() + }) + + it('should not react after cleanup', () => { + const nodes = [{ id: 'n1', position: { x: 0, y: 0 } }] + const reactflow = { setCenter: vi.fn() } + + const cleanup = setupScrollToNodeListener(nodes, reactflow) + cleanup() + + scrollToWorkflowNode('n1') + expect(reactflow.setCenter).not.toHaveBeenCalled() + }) + + it('should ignore events with empty nodeId', () => { + const nodes = [{ id: 'n1', position: { x: 0, y: 0 } }] + const reactflow = { setCenter: vi.fn() } + + const cleanup = setupScrollToNodeListener(nodes, reactflow) + + const event = new CustomEvent('workflow:scroll-to-node', { + detail: { nodeId: '' }, + }) + document.dispatchEvent(event) + + expect(reactflow.setCenter).not.toHaveBeenCalled() + + cleanup() + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/node.spec.ts b/web/app/components/workflow/utils/__tests__/node.spec.ts new file mode 100644 index 0000000000..19f3a1614a --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/node.spec.ts @@ -0,0 +1,219 @@ +import type { IterationNodeType } from '../../nodes/iteration/types' +import type { LoopNodeType } from '../../nodes/loop/types' +import type { CommonNodeType, Node } from '../../types' +import { CUSTOM_NODE, ITERATION_CHILDREN_Z_INDEX, ITERATION_NODE_Z_INDEX, LOOP_CHILDREN_Z_INDEX, LOOP_NODE_Z_INDEX } from '../../constants' +import { CUSTOM_ITERATION_START_NODE } from '../../nodes/iteration-start/constants' +import { CUSTOM_LOOP_START_NODE } from '../../nodes/loop-start/constants' +import { CUSTOM_SIMPLE_NODE } from '../../simple-node/constants' +import { BlockEnum } from '../../types' +import { + generateNewNode, + genNewNodeTitleFromOld, + getIterationStartNode, + getLoopStartNode, + getNestedNodePosition, + getNodeCustomTypeByNodeDataType, + getTopLeftNodePosition, + hasRetryNode, +} from '../node' + +describe('generateNewNode', () => { + it('should create a basic node with default CUSTOM_NODE type', () => { + const { newNode } = generateNewNode({ + data: { title: 'Test', desc: '', type: BlockEnum.Code } as CommonNodeType, + position: { x: 100, y: 200 }, + }) + + expect(newNode.type).toBe(CUSTOM_NODE) + expect(newNode.position).toEqual({ x: 100, y: 200 }) + expect(newNode.data.title).toBe('Test') + expect(newNode.id).toBeDefined() + }) + + it('should use provided id when given', () => { + const { newNode } = generateNewNode({ + id: 'custom-id', + data: { title: 'Test', desc: '', type: BlockEnum.Code } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(newNode.id).toBe('custom-id') + }) + + it('should set ITERATION_NODE_Z_INDEX for iteration nodes', () => { + const { newNode } = generateNewNode({ + data: { title: 'Iter', desc: '', type: BlockEnum.Iteration } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(newNode.zIndex).toBe(ITERATION_NODE_Z_INDEX) + }) + + it('should set LOOP_NODE_Z_INDEX for loop nodes', () => { + const { newNode } = generateNewNode({ + data: { title: 'Loop', desc: '', type: BlockEnum.Loop } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(newNode.zIndex).toBe(LOOP_NODE_Z_INDEX) + }) + + it('should create an iteration start node for iteration type', () => { + const { newNode, newIterationStartNode } = generateNewNode({ + id: 'iter-1', + data: { title: 'Iter', desc: '', type: BlockEnum.Iteration } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(newIterationStartNode).toBeDefined() + expect(newIterationStartNode!.id).toBe('iter-1start') + expect(newIterationStartNode!.data.type).toBe(BlockEnum.IterationStart) + expect((newNode.data as IterationNodeType).start_node_id).toBe('iter-1start') + expect((newNode.data as CommonNodeType)._children).toEqual([ + { nodeId: 'iter-1start', nodeType: BlockEnum.IterationStart }, + ]) + }) + + it('should create a loop start node for loop type', () => { + const { newNode, newLoopStartNode } = generateNewNode({ + id: 'loop-1', + data: { title: 'Loop', desc: '', type: BlockEnum.Loop } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(newLoopStartNode).toBeDefined() + expect(newLoopStartNode!.id).toBe('loop-1start') + expect(newLoopStartNode!.data.type).toBe(BlockEnum.LoopStart) + expect((newNode.data as LoopNodeType).start_node_id).toBe('loop-1start') + expect((newNode.data as CommonNodeType)._children).toEqual([ + { nodeId: 'loop-1start', nodeType: BlockEnum.LoopStart }, + ]) + }) + + it('should not create child start nodes for regular types', () => { + const result = generateNewNode({ + data: { title: 'Code', desc: '', type: BlockEnum.Code } as CommonNodeType, + position: { x: 0, y: 0 }, + }) + + expect(result.newIterationStartNode).toBeUndefined() + expect(result.newLoopStartNode).toBeUndefined() + }) +}) + +describe('getIterationStartNode', () => { + it('should create a properly configured iteration start node', () => { + const node = getIterationStartNode('parent-iter') + + expect(node.id).toBe('parent-iterstart') + expect(node.type).toBe(CUSTOM_ITERATION_START_NODE) + expect(node.data.type).toBe(BlockEnum.IterationStart) + expect(node.data.isInIteration).toBe(true) + expect(node.parentId).toBe('parent-iter') + expect(node.selectable).toBe(false) + expect(node.draggable).toBe(false) + expect(node.zIndex).toBe(ITERATION_CHILDREN_Z_INDEX) + expect(node.position).toEqual({ x: 24, y: 68 }) + }) +}) + +describe('getLoopStartNode', () => { + it('should create a properly configured loop start node', () => { + const node = getLoopStartNode('parent-loop') + + expect(node.id).toBe('parent-loopstart') + expect(node.type).toBe(CUSTOM_LOOP_START_NODE) + expect(node.data.type).toBe(BlockEnum.LoopStart) + expect(node.data.isInLoop).toBe(true) + expect(node.parentId).toBe('parent-loop') + expect(node.selectable).toBe(false) + expect(node.draggable).toBe(false) + expect(node.zIndex).toBe(LOOP_CHILDREN_Z_INDEX) + expect(node.position).toEqual({ x: 24, y: 68 }) + }) +}) + +describe('genNewNodeTitleFromOld', () => { + it('should append (1) to a title without a counter', () => { + expect(genNewNodeTitleFromOld('LLM')).toBe('LLM (1)') + }) + + it('should increment existing counter', () => { + expect(genNewNodeTitleFromOld('LLM (1)')).toBe('LLM (2)') + expect(genNewNodeTitleFromOld('LLM (99)')).toBe('LLM (100)') + }) + + it('should handle titles with spaces around counter', () => { + expect(genNewNodeTitleFromOld('My Node (3)')).toBe('My Node (4)') + }) + + it('should handle titles that happen to contain parentheses in the name', () => { + expect(genNewNodeTitleFromOld('Node (special) name')).toBe('Node (special) name (1)') + }) +}) + +describe('getTopLeftNodePosition', () => { + it('should return the minimum x and y from nodes', () => { + const nodes = [ + { position: { x: 100, y: 50 } }, + { position: { x: 20, y: 200 } }, + { position: { x: 50, y: 10 } }, + ] as Node[] + + expect(getTopLeftNodePosition(nodes)).toEqual({ x: 20, y: 10 }) + }) + + it('should handle a single node', () => { + const nodes = [{ position: { x: 42, y: 99 } }] as Node[] + expect(getTopLeftNodePosition(nodes)).toEqual({ x: 42, y: 99 }) + }) + + it('should handle negative positions', () => { + const nodes = [ + { position: { x: -10, y: -20 } }, + { position: { x: 5, y: -30 } }, + ] as Node[] + + expect(getTopLeftNodePosition(nodes)).toEqual({ x: -10, y: -30 }) + }) +}) + +describe('getNestedNodePosition', () => { + it('should compute relative position of child to parent', () => { + const node = { position: { x: 150, y: 200 } } as Node + const parent = { position: { x: 100, y: 80 } } as Node + + expect(getNestedNodePosition(node, parent)).toEqual({ x: 50, y: 120 }) + }) +}) + +describe('hasRetryNode', () => { + it.each([BlockEnum.LLM, BlockEnum.Tool, BlockEnum.HttpRequest, BlockEnum.Code])( + 'should return true for %s', + (nodeType) => { + expect(hasRetryNode(nodeType)).toBe(true) + }, + ) + + it.each([BlockEnum.Start, BlockEnum.End, BlockEnum.IfElse, BlockEnum.Iteration])( + 'should return false for %s', + (nodeType) => { + expect(hasRetryNode(nodeType)).toBe(false) + }, + ) + + it('should return false when nodeType is undefined', () => { + expect(hasRetryNode()).toBe(false) + }) +}) + +describe('getNodeCustomTypeByNodeDataType', () => { + it('should return CUSTOM_SIMPLE_NODE for LoopEnd', () => { + expect(getNodeCustomTypeByNodeDataType(BlockEnum.LoopEnd)).toBe(CUSTOM_SIMPLE_NODE) + }) + + it('should return undefined for other types', () => { + expect(getNodeCustomTypeByNodeDataType(BlockEnum.Code)).toBeUndefined() + expect(getNodeCustomTypeByNodeDataType(BlockEnum.LLM)).toBeUndefined() + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/tool.spec.ts b/web/app/components/workflow/utils/__tests__/tool.spec.ts new file mode 100644 index 0000000000..baa61d8a4e --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/tool.spec.ts @@ -0,0 +1,191 @@ +import type { ToolNodeType } from '../../nodes/tool/types' +import type { ToolWithProvider } from '../../types' +import { CollectionType } from '@/app/components/tools/types' +import { BlockEnum } from '../../types' +import { CHUNK_TYPE_MAP, getToolCheckParams, wrapStructuredVarItem } from '../tool' + +vi.mock('@/app/components/tools/utils/to-form-schema', () => ({ + toolParametersToFormSchemas: vi.fn((params: Array>) => + params.map(p => ({ + variable: p.name, + label: p.label || { en_US: p.name }, + type: p.type || 'string', + required: p.required ?? false, + form: p.form ?? 'llm', + }))), +})) + +vi.mock('@/utils', () => ({ + canFindTool: vi.fn((collectionId: string, providerId: string) => collectionId === providerId), +})) + +function createToolData(overrides: Partial = {}): ToolNodeType { + return { + title: 'Tool', + desc: '', + type: BlockEnum.Tool, + provider_id: 'builtin-search', + provider_type: CollectionType.builtIn, + tool_name: 'google_search', + tool_parameters: {}, + tool_configurations: {}, + ...overrides, + } as ToolNodeType +} + +function createToolCollection(overrides: Partial = {}): ToolWithProvider { + return { + id: 'builtin-search', + name: 'Search', + tools: [ + { + name: 'google_search', + parameters: [ + { name: 'query', label: { en_US: 'Query', zh_Hans: '查询' }, type: 'string', required: true, form: 'llm' }, + { name: 'api_key', label: { en_US: 'API Key' }, type: 'string', required: true, form: 'credential' }, + ], + }, + ], + allow_delete: true, + is_team_authorization: false, + ...overrides, + } as unknown as ToolWithProvider +} + +describe('getToolCheckParams', () => { + it('should separate llm inputs from settings', () => { + const result = getToolCheckParams( + createToolData(), + [createToolCollection()], + [], + [], + 'en_US', + ) + + expect(result.toolInputsSchema).toEqual([ + { label: 'Query', variable: 'query', type: 'string', required: true }, + ]) + expect(result.toolSettingSchema).toHaveLength(1) + expect(result.toolSettingSchema[0].variable).toBe('api_key') + }) + + it('should mark notAuthed for builtin tools without team auth', () => { + const result = getToolCheckParams( + createToolData(), + [createToolCollection()], + [], + [], + 'en_US', + ) + + expect(result.notAuthed).toBe(true) + }) + + it('should mark authed when is_team_authorization is true', () => { + const result = getToolCheckParams( + createToolData(), + [createToolCollection({ is_team_authorization: true })], + [], + [], + 'en_US', + ) + + expect(result.notAuthed).toBe(false) + }) + + it('should use custom tools when provider_type is custom', () => { + const customTool = createToolCollection({ id: 'custom-tool' }) + const result = getToolCheckParams( + createToolData({ provider_id: 'custom-tool', provider_type: CollectionType.custom }), + [], + [customTool], + [], + 'en_US', + ) + + expect(result.toolInputsSchema).toHaveLength(1) + }) + + it('should return empty schemas when tool is not found', () => { + const result = getToolCheckParams( + createToolData({ provider_id: 'non-existent' }), + [], + [], + [], + 'en_US', + ) + + expect(result.toolInputsSchema).toEqual([]) + expect(result.toolSettingSchema).toEqual([]) + }) + + it('should include language in result', () => { + const result = getToolCheckParams(createToolData(), [createToolCollection()], [], [], 'zh_Hans') + expect(result.language).toBe('zh_Hans') + }) + + it('should use workflowTools when provider_type is workflow', () => { + const workflowTool = createToolCollection({ id: 'wf-tool' }) + const result = getToolCheckParams( + createToolData({ provider_id: 'wf-tool', provider_type: CollectionType.workflow }), + [], + [], + [workflowTool], + 'en_US', + ) + + expect(result.toolInputsSchema).toHaveLength(1) + }) + + it('should fallback to en_US label when language key is missing', () => { + const tool = createToolCollection({ + tools: [ + { + name: 'google_search', + parameters: [ + { name: 'query', label: { en_US: 'Query' }, type: 'string', required: true, form: 'llm' }, + ], + }, + ], + } as Partial) + + const result = getToolCheckParams( + createToolData(), + [tool], + [], + [], + 'ja_JP', + ) + + expect(result.toolInputsSchema[0].label).toBe('Query') + }) +}) + +describe('CHUNK_TYPE_MAP', () => { + it('should contain all expected chunk type mappings', () => { + expect(CHUNK_TYPE_MAP).toEqual({ + general_chunks: 'GeneralStructureChunk', + parent_child_chunks: 'ParentChildStructureChunk', + qa_chunks: 'QAStructureChunk', + }) + }) +}) + +describe('wrapStructuredVarItem', () => { + it('should wrap an output item into StructuredOutput format', () => { + const outputItem = { + name: 'result', + value: { type: 'string', description: 'test' }, + } + + const result = wrapStructuredVarItem(outputItem, 'json_schema') + + expect(result.schema.type).toBe('object') + expect(result.schema.additionalProperties).toBe(false) + expect(result.schema.properties.result).toEqual({ + type: 'string', + description: 'test', + schemaType: 'json_schema', + }) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/trigger.spec.ts b/web/app/components/workflow/utils/__tests__/trigger.spec.ts new file mode 100644 index 0000000000..b74126d69f --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/trigger.spec.ts @@ -0,0 +1,132 @@ +import type { TriggerWithProvider } from '../../block-selector/types' +import type { PluginTriggerNodeType } from '../../nodes/trigger-plugin/types' +import { CollectionType } from '@/app/components/tools/types' +import { BlockEnum } from '../../types' +import { getTriggerCheckParams } from '../trigger' + +function createTriggerData(overrides: Partial = {}): PluginTriggerNodeType { + return { + title: 'Trigger', + desc: '', + type: BlockEnum.TriggerPlugin, + provider_id: 'provider-1', + provider_type: CollectionType.builtIn, + provider_name: 'my-provider', + event_name: 'on_message', + event_label: 'On Message', + event_parameters: {}, + event_configurations: {}, + output_schema: {}, + ...overrides, + } as PluginTriggerNodeType +} + +function createTriggerProvider(overrides: Partial = {}): TriggerWithProvider { + return { + id: 'provider-1', + name: 'my-provider', + plugin_id: 'plugin-1', + events: [ + { + name: 'on_message', + label: { en_US: 'On Message', zh_Hans: '收到消息' }, + parameters: [ + { + name: 'channel', + label: { en_US: 'Channel', zh_Hans: '频道' }, + required: true, + }, + { + name: 'filter', + label: { en_US: 'Filter' }, + required: false, + }, + ], + }, + ], + ...overrides, + } as unknown as TriggerWithProvider +} + +describe('getTriggerCheckParams', () => { + it('should return empty schema when triggerProviders is undefined', () => { + const result = getTriggerCheckParams(createTriggerData(), undefined, 'en_US') + + expect(result).toEqual({ + triggerInputsSchema: [], + isReadyForCheckValid: false, + }) + }) + + it('should match provider by name and extract parameters', () => { + const result = getTriggerCheckParams( + createTriggerData(), + [createTriggerProvider()], + 'en_US', + ) + + expect(result.isReadyForCheckValid).toBe(true) + expect(result.triggerInputsSchema).toEqual([ + { variable: 'channel', label: 'Channel', required: true }, + { variable: 'filter', label: 'Filter', required: false }, + ]) + }) + + it('should use the requested language for labels', () => { + const result = getTriggerCheckParams( + createTriggerData(), + [createTriggerProvider()], + 'zh_Hans', + ) + + expect(result.triggerInputsSchema[0].label).toBe('频道') + }) + + it('should fall back to en_US when language label is missing', () => { + const result = getTriggerCheckParams( + createTriggerData(), + [createTriggerProvider()], + 'ja_JP', + ) + + expect(result.triggerInputsSchema[0].label).toBe('Channel') + }) + + it('should fall back to parameter name when no labels exist', () => { + const provider = createTriggerProvider({ + events: [{ + name: 'on_message', + label: { en_US: 'On Message' }, + parameters: [{ name: 'raw_param' }], + }], + } as Partial) + + const result = getTriggerCheckParams(createTriggerData(), [provider], 'en_US') + + expect(result.triggerInputsSchema[0].label).toBe('raw_param') + }) + + it('should match provider by provider_id', () => { + const trigger = createTriggerData({ provider_name: 'different-name', provider_id: 'provider-1' }) + const provider = createTriggerProvider({ name: 'other-name', id: 'provider-1' }) + + const result = getTriggerCheckParams(trigger, [provider], 'en_US') + expect(result.isReadyForCheckValid).toBe(true) + }) + + it('should match provider by plugin_id', () => { + const trigger = createTriggerData({ provider_name: 'x', provider_id: 'plugin-1' }) + const provider = createTriggerProvider({ name: 'y', id: 'z', plugin_id: 'plugin-1' }) + + const result = getTriggerCheckParams(trigger, [provider], 'en_US') + expect(result.isReadyForCheckValid).toBe(true) + }) + + it('should return empty schema when event is not found', () => { + const trigger = createTriggerData({ event_name: 'non_existent_event' }) + + const result = getTriggerCheckParams(trigger, [createTriggerProvider()], 'en_US') + expect(result.triggerInputsSchema).toEqual([]) + expect(result.isReadyForCheckValid).toBe(true) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/variable.spec.ts b/web/app/components/workflow/utils/__tests__/variable.spec.ts new file mode 100644 index 0000000000..065e2187ac --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/variable.spec.ts @@ -0,0 +1,55 @@ +import { BlockEnum } from '../../types' +import { isExceptionVariable, variableTransformer } from '../variable' + +describe('variableTransformer', () => { + describe('string → array (template to selector)', () => { + it('should parse a simple template variable', () => { + expect(variableTransformer('{{#node1.output#}}')).toEqual(['node1', 'output']) + }) + + it('should parse a deeply nested path', () => { + expect(variableTransformer('{{#node1.data.items.0.name#}}')).toEqual(['node1', 'data', 'items', '0', 'name']) + }) + + it('should handle a single-segment path', () => { + expect(variableTransformer('{{#value#}}')).toEqual(['value']) + }) + }) + + describe('array → string (selector to template)', () => { + it('should join an array into a template variable', () => { + expect(variableTransformer(['node1', 'output'])).toBe('{{#node1.output#}}') + }) + + it('should join a single-element array', () => { + expect(variableTransformer(['value'])).toBe('{{#value#}}') + }) + }) +}) + +describe('isExceptionVariable', () => { + const errorHandleTypes = [BlockEnum.LLM, BlockEnum.Tool, BlockEnum.HttpRequest, BlockEnum.Code, BlockEnum.Agent] + + it.each(errorHandleTypes)('should return true for error_message with %s node type', (nodeType) => { + expect(isExceptionVariable('error_message', nodeType)).toBe(true) + }) + + it.each(errorHandleTypes)('should return true for error_type with %s node type', (nodeType) => { + expect(isExceptionVariable('error_type', nodeType)).toBe(true) + }) + + it('should return false for error_message with non-error-handle node types', () => { + expect(isExceptionVariable('error_message', BlockEnum.Start)).toBe(false) + expect(isExceptionVariable('error_message', BlockEnum.End)).toBe(false) + expect(isExceptionVariable('error_message', BlockEnum.IfElse)).toBe(false) + }) + + it('should return false for normal variables with error-handle node types', () => { + expect(isExceptionVariable('output', BlockEnum.LLM)).toBe(false) + expect(isExceptionVariable('text', BlockEnum.Tool)).toBe(false) + }) + + it('should return false when nodeType is undefined', () => { + expect(isExceptionVariable('error_message')).toBe(false) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/workflow-entry.spec.ts b/web/app/components/workflow/utils/__tests__/workflow-entry.spec.ts new file mode 100644 index 0000000000..5a2a3d8e47 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/workflow-entry.spec.ts @@ -0,0 +1,89 @@ +import { createNode, createStartNode, createTriggerNode, resetFixtureCounters } from '../../__tests__/fixtures' +import { BlockEnum } from '../../types' +import { getWorkflowEntryNode, isTriggerWorkflow, isWorkflowEntryNode } from '../workflow-entry' + +beforeEach(() => { + resetFixtureCounters() +}) + +describe('getWorkflowEntryNode', () => { + it('should return the trigger node when present', () => { + const nodes = [ + createStartNode({ id: 'start' }), + createTriggerNode(BlockEnum.TriggerWebhook, { id: 'trigger' }), + createNode({ id: 'code', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const entry = getWorkflowEntryNode(nodes) + expect(entry?.id).toBe('trigger') + }) + + it('should return the start node when no trigger node exists', () => { + const nodes = [ + createStartNode({ id: 'start' }), + createNode({ id: 'code', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + const entry = getWorkflowEntryNode(nodes) + expect(entry?.id).toBe('start') + }) + + it('should return undefined when no entry node exists', () => { + const nodes = [ + createNode({ id: 'code', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + + expect(getWorkflowEntryNode(nodes)).toBeUndefined() + }) + + it('should prefer trigger node over start node', () => { + const nodes = [ + createStartNode({ id: 'start' }), + createTriggerNode(BlockEnum.TriggerSchedule, { id: 'schedule' }), + ] + + const entry = getWorkflowEntryNode(nodes) + expect(entry?.id).toBe('schedule') + }) +}) + +describe('isWorkflowEntryNode', () => { + it('should return true for Start', () => { + expect(isWorkflowEntryNode(BlockEnum.Start)).toBe(true) + }) + + it.each([BlockEnum.TriggerSchedule, BlockEnum.TriggerWebhook, BlockEnum.TriggerPlugin])( + 'should return true for %s', + (type) => { + expect(isWorkflowEntryNode(type)).toBe(true) + }, + ) + + it('should return false for non-entry types', () => { + expect(isWorkflowEntryNode(BlockEnum.Code)).toBe(false) + expect(isWorkflowEntryNode(BlockEnum.LLM)).toBe(false) + expect(isWorkflowEntryNode(BlockEnum.End)).toBe(false) + }) +}) + +describe('isTriggerWorkflow', () => { + it('should return true when nodes contain a trigger node', () => { + const nodes = [ + createStartNode(), + createTriggerNode(BlockEnum.TriggerWebhook), + ] + expect(isTriggerWorkflow(nodes)).toBe(true) + }) + + it('should return false when no trigger nodes exist', () => { + const nodes = [ + createStartNode(), + createNode({ data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + expect(isTriggerWorkflow(nodes)).toBe(false) + }) + + it('should return false for empty nodes', () => { + expect(isTriggerWorkflow([])).toBe(false) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/workflow-init.spec.ts b/web/app/components/workflow/utils/__tests__/workflow-init.spec.ts new file mode 100644 index 0000000000..15aa2a933d --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/workflow-init.spec.ts @@ -0,0 +1,742 @@ +import type { IfElseNodeType } from '../../nodes/if-else/types' +import type { IterationNodeType } from '../../nodes/iteration/types' +import type { KnowledgeRetrievalNodeType } from '../../nodes/knowledge-retrieval/types' +import type { LLMNodeType } from '../../nodes/llm/types' +import type { LoopNodeType } from '../../nodes/loop/types' +import type { ParameterExtractorNodeType } from '../../nodes/parameter-extractor/types' +import type { ToolNodeType } from '../../nodes/tool/types' +import type { + Edge, + Node, +} from '@/app/components/workflow/types' +import { CUSTOM_NODE, DEFAULT_RETRY_INTERVAL, DEFAULT_RETRY_MAX } from '@/app/components/workflow/constants' +import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants' +import { CUSTOM_LOOP_START_NODE } from '@/app/components/workflow/nodes/loop-start/constants' +import { BlockEnum, ErrorHandleMode } from '@/app/components/workflow/types' +import { createEdge, createNode, resetFixtureCounters } from '../../__tests__/fixtures' +import { initialEdges, initialNodes, preprocessNodesAndEdges } from '../workflow-init' + +vi.mock('reactflow', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + getConnectedEdges: vi.fn((_nodes: Node[], edges: Edge[]) => { + const node = _nodes[0] + return edges.filter(e => e.source === node.id || e.target === node.id) + }), + } +}) + +vi.mock('@/utils', () => ({ + correctModelProvider: vi.fn((p: string) => p ? `corrected/${p}` : ''), +})) + +vi.mock('@/app/components/workflow/nodes/if-else/utils', () => ({ + branchNameCorrect: vi.fn((branches: Array>) => branches.map((b: Record, i: number) => ({ + ...b, + name: b.id === 'false' ? 'ELSE' : branches.length === 2 ? 'IF' : `CASE ${i + 1}`, + }))), +})) + +beforeEach(() => { + resetFixtureCounters() + vi.clearAllMocks() +}) + +describe('preprocessNodesAndEdges', () => { + it('should return origin nodes and edges when no iteration/loop nodes exist', () => { + const nodes = [createNode({ data: { type: BlockEnum.Code, title: '', desc: '' } })] + const result = preprocessNodesAndEdges(nodes, []) + expect(result).toEqual({ nodes, edges: [] }) + }) + + it('should add iteration start node when iteration has no start_node_id', () => { + const nodes = [ + createNode({ id: 'iter-1', data: { type: BlockEnum.Iteration, title: '', desc: '' } }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const startNodes = result.nodes.filter(n => n.data.type === BlockEnum.IterationStart) + expect(startNodes).toHaveLength(1) + expect(startNodes[0].parentId).toBe('iter-1') + }) + + it('should add iteration start node when iteration has start_node_id but node type does not match', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { type: BlockEnum.Iteration, title: '', desc: '', start_node_id: 'some-node' }, + }), + createNode({ id: 'some-node', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const startNodes = result.nodes.filter(n => n.data.type === BlockEnum.IterationStart) + expect(startNodes).toHaveLength(1) + }) + + it('should not add iteration start node when one already exists with correct type', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { type: BlockEnum.Iteration, title: '', desc: '', start_node_id: 'iter-start' }, + }), + createNode({ + id: 'iter-start', + type: CUSTOM_ITERATION_START_NODE, + data: { type: BlockEnum.IterationStart, title: '', desc: '' }, + }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + expect(result.nodes).toEqual(nodes) + }) + + it('should add loop start node when loop has no start_node_id', () => { + const nodes = [ + createNode({ id: 'loop-1', data: { type: BlockEnum.Loop, title: '', desc: '' } }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const startNodes = result.nodes.filter(n => n.data.type === BlockEnum.LoopStart) + expect(startNodes).toHaveLength(1) + }) + + it('should add loop start node when loop has start_node_id but type does not match', () => { + const nodes = [ + createNode({ + id: 'loop-1', + data: { type: BlockEnum.Loop, title: '', desc: '', start_node_id: 'some-node' }, + }), + createNode({ id: 'some-node', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const startNodes = result.nodes.filter(n => n.data.type === BlockEnum.LoopStart) + expect(startNodes).toHaveLength(1) + }) + + it('should not add loop start node when one already exists with correct type', () => { + const nodes = [ + createNode({ + id: 'loop-1', + data: { type: BlockEnum.Loop, title: '', desc: '', start_node_id: 'loop-start' }, + }), + createNode({ + id: 'loop-start', + type: CUSTOM_LOOP_START_NODE, + data: { type: BlockEnum.LoopStart, title: '', desc: '' }, + }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + expect(result.nodes).toEqual(nodes) + }) + + it('should create edges linking new start nodes to existing start nodes', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { type: BlockEnum.Iteration, title: '', desc: '', start_node_id: 'child-1' }, + }), + createNode({ + id: 'child-1', + parentId: 'iter-1', + data: { type: BlockEnum.Code, title: '', desc: '' }, + }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const newEdges = result.edges + expect(newEdges).toHaveLength(1) + expect(newEdges[0].target).toBe('child-1') + expect(newEdges[0].data!.sourceType).toBe(BlockEnum.IterationStart) + expect(newEdges[0].data!.isInIteration).toBe(true) + }) + + it('should create edges for loop nodes with start_node_id', () => { + const nodes = [ + createNode({ + id: 'loop-1', + data: { type: BlockEnum.Loop, title: '', desc: '', start_node_id: 'child-1' }, + }), + createNode({ + id: 'child-1', + parentId: 'loop-1', + data: { type: BlockEnum.Code, title: '', desc: '' }, + }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const newEdges = result.edges + expect(newEdges).toHaveLength(1) + expect(newEdges[0].target).toBe('child-1') + expect(newEdges[0].data!.isInLoop).toBe(true) + }) + + it('should update start_node_id on iteration and loop nodes', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { type: BlockEnum.Iteration, title: '', desc: '' }, + }), + createNode({ + id: 'loop-1', + data: { type: BlockEnum.Loop, title: '', desc: '' }, + }), + ] + const result = preprocessNodesAndEdges(nodes as Node[], []) + const iterNode = result.nodes.find(n => n.id === 'iter-1') + const loopNode = result.nodes.find(n => n.id === 'loop-1') + expect((iterNode!.data as IterationNodeType).start_node_id).toBeTruthy() + expect((loopNode!.data as LoopNodeType).start_node_id).toBeTruthy() + }) +}) + +describe('initialNodes', () => { + it('should set positions when first node has no position', () => { + const nodes = [ + createNode({ id: 'n1', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'n2', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + nodes.forEach(n => Reflect.deleteProperty(n, 'position')) + + const result = initialNodes(nodes, []) + expect(result[0].position).toBeDefined() + expect(result[1].position).toBeDefined() + expect(result[1].position.x).toBeGreaterThan(result[0].position.x) + }) + + it('should set type to CUSTOM_NODE when type is missing', () => { + const nodes = [ + createNode({ id: 'n1', data: { type: BlockEnum.Start, title: '', desc: '' } }), + ] + Reflect.deleteProperty(nodes[0], 'type') + + const result = initialNodes(nodes, []) + expect(result[0].type).toBe(CUSTOM_NODE) + }) + + it('should set connected source and target handle ids', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'a', target: 'b', sourceHandle: 'source', targetHandle: 'target' }), + ] + + const result = initialNodes(nodes, edges) + expect(result[0].data._connectedSourceHandleIds).toContain('source') + expect(result[1].data._connectedTargetHandleIds).toContain('target') + }) + + it('should handle IfElse node with cases', () => { + const nodes = [ + createNode({ + id: 'if-1', + data: { + type: BlockEnum.IfElse, + title: '', + desc: '', + cases: [ + { case_id: 'case-1', logical_operator: 'and', conditions: [] }, + ], + }, + }), + ] + + const result = initialNodes(nodes, []) + expect(result[0].data._targetBranches).toBeDefined() + expect(result[0].data._targetBranches).toHaveLength(2) + }) + + it('should migrate legacy IfElse node without cases to cases format', () => { + const nodes = [ + createNode({ + id: 'if-1', + data: { + type: BlockEnum.IfElse, + title: '', + desc: '', + logical_operator: 'and', + conditions: [{ id: 'c1', value: 'test' }], + cases: undefined, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as IfElseNodeType + expect(data.cases).toHaveLength(1) + expect(data.cases[0].case_id).toBe('true') + }) + + it('should delete legacy conditions/logical_operator when cases exist', () => { + const nodes = [ + createNode({ + id: 'if-1', + data: { + type: BlockEnum.IfElse, + title: '', + desc: '', + logical_operator: 'and', + conditions: [{ id: 'c1', value: 'test' }], + cases: [ + { case_id: 'true', logical_operator: 'and', conditions: [{ id: 'c1', value: 'test' }] }, + ], + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as IfElseNodeType + expect(data.conditions).toBeUndefined() + expect(data.logical_operator).toBeUndefined() + }) + + it('should set _targetBranches for QuestionClassifier nodes', () => { + const nodes = [ + createNode({ + id: 'qc-1', + data: { + type: BlockEnum.QuestionClassifier, + title: '', + desc: '', + classes: [{ id: 'cls-1', name: 'Class 1' }], + model: { provider: 'openai' }, + }, + }), + ] + + const result = initialNodes(nodes, []) + expect(result[0].data._targetBranches).toHaveLength(1) + }) + + it('should set iteration node defaults', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { + type: BlockEnum.Iteration, + title: '', + desc: '', + }, + }), + ] + + const result = initialNodes(nodes, []) + const iterNode = result.find(n => n.id === 'iter-1')! + const data = iterNode.data as IterationNodeType + expect(data.is_parallel).toBe(false) + expect(data.parallel_nums).toBe(10) + expect(data.error_handle_mode).toBe(ErrorHandleMode.Terminated) + expect(data._children).toBeDefined() + }) + + it('should set loop node defaults', () => { + const nodes = [ + createNode({ + id: 'loop-1', + data: { + type: BlockEnum.Loop, + title: '', + desc: '', + }, + }), + ] + + const result = initialNodes(nodes, []) + const loopNode = result.find(n => n.id === 'loop-1')! + const data = loopNode.data as LoopNodeType + expect(data.error_handle_mode).toBe(ErrorHandleMode.Terminated) + expect(data._children).toBeDefined() + }) + + it('should populate _children for iteration nodes with child nodes', () => { + const nodes = [ + createNode({ + id: 'iter-1', + data: { type: BlockEnum.Iteration, title: '', desc: '' }, + }), + createNode({ + id: 'child-1', + parentId: 'iter-1', + data: { type: BlockEnum.Code, title: '', desc: '' }, + }), + ] + + const result = initialNodes(nodes, []) + const iterNode = result.find(n => n.id === 'iter-1')! + const data = iterNode.data as IterationNodeType + expect(data._children).toEqual( + expect.arrayContaining([ + expect.objectContaining({ nodeId: 'child-1', nodeType: BlockEnum.Code }), + ]), + ) + }) + + it('should correct model provider for LLM nodes', () => { + const nodes = [ + createNode({ + id: 'llm-1', + data: { + type: BlockEnum.LLM, + title: '', + desc: '', + model: { provider: 'openai' }, + }, + }), + ] + + const result = initialNodes(nodes, []) + expect((result[0].data as LLMNodeType).model.provider).toBe('corrected/openai') + }) + + it('should correct model provider for KnowledgeRetrieval reranking_model', () => { + const nodes = [ + createNode({ + id: 'kr-1', + data: { + type: BlockEnum.KnowledgeRetrieval, + title: '', + desc: '', + multiple_retrieval_config: { + reranking_model: { provider: 'cohere' }, + }, + }, + }), + ] + + const result = initialNodes(nodes, []) + expect((result[0].data as KnowledgeRetrievalNodeType).multiple_retrieval_config!.reranking_model!.provider).toBe('corrected/cohere') + }) + + it('should correct model provider for ParameterExtractor nodes', () => { + const nodes = [ + createNode({ + id: 'pe-1', + data: { + type: BlockEnum.ParameterExtractor, + title: '', + desc: '', + model: { provider: 'anthropic' }, + }, + }), + ] + + const result = initialNodes(nodes, []) + expect((result[0].data as ParameterExtractorNodeType).model.provider).toBe('corrected/anthropic') + }) + + it('should add default retry_config for HttpRequest nodes', () => { + const nodes = [ + createNode({ + id: 'http-1', + data: { + type: BlockEnum.HttpRequest, + title: '', + desc: '', + }, + }), + ] + + const result = initialNodes(nodes, []) + expect(result[0].data.retry_config).toEqual({ + retry_enabled: true, + max_retries: DEFAULT_RETRY_MAX, + retry_interval: DEFAULT_RETRY_INTERVAL, + }) + }) + + it('should not overwrite existing retry_config for HttpRequest nodes', () => { + const existingConfig = { retry_enabled: false, max_retries: 1, retry_interval: 50 } + const nodes = [ + createNode({ + id: 'http-1', + data: { + type: BlockEnum.HttpRequest, + title: '', + desc: '', + retry_config: existingConfig, + }, + }), + ] + + const result = initialNodes(nodes, []) + expect(result[0].data.retry_config).toEqual(existingConfig) + }) + + it('should migrate legacy Tool node configurations', () => { + const nodes = [ + createNode({ + id: 'tool-1', + data: { + type: BlockEnum.Tool, + title: '', + desc: '', + tool_configurations: { + api_key: 'secret-key', + nested: { type: 'constant', value: 'already-migrated' }, + }, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as ToolNodeType + expect(data.tool_node_version).toBe('2') + expect(data.tool_configurations.api_key).toEqual({ + type: 'constant', + value: 'secret-key', + }) + expect(data.tool_configurations.nested).toEqual({ + type: 'constant', + value: 'already-migrated', + }) + }) + + it('should not migrate Tool node when version already exists', () => { + const nodes = [ + createNode({ + id: 'tool-1', + data: { + type: BlockEnum.Tool, + title: '', + desc: '', + version: '1', + tool_configurations: { key: 'val' }, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as ToolNodeType + expect(data.tool_configurations).toEqual({ key: 'val' }) + }) + + it('should not migrate Tool node when tool_node_version already exists', () => { + const nodes = [ + createNode({ + id: 'tool-1', + data: { + type: BlockEnum.Tool, + title: '', + desc: '', + tool_node_version: '2', + tool_configurations: { key: 'val' }, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as ToolNodeType + expect(data.tool_configurations).toEqual({ key: 'val' }) + }) + + it('should handle Tool node with null configuration value', () => { + const nodes = [ + createNode({ + id: 'tool-1', + data: { + type: BlockEnum.Tool, + title: '', + desc: '', + tool_configurations: { key: null }, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as ToolNodeType + expect(data.tool_configurations.key).toEqual({ type: 'constant', value: null }) + }) + + it('should handle Tool node with empty tool_configurations', () => { + const nodes = [ + createNode({ + id: 'tool-1', + data: { + type: BlockEnum.Tool, + title: '', + desc: '', + tool_configurations: {}, + }, + }), + ] + + const result = initialNodes(nodes, []) + const data = result[0].data as ToolNodeType + expect(data.tool_node_version).toBe('2') + }) +}) + +describe('initialEdges', () => { + it('should set edge type to custom', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'b' })] + + const result = initialEdges(edges, nodes) + expect(result[0].type).toBe('custom') + }) + + it('should set default sourceHandle and targetHandle', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edge = createEdge({ source: 'a', target: 'b' }) + Reflect.deleteProperty(edge, 'sourceHandle') + Reflect.deleteProperty(edge, 'targetHandle') + + const result = initialEdges([edge], nodes) + expect(result[0].sourceHandle).toBe('source') + expect(result[0].targetHandle).toBe('target') + }) + + it('should set sourceType and targetType from nodes', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'b' })] + Reflect.deleteProperty(edges[0].data!, 'sourceType') + Reflect.deleteProperty(edges[0].data!, 'targetType') + + const result = initialEdges(edges, nodes) + expect(result[0].data!.sourceType).toBe(BlockEnum.Start) + expect(result[0].data!.targetType).toBe(BlockEnum.Code) + }) + + it('should set _connectedNodeIsSelected when a node is selected', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '', selected: true } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'b' })] + + const result = initialEdges(edges, nodes) + expect(result[0].data!._connectedNodeIsSelected).toBe(true) + }) + + it('should filter cycle edges', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'a', target: 'b' }), + createEdge({ source: 'b', target: 'c' }), + createEdge({ source: 'c', target: 'b' }), + ] + + const result = initialEdges(edges, nodes) + const hasCycleEdge = result.some( + e => (e.source === 'b' && e.target === 'c') || (e.source === 'c' && e.target === 'b'), + ) + const hasABEdge = result.some( + e => e.source === 'a' && e.target === 'b', + ) + expect(hasCycleEdge).toBe(false) + // In this specific graph, getCycleEdges treats all nodes remaining in the DFS stack (a, b, c) + // as part of the cycle, so a→b is also filtered. This assertion documents that behaviour. + expect(hasABEdge).toBe(false) + }) + + it('should keep non-cycle edges intact', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'b' })] + + const result = initialEdges(edges, nodes) + expect(result).toHaveLength(1) + expect(result[0].source).toBe('a') + expect(result[0].target).toBe('b') + }) + + it('should handle empty edges', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + ] + const result = initialEdges([], nodes) + expect(result).toHaveLength(0) + }) + + it('should handle edges where source/target node is missing from nodesMap', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'missing' })] + + const result = initialEdges(edges, nodes) + expect(result).toHaveLength(1) + }) + + it('should set _connectedNodeIsSelected for edge target matching selected node', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '', selected: true } }), + ] + const edges = [createEdge({ source: 'a', target: 'b' })] + + const result = initialEdges(edges, nodes) + expect(result[0].data!._connectedNodeIsSelected).toBe(true) + }) + + it('should not set default sourceHandle when sourceHandle already exists', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [createEdge({ source: 'a', target: 'b', sourceHandle: 'custom-src', targetHandle: 'custom-tgt' })] + + const result = initialEdges(edges, nodes) + expect(result[0].sourceHandle).toBe('custom-src') + expect(result[0].targetHandle).toBe('custom-tgt') + }) + + it('should handle graph with edges referencing nodes not in the node list', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'a', target: 'b' }), + createEdge({ source: 'unknown-src', target: 'unknown-tgt' }), + ] + + const result = initialEdges(edges, nodes) + expect(result.length).toBeGreaterThanOrEqual(1) + }) + + it('should handle self-referencing cycle', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'a', target: 'b' }), + createEdge({ source: 'b', target: 'b' }), + ] + + const result = initialEdges(edges, nodes) + const selfLoop = result.find(e => e.source === 'b' && e.target === 'b') + expect(selfLoop).toBeUndefined() + }) + + it('should handle complex cycle with multiple nodes', () => { + const nodes = [ + createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'd', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'a', target: 'b' }), + createEdge({ source: 'b', target: 'c' }), + createEdge({ source: 'c', target: 'd' }), + createEdge({ source: 'd', target: 'b' }), + ] + + const result = initialEdges(edges, nodes) + expect(result.length).toBeLessThan(edges.length) + }) +}) diff --git a/web/app/components/workflow/utils/__tests__/workflow.spec.ts b/web/app/components/workflow/utils/__tests__/workflow.spec.ts new file mode 100644 index 0000000000..165b4d5ee6 --- /dev/null +++ b/web/app/components/workflow/utils/__tests__/workflow.spec.ts @@ -0,0 +1,423 @@ +import { createEdge, createNode, resetFixtureCounters } from '../../__tests__/fixtures' +import { BlockEnum } from '../../types' +import { + canRunBySingle, + changeNodesAndEdgesId, + getNodesConnectedSourceOrTargetHandleIdsMap, + getValidTreeNodes, + hasErrorHandleNode, + isSupportCustomRunForm, +} from '../workflow' + +beforeEach(() => { + resetFixtureCounters() +}) + +describe('canRunBySingle', () => { + const runnableTypes = [ + BlockEnum.LLM, + BlockEnum.KnowledgeRetrieval, + BlockEnum.Code, + BlockEnum.TemplateTransform, + BlockEnum.QuestionClassifier, + BlockEnum.HttpRequest, + BlockEnum.Tool, + BlockEnum.ParameterExtractor, + BlockEnum.Iteration, + BlockEnum.Agent, + BlockEnum.DocExtractor, + BlockEnum.Loop, + BlockEnum.Start, + BlockEnum.IfElse, + BlockEnum.VariableAggregator, + BlockEnum.Assigner, + BlockEnum.HumanInput, + BlockEnum.DataSource, + BlockEnum.TriggerSchedule, + BlockEnum.TriggerWebhook, + BlockEnum.TriggerPlugin, + ] + + it.each(runnableTypes)('should return true for %s when not a child node', (type) => { + expect(canRunBySingle(type, false)).toBe(true) + }) + + it('should return false for Assigner when it is a child node', () => { + expect(canRunBySingle(BlockEnum.Assigner, true)).toBe(false) + }) + + it('should return true for LLM even as a child node', () => { + expect(canRunBySingle(BlockEnum.LLM, true)).toBe(true) + }) + + it('should return false for End node', () => { + expect(canRunBySingle(BlockEnum.End, false)).toBe(false) + }) + + it('should return false for Answer node', () => { + expect(canRunBySingle(BlockEnum.Answer, false)).toBe(false) + }) +}) + +describe('isSupportCustomRunForm', () => { + it('should return true for DataSource', () => { + expect(isSupportCustomRunForm(BlockEnum.DataSource)).toBe(true) + }) + + it('should return false for other types', () => { + expect(isSupportCustomRunForm(BlockEnum.LLM)).toBe(false) + expect(isSupportCustomRunForm(BlockEnum.Code)).toBe(false) + }) +}) + +describe('hasErrorHandleNode', () => { + it.each([BlockEnum.LLM, BlockEnum.Tool, BlockEnum.HttpRequest, BlockEnum.Code, BlockEnum.Agent])( + 'should return true for %s', + (type) => { + expect(hasErrorHandleNode(type)).toBe(true) + }, + ) + + it('should return false for non-error-handle types', () => { + expect(hasErrorHandleNode(BlockEnum.Start)).toBe(false) + expect(hasErrorHandleNode(BlockEnum.Iteration)).toBe(false) + }) + + it('should return false when undefined', () => { + expect(hasErrorHandleNode()).toBe(false) + }) +}) + +describe('getNodesConnectedSourceOrTargetHandleIdsMap', () => { + it('should add handle ids when type is add', () => { + const node1 = createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + const node2 = createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }) + const edge = createEdge({ + source: 'a', + target: 'b', + sourceHandle: 'src-handle', + targetHandle: 'tgt-handle', + }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge }], + [node1, node2], + ) + + expect(result.a._connectedSourceHandleIds).toContain('src-handle') + expect(result.b._connectedTargetHandleIds).toContain('tgt-handle') + }) + + it('should remove handle ids when type is remove', () => { + const node1 = createNode({ + id: 'a', + data: { type: BlockEnum.Start, title: '', desc: '', _connectedSourceHandleIds: ['src-handle'] }, + }) + const node2 = createNode({ + id: 'b', + data: { type: BlockEnum.Code, title: '', desc: '', _connectedTargetHandleIds: ['tgt-handle'] }, + }) + const edge = createEdge({ + source: 'a', + target: 'b', + sourceHandle: 'src-handle', + targetHandle: 'tgt-handle', + }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'remove', edge }], + [node1, node2], + ) + + expect(result.a._connectedSourceHandleIds).not.toContain('src-handle') + expect(result.b._connectedTargetHandleIds).not.toContain('tgt-handle') + }) + + it('should use default handle ids when sourceHandle/targetHandle are missing', () => { + const node1 = createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + const node2 = createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }) + const edge = createEdge({ source: 'a', target: 'b' }) + Reflect.deleteProperty(edge, 'sourceHandle') + Reflect.deleteProperty(edge, 'targetHandle') + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge }], + [node1, node2], + ) + + expect(result.a._connectedSourceHandleIds).toContain('source') + expect(result.b._connectedTargetHandleIds).toContain('target') + }) + + it('should skip when source node is not found', () => { + const node2 = createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }) + const edge = createEdge({ source: 'missing', target: 'b', sourceHandle: 'src' }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge }], + [node2], + ) + + expect(result.missing).toBeUndefined() + expect(result.b._connectedTargetHandleIds).toBeDefined() + }) + + it('should skip when target node is not found', () => { + const node1 = createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + const edge = createEdge({ source: 'a', target: 'missing', targetHandle: 'tgt' }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge }], + [node1], + ) + + expect(result.a._connectedSourceHandleIds).toBeDefined() + expect(result.missing).toBeUndefined() + }) + + it('should reuse existing map entry for same node across multiple changes', () => { + const node1 = createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + const node2 = createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }) + const node3 = createNode({ id: 'c', data: { type: BlockEnum.Code, title: '', desc: '' } }) + const edge1 = createEdge({ source: 'a', target: 'b', sourceHandle: 'h1' }) + const edge2 = createEdge({ source: 'a', target: 'c', sourceHandle: 'h2' }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge: edge1 }, { type: 'add', edge: edge2 }], + [node1, node2, node3], + ) + + expect(result.a._connectedSourceHandleIds).toContain('h1') + expect(result.a._connectedSourceHandleIds).toContain('h2') + }) + + it('should fallback to empty arrays when node data has no handle id arrays', () => { + const node1 = createNode({ id: 'a', data: { type: BlockEnum.Start, title: '', desc: '' } }) + const node2 = createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }) + Reflect.deleteProperty(node1.data, '_connectedSourceHandleIds') + Reflect.deleteProperty(node1.data, '_connectedTargetHandleIds') + Reflect.deleteProperty(node2.data, '_connectedSourceHandleIds') + Reflect.deleteProperty(node2.data, '_connectedTargetHandleIds') + + const edge = createEdge({ source: 'a', target: 'b', sourceHandle: 'h1', targetHandle: 'h2' }) + + const result = getNodesConnectedSourceOrTargetHandleIdsMap( + [{ type: 'add', edge }], + [node1, node2], + ) + + expect(result.a._connectedSourceHandleIds).toContain('h1') + expect(result.b._connectedTargetHandleIds).toContain('h2') + }) +}) + +describe('getValidTreeNodes', () => { + it('should return empty when there are no start/trigger nodes', () => { + const nodes = [ + createNode({ id: 'n1', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const result = getValidTreeNodes(nodes, []) + expect(result.validNodes).toEqual([]) + expect(result.maxDepth).toBe(0) + }) + + it('should traverse a linear graph from Start', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'llm', data: { type: BlockEnum.LLM, title: '', desc: '' } }), + createNode({ id: 'end', data: { type: BlockEnum.End, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start', target: 'llm' }), + createEdge({ source: 'llm', target: 'end' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toEqual(['start', 'llm', 'end']) + expect(result.maxDepth).toBe(3) + }) + + it('should traverse from trigger nodes', () => { + const nodes = [ + createNode({ id: 'trigger', data: { type: BlockEnum.TriggerWebhook, title: '', desc: '' } }), + createNode({ id: 'code', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'trigger', target: 'code' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('trigger') + expect(result.validNodes.map(n => n.id)).toContain('code') + }) + + it('should include iteration children as valid nodes', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'iter', data: { type: BlockEnum.Iteration, title: '', desc: '' } }), + createNode({ id: 'child1', data: { type: BlockEnum.Code, title: '', desc: '' }, parentId: 'iter' }), + ] + const edges = [ + createEdge({ source: 'start', target: 'iter' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('child1') + }) + + it('should include loop children when loop has outgoers', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'loop', data: { type: BlockEnum.Loop, title: '', desc: '' } }), + createNode({ id: 'loop-child', data: { type: BlockEnum.Code, title: '', desc: '' }, parentId: 'loop' }), + createNode({ id: 'end', data: { type: BlockEnum.End, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start', target: 'loop' }), + createEdge({ source: 'loop', target: 'end' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('loop-child') + }) + + it('should include loop children as valid nodes when loop is a leaf', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'loop', data: { type: BlockEnum.Loop, title: '', desc: '' } }), + createNode({ id: 'loop-child', data: { type: BlockEnum.Code, title: '', desc: '' }, parentId: 'loop' }), + ] + const edges = [ + createEdge({ source: 'start', target: 'loop' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('loop-child') + }) + + it('should handle cycles without infinite loop', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'a', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start', target: 'a' }), + createEdge({ source: 'a', target: 'b' }), + createEdge({ source: 'b', target: 'a' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes).toHaveLength(3) + }) + + it('should exclude disconnected nodes', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'connected', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'isolated', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start', target: 'connected' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).not.toContain('isolated') + }) + + it('should handle multiple start nodes without double-traversal', () => { + const nodes = [ + createNode({ id: 'start1', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'trigger', data: { type: BlockEnum.TriggerSchedule, title: '', desc: '' } }), + createNode({ id: 'shared', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start1', target: 'shared' }), + createEdge({ source: 'trigger', target: 'shared' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('start1') + expect(result.validNodes.map(n => n.id)).toContain('trigger') + expect(result.validNodes.map(n => n.id)).toContain('shared') + }) + + it('should not increase maxDepth when visiting nodes at same or lower depth', () => { + const nodes = [ + createNode({ id: 'start', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'a', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'b', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start', target: 'a' }), + createEdge({ source: 'start', target: 'b' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.maxDepth).toBe(2) + }) + + it('should traverse from all trigger types', () => { + const nodes = [ + createNode({ id: 'ts', data: { type: BlockEnum.TriggerSchedule, title: '', desc: '' } }), + createNode({ id: 'tp', data: { type: BlockEnum.TriggerPlugin, title: '', desc: '' } }), + createNode({ id: 'code1', data: { type: BlockEnum.Code, title: '', desc: '' } }), + createNode({ id: 'code2', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'ts', target: 'code1' }), + createEdge({ source: 'tp', target: 'code2' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes).toHaveLength(4) + }) + + it('should skip start nodes already visited by a previous start node traversal', () => { + const nodes = [ + createNode({ id: 'start1', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'start2', data: { type: BlockEnum.TriggerWebhook, title: '', desc: '' } }), + createNode({ id: 'shared', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'start1', target: 'start2' }), + createEdge({ source: 'start2', target: 'shared' }), + ] + + const result = getValidTreeNodes(nodes, edges) + expect(result.validNodes.map(n => n.id)).toContain('start1') + expect(result.validNodes.map(n => n.id)).toContain('start2') + expect(result.validNodes.map(n => n.id)).toContain('shared') + }) +}) + +describe('changeNodesAndEdgesId', () => { + it('should replace all node and edge ids with new uuids', () => { + const nodes = [ + createNode({ id: 'old-1', data: { type: BlockEnum.Start, title: '', desc: '' } }), + createNode({ id: 'old-2', data: { type: BlockEnum.Code, title: '', desc: '' } }), + ] + const edges = [ + createEdge({ source: 'old-1', target: 'old-2' }), + ] + + const [newNodes, newEdges] = changeNodesAndEdgesId(nodes, edges) + + expect(newNodes[0].id).not.toBe('old-1') + expect(newNodes[1].id).not.toBe('old-2') + expect(newEdges[0].source).toBe(newNodes[0].id) + expect(newEdges[0].target).toBe(newNodes[1].id) + }) + + it('should generate unique ids for all nodes', () => { + const nodes = [ + createNode({ id: 'a' }), + createNode({ id: 'b' }), + createNode({ id: 'c' }), + ] + + const [newNodes] = changeNodesAndEdgesId(nodes, []) + const ids = new Set(newNodes.map(n => n.id)) + expect(ids.size).toBe(3) + }) +}) diff --git a/web/app/components/workflow/utils/workflow-init.spec.ts b/web/app/components/workflow/utils/workflow-init.spec.ts deleted file mode 100644 index 8dfcbeb30d..0000000000 --- a/web/app/components/workflow/utils/workflow-init.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { - Node, -} from '@/app/components/workflow/types' -import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants' -import { BlockEnum } from '@/app/components/workflow/types' -import { preprocessNodesAndEdges } from './workflow-init' - -describe('preprocessNodesAndEdges', () => { - it('process nodes without iteration node or loop node should return origin nodes and edges.', () => { - const nodes = [ - { - data: { - type: BlockEnum.Code, - }, - }, - ] - - const result = preprocessNodesAndEdges(nodes as Node[], []) - expect(result).toEqual({ - nodes, - edges: [], - }) - }) - - it('process nodes with iteration node should return nodes with iteration start node', () => { - const nodes = [ - { - id: 'iteration', - data: { - type: BlockEnum.Iteration, - }, - }, - ] - - const result = preprocessNodesAndEdges(nodes as Node[], []) - expect(result.nodes).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - type: BlockEnum.IterationStart, - }), - }), - ]), - ) - }) - - it('process nodes with iteration node start should return origin', () => { - const nodes = [ - { - data: { - type: BlockEnum.Iteration, - start_node_id: 'iterationStart', - }, - }, - { - id: 'iterationStart', - type: CUSTOM_ITERATION_START_NODE, - data: { - type: BlockEnum.IterationStart, - }, - }, - ] - const result = preprocessNodesAndEdges(nodes as Node[], []) - expect(result).toEqual({ - nodes, - edges: [], - }) - }) -}) From c917838f9c855e32d06ff6c12fbb55422b1bd219 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Mon, 2 Mar 2026 18:42:30 +0800 Subject: [PATCH 016/159] refactor: move workflow package to dify_graph (#32844) --- api/.importlinter | 210 +++++++++--------- api/context/__init__.py | 2 +- api/context/flask_app_context.py | 4 +- api/controllers/common/fields.py | 2 +- api/controllers/console/app/app.py | 4 +- api/controllers/console/app/workflow.py | 6 +- .../console/app/workflow_app_log.py | 2 +- .../console/app/workflow_draft_variable.py | 10 +- api/controllers/console/app/workflow_run.py | 4 +- .../rag_pipeline_draft_variable.py | 4 +- api/controllers/console/explore/trial.py | 2 +- api/controllers/console/explore/workflow.py | 2 +- api/controllers/console/remote_files.py | 2 +- api/controllers/files/upload.py | 2 +- api/controllers/inner_api/plugin/plugin.py | 2 +- api/controllers/mcp/mcp.py | 2 +- api/controllers/service_api/app/workflow.py | 4 +- api/controllers/web/remote_files.py | 2 +- api/controllers/web/workflow.py | 2 +- api/core/agent/base_agent_runner.py | 2 +- api/core/agent/cot_agent_runner.py | 2 +- api/core/agent/cot_chat_agent_runner.py | 2 +- api/core/agent/fc_agent_runner.py | 4 +- .../easy_ui_based_app/variables/manager.py | 2 +- api/core/app/app_config/entities.py | 4 +- .../features/file_upload/manager.py | 2 +- .../variables/manager.py | 2 +- .../app/apps/advanced_chat/app_generator.py | 12 +- api/core/app/apps/advanced_chat/app_runner.py | 18 +- .../advanced_chat/generate_task_pipeline.py | 12 +- api/core/app/apps/base_app_generator.py | 10 +- api/core/app/apps/base_app_queue_manager.py | 2 +- api/core/app/apps/base_app_runner.py | 4 +- api/core/app/apps/chat/app_runner.py | 2 +- .../common/graph_runtime_state_support.py | 2 +- .../common/workflow_response_converter.py | 18 +- api/core/app/apps/completion/app_runner.py | 2 +- .../app/apps/pipeline/pipeline_generator.py | 8 +- api/core/app/apps/pipeline/pipeline_runner.py | 22 +- api/core/app/apps/workflow/app_generator.py | 12 +- api/core/app/apps/workflow/app_runner.py | 16 +- .../apps/workflow/generate_task_pipeline.py | 10 +- api/core/app/apps/workflow_app_runner.py | 26 +-- api/core/app/entities/app_invoke_entities.py | 2 +- api/core/app/entities/queue_entities.py | 10 +- api/core/app/entities/task_entities.py | 8 +- .../conversation_variable_persist_layer.py | 14 +- .../app/layers/pause_state_persist_layer.py | 6 +- api/core/app/layers/suspend_layer.py | 6 +- api/core/app/layers/timeslice_layer.py | 6 +- api/core/app/layers/trigger_post_layer.py | 6 +- api/core/app/llm/model_access.py | 6 +- .../easy_ui_based_generate_task_pipeline.py | 4 +- api/core/app/workflow/__init__.py | 2 +- api/core/app/workflow/file_runtime.py | 6 +- api/core/app/workflow/layers/llm_quota.py | 18 +- api/core/app/workflow/layers/observability.py | 8 +- api/core/app/workflow/layers/persistence.py | 16 +- .../datasource/datasource_file_manager.py | 2 +- api/core/datasource/datasource_manager.py | 12 +- .../datasource/utils/message_transformer.py | 2 +- api/core/entities/execution_extra_content.py | 2 +- api/core/entities/mcp_provider.py | 2 +- .../helper/code_executor/code_executor.py | 2 +- .../code_executor/template_transformer.py | 2 +- api/core/llm_generator/llm_generator.py | 2 +- api/core/mcp/server/streamable_http.py | 2 +- api/core/memory/token_buffer_memory.py | 2 +- api/core/ops/aliyun_trace/aliyun_trace.py | 4 +- api/core/ops/aliyun_trace/utils.py | 4 +- api/core/ops/langfuse_trace/langfuse_trace.py | 2 +- .../ops/langsmith_trace/langsmith_trace.py | 2 +- api/core/ops/mlflow_trace/mlflow_trace.py | 2 +- api/core/ops/opik_trace/opik_trace.py | 2 +- api/core/ops/ops_trace_manager.py | 2 +- api/core/ops/tencent_trace/span_builder.py | 2 +- api/core/ops/tencent_trace/tencent_trace.py | 4 +- api/core/ops/weave_trace/weave_trace.py | 2 +- api/core/plugin/backwards_invocation/node.py | 10 +- api/core/plugin/entities/request.py | 8 +- api/core/plugin/utils/converter.py | 2 +- api/core/prompt/advanced_prompt_transform.py | 6 +- api/core/prompt/simple_prompt_transform.py | 4 +- .../rag/index_processor/index_processor.py | 4 +- .../processor/paragraph_index_processor.py | 2 +- api/core/rag/models/document.py | 2 +- api/core/rag/retrieval/dataset_retrieval.py | 6 +- .../celery_workflow_execution_repository.py | 4 +- ...lery_workflow_node_execution_repository.py | 4 +- api/core/repositories/factory.py | 4 +- .../repositories/human_input_repository.py | 6 +- ...qlalchemy_workflow_execution_repository.py | 8 +- ...hemy_workflow_node_execution_repository.py | 8 +- .../builtin_tool/providers/audio/tools/asr.py | 4 +- api/core/tools/custom_tool/tool.py | 2 +- api/core/tools/tool_engine.py | 4 +- api/core/tools/tool_file_manager.py | 2 +- api/core/tools/tool_manager.py | 10 +- api/core/tools/utils/message_transformer.py | 2 +- .../utils/workflow_configuration_sync.py | 6 +- api/core/tools/workflow_as_tool/provider.py | 2 +- api/core/tools/workflow_as_tool/tool.py | 2 +- api/core/trigger/debug/event_selectors.py | 6 +- api/core/workflow/__init__.py | 4 + api/core/{app => }/workflow/node_factory.py | 48 ++-- api/core/workflow/nodes/__init__.py | 3 - .../nodes/trigger_schedule/__init__.py | 3 - api/core/workflow/workflow_entry.py | 36 +-- api/{core/workflow => dify_graph}/README.md | 2 +- .../entities => dify_graph}/__init__.py | 0 .../workflow => dify_graph}/constants.py | 0 .../context/__init__.py | 4 +- .../context/execution_context.py | 0 .../workflow => dify_graph}/context/models.py | 0 .../conversation_variable_updater.py | 2 +- .../entities/__init__.py | 0 .../workflow => dify_graph}/entities/agent.py | 0 .../entities/graph_config.py | 0 .../entities/graph_init_params.py | 0 .../entities/pause_reason.py | 2 +- .../entities/workflow_execution.py | 2 +- .../entities/workflow_node_execution.py | 2 +- .../entities/workflow_start_reason.py | 0 api/{core/workflow => dify_graph}/enums.py | 0 api/{core/workflow => dify_graph}/errors.py | 2 +- .../workflow => dify_graph}/file/__init__.py | 0 .../workflow => dify_graph}/file/constants.py | 0 .../workflow => dify_graph}/file/enums.py | 0 .../file/file_manager.py | 0 .../workflow => dify_graph}/file/helpers.py | 0 .../workflow => dify_graph}/file/models.py | 0 .../workflow => dify_graph}/file/protocols.py | 2 +- .../workflow => dify_graph}/file/runtime.py | 0 .../file/tool_file_parser.py | 0 .../workflow => dify_graph}/graph/__init__.py | 0 .../workflow => dify_graph}/graph/edge.py | 2 +- .../workflow => dify_graph}/graph/graph.py | 6 +- .../graph/graph_template.py | 0 .../graph/validation.py | 2 +- .../graph_engine/__init__.py | 0 .../graph_engine/_engine_utils.py | 0 .../graph_engine/command_channels/README.md | 0 .../graph_engine/command_channels/__init__.py | 0 .../command_channels/in_memory_channel.py | 0 .../command_channels/redis_channel.py | 0 .../command_processing/__init__.py | 0 .../command_processing/command_handlers.py | 4 +- .../command_processing/command_processor.py | 0 .../graph_engine/config.py | 0 .../graph_engine/domain/__init__.py | 0 .../graph_engine/domain/graph_execution.py | 6 +- .../graph_engine/domain/node_execution.py | 2 +- .../graph_engine/entities}/__init__.py | 0 .../graph_engine/entities/commands.py | 2 +- .../graph_engine/error_handler.py | 10 +- .../graph_engine/event_management/__init__.py | 0 .../event_management/event_handlers.py | 8 +- .../event_management/event_manager.py | 2 +- .../graph_engine/graph_engine.py | 18 +- .../graph_engine/graph_state_manager.py | 4 +- .../graph_engine/graph_traversal/__init__.py | 0 .../graph_traversal/edge_processor.py | 6 +- .../graph_traversal/skip_propagator.py | 2 +- .../graph_engine/layers/README.md | 0 .../graph_engine/layers/__init__.py | 0 .../graph_engine/layers/base.py | 8 +- .../graph_engine/layers/debug_logging.py | 2 +- .../graph_engine/layers/execution_limits.py | 8 +- .../graph_engine/manager.py | 4 +- .../graph_engine/orchestration/__init__.py | 0 .../graph_engine/orchestration/dispatcher.py | 2 +- .../orchestration/execution_coordinator.py | 0 .../graph_engine/protocols/command_channel.py | 0 .../graph_engine/ready_queue/__init__.py | 0 .../graph_engine/ready_queue/factory.py | 0 .../graph_engine/ready_queue/in_memory.py | 0 .../graph_engine/ready_queue/protocol.py | 0 .../response_coordinator/__init__.py | 0 .../response_coordinator/coordinator.py | 10 +- .../graph_engine/response_coordinator/path.py | 0 .../response_coordinator/session.py | 10 +- .../graph_engine/worker.py | 10 +- .../worker_management/__init__.py | 0 .../worker_management/worker_pool.py | 6 +- .../graph_events/__init__.py | 0 .../graph_events/agent.py | 0 .../graph_events/base.py | 4 +- .../graph_events/graph.py | 6 +- .../graph_events/human_input.py | 0 .../graph_events/iteration.py | 0 .../graph_events/loop.py | 0 .../graph_events/node.py | 4 +- .../node_events/__init__.py | 0 .../node_events/agent.py | 0 .../node_events/base.py | 2 +- .../node_events/iteration.py | 0 .../node_events/loop.py | 0 .../node_events/node.py | 6 +- api/dify_graph/nodes/__init__.py | 3 + .../nodes/agent/__init__.py | 0 .../nodes/agent/agent_node.py | 16 +- .../nodes/agent/entities.py | 2 +- .../nodes/agent/exc.py | 0 .../nodes/answer}/__init__.py | 0 .../nodes/answer/answer_node.py | 14 +- .../nodes/answer/entities.py | 2 +- .../nodes/base/__init__.py | 0 .../nodes/base/entities.py | 2 +- .../workflow => dify_graph}/nodes/base/exc.py | 0 .../nodes/base/node.py | 32 +-- .../nodes/base/template.py | 2 +- .../nodes/base/usage_tracking_mixin.py | 2 +- .../nodes/base/variable_template_parser.py | 0 .../nodes/code/__init__.py | 0 .../nodes/code/code_node.py | 18 +- .../nodes/code/entities.py | 6 +- .../workflow => dify_graph}/nodes/code/exc.py | 0 .../nodes/code/limits.py | 0 .../nodes/datasource/__init__.py | 0 .../nodes/datasource/datasource_node.py | 16 +- .../nodes/datasource/entities.py | 2 +- .../nodes/datasource/exc.py | 0 .../nodes/document_extractor/__init__.py | 0 .../nodes/document_extractor/entities.py | 2 +- .../nodes/document_extractor/exc.py | 0 .../nodes/document_extractor/node.py | 16 +- .../nodes/end}/__init__.py | 0 .../nodes/end/end_node.py | 10 +- .../nodes/end/entities.py | 2 +- .../nodes/http_request/__init__.py | 0 .../nodes/http_request/config.py | 0 .../nodes/http_request/entities.py | 2 +- .../nodes/http_request/exc.py | 0 .../nodes/http_request/executor.py | 6 +- .../nodes/http_request/node.py | 22 +- .../nodes/human_input/__init__.py | 0 .../nodes/human_input/entities.py | 8 +- .../nodes/human_input/enums.py | 0 .../nodes/human_input/human_input_node.py | 20 +- .../nodes/if_else/__init__.py | 0 .../nodes/if_else/entities.py | 4 +- .../nodes/if_else/if_else_node.py | 14 +- .../nodes/iteration/__init__.py | 0 .../nodes/iteration/entities.py | 2 +- .../nodes/iteration/exc.py | 0 .../nodes/iteration/iteration_node.py | 42 ++-- .../nodes/iteration/iteration_start_node.py | 8 +- .../nodes/knowledge_index/__init__.py | 0 .../nodes/knowledge_index/entities.py | 2 +- .../nodes/knowledge_index/exc.py | 0 .../knowledge_index/knowledge_index_node.py | 18 +- .../nodes/knowledge_retrieval/__init__.py | 0 .../nodes/knowledge_retrieval/entities.py | 4 +- .../nodes/knowledge_retrieval/exc.py | 0 .../knowledge_retrieval_node.py | 22 +- .../knowledge_retrieval/template_prompts.py | 0 .../nodes/list_operator/__init__.py | 0 .../nodes/list_operator/entities.py | 2 +- .../nodes/list_operator/exc.py | 0 .../nodes/list_operator/node.py | 12 +- .../nodes/llm/__init__.py | 0 .../nodes/llm/entities.py | 4 +- .../workflow => dify_graph}/nodes/llm/exc.py | 0 .../nodes/llm/file_saver.py | 2 +- .../nodes/llm/llm_utils.py | 6 +- .../workflow => dify_graph}/nodes/llm/node.py | 26 +-- .../nodes/llm/protocols.py | 0 .../nodes/loop/__init__.py | 0 .../nodes/loop/entities.py | 6 +- .../nodes/loop/loop_end_node.py | 8 +- .../nodes/loop/loop_node.py | 32 +-- .../nodes/loop/loop_start_node.py | 8 +- .../nodes/node_mapping.py | 6 +- .../nodes/parameter_extractor/__init__.py | 0 .../nodes/parameter_extractor/entities.py | 6 +- .../nodes/parameter_extractor/exc.py | 2 +- .../parameter_extractor_node.py | 22 +- .../nodes/parameter_extractor/prompts.py | 0 .../nodes/protocols.py | 2 +- .../nodes/question_classifier/__init__.py | 0 .../nodes/question_classifier/entities.py | 4 +- .../nodes/question_classifier/exc.py | 0 .../question_classifier_node.py | 22 +- .../question_classifier/template_prompts.py | 0 .../nodes/start/__init__.py | 0 .../nodes/start/entities.py | 4 +- .../nodes/start/start_node.py | 12 +- .../nodes/template_transform/__init__.py | 0 .../nodes/template_transform/entities.py | 4 +- .../template_transform/template_renderer.py | 0 .../template_transform_node.py | 14 +- .../nodes/tool/__init__.py | 0 .../nodes/tool/entities.py | 2 +- .../workflow => dify_graph}/nodes/tool/exc.py | 0 .../nodes/tool/tool_node.py | 16 +- .../nodes/trigger_plugin/__init__.py | 0 .../nodes/trigger_plugin/entities.py | 4 +- .../nodes/trigger_plugin/exc.py | 0 .../trigger_plugin/trigger_event_node.py | 10 +- .../nodes/trigger_schedule/__init__.py | 3 + .../nodes/trigger_schedule/entities.py | 2 +- .../nodes/trigger_schedule/exc.py | 2 +- .../trigger_schedule/trigger_schedule_node.py | 12 +- .../nodes/trigger_webhook/__init__.py | 0 .../nodes/trigger_webhook/entities.py | 2 +- .../nodes/trigger_webhook/exc.py | 2 +- .../nodes/trigger_webhook/node.py | 16 +- .../nodes/variable_aggregator/__init__.py | 0 .../nodes/variable_aggregator/entities.py | 4 +- .../variable_aggregator_node.py | 10 +- .../nodes/variable_assigner}/__init__.py | 0 .../variable_assigner/common}/__init__.py | 0 .../nodes/variable_assigner/common/exc.py | 0 .../nodes/variable_assigner/common/helpers.py | 6 +- .../nodes/variable_assigner/v1/__init__.py | 0 .../nodes/variable_assigner/v1/node.py | 18 +- .../nodes/variable_assigner/v1/node_data.py | 2 +- .../nodes/variable_assigner/v2/__init__.py | 0 .../nodes/variable_assigner/v2/entities.py | 2 +- .../nodes/variable_assigner/v2/enums.py | 0 .../nodes/variable_assigner/v2/exc.py | 2 +- .../nodes/variable_assigner/v2/helpers.py | 2 +- .../nodes/variable_assigner/v2/node.py | 20 +- .../repositories/__init__.py | 2 +- .../datasource_manager_protocol.py | 4 +- .../repositories/draft_variable_repository.py | 2 +- .../human_input_form_repository.py | 4 +- .../repositories/index_processor_protocol.py | 0 .../repositories/rag_retrieval_protocol.py | 4 +- .../summary_index_service_protocol.py | 0 .../workflow_execution_repository.py | 2 +- .../workflow_node_execution_repository.py | 2 +- .../runtime/__init__.py | 0 .../runtime/graph_runtime_state.py | 12 +- .../runtime/graph_runtime_state_protocol.py | 4 +- .../runtime/read_only_wrappers.py | 4 +- .../runtime/variable_pool.py | 14 +- .../system_variable.py | 4 +- .../utils}/__init__.py | 0 api/dify_graph/utils/condition/__init__.py | 0 .../utils/condition/entities.py | 0 .../utils/condition/processor.py | 8 +- .../variable_loader.py | 6 +- .../variables/__init__.py | 0 .../variables/consts.py | 0 .../workflow => dify_graph}/variables/exc.py | 0 .../variables/input_entities.py | 2 +- .../variables/segment_group.py | 0 .../variables/segments.py | 2 +- .../variables/types.py | 2 +- .../variables/utils.py | 0 .../variables/variables.py | 0 .../workflow_type_encoder.py | 4 +- ...rameters_cache_when_sync_draft_workflow.py | 4 +- ...nc_workflow_schedule_when_app_published.py | 2 +- ...oin_when_app_published_workflow_updated.py | 4 +- ...ers_when_app_published_workflow_updated.py | 2 +- ..._api_workflow_node_execution_repository.py | 2 +- .../logstore_workflow_execution_repository.py | 6 +- ...tore_workflow_node_execution_repository.py | 10 +- api/extensions/otel/parser/base.py | 10 +- api/extensions/otel/parser/llm.py | 4 +- api/extensions/otel/parser/retrieval.py | 6 +- api/extensions/otel/parser/tool.py | 8 +- api/factories/file_factory.py | 2 +- api/factories/variable_factory.py | 12 +- api/fields/_value_type_serializer.py | 4 +- api/fields/conversation_fields.py | 2 +- api/fields/member_fields.py | 2 +- api/fields/message_fields.py | 2 +- api/fields/raws.py | 2 +- api/fields/workflow_fields.py | 2 +- api/libs/helper.py | 2 +- api/models/enums.py | 2 +- api/models/human_input.py | 2 +- api/models/model.py | 6 +- api/models/workflow.py | 22 +- api/pyproject.toml | 2 +- .../api_workflow_node_execution_repository.py | 2 +- .../api_workflow_run_repository.py | 6 +- api/repositories/entities/workflow_pause.py | 2 +- ..._api_workflow_node_execution_repository.py | 2 +- .../sqlalchemy_api_workflow_run_repository.py | 6 +- ...hemy_execution_extra_content_repository.py | 6 +- api/services/app_dsl_service.py | 14 +- api/services/app_task_service.py | 2 +- api/services/conversation_service.py | 2 +- api/services/conversation_variable_updater.py | 2 +- api/services/dataset_service.py | 2 +- api/services/external_knowledge_service.py | 2 +- api/services/file_service.py | 2 +- .../human_input_delivery_test_service.py | 4 +- api/services/human_input_service.py | 4 +- api/services/rag_pipeline/rag_pipeline.py | 28 +-- .../rag_pipeline/rag_pipeline_dsl_service.py | 14 +- .../archive_paid_plan_workflow_run.py | 2 +- api/services/trigger/schedule_service.py | 6 +- api/services/trigger/trigger_service.py | 4 +- api/services/trigger/webhook_service.py | 6 +- api/services/variable_truncator.py | 8 +- api/services/workflow/workflow_converter.py | 6 +- api/services/workflow_app_service.py | 2 +- .../workflow_draft_variable_service.py | 24 +- .../workflow_event_snapshot_service.py | 8 +- api/services/workflow_service.py | 48 ++-- .../app_generate/workflow_execute_task.py | 2 +- api/tasks/async_workflow_tasks.py | 2 +- api/tasks/human_input_timeout_tasks.py | 4 +- api/tasks/mail_human_input_delivery_task.py | 4 +- api/tasks/trigger_processing_tasks.py | 4 +- api/tasks/workflow_execution_tasks.py | 4 +- api/tasks/workflow_node_execution_tasks.py | 4 +- api/tasks/workflow_schedule_tasks.py | 2 +- .../test_datasource_manager_integration.py | 2 +- .../test_datasource_node_integration.py | 6 +- .../factories/test_storage_key_loader.py | 2 +- .../test_workflow_draft_variable_service.py | 10 +- .../test_remove_app_and_related_data_task.py | 6 +- .../workflow/nodes/test_code.py | 18 +- .../workflow/nodes/test_http.py | 26 +-- .../workflow/nodes/test_llm.py | 14 +- .../nodes/test_parameter_extractor.py | 12 +- .../workflow/nodes/test_template_transform.py | 14 +- .../workflow/nodes/test_tool.py | 16 +- ...test_chat_conversation_status_count_api.py | 2 +- .../layers/test_pause_state_persist_layer.py | 20 +- .../test_dataset_retrieval_integration.py | 2 +- .../test_human_input_form_repository_impl.py | 4 +- .../test_human_input_resume_node_execution.py | 30 +-- .../factories/test_storage_key_loader.py | 2 +- .../helpers/execution_extra_content.py | 2 +- ..._api_workflow_node_execution_repository.py | 2 +- ..._sqlalchemy_api_workflow_run_repository.py | 6 +- .../services/test_agent_service.py | 2 +- .../test_delete_archived_workflow_run.py | 2 +- .../test_human_input_delivery_test.py | 4 +- .../services/test_workflow_app_service.py | 2 +- .../test_workflow_draft_variable_service.py | 8 +- .../services/test_workflow_service.py | 34 +-- .../workflow/test_workflow_converter.py | 2 +- ...kflow_node_execution_service_repository.py | 2 +- .../test_mail_human_input_delivery_task.py | 6 +- .../test_remove_app_and_related_data_task.py | 4 +- .../test_workflow_pause_integration.py | 4 +- .../trigger/test_trigger_e2e.py | 2 +- .../app/test_workflow_pause_details_api.py | 8 +- .../app/workflow_draft_variables_test.py | 12 +- .../service_api/app/test_workflow.py | 4 +- .../service_api/app/test_workflow_fields.py | 2 +- .../features/file_upload/test_manager.py | 2 +- .../test_app_runner_conversation_variables.py | 2 +- ...t_generate_task_pipeline_extra_contents.py | 2 +- .../chat/test_base_app_runner_multimodal.py | 2 +- .../test_graph_runtime_state_support.py | 6 +- .../test_workflow_response_converter.py | 4 +- ...workflow_response_converter_human_input.py | 6 +- ..._workflow_response_converter_resumption.py | 6 +- ..._workflow_response_converter_truncation.py | 6 +- .../core/app/apps/test_base_app_generator.py | 2 +- .../core/app/apps/test_pause_resume.py | 34 +-- .../test_workflow_app_runner_notifications.py | 4 +- .../test_workflow_app_runner_single_node.py | 4 +- .../app/apps/test_workflow_pause_events.py | 12 +- .../workflow/test_generate_task_pipeline.py | 6 +- ...est_conversation_variable_persist_layer.py | 20 +- .../layers/test_pause_state_persist_layer.py | 12 +- .../datasource/test_datasource_manager.py | 4 +- api/tests/unit_tests/core/file/test_models.py | 2 +- .../core/mcp/server/test_streamable_http.py | 2 +- .../core/ops/test_arize_phoenix_trace.py | 2 +- .../prompt/test_advanced_prompt_transform.py | 4 +- .../test_dataset_retrieval_methods.py | 4 +- ...st_celery_workflow_execution_repository.py | 2 +- ...lery_workflow_node_execution_repository.py | 6 +- .../core/repositories/test_factory.py | 4 +- .../test_human_input_form_repository_impl.py | 4 +- ...rkflow_node_execution_conflict_handling.py | 4 +- ...test_workflow_node_execution_truncation.py | 4 +- api/tests/unit_tests/core/test_file.py | 2 +- .../test_trigger_debug_event_selectors.py | 2 +- .../unit_tests/core/variables/test_segment.py | 12 +- .../core/variables/test_segment_type.py | 2 +- .../variables/test_segment_type_validation.py | 10 +- .../core/variables/test_variables.py | 4 +- .../context/test_execution_context.py | 12 +- .../entities/test_graph_runtime_state.py | 8 +- .../workflow/entities/test_pause_reason.py | 2 +- .../core/workflow/entities/test_template.py | 2 +- .../workflow/entities/test_variable_pool.py | 4 +- .../entities/test_workflow_node_execution.py | 4 +- .../core/workflow/graph/test_graph.py | 8 +- .../core/workflow/graph/test_graph_builder.py | 6 +- .../graph/test_graph_skip_validation.py | 14 +- .../workflow/graph/test_graph_validation.py | 16 +- .../core/workflow/graph_engine/README.md | 20 +- .../command_channels/test_redis_channel.py | 6 +- .../event_management/test_event_handlers.py | 24 +- .../event_management/test_event_manager.py | 6 +- .../graph_traversal/test_skip_propagator.py | 6 +- .../graph_engine/human_input_test_utils.py | 4 +- .../workflow/graph_engine/layers/conftest.py | 8 +- .../layers/test_layer_initialization.py | 8 +- .../graph_engine/layers/test_llm_quota.py | 8 +- .../graph_engine/layers/test_observability.py | 8 +- .../orchestration/test_dispatcher.py | 14 +- .../graph_engine/test_answer_end_with_text.py | 2 +- .../graph_engine/test_auto_mock_system.py | 12 +- .../graph_engine/test_basic_chatflow.py | 2 +- .../graph_engine/test_command_system.py | 22 +- .../test_complex_branch_workflow.py | 2 +- ...ditional_streaming_vs_template_workflow.py | 8 +- .../test_dispatcher_pause_drain.py | 8 +- .../test_end_node_without_value_type.py | 2 +- .../test_execution_coordinator.py | 10 +- .../graph_engine/test_graph_engine.py | 20 +- .../test_graph_execution_serialization.py | 14 +- .../graph_engine/test_graph_state_snapshot.py | 24 +- .../test_human_input_pause_multi_branch.py | 30 +-- .../test_human_input_pause_single_branch.py | 30 +-- .../graph_engine/test_if_else_streaming.py | 28 +-- .../graph_engine/test_loop_contains_answer.py | 2 +- .../graph_engine/test_loop_with_tool.py | 2 +- .../workflow/graph_engine/test_mock_config.py | 2 +- .../graph_engine/test_mock_factory.py | 10 +- .../test_mock_iteration_simple.py | 14 +- .../workflow/graph_engine/test_mock_nodes.py | 56 ++--- .../test_mock_nodes_template_code.py | 46 ++-- .../workflow/graph_engine/test_mock_simple.py | 10 +- .../test_parallel_human_input_join_resume.py | 36 +-- ...rallel_human_input_pause_missing_finish.py | 32 +-- .../test_parallel_streaming_workflow.py | 22 +- .../test_pause_deferred_ready_nodes.py | 36 +-- .../graph_engine/test_pause_resume_state.py | 34 +-- .../test_redis_stop_integration.py | 6 +- .../test_streaming_conversation_variables.py | 2 +- .../graph_engine/test_table_runner.py | 18 +- .../graph_engine/test_tool_in_chatflow.py | 6 +- .../graph_engine/test_variable_aggregator.py | 6 +- .../core/workflow/nodes/answer/test_answer.py | 14 +- .../workflow/nodes/base/test_base_node.py | 8 +- .../test_get_node_type_classes_mapping.py | 10 +- .../workflow/nodes/code/code_node_spec.py | 10 +- .../core/workflow/nodes/code/entities_spec.py | 4 +- .../nodes/datasource/test_datasource_node.py | 6 +- .../nodes/http_request/test_config.py | 2 +- .../nodes/http_request/test_entities.py | 4 +- .../test_http_request_executor.py | 14 +- .../http_request/test_http_request_node.py | 16 +- .../human_input/test_email_delivery_config.py | 4 +- .../nodes/human_input/test_entities.py | 18 +- .../test_human_input_form_filled_event.py | 14 +- .../workflow/nodes/iteration/entities_spec.py | 2 +- .../nodes/iteration/iteration_node_spec.py | 8 +- .../test_knowledge_index_node.py | 20 +- .../test_knowledge_retrieval_node.py | 22 +- .../workflow/nodes/list_operator/node_spec.py | 12 +- .../workflow/nodes/llm/test_file_saver.py | 4 +- .../core/workflow/nodes/llm/test_node.py | 22 +- .../core/workflow/nodes/llm/test_scenarios.py | 4 +- .../parameter_extractor/test_entities.py | 4 +- .../test_parameter_extractor_node.py | 10 +- .../nodes/template_transform/entities_spec.py | 4 +- .../template_transform_node_spec.py | 30 +-- .../core/workflow/nodes/test_base_node.py | 12 +- .../nodes/test_document_extractor_node.py | 24 +- .../core/workflow/nodes/test_if_else.py | 22 +- .../core/workflow/nodes/test_list_operator.py | 12 +- .../nodes/test_question_classifier_node.py | 2 +- .../nodes/test_start_node_json_object.py | 12 +- .../workflow/nodes/tool/test_tool_node.py | 16 +- .../v1/test_variable_assigner_v1.py | 20 +- .../variable_assigner/v2/test_helpers.py | 6 +- .../v2/test_variable_assigner_v2.py | 16 +- .../workflow/nodes/webhook/test_entities.py | 4 +- .../workflow/nodes/webhook/test_exceptions.py | 6 +- .../webhook/test_webhook_file_conversion.py | 26 +-- .../nodes/webhook/test_webhook_node.py | 18 +- .../unit_tests/core/workflow/test_enums.py | 2 +- .../core/workflow/test_system_variable.py | 6 +- .../test_system_variable_read_only_view.py | 4 +- .../core/workflow/test_variable_pool.py | 14 +- .../core/workflow/test_workflow_entry.py | 18 +- .../test_workflow_entry_redis_channel.py | 4 +- .../core/workflow/utils/test_condition.py | 6 +- .../utils/test_variable_template_parser.py | 4 +- .../factories/test_variable_factory.py | 10 +- .../unit_tests/libs/_human_input/support.py | 4 +- .../libs/_human_input/test_form_service.py | 4 +- .../libs/_human_input/test_models.py | 4 +- .../libs/test_cron_compatibility.py | 2 +- .../unit_tests/models/test_app_models.py | 4 +- .../models/test_conversation_variable.py | 2 +- api/tests/unit_tests/models/test_workflow.py | 8 +- .../unit_tests/models/test_workflow_models.py | 2 +- ..._sqlalchemy_api_workflow_run_repository.py | 6 +- ...hemy_execution_extra_content_repository.py | 4 +- .../test_sqlalchemy_repository.py | 6 +- ...hemy_workflow_node_execution_repository.py | 4 +- .../services/external_dataset_service.py | 2 +- .../test_human_input_delivery_test_service.py | 4 +- .../services/test_human_input_service.py | 4 +- .../services/test_schedule_service.py | 8 +- .../services/test_variable_truncator.py | 6 +- .../test_workflow_run_service_pause.py | 2 +- .../services/test_workflow_service.py | 4 +- .../workflow/test_draft_var_loader_simple.py | 8 +- .../workflow/test_workflow_converter.py | 2 +- .../test_workflow_draft_variable_service.py | 8 +- .../test_workflow_event_snapshot_service.py | 6 +- .../test_workflow_human_input_delivery.py | 4 +- .../workflow/test_workflow_service.py | 6 +- .../tasks/test_human_input_timeout_tasks.py | 2 +- .../test_workflow_node_execution_tasks.py | 4 +- 613 files changed, 2008 insertions(+), 2012 deletions(-) rename api/core/{app => }/workflow/node_factory.py (88%) delete mode 100644 api/core/workflow/nodes/__init__.py delete mode 100644 api/core/workflow/nodes/trigger_schedule/__init__.py rename api/{core/workflow => dify_graph}/README.md (98%) rename api/{core/workflow/graph_engine/entities => dify_graph}/__init__.py (100%) rename api/{core/workflow => dify_graph}/constants.py (100%) rename api/{core/workflow => dify_graph}/context/__init__.py (86%) rename api/{core/workflow => dify_graph}/context/execution_context.py (100%) rename api/{core/workflow => dify_graph}/context/models.py (100%) rename api/{core/workflow => dify_graph}/conversation_variable_updater.py (96%) rename api/{core/workflow => dify_graph}/entities/__init__.py (100%) rename api/{core/workflow => dify_graph}/entities/agent.py (100%) rename api/{core/workflow => dify_graph}/entities/graph_config.py (100%) rename api/{core/workflow => dify_graph}/entities/graph_init_params.py (100%) rename api/{core/workflow => dify_graph}/entities/pause_reason.py (96%) rename api/{core/workflow => dify_graph}/entities/workflow_execution.py (96%) rename api/{core/workflow => dify_graph}/entities/workflow_node_execution.py (98%) rename api/{core/workflow => dify_graph}/entities/workflow_start_reason.py (100%) rename api/{core/workflow => dify_graph}/enums.py (100%) rename api/{core/workflow => dify_graph}/errors.py (88%) rename api/{core/workflow => dify_graph}/file/__init__.py (100%) rename api/{core/workflow => dify_graph}/file/constants.py (100%) rename api/{core/workflow => dify_graph}/file/enums.py (100%) rename api/{core/workflow => dify_graph}/file/file_manager.py (100%) rename api/{core/workflow => dify_graph}/file/helpers.py (100%) rename api/{core/workflow => dify_graph}/file/models.py (100%) rename api/{core/workflow => dify_graph}/file/protocols.py (94%) rename api/{core/workflow => dify_graph}/file/runtime.py (100%) rename api/{core/workflow => dify_graph}/file/tool_file_parser.py (100%) rename api/{core/workflow => dify_graph}/graph/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph/edge.py (91%) rename api/{core/workflow => dify_graph}/graph/graph.py (98%) rename api/{core/workflow => dify_graph}/graph/graph_template.py (100%) rename api/{core/workflow => dify_graph}/graph/validation.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/_engine_utils.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_channels/README.md (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_channels/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_channels/in_memory_channel.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_channels/redis_channel.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_processing/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/command_processing/command_handlers.py (94%) rename api/{core/workflow => dify_graph}/graph_engine/command_processing/command_processor.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/config.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/domain/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/domain/graph_execution.py (97%) rename api/{core/workflow => dify_graph}/graph_engine/domain/node_execution.py (96%) rename api/{core/workflow/nodes/answer => dify_graph/graph_engine/entities}/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/entities/commands.py (96%) rename api/{core/workflow => dify_graph}/graph_engine/error_handler.py (97%) rename api/{core/workflow => dify_graph}/graph_engine/event_management/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/event_management/event_handlers.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/event_management/event_manager.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/graph_engine.py (95%) rename api/{core/workflow => dify_graph}/graph_engine/graph_state_manager.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/graph_traversal/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/graph_traversal/edge_processor.py (97%) rename api/{core/workflow => dify_graph}/graph_engine/graph_traversal/skip_propagator.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/layers/README.md (100%) rename api/{core/workflow => dify_graph}/graph_engine/layers/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/layers/base.py (94%) rename api/{core/workflow => dify_graph}/graph_engine/layers/debug_logging.py (99%) rename api/{core/workflow => dify_graph}/graph_engine/layers/execution_limits.py (94%) rename api/{core/workflow => dify_graph}/graph_engine/manager.py (94%) rename api/{core/workflow => dify_graph}/graph_engine/orchestration/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/orchestration/dispatcher.py (99%) rename api/{core/workflow => dify_graph}/graph_engine/orchestration/execution_coordinator.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/protocols/command_channel.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/ready_queue/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/ready_queue/factory.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/ready_queue/in_memory.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/ready_queue/protocol.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/response_coordinator/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/response_coordinator/coordinator.py (98%) rename api/{core/workflow => dify_graph}/graph_engine/response_coordinator/path.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/response_coordinator/session.py (85%) rename api/{core/workflow => dify_graph}/graph_engine/worker.py (95%) rename api/{core/workflow => dify_graph}/graph_engine/worker_management/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_engine/worker_management/worker_pool.py (98%) rename api/{core/workflow => dify_graph}/graph_events/__init__.py (100%) rename api/{core/workflow => dify_graph}/graph_events/agent.py (100%) rename api/{core/workflow => dify_graph}/graph_events/base.py (87%) rename api/{core/workflow => dify_graph}/graph_events/graph.py (90%) rename api/{core/workflow => dify_graph}/graph_events/human_input.py (100%) rename api/{core/workflow => dify_graph}/graph_events/iteration.py (100%) rename api/{core/workflow => dify_graph}/graph_events/loop.py (100%) rename api/{core/workflow => dify_graph}/graph_events/node.py (96%) rename api/{core/workflow => dify_graph}/node_events/__init__.py (100%) rename api/{core/workflow => dify_graph}/node_events/agent.py (100%) rename api/{core/workflow => dify_graph}/node_events/base.py (91%) rename api/{core/workflow => dify_graph}/node_events/iteration.py (100%) rename api/{core/workflow => dify_graph}/node_events/loop.py (100%) rename api/{core/workflow => dify_graph}/node_events/node.py (92%) create mode 100644 api/dify_graph/nodes/__init__.py rename api/{core/workflow => dify_graph}/nodes/agent/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/agent/agent_node.py (98%) rename api/{core/workflow => dify_graph}/nodes/agent/entities.py (95%) rename api/{core/workflow => dify_graph}/nodes/agent/exc.py (100%) rename api/{core/workflow/nodes/end => dify_graph/nodes/answer}/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/answer/answer_node.py (83%) rename api/{core/workflow => dify_graph}/nodes/answer/entities.py (97%) rename api/{core/workflow => dify_graph}/nodes/base/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/base/entities.py (99%) rename api/{core/workflow => dify_graph}/nodes/base/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/base/node.py (96%) rename api/{core/workflow => dify_graph}/nodes/base/template.py (98%) rename api/{core/workflow => dify_graph}/nodes/base/usage_tracking_mixin.py (95%) rename api/{core/workflow => dify_graph}/nodes/base/variable_template_parser.py (100%) rename api/{core/workflow => dify_graph}/nodes/code/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/code/code_node.py (97%) rename api/{core/workflow => dify_graph}/nodes/code/entities.py (88%) rename api/{core/workflow => dify_graph}/nodes/code/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/code/limits.py (100%) rename api/{core/workflow => dify_graph}/nodes/datasource/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/datasource/datasource_node.py (94%) rename api/{core/workflow => dify_graph}/nodes/datasource/entities.py (96%) rename api/{core/workflow => dify_graph}/nodes/datasource/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/document_extractor/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/document_extractor/entities.py (84%) rename api/{core/workflow => dify_graph}/nodes/document_extractor/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/document_extractor/node.py (98%) rename api/{core/workflow/nodes/variable_assigner => dify_graph/nodes/end}/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/end/end_node.py (81%) rename api/{core/workflow => dify_graph}/nodes/end/entities.py (87%) rename api/{core/workflow => dify_graph}/nodes/http_request/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/http_request/config.py (100%) rename api/{core/workflow => dify_graph}/nodes/http_request/entities.py (99%) rename api/{core/workflow => dify_graph}/nodes/http_request/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/http_request/executor.py (99%) rename api/{core/workflow => dify_graph}/nodes/http_request/node.py (93%) rename api/{core/workflow => dify_graph}/nodes/human_input/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/human_input/entities.py (98%) rename api/{core/workflow => dify_graph}/nodes/human_input/enums.py (100%) rename api/{core/workflow => dify_graph}/nodes/human_input/human_input_node.py (95%) rename api/{core/workflow => dify_graph}/nodes/if_else/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/if_else/entities.py (82%) rename api/{core/workflow => dify_graph}/nodes/if_else/if_else_node.py (90%) rename api/{core/workflow => dify_graph}/nodes/iteration/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/iteration/entities.py (94%) rename api/{core/workflow => dify_graph}/nodes/iteration/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/iteration/iteration_node.py (95%) rename api/{core/workflow => dify_graph}/nodes/iteration/iteration_start_node.py (60%) rename api/{core/workflow => dify_graph}/nodes/knowledge_index/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/knowledge_index/entities.py (98%) rename api/{core/workflow => dify_graph}/nodes/knowledge_index/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/knowledge_index/knowledge_index_node.py (90%) rename api/{core/workflow => dify_graph}/nodes/knowledge_retrieval/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/knowledge_retrieval/entities.py (96%) rename api/{core/workflow => dify_graph}/nodes/knowledge_retrieval/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/knowledge_retrieval/knowledge_retrieval_node.py (94%) rename api/{core/workflow => dify_graph}/nodes/knowledge_retrieval/template_prompts.py (100%) rename api/{core/workflow => dify_graph}/nodes/list_operator/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/list_operator/entities.py (96%) rename api/{core/workflow => dify_graph}/nodes/list_operator/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/list_operator/node.py (97%) rename api/{core/workflow => dify_graph}/nodes/llm/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/llm/entities.py (96%) rename api/{core/workflow => dify_graph}/nodes/llm/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/llm/file_saver.py (98%) rename api/{core/workflow => dify_graph}/nodes/llm/llm_utils.py (93%) rename api/{core/workflow => dify_graph}/nodes/llm/node.py (98%) rename api/{core/workflow => dify_graph}/nodes/llm/protocols.py (100%) rename api/{core/workflow => dify_graph}/nodes/loop/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/loop/entities.py (91%) rename api/{core/workflow => dify_graph}/nodes/loop/loop_end_node.py (59%) rename api/{core/workflow => dify_graph}/nodes/loop/loop_node.py (95%) rename api/{core/workflow => dify_graph}/nodes/loop/loop_start_node.py (59%) rename api/{core/workflow => dify_graph}/nodes/node_mapping.py (65%) rename api/{core/workflow => dify_graph}/nodes/parameter_extractor/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/parameter_extractor/entities.py (95%) rename api/{core/workflow => dify_graph}/nodes/parameter_extractor/exc.py (97%) rename api/{core/workflow => dify_graph}/nodes/parameter_extractor/parameter_extractor_node.py (98%) rename api/{core/workflow => dify_graph}/nodes/parameter_extractor/prompts.py (100%) rename api/{core/workflow => dify_graph}/nodes/protocols.py (96%) rename api/{core/workflow => dify_graph}/nodes/question_classifier/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/question_classifier/entities.py (87%) rename api/{core/workflow => dify_graph}/nodes/question_classifier/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/question_classifier/question_classifier_node.py (95%) rename api/{core/workflow => dify_graph}/nodes/question_classifier/template_prompts.py (100%) rename api/{core/workflow => dify_graph}/nodes/start/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/start/entities.py (64%) rename api/{core/workflow => dify_graph}/nodes/start/start_node.py (84%) rename api/{core/workflow => dify_graph}/nodes/template_transform/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/template_transform/entities.py (57%) rename api/{core/workflow => dify_graph}/nodes/template_transform/template_renderer.py (100%) rename api/{core/workflow => dify_graph}/nodes/template_transform/template_transform_node.py (88%) rename api/{core/workflow => dify_graph}/nodes/tool/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/tool/entities.py (98%) rename api/{core/workflow => dify_graph}/nodes/tool/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/tool/tool_node.py (97%) rename api/{core/workflow => dify_graph}/nodes/trigger_plugin/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/trigger_plugin/entities.py (95%) rename api/{core/workflow => dify_graph}/nodes/trigger_plugin/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/trigger_plugin/trigger_event_node.py (85%) create mode 100644 api/dify_graph/nodes/trigger_schedule/__init__.py rename api/{core/workflow => dify_graph}/nodes/trigger_schedule/entities.py (97%) rename api/{core/workflow => dify_graph}/nodes/trigger_schedule/exc.py (90%) rename api/{core/workflow => dify_graph}/nodes/trigger_schedule/trigger_schedule_node.py (77%) rename api/{core/workflow => dify_graph}/nodes/trigger_webhook/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/trigger_webhook/entities.py (97%) rename api/{core/workflow => dify_graph}/nodes/trigger_webhook/exc.py (86%) rename api/{core/workflow => dify_graph}/nodes/trigger_webhook/node.py (93%) rename api/{core/workflow => dify_graph}/nodes/variable_aggregator/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_aggregator/entities.py (83%) rename api/{core/workflow => dify_graph}/nodes/variable_aggregator/variable_aggregator_node.py (81%) rename api/{core/workflow/nodes/variable_assigner/common => dify_graph/nodes/variable_assigner}/__init__.py (100%) rename api/{core/workflow/utils => dify_graph/nodes/variable_assigner/common}/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/common/exc.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/common/helpers.py (90%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v1/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v1/node.py (88%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v1/node_data.py (86%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/__init__.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/entities.py (94%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/enums.py (100%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/exc.py (93%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/helpers.py (98%) rename api/{core/workflow => dify_graph}/nodes/variable_assigner/v2/node.py (93%) rename api/{core/workflow => dify_graph}/repositories/__init__.py (69%) rename api/{core/workflow => dify_graph}/repositories/datasource_manager_protocol.py (91%) rename api/{core/workflow => dify_graph}/repositories/draft_variable_repository.py (95%) rename api/{core/workflow => dify_graph}/repositories/human_input_form_repository.py (96%) rename api/{core/workflow => dify_graph}/repositories/index_processor_protocol.py (100%) rename api/{core/workflow => dify_graph}/repositories/rag_retrieval_protocol.py (97%) rename api/{core/workflow => dify_graph}/repositories/summary_index_service_protocol.py (100%) rename api/{core/workflow => dify_graph}/repositories/workflow_execution_repository.py (95%) rename api/{core/workflow => dify_graph}/repositories/workflow_node_execution_repository.py (97%) rename api/{core/workflow => dify_graph}/runtime/__init__.py (100%) rename api/{core/workflow => dify_graph}/runtime/graph_runtime_state.py (97%) rename api/{core/workflow => dify_graph}/runtime/graph_runtime_state_protocol.py (94%) rename api/{core/workflow => dify_graph}/runtime/read_only_wrappers.py (95%) rename api/{core/workflow => dify_graph}/runtime/variable_pool.py (95%) rename api/{core/workflow => dify_graph}/system_variable.py (98%) rename api/{core/workflow/utils/condition => dify_graph/utils}/__init__.py (100%) create mode 100644 api/dify_graph/utils/condition/__init__.py rename api/{core/workflow => dify_graph}/utils/condition/entities.py (100%) rename api/{core/workflow => dify_graph}/utils/condition/processor.py (98%) rename api/{core/workflow => dify_graph}/variable_loader.py (95%) rename api/{core/workflow => dify_graph}/variables/__init__.py (100%) rename api/{core/workflow => dify_graph}/variables/consts.py (100%) rename api/{core/workflow => dify_graph}/variables/exc.py (100%) rename api/{core/workflow => dify_graph}/variables/input_entities.py (97%) rename api/{core/workflow => dify_graph}/variables/segment_group.py (100%) rename api/{core/workflow => dify_graph}/variables/segments.py (99%) rename api/{core/workflow => dify_graph}/variables/types.py (99%) rename api/{core/workflow => dify_graph}/variables/utils.py (100%) rename api/{core/workflow => dify_graph}/variables/variables.py (100%) rename api/{core/workflow => dify_graph}/workflow_type_encoder.py (95%) diff --git a/api/.importlinter b/api/.importlinter index 28c853bb62..0bba4fb1e0 100644 --- a/api/.importlinter +++ b/api/.importlinter @@ -1,6 +1,7 @@ [importlinter] root_packages = core + dify_graph configs controllers extensions @@ -21,48 +22,48 @@ layers = runtime entities containers = - core.workflow + dify_graph ignore_imports = - core.workflow.nodes.base.node -> core.workflow.graph_events - core.workflow.nodes.iteration.iteration_node -> core.workflow.graph_events - core.workflow.nodes.loop.loop_node -> core.workflow.graph_events + dify_graph.nodes.base.node -> dify_graph.graph_events + dify_graph.nodes.iteration.iteration_node -> dify_graph.graph_events + dify_graph.nodes.loop.loop_node -> dify_graph.graph_events - core.workflow.nodes.iteration.iteration_node -> core.app.workflow.node_factory - core.workflow.nodes.loop.loop_node -> core.app.workflow.node_factory - core.workflow.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota - core.workflow.nodes.loop.loop_node -> core.app.workflow.layers.llm_quota + dify_graph.nodes.iteration.iteration_node -> core.workflow.node_factory + dify_graph.nodes.loop.loop_node -> core.workflow.node_factory + dify_graph.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota + dify_graph.nodes.loop.loop_node -> core.app.workflow.layers.llm_quota - core.workflow.nodes.iteration.iteration_node -> core.workflow.graph_engine - core.workflow.nodes.iteration.iteration_node -> core.workflow.graph - core.workflow.nodes.iteration.iteration_node -> core.workflow.graph_engine.command_channels - core.workflow.nodes.loop.loop_node -> core.workflow.graph_engine - core.workflow.nodes.loop.loop_node -> core.workflow.graph - core.workflow.nodes.loop.loop_node -> core.workflow.graph_engine.command_channels + dify_graph.nodes.iteration.iteration_node -> dify_graph.graph_engine + dify_graph.nodes.iteration.iteration_node -> dify_graph.graph + dify_graph.nodes.iteration.iteration_node -> dify_graph.graph_engine.command_channels + dify_graph.nodes.loop.loop_node -> dify_graph.graph_engine + dify_graph.nodes.loop.loop_node -> dify_graph.graph + dify_graph.nodes.loop.loop_node -> dify_graph.graph_engine.command_channels # TODO(QuantumGhost): fix the import violation later - core.workflow.entities.pause_reason -> core.workflow.nodes.human_input.entities + dify_graph.entities.pause_reason -> dify_graph.nodes.human_input.entities [importlinter:contract:workflow-infrastructure-dependencies] name = Workflow Infrastructure Dependencies type = forbidden source_modules = - core.workflow + dify_graph forbidden_modules = extensions.ext_database extensions.ext_redis allow_indirect_imports = True ignore_imports = - core.workflow.nodes.agent.agent_node -> extensions.ext_database - core.workflow.nodes.llm.file_saver -> extensions.ext_database - core.workflow.nodes.llm.node -> extensions.ext_database - core.workflow.nodes.tool.tool_node -> extensions.ext_database + dify_graph.nodes.agent.agent_node -> extensions.ext_database + dify_graph.nodes.llm.file_saver -> extensions.ext_database + dify_graph.nodes.llm.node -> extensions.ext_database + dify_graph.nodes.tool.tool_node -> extensions.ext_database # TODO(QuantumGhost): use DI to avoid depending on global DB. - core.workflow.nodes.human_input.human_input_node -> extensions.ext_database + dify_graph.nodes.human_input.human_input_node -> extensions.ext_database [importlinter:contract:workflow-external-imports] name = Workflow External Imports type = forbidden source_modules = - core.workflow + dify_graph forbidden_modules = configs controllers @@ -100,77 +101,68 @@ forbidden_modules = core.trigger core.variables ignore_imports = - core.workflow.nodes.loop.loop_node -> core.app.workflow.node_factory - core.workflow.workflow_entry -> core.app.workflow.layers.observability - core.workflow.nodes.agent.agent_node -> core.model_manager - core.workflow.nodes.agent.agent_node -> core.provider_manager - core.workflow.nodes.agent.agent_node -> core.tools.tool_manager - core.workflow.nodes.document_extractor.node -> core.helper.ssrf_proxy - core.workflow.nodes.iteration.iteration_node -> core.app.workflow.node_factory - core.workflow.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota - core.workflow.nodes.llm.llm_utils -> core.model_manager - core.workflow.nodes.llm.protocols -> core.model_manager - core.workflow.nodes.llm.llm_utils -> core.model_runtime.model_providers.__base.large_language_model - core.workflow.nodes.llm.node -> core.tools.signature - core.workflow.nodes.tool.tool_node -> core.callback_handler.workflow_tool_callback_handler - core.workflow.nodes.tool.tool_node -> core.tools.tool_engine - core.workflow.nodes.tool.tool_node -> core.tools.tool_manager - core.workflow.workflow_entry -> configs - core.workflow.workflow_entry -> models.workflow - core.workflow.nodes.agent.agent_node -> core.agent.entities - core.workflow.nodes.agent.agent_node -> core.agent.plugin_entities - core.workflow.nodes.base.node -> core.app.entities.app_invoke_entities - core.workflow.nodes.human_input.human_input_node -> core.app.entities.app_invoke_entities - core.workflow.nodes.knowledge_index.knowledge_index_node -> core.app.entities.app_invoke_entities - core.workflow.nodes.knowledge_retrieval.knowledge_retrieval_node -> core.app.app_config.entities - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.advanced_prompt_transform - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.simple_prompt_transform - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.model_runtime.model_providers.__base.large_language_model - core.workflow.nodes.question_classifier.question_classifier_node -> core.prompt.simple_prompt_transform - core.workflow.workflow_entry -> core.app.apps.exc - core.workflow.workflow_entry -> core.app.entities.app_invoke_entities - core.workflow.workflow_entry -> core.app.workflow.layers.llm_quota - core.workflow.workflow_entry -> core.app.workflow.node_factory - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.model_manager - core.workflow.nodes.question_classifier.question_classifier_node -> core.model_manager - core.workflow.nodes.tool.tool_node -> core.tools.utils.message_transformer - core.workflow.nodes.tool.tool_node -> models - core.workflow.nodes.agent.agent_node -> models.model - core.workflow.nodes.llm.file_saver -> core.helper.ssrf_proxy - core.workflow.nodes.llm.node -> core.helper.code_executor - core.workflow.nodes.template_transform.template_renderer -> core.helper.code_executor.code_executor - core.workflow.nodes.llm.node -> core.llm_generator.output_parser.errors - core.workflow.nodes.llm.node -> core.llm_generator.output_parser.structured_output - core.workflow.nodes.llm.node -> core.model_manager - core.workflow.nodes.agent.entities -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.llm.entities -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.llm.node -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.llm.node -> core.prompt.utils.prompt_message_util - core.workflow.nodes.parameter_extractor.entities -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.utils.prompt_message_util - core.workflow.nodes.question_classifier.entities -> core.prompt.entities.advanced_prompt_entities - core.workflow.nodes.question_classifier.question_classifier_node -> core.prompt.utils.prompt_message_util - core.workflow.nodes.knowledge_index.entities -> core.rag.retrieval.retrieval_methods - core.workflow.nodes.llm.node -> models.dataset - core.workflow.nodes.agent.agent_node -> core.tools.utils.message_transformer - core.workflow.nodes.llm.file_saver -> core.tools.signature - core.workflow.nodes.llm.file_saver -> core.tools.tool_file_manager - core.workflow.nodes.tool.tool_node -> core.tools.errors - core.workflow.nodes.agent.agent_node -> extensions.ext_database - core.workflow.nodes.llm.file_saver -> extensions.ext_database - core.workflow.nodes.llm.node -> extensions.ext_database - core.workflow.nodes.tool.tool_node -> extensions.ext_database - core.workflow.nodes.human_input.human_input_node -> extensions.ext_database - core.workflow.nodes.human_input.human_input_node -> core.repositories.human_input_repository - core.workflow.workflow_entry -> extensions.otel.runtime - core.workflow.nodes.agent.agent_node -> models - core.workflow.nodes.base.node -> models.enums - core.workflow.nodes.loop.loop_node -> core.app.workflow.layers.llm_quota - core.workflow.nodes.llm.node -> models.model - core.workflow.workflow_entry -> models.enums - core.workflow.nodes.agent.agent_node -> services - core.workflow.nodes.tool.tool_node -> services + dify_graph.nodes.loop.loop_node -> core.workflow.node_factory + dify_graph.nodes.agent.agent_node -> core.model_manager + dify_graph.nodes.agent.agent_node -> core.provider_manager + dify_graph.nodes.agent.agent_node -> core.tools.tool_manager + dify_graph.nodes.document_extractor.node -> core.helper.ssrf_proxy + dify_graph.nodes.iteration.iteration_node -> core.workflow.node_factory + dify_graph.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota + dify_graph.nodes.llm.llm_utils -> core.model_manager + dify_graph.nodes.llm.protocols -> core.model_manager + dify_graph.nodes.llm.llm_utils -> core.model_runtime.model_providers.__base.large_language_model + dify_graph.nodes.llm.node -> core.tools.signature + dify_graph.nodes.tool.tool_node -> core.callback_handler.workflow_tool_callback_handler + dify_graph.nodes.tool.tool_node -> core.tools.tool_engine + dify_graph.nodes.tool.tool_node -> core.tools.tool_manager + dify_graph.nodes.agent.agent_node -> core.agent.entities + dify_graph.nodes.agent.agent_node -> core.agent.plugin_entities + dify_graph.nodes.base.node -> core.app.entities.app_invoke_entities + dify_graph.nodes.human_input.human_input_node -> core.app.entities.app_invoke_entities + dify_graph.nodes.knowledge_index.knowledge_index_node -> core.app.entities.app_invoke_entities + dify_graph.nodes.knowledge_retrieval.knowledge_retrieval_node -> core.app.app_config.entities + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.advanced_prompt_transform + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.simple_prompt_transform + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.model_runtime.model_providers.__base.large_language_model + dify_graph.nodes.question_classifier.question_classifier_node -> core.prompt.simple_prompt_transform + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.model_manager + dify_graph.nodes.question_classifier.question_classifier_node -> core.model_manager + dify_graph.nodes.tool.tool_node -> core.tools.utils.message_transformer + dify_graph.nodes.tool.tool_node -> models + dify_graph.nodes.agent.agent_node -> models.model + dify_graph.nodes.llm.file_saver -> core.helper.ssrf_proxy + dify_graph.nodes.llm.node -> core.helper.code_executor + dify_graph.nodes.template_transform.template_renderer -> core.helper.code_executor.code_executor + dify_graph.nodes.llm.node -> core.llm_generator.output_parser.errors + dify_graph.nodes.llm.node -> core.llm_generator.output_parser.structured_output + dify_graph.nodes.llm.node -> core.model_manager + dify_graph.nodes.agent.entities -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.llm.entities -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.llm.node -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.llm.node -> core.prompt.utils.prompt_message_util + dify_graph.nodes.parameter_extractor.entities -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.utils.prompt_message_util + dify_graph.nodes.question_classifier.entities -> core.prompt.entities.advanced_prompt_entities + dify_graph.nodes.question_classifier.question_classifier_node -> core.prompt.utils.prompt_message_util + dify_graph.nodes.knowledge_index.entities -> core.rag.retrieval.retrieval_methods + dify_graph.nodes.llm.node -> models.dataset + dify_graph.nodes.agent.agent_node -> core.tools.utils.message_transformer + dify_graph.nodes.llm.file_saver -> core.tools.signature + dify_graph.nodes.llm.file_saver -> core.tools.tool_file_manager + dify_graph.nodes.tool.tool_node -> core.tools.errors + dify_graph.nodes.agent.agent_node -> extensions.ext_database + dify_graph.nodes.llm.file_saver -> extensions.ext_database + dify_graph.nodes.llm.node -> extensions.ext_database + dify_graph.nodes.tool.tool_node -> extensions.ext_database + dify_graph.nodes.human_input.human_input_node -> extensions.ext_database + dify_graph.nodes.human_input.human_input_node -> core.repositories.human_input_repository + dify_graph.nodes.agent.agent_node -> models + dify_graph.nodes.base.node -> models.enums + dify_graph.nodes.loop.loop_node -> core.app.workflow.layers.llm_quota + dify_graph.nodes.llm.node -> models.model + dify_graph.nodes.agent.agent_node -> services + dify_graph.nodes.tool.tool_node -> services [importlinter:contract:model-runtime-no-internal-imports] name = Model Runtime Internal Imports @@ -214,7 +206,7 @@ forbidden_modules = core.tools core.trigger core.variables - core.workflow + dify_graph ignore_imports = core.model_runtime.model_providers.__base.ai_model -> configs core.model_runtime.model_providers.__base.ai_model -> extensions.ext_redis @@ -231,7 +223,7 @@ layers = graph_engine response_coordinator containers = - core.workflow.graph_engine + dify_graph.graph_engine [importlinter:contract:worker] name = Worker @@ -240,7 +232,7 @@ layers = graph_engine worker containers = - core.workflow.graph_engine + dify_graph.graph_engine [importlinter:contract:graph-engine-architecture] name = Graph Engine Architecture @@ -256,28 +248,28 @@ layers = worker_management domain containers = - core.workflow.graph_engine + dify_graph.graph_engine [importlinter:contract:domain-isolation] name = Domain Model Isolation type = forbidden source_modules = - core.workflow.graph_engine.domain + dify_graph.graph_engine.domain forbidden_modules = - core.workflow.graph_engine.worker_management - core.workflow.graph_engine.command_channels - core.workflow.graph_engine.layers - core.workflow.graph_engine.protocols + dify_graph.graph_engine.worker_management + dify_graph.graph_engine.command_channels + dify_graph.graph_engine.layers + dify_graph.graph_engine.protocols [importlinter:contract:worker-management] name = Worker Management type = forbidden source_modules = - core.workflow.graph_engine.worker_management + dify_graph.graph_engine.worker_management forbidden_modules = - core.workflow.graph_engine.orchestration - core.workflow.graph_engine.command_processing - core.workflow.graph_engine.event_management + dify_graph.graph_engine.orchestration + dify_graph.graph_engine.command_processing + dify_graph.graph_engine.event_management [importlinter:contract:graph-traversal-components] @@ -287,11 +279,11 @@ layers = edge_processor skip_propagator containers = - core.workflow.graph_engine.graph_traversal + dify_graph.graph_engine.graph_traversal [importlinter:contract:command-channels] name = Command Channels Independence type = independence modules = - core.workflow.graph_engine.command_channels.in_memory_channel - core.workflow.graph_engine.command_channels.redis_channel + dify_graph.graph_engine.command_channels.in_memory_channel + dify_graph.graph_engine.command_channels.redis_channel diff --git a/api/context/__init__.py b/api/context/__init__.py index aebf9750ce..969e5f583d 100644 --- a/api/context/__init__.py +++ b/api/context/__init__.py @@ -12,7 +12,7 @@ or any other web framework. import contextvars from collections.abc import Callable -from core.workflow.context.execution_context import ( +from dify_graph.context.execution_context import ( ExecutionContext, IExecutionContext, NullAppContext, diff --git a/api/context/flask_app_context.py b/api/context/flask_app_context.py index 2d465c8cf4..324a9ee8b4 100644 --- a/api/context/flask_app_context.py +++ b/api/context/flask_app_context.py @@ -10,8 +10,8 @@ from typing import Any, final from flask import Flask, current_app, g -from core.workflow.context import register_context_capturer -from core.workflow.context.execution_context import ( +from dify_graph.context import register_context_capturer +from dify_graph.context.execution_context import ( AppContext, IExecutionContext, ) diff --git a/api/controllers/common/fields.py b/api/controllers/common/fields.py index 9b30db8b75..ff5326dade 100644 --- a/api/controllers/common/fields.py +++ b/api/controllers/common/fields.py @@ -4,7 +4,7 @@ from typing import Any, TypeAlias from pydantic import BaseModel, ConfigDict, computed_field -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from models.model import IconType JSONValue: TypeAlias = str | int | float | bool | None | dict[str, Any] | list[Any] diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py index e799e98d3e..33b3c9ec36 100644 --- a/api/controllers/console/app/app.py +++ b/api/controllers/console/app/app.py @@ -25,8 +25,8 @@ from controllers.console.wraps import ( ) from core.ops.ops_trace_manager import OpsTraceManager from core.rag.retrieval.retrieval_methods import RetrievalMethod -from core.workflow.enums import NodeType, WorkflowExecutionStatus -from core.workflow.file import helpers as file_helpers +from dify_graph.enums import NodeType, WorkflowExecutionStatus +from dify_graph.file import helpers as file_helpers from extensions.ext_database import db from libs.login import current_account_with_tenant, login_required from models import App, DatasetPermissionEnum, Workflow diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index a66e9543ff..735616bb6b 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -29,9 +29,9 @@ from core.trigger.debug.event_selectors import ( create_event_poller, select_trigger_debug_events, ) -from core.workflow.enums import NodeType -from core.workflow.file.models import File -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.enums import NodeType +from dify_graph.file.models import File +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_database import db from extensions.ext_redis import redis_client from factories import file_factory, variable_factory diff --git a/api/controllers/console/app/workflow_app_log.py b/api/controllers/console/app/workflow_app_log.py index 6736f24a2e..9b148c3f18 100644 --- a/api/controllers/console/app/workflow_app_log.py +++ b/api/controllers/console/app/workflow_app_log.py @@ -9,7 +9,7 @@ from sqlalchemy.orm import Session from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from extensions.ext_database import db from fields.workflow_app_log_fields import ( build_workflow_app_log_pagination_model, diff --git a/api/controllers/console/app/workflow_draft_variable.py b/api/controllers/console/app/workflow_draft_variable.py index f37598fb31..165bfcd4ba 100644 --- a/api/controllers/console/app/workflow_draft_variable.py +++ b/api/controllers/console/app/workflow_draft_variable.py @@ -15,11 +15,11 @@ from controllers.console.app.error import ( from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required from controllers.web.error import InvalidArgumentError, NotFoundError -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.file import helpers as file_helpers -from core.workflow.variables.segment_group import SegmentGroup -from core.workflow.variables.segments import ArrayFileSegment, FileSegment, Segment -from core.workflow.variables.types import SegmentType +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.file import helpers as file_helpers +from dify_graph.variables.segment_group import SegmentGroup +from dify_graph.variables.segments import ArrayFileSegment, FileSegment, Segment +from dify_graph.variables.types import SegmentType from extensions.ext_database import db from factories.file_factory import build_from_mapping, build_from_mappings from factories.variable_factory import build_segment_with_type diff --git a/api/controllers/console/app/workflow_run.py b/api/controllers/console/app/workflow_run.py index 9ac45cf2da..7ac653395e 100644 --- a/api/controllers/console/app/workflow_run.py +++ b/api/controllers/console/app/workflow_run.py @@ -12,8 +12,8 @@ from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required from controllers.web.error import NotFoundError -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import WorkflowExecutionStatus from extensions.ext_database import db from fields.end_user_fields import simple_end_user_fields from fields.member_fields import simple_account_fields diff --git a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py index 7e285c8da9..4c441a5d07 100644 --- a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py +++ b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py @@ -21,8 +21,8 @@ from controllers.console.app.workflow_draft_variable import ( from controllers.console.datasets.wraps import get_rag_pipeline from controllers.console.wraps import account_initialization_required, setup_required from controllers.web.error import InvalidArgumentError, NotFoundError -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.variables.types import SegmentType +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.variables.types import SegmentType from extensions.ext_database import db from factories.file_factory import build_from_mapping, build_from_mappings from factories.variable_factory import build_segment_with_type diff --git a/api/controllers/console/explore/trial.py b/api/controllers/console/explore/trial.py index f6f731df36..7771436641 100644 --- a/api/controllers/console/explore/trial.py +++ b/api/controllers/console/explore/trial.py @@ -42,7 +42,7 @@ from core.errors.error import ( QuotaExceededError, ) from core.model_runtime.errors.invoke import InvokeError -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_database import db from extensions.ext_redis import redis_client from fields.app_fields import ( diff --git a/api/controllers/console/explore/workflow.py b/api/controllers/console/explore/workflow.py index b841bda323..7e48e43b42 100644 --- a/api/controllers/console/explore/workflow.py +++ b/api/controllers/console/explore/workflow.py @@ -22,7 +22,7 @@ from core.errors.error import ( QuotaExceededError, ) from core.model_runtime.errors.invoke import InvokeError -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_redis import redis_client from libs import helper from libs.login import current_account_with_tenant diff --git a/api/controllers/console/remote_files.py b/api/controllers/console/remote_files.py index f3738319df..49162d4dae 100644 --- a/api/controllers/console/remote_files.py +++ b/api/controllers/console/remote_files.py @@ -13,7 +13,7 @@ from controllers.common.errors import ( ) from controllers.console import console_ns from core.helper import ssrf_proxy -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from extensions.ext_database import db from fields.file_fields import FileWithSignedUrl, RemoteFileInfo from libs.login import current_account_with_tenant, login_required diff --git a/api/controllers/files/upload.py b/api/controllers/files/upload.py index b34412ef6d..52690a12e1 100644 --- a/api/controllers/files/upload.py +++ b/api/controllers/files/upload.py @@ -8,7 +8,7 @@ from werkzeug.exceptions import Forbidden import services from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file.helpers import verify_plugin_file_signature +from dify_graph.file.helpers import verify_plugin_file_signature from fields.file_fields import FileResponse from ..common.errors import ( diff --git a/api/controllers/inner_api/plugin/plugin.py b/api/controllers/inner_api/plugin/plugin.py index 4cd1c4745f..da1b40f2bd 100644 --- a/api/controllers/inner_api/plugin/plugin.py +++ b/api/controllers/inner_api/plugin/plugin.py @@ -29,7 +29,7 @@ from core.plugin.entities.request import ( RequestRequestUploadFile, ) from core.tools.entities.tool_entities import ToolProviderType -from core.workflow.file.helpers import get_signed_file_url_for_plugin +from dify_graph.file.helpers import get_signed_file_url_for_plugin from libs.helper import length_prefixed_response from models import Account, Tenant from models.model import EndUser diff --git a/api/controllers/mcp/mcp.py b/api/controllers/mcp/mcp.py index 991a9166c7..2bc6640807 100644 --- a/api/controllers/mcp/mcp.py +++ b/api/controllers/mcp/mcp.py @@ -10,7 +10,7 @@ from controllers.console.app.mcp_server import AppMCPServerStatus from controllers.mcp import mcp_ns from core.mcp import types as mcp_types from core.mcp.server.streamable_http import handle_mcp_request -from core.workflow.variables.input_entities import VariableEntity +from dify_graph.variables.input_entities import VariableEntity from extensions.ext_database import db from libs import helper from models.model import App, AppMCPServer, AppMode, EndUser diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index 2ce8f05f75..f58295099f 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -28,8 +28,8 @@ from core.errors.error import ( ) from core.helper.trace_id_helper import get_external_trace_id from core.model_runtime.errors.invoke import InvokeError -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_database import db from extensions.ext_redis import redis_client from fields.workflow_app_log_fields import build_workflow_app_log_pagination_model diff --git a/api/controllers/web/remote_files.py b/api/controllers/web/remote_files.py index 1cdae0fe56..6a93ef6748 100644 --- a/api/controllers/web/remote_files.py +++ b/api/controllers/web/remote_files.py @@ -11,7 +11,7 @@ from controllers.common.errors import ( UnsupportedFileTypeError, ) from core.helper import ssrf_proxy -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from extensions.ext_database import db from fields.file_fields import FileWithSignedUrl, RemoteFileInfo from services.file_service import FileService diff --git a/api/controllers/web/workflow.py b/api/controllers/web/workflow.py index a309ef3dad..a4c1ba75eb 100644 --- a/api/controllers/web/workflow.py +++ b/api/controllers/web/workflow.py @@ -23,7 +23,7 @@ from core.errors.error import ( QuotaExceededError, ) from core.model_runtime.errors.invoke import InvokeError -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_redis import redis_client from libs import helper from models.model import App, AppMode, EndUser diff --git a/api/core/agent/base_agent_runner.py b/api/core/agent/base_agent_runner.py index 80e180ce96..22e3843fec 100644 --- a/api/core/agent/base_agent_runner.py +++ b/api/core/agent/base_agent_runner.py @@ -39,7 +39,7 @@ from core.tools.entities.tool_entities import ( ) from core.tools.tool_manager import ToolManager from core.tools.utils.dataset_retriever_tool import DatasetRetrieverTool -from core.workflow.file import file_manager +from dify_graph.file import file_manager from extensions.ext_database import db from factories import file_factory from models.enums import CreatorUserRole diff --git a/api/core/agent/cot_agent_runner.py b/api/core/agent/cot_agent_runner.py index 0464afe194..511406afde 100644 --- a/api/core/agent/cot_agent_runner.py +++ b/api/core/agent/cot_agent_runner.py @@ -22,7 +22,7 @@ from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransfo from core.tools.__base.tool import Tool from core.tools.entities.tool_entities import ToolInvokeMeta from core.tools.tool_engine import ToolEngine -from core.workflow.nodes.agent.exc import AgentMaxIterationError +from dify_graph.nodes.agent.exc import AgentMaxIterationError from models.model import Message logger = logging.getLogger(__name__) diff --git a/api/core/agent/cot_chat_agent_runner.py b/api/core/agent/cot_chat_agent_runner.py index babb463aba..b0a0b23fb5 100644 --- a/api/core/agent/cot_chat_agent_runner.py +++ b/api/core/agent/cot_chat_agent_runner.py @@ -10,7 +10,7 @@ from core.model_runtime.entities import ( ) from core.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.file import file_manager +from dify_graph.file import file_manager class CotChatAgentRunner(CotAgentRunner): diff --git a/api/core/agent/fc_agent_runner.py b/api/core/agent/fc_agent_runner.py index 633609f54f..23650cc21e 100644 --- a/api/core/agent/fc_agent_runner.py +++ b/api/core/agent/fc_agent_runner.py @@ -24,8 +24,8 @@ from core.model_runtime.entities.message_entities import ImagePromptMessageConte from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform from core.tools.entities.tool_entities import ToolInvokeMeta from core.tools.tool_engine import ToolEngine -from core.workflow.file import file_manager -from core.workflow.nodes.agent.exc import AgentMaxIterationError +from dify_graph.file import file_manager +from dify_graph.nodes.agent.exc import AgentMaxIterationError from models.model import Message logger = logging.getLogger(__name__) diff --git a/api/core/app/app_config/easy_ui_based_app/variables/manager.py b/api/core/app/app_config/easy_ui_based_app/variables/manager.py index 22d602a190..157e5d8bc0 100644 --- a/api/core/app/app_config/easy_ui_based_app/variables/manager.py +++ b/api/core/app/app_config/easy_ui_based_app/variables/manager.py @@ -2,7 +2,7 @@ import re from core.app.app_config.entities import ExternalDataVariableEntity from core.external_data_tool.factory import ExternalDataToolFactory -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType _ALLOWED_VARIABLE_ENTITY_TYPE = frozenset( [ diff --git a/api/core/app/app_config/entities.py b/api/core/app/app_config/entities.py index 062cc6a0b3..b5de73dadd 100644 --- a/api/core/app/app_config/entities.py +++ b/api/core/app/app_config/entities.py @@ -6,8 +6,8 @@ from pydantic import BaseModel, Field from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.file import FileUploadConfig -from core.workflow.variables.input_entities import VariableEntity as WorkflowVariableEntity +from dify_graph.file import FileUploadConfig +from dify_graph.variables.input_entities import VariableEntity as WorkflowVariableEntity from models.model import AppMode diff --git a/api/core/app/app_config/features/file_upload/manager.py b/api/core/app/app_config/features/file_upload/manager.py index d69fa85801..0c4266fbeb 100644 --- a/api/core/app/app_config/features/file_upload/manager.py +++ b/api/core/app/app_config/features/file_upload/manager.py @@ -2,7 +2,7 @@ from collections.abc import Mapping from typing import Any from constants import DEFAULT_FILE_NUMBER_LIMITS -from core.workflow.file import FileUploadConfig +from dify_graph.file import FileUploadConfig class FileUploadConfigManager: diff --git a/api/core/app/app_config/workflow_ui_based_app/variables/manager.py b/api/core/app/app_config/workflow_ui_based_app/variables/manager.py index ec7d85a09f..d2a9a73380 100644 --- a/api/core/app/app_config/workflow_ui_based_app/variables/manager.py +++ b/api/core/app/app_config/workflow_ui_based_app/variables/manager.py @@ -1,7 +1,7 @@ import re from core.app.app_config.entities import RagPipelineVariableEntity -from core.workflow.variables.input_entities import VariableEntity +from dify_graph.variables.input_entities import VariableEntity from models.workflow import Workflow diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index 2891d3ceeb..ccac77eeaa 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -35,14 +35,14 @@ from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.prompt.utils.get_thread_messages_length import get_thread_messages_length from core.repositories import DifyCoreRepositoryFactory -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.repositories.draft_variable_repository import ( +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.repositories.draft_variable_repository import ( DraftVariableSaverFactory, ) -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.runtime import GraphRuntimeState -from core.workflow.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.runtime import GraphRuntimeState +from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader from extensions.ext_database import db from factories import file_factory from libs.flask_utils import preserve_flask_contexts diff --git a/api/core/app/apps/advanced_chat/app_runner.py b/api/core/app/apps/advanced_chat/app_runner.py index 18ae75a087..b38dfdfc1f 100644 --- a/api/core/app/apps/advanced_chat/app_runner.py +++ b/api/core/app/apps/advanced_chat/app_runner.py @@ -25,16 +25,16 @@ from core.app.workflow.layers.persistence import PersistenceWorkflowInfo, Workfl from core.db.session_factory import session_factory from core.moderation.base import ModerationError from core.moderation.input_moderation import InputModeration -from core.workflow.enums import WorkflowType -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import VariableLoader -from core.workflow.variables.variables import Variable from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.enums import WorkflowType +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import VariableLoader +from dify_graph.variables.variables import Variable from extensions.ext_database import db from extensions.ext_redis import redis_client from extensions.otel import WorkflowAppRunnerHandler, trace_span diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index 534ef6994a..c19a1e9c0d 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -67,12 +67,12 @@ from core.model_runtime.entities.llm_entities import LLMUsage from core.model_runtime.utils.encoders import jsonable_encoder from core.ops.ops_trace_manager import TraceQueueManager from core.repositories.human_input_repository import HumanInputFormRepositoryImpl -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.nodes import NodeType -from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory -from core.workflow.runtime import GraphRuntimeState -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.nodes import NodeType +from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory +from dify_graph.runtime import GraphRuntimeState +from dify_graph.system_variable import SystemVariable from extensions.ext_database import db from libs.datetime_utils import naive_utc_now from models import Account, Conversation, EndUser, Message, MessageFile diff --git a/api/core/app/apps/base_app_generator.py b/api/core/app/apps/base_app_generator.py index 81617c5fb2..20e6ac98ea 100644 --- a/api/core/app/apps/base_app_generator.py +++ b/api/core/app/apps/base_app_generator.py @@ -4,21 +4,21 @@ from typing import TYPE_CHECKING, Any, Union, final from sqlalchemy.orm import Session from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.enums import NodeType -from core.workflow.file import File, FileUploadConfig -from core.workflow.repositories.draft_variable_repository import ( +from dify_graph.enums import NodeType +from dify_graph.file import File, FileUploadConfig +from dify_graph.repositories.draft_variable_repository import ( DraftVariableSaver, DraftVariableSaverFactory, NoopDraftVariableSaver, ) -from core.workflow.variables.input_entities import VariableEntityType +from dify_graph.variables.input_entities import VariableEntityType from factories import file_factory from libs.orjson import orjson_dumps from models import Account, EndUser from services.workflow_draft_variable_service import DraftVariableSaver as DraftVariableSaverImpl if TYPE_CHECKING: - from core.workflow.variables.input_entities import VariableEntity + from dify_graph.variables.input_entities import VariableEntity class BaseAppGenerator: diff --git a/api/core/app/apps/base_app_queue_manager.py b/api/core/app/apps/base_app_queue_manager.py index af1f1d7c66..5addd41815 100644 --- a/api/core/app/apps/base_app_queue_manager.py +++ b/api/core/app/apps/base_app_queue_manager.py @@ -20,7 +20,7 @@ from core.app.entities.queue_entities import ( QueueStopEvent, WorkflowQueueMessage, ) -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState from extensions.ext_redis import redis_client logger = logging.getLogger(__name__) diff --git a/api/core/app/apps/base_app_runner.py b/api/core/app/apps/base_app_runner.py index b98e85dbe9..0223d8f9a7 100644 --- a/api/core/app/apps/base_app_runner.py +++ b/api/core/app/apps/base_app_runner.py @@ -38,13 +38,13 @@ from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig from core.prompt.simple_prompt_transform import ModelMode, SimplePromptTransform from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file.enums import FileTransferMethod, FileType +from dify_graph.file.enums import FileTransferMethod, FileType from extensions.ext_database import db from models.enums import CreatorUserRole from models.model import App, AppMode, Message, MessageAnnotation, MessageFile if TYPE_CHECKING: - from core.workflow.file.models import File + from dify_graph.file.models import File _logger = logging.getLogger(__name__) diff --git a/api/core/app/apps/chat/app_runner.py b/api/core/app/apps/chat/app_runner.py index 4870a56281..5cf13fbb17 100644 --- a/api/core/app/apps/chat/app_runner.py +++ b/api/core/app/apps/chat/app_runner.py @@ -16,7 +16,7 @@ from core.model_manager import ModelInstance from core.model_runtime.entities.message_entities import ImagePromptMessageContent from core.moderation.base import ModerationError from core.rag.retrieval.dataset_retrieval import DatasetRetrieval -from core.workflow.file import File +from dify_graph.file import File from extensions.ext_database import db from models.model import App, Conversation, Message diff --git a/api/core/app/apps/common/graph_runtime_state_support.py b/api/core/app/apps/common/graph_runtime_state_support.py index 0b03149665..6a8e436163 100644 --- a/api/core/app/apps/common/graph_runtime_state_support.py +++ b/api/core/app/apps/common/graph_runtime_state_support.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import TYPE_CHECKING -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState if TYPE_CHECKING: from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline diff --git a/api/core/app/apps/common/workflow_response_converter.py b/api/core/app/apps/common/workflow_response_converter.py index d4e801de13..67dc9909a1 100644 --- a/api/core/app/apps/common/workflow_response_converter.py +++ b/api/core/app/apps/common/workflow_response_converter.py @@ -49,21 +49,21 @@ from core.plugin.impl.datasource import PluginDatasourceManager from core.tools.entities.tool_entities import ToolProviderType from core.tools.tool_manager import ToolManager from core.trigger.trigger_manager import TriggerManager -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import ( +from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import ( NodeType, SystemVariableKey, WorkflowExecutionStatus, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.file import FILE_MODEL_IDENTITY, File -from core.workflow.runtime import GraphRuntimeState -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.segments import ArrayFileSegment, FileSegment, Segment -from core.workflow.workflow_entry import WorkflowEntry -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.file import FILE_MODEL_IDENTITY, File +from dify_graph.runtime import GraphRuntimeState +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.segments import ArrayFileSegment, FileSegment, Segment +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.ext_database import db from libs.datetime_utils import naive_utc_now from models import Account, EndUser diff --git a/api/core/app/apps/completion/app_runner.py b/api/core/app/apps/completion/app_runner.py index 30e1a609f8..96bbe532f1 100644 --- a/api/core/app/apps/completion/app_runner.py +++ b/api/core/app/apps/completion/app_runner.py @@ -14,7 +14,7 @@ from core.model_manager import ModelInstance from core.model_runtime.entities.message_entities import ImagePromptMessageContent from core.moderation.base import ModerationError from core.rag.retrieval.dataset_retrieval import DatasetRetrieval -from core.workflow.file import File +from dify_graph.file import File from extensions.ext_database import db from models.model import App, Message diff --git a/api/core/app/apps/pipeline/pipeline_generator.py b/api/core/app/apps/pipeline/pipeline_generator.py index eca96cb074..6be2d034b5 100644 --- a/api/core/app/apps/pipeline/pipeline_generator.py +++ b/api/core/app/apps/pipeline/pipeline_generator.py @@ -36,10 +36,10 @@ from core.entities.knowledge_entities import PipelineDataset, PipelineDocument from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.rag.index_processor.constant.built_in_field import BuiltInField from core.repositories.factory import DifyCoreRepositoryFactory -from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader +from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader from extensions.ext_database import db from libs.flask_utils import preserve_flask_contexts from models import Account, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/app/apps/pipeline/pipeline_runner.py b/api/core/app/apps/pipeline/pipeline_runner.py index 02caf8f511..b518e33eeb 100644 --- a/api/core/app/apps/pipeline/pipeline_runner.py +++ b/api/core/app/apps/pipeline/pipeline_runner.py @@ -10,18 +10,18 @@ from core.app.entities.app_invoke_entities import ( RagPipelineGenerateEntity, ) from core.app.workflow.layers.persistence import PersistenceWorkflowInfo, WorkflowPersistenceLayer -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.enums import WorkflowType -from core.workflow.graph import Graph -from core.workflow.graph_events import GraphEngineEvent, GraphRunFailedEvent -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import VariableLoader -from core.workflow.variables.variables import RAGPipelineVariable, RAGPipelineVariableInput +from core.workflow.node_factory import DifyNodeFactory from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.enums import WorkflowType +from dify_graph.graph import Graph +from dify_graph.graph_events import GraphEngineEvent, GraphRunFailedEvent +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import VariableLoader +from dify_graph.variables.variables import RAGPipelineVariable, RAGPipelineVariableInput from extensions.ext_database import db from models.dataset import Document, Pipeline from models.enums import UserFrom diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index dc5852d552..4eee00c999 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -31,12 +31,12 @@ from core.helper.trace_id_helper import extract_external_trace_id_from_args from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.repositories import DifyCoreRepositoryFactory -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.runtime import GraphRuntimeState -from core.workflow.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.runtime import GraphRuntimeState +from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader from extensions.ext_database import db from factories import file_factory from libs.flask_utils import preserve_flask_contexts diff --git a/api/core/app/apps/workflow/app_runner.py b/api/core/app/apps/workflow/app_runner.py index a43f7879d6..caea8b6b95 100644 --- a/api/core/app/apps/workflow/app_runner.py +++ b/api/core/app/apps/workflow/app_runner.py @@ -8,15 +8,15 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfig from core.app.apps.workflow_app_runner import WorkflowBasedAppRunner from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity from core.app.workflow.layers.persistence import PersistenceWorkflowInfo, WorkflowPersistenceLayer -from core.workflow.enums import WorkflowType -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import VariableLoader from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.enums import WorkflowType +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import VariableLoader from extensions.ext_redis import redis_client from extensions.otel import WorkflowAppRunnerHandler, trace_span from libs.datetime_utils import naive_utc_now diff --git a/api/core/app/apps/workflow/generate_task_pipeline.py b/api/core/app/apps/workflow/generate_task_pipeline.py index 0a567a4315..96dd8c5445 100644 --- a/api/core/app/apps/workflow/generate_task_pipeline.py +++ b/api/core/app/apps/workflow/generate_task_pipeline.py @@ -55,11 +55,11 @@ from core.app.entities.task_entities import ( from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.ops.ops_trace_manager import TraceQueueManager -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory -from core.workflow.runtime import GraphRuntimeState -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory +from dify_graph.runtime import GraphRuntimeState +from dify_graph.system_variable import SystemVariable from extensions.ext_database import db from models import Account from models.enums import CreatorUserRole diff --git a/api/core/app/apps/workflow_app_runner.py b/api/core/app/apps/workflow_app_runner.py index c9d7464c17..648c2829de 100644 --- a/api/core/app/apps/workflow_app_runner.py +++ b/api/core/app/apps/workflow_app_runner.py @@ -29,12 +29,13 @@ from core.app.entities.queue_entities import ( QueueWorkflowStartedEvent, QueueWorkflowSucceededEvent, ) -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.graph import Graph -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import ( +from core.workflow.node_factory import DifyNodeFactory +from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.entities import GraphInitParams +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.graph import Graph +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunFailedEvent, GraphRunPartialSucceededEvent, @@ -60,13 +61,12 @@ from core.workflow.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.graph_events.graph import GraphRunAbortedEvent -from core.workflow.nodes import NodeType -from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool -from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.graph_events.graph import GraphRunAbortedEvent +from dify_graph.nodes import NodeType +from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool from models.enums import UserFrom from models.workflow import Workflow from tasks.mail_human_input_delivery_task import dispatch_human_input_email_task diff --git a/api/core/app/entities/app_invoke_entities.py b/api/core/app/entities/app_invoke_entities.py index 65919e89e1..df906e5e54 100644 --- a/api/core/app/entities/app_invoke_entities.py +++ b/api/core/app/entities/app_invoke_entities.py @@ -8,7 +8,7 @@ from constants import UUID_NIL from core.app.app_config.entities import EasyUIBasedAppConfig, WorkflowUIBasedAppConfig from core.entities.provider_configuration import ProviderModelBundle from core.model_runtime.entities.model_entities import AIModelEntity -from core.workflow.file import File, FileUploadConfig +from dify_graph.file import File, FileUploadConfig if TYPE_CHECKING: from core.ops.ops_trace_manager import TraceQueueManager diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index 5b2fa29b56..de19b8e6d2 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -7,11 +7,11 @@ from pydantic import BaseModel, ConfigDict, Field from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk from core.rag.entities.citation_metadata import RetrievalSourceMetadata -from core.workflow.entities import AgentNodeStrategyInit -from core.workflow.entities.pause_reason import PauseReason -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import WorkflowNodeExecutionMetadataKey -from core.workflow.nodes import NodeType +from dify_graph.entities import AgentNodeStrategyInit +from dify_graph.entities.pause_reason import PauseReason +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import WorkflowNodeExecutionMetadataKey +from dify_graph.nodes import NodeType class QueueEvent(StrEnum): diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index f6096eb683..1f3153fff4 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -6,10 +6,10 @@ from pydantic import BaseModel, ConfigDict, Field from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage from core.rag.entities.citation_metadata import RetrievalSourceMetadata -from core.workflow.entities import AgentNodeStrategyInit -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import WorkflowExecutionStatus, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.nodes.human_input.entities import FormInput, UserAction +from dify_graph.entities import AgentNodeStrategyInit +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import WorkflowExecutionStatus, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.nodes.human_input.entities import FormInput, UserAction class AnnotationReplyAccount(BaseModel): diff --git a/api/core/app/layers/conversation_variable_persist_layer.py b/api/core/app/layers/conversation_variable_persist_layer.py index a748d90387..e495abf855 100644 --- a/api/core/app/layers/conversation_variable_persist_layer.py +++ b/api/core/app/layers/conversation_variable_persist_layer.py @@ -1,12 +1,12 @@ import logging -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID -from core.workflow.conversation_variable_updater import ConversationVariableUpdater -from core.workflow.enums import NodeType -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import GraphEngineEvent, NodeRunSucceededEvent -from core.workflow.nodes.variable_assigner.common import helpers as common_helpers -from core.workflow.variables import VariableBase +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID +from dify_graph.conversation_variable_updater import ConversationVariableUpdater +from dify_graph.enums import NodeType +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import GraphEngineEvent, NodeRunSucceededEvent +from dify_graph.nodes.variable_assigner.common import helpers as common_helpers +from dify_graph.variables import VariableBase logger = logging.getLogger(__name__) diff --git a/api/core/app/layers/pause_state_persist_layer.py b/api/core/app/layers/pause_state_persist_layer.py index 1c267091a4..4370c01a0b 100644 --- a/api/core/app/layers/pause_state_persist_layer.py +++ b/api/core/app/layers/pause_state_persist_layer.py @@ -6,9 +6,9 @@ from sqlalchemy import Engine from sqlalchemy.orm import Session, sessionmaker from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events.base import GraphEngineEvent -from core.workflow.graph_events.graph import GraphRunPausedEvent +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events.base import GraphEngineEvent +from dify_graph.graph_events.graph import GraphRunPausedEvent from models.model import AppMode from repositories.api_workflow_run_repository import APIWorkflowRunRepository from repositories.factory import DifyAPIRepositoryFactory diff --git a/api/core/app/layers/suspend_layer.py b/api/core/app/layers/suspend_layer.py index 0a107de012..2adaf14a35 100644 --- a/api/core/app/layers/suspend_layer.py +++ b/api/core/app/layers/suspend_layer.py @@ -1,6 +1,6 @@ -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events.base import GraphEngineEvent -from core.workflow.graph_events.graph import GraphRunPausedEvent +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events.base import GraphEngineEvent +from dify_graph.graph_events.graph import GraphRunPausedEvent class SuspendLayer(GraphEngineLayer): diff --git a/api/core/app/layers/timeslice_layer.py b/api/core/app/layers/timeslice_layer.py index f82397deca..d7ca45f209 100644 --- a/api/core/app/layers/timeslice_layer.py +++ b/api/core/app/layers/timeslice_layer.py @@ -4,9 +4,9 @@ from typing import ClassVar from apscheduler.schedulers.background import BackgroundScheduler # type: ignore -from core.workflow.graph_engine.entities.commands import CommandType, GraphEngineCommand -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events.base import GraphEngineEvent +from dify_graph.graph_engine.entities.commands import CommandType, GraphEngineCommand +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events.base import GraphEngineEvent from services.workflow.entities import WorkflowScheduleCFSPlanEntity from services.workflow.scheduler import CFSPlanScheduler, SchedulerCommand diff --git a/api/core/app/layers/trigger_post_layer.py b/api/core/app/layers/trigger_post_layer.py index a7ea9ef446..a4019a83e1 100644 --- a/api/core/app/layers/trigger_post_layer.py +++ b/api/core/app/layers/trigger_post_layer.py @@ -5,9 +5,9 @@ from typing import Any, ClassVar from pydantic import TypeAdapter from core.db.session_factory import session_factory -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events.base import GraphEngineEvent -from core.workflow.graph_events.graph import GraphRunFailedEvent, GraphRunPausedEvent, GraphRunSucceededEvent +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events.base import GraphEngineEvent +from dify_graph.graph_events.graph import GraphRunFailedEvent, GraphRunPausedEvent, GraphRunSucceededEvent from models.enums import WorkflowTriggerStatus from repositories.sqlalchemy_workflow_trigger_log_repository import SQLAlchemyWorkflowTriggerLogRepository from tasks.workflow_cfs_scheduler.cfs_scheduler import AsyncWorkflowCFSPlanEntity diff --git a/api/core/app/llm/model_access.py b/api/core/app/llm/model_access.py index ebae830389..dc28225b8e 100644 --- a/api/core/app/llm/model_access.py +++ b/api/core/app/llm/model_access.py @@ -7,9 +7,9 @@ from core.errors.error import ProviderTokenNotInitError from core.model_manager import ModelInstance, ModelManager from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager -from core.workflow.nodes.llm.entities import ModelConfig -from core.workflow.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.nodes.llm.entities import ModelConfig +from dify_graph.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory class DifyCredentialsProvider: diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index a77e5abb30..d7946d5478 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -57,8 +57,8 @@ from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.prompt.utils.prompt_message_util import PromptMessageUtil from core.prompt.utils.prompt_template_parser import PromptTemplateParser from core.tools.signature import sign_tool_file -from core.workflow.file import helpers as file_helpers -from core.workflow.file.enums import FileTransferMethod +from dify_graph.file import helpers as file_helpers +from dify_graph.file.enums import FileTransferMethod from events.message_event import message_was_created from extensions.ext_database import db from libs.datetime_utils import naive_utc_now diff --git a/api/core/app/workflow/__init__.py b/api/core/app/workflow/__init__.py index 172ee5d703..3bca7f5c34 100644 --- a/api/core/app/workflow/__init__.py +++ b/api/core/app/workflow/__init__.py @@ -1,3 +1,3 @@ -from .node_factory import DifyNodeFactory +from core.workflow.node_factory import DifyNodeFactory __all__ = ["DifyNodeFactory"] diff --git a/api/core/app/workflow/file_runtime.py b/api/core/app/workflow/file_runtime.py index 954638b901..e0f8d27111 100644 --- a/api/core/app/workflow/file_runtime.py +++ b/api/core/app/workflow/file_runtime.py @@ -5,13 +5,13 @@ from collections.abc import Generator from configs import dify_config from core.helper.ssrf_proxy import ssrf_proxy from core.tools.signature import sign_tool_file -from core.workflow.file.protocols import HttpResponseProtocol, WorkflowFileRuntimeProtocol -from core.workflow.file.runtime import set_workflow_file_runtime +from dify_graph.file.protocols import HttpResponseProtocol, WorkflowFileRuntimeProtocol +from dify_graph.file.runtime import set_workflow_file_runtime from extensions.ext_storage import storage class DifyWorkflowFileRuntime(WorkflowFileRuntimeProtocol): - """Production runtime wiring for ``core.workflow.file``.""" + """Production runtime wiring for ``dify_graph.file``.""" @property def files_url(self) -> str: diff --git a/api/core/app/workflow/layers/llm_quota.py b/api/core/app/workflow/layers/llm_quota.py index 45fb84c81f..f6c80d25c5 100644 --- a/api/core/app/workflow/layers/llm_quota.py +++ b/api/core/app/workflow/layers/llm_quota.py @@ -12,17 +12,17 @@ from typing_extensions import override from core.app.llm import deduct_llm_quota, ensure_llm_quota_available from core.errors.error import QuotaExceededError from core.model_manager import ModelInstance -from core.workflow.enums import NodeType -from core.workflow.graph_engine.entities.commands import AbortCommand, CommandType -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import GraphEngineEvent, GraphNodeEventBase -from core.workflow.graph_events.node import NodeRunSucceededEvent -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.graph_engine.entities.commands import AbortCommand, CommandType +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import GraphEngineEvent, GraphNodeEventBase +from dify_graph.graph_events.node import NodeRunSucceededEvent +from dify_graph.nodes.base.node import Node if TYPE_CHECKING: - from core.workflow.nodes.llm.node import LLMNode - from core.workflow.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode - from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode + from dify_graph.nodes.llm.node import LLMNode + from dify_graph.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode + from dify_graph.nodes.question_classifier.question_classifier_node import QuestionClassifierNode logger = logging.getLogger(__name__) diff --git a/api/core/app/workflow/layers/observability.py b/api/core/app/workflow/layers/observability.py index 94839c8ae3..ab73db59f1 100644 --- a/api/core/app/workflow/layers/observability.py +++ b/api/core/app/workflow/layers/observability.py @@ -16,10 +16,10 @@ from opentelemetry.trace import Span, SpanKind, Tracer, get_tracer, set_span_in_ from typing_extensions import override from configs import dify_config -from core.workflow.enums import NodeType -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import GraphNodeEventBase -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import GraphNodeEventBase +from dify_graph.nodes.base.node import Node from extensions.otel.parser import ( DefaultNodeOTelParser, LLMNodeOTelParser, diff --git a/api/core/app/workflow/layers/persistence.py b/api/core/app/workflow/layers/persistence.py index 41052b4f52..a30491f30c 100644 --- a/api/core/app/workflow/layers/persistence.py +++ b/api/core/app/workflow/layers/persistence.py @@ -17,17 +17,17 @@ from typing import Any, Union from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities import WorkflowExecution, WorkflowNodeExecution -from core.workflow.enums import ( +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.entities import WorkflowExecution, WorkflowNodeExecution +from dify_graph.enums import ( SystemVariableKey, WorkflowExecutionStatus, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, WorkflowType, ) -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import ( +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunAbortedEvent, GraphRunFailedEvent, @@ -42,9 +42,9 @@ from core.workflow.graph_events import ( NodeRunStartedEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import NodeRunResult -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.node_events import NodeRunResult +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from libs.datetime_utils import naive_utc_now diff --git a/api/core/datasource/datasource_file_manager.py b/api/core/datasource/datasource_file_manager.py index f67bfb6ead..5971c1e013 100644 --- a/api/core/datasource/datasource_file_manager.py +++ b/api/core/datasource/datasource_file_manager.py @@ -213,6 +213,6 @@ class DatasourceFileManager: # init tool_file_parser -# from core.workflow.file.datasource_file_parser import datasource_file_manager +# from dify_graph.file.datasource_file_parser import datasource_file_manager # # datasource_file_manager["manager"] = DatasourceFileManager diff --git a/api/core/datasource/datasource_manager.py b/api/core/datasource/datasource_manager.py index 9c48f755a9..15cd319750 100644 --- a/api/core/datasource/datasource_manager.py +++ b/api/core/datasource/datasource_manager.py @@ -24,12 +24,12 @@ from core.datasource.utils.message_transformer import DatasourceFileMessageTrans from core.datasource.website_crawl.website_crawl_provider import WebsiteCrawlDatasourcePluginProviderController from core.db.session_factory import session_factory from core.plugin.impl.datasource import PluginDatasourceManager -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.enums import WorkflowNodeExecutionMetadataKey -from core.workflow.file import File -from core.workflow.file.enums import FileTransferMethod, FileType -from core.workflow.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent -from core.workflow.repositories.datasource_manager_protocol import DatasourceParameter, OnlineDriveDownloadFileParam +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionMetadataKey +from dify_graph.file import File +from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent +from dify_graph.repositories.datasource_manager_protocol import DatasourceParameter, OnlineDriveDownloadFileParam from factories import file_factory from models.model import UploadFile from models.tools import ToolFile diff --git a/api/core/datasource/utils/message_transformer.py b/api/core/datasource/utils/message_transformer.py index ab3302bd6e..2881888e27 100644 --- a/api/core/datasource/utils/message_transformer.py +++ b/api/core/datasource/utils/message_transformer.py @@ -4,7 +4,7 @@ from mimetypes import guess_extension, guess_type from core.datasource.entities.datasource_entities import DatasourceMessage from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from models.tools import ToolFile logger = logging.getLogger(__name__) diff --git a/api/core/entities/execution_extra_content.py b/api/core/entities/execution_extra_content.py index 46006f4381..1343bd8e82 100644 --- a/api/core/entities/execution_extra_content.py +++ b/api/core/entities/execution_extra_content.py @@ -5,7 +5,7 @@ from typing import Any, TypeAlias from pydantic import BaseModel, ConfigDict, Field -from core.workflow.nodes.human_input.entities import FormInput, UserAction +from dify_graph.nodes.human_input.entities import FormInput, UserAction from models.execution_extra_content import ExecutionContentType diff --git a/api/core/entities/mcp_provider.py b/api/core/entities/mcp_provider.py index 5902c03e27..d214652e9c 100644 --- a/api/core/entities/mcp_provider.py +++ b/api/core/entities/mcp_provider.py @@ -15,7 +15,7 @@ from core.helper.provider_cache import NoOpProviderCredentialCache from core.mcp.types import OAuthClientInformation, OAuthClientMetadata, OAuthTokens from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolProviderType -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers if TYPE_CHECKING: from models.tools import MCPToolProvider diff --git a/api/core/helper/code_executor/code_executor.py b/api/core/helper/code_executor/code_executor.py index d581b3ac39..4251cfd30b 100644 --- a/api/core/helper/code_executor/code_executor.py +++ b/api/core/helper/code_executor/code_executor.py @@ -13,7 +13,7 @@ from core.helper.code_executor.jinja2.jinja2_transformer import Jinja2TemplateTr from core.helper.code_executor.python3.python3_transformer import Python3TemplateTransformer from core.helper.code_executor.template_transformer import TemplateTransformer from core.helper.http_client_pooling import get_pooled_http_client -from core.workflow.nodes.code.entities import CodeLanguage +from dify_graph.nodes.code.entities import CodeLanguage logger = logging.getLogger(__name__) code_execution_endpoint_url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) diff --git a/api/core/helper/code_executor/template_transformer.py b/api/core/helper/code_executor/template_transformer.py index 1b56eaba21..c569e066f4 100644 --- a/api/core/helper/code_executor/template_transformer.py +++ b/api/core/helper/code_executor/template_transformer.py @@ -5,7 +5,7 @@ from base64 import b64encode from collections.abc import Mapping from typing import Any -from core.workflow.variables.utils import dumps_with_segments +from dify_graph.variables.utils import dumps_with_segments class TemplateTransformer(ABC): diff --git a/api/core/llm_generator/llm_generator.py b/api/core/llm_generator/llm_generator.py index 5b2c640265..b16a42e390 100644 --- a/api/core/llm_generator/llm_generator.py +++ b/api/core/llm_generator/llm_generator.py @@ -31,7 +31,7 @@ from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.ops.utils import measure_time from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from extensions.ext_database import db from extensions.ext_storage import storage from models import App, Message, WorkflowNodeExecutionModel diff --git a/api/core/mcp/server/streamable_http.py b/api/core/mcp/server/streamable_http.py index da747d2c1f..de68eb268b 100644 --- a/api/core/mcp/server/streamable_http.py +++ b/api/core/mcp/server/streamable_http.py @@ -7,7 +7,7 @@ from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom from core.app.features.rate_limiting.rate_limit import RateLimitGenerator from core.mcp import types as mcp_types -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models.model import App, AppMCPServer, AppMode, EndUser from services.app_generate_service import AppGenerateService diff --git a/api/core/memory/token_buffer_memory.py b/api/core/memory/token_buffer_memory.py index 2b78a705c9..2e93681da0 100644 --- a/api/core/memory/token_buffer_memory.py +++ b/api/core/memory/token_buffer_memory.py @@ -15,7 +15,7 @@ from core.model_runtime.entities import ( ) from core.model_runtime.entities.message_entities import PromptMessageContentUnionTypes from core.prompt.utils.extract_thread_messages import extract_thread_messages -from core.workflow.file import file_manager +from dify_graph.file import file_manager from extensions.ext_database import db from factories import file_factory from models.model import AppMode, Conversation, Message, MessageFile diff --git a/api/core/ops/aliyun_trace/aliyun_trace.py b/api/core/ops/aliyun_trace/aliyun_trace.py index 46c129099d..19111cc917 100644 --- a/api/core/ops/aliyun_trace/aliyun_trace.py +++ b/api/core/ops/aliyun_trace/aliyun_trace.py @@ -57,8 +57,8 @@ from core.ops.entities.trace_entity import ( WorkflowTraceInfo, ) from core.repositories import DifyCoreRepositoryFactory -from core.workflow.entities import WorkflowNodeExecution -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey +from dify_graph.entities import WorkflowNodeExecution +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey from extensions.ext_database import db from models import WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/aliyun_trace/utils.py b/api/core/ops/aliyun_trace/utils.py index 7f68889e92..45319f24c1 100644 --- a/api/core/ops/aliyun_trace/utils.py +++ b/api/core/ops/aliyun_trace/utils.py @@ -14,8 +14,8 @@ from core.ops.aliyun_trace.entities.semconv import ( GenAISpanKind, ) from core.rag.models.document import Document -from core.workflow.entities import WorkflowNodeExecution -from core.workflow.enums import WorkflowNodeExecutionStatus +from dify_graph.entities import WorkflowNodeExecution +from dify_graph.enums import WorkflowNodeExecutionStatus from extensions.ext_database import db from models import EndUser diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 4de4f403ce..28e800e6c7 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -28,7 +28,7 @@ from core.ops.langfuse_trace.entities.langfuse_trace_entity import ( ) from core.ops.utils import filter_none_values from core.repositories import DifyCoreRepositoryFactory -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from extensions.ext_database import db from models import EndUser, WorkflowNodeExecutionTriggeredFrom from models.enums import MessageStatus diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index 8b8117b24c..b40bc89b71 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -28,7 +28,7 @@ from core.ops.langsmith_trace.entities.langsmith_trace_entity import ( ) from core.ops.utils import filter_none_values, generate_dotted_order from core.repositories import DifyCoreRepositoryFactory -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey from extensions.ext_database import db from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/mlflow_trace/mlflow_trace.py b/api/core/ops/mlflow_trace/mlflow_trace.py index df6e016632..ba2cb9e0c3 100644 --- a/api/core/ops/mlflow_trace/mlflow_trace.py +++ b/api/core/ops/mlflow_trace/mlflow_trace.py @@ -23,7 +23,7 @@ from core.ops.entities.trace_entity import ( TraceTaskName, WorkflowTraceInfo, ) -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from extensions.ext_database import db from models import EndUser from models.workflow import WorkflowNodeExecutionModel diff --git a/api/core/ops/opik_trace/opik_trace.py b/api/core/ops/opik_trace/opik_trace.py index 8050c59db9..eeae489c68 100644 --- a/api/core/ops/opik_trace/opik_trace.py +++ b/api/core/ops/opik_trace/opik_trace.py @@ -22,7 +22,7 @@ from core.ops.entities.trace_entity import ( WorkflowTraceInfo, ) from core.repositories import DifyCoreRepositoryFactory -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey from extensions.ext_database import db from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index 177991e645..33782e7949 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -35,7 +35,7 @@ from models.workflow import WorkflowAppLog from tasks.ops_trace_task import process_trace_tasks if TYPE_CHECKING: - from core.workflow.entities import WorkflowExecution + from dify_graph.entities import WorkflowExecution logger = logging.getLogger(__name__) diff --git a/api/core/ops/tencent_trace/span_builder.py b/api/core/ops/tencent_trace/span_builder.py index 26e8779e3e..0a6013e244 100644 --- a/api/core/ops/tencent_trace/span_builder.py +++ b/api/core/ops/tencent_trace/span_builder.py @@ -41,7 +41,7 @@ from core.ops.tencent_trace.entities.semconv import ( from core.ops.tencent_trace.entities.tencent_trace_entity import SpanData from core.ops.tencent_trace.utils import TencentTraceUtils from core.rag.models.document import Document -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, diff --git a/api/core/ops/tencent_trace/tencent_trace.py b/api/core/ops/tencent_trace/tencent_trace.py index 93ec186863..cbff1c9e1c 100644 --- a/api/core/ops/tencent_trace/tencent_trace.py +++ b/api/core/ops/tencent_trace/tencent_trace.py @@ -24,10 +24,10 @@ from core.ops.tencent_trace.entities.tencent_trace_entity import SpanData from core.ops.tencent_trace.span_builder import TencentSpanBuilder from core.ops.tencent_trace.utils import TencentTraceUtils from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, ) -from core.workflow.nodes import NodeType +from dify_graph.nodes import NodeType from extensions.ext_database import db from models import Account, App, TenantAccountJoin, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index 2134be0bce..7b62207366 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -31,7 +31,7 @@ from core.ops.entities.trace_entity import ( ) from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel from core.repositories import DifyCoreRepositoryFactory -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey from extensions.ext_database import db from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/plugin/backwards_invocation/node.py b/api/core/plugin/backwards_invocation/node.py index 9fbcbf55b4..33c45c0007 100644 --- a/api/core/plugin/backwards_invocation/node.py +++ b/api/core/plugin/backwards_invocation/node.py @@ -1,17 +1,17 @@ from core.plugin.backwards_invocation.base import BaseBackwardsInvocation -from core.workflow.enums import NodeType -from core.workflow.nodes.parameter_extractor.entities import ( +from dify_graph.enums import NodeType +from dify_graph.nodes.parameter_extractor.entities import ( ModelConfig as ParameterExtractorModelConfig, ) -from core.workflow.nodes.parameter_extractor.entities import ( +from dify_graph.nodes.parameter_extractor.entities import ( ParameterConfig, ParameterExtractorNodeData, ) -from core.workflow.nodes.question_classifier.entities import ( +from dify_graph.nodes.question_classifier.entities import ( ClassConfig, QuestionClassifierNodeData, ) -from core.workflow.nodes.question_classifier.entities import ( +from dify_graph.nodes.question_classifier.entities import ( ModelConfig as QuestionClassifierModelConfig, ) from services.workflow_service import WorkflowService diff --git a/api/core/plugin/entities/request.py b/api/core/plugin/entities/request.py index 73d3b8c89c..0a1dc50bfa 100644 --- a/api/core/plugin/entities/request.py +++ b/api/core/plugin/entities/request.py @@ -18,16 +18,16 @@ from core.model_runtime.entities.message_entities import ( ) from core.model_runtime.entities.model_entities import ModelType from core.plugin.utils.http_parser import deserialize_response -from core.workflow.nodes.parameter_extractor.entities import ( +from dify_graph.nodes.parameter_extractor.entities import ( ModelConfig as ParameterExtractorModelConfig, ) -from core.workflow.nodes.parameter_extractor.entities import ( +from dify_graph.nodes.parameter_extractor.entities import ( ParameterConfig, ) -from core.workflow.nodes.question_classifier.entities import ( +from dify_graph.nodes.question_classifier.entities import ( ClassConfig, ) -from core.workflow.nodes.question_classifier.entities import ( +from dify_graph.nodes.question_classifier.entities import ( ModelConfig as QuestionClassifierModelConfig, ) diff --git a/api/core/plugin/utils/converter.py b/api/core/plugin/utils/converter.py index 3fe1b84dfa..53bcd9e9c6 100644 --- a/api/core/plugin/utils/converter.py +++ b/api/core/plugin/utils/converter.py @@ -1,7 +1,7 @@ from typing import Any from core.tools.entities.tool_entities import ToolSelector -from core.workflow.file.models import File +from dify_graph.file.models import File def convert_parameters_to_plugin_format(parameters: dict[str, Any]) -> dict[str, Any]: diff --git a/api/core/prompt/advanced_prompt_transform.py b/api/core/prompt/advanced_prompt_transform.py index 771b6be332..1883538dad 100644 --- a/api/core/prompt/advanced_prompt_transform.py +++ b/api/core/prompt/advanced_prompt_transform.py @@ -17,9 +17,9 @@ from core.model_runtime.entities.message_entities import ImagePromptMessageConte from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig from core.prompt.prompt_transform import PromptTransform from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.file import file_manager -from core.workflow.file.models import File -from core.workflow.runtime import VariablePool +from dify_graph.file import file_manager +from dify_graph.file.models import File +from dify_graph.runtime import VariablePool class AdvancedPromptTransform(PromptTransform): diff --git a/api/core/prompt/simple_prompt_transform.py b/api/core/prompt/simple_prompt_transform.py index 936a093488..53981eb1e1 100644 --- a/api/core/prompt/simple_prompt_transform.py +++ b/api/core/prompt/simple_prompt_transform.py @@ -18,11 +18,11 @@ from core.model_runtime.entities.message_entities import ( from core.prompt.entities.advanced_prompt_entities import MemoryConfig from core.prompt.prompt_transform import PromptTransform from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.file import file_manager +from dify_graph.file import file_manager from models.model import AppMode if TYPE_CHECKING: - from core.workflow.file.models import File + from dify_graph.file.models import File class ModelMode(StrEnum): diff --git a/api/core/rag/index_processor/index_processor.py b/api/core/rag/index_processor/index_processor.py index 95b197c874..c8f9d29012 100644 --- a/api/core/rag/index_processor/index_processor.py +++ b/api/core/rag/index_processor/index_processor.py @@ -9,8 +9,8 @@ from flask import current_app from sqlalchemy import delete, func, select from core.db.session_factory import session_factory -from core.workflow.nodes.knowledge_index.exc import KnowledgeIndexNodeError -from core.workflow.repositories.index_processor_protocol import Preview, PreviewItem, QaPreview +from dify_graph.nodes.knowledge_index.exc import KnowledgeIndexNodeError +from dify_graph.repositories.index_processor_protocol import Preview, PreviewItem, QaPreview from models.dataset import Dataset, Document, DocumentSegment from .index_processor_factory import IndexProcessorFactory diff --git a/api/core/rag/index_processor/processor/paragraph_index_processor.py b/api/core/rag/index_processor/processor/paragraph_index_processor.py index df5c89a522..79265cf3ed 100644 --- a/api/core/rag/index_processor/processor/paragraph_index_processor.py +++ b/api/core/rag/index_processor/processor/paragraph_index_processor.py @@ -35,7 +35,7 @@ from core.rag.index_processor.index_processor_base import BaseIndexProcessor from core.rag.models.document import AttachmentDocument, Document, MultimodalGeneralStructureChunk from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.tools.utils.text_processing_utils import remove_leading_symbols -from core.workflow.file import File, FileTransferMethod, FileType, file_manager +from dify_graph.file import File, FileTransferMethod, FileType, file_manager from extensions.ext_database import db from factories.file_factory import build_from_mapping from libs import helper diff --git a/api/core/rag/models/document.py b/api/core/rag/models/document.py index 48639bf4c8..dc3b771406 100644 --- a/api/core/rag/models/document.py +++ b/api/core/rag/models/document.py @@ -4,7 +4,7 @@ from typing import Any from pydantic import BaseModel, Field -from core.workflow.file import File +from dify_graph.file import File class ChildDocument(BaseModel): diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index 459d7bed95..151dfe81b3 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -60,9 +60,9 @@ from core.rag.retrieval.template_prompts import ( ) from core.tools.signature import sign_upload_file from core.tools.utils.dataset_retriever.dataset_retriever_base_tool import DatasetRetrieverBaseTool -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.nodes.knowledge_retrieval import exc -from core.workflow.repositories.rag_retrieval_protocol import ( +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.nodes.knowledge_retrieval import exc +from dify_graph.repositories.rag_retrieval_protocol import ( KnowledgeRetrievalRequest, Source, SourceChildChunk, diff --git a/api/core/repositories/celery_workflow_execution_repository.py b/api/core/repositories/celery_workflow_execution_repository.py index c7f5942f5f..57764574d7 100644 --- a/api/core/repositories/celery_workflow_execution_repository.py +++ b/api/core/repositories/celery_workflow_execution_repository.py @@ -11,8 +11,8 @@ from typing import Union from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker -from core.workflow.entities.workflow_execution import WorkflowExecution -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.entities.workflow_execution import WorkflowExecution +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository from libs.helper import extract_tenant_id from models import Account, CreatorUserRole, EndUser from models.enums import WorkflowRunTriggeredFrom diff --git a/api/core/repositories/celery_workflow_node_execution_repository.py b/api/core/repositories/celery_workflow_node_execution_repository.py index 9b8e45b1eb..650cf79550 100644 --- a/api/core/repositories/celery_workflow_node_execution_repository.py +++ b/api/core/repositories/celery_workflow_node_execution_repository.py @@ -12,8 +12,8 @@ from typing import Union from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution -from core.workflow.repositories.workflow_node_execution_repository import ( +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecution +from dify_graph.repositories.workflow_node_execution_repository import ( OrderConfig, WorkflowNodeExecutionRepository, ) diff --git a/api/core/repositories/factory.py b/api/core/repositories/factory.py index 02fcabab5d..dc9f8c96bf 100644 --- a/api/core/repositories/factory.py +++ b/api/core/repositories/factory.py @@ -11,8 +11,8 @@ from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker from configs import dify_config -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from libs.module_loading import import_string from models import Account, EndUser from models.enums import WorkflowRunTriggeredFrom diff --git a/api/core/repositories/human_input_repository.py b/api/core/repositories/human_input_repository.py index 0e04c56e0e..bd9afe36f0 100644 --- a/api/core/repositories/human_input_repository.py +++ b/api/core/repositories/human_input_repository.py @@ -7,7 +7,7 @@ from typing import Any from sqlalchemy import Engine, select from sqlalchemy.orm import Session, selectinload, sessionmaker -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( DeliveryChannelConfig, EmailDeliveryMethod, EmailRecipients, @@ -17,12 +17,12 @@ from core.workflow.nodes.human_input.entities import ( MemberRecipient, WebAppDeliveryMethod, ) -from core.workflow.nodes.human_input.enums import ( +from dify_graph.nodes.human_input.enums import ( DeliveryMethodType, HumanInputFormKind, HumanInputFormStatus, ) -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, FormNotFoundError, HumanInputFormEntity, diff --git a/api/core/repositories/sqlalchemy_workflow_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_execution_repository.py index 9091a3190b..649e2f7358 100644 --- a/api/core/repositories/sqlalchemy_workflow_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_execution_repository.py @@ -9,10 +9,10 @@ from typing import Union from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker -from core.workflow.entities import WorkflowExecution -from core.workflow.enums import WorkflowExecutionStatus, WorkflowType -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities import WorkflowExecution +from dify_graph.enums import WorkflowExecutionStatus, WorkflowType +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from libs.helper import extract_tenant_id from models import ( Account, diff --git a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py index 324dd059d1..85ee9b5083 100644 --- a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py @@ -18,10 +18,10 @@ from tenacity import before_sleep_log, retry, retry_if_exception, stop_after_att from configs import dify_config from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.entities import WorkflowNodeExecution -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities import WorkflowNodeExecution +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.ext_storage import storage from libs.helper import extract_tenant_id from libs.uuid_utils import uuidv7 diff --git a/api/core/tools/builtin_tool/providers/audio/tools/asr.py b/api/core/tools/builtin_tool/providers/audio/tools/asr.py index 2c1e9fb555..b0552fd863 100644 --- a/api/core/tools/builtin_tool/providers/audio/tools/asr.py +++ b/api/core/tools/builtin_tool/providers/audio/tools/asr.py @@ -8,8 +8,8 @@ from core.plugin.entities.parameters import PluginParameterOption from core.tools.builtin_tool.tool import BuiltinTool from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter -from core.workflow.file.enums import FileType -from core.workflow.file.file_manager import download +from dify_graph.file.enums import FileType +from dify_graph.file.file_manager import download from services.model_provider_service import ModelProviderService diff --git a/api/core/tools/custom_tool/tool.py b/api/core/tools/custom_tool/tool.py index afa2ddffed..c6a84e27c6 100644 --- a/api/core/tools/custom_tool/tool.py +++ b/api/core/tools/custom_tool/tool.py @@ -13,7 +13,7 @@ from core.tools.__base.tool_runtime import ToolRuntime from core.tools.entities.tool_bundle import ApiToolBundle from core.tools.entities.tool_entities import ToolEntity, ToolInvokeMessage, ToolProviderType from core.tools.errors import ToolInvokeError, ToolParameterValidationError, ToolProviderCredentialValidationError -from core.workflow.file.file_manager import download +from dify_graph.file.file_manager import download API_TOOL_DEFAULT_TIMEOUT = ( int(getenv("API_TOOL_DEFAULT_CONNECT_TIMEOUT", "10")), diff --git a/api/core/tools/tool_engine.py b/api/core/tools/tool_engine.py index de476f6461..0f0eacbdc4 100644 --- a/api/core/tools/tool_engine.py +++ b/api/core/tools/tool_engine.py @@ -31,8 +31,8 @@ from core.tools.errors import ( ) from core.tools.utils.message_transformer import ToolFileMessageTransformer, safe_json_value from core.tools.workflow_as_tool.tool import WorkflowTool -from core.workflow.file import FileType -from core.workflow.file.models import FileTransferMethod +from dify_graph.file import FileType +from dify_graph.file.models import FileTransferMethod from extensions.ext_database import db from models.enums import CreatorUserRole from models.model import Message, MessageFile diff --git a/api/core/tools/tool_file_manager.py b/api/core/tools/tool_file_manager.py index ca0dc27f3d..83e4e53418 100644 --- a/api/core/tools/tool_file_manager.py +++ b/api/core/tools/tool_file_manager.py @@ -243,7 +243,7 @@ class ToolFileManager: # init tool_file_parser -from core.workflow.file.tool_file_parser import set_tool_file_manager_factory +from dify_graph.file.tool_file_parser import set_tool_file_manager_factory def _factory() -> ToolFileManager: diff --git a/api/core/tools/tool_manager.py b/api/core/tools/tool_manager.py index d561d39923..1bb9960e62 100644 --- a/api/core/tools/tool_manager.py +++ b/api/core/tools/tool_manager.py @@ -24,14 +24,14 @@ from core.tools.plugin_tool.provider import PluginToolProviderController from core.tools.plugin_tool.tool import PluginTool from core.tools.utils.uuid_utils import is_valid_uuid from core.tools.workflow_as_tool.provider import WorkflowToolProviderController -from core.workflow.runtime.variable_pool import VariablePool +from dify_graph.runtime.variable_pool import VariablePool from extensions.ext_database import db from models.provider_ids import ToolProviderID from services.enterprise.plugin_manager_service import PluginCredentialType from services.tools.mcp_tools_manage_service import MCPToolManageService if TYPE_CHECKING: - from core.workflow.nodes.tool.entities import ToolEntity + from dify_graph.nodes.tool.entities import ToolEntity from core.agent.entities import AgentToolEntity from core.app.entities.app_invoke_entities import InvokeFrom @@ -62,7 +62,7 @@ from models.tools import ApiToolProvider, BuiltinToolProvider, WorkflowToolProvi from services.tools.tools_transform_service import ToolTransformService if TYPE_CHECKING: - from core.workflow.nodes.tool.entities import ToolEntity + from dify_graph.nodes.tool.entities import ToolEntity logger = logging.getLogger(__name__) @@ -1017,8 +1017,8 @@ class ToolManager: """ Convert tool parameters type """ - from core.workflow.nodes.tool.entities import ToolNodeData - from core.workflow.nodes.tool.exc import ToolParameterError + from dify_graph.nodes.tool.entities import ToolNodeData + from dify_graph.nodes.tool.exc import ToolParameterError runtime_parameters = {} for parameter in parameters: diff --git a/api/core/tools/utils/message_transformer.py b/api/core/tools/utils/message_transformer.py index 622cdcf73b..6fc5fead2d 100644 --- a/api/core/tools/utils/message_transformer.py +++ b/api/core/tools/utils/message_transformer.py @@ -10,7 +10,7 @@ import pytz from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from libs.login import current_user from models import Account diff --git a/api/core/tools/utils/workflow_configuration_sync.py b/api/core/tools/utils/workflow_configuration_sync.py index 8e8c5e9c6a..d8ce53083b 100644 --- a/api/core/tools/utils/workflow_configuration_sync.py +++ b/api/core/tools/utils/workflow_configuration_sync.py @@ -3,9 +3,9 @@ from typing import Any from core.tools.entities.tool_entities import WorkflowToolParameterConfiguration from core.tools.errors import WorkflowToolHumanInputNotSupportedError -from core.workflow.enums import NodeType -from core.workflow.nodes.base.entities import OutputVariableEntity -from core.workflow.variables.input_entities import VariableEntity +from dify_graph.enums import NodeType +from dify_graph.nodes.base.entities import OutputVariableEntity +from dify_graph.variables.input_entities import VariableEntity class WorkflowToolConfigurationUtils: diff --git a/api/core/tools/workflow_as_tool/provider.py b/api/core/tools/workflow_as_tool/provider.py index 56faccb407..d73012375d 100644 --- a/api/core/tools/workflow_as_tool/provider.py +++ b/api/core/tools/workflow_as_tool/provider.py @@ -22,7 +22,7 @@ from core.tools.entities.tool_entities import ( ) from core.tools.utils.workflow_configuration_sync import WorkflowToolConfigurationUtils from core.tools.workflow_as_tool.tool import WorkflowTool -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from extensions.ext_database import db from models.account import Account from models.model import App, AppMode diff --git a/api/core/tools/workflow_as_tool/tool.py b/api/core/tools/workflow_as_tool/tool.py index b2606009a6..6b1b48505b 100644 --- a/api/core/tools/workflow_as_tool/tool.py +++ b/api/core/tools/workflow_as_tool/tool.py @@ -18,7 +18,7 @@ from core.tools.entities.tool_entities import ( ToolProviderType, ) from core.tools.errors import ToolInvokeError -from core.workflow.file import FILE_MODEL_IDENTITY, File, FileTransferMethod +from dify_graph.file import FILE_MODEL_IDENTITY, File, FileTransferMethod from factories.file_factory import build_from_mapping from models import Account, Tenant from models.model import App, EndUser diff --git a/api/core/trigger/debug/event_selectors.py b/api/core/trigger/debug/event_selectors.py index bd1ff4ebfe..9b7b3de614 100644 --- a/api/core/trigger/debug/event_selectors.py +++ b/api/core/trigger/debug/event_selectors.py @@ -19,9 +19,9 @@ from core.trigger.debug.events import ( build_plugin_pool_key, build_webhook_pool_key, ) -from core.workflow.enums import NodeType -from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData -from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig +from dify_graph.enums import NodeType +from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData +from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig from extensions.ext_redis import redis_client from libs.datetime_utils import ensure_naive_utc, naive_utc_now from libs.schedule_utils import calculate_next_run_at diff --git a/api/core/workflow/__init__.py b/api/core/workflow/__init__.py index e69de29bb2..57c2ef3d10 100644 --- a/api/core/workflow/__init__.py +++ b/api/core/workflow/__init__.py @@ -0,0 +1,4 @@ +from .node_factory import DifyNodeFactory +from .workflow_entry import WorkflowEntry + +__all__ = ["DifyNodeFactory", "WorkflowEntry"] diff --git a/api/core/app/workflow/node_factory.py b/api/core/workflow/node_factory.py similarity index 88% rename from api/core/app/workflow/node_factory.py rename to api/core/workflow/node_factory.py index 9a56f0fb0d..522e510755 100644 --- a/api/core/app/workflow/node_factory.py +++ b/api/core/workflow/node_factory.py @@ -23,36 +23,36 @@ from core.rag.index_processor.index_processor import IndexProcessor from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from core.rag.summary_index.summary_index import SummaryIndex from core.tools.tool_file_manager import ToolFileManager -from core.workflow.entities.graph_config import NodeConfigDict -from core.workflow.enums import NodeType, SystemVariableKey -from core.workflow.file.file_manager import file_manager -from core.workflow.graph.graph import NodeFactory -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.code.code_node import CodeNode, WorkflowCodeExecutor -from core.workflow.nodes.code.entities import CodeLanguage -from core.workflow.nodes.code.limits import CodeNodeLimits -from core.workflow.nodes.datasource import DatasourceNode -from core.workflow.nodes.document_extractor import DocumentExtractorNode, UnstructuredApiConfig -from core.workflow.nodes.http_request import HttpRequestNode, build_http_request_config -from core.workflow.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode -from core.workflow.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode -from core.workflow.nodes.llm.entities import ModelConfig -from core.workflow.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError -from core.workflow.nodes.llm.node import LLMNode -from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING -from core.workflow.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode -from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode -from core.workflow.nodes.template_transform.template_renderer import ( +from dify_graph.entities.graph_config import NodeConfigDict +from dify_graph.enums import NodeType, SystemVariableKey +from dify_graph.file.file_manager import file_manager +from dify_graph.graph.graph import NodeFactory +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.code.code_node import CodeNode, WorkflowCodeExecutor +from dify_graph.nodes.code.entities import CodeLanguage +from dify_graph.nodes.code.limits import CodeNodeLimits +from dify_graph.nodes.datasource import DatasourceNode +from dify_graph.nodes.document_extractor import DocumentExtractorNode, UnstructuredApiConfig +from dify_graph.nodes.http_request import HttpRequestNode, build_http_request_config +from dify_graph.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode +from dify_graph.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode +from dify_graph.nodes.llm.entities import ModelConfig +from dify_graph.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError +from dify_graph.nodes.llm.node import LLMNode +from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING +from dify_graph.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode +from dify_graph.nodes.question_classifier.question_classifier_node import QuestionClassifierNode +from dify_graph.nodes.template_transform.template_renderer import ( CodeExecutorJinja2TemplateRenderer, ) -from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode -from core.workflow.variables.segments import StringSegment +from dify_graph.nodes.template_transform.template_transform_node import TemplateTransformNode +from dify_graph.variables.segments import StringSegment from extensions.ext_database import db from models.model import Conversation if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState def fetch_memory( diff --git a/api/core/workflow/nodes/__init__.py b/api/core/workflow/nodes/__init__.py deleted file mode 100644 index 82a37acbfa..0000000000 --- a/api/core/workflow/nodes/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from core.workflow.enums import NodeType - -__all__ = ["NodeType"] diff --git a/api/core/workflow/nodes/trigger_schedule/__init__.py b/api/core/workflow/nodes/trigger_schedule/__init__.py deleted file mode 100644 index 6773bae502..0000000000 --- a/api/core/workflow/nodes/trigger_schedule/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from core.workflow.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode - -__all__ = ["TriggerScheduleNode"] diff --git a/api/core/workflow/workflow_entry.py b/api/core/workflow/workflow_entry.py index 2ea4266b16..37e7b5fabe 100644 --- a/api/core/workflow/workflow_entry.py +++ b/api/core/workflow/workflow_entry.py @@ -8,24 +8,24 @@ from core.app.apps.exc import GenerateTaskStoppedError from core.app.entities.app_invoke_entities import InvokeFrom from core.app.workflow.layers.llm_quota import LLMQuotaLayer from core.app.workflow.layers.observability import ObservabilityLayer -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.constants import ENVIRONMENT_VARIABLE_NODE_ID -from core.workflow.entities import GraphInitParams -from core.workflow.entities.graph_config import NodeConfigData, NodeConfigDict -from core.workflow.errors import WorkflowNodeRunFailedError -from core.workflow.file.models import File -from core.workflow.graph import Graph -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_engine.layers import DebugLoggingLayer, ExecutionLimitsLayer -from core.workflow.graph_engine.protocols.command_channel import CommandChannel -from core.workflow.graph_events import GraphEngineEvent, GraphNodeEventBase, GraphRunFailedEvent -from core.workflow.nodes import NodeType -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.constants import ENVIRONMENT_VARIABLE_NODE_ID +from dify_graph.entities import GraphInitParams +from dify_graph.entities.graph_config import NodeConfigData, NodeConfigDict +from dify_graph.errors import WorkflowNodeRunFailedError +from dify_graph.file.models import File +from dify_graph.graph import Graph +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_engine.layers import DebugLoggingLayer, ExecutionLimitsLayer +from dify_graph.graph_engine.protocols.command_channel import CommandChannel +from dify_graph.graph_events import GraphEngineEvent, GraphNodeEventBase, GraphRunFailedEvent +from dify_graph.nodes import NodeType +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import DUMMY_VARIABLE_LOADER, VariableLoader, load_into_variable_pool from extensions.otel.runtime import is_instrument_flag_enabled from factories import file_factory from models.enums import UserFrom diff --git a/api/core/workflow/README.md b/api/dify_graph/README.md similarity index 98% rename from api/core/workflow/README.md rename to api/dify_graph/README.md index 9a39f976a6..09c4f5afdc 100644 --- a/api/core/workflow/README.md +++ b/api/dify_graph/README.md @@ -114,7 +114,7 @@ The codebase enforces strict layering via import-linter: 1. Inherit from `BaseNode` or appropriate base class 1. Implement `_run()` method 1. Register in `nodes/node_mapping.py` -1. Add tests in `tests/unit_tests/core/workflow/nodes/` +1. Add tests in `tests/unit_tests/dify_graph/nodes/` ### Implementing a Custom Layer diff --git a/api/core/workflow/graph_engine/entities/__init__.py b/api/dify_graph/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/entities/__init__.py rename to api/dify_graph/__init__.py diff --git a/api/core/workflow/constants.py b/api/dify_graph/constants.py similarity index 100% rename from api/core/workflow/constants.py rename to api/dify_graph/constants.py diff --git a/api/core/workflow/context/__init__.py b/api/dify_graph/context/__init__.py similarity index 86% rename from api/core/workflow/context/__init__.py rename to api/dify_graph/context/__init__.py index 1237d6a017..103f526bec 100644 --- a/api/core/workflow/context/__init__.py +++ b/api/dify_graph/context/__init__.py @@ -5,7 +5,7 @@ This package provides Flask-independent context management for workflow execution in multi-threaded environments. """ -from core.workflow.context.execution_context import ( +from dify_graph.context.execution_context import ( AppContext, ContextProviderNotFoundError, ExecutionContext, @@ -17,7 +17,7 @@ from core.workflow.context.execution_context import ( register_context_capturer, reset_context_provider, ) -from core.workflow.context.models import SandboxContext +from dify_graph.context.models import SandboxContext __all__ = [ "AppContext", diff --git a/api/core/workflow/context/execution_context.py b/api/dify_graph/context/execution_context.py similarity index 100% rename from api/core/workflow/context/execution_context.py rename to api/dify_graph/context/execution_context.py diff --git a/api/core/workflow/context/models.py b/api/dify_graph/context/models.py similarity index 100% rename from api/core/workflow/context/models.py rename to api/dify_graph/context/models.py diff --git a/api/core/workflow/conversation_variable_updater.py b/api/dify_graph/conversation_variable_updater.py similarity index 96% rename from api/core/workflow/conversation_variable_updater.py rename to api/dify_graph/conversation_variable_updater.py index 6bfb2b2880..17b19f2502 100644 --- a/api/core/workflow/conversation_variable_updater.py +++ b/api/dify_graph/conversation_variable_updater.py @@ -1,7 +1,7 @@ import abc from typing import Protocol -from core.workflow.variables import VariableBase +from dify_graph.variables import VariableBase class ConversationVariableUpdater(Protocol): diff --git a/api/core/workflow/entities/__init__.py b/api/dify_graph/entities/__init__.py similarity index 100% rename from api/core/workflow/entities/__init__.py rename to api/dify_graph/entities/__init__.py diff --git a/api/core/workflow/entities/agent.py b/api/dify_graph/entities/agent.py similarity index 100% rename from api/core/workflow/entities/agent.py rename to api/dify_graph/entities/agent.py diff --git a/api/core/workflow/entities/graph_config.py b/api/dify_graph/entities/graph_config.py similarity index 100% rename from api/core/workflow/entities/graph_config.py rename to api/dify_graph/entities/graph_config.py diff --git a/api/core/workflow/entities/graph_init_params.py b/api/dify_graph/entities/graph_init_params.py similarity index 100% rename from api/core/workflow/entities/graph_init_params.py rename to api/dify_graph/entities/graph_init_params.py diff --git a/api/core/workflow/entities/pause_reason.py b/api/dify_graph/entities/pause_reason.py similarity index 96% rename from api/core/workflow/entities/pause_reason.py rename to api/dify_graph/entities/pause_reason.py index 147f56e8be..86d8c8ca16 100644 --- a/api/core/workflow/entities/pause_reason.py +++ b/api/dify_graph/entities/pause_reason.py @@ -4,7 +4,7 @@ from typing import Annotated, Any, Literal, TypeAlias from pydantic import BaseModel, Field -from core.workflow.nodes.human_input.entities import FormInput, UserAction +from dify_graph.nodes.human_input.entities import FormInput, UserAction class PauseReasonType(StrEnum): diff --git a/api/core/workflow/entities/workflow_execution.py b/api/dify_graph/entities/workflow_execution.py similarity index 96% rename from api/core/workflow/entities/workflow_execution.py rename to api/dify_graph/entities/workflow_execution.py index 1b3fb36f1f..459ac46415 100644 --- a/api/core/workflow/entities/workflow_execution.py +++ b/api/dify_graph/entities/workflow_execution.py @@ -13,7 +13,7 @@ from typing import Any from pydantic import BaseModel, Field -from core.workflow.enums import WorkflowExecutionStatus, WorkflowType +from dify_graph.enums import WorkflowExecutionStatus, WorkflowType from libs.datetime_utils import naive_utc_now diff --git a/api/core/workflow/entities/workflow_node_execution.py b/api/dify_graph/entities/workflow_node_execution.py similarity index 98% rename from api/core/workflow/entities/workflow_node_execution.py rename to api/dify_graph/entities/workflow_node_execution.py index 4abc9c068d..9dd04e331b 100644 --- a/api/core/workflow/entities/workflow_node_execution.py +++ b/api/dify_graph/entities/workflow_node_execution.py @@ -12,7 +12,7 @@ from typing import Any from pydantic import BaseModel, Field, PrivateAttr -from core.workflow.enums import NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus class WorkflowNodeExecution(BaseModel): diff --git a/api/core/workflow/entities/workflow_start_reason.py b/api/dify_graph/entities/workflow_start_reason.py similarity index 100% rename from api/core/workflow/entities/workflow_start_reason.py rename to api/dify_graph/entities/workflow_start_reason.py diff --git a/api/core/workflow/enums.py b/api/dify_graph/enums.py similarity index 100% rename from api/core/workflow/enums.py rename to api/dify_graph/enums.py diff --git a/api/core/workflow/errors.py b/api/dify_graph/errors.py similarity index 88% rename from api/core/workflow/errors.py rename to api/dify_graph/errors.py index 5bf1faee5d..463d17713e 100644 --- a/api/core/workflow/errors.py +++ b/api/dify_graph/errors.py @@ -1,4 +1,4 @@ -from core.workflow.nodes.base.node import Node +from dify_graph.nodes.base.node import Node class WorkflowNodeRunFailedError(Exception): diff --git a/api/core/workflow/file/__init__.py b/api/dify_graph/file/__init__.py similarity index 100% rename from api/core/workflow/file/__init__.py rename to api/dify_graph/file/__init__.py diff --git a/api/core/workflow/file/constants.py b/api/dify_graph/file/constants.py similarity index 100% rename from api/core/workflow/file/constants.py rename to api/dify_graph/file/constants.py diff --git a/api/core/workflow/file/enums.py b/api/dify_graph/file/enums.py similarity index 100% rename from api/core/workflow/file/enums.py rename to api/dify_graph/file/enums.py diff --git a/api/core/workflow/file/file_manager.py b/api/dify_graph/file/file_manager.py similarity index 100% rename from api/core/workflow/file/file_manager.py rename to api/dify_graph/file/file_manager.py diff --git a/api/core/workflow/file/helpers.py b/api/dify_graph/file/helpers.py similarity index 100% rename from api/core/workflow/file/helpers.py rename to api/dify_graph/file/helpers.py diff --git a/api/core/workflow/file/models.py b/api/dify_graph/file/models.py similarity index 100% rename from api/core/workflow/file/models.py rename to api/dify_graph/file/models.py diff --git a/api/core/workflow/file/protocols.py b/api/dify_graph/file/protocols.py similarity index 94% rename from api/core/workflow/file/protocols.py rename to api/dify_graph/file/protocols.py index 8d923148e0..24cbb42735 100644 --- a/api/core/workflow/file/protocols.py +++ b/api/dify_graph/file/protocols.py @@ -14,7 +14,7 @@ class HttpResponseProtocol(Protocol): class WorkflowFileRuntimeProtocol(Protocol): - """Runtime dependencies required by ``core.workflow.file``. + """Runtime dependencies required by ``dify_graph.file``. Implementations are expected to be provided by integration layers (for example, ``core.app.workflow.file_runtime``) so the workflow package avoids importing diff --git a/api/core/workflow/file/runtime.py b/api/dify_graph/file/runtime.py similarity index 100% rename from api/core/workflow/file/runtime.py rename to api/dify_graph/file/runtime.py diff --git a/api/core/workflow/file/tool_file_parser.py b/api/dify_graph/file/tool_file_parser.py similarity index 100% rename from api/core/workflow/file/tool_file_parser.py rename to api/dify_graph/file/tool_file_parser.py diff --git a/api/core/workflow/graph/__init__.py b/api/dify_graph/graph/__init__.py similarity index 100% rename from api/core/workflow/graph/__init__.py rename to api/dify_graph/graph/__init__.py diff --git a/api/core/workflow/graph/edge.py b/api/dify_graph/graph/edge.py similarity index 91% rename from api/core/workflow/graph/edge.py rename to api/dify_graph/graph/edge.py index 1d57747dbb..f4f67ea6be 100644 --- a/api/core/workflow/graph/edge.py +++ b/api/dify_graph/graph/edge.py @@ -1,7 +1,7 @@ import uuid from dataclasses import dataclass, field -from core.workflow.enums import NodeState +from dify_graph.enums import NodeState @dataclass diff --git a/api/core/workflow/graph/graph.py b/api/dify_graph/graph/graph.py similarity index 98% rename from api/core/workflow/graph/graph.py rename to api/dify_graph/graph/graph.py index 52bbbb20cc..3fe94eb3fd 100644 --- a/api/core/workflow/graph/graph.py +++ b/api/dify_graph/graph/graph.py @@ -7,9 +7,9 @@ from typing import Protocol, cast, final from pydantic import TypeAdapter -from core.workflow.entities.graph_config import NodeConfigDict -from core.workflow.enums import ErrorStrategy, NodeExecutionType, NodeState, NodeType -from core.workflow.nodes.base.node import Node +from dify_graph.entities.graph_config import NodeConfigDict +from dify_graph.enums import ErrorStrategy, NodeExecutionType, NodeState, NodeType +from dify_graph.nodes.base.node import Node from libs.typing import is_str from .edge import Edge diff --git a/api/core/workflow/graph/graph_template.py b/api/dify_graph/graph/graph_template.py similarity index 100% rename from api/core/workflow/graph/graph_template.py rename to api/dify_graph/graph/graph_template.py diff --git a/api/core/workflow/graph/validation.py b/api/dify_graph/graph/validation.py similarity index 98% rename from api/core/workflow/graph/validation.py rename to api/dify_graph/graph/validation.py index 41b4fdfa60..6840bcfed2 100644 --- a/api/core/workflow/graph/validation.py +++ b/api/dify_graph/graph/validation.py @@ -4,7 +4,7 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import TYPE_CHECKING, Protocol -from core.workflow.enums import NodeExecutionType, NodeType +from dify_graph.enums import NodeExecutionType, NodeType if TYPE_CHECKING: from .graph import Graph diff --git a/api/core/workflow/graph_engine/__init__.py b/api/dify_graph/graph_engine/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/__init__.py rename to api/dify_graph/graph_engine/__init__.py diff --git a/api/core/workflow/graph_engine/_engine_utils.py b/api/dify_graph/graph_engine/_engine_utils.py similarity index 100% rename from api/core/workflow/graph_engine/_engine_utils.py rename to api/dify_graph/graph_engine/_engine_utils.py diff --git a/api/core/workflow/graph_engine/command_channels/README.md b/api/dify_graph/graph_engine/command_channels/README.md similarity index 100% rename from api/core/workflow/graph_engine/command_channels/README.md rename to api/dify_graph/graph_engine/command_channels/README.md diff --git a/api/core/workflow/graph_engine/command_channels/__init__.py b/api/dify_graph/graph_engine/command_channels/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/command_channels/__init__.py rename to api/dify_graph/graph_engine/command_channels/__init__.py diff --git a/api/core/workflow/graph_engine/command_channels/in_memory_channel.py b/api/dify_graph/graph_engine/command_channels/in_memory_channel.py similarity index 100% rename from api/core/workflow/graph_engine/command_channels/in_memory_channel.py rename to api/dify_graph/graph_engine/command_channels/in_memory_channel.py diff --git a/api/core/workflow/graph_engine/command_channels/redis_channel.py b/api/dify_graph/graph_engine/command_channels/redis_channel.py similarity index 100% rename from api/core/workflow/graph_engine/command_channels/redis_channel.py rename to api/dify_graph/graph_engine/command_channels/redis_channel.py diff --git a/api/core/workflow/graph_engine/command_processing/__init__.py b/api/dify_graph/graph_engine/command_processing/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/command_processing/__init__.py rename to api/dify_graph/graph_engine/command_processing/__init__.py diff --git a/api/core/workflow/graph_engine/command_processing/command_handlers.py b/api/dify_graph/graph_engine/command_processing/command_handlers.py similarity index 94% rename from api/core/workflow/graph_engine/command_processing/command_handlers.py rename to api/dify_graph/graph_engine/command_processing/command_handlers.py index cfe856d9e8..eefd0c366b 100644 --- a/api/core/workflow/graph_engine/command_processing/command_handlers.py +++ b/api/dify_graph/graph_engine/command_processing/command_handlers.py @@ -3,8 +3,8 @@ from typing import final from typing_extensions import override -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.runtime import VariablePool +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.runtime import VariablePool from ..domain.graph_execution import GraphExecution from ..entities.commands import AbortCommand, GraphEngineCommand, PauseCommand, UpdateVariablesCommand diff --git a/api/core/workflow/graph_engine/command_processing/command_processor.py b/api/dify_graph/graph_engine/command_processing/command_processor.py similarity index 100% rename from api/core/workflow/graph_engine/command_processing/command_processor.py rename to api/dify_graph/graph_engine/command_processing/command_processor.py diff --git a/api/core/workflow/graph_engine/config.py b/api/dify_graph/graph_engine/config.py similarity index 100% rename from api/core/workflow/graph_engine/config.py rename to api/dify_graph/graph_engine/config.py diff --git a/api/core/workflow/graph_engine/domain/__init__.py b/api/dify_graph/graph_engine/domain/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/domain/__init__.py rename to api/dify_graph/graph_engine/domain/__init__.py diff --git a/api/core/workflow/graph_engine/domain/graph_execution.py b/api/dify_graph/graph_engine/domain/graph_execution.py similarity index 97% rename from api/core/workflow/graph_engine/domain/graph_execution.py rename to api/dify_graph/graph_engine/domain/graph_execution.py index 3ba6e5e37c..0ee4a9f9a7 100644 --- a/api/core/workflow/graph_engine/domain/graph_execution.py +++ b/api/dify_graph/graph_engine/domain/graph_execution.py @@ -8,9 +8,9 @@ from typing import Literal from pydantic import BaseModel, Field -from core.workflow.entities.pause_reason import PauseReason -from core.workflow.enums import NodeState -from core.workflow.runtime.graph_runtime_state import GraphExecutionProtocol +from dify_graph.entities.pause_reason import PauseReason +from dify_graph.enums import NodeState +from dify_graph.runtime.graph_runtime_state import GraphExecutionProtocol from .node_execution import NodeExecution diff --git a/api/core/workflow/graph_engine/domain/node_execution.py b/api/dify_graph/graph_engine/domain/node_execution.py similarity index 96% rename from api/core/workflow/graph_engine/domain/node_execution.py rename to api/dify_graph/graph_engine/domain/node_execution.py index 85700caa3a..ae8f9a5e50 100644 --- a/api/core/workflow/graph_engine/domain/node_execution.py +++ b/api/dify_graph/graph_engine/domain/node_execution.py @@ -4,7 +4,7 @@ NodeExecution entity representing a node's execution state. from dataclasses import dataclass -from core.workflow.enums import NodeState +from dify_graph.enums import NodeState @dataclass diff --git a/api/core/workflow/nodes/answer/__init__.py b/api/dify_graph/graph_engine/entities/__init__.py similarity index 100% rename from api/core/workflow/nodes/answer/__init__.py rename to api/dify_graph/graph_engine/entities/__init__.py diff --git a/api/core/workflow/graph_engine/entities/commands.py b/api/dify_graph/graph_engine/entities/commands.py similarity index 96% rename from api/core/workflow/graph_engine/entities/commands.py rename to api/dify_graph/graph_engine/entities/commands.py index 7e7b65247b..c56845cfc4 100644 --- a/api/core/workflow/graph_engine/entities/commands.py +++ b/api/dify_graph/graph_engine/entities/commands.py @@ -11,7 +11,7 @@ from typing import Any from pydantic import BaseModel, Field -from core.workflow.variables.variables import Variable +from dify_graph.variables.variables import Variable class CommandType(StrEnum): diff --git a/api/core/workflow/graph_engine/error_handler.py b/api/dify_graph/graph_engine/error_handler.py similarity index 97% rename from api/core/workflow/graph_engine/error_handler.py rename to api/dify_graph/graph_engine/error_handler.py index 62e144c12a..d4ee2922ec 100644 --- a/api/core/workflow/graph_engine/error_handler.py +++ b/api/dify_graph/graph_engine/error_handler.py @@ -6,21 +6,21 @@ import logging import time from typing import TYPE_CHECKING, final -from core.workflow.enums import ( +from dify_graph.enums import ( ErrorStrategy as ErrorStrategyEnum, ) -from core.workflow.enums import ( +from dify_graph.enums import ( WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphNodeEventBase, NodeRunExceptionEvent, NodeRunFailedEvent, NodeRunRetryEvent, ) -from core.workflow.node_events import NodeRunResult +from dify_graph.node_events import NodeRunResult if TYPE_CHECKING: from .domain import GraphExecution diff --git a/api/core/workflow/graph_engine/event_management/__init__.py b/api/dify_graph/graph_engine/event_management/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/event_management/__init__.py rename to api/dify_graph/graph_engine/event_management/__init__.py diff --git a/api/core/workflow/graph_engine/event_management/event_handlers.py b/api/dify_graph/graph_engine/event_management/event_handlers.py similarity index 98% rename from api/core/workflow/graph_engine/event_management/event_handlers.py rename to api/dify_graph/graph_engine/event_management/event_handlers.py index 98a0702e1c..92ea793ccb 100644 --- a/api/core/workflow/graph_engine/event_management/event_handlers.py +++ b/api/dify_graph/graph_engine/event_management/event_handlers.py @@ -8,9 +8,9 @@ from functools import singledispatchmethod from typing import TYPE_CHECKING, final from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import ErrorStrategy, NodeExecutionType, NodeState -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.enums import ErrorStrategy, NodeExecutionType, NodeState +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphNodeEventBase, NodeRunAgentLogEvent, NodeRunExceptionEvent, @@ -30,7 +30,7 @@ from core.workflow.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState from ..domain.graph_execution import GraphExecution from ..response_coordinator import ResponseStreamCoordinator diff --git a/api/core/workflow/graph_engine/event_management/event_manager.py b/api/dify_graph/graph_engine/event_management/event_manager.py similarity index 98% rename from api/core/workflow/graph_engine/event_management/event_manager.py rename to api/dify_graph/graph_engine/event_management/event_manager.py index ae2e659543..616f621c3e 100644 --- a/api/core/workflow/graph_engine/event_management/event_manager.py +++ b/api/dify_graph/graph_engine/event_management/event_manager.py @@ -9,7 +9,7 @@ from collections.abc import Generator from contextlib import contextmanager from typing import final -from core.workflow.graph_events import GraphEngineEvent +from dify_graph.graph_events import GraphEngineEvent from ..layers.base import GraphEngineLayer diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/dify_graph/graph_engine/graph_engine.py similarity index 95% rename from api/core/workflow/graph_engine/graph_engine.py rename to api/dify_graph/graph_engine/graph_engine.py index 7c46fc2239..772e607328 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/dify_graph/graph_engine/graph_engine.py @@ -12,11 +12,11 @@ import queue from collections.abc import Generator from typing import TYPE_CHECKING, cast, final -from core.workflow.context import capture_current_context -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import NodeExecutionType -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.context import capture_current_context +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import NodeExecutionType +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphEngineEvent, GraphNodeEventBase, GraphRunAbortedEvent, @@ -26,10 +26,10 @@ from core.workflow.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, ) -from core.workflow.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper +from dify_graph.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper if TYPE_CHECKING: # pragma: no cover - used only for static analysis - from core.workflow.runtime.graph_runtime_state import GraphProtocol + from dify_graph.runtime.graph_runtime_state import GraphProtocol from .command_processing import ( AbortCommandHandler, @@ -49,8 +49,8 @@ from .protocols.command_channel import CommandChannel from .worker_management import WorkerPool if TYPE_CHECKING: - from core.workflow.graph_engine.domain.graph_execution import GraphExecution - from core.workflow.graph_engine.response_coordinator import ResponseStreamCoordinator + from dify_graph.graph_engine.domain.graph_execution import GraphExecution + from dify_graph.graph_engine.response_coordinator import ResponseStreamCoordinator logger = logging.getLogger(__name__) diff --git a/api/core/workflow/graph_engine/graph_state_manager.py b/api/dify_graph/graph_engine/graph_state_manager.py similarity index 98% rename from api/core/workflow/graph_engine/graph_state_manager.py rename to api/dify_graph/graph_engine/graph_state_manager.py index d9773645c3..922a968435 100644 --- a/api/core/workflow/graph_engine/graph_state_manager.py +++ b/api/dify_graph/graph_engine/graph_state_manager.py @@ -6,8 +6,8 @@ import threading from collections.abc import Sequence from typing import TypedDict, final -from core.workflow.enums import NodeState -from core.workflow.graph import Edge, Graph +from dify_graph.enums import NodeState +from dify_graph.graph import Edge, Graph from .ready_queue import ReadyQueue diff --git a/api/core/workflow/graph_engine/graph_traversal/__init__.py b/api/dify_graph/graph_engine/graph_traversal/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/graph_traversal/__init__.py rename to api/dify_graph/graph_engine/graph_traversal/__init__.py diff --git a/api/core/workflow/graph_engine/graph_traversal/edge_processor.py b/api/dify_graph/graph_engine/graph_traversal/edge_processor.py similarity index 97% rename from api/core/workflow/graph_engine/graph_traversal/edge_processor.py rename to api/dify_graph/graph_engine/graph_traversal/edge_processor.py index 9bd0f86fbf..c4625a8ff7 100644 --- a/api/core/workflow/graph_engine/graph_traversal/edge_processor.py +++ b/api/dify_graph/graph_engine/graph_traversal/edge_processor.py @@ -5,9 +5,9 @@ Edge processing logic for graph traversal. from collections.abc import Sequence from typing import TYPE_CHECKING, final -from core.workflow.enums import NodeExecutionType -from core.workflow.graph import Edge, Graph -from core.workflow.graph_events import NodeRunStreamChunkEvent +from dify_graph.enums import NodeExecutionType +from dify_graph.graph import Edge, Graph +from dify_graph.graph_events import NodeRunStreamChunkEvent from ..graph_state_manager import GraphStateManager from ..response_coordinator import ResponseStreamCoordinator diff --git a/api/core/workflow/graph_engine/graph_traversal/skip_propagator.py b/api/dify_graph/graph_engine/graph_traversal/skip_propagator.py similarity index 98% rename from api/core/workflow/graph_engine/graph_traversal/skip_propagator.py rename to api/dify_graph/graph_engine/graph_traversal/skip_propagator.py index b9c9243963..76445bccd2 100644 --- a/api/core/workflow/graph_engine/graph_traversal/skip_propagator.py +++ b/api/dify_graph/graph_engine/graph_traversal/skip_propagator.py @@ -5,7 +5,7 @@ Skip state propagation through the graph. from collections.abc import Sequence from typing import final -from core.workflow.graph import Edge, Graph +from dify_graph.graph import Edge, Graph from ..graph_state_manager import GraphStateManager diff --git a/api/core/workflow/graph_engine/layers/README.md b/api/dify_graph/graph_engine/layers/README.md similarity index 100% rename from api/core/workflow/graph_engine/layers/README.md rename to api/dify_graph/graph_engine/layers/README.md diff --git a/api/core/workflow/graph_engine/layers/__init__.py b/api/dify_graph/graph_engine/layers/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/layers/__init__.py rename to api/dify_graph/graph_engine/layers/__init__.py diff --git a/api/core/workflow/graph_engine/layers/base.py b/api/dify_graph/graph_engine/layers/base.py similarity index 94% rename from api/core/workflow/graph_engine/layers/base.py rename to api/dify_graph/graph_engine/layers/base.py index ff4a483aed..890336c1ca 100644 --- a/api/core/workflow/graph_engine/layers/base.py +++ b/api/dify_graph/graph_engine/layers/base.py @@ -7,10 +7,10 @@ intercept and respond to GraphEngine events. from abc import ABC, abstractmethod -from core.workflow.graph_engine.protocols.command_channel import CommandChannel -from core.workflow.graph_events import GraphEngineEvent, GraphNodeEventBase -from core.workflow.nodes.base.node import Node -from core.workflow.runtime import ReadOnlyGraphRuntimeState +from dify_graph.graph_engine.protocols.command_channel import CommandChannel +from dify_graph.graph_events import GraphEngineEvent, GraphNodeEventBase +from dify_graph.nodes.base.node import Node +from dify_graph.runtime import ReadOnlyGraphRuntimeState class GraphEngineLayerNotInitializedError(Exception): diff --git a/api/core/workflow/graph_engine/layers/debug_logging.py b/api/dify_graph/graph_engine/layers/debug_logging.py similarity index 99% rename from api/core/workflow/graph_engine/layers/debug_logging.py rename to api/dify_graph/graph_engine/layers/debug_logging.py index e0402cd09c..1af2e2db9e 100644 --- a/api/core/workflow/graph_engine/layers/debug_logging.py +++ b/api/dify_graph/graph_engine/layers/debug_logging.py @@ -11,7 +11,7 @@ from typing import Any, final from typing_extensions import override -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunAbortedEvent, GraphRunFailedEvent, diff --git a/api/core/workflow/graph_engine/layers/execution_limits.py b/api/dify_graph/graph_engine/layers/execution_limits.py similarity index 94% rename from api/core/workflow/graph_engine/layers/execution_limits.py rename to api/dify_graph/graph_engine/layers/execution_limits.py index a2d36d142d..48ba5608d9 100644 --- a/api/core/workflow/graph_engine/layers/execution_limits.py +++ b/api/dify_graph/graph_engine/layers/execution_limits.py @@ -15,13 +15,13 @@ from typing import final from typing_extensions import override -from core.workflow.graph_engine.entities.commands import AbortCommand, CommandType -from core.workflow.graph_engine.layers import GraphEngineLayer -from core.workflow.graph_events import ( +from dify_graph.graph_engine.entities.commands import AbortCommand, CommandType +from dify_graph.graph_engine.layers import GraphEngineLayer +from dify_graph.graph_events import ( GraphEngineEvent, NodeRunStartedEvent, ) -from core.workflow.graph_events.node import NodeRunFailedEvent, NodeRunSucceededEvent +from dify_graph.graph_events.node import NodeRunFailedEvent, NodeRunSucceededEvent class LimitType(StrEnum): diff --git a/api/core/workflow/graph_engine/manager.py b/api/dify_graph/graph_engine/manager.py similarity index 94% rename from api/core/workflow/graph_engine/manager.py rename to api/dify_graph/graph_engine/manager.py index 36f1612af0..955c149069 100644 --- a/api/core/workflow/graph_engine/manager.py +++ b/api/dify_graph/graph_engine/manager.py @@ -10,8 +10,8 @@ import logging from collections.abc import Sequence from typing import final -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel, RedisClientProtocol -from core.workflow.graph_engine.entities.commands import ( +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel, RedisClientProtocol +from dify_graph.graph_engine.entities.commands import ( AbortCommand, GraphEngineCommand, PauseCommand, diff --git a/api/core/workflow/graph_engine/orchestration/__init__.py b/api/dify_graph/graph_engine/orchestration/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/orchestration/__init__.py rename to api/dify_graph/graph_engine/orchestration/__init__.py diff --git a/api/core/workflow/graph_engine/orchestration/dispatcher.py b/api/dify_graph/graph_engine/orchestration/dispatcher.py similarity index 99% rename from api/core/workflow/graph_engine/orchestration/dispatcher.py rename to api/dify_graph/graph_engine/orchestration/dispatcher.py index 76dd1c7768..f8aaf20b2f 100644 --- a/api/core/workflow/graph_engine/orchestration/dispatcher.py +++ b/api/dify_graph/graph_engine/orchestration/dispatcher.py @@ -8,7 +8,7 @@ import threading import time from typing import TYPE_CHECKING, final -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphNodeEventBase, NodeRunExceptionEvent, NodeRunFailedEvent, diff --git a/api/core/workflow/graph_engine/orchestration/execution_coordinator.py b/api/dify_graph/graph_engine/orchestration/execution_coordinator.py similarity index 100% rename from api/core/workflow/graph_engine/orchestration/execution_coordinator.py rename to api/dify_graph/graph_engine/orchestration/execution_coordinator.py diff --git a/api/core/workflow/graph_engine/protocols/command_channel.py b/api/dify_graph/graph_engine/protocols/command_channel.py similarity index 100% rename from api/core/workflow/graph_engine/protocols/command_channel.py rename to api/dify_graph/graph_engine/protocols/command_channel.py diff --git a/api/core/workflow/graph_engine/ready_queue/__init__.py b/api/dify_graph/graph_engine/ready_queue/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/ready_queue/__init__.py rename to api/dify_graph/graph_engine/ready_queue/__init__.py diff --git a/api/core/workflow/graph_engine/ready_queue/factory.py b/api/dify_graph/graph_engine/ready_queue/factory.py similarity index 100% rename from api/core/workflow/graph_engine/ready_queue/factory.py rename to api/dify_graph/graph_engine/ready_queue/factory.py diff --git a/api/core/workflow/graph_engine/ready_queue/in_memory.py b/api/dify_graph/graph_engine/ready_queue/in_memory.py similarity index 100% rename from api/core/workflow/graph_engine/ready_queue/in_memory.py rename to api/dify_graph/graph_engine/ready_queue/in_memory.py diff --git a/api/core/workflow/graph_engine/ready_queue/protocol.py b/api/dify_graph/graph_engine/ready_queue/protocol.py similarity index 100% rename from api/core/workflow/graph_engine/ready_queue/protocol.py rename to api/dify_graph/graph_engine/ready_queue/protocol.py diff --git a/api/core/workflow/graph_engine/response_coordinator/__init__.py b/api/dify_graph/graph_engine/response_coordinator/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/response_coordinator/__init__.py rename to api/dify_graph/graph_engine/response_coordinator/__init__.py diff --git a/api/core/workflow/graph_engine/response_coordinator/coordinator.py b/api/dify_graph/graph_engine/response_coordinator/coordinator.py similarity index 98% rename from api/core/workflow/graph_engine/response_coordinator/coordinator.py rename to api/dify_graph/graph_engine/response_coordinator/coordinator.py index e82ba29438..941a8a496b 100644 --- a/api/core/workflow/graph_engine/response_coordinator/coordinator.py +++ b/api/dify_graph/graph_engine/response_coordinator/coordinator.py @@ -14,11 +14,11 @@ from uuid import uuid4 from pydantic import BaseModel, Field -from core.workflow.enums import NodeExecutionType, NodeState -from core.workflow.graph_events import NodeRunStreamChunkEvent, NodeRunSucceededEvent -from core.workflow.nodes.base.template import TextSegment, VariableSegment -from core.workflow.runtime import VariablePool -from core.workflow.runtime.graph_runtime_state import GraphProtocol +from dify_graph.enums import NodeExecutionType, NodeState +from dify_graph.graph_events import NodeRunStreamChunkEvent, NodeRunSucceededEvent +from dify_graph.nodes.base.template import TextSegment, VariableSegment +from dify_graph.runtime import VariablePool +from dify_graph.runtime.graph_runtime_state import GraphProtocol from .path import Path from .session import ResponseSession diff --git a/api/core/workflow/graph_engine/response_coordinator/path.py b/api/dify_graph/graph_engine/response_coordinator/path.py similarity index 100% rename from api/core/workflow/graph_engine/response_coordinator/path.py rename to api/dify_graph/graph_engine/response_coordinator/path.py diff --git a/api/core/workflow/graph_engine/response_coordinator/session.py b/api/dify_graph/graph_engine/response_coordinator/session.py similarity index 85% rename from api/core/workflow/graph_engine/response_coordinator/session.py rename to api/dify_graph/graph_engine/response_coordinator/session.py index 5e4fada7d9..0548e88d93 100644 --- a/api/core/workflow/graph_engine/response_coordinator/session.py +++ b/api/dify_graph/graph_engine/response_coordinator/session.py @@ -9,11 +9,11 @@ from __future__ import annotations from dataclasses import dataclass -from core.workflow.nodes.answer.answer_node import AnswerNode -from core.workflow.nodes.base.template import Template -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.knowledge_index import KnowledgeIndexNode -from core.workflow.runtime.graph_runtime_state import NodeProtocol +from dify_graph.nodes.answer.answer_node import AnswerNode +from dify_graph.nodes.base.template import Template +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.knowledge_index import KnowledgeIndexNode +from dify_graph.runtime.graph_runtime_state import NodeProtocol @dataclass diff --git a/api/core/workflow/graph_engine/worker.py b/api/dify_graph/graph_engine/worker.py similarity index 95% rename from api/core/workflow/graph_engine/worker.py rename to api/dify_graph/graph_engine/worker.py index 9e218f6fa6..5c5d0fe5b9 100644 --- a/api/core/workflow/graph_engine/worker.py +++ b/api/dify_graph/graph_engine/worker.py @@ -14,11 +14,11 @@ from typing import TYPE_CHECKING, final from typing_extensions import override -from core.workflow.context import IExecutionContext -from core.workflow.graph import Graph -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import GraphNodeEventBase, NodeRunFailedEvent, is_node_result_event -from core.workflow.nodes.base.node import Node +from dify_graph.context import IExecutionContext +from dify_graph.graph import Graph +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import GraphNodeEventBase, NodeRunFailedEvent, is_node_result_event +from dify_graph.nodes.base.node import Node from .ready_queue import ReadyQueue diff --git a/api/core/workflow/graph_engine/worker_management/__init__.py b/api/dify_graph/graph_engine/worker_management/__init__.py similarity index 100% rename from api/core/workflow/graph_engine/worker_management/__init__.py rename to api/dify_graph/graph_engine/worker_management/__init__.py diff --git a/api/core/workflow/graph_engine/worker_management/worker_pool.py b/api/dify_graph/graph_engine/worker_management/worker_pool.py similarity index 98% rename from api/core/workflow/graph_engine/worker_management/worker_pool.py rename to api/dify_graph/graph_engine/worker_management/worker_pool.py index 2c14f53746..cc93087783 100644 --- a/api/core/workflow/graph_engine/worker_management/worker_pool.py +++ b/api/dify_graph/graph_engine/worker_management/worker_pool.py @@ -10,9 +10,9 @@ import queue import threading from typing import final -from core.workflow.context import IExecutionContext -from core.workflow.graph import Graph -from core.workflow.graph_events import GraphNodeEventBase +from dify_graph.context import IExecutionContext +from dify_graph.graph import Graph +from dify_graph.graph_events import GraphNodeEventBase from ..config import GraphEngineConfig from ..layers.base import GraphEngineLayer diff --git a/api/core/workflow/graph_events/__init__.py b/api/dify_graph/graph_events/__init__.py similarity index 100% rename from api/core/workflow/graph_events/__init__.py rename to api/dify_graph/graph_events/__init__.py diff --git a/api/core/workflow/graph_events/agent.py b/api/dify_graph/graph_events/agent.py similarity index 100% rename from api/core/workflow/graph_events/agent.py rename to api/dify_graph/graph_events/agent.py diff --git a/api/core/workflow/graph_events/base.py b/api/dify_graph/graph_events/base.py similarity index 87% rename from api/core/workflow/graph_events/base.py rename to api/dify_graph/graph_events/base.py index 3714679201..4560cf5085 100644 --- a/api/core/workflow/graph_events/base.py +++ b/api/dify_graph/graph_events/base.py @@ -1,7 +1,7 @@ from pydantic import BaseModel, Field -from core.workflow.enums import NodeType -from core.workflow.node_events import NodeRunResult +from dify_graph.enums import NodeType +from dify_graph.node_events import NodeRunResult class GraphEngineEvent(BaseModel): diff --git a/api/core/workflow/graph_events/graph.py b/api/dify_graph/graph_events/graph.py similarity index 90% rename from api/core/workflow/graph_events/graph.py rename to api/dify_graph/graph_events/graph.py index f46526bcab..f4aaba64d6 100644 --- a/api/core/workflow/graph_events/graph.py +++ b/api/dify_graph/graph_events/graph.py @@ -1,8 +1,8 @@ from pydantic import Field -from core.workflow.entities.pause_reason import PauseReason -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph_events import BaseGraphEvent +from dify_graph.entities.pause_reason import PauseReason +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph_events import BaseGraphEvent class GraphRunStartedEvent(BaseGraphEvent): diff --git a/api/core/workflow/graph_events/human_input.py b/api/dify_graph/graph_events/human_input.py similarity index 100% rename from api/core/workflow/graph_events/human_input.py rename to api/dify_graph/graph_events/human_input.py diff --git a/api/core/workflow/graph_events/iteration.py b/api/dify_graph/graph_events/iteration.py similarity index 100% rename from api/core/workflow/graph_events/iteration.py rename to api/dify_graph/graph_events/iteration.py diff --git a/api/core/workflow/graph_events/loop.py b/api/dify_graph/graph_events/loop.py similarity index 100% rename from api/core/workflow/graph_events/loop.py rename to api/dify_graph/graph_events/loop.py diff --git a/api/core/workflow/graph_events/node.py b/api/dify_graph/graph_events/node.py similarity index 96% rename from api/core/workflow/graph_events/node.py rename to api/dify_graph/graph_events/node.py index 975d72ad1f..21ddf80b64 100644 --- a/api/core/workflow/graph_events/node.py +++ b/api/dify_graph/graph_events/node.py @@ -4,8 +4,8 @@ from datetime import datetime from pydantic import Field from core.rag.entities.citation_metadata import RetrievalSourceMetadata -from core.workflow.entities import AgentNodeStrategyInit -from core.workflow.entities.pause_reason import PauseReason +from dify_graph.entities import AgentNodeStrategyInit +from dify_graph.entities.pause_reason import PauseReason from .base import GraphNodeEventBase diff --git a/api/core/workflow/node_events/__init__.py b/api/dify_graph/node_events/__init__.py similarity index 100% rename from api/core/workflow/node_events/__init__.py rename to api/dify_graph/node_events/__init__.py diff --git a/api/core/workflow/node_events/agent.py b/api/dify_graph/node_events/agent.py similarity index 100% rename from api/core/workflow/node_events/agent.py rename to api/dify_graph/node_events/agent.py diff --git a/api/core/workflow/node_events/base.py b/api/dify_graph/node_events/base.py similarity index 91% rename from api/core/workflow/node_events/base.py rename to api/dify_graph/node_events/base.py index 7fec47e21f..f30c37f2cc 100644 --- a/api/core/workflow/node_events/base.py +++ b/api/dify_graph/node_events/base.py @@ -4,7 +4,7 @@ from typing import Any from pydantic import BaseModel, Field from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus class NodeEventBase(BaseModel): diff --git a/api/core/workflow/node_events/iteration.py b/api/dify_graph/node_events/iteration.py similarity index 100% rename from api/core/workflow/node_events/iteration.py rename to api/dify_graph/node_events/iteration.py diff --git a/api/core/workflow/node_events/loop.py b/api/dify_graph/node_events/loop.py similarity index 100% rename from api/core/workflow/node_events/loop.py rename to api/dify_graph/node_events/loop.py diff --git a/api/core/workflow/node_events/node.py b/api/dify_graph/node_events/node.py similarity index 92% rename from api/core/workflow/node_events/node.py rename to api/dify_graph/node_events/node.py index 2468bd0ac3..7f48539255 100644 --- a/api/core/workflow/node_events/node.py +++ b/api/dify_graph/node_events/node.py @@ -5,9 +5,9 @@ from pydantic import Field from core.model_runtime.entities.llm_entities import LLMUsage from core.rag.entities.citation_metadata import RetrievalSourceMetadata -from core.workflow.entities.pause_reason import PauseReason -from core.workflow.file import File -from core.workflow.node_events import NodeRunResult +from dify_graph.entities.pause_reason import PauseReason +from dify_graph.file import File +from dify_graph.node_events import NodeRunResult from .base import NodeEventBase diff --git a/api/dify_graph/nodes/__init__.py b/api/dify_graph/nodes/__init__.py new file mode 100644 index 0000000000..d113ad5e70 --- /dev/null +++ b/api/dify_graph/nodes/__init__.py @@ -0,0 +1,3 @@ +from dify_graph.enums import NodeType + +__all__ = ["NodeType"] diff --git a/api/core/workflow/nodes/agent/__init__.py b/api/dify_graph/nodes/agent/__init__.py similarity index 100% rename from api/core/workflow/nodes/agent/__init__.py rename to api/dify_graph/nodes/agent/__init__.py diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/dify_graph/nodes/agent/agent_node.py similarity index 98% rename from api/core/workflow/nodes/agent/agent_node.py rename to api/dify_graph/nodes/agent/agent_node.py index ac86b1784f..5d4c6526c4 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/dify_graph/nodes/agent/agent_node.py @@ -25,25 +25,25 @@ from core.tools.entities.tool_entities import ( ) from core.tools.tool_manager import ToolManager from core.tools.utils.message_transformer import ToolFileMessageTransformer -from core.workflow.enums import ( +from dify_graph.enums import ( NodeType, SystemVariableKey, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.file import File, FileTransferMethod -from core.workflow.node_events import ( +from dify_graph.file import File, FileTransferMethod +from dify_graph.node_events import ( AgentLogEvent, NodeEventBase, NodeRunResult, StreamChunkEvent, StreamCompletedEvent, ) -from core.workflow.nodes.agent.entities import AgentNodeData, AgentOldVersionModelFeatures, ParamsAutoGenerated -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.runtime import VariablePool -from core.workflow.variables.segments import ArrayFileSegment, StringSegment +from dify_graph.nodes.agent.entities import AgentNodeData, AgentOldVersionModelFeatures, ParamsAutoGenerated +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.runtime import VariablePool +from dify_graph.variables.segments import ArrayFileSegment, StringSegment from extensions.ext_database import db from factories import file_factory from factories.agent_factory import get_plugin_agent_strategy diff --git a/api/core/workflow/nodes/agent/entities.py b/api/dify_graph/nodes/agent/entities.py similarity index 95% rename from api/core/workflow/nodes/agent/entities.py rename to api/dify_graph/nodes/agent/entities.py index 985ee5eef2..9124420f01 100644 --- a/api/core/workflow/nodes/agent/entities.py +++ b/api/dify_graph/nodes/agent/entities.py @@ -5,7 +5,7 @@ from pydantic import BaseModel from core.prompt.entities.advanced_prompt_entities import MemoryConfig from core.tools.entities.tool_entities import ToolSelector -from core.workflow.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.entities import BaseNodeData class AgentNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/agent/exc.py b/api/dify_graph/nodes/agent/exc.py similarity index 100% rename from api/core/workflow/nodes/agent/exc.py rename to api/dify_graph/nodes/agent/exc.py diff --git a/api/core/workflow/nodes/end/__init__.py b/api/dify_graph/nodes/answer/__init__.py similarity index 100% rename from api/core/workflow/nodes/end/__init__.py rename to api/dify_graph/nodes/answer/__init__.py diff --git a/api/core/workflow/nodes/answer/answer_node.py b/api/dify_graph/nodes/answer/answer_node.py similarity index 83% rename from api/core/workflow/nodes/answer/answer_node.py rename to api/dify_graph/nodes/answer/answer_node.py index 388447368e..d07b9c8062 100644 --- a/api/core/workflow/nodes/answer/answer_node.py +++ b/api/dify_graph/nodes/answer/answer_node.py @@ -1,13 +1,13 @@ from collections.abc import Mapping, Sequence from typing import Any -from core.workflow.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.answer.entities import AnswerNodeData -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.template import Template -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.variables import ArrayFileSegment, FileSegment, Segment +from dify_graph.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.answer.entities import AnswerNodeData +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.template import Template +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.variables import ArrayFileSegment, FileSegment, Segment class AnswerNode(Node[AnswerNodeData]): diff --git a/api/core/workflow/nodes/answer/entities.py b/api/dify_graph/nodes/answer/entities.py similarity index 97% rename from api/core/workflow/nodes/answer/entities.py rename to api/dify_graph/nodes/answer/entities.py index 850ff14880..06927cd71e 100644 --- a/api/core/workflow/nodes/answer/entities.py +++ b/api/dify_graph/nodes/answer/entities.py @@ -3,7 +3,7 @@ from enum import StrEnum, auto from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class AnswerNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/base/__init__.py b/api/dify_graph/nodes/base/__init__.py similarity index 100% rename from api/core/workflow/nodes/base/__init__.py rename to api/dify_graph/nodes/base/__init__.py diff --git a/api/core/workflow/nodes/base/entities.py b/api/dify_graph/nodes/base/entities.py similarity index 99% rename from api/core/workflow/nodes/base/entities.py rename to api/dify_graph/nodes/base/entities.py index c5426e3fb7..956fa59e78 100644 --- a/api/core/workflow/nodes/base/entities.py +++ b/api/dify_graph/nodes/base/entities.py @@ -9,7 +9,7 @@ from typing import Any, Union from pydantic import BaseModel, field_validator, model_validator -from core.workflow.enums import ErrorStrategy +from dify_graph.enums import ErrorStrategy from .exc import DefaultValueTypeError diff --git a/api/core/workflow/nodes/base/exc.py b/api/dify_graph/nodes/base/exc.py similarity index 100% rename from api/core/workflow/nodes/base/exc.py rename to api/dify_graph/nodes/base/exc.py diff --git a/api/core/workflow/nodes/base/node.py b/api/dify_graph/nodes/base/node.py similarity index 96% rename from api/core/workflow/nodes/base/node.py rename to api/dify_graph/nodes/base/node.py index 976e8032b8..bd8116c1ba 100644 --- a/api/core/workflow/nodes/base/node.py +++ b/api/dify_graph/nodes/base/node.py @@ -12,9 +12,9 @@ from typing import Any, ClassVar, Generic, TypeVar, cast, get_args, get_origin from uuid import uuid4 from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities import AgentNodeStrategyInit, GraphInitParams -from core.workflow.enums import ErrorStrategy, NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph_events import ( +from dify_graph.entities import AgentNodeStrategyInit, GraphInitParams +from dify_graph.enums import ErrorStrategy, NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph_events import ( GraphNodeEventBase, NodeRunAgentLogEvent, NodeRunFailedEvent, @@ -34,7 +34,7 @@ from core.workflow.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import ( +from dify_graph.node_events import ( AgentLogEvent, HumanInputFormFilledEvent, HumanInputFormTimeoutEvent, @@ -53,7 +53,7 @@ from core.workflow.node_events import ( StreamChunkEvent, StreamCompletedEvent, ) -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState from libs.datetime_utils import naive_utc_now from models.enums import UserFrom @@ -156,7 +156,7 @@ class Node(Generic[NodeDataT]): # Skip base class itself if cls is Node: return - # Only register production node implementations defined under core.workflow.nodes.* + # Only register production node implementations defined under dify_graph.nodes.* # This prevents test helper subclasses from polluting the global registry and # accidentally overriding real node types (e.g., a test Answer node). module_name = getattr(cls, "__module__", "") @@ -164,7 +164,7 @@ class Node(Generic[NodeDataT]): node_type = cls.node_type version = cls.version() bucket = Node._registry.setdefault(node_type, {}) - if module_name.startswith("core.workflow.nodes."): + if module_name.startswith("dify_graph.nodes."): # Production node definitions take precedence and may override bucket[version] = cls # type: ignore[index] else: @@ -317,13 +317,13 @@ class Node(Generic[NodeDataT]): ) # === FIXME(-LAN-): Needs to refactor. - from core.workflow.nodes.tool.tool_node import ToolNode + from dify_graph.nodes.tool.tool_node import ToolNode if isinstance(self, ToolNode): start_event.provider_id = getattr(self.node_data, "provider_id", "") start_event.provider_type = getattr(self.node_data, "provider_type", "") - from core.workflow.nodes.datasource.datasource_node import DatasourceNode + from dify_graph.nodes.datasource.datasource_node import DatasourceNode if isinstance(self, DatasourceNode): plugin_id = getattr(self.node_data, "plugin_id", "") @@ -332,7 +332,7 @@ class Node(Generic[NodeDataT]): start_event.provider_id = f"{plugin_id}/{provider_name}" start_event.provider_type = getattr(self.node_data, "provider_type", "") - from core.workflow.nodes.trigger_plugin.trigger_event_node import TriggerEventNode + from dify_graph.nodes.trigger_plugin.trigger_event_node import TriggerEventNode if isinstance(self, TriggerEventNode): start_event.provider_id = getattr(self.node_data, "provider_id", "") @@ -340,8 +340,8 @@ class Node(Generic[NodeDataT]): from typing import cast - from core.workflow.nodes.agent.agent_node import AgentNode - from core.workflow.nodes.agent.entities import AgentNodeData + from dify_graph.nodes.agent.agent_node import AgentNode + from dify_graph.nodes.agent.entities import AgentNodeData if isinstance(self, AgentNode): start_event.agent_strategy = AgentNodeStrategyInit( @@ -472,22 +472,22 @@ class Node(Generic[NodeDataT]): # NOTE(QuantumGhost): This should be in sync with `NODE_TYPE_CLASSES_MAPPING`. # # If you have introduced a new node type, please add it to `NODE_TYPE_CLASSES_MAPPING` - # in `api/core/workflow/nodes/__init__.py`. + # in `api/dify_graph/nodes/__init__.py`. raise NotImplementedError("subclasses of BaseNode must implement `version` method.") @classmethod def get_node_type_classes_mapping(cls) -> Mapping[NodeType, Mapping[str, type[Node]]]: """Return mapping of NodeType -> {version -> Node subclass} using __init_subclass__ registry. - Import all modules under core.workflow.nodes so subclasses register themselves on import. + Import all modules under dify_graph.nodes so subclasses register themselves on import. Then we return a readonly view of the registry to avoid accidental mutation. """ # Import all node modules to ensure they are loaded (thus registered) - import core.workflow.nodes as _nodes_pkg + import dify_graph.nodes as _nodes_pkg for _, _modname, _ in pkgutil.walk_packages(_nodes_pkg.__path__, _nodes_pkg.__name__ + "."): # Avoid importing modules that depend on the registry to prevent circular imports. - if _modname == "core.workflow.nodes.node_mapping": + if _modname == "dify_graph.nodes.node_mapping": continue importlib.import_module(_modname) diff --git a/api/core/workflow/nodes/base/template.py b/api/dify_graph/nodes/base/template.py similarity index 98% rename from api/core/workflow/nodes/base/template.py rename to api/dify_graph/nodes/base/template.py index 81f4b9f6fb..5976e808e3 100644 --- a/api/core/workflow/nodes/base/template.py +++ b/api/dify_graph/nodes/base/template.py @@ -11,7 +11,7 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import Any, Union -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser @dataclass(frozen=True) diff --git a/api/core/workflow/nodes/base/usage_tracking_mixin.py b/api/dify_graph/nodes/base/usage_tracking_mixin.py similarity index 95% rename from api/core/workflow/nodes/base/usage_tracking_mixin.py rename to api/dify_graph/nodes/base/usage_tracking_mixin.py index d9a0ef8972..f1ba953af5 100644 --- a/api/core/workflow/nodes/base/usage_tracking_mixin.py +++ b/api/dify_graph/nodes/base/usage_tracking_mixin.py @@ -1,5 +1,5 @@ from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState class LLMUsageTrackingMixin: diff --git a/api/core/workflow/nodes/base/variable_template_parser.py b/api/dify_graph/nodes/base/variable_template_parser.py similarity index 100% rename from api/core/workflow/nodes/base/variable_template_parser.py rename to api/dify_graph/nodes/base/variable_template_parser.py diff --git a/api/core/workflow/nodes/code/__init__.py b/api/dify_graph/nodes/code/__init__.py similarity index 100% rename from api/core/workflow/nodes/code/__init__.py rename to api/dify_graph/nodes/code/__init__.py diff --git a/api/core/workflow/nodes/code/code_node.py b/api/dify_graph/nodes/code/code_node.py similarity index 97% rename from api/core/workflow/nodes/code/code_node.py rename to api/dify_graph/nodes/code/code_node.py index 7b1cbfcfea..83e72deea9 100644 --- a/api/core/workflow/nodes/code/code_node.py +++ b/api/dify_graph/nodes/code/code_node.py @@ -3,13 +3,13 @@ from decimal import Decimal from textwrap import dedent from typing import TYPE_CHECKING, Any, Protocol, cast -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.code.entities import CodeLanguage, CodeNodeData -from core.workflow.nodes.code.limits import CodeNodeLimits -from core.workflow.variables.segments import ArrayFileSegment -from core.workflow.variables.types import SegmentType +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.code.entities import CodeLanguage, CodeNodeData +from dify_graph.nodes.code.limits import CodeNodeLimits +from dify_graph.variables.segments import ArrayFileSegment +from dify_graph.variables.types import SegmentType from .exc import ( CodeNodeError, @@ -18,8 +18,8 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState class WorkflowCodeExecutor(Protocol): diff --git a/api/core/workflow/nodes/code/entities.py b/api/dify_graph/nodes/code/entities.py similarity index 88% rename from api/core/workflow/nodes/code/entities.py rename to api/dify_graph/nodes/code/entities.py index 8b73b89e2f..9e161c29d0 100644 --- a/api/core/workflow/nodes/code/entities.py +++ b/api/dify_graph/nodes/code/entities.py @@ -3,9 +3,9 @@ from typing import Annotated, Literal from pydantic import AfterValidator, BaseModel -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.base.entities import VariableSelector -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.base.entities import VariableSelector +from dify_graph.variables.types import SegmentType class CodeLanguage(StrEnum): diff --git a/api/core/workflow/nodes/code/exc.py b/api/dify_graph/nodes/code/exc.py similarity index 100% rename from api/core/workflow/nodes/code/exc.py rename to api/dify_graph/nodes/code/exc.py diff --git a/api/core/workflow/nodes/code/limits.py b/api/dify_graph/nodes/code/limits.py similarity index 100% rename from api/core/workflow/nodes/code/limits.py rename to api/dify_graph/nodes/code/limits.py diff --git a/api/core/workflow/nodes/datasource/__init__.py b/api/dify_graph/nodes/datasource/__init__.py similarity index 100% rename from api/core/workflow/nodes/datasource/__init__.py rename to api/dify_graph/nodes/datasource/__init__.py diff --git a/api/core/workflow/nodes/datasource/datasource_node.py b/api/dify_graph/nodes/datasource/datasource_node.py similarity index 94% rename from api/core/workflow/nodes/datasource/datasource_node.py rename to api/dify_graph/nodes/datasource/datasource_node.py index 17f8bcb2db..802d34d2d0 100644 --- a/api/core/workflow/nodes/datasource/datasource_node.py +++ b/api/dify_graph/nodes/datasource/datasource_node.py @@ -3,12 +3,12 @@ from typing import TYPE_CHECKING, Any from core.datasource.entities.datasource_entities import DatasourceProviderType from core.plugin.impl.exc import PluginDaemonClientSideError -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.enums import NodeExecutionType, NodeType, SystemVariableKey -from core.workflow.node_events import NodeRunResult, StreamCompletedEvent -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.repositories.datasource_manager_protocol import ( +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.enums import NodeExecutionType, NodeType, SystemVariableKey +from dify_graph.node_events import NodeRunResult, StreamCompletedEvent +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.repositories.datasource_manager_protocol import ( DatasourceManagerProtocol, DatasourceParameter, OnlineDriveDownloadFileParam, @@ -19,8 +19,8 @@ from .entities import DatasourceNodeData from .exc import DatasourceNodeError if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState class DatasourceNode(Node[DatasourceNodeData]): diff --git a/api/core/workflow/nodes/datasource/entities.py b/api/dify_graph/nodes/datasource/entities.py similarity index 96% rename from api/core/workflow/nodes/datasource/entities.py rename to api/dify_graph/nodes/datasource/entities.py index 4802d3ed98..ba49e65f31 100644 --- a/api/core/workflow/nodes/datasource/entities.py +++ b/api/dify_graph/nodes/datasource/entities.py @@ -3,7 +3,7 @@ from typing import Any, Literal, Union from pydantic import BaseModel, field_validator from pydantic_core.core_schema import ValidationInfo -from core.workflow.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.entities import BaseNodeData class DatasourceEntity(BaseModel): diff --git a/api/core/workflow/nodes/datasource/exc.py b/api/dify_graph/nodes/datasource/exc.py similarity index 100% rename from api/core/workflow/nodes/datasource/exc.py rename to api/dify_graph/nodes/datasource/exc.py diff --git a/api/core/workflow/nodes/document_extractor/__init__.py b/api/dify_graph/nodes/document_extractor/__init__.py similarity index 100% rename from api/core/workflow/nodes/document_extractor/__init__.py rename to api/dify_graph/nodes/document_extractor/__init__.py diff --git a/api/core/workflow/nodes/document_extractor/entities.py b/api/dify_graph/nodes/document_extractor/entities.py similarity index 84% rename from api/core/workflow/nodes/document_extractor/entities.py rename to api/dify_graph/nodes/document_extractor/entities.py index db05bbf4fe..f4949d0df8 100644 --- a/api/core/workflow/nodes/document_extractor/entities.py +++ b/api/dify_graph/nodes/document_extractor/entities.py @@ -1,7 +1,7 @@ from collections.abc import Sequence from dataclasses import dataclass -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class DocumentExtractorNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/document_extractor/exc.py b/api/dify_graph/nodes/document_extractor/exc.py similarity index 100% rename from api/core/workflow/nodes/document_extractor/exc.py rename to api/dify_graph/nodes/document_extractor/exc.py diff --git a/api/core/workflow/nodes/document_extractor/node.py b/api/dify_graph/nodes/document_extractor/node.py similarity index 98% rename from api/core/workflow/nodes/document_extractor/node.py rename to api/dify_graph/nodes/document_extractor/node.py index 59be4c54ef..01ecd49494 100644 --- a/api/core/workflow/nodes/document_extractor/node.py +++ b/api/dify_graph/nodes/document_extractor/node.py @@ -21,12 +21,12 @@ from docx.table import Table from docx.text.paragraph import Paragraph from core.helper import ssrf_proxy -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod, file_manager -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.variables import ArrayFileSegment -from core.workflow.variables.segments import ArrayStringSegment, FileSegment +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod, file_manager +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.variables import ArrayFileSegment +from dify_graph.variables.segments import ArrayStringSegment, FileSegment from .entities import DocumentExtractorNodeData, UnstructuredApiConfig from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, UnsupportedFileTypeError @@ -34,8 +34,8 @@ from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, logger = logging.getLogger(__name__) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState class DocumentExtractorNode(Node[DocumentExtractorNodeData]): diff --git a/api/core/workflow/nodes/variable_assigner/__init__.py b/api/dify_graph/nodes/end/__init__.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/__init__.py rename to api/dify_graph/nodes/end/__init__.py diff --git a/api/core/workflow/nodes/end/end_node.py b/api/dify_graph/nodes/end/end_node.py similarity index 81% rename from api/core/workflow/nodes/end/end_node.py rename to api/dify_graph/nodes/end/end_node.py index 2efcb4f418..7aa526b85b 100644 --- a/api/core/workflow/nodes/end/end_node.py +++ b/api/dify_graph/nodes/end/end_node.py @@ -1,8 +1,8 @@ -from core.workflow.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.template import Template -from core.workflow.nodes.end.entities import EndNodeData +from dify_graph.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.template import Template +from dify_graph.nodes.end.entities import EndNodeData class EndNode(Node[EndNodeData]): diff --git a/api/core/workflow/nodes/end/entities.py b/api/dify_graph/nodes/end/entities.py similarity index 87% rename from api/core/workflow/nodes/end/entities.py rename to api/dify_graph/nodes/end/entities.py index 87a221b5f6..a410087214 100644 --- a/api/core/workflow/nodes/end/entities.py +++ b/api/dify_graph/nodes/end/entities.py @@ -1,6 +1,6 @@ from pydantic import BaseModel, Field -from core.workflow.nodes.base.entities import BaseNodeData, OutputVariableEntity +from dify_graph.nodes.base.entities import BaseNodeData, OutputVariableEntity class EndNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/http_request/__init__.py b/api/dify_graph/nodes/http_request/__init__.py similarity index 100% rename from api/core/workflow/nodes/http_request/__init__.py rename to api/dify_graph/nodes/http_request/__init__.py diff --git a/api/core/workflow/nodes/http_request/config.py b/api/dify_graph/nodes/http_request/config.py similarity index 100% rename from api/core/workflow/nodes/http_request/config.py rename to api/dify_graph/nodes/http_request/config.py diff --git a/api/core/workflow/nodes/http_request/entities.py b/api/dify_graph/nodes/http_request/entities.py similarity index 99% rename from api/core/workflow/nodes/http_request/entities.py rename to api/dify_graph/nodes/http_request/entities.py index 0eda20f485..a5564689f8 100644 --- a/api/core/workflow/nodes/http_request/entities.py +++ b/api/dify_graph/nodes/http_request/entities.py @@ -8,7 +8,7 @@ import charset_normalizer import httpx from pydantic import BaseModel, Field, ValidationInfo, field_validator -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData HTTP_REQUEST_CONFIG_FILTER_KEY = "http_request_config" diff --git a/api/core/workflow/nodes/http_request/exc.py b/api/dify_graph/nodes/http_request/exc.py similarity index 100% rename from api/core/workflow/nodes/http_request/exc.py rename to api/dify_graph/nodes/http_request/exc.py diff --git a/api/core/workflow/nodes/http_request/executor.py b/api/dify_graph/nodes/http_request/executor.py similarity index 99% rename from api/core/workflow/nodes/http_request/executor.py rename to api/dify_graph/nodes/http_request/executor.py index de14c8c517..892b0fc688 100644 --- a/api/core/workflow/nodes/http_request/executor.py +++ b/api/dify_graph/nodes/http_request/executor.py @@ -10,9 +10,9 @@ from urllib.parse import urlencode, urlparse import httpx from json_repair import repair_json -from core.workflow.file.enums import FileTransferMethod -from core.workflow.runtime import VariablePool -from core.workflow.variables.segments import ArrayFileSegment, FileSegment +from dify_graph.file.enums import FileTransferMethod +from dify_graph.runtime import VariablePool +from dify_graph.variables.segments import ArrayFileSegment, FileSegment from ..protocols import FileManagerProtocol, HttpClientProtocol from .entities import ( diff --git a/api/core/workflow/nodes/http_request/node.py b/api/dify_graph/nodes/http_request/node.py similarity index 93% rename from api/core/workflow/nodes/http_request/node.py rename to api/dify_graph/nodes/http_request/node.py index 11458db758..ae0faa8a56 100644 --- a/api/core/workflow/nodes/http_request/node.py +++ b/api/dify_graph/nodes/http_request/node.py @@ -3,15 +3,15 @@ import mimetypes from collections.abc import Callable, Mapping, Sequence from typing import TYPE_CHECKING, Any -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base import variable_template_parser -from core.workflow.nodes.base.entities import VariableSelector -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.http_request.executor import Executor -from core.workflow.nodes.protocols import FileManagerProtocol, HttpClientProtocol, ToolFileManagerProtocol -from core.workflow.variables.segments import ArrayFileSegment +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base import variable_template_parser +from dify_graph.nodes.base.entities import VariableSelector +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.http_request.executor import Executor +from dify_graph.nodes.protocols import FileManagerProtocol, HttpClientProtocol, ToolFileManagerProtocol +from dify_graph.variables.segments import ArrayFileSegment from factories import file_factory from .config import build_http_request_config, resolve_http_request_config @@ -27,8 +27,8 @@ from .exc import HttpRequestNodeError, RequestBodyError logger = logging.getLogger(__name__) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState class HttpRequestNode(Node[HttpRequestNodeData]): diff --git a/api/core/workflow/nodes/human_input/__init__.py b/api/dify_graph/nodes/human_input/__init__.py similarity index 100% rename from api/core/workflow/nodes/human_input/__init__.py rename to api/dify_graph/nodes/human_input/__init__.py diff --git a/api/core/workflow/nodes/human_input/entities.py b/api/dify_graph/nodes/human_input/entities.py similarity index 98% rename from api/core/workflow/nodes/human_input/entities.py rename to api/dify_graph/nodes/human_input/entities.py index a4473dfa7d..5616949dcc 100644 --- a/api/core/workflow/nodes/human_input/entities.py +++ b/api/dify_graph/nodes/human_input/entities.py @@ -10,10 +10,10 @@ from typing import Annotated, Any, ClassVar, Literal, Self from pydantic import BaseModel, Field, field_validator, model_validator -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.runtime import VariablePool -from core.workflow.variables.consts import SELECTORS_LENGTH +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.runtime import VariablePool +from dify_graph.variables.consts import SELECTORS_LENGTH from .enums import ButtonStyle, DeliveryMethodType, EmailRecipientType, FormInputType, PlaceholderType, TimeoutUnit diff --git a/api/core/workflow/nodes/human_input/enums.py b/api/dify_graph/nodes/human_input/enums.py similarity index 100% rename from api/core/workflow/nodes/human_input/enums.py rename to api/dify_graph/nodes/human_input/enums.py diff --git a/api/core/workflow/nodes/human_input/human_input_node.py b/api/dify_graph/nodes/human_input/human_input_node.py similarity index 95% rename from api/core/workflow/nodes/human_input/human_input_node.py rename to api/dify_graph/nodes/human_input/human_input_node.py index 1d7522ea25..ec4a7c85f9 100644 --- a/api/core/workflow/nodes/human_input/human_input_node.py +++ b/api/dify_graph/nodes/human_input/human_input_node.py @@ -5,23 +5,23 @@ from typing import TYPE_CHECKING, Any from core.app.entities.app_invoke_entities import InvokeFrom from core.repositories.human_input_repository import HumanInputFormRepositoryImpl -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import ( +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import ( HumanInputFormFilledEvent, HumanInputFormTimeoutEvent, NodeRunResult, PauseRequestedEvent, ) -from core.workflow.node_events.base import NodeEventBase -from core.workflow.node_events.node import StreamCompletedEvent -from core.workflow.nodes.base.node import Node -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.node_events.base import NodeEventBase +from dify_graph.node_events.node import StreamCompletedEvent +from dify_graph.nodes.base.node import Node +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, HumanInputFormEntity, HumanInputFormRepository, ) -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.ext_database import db from libs.datetime_utils import naive_utc_now @@ -29,8 +29,8 @@ from .entities import DeliveryChannelConfig, HumanInputNodeData, apply_debug_ema from .enums import DeliveryMethodType, HumanInputFormStatus, PlaceholderType if TYPE_CHECKING: - from core.workflow.entities.graph_init_params import GraphInitParams - from core.workflow.runtime.graph_runtime_state import GraphRuntimeState + from dify_graph.entities.graph_init_params import GraphInitParams + from dify_graph.runtime.graph_runtime_state import GraphRuntimeState _SELECTED_BRANCH_KEY = "selected_branch" diff --git a/api/core/workflow/nodes/if_else/__init__.py b/api/dify_graph/nodes/if_else/__init__.py similarity index 100% rename from api/core/workflow/nodes/if_else/__init__.py rename to api/dify_graph/nodes/if_else/__init__.py diff --git a/api/core/workflow/nodes/if_else/entities.py b/api/dify_graph/nodes/if_else/entities.py similarity index 82% rename from api/core/workflow/nodes/if_else/entities.py rename to api/dify_graph/nodes/if_else/entities.py index b22bd6f508..4733944039 100644 --- a/api/core/workflow/nodes/if_else/entities.py +++ b/api/dify_graph/nodes/if_else/entities.py @@ -2,8 +2,8 @@ from typing import Literal from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData -from core.workflow.utils.condition.entities import Condition +from dify_graph.nodes.base import BaseNodeData +from dify_graph.utils.condition.entities import Condition class IfElseNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/if_else/if_else_node.py b/api/dify_graph/nodes/if_else/if_else_node.py similarity index 90% rename from api/core/workflow/nodes/if_else/if_else_node.py rename to api/dify_graph/nodes/if_else/if_else_node.py index cda5f1dd42..3c5a33e2b7 100644 --- a/api/core/workflow/nodes/if_else/if_else_node.py +++ b/api/dify_graph/nodes/if_else/if_else_node.py @@ -3,13 +3,13 @@ from typing import Any, Literal from typing_extensions import deprecated -from core.workflow.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.if_else.entities import IfElseNodeData -from core.workflow.runtime import VariablePool -from core.workflow.utils.condition.entities import Condition -from core.workflow.utils.condition.processor import ConditionProcessor +from dify_graph.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.if_else.entities import IfElseNodeData +from dify_graph.runtime import VariablePool +from dify_graph.utils.condition.entities import Condition +from dify_graph.utils.condition.processor import ConditionProcessor class IfElseNode(Node[IfElseNodeData]): diff --git a/api/core/workflow/nodes/iteration/__init__.py b/api/dify_graph/nodes/iteration/__init__.py similarity index 100% rename from api/core/workflow/nodes/iteration/__init__.py rename to api/dify_graph/nodes/iteration/__init__.py diff --git a/api/core/workflow/nodes/iteration/entities.py b/api/dify_graph/nodes/iteration/entities.py similarity index 94% rename from api/core/workflow/nodes/iteration/entities.py rename to api/dify_graph/nodes/iteration/entities.py index 63a41ec755..a31b05463e 100644 --- a/api/core/workflow/nodes/iteration/entities.py +++ b/api/dify_graph/nodes/iteration/entities.py @@ -3,7 +3,7 @@ from typing import Any from pydantic import Field -from core.workflow.nodes.base import BaseIterationNodeData, BaseIterationState, BaseNodeData +from dify_graph.nodes.base import BaseIterationNodeData, BaseIterationState, BaseNodeData class ErrorHandleMode(StrEnum): diff --git a/api/core/workflow/nodes/iteration/exc.py b/api/dify_graph/nodes/iteration/exc.py similarity index 100% rename from api/core/workflow/nodes/iteration/exc.py rename to api/dify_graph/nodes/iteration/exc.py diff --git a/api/core/workflow/nodes/iteration/iteration_node.py b/api/dify_graph/nodes/iteration/iteration_node.py similarity index 95% rename from api/core/workflow/nodes/iteration/iteration_node.py rename to api/dify_graph/nodes/iteration/iteration_node.py index 54b0561dd8..5ac25b493d 100644 --- a/api/core/workflow/nodes/iteration/iteration_node.py +++ b/api/dify_graph/nodes/iteration/iteration_node.py @@ -7,20 +7,20 @@ from typing import TYPE_CHECKING, Any, NewType, cast from typing_extensions import TypeIs from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID -from core.workflow.enums import ( +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID +from dify_graph.enums import ( NodeExecutionType, NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphNodeEventBase, GraphRunFailedEvent, GraphRunPartialSucceededEvent, GraphRunSucceededEvent, ) -from core.workflow.node_events import ( +from dify_graph.node_events import ( IterationFailedEvent, IterationNextEvent, IterationStartedEvent, @@ -29,13 +29,13 @@ from core.workflow.node_events import ( NodeRunResult, StreamCompletedEvent, ) -from core.workflow.nodes.base import LLMUsageTrackingMixin -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData -from core.workflow.runtime import VariablePool -from core.workflow.variables import IntegerVariable, NoneSegment -from core.workflow.variables.segments import ArrayAnySegment, ArraySegment -from core.workflow.variables.variables import Variable +from dify_graph.nodes.base import LLMUsageTrackingMixin +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.iteration.entities import ErrorHandleMode, IterationNodeData +from dify_graph.runtime import VariablePool +from dify_graph.variables import IntegerVariable, NoneSegment +from dify_graph.variables.segments import ArrayAnySegment, ArraySegment +from dify_graph.variables.variables import Variable from libs.datetime_utils import naive_utc_now from .exc import ( @@ -48,8 +48,8 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.context import IExecutionContext - from core.workflow.graph_engine import GraphEngine + from dify_graph.context import IExecutionContext + from dify_graph.graph_engine import GraphEngine logger = logging.getLogger(__name__) @@ -337,7 +337,7 @@ class IterationNode(LLMUsageTrackingMixin, Node[IterationNodeData]): def _capture_execution_context(self) -> "IExecutionContext": """Capture current execution context for parallel iterations.""" - from core.workflow.context import capture_current_context + from dify_graph.context import capture_current_context return capture_current_context() @@ -488,7 +488,7 @@ class IterationNode(LLMUsageTrackingMixin, Node[IterationNodeData]): # variable selector to variable mapping try: # Get node class - from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING + from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING node_type = NodeType(sub_node_config.get("data", {}).get("type")) if node_type not in NODE_TYPE_CLASSES_MAPPING: @@ -589,12 +589,12 @@ class IterationNode(LLMUsageTrackingMixin, Node[IterationNodeData]): def _create_graph_engine(self, index: int, item: object): # Import dependencies from core.app.workflow.layers.llm_quota import LLMQuotaLayer - from core.app.workflow.node_factory import DifyNodeFactory - from core.workflow.entities import GraphInitParams - from core.workflow.graph import Graph - from core.workflow.graph_engine import GraphEngine, GraphEngineConfig - from core.workflow.graph_engine.command_channels import InMemoryChannel - from core.workflow.runtime import GraphRuntimeState + from core.workflow.node_factory import DifyNodeFactory + from dify_graph.entities import GraphInitParams + from dify_graph.graph import Graph + from dify_graph.graph_engine import GraphEngine, GraphEngineConfig + from dify_graph.graph_engine.command_channels import InMemoryChannel + from dify_graph.runtime import GraphRuntimeState # Create GraphInitParams from node attributes graph_init_params = GraphInitParams( diff --git a/api/core/workflow/nodes/iteration/iteration_start_node.py b/api/dify_graph/nodes/iteration/iteration_start_node.py similarity index 60% rename from api/core/workflow/nodes/iteration/iteration_start_node.py rename to api/dify_graph/nodes/iteration/iteration_start_node.py index 30d9fccbfd..2e1f555ed2 100644 --- a/api/core/workflow/nodes/iteration/iteration_start_node.py +++ b/api/dify_graph/nodes/iteration/iteration_start_node.py @@ -1,7 +1,7 @@ -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.iteration.entities import IterationStartNodeData +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.iteration.entities import IterationStartNodeData class IterationStartNode(Node[IterationStartNodeData]): diff --git a/api/core/workflow/nodes/knowledge_index/__init__.py b/api/dify_graph/nodes/knowledge_index/__init__.py similarity index 100% rename from api/core/workflow/nodes/knowledge_index/__init__.py rename to api/dify_graph/nodes/knowledge_index/__init__.py diff --git a/api/core/workflow/nodes/knowledge_index/entities.py b/api/dify_graph/nodes/knowledge_index/entities.py similarity index 98% rename from api/core/workflow/nodes/knowledge_index/entities.py rename to api/dify_graph/nodes/knowledge_index/entities.py index bfeb9b5b79..493b5eadd8 100644 --- a/api/core/workflow/nodes/knowledge_index/entities.py +++ b/api/dify_graph/nodes/knowledge_index/entities.py @@ -3,7 +3,7 @@ from typing import Literal, Union from pydantic import BaseModel from core.rag.retrieval.retrieval_methods import RetrievalMethod -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class RerankingModelConfig(BaseModel): diff --git a/api/core/workflow/nodes/knowledge_index/exc.py b/api/dify_graph/nodes/knowledge_index/exc.py similarity index 100% rename from api/core/workflow/nodes/knowledge_index/exc.py rename to api/dify_graph/nodes/knowledge_index/exc.py diff --git a/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py b/api/dify_graph/nodes/knowledge_index/knowledge_index_node.py similarity index 90% rename from api/core/workflow/nodes/knowledge_index/knowledge_index_node.py rename to api/dify_graph/nodes/knowledge_index/knowledge_index_node.py index 8fb5b99454..e1e534911f 100644 --- a/api/core/workflow/nodes/knowledge_index/knowledge_index_node.py +++ b/api/dify_graph/nodes/knowledge_index/knowledge_index_node.py @@ -3,13 +3,13 @@ from collections.abc import Mapping from typing import TYPE_CHECKING, Any from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.enums import NodeExecutionType, NodeType, SystemVariableKey -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.template import Template -from core.workflow.repositories.index_processor_protocol import IndexProcessorProtocol -from core.workflow.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.enums import NodeExecutionType, NodeType, SystemVariableKey +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.template import Template +from dify_graph.repositories.index_processor_protocol import IndexProcessorProtocol +from dify_graph.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol from .entities import KnowledgeIndexNodeData from .exc import ( @@ -17,8 +17,8 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState logger = logging.getLogger(__name__) diff --git a/api/core/workflow/nodes/knowledge_retrieval/__init__.py b/api/dify_graph/nodes/knowledge_retrieval/__init__.py similarity index 100% rename from api/core/workflow/nodes/knowledge_retrieval/__init__.py rename to api/dify_graph/nodes/knowledge_retrieval/__init__.py diff --git a/api/core/workflow/nodes/knowledge_retrieval/entities.py b/api/dify_graph/nodes/knowledge_retrieval/entities.py similarity index 96% rename from api/core/workflow/nodes/knowledge_retrieval/entities.py rename to api/dify_graph/nodes/knowledge_retrieval/entities.py index 86bb2495e7..c3059897c7 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/entities.py +++ b/api/dify_graph/nodes/knowledge_retrieval/entities.py @@ -3,8 +3,8 @@ from typing import Literal from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.llm.entities import ModelConfig, VisionConfig +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.llm.entities import ModelConfig, VisionConfig class RerankingModelConfig(BaseModel): diff --git a/api/core/workflow/nodes/knowledge_retrieval/exc.py b/api/dify_graph/nodes/knowledge_retrieval/exc.py similarity index 100% rename from api/core/workflow/nodes/knowledge_retrieval/exc.py rename to api/dify_graph/nodes/knowledge_retrieval/exc.py diff --git a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py similarity index 94% rename from api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py rename to api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 0cfd39e485..86e4a35901 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -5,23 +5,23 @@ from typing import TYPE_CHECKING, Any, Literal from core.app.app_config.entities import DatasetRetrieveConfigEntity from core.model_runtime.entities.llm_entities import LLMUsage from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.entities import GraphInitParams -from core.workflow.enums import ( +from dify_graph.entities import GraphInitParams +from dify_graph.enums import ( NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base import LLMUsageTrackingMixin -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.llm.file_saver import FileSaverImpl, LLMFileSaver -from core.workflow.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest, RAGRetrievalProtocol, Source -from core.workflow.variables import ( +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base import LLMUsageTrackingMixin +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.llm.file_saver import FileSaverImpl, LLMFileSaver +from dify_graph.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest, RAGRetrievalProtocol, Source +from dify_graph.variables import ( ArrayFileSegment, FileSegment, StringSegment, ) -from core.workflow.variables.segments import ArrayObjectSegment +from dify_graph.variables.segments import ArrayObjectSegment from .entities import KnowledgeRetrievalNodeData from .exc import ( @@ -30,8 +30,8 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.file.models import File - from core.workflow.runtime import GraphRuntimeState + from dify_graph.file.models import File + from dify_graph.runtime import GraphRuntimeState logger = logging.getLogger(__name__) diff --git a/api/core/workflow/nodes/knowledge_retrieval/template_prompts.py b/api/dify_graph/nodes/knowledge_retrieval/template_prompts.py similarity index 100% rename from api/core/workflow/nodes/knowledge_retrieval/template_prompts.py rename to api/dify_graph/nodes/knowledge_retrieval/template_prompts.py diff --git a/api/core/workflow/nodes/list_operator/__init__.py b/api/dify_graph/nodes/list_operator/__init__.py similarity index 100% rename from api/core/workflow/nodes/list_operator/__init__.py rename to api/dify_graph/nodes/list_operator/__init__.py diff --git a/api/core/workflow/nodes/list_operator/entities.py b/api/dify_graph/nodes/list_operator/entities.py similarity index 96% rename from api/core/workflow/nodes/list_operator/entities.py rename to api/dify_graph/nodes/list_operator/entities.py index e51a91f07f..0fdd85f210 100644 --- a/api/core/workflow/nodes/list_operator/entities.py +++ b/api/dify_graph/nodes/list_operator/entities.py @@ -3,7 +3,7 @@ from enum import StrEnum from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class FilterOperator(StrEnum): diff --git a/api/core/workflow/nodes/list_operator/exc.py b/api/dify_graph/nodes/list_operator/exc.py similarity index 100% rename from api/core/workflow/nodes/list_operator/exc.py rename to api/dify_graph/nodes/list_operator/exc.py diff --git a/api/core/workflow/nodes/list_operator/node.py b/api/dify_graph/nodes/list_operator/node.py similarity index 97% rename from api/core/workflow/nodes/list_operator/node.py rename to api/dify_graph/nodes/list_operator/node.py index d9ef16fbe7..d2fdadc29c 100644 --- a/api/core/workflow/nodes/list_operator/node.py +++ b/api/dify_graph/nodes/list_operator/node.py @@ -1,12 +1,12 @@ from collections.abc import Callable, Sequence from typing import Any, TypeAlias, TypeVar -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.file import File -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment -from core.workflow.variables.segments import ArrayAnySegment, ArrayBooleanSegment, ArraySegment +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.file import File +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment +from dify_graph.variables.segments import ArrayAnySegment, ArrayBooleanSegment, ArraySegment from .entities import FilterOperator, ListOperatorNodeData, Order from .exc import InvalidConditionError, InvalidFilterValueError, InvalidKeyError, ListOperatorError diff --git a/api/core/workflow/nodes/llm/__init__.py b/api/dify_graph/nodes/llm/__init__.py similarity index 100% rename from api/core/workflow/nodes/llm/__init__.py rename to api/dify_graph/nodes/llm/__init__.py diff --git a/api/core/workflow/nodes/llm/entities.py b/api/dify_graph/nodes/llm/entities.py similarity index 96% rename from api/core/workflow/nodes/llm/entities.py rename to api/dify_graph/nodes/llm/entities.py index fe6f2290aa..74e90fdc7d 100644 --- a/api/core/workflow/nodes/llm/entities.py +++ b/api/dify_graph/nodes/llm/entities.py @@ -5,8 +5,8 @@ from pydantic import BaseModel, Field, field_validator from core.model_runtime.entities import ImagePromptMessageContent, LLMMode from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.base.entities import VariableSelector +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.base.entities import VariableSelector class ModelConfig(BaseModel): diff --git a/api/core/workflow/nodes/llm/exc.py b/api/dify_graph/nodes/llm/exc.py similarity index 100% rename from api/core/workflow/nodes/llm/exc.py rename to api/dify_graph/nodes/llm/exc.py diff --git a/api/core/workflow/nodes/llm/file_saver.py b/api/dify_graph/nodes/llm/file_saver.py similarity index 98% rename from api/core/workflow/nodes/llm/file_saver.py rename to api/dify_graph/nodes/llm/file_saver.py index 3c06ab7d81..b4f64f4093 100644 --- a/api/core/workflow/nodes/llm/file_saver.py +++ b/api/dify_graph/nodes/llm/file_saver.py @@ -7,7 +7,7 @@ from constants.mimetypes import DEFAULT_EXTENSION, DEFAULT_MIME_TYPE from core.helper import ssrf_proxy from core.tools.signature import sign_tool_file from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from extensions.ext_database import db as global_db diff --git a/api/core/workflow/nodes/llm/llm_utils.py b/api/dify_graph/nodes/llm/llm_utils.py similarity index 93% rename from api/core/workflow/nodes/llm/llm_utils.py rename to api/dify_graph/nodes/llm/llm_utils.py index 72f150d920..fb64630cd8 100644 --- a/api/core/workflow/nodes/llm/llm_utils.py +++ b/api/dify_graph/nodes/llm/llm_utils.py @@ -11,9 +11,9 @@ from core.model_runtime.entities.message_entities import ( from core.model_runtime.entities.model_entities import AIModelEntity from core.model_runtime.memory import PromptMessageMemory from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.workflow.file.models import File -from core.workflow.runtime import VariablePool -from core.workflow.variables.segments import ArrayAnySegment, ArrayFileSegment, FileSegment, NoneSegment +from dify_graph.file.models import File +from dify_graph.runtime import VariablePool +from dify_graph.variables.segments import ArrayAnySegment, ArrayFileSegment, FileSegment, NoneSegment from .exc import InvalidVariableTypeError diff --git a/api/core/workflow/nodes/llm/node.py b/api/dify_graph/nodes/llm/node.py similarity index 98% rename from api/core/workflow/nodes/llm/node.py rename to api/dify_graph/nodes/llm/node.py index c06db0dc16..0e243bfd3b 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/dify_graph/nodes/llm/node.py @@ -43,16 +43,16 @@ from core.prompt.entities.advanced_prompt_entities import CompletionModelPromptT from core.prompt.utils.prompt_message_util import PromptMessageUtil from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.tools.signature import sign_upload_file -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities import GraphInitParams -from core.workflow.enums import ( +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.entities import GraphInitParams +from dify_graph.enums import ( NodeType, SystemVariableKey, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.file import File, FileTransferMethod, FileType, file_manager -from core.workflow.node_events import ( +from dify_graph.file import File, FileTransferMethod, FileType, file_manager +from dify_graph.node_events import ( ModelInvokeCompletedEvent, NodeEventBase, NodeRunResult, @@ -60,12 +60,12 @@ from core.workflow.node_events import ( StreamChunkEvent, StreamCompletedEvent, ) -from core.workflow.nodes.base.entities import VariableSelector -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory -from core.workflow.runtime import VariablePool -from core.workflow.variables import ( +from dify_graph.nodes.base.entities import VariableSelector +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.runtime import VariablePool +from dify_graph.variables import ( ArrayFileSegment, ArraySegment, FileSegment, @@ -95,8 +95,8 @@ from .exc import ( from .file_saver import FileSaverImpl, LLMFileSaver if TYPE_CHECKING: - from core.workflow.file.models import File - from core.workflow.runtime import GraphRuntimeState + from dify_graph.file.models import File + from dify_graph.runtime import GraphRuntimeState logger = logging.getLogger(__name__) diff --git a/api/core/workflow/nodes/llm/protocols.py b/api/dify_graph/nodes/llm/protocols.py similarity index 100% rename from api/core/workflow/nodes/llm/protocols.py rename to api/dify_graph/nodes/llm/protocols.py diff --git a/api/core/workflow/nodes/loop/__init__.py b/api/dify_graph/nodes/loop/__init__.py similarity index 100% rename from api/core/workflow/nodes/loop/__init__.py rename to api/dify_graph/nodes/loop/__init__.py diff --git a/api/core/workflow/nodes/loop/entities.py b/api/dify_graph/nodes/loop/entities.py similarity index 91% rename from api/core/workflow/nodes/loop/entities.py rename to api/dify_graph/nodes/loop/entities.py index 4090f27799..b4a8518048 100644 --- a/api/core/workflow/nodes/loop/entities.py +++ b/api/dify_graph/nodes/loop/entities.py @@ -3,9 +3,9 @@ from typing import Annotated, Any, Literal from pydantic import AfterValidator, BaseModel, Field, field_validator -from core.workflow.nodes.base import BaseLoopNodeData, BaseLoopState, BaseNodeData -from core.workflow.utils.condition.entities import Condition -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.base import BaseLoopNodeData, BaseLoopState, BaseNodeData +from dify_graph.utils.condition.entities import Condition +from dify_graph.variables.types import SegmentType _VALID_VAR_TYPE = frozenset( [ diff --git a/api/core/workflow/nodes/loop/loop_end_node.py b/api/dify_graph/nodes/loop/loop_end_node.py similarity index 59% rename from api/core/workflow/nodes/loop/loop_end_node.py rename to api/dify_graph/nodes/loop/loop_end_node.py index 1e3e317b53..73ac5da927 100644 --- a/api/core/workflow/nodes/loop/loop_end_node.py +++ b/api/dify_graph/nodes/loop/loop_end_node.py @@ -1,7 +1,7 @@ -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.loop.entities import LoopEndNodeData +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.loop.entities import LoopEndNodeData class LoopEndNode(Node[LoopEndNodeData]): diff --git a/api/core/workflow/nodes/loop/loop_node.py b/api/dify_graph/nodes/loop/loop_node.py similarity index 95% rename from api/core/workflow/nodes/loop/loop_node.py rename to api/dify_graph/nodes/loop/loop_node.py index 40ec0cf8b1..9bd79b7947 100644 --- a/api/core/workflow/nodes/loop/loop_node.py +++ b/api/dify_graph/nodes/loop/loop_node.py @@ -6,18 +6,18 @@ from datetime import datetime from typing import TYPE_CHECKING, Any, Literal, cast from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import ( +from dify_graph.enums import ( NodeExecutionType, NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphNodeEventBase, GraphRunFailedEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import ( +from dify_graph.node_events import ( LoopFailedEvent, LoopNextEvent, LoopStartedEvent, @@ -26,16 +26,16 @@ from core.workflow.node_events import ( NodeRunResult, StreamCompletedEvent, ) -from core.workflow.nodes.base import LLMUsageTrackingMixin -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.loop.entities import LoopCompletedReason, LoopNodeData, LoopVariableData -from core.workflow.utils.condition.processor import ConditionProcessor -from core.workflow.variables import Segment, SegmentType +from dify_graph.nodes.base import LLMUsageTrackingMixin +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.loop.entities import LoopCompletedReason, LoopNodeData, LoopVariableData +from dify_graph.utils.condition.processor import ConditionProcessor +from dify_graph.variables import Segment, SegmentType from factories.variable_factory import TypeMismatchError, build_segment_with_type, segment_to_variable from libs.datetime_utils import naive_utc_now if TYPE_CHECKING: - from core.workflow.graph_engine import GraphEngine + from dify_graph.graph_engine import GraphEngine logger = logging.getLogger(__name__) @@ -318,7 +318,7 @@ class LoopNode(LLMUsageTrackingMixin, Node[LoopNodeData]): # variable selector to variable mapping try: # Get node class - from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING + from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING node_type = NodeType(sub_node_config.get("data", {}).get("type")) if node_type not in NODE_TYPE_CLASSES_MAPPING: @@ -414,12 +414,12 @@ class LoopNode(LLMUsageTrackingMixin, Node[LoopNodeData]): def _create_graph_engine(self, start_at: datetime, root_node_id: str): # Import dependencies from core.app.workflow.layers.llm_quota import LLMQuotaLayer - from core.app.workflow.node_factory import DifyNodeFactory - from core.workflow.entities import GraphInitParams - from core.workflow.graph import Graph - from core.workflow.graph_engine import GraphEngine, GraphEngineConfig - from core.workflow.graph_engine.command_channels import InMemoryChannel - from core.workflow.runtime import GraphRuntimeState + from core.workflow.node_factory import DifyNodeFactory + from dify_graph.entities import GraphInitParams + from dify_graph.graph import Graph + from dify_graph.graph_engine import GraphEngine, GraphEngineConfig + from dify_graph.graph_engine.command_channels import InMemoryChannel + from dify_graph.runtime import GraphRuntimeState # Create GraphInitParams from node attributes graph_init_params = GraphInitParams( diff --git a/api/core/workflow/nodes/loop/loop_start_node.py b/api/dify_graph/nodes/loop/loop_start_node.py similarity index 59% rename from api/core/workflow/nodes/loop/loop_start_node.py rename to api/dify_graph/nodes/loop/loop_start_node.py index 95bb5c4018..f469c8286e 100644 --- a/api/core/workflow/nodes/loop/loop_start_node.py +++ b/api/dify_graph/nodes/loop/loop_start_node.py @@ -1,7 +1,7 @@ -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.loop.entities import LoopStartNodeData +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.loop.entities import LoopStartNodeData class LoopStartNode(Node[LoopStartNodeData]): diff --git a/api/core/workflow/nodes/node_mapping.py b/api/dify_graph/nodes/node_mapping.py similarity index 65% rename from api/core/workflow/nodes/node_mapping.py rename to api/dify_graph/nodes/node_mapping.py index 85df543a2a..8e5405f1aa 100644 --- a/api/core/workflow/nodes/node_mapping.py +++ b/api/dify_graph/nodes/node_mapping.py @@ -1,9 +1,9 @@ from collections.abc import Mapping -from core.workflow.enums import NodeType -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.nodes.base.node import Node LATEST_VERSION = "latest" -# Mapping is built by Node.get_node_type_classes_mapping(), which imports and walks core.workflow.nodes +# Mapping is built by Node.get_node_type_classes_mapping(), which imports and walks dify_graph.nodes NODE_TYPE_CLASSES_MAPPING: Mapping[NodeType, Mapping[str, type[Node]]] = Node.get_node_type_classes_mapping() diff --git a/api/core/workflow/nodes/parameter_extractor/__init__.py b/api/dify_graph/nodes/parameter_extractor/__init__.py similarity index 100% rename from api/core/workflow/nodes/parameter_extractor/__init__.py rename to api/dify_graph/nodes/parameter_extractor/__init__.py diff --git a/api/core/workflow/nodes/parameter_extractor/entities.py b/api/dify_graph/nodes/parameter_extractor/entities.py similarity index 95% rename from api/core/workflow/nodes/parameter_extractor/entities.py rename to api/dify_graph/nodes/parameter_extractor/entities.py index 90d78ae429..3b042710f9 100644 --- a/api/core/workflow/nodes/parameter_extractor/entities.py +++ b/api/dify_graph/nodes/parameter_extractor/entities.py @@ -8,9 +8,9 @@ from pydantic import ( ) from core.prompt.entities.advanced_prompt_entities import MemoryConfig -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.llm.entities import ModelConfig, VisionConfig -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.llm.entities import ModelConfig, VisionConfig +from dify_graph.variables.types import SegmentType _OLD_BOOL_TYPE_NAME = "bool" _OLD_SELECT_TYPE_NAME = "select" diff --git a/api/core/workflow/nodes/parameter_extractor/exc.py b/api/dify_graph/nodes/parameter_extractor/exc.py similarity index 97% rename from api/core/workflow/nodes/parameter_extractor/exc.py rename to api/dify_graph/nodes/parameter_extractor/exc.py index 5a58780575..c25b809d1c 100644 --- a/api/core/workflow/nodes/parameter_extractor/exc.py +++ b/api/dify_graph/nodes/parameter_extractor/exc.py @@ -1,6 +1,6 @@ from typing import Any -from core.workflow.variables.types import SegmentType +from dify_graph.variables.types import SegmentType class ParameterExtractorNodeError(ValueError): diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py similarity index 98% rename from api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py rename to api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py index 4272b98116..626f38fc9b 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py @@ -24,18 +24,18 @@ from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil -from core.workflow.enums import ( +from dify_graph.enums import ( NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.file import File -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base import variable_template_parser -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.llm import llm_utils -from core.workflow.runtime import VariablePool -from core.workflow.variables.types import ArrayValidation, SegmentType +from dify_graph.file import File +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base import variable_template_parser +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.llm import llm_utils +from dify_graph.runtime import VariablePool +from dify_graph.variables.types import ArrayValidation, SegmentType from factories.variable_factory import build_segment_with_type from .entities import ParameterExtractorNodeData @@ -64,9 +64,9 @@ from .prompts import ( logger = logging.getLogger(__name__) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory + from dify_graph.runtime import GraphRuntimeState def extract_json(text): diff --git a/api/core/workflow/nodes/parameter_extractor/prompts.py b/api/dify_graph/nodes/parameter_extractor/prompts.py similarity index 100% rename from api/core/workflow/nodes/parameter_extractor/prompts.py rename to api/dify_graph/nodes/parameter_extractor/prompts.py diff --git a/api/core/workflow/nodes/protocols.py b/api/dify_graph/nodes/protocols.py similarity index 96% rename from api/core/workflow/nodes/protocols.py rename to api/dify_graph/nodes/protocols.py index fda524d701..cc007150f1 100644 --- a/api/core/workflow/nodes/protocols.py +++ b/api/dify_graph/nodes/protocols.py @@ -2,7 +2,7 @@ from typing import Any, Protocol import httpx -from core.workflow.file import File +from dify_graph.file import File class HttpClientProtocol(Protocol): diff --git a/api/core/workflow/nodes/question_classifier/__init__.py b/api/dify_graph/nodes/question_classifier/__init__.py similarity index 100% rename from api/core/workflow/nodes/question_classifier/__init__.py rename to api/dify_graph/nodes/question_classifier/__init__.py diff --git a/api/core/workflow/nodes/question_classifier/entities.py b/api/dify_graph/nodes/question_classifier/entities.py similarity index 87% rename from api/core/workflow/nodes/question_classifier/entities.py rename to api/dify_graph/nodes/question_classifier/entities.py index edde30708a..03e0a0ac53 100644 --- a/api/core/workflow/nodes/question_classifier/entities.py +++ b/api/dify_graph/nodes/question_classifier/entities.py @@ -1,8 +1,8 @@ from pydantic import BaseModel, Field from core.prompt.entities.advanced_prompt_entities import MemoryConfig -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.llm import ModelConfig, VisionConfig +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.llm import ModelConfig, VisionConfig class ClassConfig(BaseModel): diff --git a/api/core/workflow/nodes/question_classifier/exc.py b/api/dify_graph/nodes/question_classifier/exc.py similarity index 100% rename from api/core/workflow/nodes/question_classifier/exc.py rename to api/dify_graph/nodes/question_classifier/exc.py diff --git a/api/core/workflow/nodes/question_classifier/question_classifier_node.py b/api/dify_graph/nodes/question_classifier/question_classifier_node.py similarity index 95% rename from api/core/workflow/nodes/question_classifier/question_classifier_node.py rename to api/dify_graph/nodes/question_classifier/question_classifier_node.py index 6005bff1a6..59b0a97496 100644 --- a/api/core/workflow/nodes/question_classifier/question_classifier_node.py +++ b/api/dify_graph/nodes/question_classifier/question_classifier_node.py @@ -9,25 +9,25 @@ from core.model_runtime.memory import PromptMessageMemory from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil -from core.workflow.entities import GraphInitParams -from core.workflow.enums import ( +from dify_graph.entities import GraphInitParams +from dify_graph.enums import ( NodeExecutionType, NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.node_events import ModelInvokeCompletedEvent, NodeRunResult -from core.workflow.nodes.base.entities import VariableSelector -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.nodes.llm import ( +from dify_graph.node_events import ModelInvokeCompletedEvent, NodeRunResult +from dify_graph.nodes.base.entities import VariableSelector +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.nodes.llm import ( LLMNode, LLMNodeChatModelMessage, LLMNodeCompletionModelPromptTemplate, llm_utils, ) -from core.workflow.nodes.llm.file_saver import FileSaverImpl, LLMFileSaver -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.nodes.llm.file_saver import FileSaverImpl, LLMFileSaver +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory from libs.json_in_md_parser import parse_and_check_json_markdown from .entities import QuestionClassifierNodeData @@ -43,8 +43,8 @@ from .template_prompts import ( ) if TYPE_CHECKING: - from core.workflow.file.models import File - from core.workflow.runtime import GraphRuntimeState + from dify_graph.file.models import File + from dify_graph.runtime import GraphRuntimeState class QuestionClassifierNode(Node[QuestionClassifierNodeData]): diff --git a/api/core/workflow/nodes/question_classifier/template_prompts.py b/api/dify_graph/nodes/question_classifier/template_prompts.py similarity index 100% rename from api/core/workflow/nodes/question_classifier/template_prompts.py rename to api/dify_graph/nodes/question_classifier/template_prompts.py diff --git a/api/core/workflow/nodes/start/__init__.py b/api/dify_graph/nodes/start/__init__.py similarity index 100% rename from api/core/workflow/nodes/start/__init__.py rename to api/dify_graph/nodes/start/__init__.py diff --git a/api/core/workflow/nodes/start/entities.py b/api/dify_graph/nodes/start/entities.py similarity index 64% rename from api/core/workflow/nodes/start/entities.py rename to api/dify_graph/nodes/start/entities.py index 3a99e2cbc2..0df832740e 100644 --- a/api/core/workflow/nodes/start/entities.py +++ b/api/dify_graph/nodes/start/entities.py @@ -2,8 +2,8 @@ from collections.abc import Sequence from pydantic import Field -from core.workflow.nodes.base import BaseNodeData -from core.workflow.variables.input_entities import VariableEntity +from dify_graph.nodes.base import BaseNodeData +from dify_graph.variables.input_entities import VariableEntity class StartNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/start/start_node.py b/api/dify_graph/nodes/start/start_node.py similarity index 84% rename from api/core/workflow/nodes/start/start_node.py rename to api/dify_graph/nodes/start/start_node.py index 4e5545d330..c09ead0124 100644 --- a/api/core/workflow/nodes/start/start_node.py +++ b/api/dify_graph/nodes/start/start_node.py @@ -2,12 +2,12 @@ from typing import Any from jsonschema import Draft7Validator, ValidationError -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.variables.input_entities import VariableEntityType +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.enums import NodeExecutionType, NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.variables.input_entities import VariableEntityType class StartNode(Node[StartNodeData]): diff --git a/api/core/workflow/nodes/template_transform/__init__.py b/api/dify_graph/nodes/template_transform/__init__.py similarity index 100% rename from api/core/workflow/nodes/template_transform/__init__.py rename to api/dify_graph/nodes/template_transform/__init__.py diff --git a/api/core/workflow/nodes/template_transform/entities.py b/api/dify_graph/nodes/template_transform/entities.py similarity index 57% rename from api/core/workflow/nodes/template_transform/entities.py rename to api/dify_graph/nodes/template_transform/entities.py index efb7a72f59..123fd41f81 100644 --- a/api/core/workflow/nodes/template_transform/entities.py +++ b/api/dify_graph/nodes/template_transform/entities.py @@ -1,5 +1,5 @@ -from core.workflow.nodes.base import BaseNodeData -from core.workflow.nodes.base.entities import VariableSelector +from dify_graph.nodes.base import BaseNodeData +from dify_graph.nodes.base.entities import VariableSelector class TemplateTransformNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/template_transform/template_renderer.py b/api/dify_graph/nodes/template_transform/template_renderer.py similarity index 100% rename from api/core/workflow/nodes/template_transform/template_renderer.py rename to api/dify_graph/nodes/template_transform/template_renderer.py diff --git a/api/core/workflow/nodes/template_transform/template_transform_node.py b/api/dify_graph/nodes/template_transform/template_transform_node.py similarity index 88% rename from api/core/workflow/nodes/template_transform/template_transform_node.py rename to api/dify_graph/nodes/template_transform/template_transform_node.py index 3dc8afd9be..b42bf02d08 100644 --- a/api/core/workflow/nodes/template_transform/template_transform_node.py +++ b/api/dify_graph/nodes/template_transform/template_transform_node.py @@ -1,19 +1,19 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData -from core.workflow.nodes.template_transform.template_renderer import ( +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.template_transform.entities import TemplateTransformNodeData +from dify_graph.nodes.template_transform.template_renderer import ( CodeExecutorJinja2TemplateRenderer, Jinja2TemplateRenderer, TemplateRenderError, ) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState DEFAULT_TEMPLATE_TRANSFORM_MAX_OUTPUT_LENGTH = 400_000 diff --git a/api/core/workflow/nodes/tool/__init__.py b/api/dify_graph/nodes/tool/__init__.py similarity index 100% rename from api/core/workflow/nodes/tool/__init__.py rename to api/dify_graph/nodes/tool/__init__.py diff --git a/api/core/workflow/nodes/tool/entities.py b/api/dify_graph/nodes/tool/entities.py similarity index 98% rename from api/core/workflow/nodes/tool/entities.py rename to api/dify_graph/nodes/tool/entities.py index 8fe33c240a..f15dabdeeb 100644 --- a/api/core/workflow/nodes/tool/entities.py +++ b/api/dify_graph/nodes/tool/entities.py @@ -4,7 +4,7 @@ from pydantic import BaseModel, field_validator from pydantic_core.core_schema import ValidationInfo from core.tools.entities.tool_entities import ToolProviderType -from core.workflow.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.entities import BaseNodeData class ToolEntity(BaseModel): diff --git a/api/core/workflow/nodes/tool/exc.py b/api/dify_graph/nodes/tool/exc.py similarity index 100% rename from api/core/workflow/nodes/tool/exc.py rename to api/dify_graph/nodes/tool/exc.py diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/dify_graph/nodes/tool/tool_node.py similarity index 97% rename from api/core/workflow/nodes/tool/tool_node.py rename to api/dify_graph/nodes/tool/tool_node.py index 0d7270a282..3c072978e9 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/dify_graph/nodes/tool/tool_node.py @@ -11,18 +11,18 @@ from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter from core.tools.errors import ToolInvokeError from core.tools.tool_engine import ToolEngine from core.tools.utils.message_transformer import ToolFileMessageTransformer -from core.workflow.enums import ( +from dify_graph.enums import ( NodeType, SystemVariableKey, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.file import File, FileTransferMethod -from core.workflow.node_events import NodeEventBase, NodeRunResult, StreamChunkEvent, StreamCompletedEvent -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.base.variable_template_parser import VariableTemplateParser -from core.workflow.variables.segments import ArrayAnySegment, ArrayFileSegment -from core.workflow.variables.variables import ArrayAnyVariable +from dify_graph.file import File, FileTransferMethod +from dify_graph.node_events import NodeEventBase, NodeRunResult, StreamChunkEvent, StreamCompletedEvent +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser +from dify_graph.variables.segments import ArrayAnySegment, ArrayFileSegment +from dify_graph.variables.variables import ArrayAnyVariable from extensions.ext_database import db from factories import file_factory from models import ToolFile @@ -36,7 +36,7 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.runtime import VariablePool + from dify_graph.runtime import VariablePool class ToolNode(Node[ToolNodeData]): diff --git a/api/core/workflow/nodes/trigger_plugin/__init__.py b/api/dify_graph/nodes/trigger_plugin/__init__.py similarity index 100% rename from api/core/workflow/nodes/trigger_plugin/__init__.py rename to api/dify_graph/nodes/trigger_plugin/__init__.py diff --git a/api/core/workflow/nodes/trigger_plugin/entities.py b/api/dify_graph/nodes/trigger_plugin/entities.py similarity index 95% rename from api/core/workflow/nodes/trigger_plugin/entities.py rename to api/dify_graph/nodes/trigger_plugin/entities.py index 6c53acee4f..75d10ecaa4 100644 --- a/api/core/workflow/nodes/trigger_plugin/entities.py +++ b/api/dify_graph/nodes/trigger_plugin/entities.py @@ -4,8 +4,8 @@ from typing import Any, Literal, Union from pydantic import BaseModel, Field, ValidationInfo, field_validator from core.trigger.entities.entities import EventParameter -from core.workflow.nodes.base.entities import BaseNodeData -from core.workflow.nodes.trigger_plugin.exc import TriggerEventParameterError +from dify_graph.nodes.base.entities import BaseNodeData +from dify_graph.nodes.trigger_plugin.exc import TriggerEventParameterError class TriggerEventNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/trigger_plugin/exc.py b/api/dify_graph/nodes/trigger_plugin/exc.py similarity index 100% rename from api/core/workflow/nodes/trigger_plugin/exc.py rename to api/dify_graph/nodes/trigger_plugin/exc.py diff --git a/api/core/workflow/nodes/trigger_plugin/trigger_event_node.py b/api/dify_graph/nodes/trigger_plugin/trigger_event_node.py similarity index 85% rename from api/core/workflow/nodes/trigger_plugin/trigger_event_node.py rename to api/dify_graph/nodes/trigger_plugin/trigger_event_node.py index e11cb30a7f..b4f1116f7e 100644 --- a/api/core/workflow/nodes/trigger_plugin/trigger_event_node.py +++ b/api/dify_graph/nodes/trigger_plugin/trigger_event_node.py @@ -1,10 +1,10 @@ from collections.abc import Mapping -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.enums import NodeExecutionType, NodeType -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.enums import NodeExecutionType, NodeType +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node from .entities import TriggerEventNodeData diff --git a/api/dify_graph/nodes/trigger_schedule/__init__.py b/api/dify_graph/nodes/trigger_schedule/__init__.py new file mode 100644 index 0000000000..c9b3ae6a0d --- /dev/null +++ b/api/dify_graph/nodes/trigger_schedule/__init__.py @@ -0,0 +1,3 @@ +from dify_graph.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode + +__all__ = ["TriggerScheduleNode"] diff --git a/api/core/workflow/nodes/trigger_schedule/entities.py b/api/dify_graph/nodes/trigger_schedule/entities.py similarity index 97% rename from api/core/workflow/nodes/trigger_schedule/entities.py rename to api/dify_graph/nodes/trigger_schedule/entities.py index a515d02d55..6daadc7666 100644 --- a/api/core/workflow/nodes/trigger_schedule/entities.py +++ b/api/dify_graph/nodes/trigger_schedule/entities.py @@ -2,7 +2,7 @@ from typing import Literal, Union from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class TriggerScheduleNodeData(BaseNodeData): diff --git a/api/core/workflow/nodes/trigger_schedule/exc.py b/api/dify_graph/nodes/trigger_schedule/exc.py similarity index 90% rename from api/core/workflow/nodes/trigger_schedule/exc.py rename to api/dify_graph/nodes/trigger_schedule/exc.py index 2f99880ff1..caea6241e4 100644 --- a/api/core/workflow/nodes/trigger_schedule/exc.py +++ b/api/dify_graph/nodes/trigger_schedule/exc.py @@ -1,4 +1,4 @@ -from core.workflow.nodes.base.exc import BaseNodeError +from dify_graph.nodes.base.exc import BaseNodeError class ScheduleNodeError(BaseNodeError): diff --git a/api/core/workflow/nodes/trigger_schedule/trigger_schedule_node.py b/api/dify_graph/nodes/trigger_schedule/trigger_schedule_node.py similarity index 77% rename from api/core/workflow/nodes/trigger_schedule/trigger_schedule_node.py rename to api/dify_graph/nodes/trigger_schedule/trigger_schedule_node.py index fb5c8a4dce..7e92eb3f4f 100644 --- a/api/core/workflow/nodes/trigger_schedule/trigger_schedule_node.py +++ b/api/dify_graph/nodes/trigger_schedule/trigger_schedule_node.py @@ -1,11 +1,11 @@ from collections.abc import Mapping -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.enums import NodeExecutionType, NodeType -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.trigger_schedule.entities import TriggerScheduleNodeData +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.enums import NodeExecutionType, NodeType +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.trigger_schedule.entities import TriggerScheduleNodeData class TriggerScheduleNode(Node[TriggerScheduleNodeData]): diff --git a/api/core/workflow/nodes/trigger_webhook/__init__.py b/api/dify_graph/nodes/trigger_webhook/__init__.py similarity index 100% rename from api/core/workflow/nodes/trigger_webhook/__init__.py rename to api/dify_graph/nodes/trigger_webhook/__init__.py diff --git a/api/core/workflow/nodes/trigger_webhook/entities.py b/api/dify_graph/nodes/trigger_webhook/entities.py similarity index 97% rename from api/core/workflow/nodes/trigger_webhook/entities.py rename to api/dify_graph/nodes/trigger_webhook/entities.py index 1011e60b43..fa36aeabd3 100644 --- a/api/core/workflow/nodes/trigger_webhook/entities.py +++ b/api/dify_graph/nodes/trigger_webhook/entities.py @@ -4,7 +4,7 @@ from typing import Literal from pydantic import BaseModel, Field, field_validator -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class Method(StrEnum): diff --git a/api/core/workflow/nodes/trigger_webhook/exc.py b/api/dify_graph/nodes/trigger_webhook/exc.py similarity index 86% rename from api/core/workflow/nodes/trigger_webhook/exc.py rename to api/dify_graph/nodes/trigger_webhook/exc.py index dc2239c287..853b2456c5 100644 --- a/api/core/workflow/nodes/trigger_webhook/exc.py +++ b/api/dify_graph/nodes/trigger_webhook/exc.py @@ -1,4 +1,4 @@ -from core.workflow.nodes.base.exc import BaseNodeError +from dify_graph.nodes.base.exc import BaseNodeError class WebhookNodeError(BaseNodeError): diff --git a/api/core/workflow/nodes/trigger_webhook/node.py b/api/dify_graph/nodes/trigger_webhook/node.py similarity index 93% rename from api/core/workflow/nodes/trigger_webhook/node.py rename to api/dify_graph/nodes/trigger_webhook/node.py index 9f6046c11a..1b8167e799 100644 --- a/api/core/workflow/nodes/trigger_webhook/node.py +++ b/api/dify_graph/nodes/trigger_webhook/node.py @@ -2,14 +2,14 @@ import logging from collections.abc import Mapping from typing import Any -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.enums import NodeExecutionType, NodeType -from core.workflow.file import FileTransferMethod -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.variables.types import SegmentType -from core.workflow.variables.variables import FileVariable +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.enums import NodeExecutionType, NodeType +from dify_graph.file import FileTransferMethod +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.variables.types import SegmentType +from dify_graph.variables.variables import FileVariable from factories import file_factory from factories.variable_factory import build_segment_with_type diff --git a/api/core/workflow/nodes/variable_aggregator/__init__.py b/api/dify_graph/nodes/variable_aggregator/__init__.py similarity index 100% rename from api/core/workflow/nodes/variable_aggregator/__init__.py rename to api/dify_graph/nodes/variable_aggregator/__init__.py diff --git a/api/core/workflow/nodes/variable_aggregator/entities.py b/api/dify_graph/nodes/variable_aggregator/entities.py similarity index 83% rename from api/core/workflow/nodes/variable_aggregator/entities.py rename to api/dify_graph/nodes/variable_aggregator/entities.py index febbf1d1d6..5f7c1dbe93 100644 --- a/api/core/workflow/nodes/variable_aggregator/entities.py +++ b/api/dify_graph/nodes/variable_aggregator/entities.py @@ -1,7 +1,7 @@ from pydantic import BaseModel -from core.workflow.nodes.base import BaseNodeData -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.base import BaseNodeData +from dify_graph.variables.types import SegmentType class AdvancedSettings(BaseModel): diff --git a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py b/api/dify_graph/nodes/variable_aggregator/variable_aggregator_node.py similarity index 81% rename from api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py rename to api/dify_graph/nodes/variable_aggregator/variable_aggregator_node.py index 762b7dab07..98ab8105fe 100644 --- a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py +++ b/api/dify_graph/nodes/variable_aggregator/variable_aggregator_node.py @@ -1,10 +1,10 @@ from collections.abc import Mapping -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.variable_aggregator.entities import VariableAggregatorNodeData -from core.workflow.variables.segments import Segment +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.variable_aggregator.entities import VariableAggregatorNodeData +from dify_graph.variables.segments import Segment class VariableAggregatorNode(Node[VariableAggregatorNodeData]): diff --git a/api/core/workflow/nodes/variable_assigner/common/__init__.py b/api/dify_graph/nodes/variable_assigner/__init__.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/common/__init__.py rename to api/dify_graph/nodes/variable_assigner/__init__.py diff --git a/api/core/workflow/utils/__init__.py b/api/dify_graph/nodes/variable_assigner/common/__init__.py similarity index 100% rename from api/core/workflow/utils/__init__.py rename to api/dify_graph/nodes/variable_assigner/common/__init__.py diff --git a/api/core/workflow/nodes/variable_assigner/common/exc.py b/api/dify_graph/nodes/variable_assigner/common/exc.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/common/exc.py rename to api/dify_graph/nodes/variable_assigner/common/exc.py diff --git a/api/core/workflow/nodes/variable_assigner/common/helpers.py b/api/dify_graph/nodes/variable_assigner/common/helpers.py similarity index 90% rename from api/core/workflow/nodes/variable_assigner/common/helpers.py rename to api/dify_graph/nodes/variable_assigner/common/helpers.py index 37fde9d1b0..f0b22904a9 100644 --- a/api/core/workflow/nodes/variable_assigner/common/helpers.py +++ b/api/dify_graph/nodes/variable_assigner/common/helpers.py @@ -3,9 +3,9 @@ from typing import Any, TypeVar from pydantic import BaseModel -from core.workflow.variables import Segment -from core.workflow.variables.consts import SELECTORS_LENGTH -from core.workflow.variables.types import SegmentType +from dify_graph.variables import Segment +from dify_graph.variables.consts import SELECTORS_LENGTH +from dify_graph.variables.types import SegmentType # Use double underscore (`__`) prefix for internal variables # to minimize risk of collision with user-defined variable names. diff --git a/api/core/workflow/nodes/variable_assigner/v1/__init__.py b/api/dify_graph/nodes/variable_assigner/v1/__init__.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/v1/__init__.py rename to api/dify_graph/nodes/variable_assigner/v1/__init__.py diff --git a/api/core/workflow/nodes/variable_assigner/v1/node.py b/api/dify_graph/nodes/variable_assigner/v1/node.py similarity index 88% rename from api/core/workflow/nodes/variable_assigner/v1/node.py rename to api/dify_graph/nodes/variable_assigner/v1/node.py index b987949541..1aa7042b02 100644 --- a/api/core/workflow/nodes/variable_assigner/v1/node.py +++ b/api/dify_graph/nodes/variable_assigner/v1/node.py @@ -1,19 +1,19 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID -from core.workflow.entities import GraphInitParams -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.variable_assigner.common import helpers as common_helpers -from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError -from core.workflow.variables import SegmentType, VariableBase +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID +from dify_graph.entities import GraphInitParams +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.variable_assigner.common import helpers as common_helpers +from dify_graph.nodes.variable_assigner.common.exc import VariableOperatorNodeError +from dify_graph.variables import SegmentType, VariableBase from .node_data import VariableAssignerData, WriteMode if TYPE_CHECKING: - from core.workflow.runtime import GraphRuntimeState + from dify_graph.runtime import GraphRuntimeState class VariableAssignerNode(Node[VariableAssignerData]): diff --git a/api/core/workflow/nodes/variable_assigner/v1/node_data.py b/api/dify_graph/nodes/variable_assigner/v1/node_data.py similarity index 86% rename from api/core/workflow/nodes/variable_assigner/v1/node_data.py rename to api/dify_graph/nodes/variable_assigner/v1/node_data.py index 9734d64712..11e8f93f35 100644 --- a/api/core/workflow/nodes/variable_assigner/v1/node_data.py +++ b/api/dify_graph/nodes/variable_assigner/v1/node_data.py @@ -1,7 +1,7 @@ from collections.abc import Sequence from enum import StrEnum -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData class WriteMode(StrEnum): diff --git a/api/core/workflow/nodes/variable_assigner/v2/__init__.py b/api/dify_graph/nodes/variable_assigner/v2/__init__.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/v2/__init__.py rename to api/dify_graph/nodes/variable_assigner/v2/__init__.py diff --git a/api/core/workflow/nodes/variable_assigner/v2/entities.py b/api/dify_graph/nodes/variable_assigner/v2/entities.py similarity index 94% rename from api/core/workflow/nodes/variable_assigner/v2/entities.py rename to api/dify_graph/nodes/variable_assigner/v2/entities.py index 2955730289..5f9211d600 100644 --- a/api/core/workflow/nodes/variable_assigner/v2/entities.py +++ b/api/dify_graph/nodes/variable_assigner/v2/entities.py @@ -3,7 +3,7 @@ from typing import Any from pydantic import BaseModel, Field -from core.workflow.nodes.base import BaseNodeData +from dify_graph.nodes.base import BaseNodeData from .enums import InputType, Operation diff --git a/api/core/workflow/nodes/variable_assigner/v2/enums.py b/api/dify_graph/nodes/variable_assigner/v2/enums.py similarity index 100% rename from api/core/workflow/nodes/variable_assigner/v2/enums.py rename to api/dify_graph/nodes/variable_assigner/v2/enums.py diff --git a/api/core/workflow/nodes/variable_assigner/v2/exc.py b/api/dify_graph/nodes/variable_assigner/v2/exc.py similarity index 93% rename from api/core/workflow/nodes/variable_assigner/v2/exc.py rename to api/dify_graph/nodes/variable_assigner/v2/exc.py index 05173b3ca1..c50aab8668 100644 --- a/api/core/workflow/nodes/variable_assigner/v2/exc.py +++ b/api/dify_graph/nodes/variable_assigner/v2/exc.py @@ -1,7 +1,7 @@ from collections.abc import Sequence from typing import Any -from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError +from dify_graph.nodes.variable_assigner.common.exc import VariableOperatorNodeError from .enums import InputType, Operation diff --git a/api/core/workflow/nodes/variable_assigner/v2/helpers.py b/api/dify_graph/nodes/variable_assigner/v2/helpers.py similarity index 98% rename from api/core/workflow/nodes/variable_assigner/v2/helpers.py rename to api/dify_graph/nodes/variable_assigner/v2/helpers.py index ce3fe9620c..38c69cbe3c 100644 --- a/api/core/workflow/nodes/variable_assigner/v2/helpers.py +++ b/api/dify_graph/nodes/variable_assigner/v2/helpers.py @@ -1,6 +1,6 @@ from typing import Any -from core.workflow.variables import SegmentType +from dify_graph.variables import SegmentType from .enums import Operation diff --git a/api/core/workflow/nodes/variable_assigner/v2/node.py b/api/dify_graph/nodes/variable_assigner/v2/node.py similarity index 93% rename from api/core/workflow/nodes/variable_assigner/v2/node.py rename to api/dify_graph/nodes/variable_assigner/v2/node.py index 0d4c3d2774..7753382cd0 100644 --- a/api/core/workflow/nodes/variable_assigner/v2/node.py +++ b/api/dify_graph/nodes/variable_assigner/v2/node.py @@ -2,14 +2,14 @@ import json from collections.abc import Mapping, MutableMapping, Sequence from typing import TYPE_CHECKING, Any -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.variable_assigner.common import helpers as common_helpers -from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError -from core.workflow.variables import SegmentType, VariableBase -from core.workflow.variables.consts import SELECTORS_LENGTH +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.variable_assigner.common import helpers as common_helpers +from dify_graph.nodes.variable_assigner.common.exc import VariableOperatorNodeError +from dify_graph.variables import SegmentType, VariableBase +from dify_graph.variables.consts import SELECTORS_LENGTH from . import helpers from .entities import VariableAssignerNodeData, VariableOperationItem @@ -23,8 +23,8 @@ from .exc import ( ) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState def _target_mapping_from_item(mapping: MutableMapping[str, Sequence[str]], node_id: str, item: VariableOperationItem): diff --git a/api/core/workflow/repositories/__init__.py b/api/dify_graph/repositories/__init__.py similarity index 69% rename from api/core/workflow/repositories/__init__.py rename to api/dify_graph/repositories/__init__.py index a778151baa..ef70eb09cc 100644 --- a/api/core/workflow/repositories/__init__.py +++ b/api/dify_graph/repositories/__init__.py @@ -6,7 +6,7 @@ for accessing and manipulating data, regardless of the underlying storage mechanism. """ -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository __all__ = [ "OrderConfig", diff --git a/api/core/workflow/repositories/datasource_manager_protocol.py b/api/dify_graph/repositories/datasource_manager_protocol.py similarity index 91% rename from api/core/workflow/repositories/datasource_manager_protocol.py rename to api/dify_graph/repositories/datasource_manager_protocol.py index 4acf486bef..fbe2016d3c 100644 --- a/api/core/workflow/repositories/datasource_manager_protocol.py +++ b/api/dify_graph/repositories/datasource_manager_protocol.py @@ -3,8 +3,8 @@ from typing import Any, Protocol from pydantic import BaseModel -from core.workflow.file import File -from core.workflow.node_events import StreamChunkEvent, StreamCompletedEvent +from dify_graph.file import File +from dify_graph.node_events import StreamChunkEvent, StreamCompletedEvent class DatasourceParameter(BaseModel): diff --git a/api/core/workflow/repositories/draft_variable_repository.py b/api/dify_graph/repositories/draft_variable_repository.py similarity index 95% rename from api/core/workflow/repositories/draft_variable_repository.py rename to api/dify_graph/repositories/draft_variable_repository.py index 66ef714c16..b2ebfacffd 100644 --- a/api/core/workflow/repositories/draft_variable_repository.py +++ b/api/dify_graph/repositories/draft_variable_repository.py @@ -6,7 +6,7 @@ from typing import Any, Protocol from sqlalchemy.orm import Session -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType class DraftVariableSaver(Protocol): diff --git a/api/core/workflow/repositories/human_input_form_repository.py b/api/dify_graph/repositories/human_input_form_repository.py similarity index 96% rename from api/core/workflow/repositories/human_input_form_repository.py rename to api/dify_graph/repositories/human_input_form_repository.py index efde59c6fd..88966831cb 100644 --- a/api/core/workflow/repositories/human_input_form_repository.py +++ b/api/dify_graph/repositories/human_input_form_repository.py @@ -4,8 +4,8 @@ from collections.abc import Mapping, Sequence from datetime import datetime from typing import Any, Protocol -from core.workflow.nodes.human_input.entities import DeliveryChannelConfig, HumanInputNodeData -from core.workflow.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus +from dify_graph.nodes.human_input.entities import DeliveryChannelConfig, HumanInputNodeData +from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus class HumanInputError(Exception): diff --git a/api/core/workflow/repositories/index_processor_protocol.py b/api/dify_graph/repositories/index_processor_protocol.py similarity index 100% rename from api/core/workflow/repositories/index_processor_protocol.py rename to api/dify_graph/repositories/index_processor_protocol.py diff --git a/api/core/workflow/repositories/rag_retrieval_protocol.py b/api/dify_graph/repositories/rag_retrieval_protocol.py similarity index 97% rename from api/core/workflow/repositories/rag_retrieval_protocol.py rename to api/dify_graph/repositories/rag_retrieval_protocol.py index f91cecb694..023400cf32 100644 --- a/api/core/workflow/repositories/rag_retrieval_protocol.py +++ b/api/dify_graph/repositories/rag_retrieval_protocol.py @@ -3,8 +3,8 @@ from typing import Any, Literal, Protocol from pydantic import BaseModel, Field from core.model_runtime.entities import LLMUsage -from core.workflow.nodes.knowledge_retrieval.entities import MetadataFilteringCondition -from core.workflow.nodes.llm.entities import ModelConfig +from dify_graph.nodes.knowledge_retrieval.entities import MetadataFilteringCondition +from dify_graph.nodes.llm.entities import ModelConfig class SourceChildChunk(BaseModel): diff --git a/api/core/workflow/repositories/summary_index_service_protocol.py b/api/dify_graph/repositories/summary_index_service_protocol.py similarity index 100% rename from api/core/workflow/repositories/summary_index_service_protocol.py rename to api/dify_graph/repositories/summary_index_service_protocol.py diff --git a/api/core/workflow/repositories/workflow_execution_repository.py b/api/dify_graph/repositories/workflow_execution_repository.py similarity index 95% rename from api/core/workflow/repositories/workflow_execution_repository.py rename to api/dify_graph/repositories/workflow_execution_repository.py index d9ce591db8..ef83f07649 100644 --- a/api/core/workflow/repositories/workflow_execution_repository.py +++ b/api/dify_graph/repositories/workflow_execution_repository.py @@ -1,6 +1,6 @@ from typing import Protocol -from core.workflow.entities import WorkflowExecution +from dify_graph.entities import WorkflowExecution class WorkflowExecutionRepository(Protocol): diff --git a/api/core/workflow/repositories/workflow_node_execution_repository.py b/api/dify_graph/repositories/workflow_node_execution_repository.py similarity index 97% rename from api/core/workflow/repositories/workflow_node_execution_repository.py rename to api/dify_graph/repositories/workflow_node_execution_repository.py index 43b41ff6b8..e6c1c3e497 100644 --- a/api/core/workflow/repositories/workflow_node_execution_repository.py +++ b/api/dify_graph/repositories/workflow_node_execution_repository.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import Literal, Protocol -from core.workflow.entities import WorkflowNodeExecution +from dify_graph.entities import WorkflowNodeExecution @dataclass diff --git a/api/core/workflow/runtime/__init__.py b/api/dify_graph/runtime/__init__.py similarity index 100% rename from api/core/workflow/runtime/__init__.py rename to api/dify_graph/runtime/__init__.py diff --git a/api/core/workflow/runtime/graph_runtime_state.py b/api/dify_graph/runtime/graph_runtime_state.py similarity index 97% rename from api/core/workflow/runtime/graph_runtime_state.py rename to api/dify_graph/runtime/graph_runtime_state.py index 0af6bf49bc..541830c58b 100644 --- a/api/core/workflow/runtime/graph_runtime_state.py +++ b/api/dify_graph/runtime/graph_runtime_state.py @@ -11,11 +11,11 @@ from pydantic import BaseModel, Field from pydantic.json import pydantic_encoder from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import NodeExecutionType, NodeState, NodeType -from core.workflow.runtime.variable_pool import VariablePool +from dify_graph.enums import NodeExecutionType, NodeState, NodeType +from dify_graph.runtime.variable_pool import VariablePool if TYPE_CHECKING: - from core.workflow.entities.pause_reason import PauseReason + from dify_graph.entities.pause_reason import PauseReason class ReadyQueueProtocol(Protocol): @@ -433,13 +433,13 @@ class GraphRuntimeState: # ------------------------------------------------------------------ def _build_ready_queue(self) -> ReadyQueueProtocol: # Import lazily to avoid breaching architecture boundaries enforced by import-linter. - module = importlib.import_module("core.workflow.graph_engine.ready_queue") + module = importlib.import_module("dify_graph.graph_engine.ready_queue") in_memory_cls = module.InMemoryReadyQueue return in_memory_cls() def _build_graph_execution(self) -> GraphExecutionProtocol: # Lazily import to keep the runtime domain decoupled from graph_engine modules. - module = importlib.import_module("core.workflow.graph_engine.domain.graph_execution") + module = importlib.import_module("dify_graph.graph_engine.domain.graph_execution") graph_execution_cls = module.GraphExecution workflow_id = self._pending_graph_execution_workflow_id or "" self._pending_graph_execution_workflow_id = None @@ -447,7 +447,7 @@ class GraphRuntimeState: def _build_response_coordinator(self, graph: GraphProtocol) -> ResponseStreamCoordinatorProtocol: # Lazily import to keep the runtime domain decoupled from graph_engine modules. - module = importlib.import_module("core.workflow.graph_engine.response_coordinator") + module = importlib.import_module("dify_graph.graph_engine.response_coordinator") coordinator_cls = module.ResponseStreamCoordinator return coordinator_cls(variable_pool=self.variable_pool, graph=graph) diff --git a/api/core/workflow/runtime/graph_runtime_state_protocol.py b/api/dify_graph/runtime/graph_runtime_state_protocol.py similarity index 94% rename from api/core/workflow/runtime/graph_runtime_state_protocol.py rename to api/dify_graph/runtime/graph_runtime_state_protocol.py index 81d87e5a74..4590a4205c 100644 --- a/api/core/workflow/runtime/graph_runtime_state_protocol.py +++ b/api/dify_graph/runtime/graph_runtime_state_protocol.py @@ -2,8 +2,8 @@ from collections.abc import Mapping, Sequence from typing import Any, Protocol from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.system_variable import SystemVariableReadOnlyView -from core.workflow.variables.segments import Segment +from dify_graph.system_variable import SystemVariableReadOnlyView +from dify_graph.variables.segments import Segment class ReadOnlyVariablePool(Protocol): diff --git a/api/core/workflow/runtime/read_only_wrappers.py b/api/dify_graph/runtime/read_only_wrappers.py similarity index 95% rename from api/core/workflow/runtime/read_only_wrappers.py rename to api/dify_graph/runtime/read_only_wrappers.py index 25a834a539..8e4a3ed832 100644 --- a/api/core/workflow/runtime/read_only_wrappers.py +++ b/api/dify_graph/runtime/read_only_wrappers.py @@ -5,8 +5,8 @@ from copy import deepcopy from typing import Any from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.system_variable import SystemVariableReadOnlyView -from core.workflow.variables.segments import Segment +from dify_graph.system_variable import SystemVariableReadOnlyView +from dify_graph.variables.segments import Segment from .graph_runtime_state import GraphRuntimeState from .variable_pool import VariablePool diff --git a/api/core/workflow/runtime/variable_pool.py b/api/dify_graph/runtime/variable_pool.py similarity index 95% rename from api/core/workflow/runtime/variable_pool.py rename to api/dify_graph/runtime/variable_pool.py index 48ad102b43..a2b1af99bb 100644 --- a/api/core/workflow/runtime/variable_pool.py +++ b/api/dify_graph/runtime/variable_pool.py @@ -8,18 +8,18 @@ from typing import Annotated, Any, Union, cast from pydantic import BaseModel, Field -from core.workflow.constants import ( +from dify_graph.constants import ( CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, RAG_PIPELINE_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID, ) -from core.workflow.file import File, FileAttribute, file_manager -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import Segment, SegmentGroup, VariableBase -from core.workflow.variables.consts import SELECTORS_LENGTH -from core.workflow.variables.segments import FileSegment, ObjectSegment -from core.workflow.variables.variables import RAGPipelineVariableInput, Variable +from dify_graph.file import File, FileAttribute, file_manager +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import Segment, SegmentGroup, VariableBase +from dify_graph.variables.consts import SELECTORS_LENGTH +from dify_graph.variables.segments import FileSegment, ObjectSegment +from dify_graph.variables.variables import RAGPipelineVariableInput, Variable from factories import variable_factory VariableValue = Union[str, int, float, dict[str, object], list[object], File] diff --git a/api/core/workflow/system_variable.py b/api/dify_graph/system_variable.py similarity index 98% rename from api/core/workflow/system_variable.py rename to api/dify_graph/system_variable.py index 4144f79b8a..cc5deda892 100644 --- a/api/core/workflow/system_variable.py +++ b/api/dify_graph/system_variable.py @@ -7,8 +7,8 @@ from uuid import uuid4 from pydantic import AliasChoices, BaseModel, ConfigDict, Field, model_validator -from core.workflow.enums import SystemVariableKey -from core.workflow.file.models import File +from dify_graph.enums import SystemVariableKey +from dify_graph.file.models import File class SystemVariable(BaseModel): diff --git a/api/core/workflow/utils/condition/__init__.py b/api/dify_graph/utils/__init__.py similarity index 100% rename from api/core/workflow/utils/condition/__init__.py rename to api/dify_graph/utils/__init__.py diff --git a/api/dify_graph/utils/condition/__init__.py b/api/dify_graph/utils/condition/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/core/workflow/utils/condition/entities.py b/api/dify_graph/utils/condition/entities.py similarity index 100% rename from api/core/workflow/utils/condition/entities.py rename to api/dify_graph/utils/condition/entities.py diff --git a/api/core/workflow/utils/condition/processor.py b/api/dify_graph/utils/condition/processor.py similarity index 98% rename from api/core/workflow/utils/condition/processor.py rename to api/dify_graph/utils/condition/processor.py index 4e635cc2f2..dea72d96c2 100644 --- a/api/core/workflow/utils/condition/processor.py +++ b/api/dify_graph/utils/condition/processor.py @@ -2,10 +2,10 @@ import json from collections.abc import Mapping, Sequence from typing import Literal, NamedTuple -from core.workflow.file import FileAttribute, file_manager -from core.workflow.runtime import VariablePool -from core.workflow.variables import ArrayFileSegment -from core.workflow.variables.segments import ArrayBooleanSegment, BooleanSegment +from dify_graph.file import FileAttribute, file_manager +from dify_graph.runtime import VariablePool +from dify_graph.variables import ArrayFileSegment +from dify_graph.variables.segments import ArrayBooleanSegment, BooleanSegment from .entities import Condition, SubCondition, SupportedComparisonOperator diff --git a/api/core/workflow/variable_loader.py b/api/dify_graph/variable_loader.py similarity index 95% rename from api/core/workflow/variable_loader.py rename to api/dify_graph/variable_loader.py index dfa4ce2e75..d263450334 100644 --- a/api/core/workflow/variable_loader.py +++ b/api/dify_graph/variable_loader.py @@ -2,9 +2,9 @@ import abc from collections.abc import Mapping, Sequence from typing import Any, Protocol -from core.workflow.runtime import VariablePool -from core.workflow.variables import VariableBase -from core.workflow.variables.consts import SELECTORS_LENGTH +from dify_graph.runtime import VariablePool +from dify_graph.variables import VariableBase +from dify_graph.variables.consts import SELECTORS_LENGTH class VariableLoader(Protocol): diff --git a/api/core/workflow/variables/__init__.py b/api/dify_graph/variables/__init__.py similarity index 100% rename from api/core/workflow/variables/__init__.py rename to api/dify_graph/variables/__init__.py diff --git a/api/core/workflow/variables/consts.py b/api/dify_graph/variables/consts.py similarity index 100% rename from api/core/workflow/variables/consts.py rename to api/dify_graph/variables/consts.py diff --git a/api/core/workflow/variables/exc.py b/api/dify_graph/variables/exc.py similarity index 100% rename from api/core/workflow/variables/exc.py rename to api/dify_graph/variables/exc.py diff --git a/api/core/workflow/variables/input_entities.py b/api/dify_graph/variables/input_entities.py similarity index 97% rename from api/core/workflow/variables/input_entities.py rename to api/dify_graph/variables/input_entities.py index 9a42012f0a..e6a68ea359 100644 --- a/api/core/workflow/variables/input_entities.py +++ b/api/dify_graph/variables/input_entities.py @@ -5,7 +5,7 @@ from typing import Any from jsonschema import Draft7Validator, SchemaError from pydantic import BaseModel, Field, field_validator -from core.workflow.file import FileTransferMethod, FileType +from dify_graph.file import FileTransferMethod, FileType class VariableEntityType(StrEnum): diff --git a/api/core/workflow/variables/segment_group.py b/api/dify_graph/variables/segment_group.py similarity index 100% rename from api/core/workflow/variables/segment_group.py rename to api/dify_graph/variables/segment_group.py diff --git a/api/core/workflow/variables/segments.py b/api/dify_graph/variables/segments.py similarity index 99% rename from api/core/workflow/variables/segments.py rename to api/dify_graph/variables/segments.py index 64bba7dbe2..bdb213ed48 100644 --- a/api/core/workflow/variables/segments.py +++ b/api/dify_graph/variables/segments.py @@ -5,7 +5,7 @@ from typing import Annotated, Any, TypeAlias from pydantic import BaseModel, ConfigDict, Discriminator, Tag, field_validator -from core.workflow.file import File +from dify_graph.file import File from .types import SegmentType diff --git a/api/core/workflow/variables/types.py b/api/dify_graph/variables/types.py similarity index 99% rename from api/core/workflow/variables/types.py rename to api/dify_graph/variables/types.py index 596905c26d..df8430de5d 100644 --- a/api/core/workflow/variables/types.py +++ b/api/dify_graph/variables/types.py @@ -4,7 +4,7 @@ from collections.abc import Mapping from enum import StrEnum from typing import TYPE_CHECKING, Any -from core.workflow.file.models import File +from dify_graph.file.models import File if TYPE_CHECKING: pass diff --git a/api/core/workflow/variables/utils.py b/api/dify_graph/variables/utils.py similarity index 100% rename from api/core/workflow/variables/utils.py rename to api/dify_graph/variables/utils.py diff --git a/api/core/workflow/variables/variables.py b/api/dify_graph/variables/variables.py similarity index 100% rename from api/core/workflow/variables/variables.py rename to api/dify_graph/variables/variables.py diff --git a/api/core/workflow/workflow_type_encoder.py b/api/dify_graph/workflow_type_encoder.py similarity index 95% rename from api/core/workflow/workflow_type_encoder.py rename to api/dify_graph/workflow_type_encoder.py index a192b884f7..3dd846b3cb 100644 --- a/api/core/workflow/workflow_type_encoder.py +++ b/api/dify_graph/workflow_type_encoder.py @@ -4,8 +4,8 @@ from typing import Any, overload from pydantic import BaseModel -from core.workflow.file.models import File -from core.workflow.variables import Segment +from dify_graph.file.models import File +from dify_graph.variables import Segment class WorkflowRuntimeTypeConverter: diff --git a/api/events/event_handlers/delete_tool_parameters_cache_when_sync_draft_workflow.py b/api/events/event_handlers/delete_tool_parameters_cache_when_sync_draft_workflow.py index bac2fbef47..5c02a16a7d 100644 --- a/api/events/event_handlers/delete_tool_parameters_cache_when_sync_draft_workflow.py +++ b/api/events/event_handlers/delete_tool_parameters_cache_when_sync_draft_workflow.py @@ -2,8 +2,8 @@ import logging from core.tools.tool_manager import ToolManager from core.tools.utils.configuration import ToolParameterConfigurationManager -from core.workflow.nodes import NodeType -from core.workflow.nodes.tool.entities import ToolEntity +from dify_graph.nodes import NodeType +from dify_graph.nodes.tool.entities import ToolEntity from events.app_event import app_draft_workflow_was_synced logger = logging.getLogger(__name__) diff --git a/api/events/event_handlers/sync_workflow_schedule_when_app_published.py b/api/events/event_handlers/sync_workflow_schedule_when_app_published.py index 168513fc04..90f562d167 100644 --- a/api/events/event_handlers/sync_workflow_schedule_when_app_published.py +++ b/api/events/event_handlers/sync_workflow_schedule_when_app_published.py @@ -4,7 +4,7 @@ from typing import cast from sqlalchemy import select from sqlalchemy.orm import Session -from core.workflow.nodes.trigger_schedule.entities import SchedulePlanUpdate +from dify_graph.nodes.trigger_schedule.entities import SchedulePlanUpdate from events.app_event import app_published_workflow_was_updated from extensions.ext_database import db from models import AppMode, Workflow, WorkflowSchedulePlan diff --git a/api/events/event_handlers/update_app_dataset_join_when_app_published_workflow_updated.py b/api/events/event_handlers/update_app_dataset_join_when_app_published_workflow_updated.py index 53e0065f6e..8da33d03b9 100644 --- a/api/events/event_handlers/update_app_dataset_join_when_app_published_workflow_updated.py +++ b/api/events/event_handlers/update_app_dataset_join_when_app_published_workflow_updated.py @@ -2,8 +2,8 @@ from typing import cast from sqlalchemy import select -from core.workflow.nodes import NodeType -from core.workflow.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData +from dify_graph.nodes import NodeType +from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData from events.app_event import app_published_workflow_was_updated from extensions.ext_database import db from models.dataset import AppDatasetJoin diff --git a/api/events/event_handlers/update_app_triggers_when_app_published_workflow_updated.py b/api/events/event_handlers/update_app_triggers_when_app_published_workflow_updated.py index 430514ada2..fd211a3e55 100644 --- a/api/events/event_handlers/update_app_triggers_when_app_published_workflow_updated.py +++ b/api/events/event_handlers/update_app_triggers_when_app_published_workflow_updated.py @@ -3,7 +3,7 @@ from typing import cast from sqlalchemy import select from sqlalchemy.orm import Session -from core.workflow.nodes import NodeType +from dify_graph.nodes import NodeType from events.app_event import app_published_workflow_was_updated from extensions.ext_database import db from models import AppMode diff --git a/api/extensions/logstore/repositories/logstore_api_workflow_node_execution_repository.py b/api/extensions/logstore/repositories/logstore_api_workflow_node_execution_repository.py index 817c8b0448..7ee4638e77 100644 --- a/api/extensions/logstore/repositories/logstore_api_workflow_node_execution_repository.py +++ b/api/extensions/logstore/repositories/logstore_api_workflow_node_execution_repository.py @@ -13,7 +13,7 @@ from typing import Any from sqlalchemy.orm import sessionmaker -from core.workflow.enums import WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionStatus from extensions.logstore.aliyun_logstore import AliyunLogStore from extensions.logstore.repositories import safe_float, safe_int from extensions.logstore.sql_escape import escape_identifier, escape_logstore_query_value diff --git a/api/extensions/logstore/repositories/logstore_workflow_execution_repository.py b/api/extensions/logstore/repositories/logstore_workflow_execution_repository.py index 9928879a7b..c58aa6adbb 100644 --- a/api/extensions/logstore/repositories/logstore_workflow_execution_repository.py +++ b/api/extensions/logstore/repositories/logstore_workflow_execution_repository.py @@ -8,9 +8,9 @@ from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository -from core.workflow.entities import WorkflowExecution -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities import WorkflowExecution +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.logstore.aliyun_logstore import AliyunLogStore from libs.helper import extract_tenant_id from models import ( diff --git a/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py b/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py index 4897171b12..b660a6c54a 100644 --- a/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py +++ b/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py @@ -18,11 +18,11 @@ from sqlalchemy.orm import sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities import WorkflowNodeExecution -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.enums import NodeType -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities import WorkflowNodeExecution +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.enums import NodeType +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.logstore.aliyun_logstore import AliyunLogStore from extensions.logstore.repositories import safe_float, safe_int from extensions.logstore.sql_escape import escape_identifier diff --git a/api/extensions/otel/parser/base.py b/api/extensions/otel/parser/base.py index 66d1c977d6..fc84147e01 100644 --- a/api/extensions/otel/parser/base.py +++ b/api/extensions/otel/parser/base.py @@ -9,11 +9,11 @@ from opentelemetry.trace import Span from opentelemetry.trace.status import Status, StatusCode from pydantic import BaseModel -from core.workflow.enums import NodeType -from core.workflow.file.models import File -from core.workflow.graph_events import GraphNodeEventBase -from core.workflow.nodes.base.node import Node -from core.workflow.variables import Segment +from dify_graph.enums import NodeType +from dify_graph.file.models import File +from dify_graph.graph_events import GraphNodeEventBase +from dify_graph.nodes.base.node import Node +from dify_graph.variables import Segment from extensions.otel.semconv.gen_ai import ChainAttributes, GenAIAttributes diff --git a/api/extensions/otel/parser/llm.py b/api/extensions/otel/parser/llm.py index 8556974080..3da9a9e97d 100644 --- a/api/extensions/otel/parser/llm.py +++ b/api/extensions/otel/parser/llm.py @@ -8,8 +8,8 @@ from typing import Any from opentelemetry.trace import Span -from core.workflow.graph_events import GraphNodeEventBase -from core.workflow.nodes.base.node import Node +from dify_graph.graph_events import GraphNodeEventBase +from dify_graph.nodes.base.node import Node from extensions.otel.parser.base import DefaultNodeOTelParser, safe_json_dumps from extensions.otel.semconv.gen_ai import LLMAttributes diff --git a/api/extensions/otel/parser/retrieval.py b/api/extensions/otel/parser/retrieval.py index 82cb865b8b..dd658b250b 100644 --- a/api/extensions/otel/parser/retrieval.py +++ b/api/extensions/otel/parser/retrieval.py @@ -8,9 +8,9 @@ from typing import Any from opentelemetry.trace import Span -from core.workflow.graph_events import GraphNodeEventBase -from core.workflow.nodes.base.node import Node -from core.workflow.variables import Segment +from dify_graph.graph_events import GraphNodeEventBase +from dify_graph.nodes.base.node import Node +from dify_graph.variables import Segment from extensions.otel.parser.base import DefaultNodeOTelParser, safe_json_dumps from extensions.otel.semconv.gen_ai import RetrieverAttributes diff --git a/api/extensions/otel/parser/tool.py b/api/extensions/otel/parser/tool.py index b99180722b..f4e6a18b4d 100644 --- a/api/extensions/otel/parser/tool.py +++ b/api/extensions/otel/parser/tool.py @@ -4,10 +4,10 @@ Parser for tool nodes that captures tool-specific metadata. from opentelemetry.trace import Span -from core.workflow.enums import WorkflowNodeExecutionMetadataKey -from core.workflow.graph_events import GraphNodeEventBase -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.tool.entities import ToolNodeData +from dify_graph.enums import WorkflowNodeExecutionMetadataKey +from dify_graph.graph_events import GraphNodeEventBase +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.tool.entities import ToolNodeData from extensions.otel.parser.base import DefaultNodeOTelParser, safe_json_dumps from extensions.otel.semconv.gen_ai import ToolAttributes diff --git a/api/factories/file_factory.py b/api/factories/file_factory.py index 47396831fa..ef55fe53c5 100644 --- a/api/factories/file_factory.py +++ b/api/factories/file_factory.py @@ -14,7 +14,7 @@ from werkzeug.http import parse_options_header from constants import AUDIO_EXTENSIONS, DOCUMENT_EXTENSIONS, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS from core.helper import ssrf_proxy -from core.workflow.file import File, FileBelongsTo, FileTransferMethod, FileType, FileUploadConfig, helpers +from dify_graph.file import File, FileBelongsTo, FileTransferMethod, FileType, FileUploadConfig, helpers from extensions.ext_database import db from models import MessageFile, ToolFile, UploadFile diff --git a/api/factories/variable_factory.py b/api/factories/variable_factory.py index b74d9517f4..255e5cde83 100644 --- a/api/factories/variable_factory.py +++ b/api/factories/variable_factory.py @@ -3,13 +3,13 @@ from typing import Any, cast from uuid import uuid4 from configs import dify_config -from core.workflow.constants import ( +from dify_graph.constants import ( CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, ) -from core.workflow.file import File -from core.workflow.variables.exc import VariableError -from core.workflow.variables.segments import ( +from dify_graph.file import File +from dify_graph.variables.exc import VariableError +from dify_graph.variables.segments import ( ArrayAnySegment, ArrayBooleanSegment, ArrayFileSegment, @@ -26,8 +26,8 @@ from core.workflow.variables.segments import ( Segment, StringSegment, ) -from core.workflow.variables.types import SegmentType -from core.workflow.variables.variables import ( +from dify_graph.variables.types import SegmentType +from dify_graph.variables.variables import ( ArrayAnyVariable, ArrayBooleanVariable, ArrayFileVariable, diff --git a/api/fields/_value_type_serializer.py b/api/fields/_value_type_serializer.py index 461c163e2f..ac7c5376fb 100644 --- a/api/fields/_value_type_serializer.py +++ b/api/fields/_value_type_serializer.py @@ -1,7 +1,7 @@ from typing import TypedDict -from core.workflow.variables.segments import Segment -from core.workflow.variables.types import SegmentType +from dify_graph.variables.segments import Segment +from dify_graph.variables.types import SegmentType class _VarTypedDict(TypedDict, total=False): diff --git a/api/fields/conversation_fields.py b/api/fields/conversation_fields.py index faa3606f0e..a5c7ddbb11 100644 --- a/api/fields/conversation_fields.py +++ b/api/fields/conversation_fields.py @@ -5,7 +5,7 @@ from typing import Any, TypeAlias from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator -from core.workflow.file import File +from dify_graph.file import File JSONValue: TypeAlias = Any diff --git a/api/fields/member_fields.py b/api/fields/member_fields.py index 29b9e40242..7ee628726b 100644 --- a/api/fields/member_fields.py +++ b/api/fields/member_fields.py @@ -5,7 +5,7 @@ from datetime import datetime from flask_restx import fields from pydantic import BaseModel, ConfigDict, computed_field, field_validator -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers simple_account_fields = { "id": fields.String, diff --git a/api/fields/message_fields.py b/api/fields/message_fields.py index 55bd0a5fbd..428f92ed33 100644 --- a/api/fields/message_fields.py +++ b/api/fields/message_fields.py @@ -7,7 +7,7 @@ from uuid import uuid4 from pydantic import BaseModel, ConfigDict, Field, field_validator from core.entities.execution_extra_content import ExecutionExtraContentDomainModel -from core.workflow.file import File +from dify_graph.file import File from fields.conversation_fields import AgentThought, JSONValue, MessageFile JSONValueType: TypeAlias = JSONValue diff --git a/api/fields/raws.py b/api/fields/raws.py index 33b47ba2c3..318dedc25c 100644 --- a/api/fields/raws.py +++ b/api/fields/raws.py @@ -1,6 +1,6 @@ from flask_restx import fields -from core.workflow.file import File +from dify_graph.file import File class FilesContainedField(fields.Raw): diff --git a/api/fields/workflow_fields.py b/api/fields/workflow_fields.py index 019949e105..7ce2139687 100644 --- a/api/fields/workflow_fields.py +++ b/api/fields/workflow_fields.py @@ -1,7 +1,7 @@ from flask_restx import fields from core.helper import encrypter -from core.workflow.variables import SecretVariable, SegmentType, VariableBase +from dify_graph.variables import SecretVariable, SegmentType, VariableBase from fields.member_fields import simple_account_fields from libs.helper import TimestampField diff --git a/api/libs/helper.py b/api/libs/helper.py index 206bb8fd81..39f1931299 100644 --- a/api/libs/helper.py +++ b/api/libs/helper.py @@ -22,7 +22,7 @@ from pydantic.functional_validators import AfterValidator from configs import dify_config from core.app.features.rate_limiting.rate_limit import RateLimitGenerator from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from extensions.ext_redis import redis_client if TYPE_CHECKING: diff --git a/api/models/enums.py b/api/models/enums.py index 2bc61120ce..86dcb00bcc 100644 --- a/api/models/enums.py +++ b/api/models/enums.py @@ -1,6 +1,6 @@ from enum import StrEnum -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType class CreatorUserRole(StrEnum): diff --git a/api/models/human_input.py b/api/models/human_input.py index 5208461de1..709cc8fe61 100644 --- a/api/models/human_input.py +++ b/api/models/human_input.py @@ -6,7 +6,7 @@ import sqlalchemy as sa from pydantic import BaseModel, Field from sqlalchemy.orm import Mapped, mapped_column, relationship -from core.workflow.nodes.human_input.enums import ( +from dify_graph.nodes.human_input.enums import ( DeliveryMethodType, HumanInputFormKind, HumanInputFormStatus, diff --git a/api/models/model.py b/api/models/model.py index 4a95faf7f7..a5bca06666 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -19,9 +19,9 @@ from sqlalchemy.orm import Mapped, Session, mapped_column from configs import dify_config from constants import DEFAULT_FILE_NUMBER_LIMITS from core.tools.signature import sign_tool_file -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.file import FILE_MODEL_IDENTITY, File, FileTransferMethod -from core.workflow.file import helpers as file_helpers +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.file import FILE_MODEL_IDENTITY, File, FileTransferMethod +from dify_graph.file import helpers as file_helpers from libs.helper import generate_string # type: ignore[import-not-found] from libs.uuid_utils import uuidv7 diff --git a/api/models/workflow.py b/api/models/workflow.py index 7da09a5a1b..d728ed83bc 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -22,17 +22,17 @@ from sqlalchemy import ( from sqlalchemy.orm import Mapped, declared_attr, mapped_column from typing_extensions import deprecated -from core.workflow.constants import ( +from dify_graph.constants import ( CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID, ) -from core.workflow.entities.graph_config import NodeConfigDict, NodeConfigDictAdapter -from core.workflow.entities.pause_reason import HumanInputRequired, PauseReason, PauseReasonType, SchedulingPause -from core.workflow.enums import NodeType, WorkflowExecutionStatus -from core.workflow.file.constants import maybe_file_object -from core.workflow.file.models import File -from core.workflow.variables import utils as variable_utils -from core.workflow.variables.variables import FloatVariable, IntegerVariable, StringVariable +from dify_graph.entities.graph_config import NodeConfigDict, NodeConfigDictAdapter +from dify_graph.entities.pause_reason import HumanInputRequired, PauseReason, PauseReasonType, SchedulingPause +from dify_graph.enums import NodeType, WorkflowExecutionStatus +from dify_graph.file.constants import maybe_file_object +from dify_graph.file.models import File +from dify_graph.variables import utils as variable_utils +from dify_graph.variables.variables import FloatVariable, IntegerVariable, StringVariable from extensions.ext_storage import Storage from factories.variable_factory import TypeMismatchError, build_segment_with_type from libs.datetime_utils import naive_utc_now @@ -46,7 +46,7 @@ if TYPE_CHECKING: from constants import DEFAULT_FILE_NUMBER_LIMITS, HIDDEN_VALUE from core.helper import encrypter -from core.workflow.variables import SecretVariable, Segment, SegmentType, VariableBase +from dify_graph.variables import SecretVariable, Segment, SegmentType, VariableBase from factories import variable_factory from libs import helper @@ -345,7 +345,7 @@ class Workflow(Base): # bug "selected": false, } - For specific node type, refer to `core.workflow.nodes` + For specific node type, refer to `dify_graph.nodes` """ graph_dict = self.graph_dict if "nodes" not in graph_dict: @@ -1344,7 +1344,7 @@ class WorkflowDraftVariable(Base): # From `VARIABLE_PATTERN`, we may conclude that the length of a top level variable is less than # 80 chars. # - # ref: api/core/workflow/entities/variable_pool.py:18 + # ref: api/dify_graph/entities/variable_pool.py:18 name: Mapped[str] = mapped_column(sa.String(255), nullable=False) description: Mapped[str] = mapped_column( sa.String(255), diff --git a/api/pyproject.toml b/api/pyproject.toml index f544cd27b2..84b95fb226 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -238,7 +238,7 @@ module = [ "configs.middleware.cache.redis_pubsub_config", "extensions.ext_redis", "tasks.workflow_execution_tasks", - "core.workflow.nodes.base.node", + "dify_graph.nodes.base.node", "services.human_input_delivery_test_service", "core.app.apps.advanced_chat.app_generator", "controllers.console.human_input_form", diff --git a/api/repositories/api_workflow_node_execution_repository.py b/api/repositories/api_workflow_node_execution_repository.py index 6446eb0d6e..2fa065bcc8 100644 --- a/api/repositories/api_workflow_node_execution_repository.py +++ b/api/repositories/api_workflow_node_execution_repository.py @@ -16,7 +16,7 @@ from typing import Protocol from sqlalchemy.orm import Session -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionOffload diff --git a/api/repositories/api_workflow_run_repository.py b/api/repositories/api_workflow_run_repository.py index ffa87b209f..a96c4acb31 100644 --- a/api/repositories/api_workflow_run_repository.py +++ b/api/repositories/api_workflow_run_repository.py @@ -40,9 +40,9 @@ from typing import Protocol from sqlalchemy.orm import Session -from core.workflow.entities.pause_reason import PauseReason -from core.workflow.enums import WorkflowType -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.entities.pause_reason import PauseReason +from dify_graph.enums import WorkflowType +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository from libs.infinite_scroll_pagination import InfiniteScrollPagination from models.enums import WorkflowRunTriggeredFrom from models.workflow import WorkflowAppLog, WorkflowArchiveLog, WorkflowPause, WorkflowPauseReason, WorkflowRun diff --git a/api/repositories/entities/workflow_pause.py b/api/repositories/entities/workflow_pause.py index a3c4039aaa..be28b7e613 100644 --- a/api/repositories/entities/workflow_pause.py +++ b/api/repositories/entities/workflow_pause.py @@ -10,7 +10,7 @@ from abc import ABC, abstractmethod from collections.abc import Sequence from datetime import datetime -from core.workflow.entities.pause_reason import PauseReason +from dify_graph.entities.pause_reason import PauseReason class WorkflowPauseEntity(ABC): diff --git a/api/repositories/sqlalchemy_api_workflow_node_execution_repository.py b/api/repositories/sqlalchemy_api_workflow_node_execution_repository.py index 6c696b6478..2266c2e646 100644 --- a/api/repositories/sqlalchemy_api_workflow_node_execution_repository.py +++ b/api/repositories/sqlalchemy_api_workflow_node_execution_repository.py @@ -14,7 +14,7 @@ from sqlalchemy import asc, delete, desc, func, select from sqlalchemy.engine import CursorResult from sqlalchemy.orm import Session, sessionmaker -from core.workflow.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionOffload from repositories.api_workflow_node_execution_repository import ( DifyAPIWorkflowNodeExecutionRepository, diff --git a/api/repositories/sqlalchemy_api_workflow_run_repository.py b/api/repositories/sqlalchemy_api_workflow_run_repository.py index 5ba7a7e7e8..fdd3e123e4 100644 --- a/api/repositories/sqlalchemy_api_workflow_run_repository.py +++ b/api/repositories/sqlalchemy_api_workflow_run_repository.py @@ -33,9 +33,9 @@ from sqlalchemy import and_, delete, func, null, or_, select, tuple_ from sqlalchemy.engine import CursorResult from sqlalchemy.orm import Session, selectinload, sessionmaker -from core.workflow.entities.pause_reason import HumanInputRequired, PauseReason, PauseReasonType, SchedulingPause -from core.workflow.enums import WorkflowExecutionStatus, WorkflowType -from core.workflow.nodes.human_input.entities import FormDefinition +from dify_graph.entities.pause_reason import HumanInputRequired, PauseReason, PauseReasonType, SchedulingPause +from dify_graph.enums import WorkflowExecutionStatus, WorkflowType +from dify_graph.nodes.human_input.entities import FormDefinition from extensions.ext_storage import storage from libs.datetime_utils import naive_utc_now from libs.helper import convert_datetime_to_date diff --git a/api/repositories/sqlalchemy_execution_extra_content_repository.py b/api/repositories/sqlalchemy_execution_extra_content_repository.py index 5a2c0ea46f..508db22eb0 100644 --- a/api/repositories/sqlalchemy_execution_extra_content_repository.py +++ b/api/repositories/sqlalchemy_execution_extra_content_repository.py @@ -18,9 +18,9 @@ from core.entities.execution_extra_content import ( from core.entities.execution_extra_content import ( HumanInputContent as HumanInputContentDomainModel, ) -from core.workflow.nodes.human_input.entities import FormDefinition -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.human_input.entities import FormDefinition +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode from models.execution_extra_content import ( ExecutionExtraContent as ExecutionExtraContentModel, ) diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index 9400362605..ad5a91e74b 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -20,13 +20,13 @@ from configs import dify_config from core.helper import ssrf_proxy from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import PluginDependency -from core.workflow.enums import NodeType -from core.workflow.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData -from core.workflow.nodes.llm.entities import LLMNodeData -from core.workflow.nodes.parameter_extractor.entities import ParameterExtractorNodeData -from core.workflow.nodes.question_classifier.entities import QuestionClassifierNodeData -from core.workflow.nodes.tool.entities import ToolNodeData -from core.workflow.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode +from dify_graph.enums import NodeType +from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData +from dify_graph.nodes.llm.entities import LLMNodeData +from dify_graph.nodes.parameter_extractor.entities import ParameterExtractorNodeData +from dify_graph.nodes.question_classifier.entities import QuestionClassifierNodeData +from dify_graph.nodes.tool.entities import ToolNodeData +from dify_graph.nodes.trigger_schedule.trigger_schedule_node import TriggerScheduleNode from events.app_event import app_model_config_was_updated, app_was_created from extensions.ext_redis import redis_client from factories import variable_factory diff --git a/api/services/app_task_service.py b/api/services/app_task_service.py index 5ae1fba2e8..d556230044 100644 --- a/api/services/app_task_service.py +++ b/api/services/app_task_service.py @@ -7,7 +7,7 @@ new GraphEngine command channel mechanism. from core.app.apps.base_app_queue_manager import AppQueueManager from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.graph_engine.manager import GraphEngineManager from extensions.ext_redis import redis_client from models.model import AppMode diff --git a/api/services/conversation_service.py b/api/services/conversation_service.py index 4c87150cf7..566c27c0f3 100644 --- a/api/services/conversation_service.py +++ b/api/services/conversation_service.py @@ -10,7 +10,7 @@ from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom from core.db.session_factory import session_factory from core.llm_generator.llm_generator import LLMGenerator -from core.workflow.variables.types import SegmentType +from dify_graph.variables.types import SegmentType from extensions.ext_database import db from factories import variable_factory from libs.datetime_utils import naive_utc_now diff --git a/api/services/conversation_variable_updater.py b/api/services/conversation_variable_updater.py index b0012d6f6a..f00e3fe01e 100644 --- a/api/services/conversation_variable_updater.py +++ b/api/services/conversation_variable_updater.py @@ -1,7 +1,7 @@ from sqlalchemy import select from sqlalchemy.orm import Session, sessionmaker -from core.workflow.variables.variables import VariableBase +from dify_graph.variables.variables import VariableBase from models import ConversationVariable diff --git a/api/services/dataset_service.py b/api/services/dataset_service.py index 35b20f7601..66a49226ba 100644 --- a/api/services/dataset_service.py +++ b/api/services/dataset_service.py @@ -25,7 +25,7 @@ from core.model_runtime.model_providers.__base.text_embedding_model import TextE from core.rag.index_processor.constant.built_in_field import BuiltInField from core.rag.index_processor.constant.index_type import IndexStructureType from core.rag.retrieval.retrieval_methods import RetrievalMethod -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from enums.cloud_plan import CloudPlan from events.dataset_event import dataset_was_deleted from events.document_event import document_was_deleted diff --git a/api/services/external_knowledge_service.py b/api/services/external_knowledge_service.py index 65dd41af43..4cf42b7f44 100644 --- a/api/services/external_knowledge_service.py +++ b/api/services/external_knowledge_service.py @@ -9,7 +9,7 @@ from sqlalchemy import select from constants import HIDDEN_VALUE from core.helper import ssrf_proxy from core.rag.entities.metadata_entities import MetadataCondition -from core.workflow.nodes.http_request.exc import InvalidHttpMethodError +from dify_graph.nodes.http_request.exc import InvalidHttpMethodError from extensions.ext_database import db from libs.datetime_utils import naive_utc_now from models.dataset import ( diff --git a/api/services/file_service.py b/api/services/file_service.py index da99a66bb9..e08b78bf4c 100644 --- a/api/services/file_service.py +++ b/api/services/file_service.py @@ -20,7 +20,7 @@ from constants import ( VIDEO_EXTENSIONS, ) from core.rag.extractor.extract_processor import ExtractProcessor -from core.workflow.file import helpers as file_helpers +from dify_graph.file import helpers as file_helpers from extensions.ext_database import db from extensions.ext_storage import storage from libs.datetime_utils import naive_utc_now diff --git a/api/services/human_input_delivery_test_service.py b/api/services/human_input_delivery_test_service.py index ff37ff098f..7b43c49686 100644 --- a/api/services/human_input_delivery_test_service.py +++ b/api/services/human_input_delivery_test_service.py @@ -8,14 +8,14 @@ from sqlalchemy import Engine, select from sqlalchemy.orm import sessionmaker from configs import dify_config -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( DeliveryChannelConfig, EmailDeliveryConfig, EmailDeliveryMethod, ExternalRecipient, MemberRecipient, ) -from core.workflow.runtime import VariablePool +from dify_graph.runtime import VariablePool from extensions.ext_database import db from extensions.ext_mail import mail from libs.email_template_renderer import render_email_template diff --git a/api/services/human_input_service.py b/api/services/human_input_service.py index 87816643f6..cfab723fef 100644 --- a/api/services/human_input_service.py +++ b/api/services/human_input_service.py @@ -11,12 +11,12 @@ from core.repositories.human_input_repository import ( HumanInputFormRecord, HumanInputFormSubmissionRepository, ) -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( FormDefinition, HumanInputSubmissionValidationError, validate_human_input_submission, ) -from core.workflow.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus +from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus from libs.datetime_utils import ensure_naive_utc, naive_utc_now from libs.exception import BaseHTTPException from models.human_input import RecipientType diff --git a/api/services/rag_pipeline/rag_pipeline.py b/api/services/rag_pipeline/rag_pipeline.py index c0f9e4f323..ce745a4679 100644 --- a/api/services/rag_pipeline/rag_pipeline.py +++ b/api/services/rag_pipeline/rag_pipeline.py @@ -36,23 +36,23 @@ from core.rag.entities.event import ( ) from core.repositories.factory import DifyCoreRepositoryFactory from core.repositories.sqlalchemy_workflow_node_execution_repository import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import ( +from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, WorkflowNodeExecutionStatus, ) -from core.workflow.enums import ErrorStrategy, NodeType, SystemVariableKey -from core.workflow.errors import WorkflowNodeRunFailedError -from core.workflow.graph_events import NodeRunFailedEvent, NodeRunSucceededEvent -from core.workflow.graph_events.base import GraphNodeEventBase -from core.workflow.node_events.base import NodeRunResult -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, build_http_request_config -from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig -from core.workflow.runtime import VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.variables import VariableBase -from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.enums import ErrorStrategy, NodeType, SystemVariableKey +from dify_graph.errors import WorkflowNodeRunFailedError +from dify_graph.graph_events import NodeRunFailedEvent, NodeRunSucceededEvent +from dify_graph.graph_events.base import GraphNodeEventBase +from dify_graph.node_events.base import NodeRunResult +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, build_http_request_config +from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig +from dify_graph.runtime import VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.variables import VariableBase from extensions.ext_database import db from libs.infinite_scroll_pagination import InfiniteScrollPagination from models import Account diff --git a/api/services/rag_pipeline/rag_pipeline_dsl_service.py b/api/services/rag_pipeline/rag_pipeline_dsl_service.py index be1ce834f6..0a257a587d 100644 --- a/api/services/rag_pipeline/rag_pipeline_dsl_service.py +++ b/api/services/rag_pipeline/rag_pipeline_dsl_service.py @@ -23,13 +23,13 @@ from core.helper import ssrf_proxy from core.helper.name_generator import generate_incremental_name from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import PluginDependency -from core.workflow.enums import NodeType -from core.workflow.nodes.datasource.entities import DatasourceNodeData -from core.workflow.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData -from core.workflow.nodes.llm.entities import LLMNodeData -from core.workflow.nodes.parameter_extractor.entities import ParameterExtractorNodeData -from core.workflow.nodes.question_classifier.entities import QuestionClassifierNodeData -from core.workflow.nodes.tool.entities import ToolNodeData +from dify_graph.enums import NodeType +from dify_graph.nodes.datasource.entities import DatasourceNodeData +from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData +from dify_graph.nodes.llm.entities import LLMNodeData +from dify_graph.nodes.parameter_extractor.entities import ParameterExtractorNodeData +from dify_graph.nodes.question_classifier.entities import QuestionClassifierNodeData +from dify_graph.nodes.tool.entities import ToolNodeData from extensions.ext_redis import redis_client from factories import variable_factory from models import Account diff --git a/api/services/retention/workflow_run/archive_paid_plan_workflow_run.py b/api/services/retention/workflow_run/archive_paid_plan_workflow_run.py index ea5cbb7740..00a2144800 100644 --- a/api/services/retention/workflow_run/archive_paid_plan_workflow_run.py +++ b/api/services/retention/workflow_run/archive_paid_plan_workflow_run.py @@ -31,7 +31,7 @@ from sqlalchemy import inspect from sqlalchemy.orm import Session, sessionmaker from configs import dify_config -from core.workflow.enums import WorkflowType +from dify_graph.enums import WorkflowType from enums.cloud_plan import CloudPlan from extensions.ext_database import db from libs.archive_storage import ( diff --git a/api/services/trigger/schedule_service.py b/api/services/trigger/schedule_service.py index b49d14f860..8389ccbb34 100644 --- a/api/services/trigger/schedule_service.py +++ b/api/services/trigger/schedule_service.py @@ -7,9 +7,9 @@ from typing import Any from sqlalchemy import select from sqlalchemy.orm import Session -from core.workflow.nodes import NodeType -from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig -from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError, ScheduleNotFoundError +from dify_graph.nodes import NodeType +from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig +from dify_graph.nodes.trigger_schedule.exc import ScheduleConfigError, ScheduleNotFoundError from libs.schedule_utils import calculate_next_run_at, convert_12h_to_24h from models.account import Account, TenantAccountJoin from models.trigger import WorkflowSchedulePlan diff --git a/api/services/trigger/trigger_service.py b/api/services/trigger/trigger_service.py index 7f12c2e19c..f1f0d0ea84 100644 --- a/api/services/trigger/trigger_service.py +++ b/api/services/trigger/trigger_service.py @@ -16,8 +16,8 @@ from core.trigger.debug.events import PluginTriggerDebugEvent from core.trigger.provider import PluginTriggerProviderController from core.trigger.trigger_manager import TriggerManager from core.trigger.utils.encryption import create_trigger_provider_encrypter_for_subscription -from core.workflow.enums import NodeType -from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData +from dify_graph.enums import NodeType +from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData from extensions.ext_database import db from extensions.ext_redis import redis_client from models.model import App diff --git a/api/services/trigger/webhook_service.py b/api/services/trigger/webhook_service.py index 75a1350e60..285645edce 100644 --- a/api/services/trigger/webhook_service.py +++ b/api/services/trigger/webhook_service.py @@ -16,9 +16,9 @@ from werkzeug.exceptions import RequestEntityTooLarge from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom from core.tools.tool_file_manager import ToolFileManager -from core.workflow.enums import NodeType -from core.workflow.file.models import FileTransferMethod -from core.workflow.variables.types import SegmentType +from dify_graph.enums import NodeType +from dify_graph.file.models import FileTransferMethod +from dify_graph.variables.types import SegmentType from enums.quota_type import QuotaType from extensions.ext_database import db from extensions.ext_redis import redis_client diff --git a/api/services/variable_truncator.py b/api/services/variable_truncator.py index 12be12776a..60dc1dedb8 100644 --- a/api/services/variable_truncator.py +++ b/api/services/variable_truncator.py @@ -6,9 +6,9 @@ from collections.abc import Mapping from typing import Any, Generic, TypeAlias, TypeVar, overload from configs import dify_config -from core.workflow.file.models import File -from core.workflow.nodes.variable_assigner.common.helpers import UpdatedVariable -from core.workflow.variables.segments import ( +from dify_graph.file.models import File +from dify_graph.nodes.variable_assigner.common.helpers import UpdatedVariable +from dify_graph.variables.segments import ( ArrayFileSegment, ArraySegment, BooleanSegment, @@ -20,7 +20,7 @@ from core.workflow.variables.segments import ( Segment, StringSegment, ) -from core.workflow.variables.utils import dumps_with_segments +from dify_graph.variables.utils import dumps_with_segments _MAX_DEPTH = 100 diff --git a/api/services/workflow/workflow_converter.py b/api/services/workflow/workflow_converter.py index 5527c108a2..8b4b3318e1 100644 --- a/api/services/workflow/workflow_converter.py +++ b/api/services/workflow/workflow_converter.py @@ -17,9 +17,9 @@ from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.simple_prompt_transform import SimplePromptTransform from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.file.models import FileUploadConfig -from core.workflow.nodes import NodeType -from core.workflow.variables.input_entities import VariableEntity +from dify_graph.file.models import FileUploadConfig +from dify_graph.nodes import NodeType +from dify_graph.variables.input_entities import VariableEntity from events.app_event import app_was_created from extensions.ext_database import db from models import Account diff --git a/api/services/workflow_app_service.py b/api/services/workflow_app_service.py index efc76c33bc..44bc64ec11 100644 --- a/api/services/workflow_app_service.py +++ b/api/services/workflow_app_service.py @@ -6,7 +6,7 @@ from typing import Any from sqlalchemy import and_, func, or_, select from sqlalchemy.orm import Session -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from models import Account, App, EndUser, WorkflowAppLog, WorkflowArchiveLog, WorkflowRun from models.enums import AppTriggerType, CreatorUserRole from models.trigger import WorkflowTriggerLog diff --git a/api/services/workflow_draft_variable_service.py b/api/services/workflow_draft_variable_service.py index 18ad6c5c16..b6f6fc5490 100644 --- a/api/services/workflow_draft_variable_service.py +++ b/api/services/workflow_draft_variable_service.py @@ -14,20 +14,20 @@ from sqlalchemy.sql.expression import and_, or_ from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.enums import SystemVariableKey -from core.workflow.file.models import File -from core.workflow.nodes import NodeType -from core.workflow.nodes.variable_assigner.common.helpers import get_updated_variables -from core.workflow.variable_loader import VariableLoader -from core.workflow.variables import Segment, StringSegment, VariableBase -from core.workflow.variables.consts import SELECTORS_LENGTH -from core.workflow.variables.segments import ( +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.enums import SystemVariableKey +from dify_graph.file.models import File +from dify_graph.nodes import NodeType +from dify_graph.nodes.variable_assigner.common.helpers import get_updated_variables +from dify_graph.variable_loader import VariableLoader +from dify_graph.variables import Segment, StringSegment, VariableBase +from dify_graph.variables.consts import SELECTORS_LENGTH +from dify_graph.variables.segments import ( ArrayFileSegment, FileSegment, ) -from core.workflow.variables.types import SegmentType -from core.workflow.variables.utils import dumps_with_segments +from dify_graph.variables.types import SegmentType +from dify_graph.variables.utils import dumps_with_segments from extensions.ext_storage import storage from factories.file_factory import StorageKeyLoader from factories.variable_factory import build_segment, segment_to_variable @@ -70,7 +70,7 @@ class UpdateNotSupportedError(WorkflowDraftVariableError): class DraftVarLoader(VariableLoader): # This implements the VariableLoader interface for loading draft variables. # - # ref: core.workflow.variable_loader.VariableLoader + # ref: dify_graph.variable_loader.VariableLoader # Database engine used for loading variables. _engine: Engine diff --git a/api/services/workflow_event_snapshot_service.py b/api/services/workflow_event_snapshot_service.py index 09037a92ce..8f323ebb8b 100644 --- a/api/services/workflow_event_snapshot_service.py +++ b/api/services/workflow_event_snapshot_service.py @@ -22,10 +22,10 @@ from core.app.entities.task_entities import ( WorkflowStartStreamResponse, ) from core.app.layers.pause_state_persist_layer import WorkflowResumptionContext -from core.workflow.entities import WorkflowStartReason -from core.workflow.enums import WorkflowExecutionStatus, WorkflowNodeExecutionStatus -from core.workflow.runtime import GraphRuntimeState -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities import WorkflowStartReason +from dify_graph.enums import WorkflowExecutionStatus, WorkflowNodeExecutionStatus +from dify_graph.runtime import GraphRuntimeState +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from models.model import AppMode, Message from models.workflow import WorkflowNodeExecutionTriggeredFrom, WorkflowRun from repositories.api_workflow_node_execution_repository import WorkflowNodeExecutionSnapshot diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index 3b448423e8..2bf291da54 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -14,34 +14,34 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager from core.app.entities.app_invoke_entities import InvokeFrom from core.repositories import DifyCoreRepositoryFactory from core.repositories.human_input_repository import HumanInputFormRepositoryImpl -from core.workflow.entities import GraphInitParams, WorkflowNodeExecution -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import ErrorStrategy, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.errors import WorkflowNodeRunFailedError -from core.workflow.file import File -from core.workflow.graph_events import GraphNodeEventBase, NodeRunFailedEvent, NodeRunSucceededEvent -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes import NodeType -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, build_http_request_config -from core.workflow.nodes.human_input.entities import ( +from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.entities import GraphInitParams, WorkflowNodeExecution +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import ErrorStrategy, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.errors import WorkflowNodeRunFailedError +from dify_graph.file import File +from dify_graph.graph_events import GraphNodeEventBase, NodeRunFailedEvent, NodeRunSucceededEvent +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes import NodeType +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, build_http_request_config +from dify_graph.nodes.human_input.entities import ( DeliveryChannelConfig, HumanInputNodeData, apply_debug_email_recipient, validate_human_input_submission, ) -from core.workflow.nodes.human_input.enums import HumanInputFormKind -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.repositories.human_input_form_repository import FormCreateParams -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variable_loader import load_into_variable_pool -from core.workflow.variables import VariableBase -from core.workflow.variables.input_entities import VariableEntityType -from core.workflow.variables.variables import Variable -from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.nodes.human_input.enums import HumanInputFormKind +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.node_mapping import LATEST_VERSION, NODE_TYPE_CLASSES_MAPPING +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.repositories.human_input_form_repository import FormCreateParams +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variable_loader import load_into_variable_pool +from dify_graph.variables import VariableBase +from dify_graph.variables.input_entities import VariableEntityType +from dify_graph.variables.variables import Variable from enums.cloud_plan import CloudPlan from events.app_event import app_draft_workflow_was_synced, app_published_workflow_was_updated from extensions.ext_database import db @@ -1360,7 +1360,7 @@ class WorkflowService: Raises: ValueError: If the node data format is invalid """ - from core.workflow.nodes.human_input.entities import HumanInputNodeData + from dify_graph.nodes.human_input.entities import HumanInputNodeData try: HumanInputNodeData.model_validate(node_data) diff --git a/api/tasks/app_generate/workflow_execute_task.py b/api/tasks/app_generate/workflow_execute_task.py index e58d334f41..dfd15f4123 100644 --- a/api/tasks/app_generate/workflow_execute_task.py +++ b/api/tasks/app_generate/workflow_execute_task.py @@ -21,7 +21,7 @@ from core.app.entities.app_invoke_entities import ( ) from core.app.layers.pause_state_persist_layer import PauseStateLayerConfig, WorkflowResumptionContext from core.repositories import DifyCoreRepositoryFactory -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState from extensions.ext_database import db from libs.flask_utils import set_login_user from models.account import Account diff --git a/api/tasks/async_workflow_tasks.py b/api/tasks/async_workflow_tasks.py index cc96542d4b..d247cf5cf7 100644 --- a/api/tasks/async_workflow_tasks.py +++ b/api/tasks/async_workflow_tasks.py @@ -21,7 +21,7 @@ from core.app.layers.timeslice_layer import TimeSliceLayer from core.app.layers.trigger_post_layer import TriggerPostLayer from core.db.session_factory import session_factory from core.repositories import DifyCoreRepositoryFactory -from core.workflow.runtime import GraphRuntimeState +from dify_graph.runtime import GraphRuntimeState from extensions.ext_database import db from models.account import Account from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom, WorkflowTriggerStatus diff --git a/api/tasks/human_input_timeout_tasks.py b/api/tasks/human_input_timeout_tasks.py index 5413a33d6a..03441683b0 100644 --- a/api/tasks/human_input_timeout_tasks.py +++ b/api/tasks/human_input_timeout_tasks.py @@ -7,8 +7,8 @@ from sqlalchemy.orm import sessionmaker from configs import dify_config from core.repositories.human_input_repository import HumanInputFormSubmissionRepository -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus from extensions.ext_database import db from extensions.ext_storage import storage from libs.datetime_utils import ensure_naive_utc, naive_utc_now diff --git a/api/tasks/mail_human_input_delivery_task.py b/api/tasks/mail_human_input_delivery_task.py index d1cd0fbadc..bded4cea2b 100644 --- a/api/tasks/mail_human_input_delivery_task.py +++ b/api/tasks/mail_human_input_delivery_task.py @@ -11,8 +11,8 @@ from sqlalchemy.orm import Session, sessionmaker from configs import dify_config from core.app.layers.pause_state_persist_layer import WorkflowResumptionContext -from core.workflow.nodes.human_input.entities import EmailDeliveryConfig, EmailDeliveryMethod -from core.workflow.runtime import GraphRuntimeState, VariablePool +from dify_graph.nodes.human_input.entities import EmailDeliveryConfig, EmailDeliveryMethod +from dify_graph.runtime import GraphRuntimeState, VariablePool from extensions.ext_database import db from extensions.ext_mail import mail from models.human_input import ( diff --git a/api/tasks/trigger_processing_tasks.py b/api/tasks/trigger_processing_tasks.py index d18ea2c23c..d06b8c980b 100644 --- a/api/tasks/trigger_processing_tasks.py +++ b/api/tasks/trigger_processing_tasks.py @@ -25,8 +25,8 @@ from core.trigger.debug.events import PluginTriggerDebugEvent, build_plugin_pool from core.trigger.entities.entities import TriggerProviderEntity from core.trigger.provider import PluginTriggerProviderController from core.trigger.trigger_manager import TriggerManager -from core.workflow.enums import NodeType, WorkflowExecutionStatus -from core.workflow.nodes.trigger_plugin.entities import TriggerEventNodeData +from dify_graph.enums import NodeType, WorkflowExecutionStatus +from dify_graph.nodes.trigger_plugin.entities import TriggerEventNodeData from enums.quota_type import QuotaType, unlimited from models.enums import ( AppTriggerType, diff --git a/api/tasks/workflow_execution_tasks.py b/api/tasks/workflow_execution_tasks.py index 3b3c6e5313..db8721e90b 100644 --- a/api/tasks/workflow_execution_tasks.py +++ b/api/tasks/workflow_execution_tasks.py @@ -12,8 +12,8 @@ from celery import shared_task from sqlalchemy import select from core.db.session_factory import session_factory -from core.workflow.entities.workflow_execution import WorkflowExecution -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.entities.workflow_execution import WorkflowExecution +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from models import CreatorUserRole, WorkflowRun from models.enums import WorkflowRunTriggeredFrom diff --git a/api/tasks/workflow_node_execution_tasks.py b/api/tasks/workflow_node_execution_tasks.py index b30a4ff15b..3f607dc55e 100644 --- a/api/tasks/workflow_node_execution_tasks.py +++ b/api/tasks/workflow_node_execution_tasks.py @@ -12,10 +12,10 @@ from celery import shared_task from sqlalchemy import select from core.db.session_factory import session_factory -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, ) -from core.workflow.workflow_type_encoder import WorkflowRuntimeTypeConverter +from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from models import CreatorUserRole, WorkflowNodeExecutionModel from models.workflow import WorkflowNodeExecutionTriggeredFrom diff --git a/api/tasks/workflow_schedule_tasks.py b/api/tasks/workflow_schedule_tasks.py index 8c64d3ab27..ced7ef973b 100644 --- a/api/tasks/workflow_schedule_tasks.py +++ b/api/tasks/workflow_schedule_tasks.py @@ -3,7 +3,7 @@ import logging from celery import shared_task from core.db.session_factory import session_factory -from core.workflow.nodes.trigger_schedule.exc import ( +from dify_graph.nodes.trigger_schedule.exc import ( ScheduleExecutionError, ScheduleNotFoundError, TenantOwnerNotFoundError, diff --git a/api/tests/integration_tests/core/datasource/test_datasource_manager_integration.py b/api/tests/integration_tests/core/datasource/test_datasource_manager_integration.py index 003bb356e5..4fdbb7d9f3 100644 --- a/api/tests/integration_tests/core/datasource/test_datasource_manager_integration.py +++ b/api/tests/integration_tests/core/datasource/test_datasource_manager_integration.py @@ -2,7 +2,7 @@ from collections.abc import Generator from core.datasource.datasource_manager import DatasourceManager from core.datasource.entities.datasource_entities import DatasourceMessage -from core.workflow.node_events import StreamCompletedEvent +from dify_graph.node_events import StreamCompletedEvent def _gen_var_stream() -> Generator[DatasourceMessage, None, None]: diff --git a/api/tests/integration_tests/core/workflow/nodes/datasource/test_datasource_node_integration.py b/api/tests/integration_tests/core/workflow/nodes/datasource/test_datasource_node_integration.py index 909d6377ce..c043c7dc10 100644 --- a/api/tests/integration_tests/core/workflow/nodes/datasource/test_datasource_node_integration.py +++ b/api/tests/integration_tests/core/workflow/nodes/datasource/test_datasource_node_integration.py @@ -1,6 +1,6 @@ -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult, StreamCompletedEvent -from core.workflow.nodes.datasource.datasource_node import DatasourceNode +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult, StreamCompletedEvent +from dify_graph.nodes.datasource.datasource_node import DatasourceNode class _Seg: diff --git a/api/tests/integration_tests/factories/test_storage_key_loader.py b/api/tests/integration_tests/factories/test_storage_key_loader.py index 16a66bc3f1..b4e3a0e4de 100644 --- a/api/tests/integration_tests/factories/test_storage_key_loader.py +++ b/api/tests/integration_tests/factories/test_storage_key_loader.py @@ -6,7 +6,7 @@ from uuid import uuid4 import pytest from sqlalchemy.orm import Session -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from extensions.ext_database import db from factories.file_factory import StorageKeyLoader from models import ToolFile, UploadFile diff --git a/api/tests/integration_tests/services/test_workflow_draft_variable_service.py b/api/tests/integration_tests/services/test_workflow_draft_variable_service.py index 5faa002fff..7c4dcda2dc 100644 --- a/api/tests/integration_tests/services/test_workflow_draft_variable_service.py +++ b/api/tests/integration_tests/services/test_workflow_draft_variable_service.py @@ -6,11 +6,11 @@ import pytest from sqlalchemy import delete from sqlalchemy.orm import Session -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.nodes import NodeType -from core.workflow.variables.segments import StringSegment -from core.workflow.variables.types import SegmentType -from core.workflow.variables.variables import StringVariable +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.nodes import NodeType +from dify_graph.variables.segments import StringSegment +from dify_graph.variables.types import SegmentType +from dify_graph.variables.variables import StringVariable from extensions.ext_database import db from extensions.ext_storage import storage from factories.variable_factory import build_segment diff --git a/api/tests/integration_tests/tasks/test_remove_app_and_related_data_task.py b/api/tests/integration_tests/tasks/test_remove_app_and_related_data_task.py index a259ccb2b9..988313e68d 100644 --- a/api/tests/integration_tests/tasks/test_remove_app_and_related_data_task.py +++ b/api/tests/integration_tests/tasks/test_remove_app_and_related_data_task.py @@ -5,7 +5,7 @@ import pytest from sqlalchemy import delete from core.db.session_factory import session_factory -from core.workflow.variables.segments import StringSegment +from dify_graph.variables.segments import StringSegment from models import Tenant from models.enums import CreatorUserRole from models.model import App, UploadFile @@ -191,7 +191,7 @@ class TestDeleteDraftVariablesWithOffloadIntegration: @pytest.fixture def setup_offload_test_data(self, app_and_tenant): tenant, app = app_and_tenant - from core.workflow.variables.types import SegmentType + from dify_graph.variables.types import SegmentType from libs.datetime_utils import naive_utc_now with session_factory.create_session() as session: @@ -422,7 +422,7 @@ class TestDeleteDraftVariablesSessionCommit: @pytest.fixture def setup_offload_test_data(self, app_and_tenant): """Create test data with offload files for session commit tests.""" - from core.workflow.variables.types import SegmentType + from dify_graph.variables.types import SegmentType from libs.datetime_utils import naive_utc_now tenant, app = app_and_tenant diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index e0ea14b789..c433e95b7a 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -5,15 +5,15 @@ import pytest from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.code.code_node import CodeNode -from core.workflow.nodes.code.limits import CodeNodeLimits -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.code.code_node import CodeNode +from dify_graph.nodes.code.limits import CodeNodeLimits +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock diff --git a/api/tests/integration_tests/workflow/nodes/test_http.py b/api/tests/integration_tests/workflow/nodes/test_http.py index e0f2363799..31cdb655fa 100644 --- a/api/tests/integration_tests/workflow/nodes/test_http.py +++ b/api/tests/integration_tests/workflow/nodes/test_http.py @@ -6,16 +6,16 @@ import pytest from configs import dify_config from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory from core.helper.ssrf_proxy import ssrf_proxy from core.tools.tool_file_manager import ToolFileManager -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.file.file_manager import file_manager -from core.workflow.graph import Graph -from core.workflow.nodes.http_request import HttpRequestNode, HttpRequestNodeConfig -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.file.file_manager import file_manager +from dify_graph.graph import Graph +from dify_graph.nodes.http_request import HttpRequestNode, HttpRequestNodeConfig +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom from tests.integration_tests.workflow.nodes.__mock.http import setup_http_mock @@ -190,15 +190,15 @@ def test_custom_authorization_header(setup_http_mock): @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True) def test_custom_auth_with_empty_api_key_raises_error(setup_http_mock): """Test: In custom authentication mode, when the api_key is empty, AuthorizationConfigError should be raised.""" - from core.workflow.nodes.http_request.entities import ( + from dify_graph.nodes.http_request.entities import ( HttpRequestNodeAuthorization, HttpRequestNodeData, HttpRequestNodeTimeout, ) - from core.workflow.nodes.http_request.exc import AuthorizationConfigError - from core.workflow.nodes.http_request.executor import Executor - from core.workflow.runtime import VariablePool - from core.workflow.system_variable import SystemVariable + from dify_graph.nodes.http_request.exc import AuthorizationConfigError + from dify_graph.nodes.http_request.executor import Executor + from dify_graph.runtime import VariablePool + from dify_graph.system_variable import SystemVariable # Create variable pool variable_pool = VariablePool( diff --git a/api/tests/integration_tests/workflow/nodes/test_llm.py b/api/tests/integration_tests/workflow/nodes/test_llm.py index b5b0fb5334..07783792d1 100644 --- a/api/tests/integration_tests/workflow/nodes/test_llm.py +++ b/api/tests/integration_tests/workflow/nodes/test_llm.py @@ -7,13 +7,13 @@ from unittest.mock import MagicMock, patch from core.app.entities.app_invoke_entities import InvokeFrom from core.llm_generator.output_parser.structured_output import _parse_structured_output from core.model_manager import ModelInstance -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.node_events import StreamCompletedEvent -from core.workflow.nodes.llm.node import LLMNode -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.node_events import StreamCompletedEvent +from dify_graph.nodes.llm.node import LLMNode +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from extensions.ext_database import db from models.enums import UserFrom diff --git a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py index 773074e92d..7a3f5bc58e 100644 --- a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py +++ b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py @@ -6,12 +6,12 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.model_manager import ModelInstance from core.model_runtime.entities import AssistantPromptMessage, UserPromptMessage -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory -from core.workflow.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from extensions.ext_database import db from models.enums import UserFrom from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_instance diff --git a/api/tests/integration_tests/workflow/nodes/test_template_transform.py b/api/tests/integration_tests/workflow/nodes/test_template_transform.py index bc03ce1b96..1a8971baa6 100644 --- a/api/tests/integration_tests/workflow/nodes/test_template_transform.py +++ b/api/tests/integration_tests/workflow/nodes/test_template_transform.py @@ -4,13 +4,13 @@ import uuid import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.nodes.template_transform.template_transform_node import TemplateTransformNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock diff --git a/api/tests/integration_tests/workflow/nodes/test_tool.py b/api/tests/integration_tests/workflow/nodes/test_tool.py index cfbef52c93..58a1137dda 100644 --- a/api/tests/integration_tests/workflow/nodes/test_tool.py +++ b/api/tests/integration_tests/workflow/nodes/test_tool.py @@ -3,15 +3,15 @@ import uuid from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory from core.tools.utils.configuration import ToolParameterConfigurationManager -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.node_events import StreamCompletedEvent -from core.workflow.nodes.tool.tool_node import ToolNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.node_events import StreamCompletedEvent +from dify_graph.nodes.tool.tool_node import ToolNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom diff --git a/api/tests/test_containers_integration_tests/controllers/console/app/test_chat_conversation_status_count_api.py b/api/tests/test_containers_integration_tests/controllers/console/app/test_chat_conversation_status_count_api.py index 7fad603a6d..6f2e008d44 100644 --- a/api/tests/test_containers_integration_tests/controllers/console/app/test_chat_conversation_status_count_api.py +++ b/api/tests/test_containers_integration_tests/controllers/console/app/test_chat_conversation_status_count_api.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import Session from configs import dify_config from constants import HEADER_NAME_CSRF_TOKEN -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from libs.datetime_utils import naive_utc_now from libs.token import _real_cookie_name, generate_csrf_token from models import Account, DifySetup, Tenant, TenantAccountJoin diff --git a/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py b/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py index dcf31aeca7..5d6fcf4775 100644 --- a/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py +++ b/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py @@ -32,15 +32,15 @@ from core.app.layers.pause_state_persist_layer import ( WorkflowResumptionContext, ) from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.graph_engine.entities.commands import GraphEngineCommand -from core.workflow.graph_engine.layers.base import GraphEngineLayerNotInitializedError -from core.workflow.graph_events.graph import GraphRunPausedEvent -from core.workflow.runtime.graph_runtime_state import GraphRuntimeState -from core.workflow.runtime.graph_runtime_state_protocol import ReadOnlyGraphRuntimeState -from core.workflow.runtime.read_only_wrappers import ReadOnlyGraphRuntimeStateWrapper -from core.workflow.runtime.variable_pool import SystemVariable, VariablePool +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.graph_engine.entities.commands import GraphEngineCommand +from dify_graph.graph_engine.layers.base import GraphEngineLayerNotInitializedError +from dify_graph.graph_events.graph import GraphRunPausedEvent +from dify_graph.runtime.graph_runtime_state import GraphRuntimeState +from dify_graph.runtime.graph_runtime_state_protocol import ReadOnlyGraphRuntimeState +from dify_graph.runtime.read_only_wrappers import ReadOnlyGraphRuntimeStateWrapper +from dify_graph.runtime.variable_pool import SystemVariable, VariablePool from extensions.ext_storage import storage from libs.datetime_utils import naive_utc_now from models import Account @@ -544,7 +544,7 @@ class TestPauseStatePersistenceLayerTestContainers: layer.initialize(graph_runtime_state, command_channel) # Import other event types - from core.workflow.graph_events.graph import ( + from dify_graph.graph_events.graph import ( GraphRunFailedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, diff --git a/api/tests/test_containers_integration_tests/core/rag/retrieval/test_dataset_retrieval_integration.py b/api/tests/test_containers_integration_tests/core/rag/retrieval/test_dataset_retrieval_integration.py index 4e6cc620ac..e5d3655771 100644 --- a/api/tests/test_containers_integration_tests/core/rag/retrieval/test_dataset_retrieval_integration.py +++ b/api/tests/test_containers_integration_tests/core/rag/retrieval/test_dataset_retrieval_integration.py @@ -5,7 +5,7 @@ import pytest from faker import Faker from core.rag.retrieval.dataset_retrieval import DatasetRetrieval -from core.workflow.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest +from dify_graph.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest from models.dataset import Dataset, Document from services.account_service import AccountService, TenantService diff --git a/api/tests/test_containers_integration_tests/core/repositories/test_human_input_form_repository_impl.py b/api/tests/test_containers_integration_tests/core/repositories/test_human_input_form_repository_impl.py index 079e4934bb..4b362d1abe 100644 --- a/api/tests/test_containers_integration_tests/core/repositories/test_human_input_form_repository_impl.py +++ b/api/tests/test_containers_integration_tests/core/repositories/test_human_input_form_repository_impl.py @@ -8,7 +8,7 @@ from sqlalchemy import Engine, select from sqlalchemy.orm import Session from core.repositories.human_input_repository import HumanInputFormRepositoryImpl -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( DeliveryChannelConfig, EmailDeliveryConfig, EmailDeliveryMethod, @@ -20,7 +20,7 @@ from core.workflow.nodes.human_input.entities import ( UserAction, WebAppDeliveryMethod, ) -from core.workflow.repositories.human_input_form_repository import FormCreateParams +from dify_graph.repositories.human_input_form_repository import FormCreateParams from models.account import Account, Tenant, TenantAccountJoin, TenantAccountRole from models.human_input import ( EmailExternalRecipientPayload, diff --git a/api/tests/test_containers_integration_tests/core/workflow/test_human_input_resume_node_execution.py b/api/tests/test_containers_integration_tests/core/workflow/test_human_input_resume_node_execution.py index 06d55177eb..c4c9d62c84 100644 --- a/api/tests/test_containers_integration_tests/core/workflow/test_human_input_resume_node_execution.py +++ b/api/tests/test_containers_integration_tests/core/workflow/test_human_input_resume_node_execution.py @@ -12,21 +12,21 @@ from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerat from core.app.workflow.layers import PersistenceWorkflowInfo, WorkflowPersistenceLayer from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository from core.repositories.sqlalchemy_workflow_node_execution_repository import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowType -from core.workflow.graph import Graph -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_engine.graph_engine import GraphEngine -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowType +from dify_graph.graph import Graph +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_engine.graph_engine import GraphEngine +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from models import Account from models.account import Tenant, TenantAccountJoin, TenantAccountRole diff --git a/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py b/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py index 3568a8b070..cb7cd37a3f 100644 --- a/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py +++ b/api/tests/test_containers_integration_tests/factories/test_storage_key_loader.py @@ -6,7 +6,7 @@ from uuid import uuid4 import pytest from sqlalchemy.orm import Session -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from extensions.ext_database import db from factories.file_factory import StorageKeyLoader from models import ToolFile, UploadFile diff --git a/api/tests/test_containers_integration_tests/helpers/execution_extra_content.py b/api/tests/test_containers_integration_tests/helpers/execution_extra_content.py index 19d7772c39..573f84cb0b 100644 --- a/api/tests/test_containers_integration_tests/helpers/execution_extra_content.py +++ b/api/tests/test_containers_integration_tests/helpers/execution_extra_content.py @@ -5,7 +5,7 @@ from datetime import datetime, timedelta from decimal import Decimal from uuid import uuid4 -from core.workflow.nodes.human_input.entities import FormDefinition, UserAction +from dify_graph.nodes.human_input.entities import FormDefinition, UserAction from models.account import Account, Tenant, TenantAccountJoin from models.execution_extra_content import HumanInputContent from models.human_input import HumanInputForm, HumanInputFormStatus diff --git a/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_node_execution_repository.py b/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_node_execution_repository.py index 556c029b24..458862b0ec 100644 --- a/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_node_execution_repository.py +++ b/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_node_execution_repository.py @@ -8,7 +8,7 @@ from uuid import uuid4 from sqlalchemy import Engine, delete from sqlalchemy.orm import Session, sessionmaker -from core.workflow.enums import WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionStatus from libs.datetime_utils import naive_utc_now from models.enums import CreatorUserRole from models.workflow import WorkflowNodeExecutionModel diff --git a/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py b/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py index 05a868c0c2..76e586e65f 100644 --- a/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py +++ b/api/tests/test_containers_integration_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py @@ -11,9 +11,9 @@ import pytest from sqlalchemy import Engine, delete, select from sqlalchemy.orm import Session, sessionmaker -from core.workflow.entities import WorkflowExecution -from core.workflow.entities.pause_reason import PauseReasonType -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.entities import WorkflowExecution +from dify_graph.entities.pause_reason import PauseReasonType +from dify_graph.enums import WorkflowExecutionStatus from extensions.ext_storage import storage from libs.datetime_utils import naive_utc_now from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom diff --git a/api/tests/test_containers_integration_tests/services/test_agent_service.py b/api/tests/test_containers_integration_tests/services/test_agent_service.py index e7cc140582..00bce32f48 100644 --- a/api/tests/test_containers_integration_tests/services/test_agent_service.py +++ b/api/tests/test_containers_integration_tests/services/test_agent_service.py @@ -841,7 +841,7 @@ class TestAgentService: app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies) conversation, message = self._create_test_conversation_and_message(db_session_with_containers, app, account) - from core.workflow.file import FileTransferMethod, FileType + from dify_graph.file import FileTransferMethod, FileType from extensions.ext_database import db from models.enums import CreatorUserRole diff --git a/api/tests/test_containers_integration_tests/services/test_delete_archived_workflow_run.py b/api/tests/test_containers_integration_tests/services/test_delete_archived_workflow_run.py index 546292109e..5f86cb2ae9 100644 --- a/api/tests/test_containers_integration_tests/services/test_delete_archived_workflow_run.py +++ b/api/tests/test_containers_integration_tests/services/test_delete_archived_workflow_run.py @@ -7,7 +7,7 @@ from uuid import uuid4 from sqlalchemy import select -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom from models.workflow import WorkflowArchiveLog, WorkflowRun from services.retention.workflow_run.delete_archived_workflow_run import ArchivedWorkflowRunDeletion diff --git a/api/tests/test_containers_integration_tests/services/test_human_input_delivery_test.py b/api/tests/test_containers_integration_tests/services/test_human_input_delivery_test.py index 9c978f830f..08f99cf55a 100644 --- a/api/tests/test_containers_integration_tests/services/test_human_input_delivery_test.py +++ b/api/tests/test_containers_integration_tests/services/test_human_input_delivery_test.py @@ -4,8 +4,8 @@ from unittest.mock import MagicMock import pytest -from core.workflow.enums import NodeType -from core.workflow.nodes.human_input.entities import ( +from dify_graph.enums import NodeType +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, diff --git a/api/tests/test_containers_integration_tests/services/test_workflow_app_service.py b/api/tests/test_containers_integration_tests/services/test_workflow_app_service.py index 040fb826e1..ce25eec6f0 100644 --- a/api/tests/test_containers_integration_tests/services/test_workflow_app_service.py +++ b/api/tests/test_containers_integration_tests/services/test_workflow_app_service.py @@ -6,7 +6,7 @@ from unittest.mock import patch import pytest from faker import Faker -from core.workflow.entities.workflow_execution import WorkflowExecutionStatus +from dify_graph.entities.workflow_execution import WorkflowExecutionStatus from models import EndUser, Workflow, WorkflowAppLog, WorkflowRun from models.enums import CreatorUserRole from services.account_service import AccountService, TenantService diff --git a/api/tests/test_containers_integration_tests/services/test_workflow_draft_variable_service.py b/api/tests/test_containers_integration_tests/services/test_workflow_draft_variable_service.py index 1f91b40963..624251cd6c 100644 --- a/api/tests/test_containers_integration_tests/services/test_workflow_draft_variable_service.py +++ b/api/tests/test_containers_integration_tests/services/test_workflow_draft_variable_service.py @@ -1,8 +1,8 @@ import pytest from faker import Faker -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.variables.segments import StringSegment +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.variables.segments import StringSegment from models import App, Workflow from models.enums import DraftVariableType from models.workflow import WorkflowDraftVariable @@ -467,7 +467,7 @@ class TestWorkflowDraftVariableService: fake = Faker() app = self._create_test_app(db_session_with_containers, mock_external_service_dependencies, fake=fake) workflow = self._create_test_workflow(db_session_with_containers, app, fake=fake) - from core.workflow.variables.variables import StringVariable + from dify_graph.variables.variables import StringVariable conv_var = StringVariable( id=fake.uuid4(), @@ -650,7 +650,7 @@ class TestWorkflowDraftVariableService: fake = Faker() app = self._create_test_app(db_session_with_containers, mock_external_service_dependencies, fake=fake) workflow = self._create_test_workflow(db_session_with_containers, app, fake=fake) - from core.workflow.variables.variables import StringVariable + from dify_graph.variables.variables import StringVariable conv_var1 = StringVariable( id=fake.uuid4(), diff --git a/api/tests/test_containers_integration_tests/services/test_workflow_service.py b/api/tests/test_containers_integration_tests/services/test_workflow_service.py index c29cda9a73..ef575a9b69 100644 --- a/api/tests/test_containers_integration_tests/services/test_workflow_service.py +++ b/api/tests/test_containers_integration_tests/services/test_workflow_service.py @@ -1393,8 +1393,8 @@ class TestWorkflowService: from unittest.mock import patch - from core.app.workflow.node_factory import DifyNodeFactory from core.model_manager import ModelInstance + from core.workflow.node_factory import DifyNodeFactory # Act with patch.object( @@ -1472,10 +1472,10 @@ class TestWorkflowService: import uuid from datetime import datetime - from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus - from core.workflow.graph_events import NodeRunSucceededEvent - from core.workflow.node_events import NodeRunResult - from core.workflow.nodes.base.node import Node + from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus + from dify_graph.graph_events import NodeRunSucceededEvent + from dify_graph.node_events import NodeRunResult + from dify_graph.nodes.base.node import Node # Create mock node mock_node = MagicMock(spec=Node) @@ -1517,12 +1517,12 @@ class TestWorkflowService: # Assert assert result is not None assert result.node_id == node_id - from core.workflow.enums import NodeType + from dify_graph.enums import NodeType assert result.node_type == NodeType.START # Should match the mock node type assert result.title == "Test Node" # Import the enum for comparison - from core.workflow.enums import WorkflowNodeExecutionStatus + from dify_graph.enums import WorkflowNodeExecutionStatus assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED assert result.inputs is not None @@ -1547,10 +1547,10 @@ class TestWorkflowService: import uuid from datetime import datetime - from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus - from core.workflow.graph_events import NodeRunFailedEvent - from core.workflow.node_events import NodeRunResult - from core.workflow.nodes.base.node import Node + from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus + from dify_graph.graph_events import NodeRunFailedEvent + from dify_graph.node_events import NodeRunResult + from dify_graph.nodes.base.node import Node # Create mock node mock_node = MagicMock(spec=Node) @@ -1592,7 +1592,7 @@ class TestWorkflowService: assert result is not None assert result.node_id == node_id # Import the enum for comparison - from core.workflow.enums import WorkflowNodeExecutionStatus + from dify_graph.enums import WorkflowNodeExecutionStatus assert result.status == WorkflowNodeExecutionStatus.FAILED assert result.error is not None @@ -1616,10 +1616,10 @@ class TestWorkflowService: import uuid from datetime import datetime - from core.workflow.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus - from core.workflow.graph_events import NodeRunFailedEvent - from core.workflow.node_events import NodeRunResult - from core.workflow.nodes.base.node import Node + from dify_graph.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus + from dify_graph.graph_events import NodeRunFailedEvent + from dify_graph.node_events import NodeRunResult + from dify_graph.nodes.base.node import Node # Create mock node with continue_on_error mock_node = MagicMock(spec=Node) @@ -1662,7 +1662,7 @@ class TestWorkflowService: assert result is not None assert result.node_id == node_id # Import the enum for comparison - from core.workflow.enums import WorkflowNodeExecutionStatus + from dify_graph.enums import WorkflowNodeExecutionStatus assert result.status == WorkflowNodeExecutionStatus.EXCEPTION # Should be EXCEPTION, not FAILED assert result.outputs is not None diff --git a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py index 2ffb884b82..c2cf249d61 100644 --- a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py +++ b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py @@ -13,7 +13,7 @@ from core.app.app_config.entities import ( ) from core.model_runtime.entities.llm_entities import LLMMode from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models import Account, Tenant from models.api_based_extension import APIBasedExtension from models.model import App, AppMode, AppModelConfig diff --git a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_node_execution_service_repository.py b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_node_execution_service_repository.py index f3ba126706..af9e8d0b2c 100644 --- a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_node_execution_service_repository.py +++ b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_node_execution_service_repository.py @@ -4,7 +4,7 @@ from uuid import uuid4 from sqlalchemy import Engine, select from sqlalchemy.orm import Session, sessionmaker -from core.workflow.enums import WorkflowNodeExecutionStatus +from dify_graph.enums import WorkflowNodeExecutionStatus from libs.datetime_utils import naive_utc_now from models.enums import CreatorUserRole from models.workflow import WorkflowNodeExecutionModel diff --git a/api/tests/test_containers_integration_tests/tasks/test_mail_human_input_delivery_task.py b/api/tests/test_containers_integration_tests/tasks/test_mail_human_input_delivery_task.py index 5fd6c56f7a..c9bcba6639 100644 --- a/api/tests/test_containers_integration_tests/tasks/test_mail_human_input_delivery_task.py +++ b/api/tests/test_containers_integration_tests/tasks/test_mail_human_input_delivery_task.py @@ -9,8 +9,8 @@ from core.app.app_config.entities import WorkflowUIBasedAppConfig from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity from core.app.layers.pause_state_persist_layer import WorkflowResumptionContext from core.repositories.human_input_repository import FormCreateParams, HumanInputFormRepositoryImpl -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.nodes.human_input.entities import ( +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, @@ -18,7 +18,7 @@ from core.workflow.nodes.human_input.entities import ( HumanInputNodeData, MemberRecipient, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool +from dify_graph.runtime import GraphRuntimeState, VariablePool from extensions.ext_storage import storage from models.account import Account, AccountStatus, Tenant, TenantAccountJoin, TenantAccountRole from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom diff --git a/api/tests/test_containers_integration_tests/tasks/test_remove_app_and_related_data_task.py b/api/tests/test_containers_integration_tests/tasks/test_remove_app_and_related_data_task.py index 8501a8e39b..182c9ef882 100644 --- a/api/tests/test_containers_integration_tests/tasks/test_remove_app_and_related_data_task.py +++ b/api/tests/test_containers_integration_tests/tasks/test_remove_app_and_related_data_task.py @@ -4,8 +4,8 @@ from unittest.mock import ANY, call, patch import pytest from core.db.session_factory import session_factory -from core.workflow.variables.segments import StringSegment -from core.workflow.variables.types import SegmentType +from dify_graph.variables.segments import StringSegment +from dify_graph.variables.types import SegmentType from libs.datetime_utils import naive_utc_now from models import Tenant from models.enums import CreatorUserRole diff --git a/api/tests/test_containers_integration_tests/test_workflow_pause_integration.py b/api/tests/test_containers_integration_tests/test_workflow_pause_integration.py index 5f4f28cf4f..ca76fa0a4b 100644 --- a/api/tests/test_containers_integration_tests/test_workflow_pause_integration.py +++ b/api/tests/test_containers_integration_tests/test_workflow_pause_integration.py @@ -27,8 +27,8 @@ import pytest from sqlalchemy import delete, select from sqlalchemy.orm import Session, selectinload, sessionmaker -from core.workflow.entities import WorkflowExecution -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.entities import WorkflowExecution +from dify_graph.enums import WorkflowExecutionStatus from extensions.ext_storage import storage from libs.datetime_utils import naive_utc_now from models import Account diff --git a/api/tests/test_containers_integration_tests/trigger/test_trigger_e2e.py b/api/tests/test_containers_integration_tests/trigger/test_trigger_e2e.py index 604d68f257..7bfc6c9e13 100644 --- a/api/tests/test_containers_integration_tests/trigger/test_trigger_e2e.py +++ b/api/tests/test_containers_integration_tests/trigger/test_trigger_e2e.py @@ -18,7 +18,7 @@ from core.trigger.debug import event_selectors from core.trigger.debug.event_bus import TriggerDebugEventBus from core.trigger.debug.event_selectors import PluginTriggerDebugEventPoller, WebhookTriggerDebugEventPoller from core.trigger.debug.events import PluginTriggerDebugEvent, build_plugin_pool_key -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from libs.datetime_utils import naive_utc_now from models.account import Account, Tenant from models.enums import AppTriggerStatus, AppTriggerType, CreatorUserRole, WorkflowTriggerStatus diff --git a/api/tests/unit_tests/controllers/console/app/test_workflow_pause_details_api.py b/api/tests/unit_tests/controllers/console/app/test_workflow_pause_details_api.py index f9788e2e50..83601dc1b9 100644 --- a/api/tests/unit_tests/controllers/console/app/test_workflow_pause_details_api.py +++ b/api/tests/unit_tests/controllers/console/app/test_workflow_pause_details_api.py @@ -10,10 +10,10 @@ from flask import Flask from controllers.console import wraps as console_wraps from controllers.console.app import workflow_run as workflow_run_module from controllers.web.error import NotFoundError -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import WorkflowExecutionStatus -from core.workflow.nodes.human_input.entities import FormInput, UserAction -from core.workflow.nodes.human_input.enums import FormInputType +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.nodes.human_input.entities import FormInput, UserAction +from dify_graph.nodes.human_input.enums import FormInputType from libs import login as login_lib from models.account import Account, AccountStatus, TenantAccountRole from models.workflow import WorkflowRun diff --git a/api/tests/unit_tests/controllers/console/app/workflow_draft_variables_test.py b/api/tests/unit_tests/controllers/console/app/workflow_draft_variables_test.py index cf10182ad3..f34702a257 100644 --- a/api/tests/unit_tests/controllers/console/app/workflow_draft_variables_test.py +++ b/api/tests/unit_tests/controllers/console/app/workflow_draft_variables_test.py @@ -13,8 +13,8 @@ from controllers.console.app.workflow_draft_variable import ( _WORKFLOW_DRAFT_VARIABLE_WITHOUT_VALUE_FIELDS, _serialize_full_content, ) -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.variables.types import SegmentType +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.variables.types import SegmentType from factories.variable_factory import build_segment from libs.datetime_utils import naive_utc_now from libs.uuid_utils import uuidv7 @@ -310,8 +310,8 @@ def test_workflow_node_variables_fields(): def test_workflow_file_variable_with_signed_url(): """Test that File type variables include signed URLs in API responses.""" - from core.workflow.file.enums import FileTransferMethod, FileType - from core.workflow.file.models import File + from dify_graph.file.enums import FileTransferMethod, FileType + from dify_graph.file.models import File # Create a File object with LOCAL_FILE transfer method (which generates signed URLs) test_file = File( @@ -368,8 +368,8 @@ def test_workflow_file_variable_with_signed_url(): def test_workflow_file_variable_remote_url(): """Test that File type variables with REMOTE_URL transfer method return the remote URL.""" - from core.workflow.file.enums import FileTransferMethod, FileType - from core.workflow.file.models import File + from dify_graph.file.enums import FileTransferMethod, FileType + from dify_graph.file.models import File # Create a File object with REMOTE_URL transfer method test_file = File( diff --git a/api/tests/unit_tests/controllers/service_api/app/test_workflow.py b/api/tests/unit_tests/controllers/service_api/app/test_workflow.py index 0eb3854c84..4eada73b82 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_workflow.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_workflow.py @@ -35,7 +35,7 @@ from controllers.service_api.app.workflow import ( WorkflowTaskStopApi, ) from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from models.model import App, AppMode from services.app_generate_service import AppGenerateService from services.errors.app import IsDraftWorkflowError, WorkflowNotFoundError @@ -315,7 +315,7 @@ class TestWorkflowStopMechanism: def test_graph_engine_manager_has_send_stop_command(self): """Test GraphEngineManager has send_stop_command method.""" - from core.workflow.graph_engine.manager import GraphEngineManager + from dify_graph.graph_engine.manager import GraphEngineManager assert hasattr(GraphEngineManager, "send_stop_command") diff --git a/api/tests/unit_tests/controllers/service_api/app/test_workflow_fields.py b/api/tests/unit_tests/controllers/service_api/app/test_workflow_fields.py index fcaa61a871..9e95f45a0a 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_workflow_fields.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_workflow_fields.py @@ -1,7 +1,7 @@ from types import SimpleNamespace from controllers.service_api.app.workflow import WorkflowRunOutputsField, WorkflowRunStatusField -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus def test_workflow_run_status_field_with_enum() -> None: diff --git a/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py b/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py index 9dddb18595..a20725c5b0 100644 --- a/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py +++ b/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py @@ -1,6 +1,6 @@ from core.app.app_config.features.file_upload.manager import FileUploadConfigManager from core.model_runtime.entities.message_entities import ImagePromptMessageContent -from core.workflow.file.models import FileTransferMethod, FileUploadConfig, ImageConfig +from dify_graph.file.models import FileTransferMethod, FileUploadConfig, ImageConfig def test_convert_with_vision(): diff --git a/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py index 0ca54a2f4a..12ab587564 100644 --- a/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py +++ b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py @@ -7,7 +7,7 @@ from sqlalchemy.orm import Session from core.app.apps.advanced_chat.app_runner import AdvancedChatAppRunner from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, InvokeFrom -from core.workflow.variables import SegmentType +from dify_graph.variables import SegmentType from factories import variable_factory from models import ConversationVariable, Workflow diff --git a/api/tests/unit_tests/core/app/apps/advanced_chat/test_generate_task_pipeline_extra_contents.py b/api/tests/unit_tests/core/app/apps/advanced_chat/test_generate_task_pipeline_extra_contents.py index a94b5445f7..be773557f6 100644 --- a/api/tests/unit_tests/core/app/apps/advanced_chat/test_generate_task_pipeline_extra_contents.py +++ b/api/tests/unit_tests/core/app/apps/advanced_chat/test_generate_task_pipeline_extra_contents.py @@ -10,7 +10,7 @@ import pytest from core.app.apps.advanced_chat import generate_task_pipeline as pipeline_module from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueTextChunkEvent, QueueWorkflowPausedEvent -from core.workflow.entities.pause_reason import HumanInputRequired +from dify_graph.entities.pause_reason import HumanInputRequired from models.enums import MessageStatus from models.execution_extra_content import HumanInputContent from models.model import EndUser diff --git a/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py b/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py index 1931e230b2..e85e6e98d9 100644 --- a/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py +++ b/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py @@ -10,7 +10,7 @@ from core.app.apps.base_app_runner import AppRunner from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueMessageFileEvent from core.model_runtime.entities.message_entities import ImagePromptMessageContent -from core.workflow.file.enums import FileTransferMethod, FileType +from dify_graph.file.enums import FileTransferMethod, FileType from models.enums import CreatorUserRole diff --git a/api/tests/unit_tests/core/app/apps/common/test_graph_runtime_state_support.py b/api/tests/unit_tests/core/app/apps/common/test_graph_runtime_state_support.py index cd5ea8986a..b0789bbc1e 100644 --- a/api/tests/unit_tests/core/app/apps/common/test_graph_runtime_state_support.py +++ b/api/tests/unit_tests/core/app/apps/common/test_graph_runtime_state_support.py @@ -3,9 +3,9 @@ from types import SimpleNamespace import pytest from core.app.apps.common.graph_runtime_state_support import GraphRuntimeStateSupport -from core.workflow.runtime import GraphRuntimeState -from core.workflow.runtime.variable_pool import VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState +from dify_graph.runtime.variable_pool import VariablePool +from dify_graph.system_variable import SystemVariable def _make_state(workflow_run_id: str | None) -> GraphRuntimeState: diff --git a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter.py b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter.py index 5508a117c1..72430a3347 100644 --- a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter.py +++ b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter.py @@ -1,8 +1,8 @@ from collections.abc import Mapping, Sequence from core.app.apps.common.workflow_response_converter import WorkflowResponseConverter -from core.workflow.file import FILE_MODEL_IDENTITY, File, FileTransferMethod, FileType -from core.workflow.variables.segments import ArrayFileSegment, FileSegment +from dify_graph.file import FILE_MODEL_IDENTITY, File, FileTransferMethod, FileType +from dify_graph.variables.segments import ArrayFileSegment, FileSegment class TestWorkflowResponseConverterFetchFilesFromVariableValue: diff --git a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_human_input.py b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_human_input.py index 1c36b4d12b..4ed7d73cd0 100644 --- a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_human_input.py +++ b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_human_input.py @@ -4,9 +4,9 @@ from types import SimpleNamespace from core.app.apps.common.workflow_response_converter import WorkflowResponseConverter from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueHumanInputFormFilledEvent, QueueHumanInputFormTimeoutEvent -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable def _build_converter(): diff --git a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_resumption.py b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_resumption.py index 0a9794e41c..5879e8fb9b 100644 --- a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_resumption.py +++ b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_resumption.py @@ -2,9 +2,9 @@ from types import SimpleNamespace from core.app.apps.common.workflow_response_converter import WorkflowResponseConverter from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable def _build_converter() -> WorkflowResponseConverter: diff --git a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_truncation.py b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_truncation.py index d25bff92dc..69d476bd13 100644 --- a/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_truncation.py +++ b/api/tests/unit_tests/core/app/apps/common/test_workflow_response_converter_truncation.py @@ -23,9 +23,9 @@ from core.app.entities.queue_entities import ( QueueNodeStartedEvent, QueueNodeSucceededEvent, ) -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import NodeType -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import NodeType +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from models import Account from models.model import AppMode diff --git a/api/tests/unit_tests/core/app/apps/test_base_app_generator.py b/api/tests/unit_tests/core/app/apps/test_base_app_generator.py index 04c8696525..43a97ae098 100644 --- a/api/tests/unit_tests/core/app/apps/test_base_app_generator.py +++ b/api/tests/unit_tests/core/app/apps/test_base_app_generator.py @@ -1,7 +1,7 @@ import pytest from core.app.apps.base_app_generator import BaseAppGenerator -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType def test_validate_inputs_with_zero(): diff --git a/api/tests/unit_tests/core/app/apps/test_pause_resume.py b/api/tests/unit_tests/core/app/apps/test_pause_resume.py index 97c993928e..dd722c52b2 100644 --- a/api/tests/unit_tests/core/app/apps/test_pause_resume.py +++ b/api/tests/unit_tests/core/app/apps/test_pause_resume.py @@ -8,32 +8,32 @@ API_DIR = str(Path(__file__).resolve().parents[5]) if API_DIR not in sys.path: sys.path.insert(0, API_DIR) -import core.workflow.nodes.human_input.entities # noqa: F401 +import dify_graph.nodes.human_input.entities # noqa: F401 from core.app.apps.advanced_chat import app_generator as adv_app_gen_module from core.app.apps.workflow import app_generator as wf_app_gen_module from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.graph_engine import GraphEngine -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_events import ( +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.graph_engine import GraphEngine +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunPausedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import NodeRunResult, PauseRequestedEvent -from core.workflow.nodes.base.entities import BaseNodeData, OutputVariableEntity, RetryConfig -from core.workflow.nodes.base.node import Node -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.node_events import NodeRunResult, PauseRequestedEvent +from dify_graph.nodes.base.entities import BaseNodeData, OutputVariableEntity, RetryConfig +from dify_graph.nodes.base.node import Node +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable if "core.ops.ops_trace_manager" not in sys.modules: ops_stub = ModuleType("core.ops.ops_trace_manager") diff --git a/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py b/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py index f4efb240c0..1388279221 100644 --- a/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py +++ b/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_notifications.py @@ -4,8 +4,8 @@ import pytest from core.app.apps.workflow_app_runner import WorkflowBasedAppRunner from core.app.entities.queue_entities import QueueWorkflowPausedEvent -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.graph_events.graph import GraphRunPausedEvent +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.graph_events.graph import GraphRunPausedEvent class _DummyQueueManager: diff --git a/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_single_node.py b/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_single_node.py index f5903d28bd..2e0715e974 100644 --- a/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_single_node.py +++ b/api/tests/unit_tests/core/app/apps/test_workflow_app_runner_single_node.py @@ -8,8 +8,8 @@ import pytest from core.app.apps.base_app_queue_manager import AppQueueManager from core.app.apps.workflow.app_runner import WorkflowAppRunner from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.workflow import Workflow diff --git a/api/tests/unit_tests/core/app/apps/test_workflow_pause_events.py b/api/tests/unit_tests/core/app/apps/test_workflow_pause_events.py index c30b925d88..65c6bd6654 100644 --- a/api/tests/unit_tests/core/app/apps/test_workflow_pause_events.py +++ b/api/tests/unit_tests/core/app/apps/test_workflow_pause_events.py @@ -10,12 +10,12 @@ from core.app.apps.workflow.app_runner import WorkflowAppRunner from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueWorkflowPausedEvent from core.app.entities.task_entities import HumanInputRequiredResponse, WorkflowPauseStreamResponse -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph_events.graph import GraphRunPausedEvent -from core.workflow.nodes.human_input.entities import FormInput, UserAction -from core.workflow.nodes.human_input.enums import FormInputType -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph_events.graph import GraphRunPausedEvent +from dify_graph.nodes.human_input.entities import FormInput, UserAction +from dify_graph.nodes.human_input.enums import FormInputType +from dify_graph.system_variable import SystemVariable from models.account import Account diff --git a/api/tests/unit_tests/core/app/apps/workflow/test_generate_task_pipeline.py b/api/tests/unit_tests/core/app/apps/workflow/test_generate_task_pipeline.py index 32cb1ed47c..5b23e71035 100644 --- a/api/tests/unit_tests/core/app/apps/workflow/test_generate_task_pipeline.py +++ b/api/tests/unit_tests/core/app/apps/workflow/test_generate_task_pipeline.py @@ -7,9 +7,9 @@ from core.app.apps.base_app_queue_manager import AppQueueManager from core.app.apps.workflow.generate_task_pipeline import WorkflowAppGenerateTaskPipeline from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity from core.app.entities.queue_entities import QueueWorkflowStartedEvent -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.account import Account from models.model import AppMode diff --git a/api/tests/unit_tests/core/app/layers/test_conversation_variable_persist_layer.py b/api/tests/unit_tests/core/app/layers/test_conversation_variable_persist_layer.py index d3ae577d0d..7d0e1d25f6 100644 --- a/api/tests/unit_tests/core/app/layers/test_conversation_variable_persist_layer.py +++ b/api/tests/unit_tests/core/app/layers/test_conversation_variable_persist_layer.py @@ -3,16 +3,16 @@ from datetime import datetime from unittest.mock import Mock from core.app.layers.conversation_variable_persist_layer import ConversationVariablePersistenceLayer -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph_engine.protocols.command_channel import CommandChannel -from core.workflow.graph_events.node import NodeRunSucceededEvent -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.variable_assigner.common import helpers as common_helpers -from core.workflow.runtime.graph_runtime_state_protocol import ReadOnlyGraphRuntimeState -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import StringVariable -from core.workflow.variables.segments import Segment +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph_engine.protocols.command_channel import CommandChannel +from dify_graph.graph_events.node import NodeRunSucceededEvent +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.variable_assigner.common import helpers as common_helpers +from dify_graph.runtime.graph_runtime_state_protocol import ReadOnlyGraphRuntimeState +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import StringVariable +from dify_graph.variables.segments import Segment class MockReadOnlyVariablePool: diff --git a/api/tests/unit_tests/core/app/layers/test_pause_state_persist_layer.py b/api/tests/unit_tests/core/app/layers/test_pause_state_persist_layer.py index 539f0cb581..035f0ee05c 100644 --- a/api/tests/unit_tests/core/app/layers/test_pause_state_persist_layer.py +++ b/api/tests/unit_tests/core/app/layers/test_pause_state_persist_layer.py @@ -13,17 +13,17 @@ from core.app.layers.pause_state_persist_layer import ( _AdvancedChatAppGenerateEntityWrapper, _WorkflowGenerateEntityWrapper, ) -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.graph_engine.entities.commands import GraphEngineCommand -from core.workflow.graph_engine.layers.base import GraphEngineLayerNotInitializedError -from core.workflow.graph_events.graph import ( +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.graph_engine.entities.commands import GraphEngineCommand +from dify_graph.graph_engine.layers.base import GraphEngineLayerNotInitializedError +from dify_graph.graph_events.graph import ( GraphRunFailedEvent, GraphRunPausedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, ) -from core.workflow.runtime.graph_runtime_state_protocol import ReadOnlyVariablePool -from core.workflow.variables.segments import Segment +from dify_graph.runtime.graph_runtime_state_protocol import ReadOnlyVariablePool +from dify_graph.variables.segments import Segment from models.model import AppMode from repositories.factory import DifyAPIRepositoryFactory diff --git a/api/tests/unit_tests/core/datasource/test_datasource_manager.py b/api/tests/unit_tests/core/datasource/test_datasource_manager.py index 9ee1df8bdc..52c91fb8c9 100644 --- a/api/tests/unit_tests/core/datasource/test_datasource_manager.py +++ b/api/tests/unit_tests/core/datasource/test_datasource_manager.py @@ -3,8 +3,8 @@ from collections.abc import Generator from core.datasource.datasource_manager import DatasourceManager from core.datasource.entities.datasource_entities import DatasourceMessage -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.node_events import StreamChunkEvent, StreamCompletedEvent +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.node_events import StreamChunkEvent, StreamCompletedEvent def _gen_messages_text_only(text: str) -> Generator[DatasourceMessage, None, None]: diff --git a/api/tests/unit_tests/core/file/test_models.py b/api/tests/unit_tests/core/file/test_models.py index 4d4ccc2672..deebf41320 100644 --- a/api/tests/unit_tests/core/file/test_models.py +++ b/api/tests/unit_tests/core/file/test_models.py @@ -1,4 +1,4 @@ -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType def test_file(): diff --git a/api/tests/unit_tests/core/mcp/server/test_streamable_http.py b/api/tests/unit_tests/core/mcp/server/test_streamable_http.py index 40a7700394..f982765b1a 100644 --- a/api/tests/unit_tests/core/mcp/server/test_streamable_http.py +++ b/api/tests/unit_tests/core/mcp/server/test_streamable_http.py @@ -18,7 +18,7 @@ from core.mcp.server.streamable_http import ( prepare_tool_arguments, process_mapping_response, ) -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models.model import App, AppMCPServer, AppMode, EndUser diff --git a/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py b/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py index 4f398ce66e..32389b4d64 100644 --- a/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py +++ b/api/tests/unit_tests/core/ops/test_arize_phoenix_trace.py @@ -1,7 +1,7 @@ from openinference.semconv.trace import OpenInferenceSpanKindValues from core.ops.arize_phoenix_trace.arize_phoenix_trace import _NODE_TYPE_TO_SPAN_KIND, _get_node_span_kind -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType class TestGetNodeSpanKind: diff --git a/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py b/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py index 1d25639343..786264513c 100644 --- a/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py +++ b/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py @@ -14,7 +14,7 @@ from core.model_runtime.entities.message_entities import ( from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from core.workflow.file import File, FileTransferMethod, FileType +from dify_graph.file import File, FileTransferMethod, FileType from models.model import Conversation @@ -142,7 +142,7 @@ def test__get_chat_model_prompt_messages_with_files_no_memory(get_chat_model_arg prompt_transform = AdvancedPromptTransform() prompt_transform._calculate_rest_token = MagicMock(return_value=2000) - with patch("core.workflow.file.file_manager.to_prompt_message_content", autospec=True) as mock_get_encoded_string: + with patch("dify_graph.file.file_manager.to_prompt_message_content", autospec=True) as mock_get_encoded_string: mock_get_encoded_string.return_value = ImagePromptMessageContent( url=str(files[0].remote_url), format="jpg", mime_type="image/jpg" ) diff --git a/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval_methods.py b/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval_methods.py index 4bc802dc23..682a451117 100644 --- a/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval_methods.py +++ b/api/tests/unit_tests/core/rag/retrieval/test_dataset_retrieval_methods.py @@ -5,8 +5,8 @@ import pytest from core.rag.models.document import Document from core.rag.retrieval.dataset_retrieval import DatasetRetrieval -from core.workflow.nodes.knowledge_retrieval import exc -from core.workflow.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest +from dify_graph.nodes.knowledge_retrieval import exc +from dify_graph.repositories.rag_retrieval_protocol import KnowledgeRetrievalRequest from models.dataset import Dataset # ==================== Helper Functions ==================== diff --git a/api/tests/unit_tests/core/repositories/test_celery_workflow_execution_repository.py b/api/tests/unit_tests/core/repositories/test_celery_workflow_execution_repository.py index e6d0371cd5..e7eecfa297 100644 --- a/api/tests/unit_tests/core/repositories/test_celery_workflow_execution_repository.py +++ b/api/tests/unit_tests/core/repositories/test_celery_workflow_execution_repository.py @@ -11,7 +11,7 @@ from uuid import uuid4 import pytest from core.repositories.celery_workflow_execution_repository import CeleryWorkflowExecutionRepository -from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowType +from dify_graph.entities.workflow_execution import WorkflowExecution, WorkflowType from libs.datetime_utils import naive_utc_now from models import Account, EndUser from models.enums import WorkflowRunTriggeredFrom diff --git a/api/tests/unit_tests/core/repositories/test_celery_workflow_node_execution_repository.py b/api/tests/unit_tests/core/repositories/test_celery_workflow_node_execution_repository.py index f6211f4cca..b613573927 100644 --- a/api/tests/unit_tests/core/repositories/test_celery_workflow_node_execution_repository.py +++ b/api/tests/unit_tests/core/repositories/test_celery_workflow_node_execution_repository.py @@ -11,12 +11,12 @@ from uuid import uuid4 import pytest from core.repositories.celery_workflow_node_execution_repository import CeleryWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, WorkflowNodeExecutionStatus, ) -from core.workflow.enums import NodeType -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig +from dify_graph.enums import NodeType +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig from libs.datetime_utils import naive_utc_now from models import Account, EndUser from models.workflow import WorkflowNodeExecutionTriggeredFrom diff --git a/api/tests/unit_tests/core/repositories/test_factory.py b/api/tests/unit_tests/core/repositories/test_factory.py index 7f1e2c5e5b..fe9eed0307 100644 --- a/api/tests/unit_tests/core/repositories/test_factory.py +++ b/api/tests/unit_tests/core/repositories/test_factory.py @@ -12,8 +12,8 @@ from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker from core.repositories.factory import DifyCoreRepositoryFactory, RepositoryImportError -from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository +from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from libs.module_loading import import_string from models import Account, EndUser from models.enums import WorkflowRunTriggeredFrom diff --git a/api/tests/unit_tests/core/repositories/test_human_input_form_repository_impl.py b/api/tests/unit_tests/core/repositories/test_human_input_form_repository_impl.py index 811ed2143b..7bf7c2e5f6 100644 --- a/api/tests/unit_tests/core/repositories/test_human_input_form_repository_impl.py +++ b/api/tests/unit_tests/core/repositories/test_human_input_form_repository_impl.py @@ -15,7 +15,7 @@ from core.repositories.human_input_repository import ( HumanInputFormSubmissionRepository, _WorkspaceMemberInfo, ) -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, @@ -24,7 +24,7 @@ from core.workflow.nodes.human_input.entities import ( MemberRecipient, UserAction, ) -from core.workflow.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus +from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus from libs.datetime_utils import naive_utc_now from models.human_input import ( EmailExternalRecipientPayload, diff --git a/api/tests/unit_tests/core/repositories/test_workflow_node_execution_conflict_handling.py b/api/tests/unit_tests/core/repositories/test_workflow_node_execution_conflict_handling.py index 07f28f162a..bae5bae06d 100644 --- a/api/tests/unit_tests/core/repositories/test_workflow_node_execution_conflict_handling.py +++ b/api/tests/unit_tests/core/repositories/test_workflow_node_execution_conflict_handling.py @@ -10,11 +10,11 @@ from sqlalchemy.orm import sessionmaker from core.repositories.sqlalchemy_workflow_node_execution_repository import ( SQLAlchemyWorkflowNodeExecutionRepository, ) -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, WorkflowNodeExecutionStatus, ) -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from libs.datetime_utils import naive_utc_now from models import Account, WorkflowNodeExecutionTriggeredFrom diff --git a/api/tests/unit_tests/core/repositories/test_workflow_node_execution_truncation.py b/api/tests/unit_tests/core/repositories/test_workflow_node_execution_truncation.py index 485be90eae..c880b8d41b 100644 --- a/api/tests/unit_tests/core/repositories/test_workflow_node_execution_truncation.py +++ b/api/tests/unit_tests/core/repositories/test_workflow_node_execution_truncation.py @@ -16,11 +16,11 @@ from sqlalchemy import Engine from core.repositories.sqlalchemy_workflow_node_execution_repository import ( SQLAlchemyWorkflowNodeExecutionRepository, ) -from core.workflow.entities.workflow_node_execution import ( +from dify_graph.entities.workflow_node_execution import ( WorkflowNodeExecution, WorkflowNodeExecutionStatus, ) -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from models import Account, WorkflowNodeExecutionTriggeredFrom from models.enums import ExecutionOffLoadType from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionOffload diff --git a/api/tests/unit_tests/core/test_file.py b/api/tests/unit_tests/core/test_file.py index b9c5fbd7d8..251d6fd25e 100644 --- a/api/tests/unit_tests/core/test_file.py +++ b/api/tests/unit_tests/core/test_file.py @@ -1,6 +1,6 @@ import json -from core.workflow.file import File, FileTransferMethod, FileType, FileUploadConfig +from dify_graph.file import File, FileTransferMethod, FileType, FileUploadConfig from models.workflow import Workflow diff --git a/api/tests/unit_tests/core/test_trigger_debug_event_selectors.py b/api/tests/unit_tests/core/test_trigger_debug_event_selectors.py index 2b508ca654..14b42adbbe 100644 --- a/api/tests/unit_tests/core/test_trigger_debug_event_selectors.py +++ b/api/tests/unit_tests/core/test_trigger_debug_event_selectors.py @@ -6,7 +6,7 @@ import pytest import pytz from core.trigger.debug import event_selectors -from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig +from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig class _DummyRedis: diff --git a/api/tests/unit_tests/core/variables/test_segment.py b/api/tests/unit_tests/core/variables/test_segment.py index a9af8bea1d..d47d4d6130 100644 --- a/api/tests/unit_tests/core/variables/test_segment.py +++ b/api/tests/unit_tests/core/variables/test_segment.py @@ -3,10 +3,10 @@ import dataclasses from pydantic import BaseModel from core.helper import encrypter -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.runtime import VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.segments import ( +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.runtime import VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.segments import ( ArrayAnySegment, ArrayFileSegment, ArrayNumberSegment, @@ -22,8 +22,8 @@ from core.workflow.variables.segments import ( StringSegment, get_segment_discriminator, ) -from core.workflow.variables.types import SegmentType -from core.workflow.variables.variables import ( +from dify_graph.variables.types import SegmentType +from dify_graph.variables.variables import ( ArrayAnyVariable, ArrayFileVariable, ArrayNumberVariable, diff --git a/api/tests/unit_tests/core/variables/test_segment_type.py b/api/tests/unit_tests/core/variables/test_segment_type.py index e28fed187b..c3371d92e3 100644 --- a/api/tests/unit_tests/core/variables/test_segment_type.py +++ b/api/tests/unit_tests/core/variables/test_segment_type.py @@ -1,6 +1,6 @@ import pytest -from core.workflow.variables.types import ArrayValidation, SegmentType +from dify_graph.variables.types import ArrayValidation, SegmentType class TestSegmentTypeIsArrayType: diff --git a/api/tests/unit_tests/core/variables/test_segment_type_validation.py b/api/tests/unit_tests/core/variables/test_segment_type_validation.py index 52e5dd180c..41ce483447 100644 --- a/api/tests/unit_tests/core/variables/test_segment_type_validation.py +++ b/api/tests/unit_tests/core/variables/test_segment_type_validation.py @@ -10,10 +10,10 @@ from typing import Any import pytest -from core.workflow.file.enums import FileTransferMethod, FileType -from core.workflow.file.models import File -from core.workflow.variables.segment_group import SegmentGroup -from core.workflow.variables.segments import ( +from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.file.models import File +from dify_graph.variables.segment_group import SegmentGroup +from dify_graph.variables.segments import ( ArrayFileSegment, BooleanSegment, FileSegment, @@ -22,7 +22,7 @@ from core.workflow.variables.segments import ( ObjectSegment, StringSegment, ) -from core.workflow.variables.types import ArrayValidation, SegmentType +from dify_graph.variables.types import ArrayValidation, SegmentType def create_test_file( diff --git a/api/tests/unit_tests/core/variables/test_variables.py b/api/tests/unit_tests/core/variables/test_variables.py index 6fc162e533..dd0fe2e65a 100644 --- a/api/tests/unit_tests/core/variables/test_variables.py +++ b/api/tests/unit_tests/core/variables/test_variables.py @@ -1,7 +1,7 @@ import pytest from pydantic import ValidationError -from core.workflow.variables import ( +from dify_graph.variables import ( ArrayFileVariable, ArrayVariable, FloatVariable, @@ -11,7 +11,7 @@ from core.workflow.variables import ( SegmentType, StringVariable, ) -from core.workflow.variables.variables import VariableBase +from dify_graph.variables.variables import VariableBase def test_frozen_variables(): diff --git a/api/tests/unit_tests/core/workflow/context/test_execution_context.py b/api/tests/unit_tests/core/workflow/context/test_execution_context.py index 8dd669e17f..d09b8397c3 100644 --- a/api/tests/unit_tests/core/workflow/context/test_execution_context.py +++ b/api/tests/unit_tests/core/workflow/context/test_execution_context.py @@ -9,7 +9,7 @@ from unittest.mock import MagicMock import pytest from pydantic import BaseModel -from core.workflow.context.execution_context import ( +from dify_graph.context.execution_context import ( AppContext, ExecutionContext, ExecutionContextBuilder, @@ -286,7 +286,7 @@ class TestCaptureCurrentContext: def test_capture_current_context_returns_context(self): """Test that capture_current_context returns a valid context.""" - from core.workflow.context.execution_context import capture_current_context + from dify_graph.context.execution_context import capture_current_context result = capture_current_context() @@ -303,7 +303,7 @@ class TestCaptureCurrentContext: test_var = contextvars.ContextVar("capture_test_var") test_var.set("test_value_123") - from core.workflow.context.execution_context import capture_current_context + from dify_graph.context.execution_context import capture_current_context result = capture_current_context() @@ -313,12 +313,12 @@ class TestCaptureCurrentContext: class TestTenantScopedContextRegistry: def setup_method(self): - from core.workflow.context import reset_context_provider + from dify_graph.context import reset_context_provider reset_context_provider() def teardown_method(self): - from core.workflow.context import reset_context_provider + from dify_graph.context import reset_context_provider reset_context_provider() @@ -333,7 +333,7 @@ class TestTenantScopedContextRegistry: assert read_context("workflow.sandbox", tenant_id="t2").base_url == "http://t2" def test_missing_provider_raises_keyerror(self): - from core.workflow.context import ContextProviderNotFoundError + from dify_graph.context import ContextProviderNotFoundError with pytest.raises(ContextProviderNotFoundError): read_context("missing", tenant_id="unknown") diff --git a/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py b/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py index 8d49394653..b472ffdf1f 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py +++ b/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock, patch import pytest from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper, VariablePool +from dify_graph.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper, VariablePool class StubCoordinator: @@ -115,7 +115,7 @@ class TestGraphRuntimeState: queue = state.ready_queue - from core.workflow.graph_engine.ready_queue import InMemoryReadyQueue + from dify_graph.graph_engine.ready_queue import InMemoryReadyQueue assert isinstance(queue, InMemoryReadyQueue) @@ -124,7 +124,7 @@ class TestGraphRuntimeState: execution = state.graph_execution - from core.workflow.graph_engine.domain.graph_execution import GraphExecution + from dify_graph.graph_engine.domain.graph_execution import GraphExecution assert isinstance(execution, GraphExecution) assert execution.workflow_id == "" @@ -139,7 +139,7 @@ class TestGraphRuntimeState: mock_graph = MagicMock() with patch( - "core.workflow.graph_engine.response_coordinator.ResponseStreamCoordinator", autospec=True + "dify_graph.graph_engine.response_coordinator.ResponseStreamCoordinator", autospec=True ) as coordinator_cls: coordinator_instance = coordinator_cls.return_value state.configure(graph=mock_graph) diff --git a/api/tests/unit_tests/core/workflow/entities/test_pause_reason.py b/api/tests/unit_tests/core/workflow/entities/test_pause_reason.py index 6144df06e0..158f7018b5 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_pause_reason.py +++ b/api/tests/unit_tests/core/workflow/entities/test_pause_reason.py @@ -5,7 +5,7 @@ Tests for PauseReason discriminated union serialization/deserialization. import pytest from pydantic import BaseModel, ValidationError -from core.workflow.entities.pause_reason import ( +from dify_graph.entities.pause_reason import ( HumanInputRequired, PauseReason, SchedulingPause, diff --git a/api/tests/unit_tests/core/workflow/entities/test_template.py b/api/tests/unit_tests/core/workflow/entities/test_template.py index f3197ea282..2d4c7f7b77 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_template.py +++ b/api/tests/unit_tests/core/workflow/entities/test_template.py @@ -1,6 +1,6 @@ """Tests for template module.""" -from core.workflow.nodes.base.template import Template, TextSegment, VariableSegment +from dify_graph.nodes.base.template import Template, TextSegment, VariableSegment class TestTemplate: diff --git a/api/tests/unit_tests/core/workflow/entities/test_variable_pool.py b/api/tests/unit_tests/core/workflow/entities/test_variable_pool.py index d4254df319..6100ebede5 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_variable_pool.py +++ b/api/tests/unit_tests/core/workflow/entities/test_variable_pool.py @@ -1,5 +1,5 @@ -from core.workflow.runtime import VariablePool -from core.workflow.variables.segments import ( +from dify_graph.runtime import VariablePool +from dify_graph.variables.segments import ( BooleanSegment, IntegerSegment, NoneSegment, diff --git a/api/tests/unit_tests/core/workflow/entities/test_workflow_node_execution.py b/api/tests/unit_tests/core/workflow/entities/test_workflow_node_execution.py index a4b1189a1c..4035c1a871 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_workflow_node_execution.py +++ b/api/tests/unit_tests/core/workflow/entities/test_workflow_node_execution.py @@ -8,8 +8,8 @@ from typing import Any import pytest -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution -from core.workflow.enums import NodeType +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecution +from dify_graph.enums import NodeType class TestWorkflowNodeExecutionProcessDataTruncation: diff --git a/api/tests/unit_tests/core/workflow/graph/test_graph.py b/api/tests/unit_tests/core/workflow/graph/test_graph.py index 01b514ed7c..c46b9e51fd 100644 --- a/api/tests/unit_tests/core/workflow/graph/test_graph.py +++ b/api/tests/unit_tests/core/workflow/graph/test_graph.py @@ -2,10 +2,10 @@ from unittest.mock import Mock -from core.workflow.enums import NodeExecutionType, NodeState, NodeType -from core.workflow.graph.edge import Edge -from core.workflow.graph.graph import Graph -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeExecutionType, NodeState, NodeType +from dify_graph.graph.edge import Edge +from dify_graph.graph.graph import Graph +from dify_graph.nodes.base.node import Node def create_mock_node(node_id: str, execution_type: NodeExecutionType, state: NodeState = NodeState.UNKNOWN) -> Node: diff --git a/api/tests/unit_tests/core/workflow/graph/test_graph_builder.py b/api/tests/unit_tests/core/workflow/graph/test_graph_builder.py index 15d1dcb48d..bd4a0f32e2 100644 --- a/api/tests/unit_tests/core/workflow/graph/test_graph_builder.py +++ b/api/tests/unit_tests/core/workflow/graph/test_graph_builder.py @@ -2,9 +2,9 @@ from unittest.mock import MagicMock import pytest -from core.workflow.enums import NodeType -from core.workflow.graph import Graph -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.graph import Graph +from dify_graph.nodes.base.node import Node def _make_node(node_id: str, node_type: NodeType = NodeType.START) -> Node: diff --git a/api/tests/unit_tests/core/workflow/graph/test_graph_skip_validation.py b/api/tests/unit_tests/core/workflow/graph/test_graph_skip_validation.py index 6858120335..d2743cbbbe 100644 --- a/api/tests/unit_tests/core/workflow/graph/test_graph_skip_validation.py +++ b/api/tests/unit_tests/core/workflow/graph/test_graph_skip_validation.py @@ -5,13 +5,13 @@ from typing import Any import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph.validation import GraphValidationError -from core.workflow.nodes import NodeType -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph.validation import GraphValidationError +from dify_graph.nodes import NodeType +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/graph/test_graph_validation.py b/api/tests/unit_tests/core/workflow/graph/test_graph_validation.py index 5716aae4c7..c9134c4543 100644 --- a/api/tests/unit_tests/core/workflow/graph/test_graph_validation.py +++ b/api/tests/unit_tests/core/workflow/graph/test_graph_validation.py @@ -7,14 +7,14 @@ from dataclasses import dataclass import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities import GraphInitParams -from core.workflow.enums import ErrorStrategy, NodeExecutionType, NodeType -from core.workflow.graph import Graph -from core.workflow.graph.validation import GraphValidationError -from core.workflow.nodes.base.entities import BaseNodeData -from core.workflow.nodes.base.node import Node -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import ErrorStrategy, NodeExecutionType, NodeType +from dify_graph.graph import Graph +from dify_graph.graph.validation import GraphValidationError +from dify_graph.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.node import Node +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/graph_engine/README.md b/api/tests/unit_tests/core/workflow/graph_engine/README.md index 3fff4cf6a9..40ed61eb02 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/README.md +++ b/api/tests/unit_tests/core/workflow/graph_engine/README.md @@ -68,7 +68,7 @@ print(f"Success rate: {suite_result.success_rate:.1f}%") #### Event Sequence Validation ```python -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, NodeRunStartedEvent, NodeRunSucceededEvent, @@ -376,39 +376,39 @@ See `test_mock_example.py` for comprehensive examples including: ```bash # Run graph engine tests (includes property-based tests) -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/test_graph_engine.py # Run with specific test patterns -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py -k "test_echo" +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/test_graph_engine.py -k "test_echo" # Run with verbose output -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py -v +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/test_graph_engine.py -v ``` ### Mock System Tests ```bash # Run auto-mock system tests -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/test_auto_mock_system.py +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/test_auto_mock_system.py # Run examples -uv run python api/tests/unit_tests/core/workflow/graph_engine/test_mock_example.py +uv run python api/tests/unit_tests/dify_graph/graph_engine/test_mock_example.py # Run simple validation -uv run python api/tests/unit_tests/core/workflow/graph_engine/test_mock_simple.py +uv run python api/tests/unit_tests/dify_graph/graph_engine/test_mock_simple.py ``` ### All Tests ```bash # Run all graph engine tests -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/ +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/ # Run with coverage -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/ --cov=core.workflow.graph_engine +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/ --cov=dify_graph.graph_engine # Run in parallel -uv run pytest api/tests/unit_tests/core/workflow/graph_engine/ -n auto +uv run pytest api/tests/unit_tests/dify_graph/graph_engine/ -n auto ``` ## Troubleshooting diff --git a/api/tests/unit_tests/core/workflow/graph_engine/command_channels/test_redis_channel.py b/api/tests/unit_tests/core/workflow/graph_engine/command_channels/test_redis_channel.py index db9b977e4a..4dec618e49 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/command_channels/test_redis_channel.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/command_channels/test_redis_channel.py @@ -3,15 +3,15 @@ import json from unittest.mock import MagicMock -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel -from core.workflow.graph_engine.entities.commands import ( +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel +from dify_graph.graph_engine.entities.commands import ( AbortCommand, CommandType, GraphEngineCommand, UpdateVariablesCommand, VariableUpdate, ) -from core.workflow.variables import IntegerVariable, StringVariable +from dify_graph.variables import IntegerVariable, StringVariable class TestRedisChannel: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_handlers.py b/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_handlers.py index 5d17b7a243..61e0f12550 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_handlers.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_handlers.py @@ -2,18 +2,18 @@ from __future__ import annotations -from core.workflow.enums import NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.graph_engine.domain.graph_execution import GraphExecution -from core.workflow.graph_engine.event_management.event_handlers import EventHandler -from core.workflow.graph_engine.event_management.event_manager import EventManager -from core.workflow.graph_engine.graph_state_manager import GraphStateManager -from core.workflow.graph_engine.ready_queue.in_memory import InMemoryReadyQueue -from core.workflow.graph_engine.response_coordinator.coordinator import ResponseStreamCoordinator -from core.workflow.graph_events import NodeRunRetryEvent, NodeRunStartedEvent -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.base.entities import RetryConfig -from core.workflow.runtime import GraphRuntimeState, VariablePool +from dify_graph.enums import NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.graph_engine.domain.graph_execution import GraphExecution +from dify_graph.graph_engine.event_management.event_handlers import EventHandler +from dify_graph.graph_engine.event_management.event_manager import EventManager +from dify_graph.graph_engine.graph_state_manager import GraphStateManager +from dify_graph.graph_engine.ready_queue.in_memory import InMemoryReadyQueue +from dify_graph.graph_engine.response_coordinator.coordinator import ResponseStreamCoordinator +from dify_graph.graph_events import NodeRunRetryEvent, NodeRunStartedEvent +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.base.entities import RetryConfig +from dify_graph.runtime import GraphRuntimeState, VariablePool from libs.datetime_utils import naive_utc_now diff --git a/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_manager.py b/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_manager.py index 15eac6b537..25494dc647 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_manager.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/event_management/test_event_manager.py @@ -4,9 +4,9 @@ from __future__ import annotations import logging -from core.workflow.graph_engine.event_management.event_manager import EventManager -from core.workflow.graph_engine.layers.base import GraphEngineLayer -from core.workflow.graph_events import GraphEngineEvent +from dify_graph.graph_engine.event_management.event_manager import EventManager +from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.graph_events import GraphEngineEvent class _FaultyLayer(GraphEngineLayer): diff --git a/api/tests/unit_tests/core/workflow/graph_engine/graph_traversal/test_skip_propagator.py b/api/tests/unit_tests/core/workflow/graph_engine/graph_traversal/test_skip_propagator.py index 0019020ede..73d59ea4e9 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/graph_traversal/test_skip_propagator.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/graph_traversal/test_skip_propagator.py @@ -2,9 +2,9 @@ from unittest.mock import MagicMock, create_autospec -from core.workflow.graph import Edge, Graph -from core.workflow.graph_engine.graph_state_manager import GraphStateManager -from core.workflow.graph_engine.graph_traversal.skip_propagator import SkipPropagator +from dify_graph.graph import Edge, Graph +from dify_graph.graph_engine.graph_state_manager import GraphStateManager +from dify_graph.graph_engine.graph_traversal.skip_propagator import SkipPropagator class TestSkipPropagator: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/human_input_test_utils.py b/api/tests/unit_tests/core/workflow/graph_engine/human_input_test_utils.py index 2ef23c7f0f..fc8133f5e1 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/human_input_test_utils.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/human_input_test_utils.py @@ -7,8 +7,8 @@ from dataclasses import dataclass from datetime import datetime, timedelta from typing import Any -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, HumanInputFormEntity, HumanInputFormRecipientEntity, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/layers/conftest.py b/api/tests/unit_tests/core/workflow/graph_engine/layers/conftest.py index 903800ce88..3d8de0a00d 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/layers/conftest.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/layers/conftest.py @@ -10,7 +10,7 @@ from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter from opentelemetry.trace import set_tracer_provider -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType @pytest.fixture @@ -63,7 +63,7 @@ def mock_llm_node(): def mock_tool_node(): """Create a mock Tool Node with tool-specific attributes.""" from core.tools.entities.tool_entities import ToolProviderType - from core.workflow.nodes.tool.entities import ToolNodeData + from dify_graph.nodes.tool.entities import ToolNodeData node = MagicMock() node.id = "test-tool-node-id" @@ -117,8 +117,8 @@ def mock_result_event(): """Create a mock result event with NodeRunResult.""" from datetime import datetime - from core.workflow.graph_events.node import NodeRunSucceededEvent - from core.workflow.node_events.base import NodeRunResult + from dify_graph.graph_events.node import NodeRunSucceededEvent + from dify_graph.node_events.base import NodeRunResult node_run_result = NodeRunResult( inputs={"query": "test query"}, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_layer_initialization.py b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_layer_initialization.py index f1086c9936..db32527849 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_layer_initialization.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_layer_initialization.py @@ -2,13 +2,13 @@ from __future__ import annotations import pytest -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_engine.layers.base import ( +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_engine.layers.base import ( GraphEngineLayer, GraphEngineLayerNotInitializedError, ) -from core.workflow.graph_events import GraphEngineEvent +from dify_graph.graph_events import GraphEngineEvent from ..test_table_runner import WorkflowRunner diff --git a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py index 9a491d24e1..2b882512c9 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py @@ -5,10 +5,10 @@ from unittest.mock import MagicMock, patch from core.app.workflow.layers.llm_quota import LLMQuotaLayer from core.errors.error import QuotaExceededError from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph_engine.entities.commands import CommandType -from core.workflow.graph_events.node import NodeRunSucceededEvent -from core.workflow.node_events import NodeRunResult +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph_engine.entities.commands import CommandType +from dify_graph.graph_events.node import NodeRunSucceededEvent +from dify_graph.node_events import NodeRunResult def _build_succeeded_event() -> NodeRunSucceededEvent: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_observability.py b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_observability.py index ade846df28..b4a7cec494 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_observability.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_observability.py @@ -16,7 +16,7 @@ import pytest from opentelemetry.trace import StatusCode from core.app.workflow.layers.observability import ObservabilityLayer -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType class TestObservabilityLayerInitialization: @@ -144,7 +144,7 @@ class TestObservabilityLayerParserIntegration: self, tracer_provider_with_memory_exporter, memory_span_exporter, mock_llm_node, mock_result_event ): """Test that LLM parser is used for LLM nodes and extracts LLM-specific attributes.""" - from core.workflow.node_events.base import NodeRunResult + from dify_graph.node_events.base import NodeRunResult mock_result_event.node_run_result = NodeRunResult( inputs={}, @@ -182,7 +182,7 @@ class TestObservabilityLayerParserIntegration: self, tracer_provider_with_memory_exporter, memory_span_exporter, mock_retrieval_node, mock_result_event ): """Test that retrieval parser is used for retrieval nodes and extracts retrieval-specific attributes.""" - from core.workflow.node_events.base import NodeRunResult + from dify_graph.node_events.base import NodeRunResult mock_result_event.node_run_result = NodeRunResult( inputs={"query": "test query"}, @@ -210,7 +210,7 @@ class TestObservabilityLayerParserIntegration: self, tracer_provider_with_memory_exporter, memory_span_exporter, mock_start_node, mock_result_event ): """Test that result_event parameter allows parsers to extract inputs and outputs.""" - from core.workflow.node_events.base import NodeRunResult + from dify_graph.node_events.base import NodeRunResult mock_result_event.node_run_result = NodeRunResult( inputs={"input_key": "input_value"}, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/orchestration/test_dispatcher.py b/api/tests/unit_tests/core/workflow/graph_engine/orchestration/test_dispatcher.py index c1fc4acd73..50d14ff48f 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/orchestration/test_dispatcher.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/orchestration/test_dispatcher.py @@ -5,18 +5,18 @@ from __future__ import annotations import queue from unittest import mock -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph_engine.event_management.event_handlers import EventHandler -from core.workflow.graph_engine.orchestration.dispatcher import Dispatcher -from core.workflow.graph_engine.orchestration.execution_coordinator import ExecutionCoordinator -from core.workflow.graph_events import ( +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph_engine.event_management.event_handlers import EventHandler +from dify_graph.graph_engine.orchestration.dispatcher import Dispatcher +from dify_graph.graph_engine.orchestration.execution_coordinator import ExecutionCoordinator +from dify_graph.graph_events import ( GraphNodeEventBase, NodeRunPauseRequestedEvent, NodeRunStartedEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import NodeRunResult +from dify_graph.node_events import NodeRunResult from libs.datetime_utils import naive_utc_now diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_answer_end_with_text.py b/api/tests/unit_tests/core/workflow/graph_engine/test_answer_end_with_text.py index fd1e6fc6dc..7af6b26d87 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_answer_end_with_text.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_answer_end_with_text.py @@ -1,4 +1,4 @@ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_auto_mock_system.py b/api/tests/unit_tests/core/workflow/graph_engine/test_auto_mock_system.py index b291f95e0f..244bb2315d 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_auto_mock_system.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_auto_mock_system.py @@ -7,7 +7,7 @@ for workflows containing nodes that require third-party services. import pytest -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from .test_mock_config import MockConfig, MockConfigBuilder, NodeMockConfig from .test_table_runner import TableTestRunner, WorkflowTestCase @@ -200,8 +200,8 @@ def test_mock_config_builder(): def test_mock_factory_node_type_detection(): """Test that MockNodeFactory correctly identifies nodes to mock.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom from .test_mock_factory import MockNodeFactory @@ -310,9 +310,9 @@ def test_workflow_without_auto_mock(): def test_register_custom_mock_node(): """Test registering a custom mock implementation for a node type.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.nodes.template_transform import TemplateTransformNode - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.nodes.template_transform import TemplateTransformNode + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom from .test_mock_factory import MockNodeFactory diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_basic_chatflow.py b/api/tests/unit_tests/core/workflow/graph_engine/test_basic_chatflow.py index b04643b78a..30acbdaf3d 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_basic_chatflow.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_basic_chatflow.py @@ -1,4 +1,4 @@ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_command_system.py b/api/tests/unit_tests/core/workflow/graph_engine/test_command_system.py index 6c3700ea2b..02ca827d6d 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_command_system.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_command_system.py @@ -4,22 +4,22 @@ import time from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.entities.pause_reason import SchedulingPause -from core.workflow.graph import Graph -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_engine.entities.commands import ( +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.entities.pause_reason import SchedulingPause +from dify_graph.graph import Graph +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_engine.entities.commands import ( AbortCommand, CommandType, PauseCommand, UpdateVariablesCommand, VariableUpdate, ) -from core.workflow.graph_events import GraphRunAbortedEvent, GraphRunPausedEvent, GraphRunStartedEvent -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.variables import IntegerVariable, StringVariable +from dify_graph.graph_events import GraphRunAbortedEvent, GraphRunPausedEvent, GraphRunStartedEvent +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.variables import IntegerVariable, StringVariable from models.enums import UserFrom @@ -99,7 +99,7 @@ def test_redis_channel_serialization(): mock_redis.pipeline.return_value.__enter__ = MagicMock(return_value=mock_pipeline) mock_redis.pipeline.return_value.__exit__ = MagicMock(return_value=None) - from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel + from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel # Create channel with a specific key channel = RedisChannel(mock_redis, channel_key="workflow:123:commands") diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_complex_branch_workflow.py b/api/tests/unit_tests/core/workflow/graph_engine/test_complex_branch_workflow.py index 96926797ec..3a9a0b18bc 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_complex_branch_workflow.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_complex_branch_workflow.py @@ -7,7 +7,7 @@ This test suite validates the behavior of a workflow that: 3. Handles multiple answer nodes with different outputs """ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_conditional_streaming_vs_template_workflow.py b/api/tests/unit_tests/core/workflow/graph_engine/test_conditional_streaming_vs_template_workflow.py index ee944c8e3e..cde99196c8 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_conditional_streaming_vs_template_workflow.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_conditional_streaming_vs_template_workflow.py @@ -6,10 +6,10 @@ This test validates that: - When blocking != 1: NodeRunStreamChunkEvent present (direct LLM to End output) """ -from core.workflow.enums import NodeType -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_events import ( +from dify_graph.enums import NodeType +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_events import ( GraphRunSucceededEvent, NodeRunStartedEvent, NodeRunStreamChunkEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_dispatcher_pause_drain.py b/api/tests/unit_tests/core/workflow/graph_engine/test_dispatcher_pause_drain.py index bf8034487c..b88c15ea2a 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_dispatcher_pause_drain.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_dispatcher_pause_drain.py @@ -1,10 +1,10 @@ import queue from datetime import datetime -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph_engine.orchestration.dispatcher import Dispatcher -from core.workflow.graph_events import NodeRunSucceededEvent -from core.workflow.node_events import NodeRunResult +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph_engine.orchestration.dispatcher import Dispatcher +from dify_graph.graph_events import NodeRunSucceededEvent +from dify_graph.node_events import NodeRunResult class StubExecutionCoordinator: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_end_node_without_value_type.py b/api/tests/unit_tests/core/workflow/graph_engine/test_end_node_without_value_type.py index b1380cd6d2..c87dc75b95 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_end_node_without_value_type.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_end_node_without_value_type.py @@ -6,7 +6,7 @@ field is missing from the output configuration, ensuring backward compatibility with older workflow definitions. """ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_execution_coordinator.py b/api/tests/unit_tests/core/workflow/graph_engine/test_execution_coordinator.py index 53de8908a8..35406997ed 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_execution_coordinator.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_execution_coordinator.py @@ -4,11 +4,11 @@ from unittest.mock import MagicMock import pytest -from core.workflow.graph_engine.command_processing.command_processor import CommandProcessor -from core.workflow.graph_engine.domain.graph_execution import GraphExecution -from core.workflow.graph_engine.graph_state_manager import GraphStateManager -from core.workflow.graph_engine.orchestration.execution_coordinator import ExecutionCoordinator -from core.workflow.graph_engine.worker_management.worker_pool import WorkerPool +from dify_graph.graph_engine.command_processing.command_processor import CommandProcessor +from dify_graph.graph_engine.domain.graph_execution import GraphExecution +from dify_graph.graph_engine.graph_state_manager import GraphStateManager +from dify_graph.graph_engine.orchestration.execution_coordinator import ExecutionCoordinator +from dify_graph.graph_engine.worker_management.worker_pool import WorkerPool def _build_coordinator(graph_execution: GraphExecution) -> tuple[ExecutionCoordinator, MagicMock, MagicMock]: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py index 5a55d7086e..b9ae680f52 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py @@ -10,15 +10,15 @@ import time from hypothesis import HealthCheck, given, settings from hypothesis import strategies as st -from core.workflow.enums import ErrorStrategy -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_events import ( +from dify_graph.enums import ErrorStrategy +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_events import ( GraphRunPartialSucceededEvent, GraphRunStartedEvent, GraphRunSucceededEvent, ) -from core.workflow.nodes.base.entities import DefaultValue, DefaultValueType +from dify_graph.nodes.base.entities import DefaultValue, DefaultValueType # Import the test framework from the new module from .test_mock_config import MockConfigBuilder @@ -455,7 +455,7 @@ def test_if_else_workflow_property_diverse_inputs(query_input): # Tests for the Layer system def test_layer_system_basic(): """Test basic layer functionality with DebugLoggingLayer.""" - from core.workflow.graph_engine.layers import DebugLoggingLayer + from dify_graph.graph_engine.layers import DebugLoggingLayer runner = WorkflowRunner() @@ -495,7 +495,7 @@ def test_layer_system_basic(): def test_layer_chaining(): """Test chaining multiple layers.""" - from core.workflow.graph_engine.layers import DebugLoggingLayer, GraphEngineLayer + from dify_graph.graph_engine.layers import DebugLoggingLayer, GraphEngineLayer # Create a custom test layer class TestLayer(GraphEngineLayer): @@ -549,7 +549,7 @@ def test_layer_chaining(): def test_layer_error_handling(): """Test that layer errors don't crash the engine.""" - from core.workflow.graph_engine.layers import GraphEngineLayer + from dify_graph.graph_engine.layers import GraphEngineLayer # Create a layer that throws errors class FaultyLayer(GraphEngineLayer): @@ -591,7 +591,7 @@ def test_layer_error_handling(): def test_event_sequence_validation(): """Test the new event sequence validation feature.""" - from core.workflow.graph_events import NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent + from dify_graph.graph_events import NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent runner = TableTestRunner() @@ -678,7 +678,7 @@ def test_event_sequence_validation(): def test_event_sequence_validation_with_table_tests(): """Test event sequence validation with table-driven tests.""" - from core.workflow.graph_events import NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent + from dify_graph.graph_events import NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent runner = TableTestRunner() diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_execution_serialization.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_execution_serialization.py index 6385b0b91f..805e7dbbce 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_execution_serialization.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_execution_serialization.py @@ -6,13 +6,13 @@ import json from collections import deque from unittest.mock import MagicMock -from core.workflow.enums import NodeExecutionType, NodeState, NodeType -from core.workflow.graph_engine.domain import GraphExecution -from core.workflow.graph_engine.response_coordinator import ResponseStreamCoordinator -from core.workflow.graph_engine.response_coordinator.path import Path -from core.workflow.graph_engine.response_coordinator.session import ResponseSession -from core.workflow.graph_events import NodeRunStreamChunkEvent -from core.workflow.nodes.base.template import Template, TextSegment, VariableSegment +from dify_graph.enums import NodeExecutionType, NodeState, NodeType +from dify_graph.graph_engine.domain import GraphExecution +from dify_graph.graph_engine.response_coordinator import ResponseStreamCoordinator +from dify_graph.graph_engine.response_coordinator.path import Path +from dify_graph.graph_engine.response_coordinator.session import ResponseSession +from dify_graph.graph_events import NodeRunStreamChunkEvent +from dify_graph.nodes.base.template import Template, TextSegment, VariableSegment class CustomGraphExecutionError(Exception): diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py index 65d34c2009..0403e91461 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py @@ -3,24 +3,24 @@ from collections.abc import Mapping from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.enums import NodeState -from core.workflow.graph import Graph -from core.workflow.graph_engine.graph_state_manager import GraphStateManager -from core.workflow.graph_engine.ready_queue import InMemoryReadyQueue -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.llm.entities import ( +from dify_graph.entities import GraphInitParams +from dify_graph.enums import NodeState +from dify_graph.graph import Graph +from dify_graph.graph_engine.graph_state_manager import GraphStateManager +from dify_graph.graph_engine.ready_queue import InMemoryReadyQueue +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from .test_mock_config import MockConfig from .test_mock_nodes import MockLLMNode diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py index b117b26b4c..9c075c31f4 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py @@ -5,9 +5,9 @@ from unittest import mock from unittest.mock import MagicMock from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphRunPausedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, @@ -16,24 +16,24 @@ from core.workflow.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.graph_events.node import NodeRunHumanInputFormFilledEvent -from core.workflow.nodes.base.entities import OutputVariableEntity, OutputVariableType -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.llm.entities import ( +from dify_graph.graph_events.node import NodeRunHumanInputFormFilledEvent +from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from .test_mock_config import MockConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py index 45505909ea..4f458a41d9 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py @@ -4,9 +4,9 @@ from unittest import mock from unittest.mock import MagicMock from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphRunPausedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, @@ -15,24 +15,24 @@ from core.workflow.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.graph_events.node import NodeRunHumanInputFormFilledEvent -from core.workflow.nodes.base.entities import OutputVariableEntity, OutputVariableType -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.llm.entities import ( +from dify_graph.graph_events.node import NodeRunHumanInputFormFilledEvent +from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import HumanInputFormEntity, HumanInputFormRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from .test_mock_config import MockConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py b/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py index f33d37e8ff..de5d87ddad 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py @@ -3,32 +3,32 @@ from unittest import mock from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.nodes.base.entities import OutputVariableEntity, OutputVariableType -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.if_else.entities import IfElseNodeData -from core.workflow.nodes.if_else.if_else_node import IfElseNode -from core.workflow.nodes.llm.entities import ( +from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.if_else.entities import IfElseNodeData +from dify_graph.nodes.if_else.if_else_node import IfElseNode +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.utils.condition.entities import Condition +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.utils.condition.entities import Condition from .test_mock_config import MockConfig from .test_mock_nodes import MockLLMNode diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_contains_answer.py b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_contains_answer.py index 3e21a5b44d..733fd53bc8 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_contains_answer.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_contains_answer.py @@ -5,7 +5,7 @@ This test validates the behavior of a loop containing an answer node inside the loop that may produce output errors. """ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunLoopNextEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py index d88c1d9f9e..6ff2722f78 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_loop_with_tool.py @@ -1,4 +1,4 @@ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunLoopNextEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_config.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_config.py index 5ceb8dd7f7..6041c6ff30 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_config.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_config.py @@ -11,7 +11,7 @@ from collections.abc import Callable from dataclasses import dataclass, field from typing import Any -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType @dataclass diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py index b862cbe89e..9f33a81985 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_factory.py @@ -8,9 +8,9 @@ requiring external services (LLM, Agent, Tool, Knowledge Retrieval, HTTP Request from collections.abc import Mapping from typing import TYPE_CHECKING, Any -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.enums import NodeType -from core.workflow.nodes.base.node import Node +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.enums import NodeType +from dify_graph.nodes.base.node import Node from .test_mock_nodes import ( MockAgentNode, @@ -28,8 +28,8 @@ from .test_mock_nodes import ( ) if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState from .test_mock_config import MockConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_iteration_simple.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_iteration_simple.py index aae4de9a27..95bf4bff60 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_iteration_simple.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_iteration_simple.py @@ -9,7 +9,7 @@ from pathlib import Path api_dir = Path(__file__).parent.parent.parent.parent.parent.parent sys.path.insert(0, str(api_dir)) -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from tests.unit_tests.core.workflow.graph_engine.test_mock_config import MockConfigBuilder from tests.unit_tests.core.workflow.graph_engine.test_mock_factory import MockNodeFactory @@ -17,8 +17,8 @@ from tests.unit_tests.core.workflow.graph_engine.test_mock_factory import MockNo def test_mock_factory_registers_iteration_node(): """Test that MockNodeFactory has iteration node registered.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom # Create a MockNodeFactory instance @@ -66,8 +66,8 @@ def test_mock_iteration_node_preserves_config(): """Test that MockIterationNode preserves mock configuration.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom from tests.unit_tests.core.workflow.graph_engine.test_mock_nodes import MockIterationNode @@ -128,8 +128,8 @@ def test_mock_loop_node_preserves_config(): """Test that MockLoopNode preserves mock configuration.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom from tests.unit_tests.core.workflow.graph_engine.test_mock_nodes import MockLoopNode diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py index 5aed463a45..2c46cc53be 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py @@ -12,23 +12,23 @@ from unittest.mock import MagicMock from core.model_manager import ModelInstance from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent -from core.workflow.nodes.agent import AgentNode -from core.workflow.nodes.code import CodeNode -from core.workflow.nodes.document_extractor import DocumentExtractorNode -from core.workflow.nodes.http_request import HttpRequestNode -from core.workflow.nodes.knowledge_retrieval import KnowledgeRetrievalNode -from core.workflow.nodes.llm import LLMNode -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory -from core.workflow.nodes.parameter_extractor import ParameterExtractorNode -from core.workflow.nodes.question_classifier import QuestionClassifierNode -from core.workflow.nodes.template_transform import TemplateTransformNode -from core.workflow.nodes.tool import ToolNode +from dify_graph.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent +from dify_graph.nodes.agent import AgentNode +from dify_graph.nodes.code import CodeNode +from dify_graph.nodes.document_extractor import DocumentExtractorNode +from dify_graph.nodes.http_request import HttpRequestNode +from dify_graph.nodes.knowledge_retrieval import KnowledgeRetrievalNode +from dify_graph.nodes.llm import LLMNode +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.nodes.parameter_extractor import ParameterExtractorNode +from dify_graph.nodes.question_classifier import QuestionClassifierNode +from dify_graph.nodes.template_transform import TemplateTransformNode +from dify_graph.nodes.tool import ToolNode if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState from .test_mock_config import MockConfig @@ -557,8 +557,8 @@ class MockDocumentExtractorNode(MockNodeMixin, DocumentExtractorNode): ) -from core.workflow.nodes.iteration import IterationNode -from core.workflow.nodes.loop import LoopNode +from dify_graph.nodes.iteration import IterationNode +from dify_graph.nodes.loop import LoopNode class MockIterationNode(MockNodeMixin, IterationNode): @@ -572,11 +572,11 @@ class MockIterationNode(MockNodeMixin, IterationNode): def _create_graph_engine(self, index: int, item: Any): """Create a graph engine with MockNodeFactory instead of DifyNodeFactory.""" # Import dependencies - from core.workflow.entities import GraphInitParams - from core.workflow.graph import Graph - from core.workflow.graph_engine import GraphEngine, GraphEngineConfig - from core.workflow.graph_engine.command_channels import InMemoryChannel - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.graph import Graph + from dify_graph.graph_engine import GraphEngine, GraphEngineConfig + from dify_graph.graph_engine.command_channels import InMemoryChannel + from dify_graph.runtime import GraphRuntimeState # Import our MockNodeFactory instead of DifyNodeFactory from .test_mock_factory import MockNodeFactory @@ -621,7 +621,7 @@ class MockIterationNode(MockNodeMixin, IterationNode): ) if not iteration_graph: - from core.workflow.nodes.iteration.exc import IterationGraphNotFoundError + from dify_graph.nodes.iteration.exc import IterationGraphNotFoundError raise IterationGraphNotFoundError("iteration graph not found") @@ -648,11 +648,11 @@ class MockLoopNode(MockNodeMixin, LoopNode): def _create_graph_engine(self, start_at, root_node_id: str): """Create a graph engine with MockNodeFactory instead of DifyNodeFactory.""" # Import dependencies - from core.workflow.entities import GraphInitParams - from core.workflow.graph import Graph - from core.workflow.graph_engine import GraphEngine, GraphEngineConfig - from core.workflow.graph_engine.command_channels import InMemoryChannel - from core.workflow.runtime import GraphRuntimeState + from dify_graph.entities import GraphInitParams + from dify_graph.graph import Graph + from dify_graph.graph_engine import GraphEngine, GraphEngineConfig + from dify_graph.graph_engine.command_channels import InMemoryChannel + from dify_graph.runtime import GraphRuntimeState # Import our MockNodeFactory instead of DifyNodeFactory from .test_mock_factory import MockNodeFactory diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes_template_code.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes_template_code.py index 6c4178dfed..0942d15073 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes_template_code.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes_template_code.py @@ -6,8 +6,8 @@ to ensure they work correctly with the TableTestRunner. """ from configs import dify_config -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.nodes.code.limits import CodeNodeLimits +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.nodes.code.limits import CodeNodeLimits from tests.unit_tests.core.workflow.graph_engine.test_mock_config import MockConfig, MockConfigBuilder, NodeMockConfig from tests.unit_tests.core.workflow.graph_engine.test_mock_factory import MockNodeFactory from tests.unit_tests.core.workflow.graph_engine.test_mock_nodes import MockCodeNode, MockTemplateTransformNode @@ -39,8 +39,8 @@ class TestMockTemplateTransformNode: def test_mock_template_transform_node_default_output(self): """Test that MockTemplateTransformNode processes templates with Jinja2.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -98,8 +98,8 @@ class TestMockTemplateTransformNode: def test_mock_template_transform_node_custom_output(self): """Test that MockTemplateTransformNode returns custom configured output.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -158,8 +158,8 @@ class TestMockTemplateTransformNode: def test_mock_template_transform_node_error_simulation(self): """Test that MockTemplateTransformNode can simulate errors.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -215,9 +215,9 @@ class TestMockTemplateTransformNode: def test_mock_template_transform_node_with_variables(self): """Test that MockTemplateTransformNode processes templates with variables.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool - from core.workflow.variables import StringVariable + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool + from dify_graph.variables import StringVariable # Create test parameters graph_init_params = GraphInitParams( @@ -281,8 +281,8 @@ class TestMockCodeNode: def test_mock_code_node_default_output(self): """Test that MockCodeNode returns default output.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -343,8 +343,8 @@ class TestMockCodeNode: def test_mock_code_node_with_output_schema(self): """Test that MockCodeNode generates outputs based on schema.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -413,8 +413,8 @@ class TestMockCodeNode: def test_mock_code_node_custom_output(self): """Test that MockCodeNode returns custom configured output.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -485,8 +485,8 @@ class TestMockNodeFactory: def test_code_and_template_nodes_mocked_by_default(self): """Test that CODE and TEMPLATE_TRANSFORM nodes are mocked by default (they require SSRF proxy).""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -526,8 +526,8 @@ class TestMockNodeFactory: def test_factory_creates_mock_template_transform_node(self): """Test that MockNodeFactory creates MockTemplateTransformNode for template-transform type.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( @@ -577,8 +577,8 @@ class TestMockNodeFactory: def test_factory_creates_mock_code_node(self): """Test that MockNodeFactory creates MockCodeNode for code type.""" - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool # Create test parameters graph_init_params = GraphInitParams( diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_simple.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_simple.py index 1b781545f5..975a48705a 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_simple.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_simple.py @@ -9,7 +9,7 @@ from pathlib import Path api_dir = Path(__file__).parent.parent.parent.parent.parent.parent sys.path.insert(0, str(api_dir)) -from core.workflow.enums import NodeType +from dify_graph.enums import NodeType from tests.unit_tests.core.workflow.graph_engine.test_mock_config import MockConfig, MockConfigBuilder, NodeMockConfig from tests.unit_tests.core.workflow.graph_engine.test_mock_factory import MockNodeFactory @@ -102,8 +102,8 @@ def test_node_mock_config(): def test_mock_factory_detection(): """Test MockNodeFactory node type detection.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom print("Testing MockNodeFactory detection...") @@ -155,8 +155,8 @@ def test_mock_factory_detection(): def test_mock_factory_registration(): """Test registering and unregistering mock node types.""" from core.app.entities.app_invoke_entities import InvokeFrom - from core.workflow.entities import GraphInitParams - from core.workflow.runtime import GraphRuntimeState, VariablePool + from dify_graph.entities import GraphInitParams + from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom print("Testing MockNodeFactory registration...") diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_join_resume.py b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_join_resume.py index a6aab81f6c..e269263bde 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_join_resume.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_join_resume.py @@ -4,33 +4,33 @@ from dataclasses import dataclass from datetime import datetime, timedelta from typing import Any, Protocol -from core.workflow.entities import GraphInitParams -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph import Graph -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_engine.config import GraphEngineConfig -from core.workflow.graph_engine.graph_engine import GraphEngine -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph import Graph +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_engine.config import GraphEngineConfig +from dify_graph.graph_engine.graph_engine import GraphEngine +from dify_graph.graph_events import ( GraphRunPausedEvent, GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunSucceededEvent, ) -from core.workflow.nodes.base.entities import OutputVariableEntity -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.nodes.base.entities import OutputVariableEntity +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, HumanInputFormEntity, HumanInputFormRepository, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py index 62aa56fc57..9d05dc5bd0 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py @@ -6,38 +6,38 @@ from typing import Any from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph import Graph -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_engine.config import GraphEngineConfig -from core.workflow.graph_engine.graph_engine import GraphEngine -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph import Graph +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_engine.config import GraphEngineConfig +from dify_graph.graph_engine.graph_engine import GraphEngine +from dify_graph.graph_events import ( GraphRunPausedEvent, GraphRunStartedEvent, NodeRunPauseRequestedEvent, NodeRunStartedEvent, NodeRunSucceededEvent, ) -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.llm.entities import ( +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, HumanInputFormEntity, HumanInputFormRepository, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from .test_mock_config import MockConfig, NodeMockConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_streaming_workflow.py b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_streaming_workflow.py index a93d03c87e..1f456175e9 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_streaming_workflow.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_streaming_workflow.py @@ -13,23 +13,23 @@ from unittest.mock import MagicMock, patch from uuid import uuid4 from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory from core.model_manager import ModelInstance -from core.workflow.entities import GraphInitParams -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_events import ( +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_events import ( GraphRunSucceededEvent, NodeRunStartedEvent, NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) -from core.workflow.node_events import NodeRunResult, StreamCompletedEvent -from core.workflow.nodes.llm.node import LLMNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.node_events import NodeRunResult, StreamCompletedEvent +from dify_graph.nodes.llm.node import LLMNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom from .test_table_runner import TableTestRunner diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py index 156cfefcd6..ab212a9403 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py @@ -6,39 +6,39 @@ from typing import Any from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.entities import GraphInitParams -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph import Graph -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_engine.config import GraphEngineConfig -from core.workflow.graph_engine.graph_engine import GraphEngine -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph import Graph +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_engine.config import GraphEngineConfig +from dify_graph.graph_engine.graph_engine import GraphEngine +from dify_graph.graph_events import ( GraphRunPausedEvent, GraphRunStartedEvent, NodeRunStartedEvent, NodeRunSucceededEvent, ) -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.llm.entities import ( +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, ModelConfig, VisionConfig, ) -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import ( FormCreateParams, HumanInputFormEntity, HumanInputFormRepository, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from .test_mock_config import MockConfig, NodeMockConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_resume_state.py b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_resume_state.py index 700b3f4b8b..183d589e2b 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_resume_state.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_resume_state.py @@ -3,32 +3,32 @@ import time from typing import Any from unittest.mock import MagicMock -from core.workflow.entities import GraphInitParams -from core.workflow.entities.workflow_start_reason import WorkflowStartReason -from core.workflow.graph import Graph -from core.workflow.graph_engine.command_channels.in_memory_channel import InMemoryChannel -from core.workflow.graph_engine.graph_engine import GraphEngine -from core.workflow.graph_events import ( +from dify_graph.entities import GraphInitParams +from dify_graph.entities.workflow_start_reason import WorkflowStartReason +from dify_graph.graph import Graph +from dify_graph.graph_engine.command_channels.in_memory_channel import InMemoryChannel +from dify_graph.graph_engine.graph_engine import GraphEngine +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunPausedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, NodeRunSucceededEvent, ) -from core.workflow.graph_events.graph import GraphRunStartedEvent -from core.workflow.nodes.base.entities import OutputVariableEntity -from core.workflow.nodes.end.end_node import EndNode -from core.workflow.nodes.end.entities import EndNodeData -from core.workflow.nodes.human_input.entities import HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.repositories.human_input_form_repository import ( +from dify_graph.graph_events.graph import GraphRunStartedEvent +from dify_graph.nodes.base.entities import OutputVariableEntity +from dify_graph.nodes.end.end_node import EndNode +from dify_graph.nodes.end.entities import EndNodeData +from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.repositories.human_input_form_repository import ( HumanInputFormEntity, HumanInputFormRepository, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_redis_stop_integration.py b/api/tests/unit_tests/core/workflow/graph_engine/test_redis_stop_integration.py index 0920940e51..9c84f42db6 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_redis_stop_integration.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_redis_stop_integration.py @@ -12,9 +12,9 @@ import pytest import redis from core.app.apps.base_app_queue_manager import AppQueueManager -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel -from core.workflow.graph_engine.entities.commands import AbortCommand, CommandType, PauseCommand -from core.workflow.graph_engine.manager import GraphEngineManager +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel +from dify_graph.graph_engine.entities.commands import AbortCommand, CommandType, PauseCommand +from dify_graph.graph_engine.manager import GraphEngineManager class TestRedisStopIntegration: diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_streaming_conversation_variables.py b/api/tests/unit_tests/core/workflow/graph_engine/test_streaming_conversation_variables.py index 99157a7c3e..4f1741d4fb 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_streaming_conversation_variables.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_streaming_conversation_variables.py @@ -1,4 +1,4 @@ -from core.workflow.graph_events import ( +from dify_graph.graph_events import ( GraphRunStartedEvent, GraphRunSucceededEvent, NodeRunStartedEvent, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_table_runner.py b/api/tests/unit_tests/core/workflow/graph_engine/test_table_runner.py index 5cbb7cf36e..ee36c976f0 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_table_runner.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_table_runner.py @@ -19,20 +19,20 @@ from functools import lru_cache from pathlib import Path from typing import Any -from core.app.workflow.node_factory import DifyNodeFactory from core.tools.utils.yaml_utils import _load_yaml_file -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_events import ( +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_events import ( GraphEngineEvent, GraphRunStartedEvent, GraphRunSucceededEvent, ) -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import ( +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import ( ArrayNumberVariable, ArrayObjectVariable, ArrayStringVariable, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_tool_in_chatflow.py b/api/tests/unit_tests/core/workflow/graph_engine/test_tool_in_chatflow.py index bfcc6e1a5f..7f26bc11a7 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_tool_in_chatflow.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_tool_in_chatflow.py @@ -1,6 +1,6 @@ -from core.workflow.graph_engine import GraphEngine, GraphEngineConfig -from core.workflow.graph_engine.command_channels import InMemoryChannel -from core.workflow.graph_events import ( +from dify_graph.graph_engine import GraphEngine, GraphEngineConfig +from dify_graph.graph_engine.command_channels import InMemoryChannel +from dify_graph.graph_events import ( GraphRunSucceededEvent, NodeRunStreamChunkEvent, ) diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_variable_aggregator.py b/api/tests/unit_tests/core/workflow/graph_engine/test_variable_aggregator.py index 221e1291d1..f63e8ff4ce 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_variable_aggregator.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_variable_aggregator.py @@ -2,9 +2,9 @@ from unittest.mock import patch import pytest -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.template_transform.template_transform_node import TemplateTransformNode from .test_table_runner import TableTestRunner, WorkflowTestCase diff --git a/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py b/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py index 1e95ec1970..842b9e2178 100644 --- a/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py +++ b/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py @@ -3,13 +3,13 @@ import uuid from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.graph import Graph -from core.workflow.nodes.answer.answer_node import AnswerNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.graph import Graph +from dify_graph.nodes.answer.answer_node import AnswerNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from extensions.ext_database import db from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/nodes/base/test_base_node.py b/api/tests/unit_tests/core/workflow/nodes/base/test_base_node.py index 21a642c2f8..bf814d0c97 100644 --- a/api/tests/unit_tests/core/workflow/nodes/base/test_base_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/base/test_base_node.py @@ -1,11 +1,11 @@ import pytest -from core.workflow.enums import NodeType -from core.workflow.nodes.base.entities import BaseNodeData -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.node import Node # Ensures that all node classes are imported. -from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING +from dify_graph.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING # Ensure `NODE_TYPE_CLASSES_MAPPING` is used and not automatically removed. _ = NODE_TYPE_CLASSES_MAPPING diff --git a/api/tests/unit_tests/core/workflow/nodes/base/test_get_node_type_classes_mapping.py b/api/tests/unit_tests/core/workflow/nodes/base/test_get_node_type_classes_mapping.py index 45d222b98c..f8d799e446 100644 --- a/api/tests/unit_tests/core/workflow/nodes/base/test_get_node_type_classes_mapping.py +++ b/api/tests/unit_tests/core/workflow/nodes/base/test_get_node_type_classes_mapping.py @@ -1,15 +1,15 @@ import types from collections.abc import Mapping -from core.workflow.enums import NodeType -from core.workflow.nodes.base.entities import BaseNodeData -from core.workflow.nodes.base.node import Node +from dify_graph.enums import NodeType +from dify_graph.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.node import Node # Import concrete nodes we will assert on (numeric version path) -from core.workflow.nodes.variable_assigner.v1.node import ( +from dify_graph.nodes.variable_assigner.v1.node import ( VariableAssignerNode as VariableAssignerV1, ) -from core.workflow.nodes.variable_assigner.v2.node import ( +from dify_graph.nodes.variable_assigner.v2.node import ( VariableAssignerNode as VariableAssignerV2, ) diff --git a/api/tests/unit_tests/core/workflow/nodes/code/code_node_spec.py b/api/tests/unit_tests/core/workflow/nodes/code/code_node_spec.py index 00c8cb3779..95cb653635 100644 --- a/api/tests/unit_tests/core/workflow/nodes/code/code_node_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/code/code_node_spec.py @@ -1,13 +1,13 @@ from configs import dify_config -from core.workflow.nodes.code.code_node import CodeNode -from core.workflow.nodes.code.entities import CodeLanguage, CodeNodeData -from core.workflow.nodes.code.exc import ( +from dify_graph.nodes.code.code_node import CodeNode +from dify_graph.nodes.code.entities import CodeLanguage, CodeNodeData +from dify_graph.nodes.code.exc import ( CodeNodeError, DepthLimitError, OutputValidationError, ) -from core.workflow.nodes.code.limits import CodeNodeLimits -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.code.limits import CodeNodeLimits +from dify_graph.variables.types import SegmentType CodeNode._limits = CodeNodeLimits( max_string_length=dify_config.CODE_MAX_STRING_LENGTH, diff --git a/api/tests/unit_tests/core/workflow/nodes/code/entities_spec.py b/api/tests/unit_tests/core/workflow/nodes/code/entities_spec.py index 28d59c3568..de7ed0815e 100644 --- a/api/tests/unit_tests/core/workflow/nodes/code/entities_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/code/entities_spec.py @@ -1,8 +1,8 @@ import pytest from pydantic import ValidationError -from core.workflow.nodes.code.entities import CodeLanguage, CodeNodeData -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.code.entities import CodeLanguage, CodeNodeData +from dify_graph.variables.types import SegmentType class TestCodeNodeDataOutput: diff --git a/api/tests/unit_tests/core/workflow/nodes/datasource/test_datasource_node.py b/api/tests/unit_tests/core/workflow/nodes/datasource/test_datasource_node.py index 584ed23e91..b100c7c02c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/datasource/test_datasource_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/datasource/test_datasource_node.py @@ -1,6 +1,6 @@ -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent -from core.workflow.nodes.datasource.datasource_node import DatasourceNode +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent +from dify_graph.nodes.datasource.datasource_node import DatasourceNode class _VarSeg: diff --git a/api/tests/unit_tests/core/workflow/nodes/http_request/test_config.py b/api/tests/unit_tests/core/workflow/nodes/http_request/test_config.py index 90f4cd018b..cd822a6f89 100644 --- a/api/tests/unit_tests/core/workflow/nodes/http_request/test_config.py +++ b/api/tests/unit_tests/core/workflow/nodes/http_request/test_config.py @@ -1,4 +1,4 @@ -from core.workflow.nodes.http_request import build_http_request_config +from dify_graph.nodes.http_request import build_http_request_config def test_build_http_request_config_uses_literal_defaults(): diff --git a/api/tests/unit_tests/core/workflow/nodes/http_request/test_entities.py b/api/tests/unit_tests/core/workflow/nodes/http_request/test_entities.py index 47a5df92a4..fec6ad90eb 100644 --- a/api/tests/unit_tests/core/workflow/nodes/http_request/test_entities.py +++ b/api/tests/unit_tests/core/workflow/nodes/http_request/test_entities.py @@ -4,7 +4,7 @@ from unittest.mock import Mock, PropertyMock, patch import httpx import pytest -from core.workflow.nodes.http_request.entities import Response +from dify_graph.nodes.http_request.entities import Response @pytest.fixture @@ -104,7 +104,7 @@ def test_mimetype_based_detection(mock_response, content_type, expected_main_typ mock_response.headers = {"content-type": content_type} type(mock_response).content = PropertyMock(return_value=bytes([0x00])) # Dummy content - with patch("core.workflow.nodes.http_request.entities.mimetypes.guess_type") as mock_guess_type: + with patch("dify_graph.nodes.http_request.entities.mimetypes.guess_type") as mock_guess_type: # Mock the return value based on expected_main_type if expected_main_type: mock_guess_type.return_value = (f"{expected_main_type}/subtype", None) diff --git a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_executor.py b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_executor.py index 67da890eb2..cea7195417 100644 --- a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_executor.py +++ b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_executor.py @@ -2,19 +2,19 @@ import pytest from configs import dify_config from core.helper.ssrf_proxy import ssrf_proxy -from core.workflow.file.file_manager import file_manager -from core.workflow.nodes.http_request import ( +from dify_graph.file.file_manager import file_manager +from dify_graph.nodes.http_request import ( BodyData, HttpRequestNodeAuthorization, HttpRequestNodeBody, HttpRequestNodeConfig, HttpRequestNodeData, ) -from core.workflow.nodes.http_request.entities import HttpRequestNodeTimeout -from core.workflow.nodes.http_request.exc import AuthorizationConfigError -from core.workflow.nodes.http_request.executor import Executor -from core.workflow.runtime import VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.http_request.entities import HttpRequestNodeTimeout +from dify_graph.nodes.http_request.exc import AuthorizationConfigError +from dify_graph.nodes.http_request.executor import Executor +from dify_graph.runtime import VariablePool +from dify_graph.system_variable import SystemVariable HTTP_REQUEST_CONFIG = HttpRequestNodeConfig( max_connect_timeout=dify_config.HTTP_REQUEST_MAX_CONNECT_TIMEOUT, diff --git a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py index cad0466809..8ca973bf9b 100644 --- a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py @@ -7,13 +7,13 @@ import pytest from core.app.entities.app_invoke_entities import InvokeFrom from core.helper.ssrf_proxy import ssrf_proxy from core.tools.tool_file_manager import ToolFileManager -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.file.file_manager import file_manager -from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNode, HttpRequestNodeConfig -from core.workflow.nodes.http_request.entities import HttpRequestNodeTimeout, Response -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.file.file_manager import file_manager +from dify_graph.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNode, HttpRequestNodeConfig +from dify_graph.nodes.http_request.entities import HttpRequestNodeTimeout, Response +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom HTTP_REQUEST_CONFIG = HttpRequestNodeConfig( @@ -162,7 +162,7 @@ def test_run_passes_node_data_ssl_verify_to_executor(monkeypatch: pytest.MonkeyP ) ) - monkeypatch.setattr("core.workflow.nodes.http_request.node.Executor", FakeExecutor) + monkeypatch.setattr("dify_graph.nodes.http_request.node.Executor", FakeExecutor) result = node._run() diff --git a/api/tests/unit_tests/core/workflow/nodes/human_input/test_email_delivery_config.py b/api/tests/unit_tests/core/workflow/nodes/human_input/test_email_delivery_config.py index ca4a887d20..d4939b1071 100644 --- a/api/tests/unit_tests/core/workflow/nodes/human_input/test_email_delivery_config.py +++ b/api/tests/unit_tests/core/workflow/nodes/human_input/test_email_delivery_config.py @@ -1,5 +1,5 @@ -from core.workflow.nodes.human_input.entities import EmailDeliveryConfig, EmailRecipients -from core.workflow.runtime import VariablePool +from dify_graph.nodes.human_input.entities import EmailDeliveryConfig, EmailRecipients +from dify_graph.runtime import VariablePool def test_render_body_template_replaces_variable_values(): diff --git a/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py b/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py index bfe7b03c13..3b2a81ccef 100644 --- a/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py +++ b/api/tests/unit_tests/core/workflow/nodes/human_input/test_entities.py @@ -8,10 +8,10 @@ from unittest.mock import MagicMock import pytest from pydantic import ValidationError -from core.workflow.entities import GraphInitParams -from core.workflow.node_events import PauseRequestedEvent -from core.workflow.node_events.node import StreamCompletedEvent -from core.workflow.nodes.human_input.entities import ( +from dify_graph.entities import GraphInitParams +from dify_graph.node_events import PauseRequestedEvent +from dify_graph.node_events.node import StreamCompletedEvent +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, @@ -24,7 +24,7 @@ from core.workflow.nodes.human_input.entities import ( WebAppDeliveryMethod, _WebAppDeliveryConfig, ) -from core.workflow.nodes.human_input.enums import ( +from dify_graph.nodes.human_input.enums import ( ButtonStyle, DeliveryMethodType, EmailRecipientType, @@ -32,10 +32,10 @@ from core.workflow.nodes.human_input.enums import ( PlaceholderType, TimeoutUnit, ) -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.repositories.human_input_form_repository import HumanInputFormRepository -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.repositories.human_input_form_repository import HumanInputFormRepository +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from tests.unit_tests.core.workflow.graph_engine.human_input_test_utils import InMemoryHumanInputFormRepository diff --git a/api/tests/unit_tests/core/workflow/nodes/human_input/test_human_input_form_filled_event.py b/api/tests/unit_tests/core/workflow/nodes/human_input/test_human_input_form_filled_event.py index a19ee4dee3..1472cdec36 100644 --- a/api/tests/unit_tests/core/workflow/nodes/human_input/test_human_input_form_filled_event.py +++ b/api/tests/unit_tests/core/workflow/nodes/human_input/test_human_input_form_filled_event.py @@ -2,17 +2,17 @@ import datetime from types import SimpleNamespace from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.enums import NodeType -from core.workflow.graph_events import ( +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.enums import NodeType +from dify_graph.graph_events import ( NodeRunHumanInputFormFilledEvent, NodeRunHumanInputFormTimeoutEvent, NodeRunStartedEvent, ) -from core.workflow.nodes.human_input.enums import HumanInputFormStatus -from core.workflow.nodes.human_input.human_input_node import HumanInputNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.human_input_node import HumanInputNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable from libs.datetime_utils import naive_utc_now from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/nodes/iteration/entities_spec.py b/api/tests/unit_tests/core/workflow/nodes/iteration/entities_spec.py index d669cc7465..93c199514e 100644 --- a/api/tests/unit_tests/core/workflow/nodes/iteration/entities_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/iteration/entities_spec.py @@ -1,4 +1,4 @@ -from core.workflow.nodes.iteration.entities import ( +from dify_graph.nodes.iteration.entities import ( ErrorHandleMode, IterationNodeData, IterationStartNodeData, diff --git a/api/tests/unit_tests/core/workflow/nodes/iteration/iteration_node_spec.py b/api/tests/unit_tests/core/workflow/nodes/iteration/iteration_node_spec.py index b67e84d1d4..b95a7ad8ae 100644 --- a/api/tests/unit_tests/core/workflow/nodes/iteration/iteration_node_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/iteration/iteration_node_spec.py @@ -1,6 +1,6 @@ -from core.workflow.enums import NodeType -from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData -from core.workflow.nodes.iteration.exc import ( +from dify_graph.enums import NodeType +from dify_graph.nodes.iteration.entities import ErrorHandleMode, IterationNodeData +from dify_graph.nodes.iteration.exc import ( InvalidIteratorValueError, IterationGraphNotFoundError, IterationIndexNotFoundError, @@ -8,7 +8,7 @@ from core.workflow.nodes.iteration.exc import ( IteratorVariableNotFoundError, StartNodeIdNotFoundError, ) -from core.workflow.nodes.iteration.iteration_node import IterationNode +from dify_graph.nodes.iteration.iteration_node import IterationNode class TestIterationNodeExceptions: diff --git a/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py b/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py index 38e434d7d8..83a5db2fae 100644 --- a/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/knowledge_index/test_knowledge_index_node.py @@ -5,16 +5,16 @@ from unittest.mock import Mock import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities import GraphInitParams -from core.workflow.enums import SystemVariableKey, WorkflowNodeExecutionStatus -from core.workflow.nodes.knowledge_index.entities import KnowledgeIndexNodeData -from core.workflow.nodes.knowledge_index.exc import KnowledgeIndexNodeError -from core.workflow.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode -from core.workflow.repositories.index_processor_protocol import IndexProcessorProtocol, Preview, PreviewItem -from core.workflow.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.segments import StringSegment +from dify_graph.entities import GraphInitParams +from dify_graph.enums import SystemVariableKey, WorkflowNodeExecutionStatus +from dify_graph.nodes.knowledge_index.entities import KnowledgeIndexNodeData +from dify_graph.nodes.knowledge_index.exc import KnowledgeIndexNodeError +from dify_graph.nodes.knowledge_index.knowledge_index_node import KnowledgeIndexNode +from dify_graph.repositories.index_processor_protocol import IndexProcessorProtocol, Preview, PreviewItem +from dify_graph.repositories.summary_index_service_protocol import SummaryIndexServiceProtocol +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.segments import StringSegment from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py b/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py index a60dde199d..5dcf36ed6a 100644 --- a/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py @@ -6,20 +6,20 @@ import pytest from core.app.entities.app_invoke_entities import InvokeFrom from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.nodes.knowledge_retrieval.entities import ( +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.nodes.knowledge_retrieval.entities import ( KnowledgeRetrievalNodeData, MultipleRetrievalConfig, RerankingModelConfig, SingleRetrievalConfig, ) -from core.workflow.nodes.knowledge_retrieval.exc import RateLimitExceededError -from core.workflow.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode -from core.workflow.repositories.rag_retrieval_protocol import RAGRetrievalProtocol, Source -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import StringSegment +from dify_graph.nodes.knowledge_retrieval.exc import RateLimitExceededError +from dify_graph.nodes.knowledge_retrieval.knowledge_retrieval_node import KnowledgeRetrievalNode +from dify_graph.repositories.rag_retrieval_protocol import RAGRetrievalProtocol, Source +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import StringSegment from models.enums import UserFrom @@ -155,7 +155,7 @@ class TestKnowledgeRetrievalNode: ): """Test _run with query variable in single mode.""" # Arrange - from core.workflow.nodes.llm.entities import ModelConfig + from dify_graph.nodes.llm.entities import ModelConfig query = "What is Python?" query_selector = ["start", "query"] @@ -444,7 +444,7 @@ class TestFetchDatasetRetriever: ): """Test _fetch_dataset_retriever in single mode.""" # Arrange - from core.workflow.nodes.llm.entities import ModelConfig + from dify_graph.nodes.llm.entities import ModelConfig query = "What is Python?" variables = {"query": query} diff --git a/api/tests/unit_tests/core/workflow/nodes/list_operator/node_spec.py b/api/tests/unit_tests/core/workflow/nodes/list_operator/node_spec.py index 63a87623da..65228df517 100644 --- a/api/tests/unit_tests/core/workflow/nodes/list_operator/node_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/list_operator/node_spec.py @@ -1,13 +1,13 @@ from unittest.mock import MagicMock import pytest -from core.workflow.graph_engine.entities.graph import Graph -from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams -from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState +from dify_graph.graph_engine.entities.graph import Graph +from dify_graph.graph_engine.entities.graph_init_params import GraphInitParams +from dify_graph.graph_engine.entities.graph_runtime_state import GraphRuntimeState -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.nodes.list_operator.node import ListOperatorNode -from core.workflow.variables import ArrayNumberSegment, ArrayStringSegment +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.nodes.list_operator.node import ListOperatorNode +from dify_graph.variables import ArrayNumberSegment, ArrayStringSegment from models.workflow import WorkflowType diff --git a/api/tests/unit_tests/core/workflow/nodes/llm/test_file_saver.py b/api/tests/unit_tests/core/workflow/nodes/llm/test_file_saver.py index 0677f1bb52..a3afd1ed5c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/llm/test_file_saver.py +++ b/api/tests/unit_tests/core/workflow/nodes/llm/test_file_saver.py @@ -9,8 +9,8 @@ from sqlalchemy import Engine from core.helper import ssrf_proxy from core.tools import signature from core.tools.tool_file_manager import ToolFileManager -from core.workflow.file import FileTransferMethod, FileType, models -from core.workflow.nodes.llm.file_saver import ( +from dify_graph.file import FileTransferMethod, FileType, models +from dify_graph.nodes.llm.file_saver import ( FileSaverImpl, _extract_content_type_and_extension, _get_extension, diff --git a/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py b/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py index 94b5b72ee1..aac5c296d8 100644 --- a/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py @@ -22,10 +22,10 @@ from core.model_runtime.entities.message_entities import ( from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from core.prompt.entities.advanced_prompt_entities import MemoryConfig -from core.workflow.entities import GraphInitParams -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.nodes.llm import llm_utils -from core.workflow.nodes.llm.entities import ( +from dify_graph.entities import GraphInitParams +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.nodes.llm import llm_utils +from dify_graph.nodes.llm.entities import ( ContextConfig, LLMNodeChatModelMessage, LLMNodeData, @@ -33,12 +33,12 @@ from core.workflow.nodes.llm.entities import ( VisionConfig, VisionConfigOptions, ) -from core.workflow.nodes.llm.file_saver import LLMFileSaver -from core.workflow.nodes.llm.node import LLMNode, _handle_memory_completion_mode -from core.workflow.nodes.llm.protocols import CredentialsProvider, ModelFactory -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import ArrayAnySegment, ArrayFileSegment, NoneSegment +from dify_graph.nodes.llm.file_saver import LLMFileSaver +from dify_graph.nodes.llm.node import LLMNode, _handle_memory_completion_mode +from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import ArrayAnySegment, ArrayFileSegment, NoneSegment from models.enums import UserFrom from models.provider import ProviderType @@ -611,7 +611,7 @@ def test_handle_memory_completion_mode_uses_prompt_message_interface(): window=MemoryConfig.WindowConfig(enabled=True, size=3), ) - with mock.patch("core.workflow.nodes.llm.node._calculate_rest_token", return_value=2000) as mock_rest_token: + with mock.patch("dify_graph.nodes.llm.node._calculate_rest_token", return_value=2000) as mock_rest_token: memory_text = _handle_memory_completion_mode( memory=memory, memory_config=memory_config, diff --git a/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py b/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py index ac0c1df9c5..44dbabb116 100644 --- a/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py +++ b/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py @@ -4,8 +4,8 @@ from pydantic import BaseModel, Field from core.model_runtime.entities.message_entities import PromptMessage from core.model_runtime.entities.model_entities import ModelFeature -from core.workflow.file import File -from core.workflow.nodes.llm.entities import LLMNodeChatModelMessage +from dify_graph.file import File +from dify_graph.nodes.llm.entities import LLMNodeChatModelMessage class LLMNodeTestScenario(BaseModel): diff --git a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_entities.py b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_entities.py index 2742b7dab0..fd48edc58c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_entities.py +++ b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_entities.py @@ -1,5 +1,5 @@ -from core.workflow.nodes.parameter_extractor.entities import ParameterConfig -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.parameter_extractor.entities import ParameterConfig +from dify_graph.variables.types import SegmentType class TestParameterConfig: diff --git a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py index ae229bbe2e..110fdeedfb 100644 --- a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py @@ -8,16 +8,16 @@ from typing import Any import pytest from core.model_runtime.entities import LLMMode -from core.workflow.nodes.llm import ModelConfig, VisionConfig -from core.workflow.nodes.parameter_extractor.entities import ParameterConfig, ParameterExtractorNodeData -from core.workflow.nodes.parameter_extractor.exc import ( +from dify_graph.nodes.llm import ModelConfig, VisionConfig +from dify_graph.nodes.parameter_extractor.entities import ParameterConfig, ParameterExtractorNodeData +from dify_graph.nodes.parameter_extractor.exc import ( InvalidNumberOfParametersError, InvalidSelectValueError, InvalidValueTypeError, RequiredParameterMissingError, ) -from core.workflow.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode -from core.workflow.variables.types import SegmentType +from dify_graph.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode +from dify_graph.variables.types import SegmentType from factories.variable_factory import build_segment_with_type diff --git a/api/tests/unit_tests/core/workflow/nodes/template_transform/entities_spec.py b/api/tests/unit_tests/core/workflow/nodes/template_transform/entities_spec.py index 5eb302798f..e57ebbd83e 100644 --- a/api/tests/unit_tests/core/workflow/nodes/template_transform/entities_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/template_transform/entities_spec.py @@ -1,8 +1,8 @@ import pytest from pydantic import ValidationError -from core.workflow.enums import ErrorStrategy -from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData +from dify_graph.enums import ErrorStrategy +from dify_graph.nodes.template_transform.entities import TemplateTransformNodeData class TestTemplateTransformNodeData: diff --git a/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py b/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py index 0fb76fb7e7..7edc56c3dc 100644 --- a/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py +++ b/api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py @@ -1,13 +1,13 @@ from unittest.mock import MagicMock, patch import pytest -from core.workflow.graph_engine.entities.graph import Graph -from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams -from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState +from dify_graph.graph_engine.entities.graph import Graph +from dify_graph.graph_engine.entities.graph_init_params import GraphInitParams +from dify_graph.graph_engine.entities.graph_runtime_state import GraphRuntimeState -from core.workflow.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus -from core.workflow.nodes.template_transform.template_renderer import TemplateRenderError -from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode +from dify_graph.enums import ErrorStrategy, NodeType, WorkflowNodeExecutionStatus +from dify_graph.nodes.template_transform.template_renderer import TemplateRenderError +from dify_graph.nodes.template_transform.template_transform_node import TemplateTransformNode from models.workflow import WorkflowType @@ -128,7 +128,7 @@ class TestTemplateTransformNode: assert TemplateTransformNode.version() == "1" @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_simple_template( @@ -166,7 +166,7 @@ class TestTemplateTransformNode: assert result.inputs["age"] == 30 @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_none_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params): @@ -194,7 +194,7 @@ class TestTemplateTransformNode: assert result.inputs["value"] is None @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_code_execution_error( @@ -218,7 +218,7 @@ class TestTemplateTransformNode: assert "Template syntax error" in result.error @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_output_length_exceeds_limit( @@ -243,7 +243,7 @@ class TestTemplateTransformNode: assert "Output length exceeds" in result.error @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_complex_jinja2_template( @@ -308,7 +308,7 @@ class TestTemplateTransformNode: assert mapping["node_123.var2"] == ["sys", "input2"] @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_empty_variables(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params): @@ -336,7 +336,7 @@ class TestTemplateTransformNode: assert result.inputs == {} @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_numeric_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params): @@ -376,7 +376,7 @@ class TestTemplateTransformNode: assert result.outputs["output"] == "Total: $31.5" @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_dict_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params): @@ -408,7 +408,7 @@ class TestTemplateTransformNode: assert "john@example.com" in result.outputs["output"] @patch( - "core.workflow.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", + "dify_graph.nodes.template_transform.template_transform_node.CodeExecutorJinja2TemplateRenderer.render_template", autospec=True, ) def test_run_with_list_values(self, mock_execute, mock_graph, mock_graph_runtime_state, graph_init_params): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_base_node.py b/api/tests/unit_tests/core/workflow/nodes/test_base_node.py index 1854cca236..d5e0a3ce2e 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_base_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_base_node.py @@ -2,12 +2,12 @@ from collections.abc import Mapping import pytest -from core.workflow.entities import GraphInitParams -from core.workflow.enums import NodeType -from core.workflow.nodes.base.entities import BaseNodeData -from core.workflow.nodes.base.node import Node -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.entities import GraphInitParams +from dify_graph.enums import NodeType +from dify_graph.nodes.base.entities import BaseNodeData +from dify_graph.nodes.base.node import Node +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable class _SampleNodeData(BaseNodeData): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py index 35c59b92c4..b6169cd735 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py @@ -6,20 +6,20 @@ import pytest from docx.oxml.text.paragraph import CT_P from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities import GraphInitParams -from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod -from core.workflow.node_events import NodeRunResult -from core.workflow.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData -from core.workflow.nodes.document_extractor.node import ( +from dify_graph.entities import GraphInitParams +from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod +from dify_graph.node_events import NodeRunResult +from dify_graph.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData +from dify_graph.nodes.document_extractor.node import ( _extract_text_from_docx, _extract_text_from_excel, _extract_text_from_pdf, _extract_text_from_plain_text, ) -from core.workflow.variables import ArrayFileSegment -from core.workflow.variables.segments import ArrayStringSegment -from core.workflow.variables.variables import StringVariable +from dify_graph.variables import ArrayFileSegment +from dify_graph.variables.segments import ArrayStringSegment +from dify_graph.variables.variables import StringVariable from models.enums import UserFrom @@ -146,15 +146,15 @@ def test_run_extract_text( mock_ssrf_proxy_get.return_value.content = file_content mock_ssrf_proxy_get.return_value.raise_for_status = Mock() - monkeypatch.setattr("core.workflow.file.file_manager.download", mock_download) + monkeypatch.setattr("dify_graph.file.file_manager.download", mock_download) monkeypatch.setattr("core.helper.ssrf_proxy.get", mock_ssrf_proxy_get) if mime_type == "application/pdf": mock_pdf_extract = Mock(return_value=expected_text[0]) - monkeypatch.setattr("core.workflow.nodes.document_extractor.node._extract_text_from_pdf", mock_pdf_extract) + monkeypatch.setattr("dify_graph.nodes.document_extractor.node._extract_text_from_pdf", mock_pdf_extract) elif mime_type.startswith("application/vnd.openxmlformats"): mock_docx_extract = Mock(return_value=expected_text[0]) - monkeypatch.setattr("core.workflow.nodes.document_extractor.node._extract_text_from_docx", mock_docx_extract) + monkeypatch.setattr("dify_graph.nodes.document_extractor.node._extract_text_from_docx", mock_docx_extract) result = document_extractor_node._run() diff --git a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py index bc87a64161..c90550b460 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py @@ -5,17 +5,17 @@ from unittest.mock import MagicMock, Mock import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.graph import Graph -from core.workflow.nodes.if_else.entities import IfElseNodeData -from core.workflow.nodes.if_else.if_else_node import IfElseNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.utils.condition.entities import Condition, SubCondition, SubVariableCondition -from core.workflow.variables import ArrayFileSegment +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.graph import Graph +from dify_graph.nodes.if_else.entities import IfElseNodeData +from dify_graph.nodes.if_else.if_else_node import IfElseNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.utils.condition.entities import Condition, SubCondition, SubVariableCondition +from dify_graph.variables import ArrayFileSegment from extensions.ext_database import db from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py b/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py index 73c17ee45a..8242f1d848 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py @@ -3,9 +3,9 @@ from unittest.mock import MagicMock import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.enums import WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.nodes.list_operator.entities import ( +from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.nodes.list_operator.entities import ( ExtractConfig, FilterBy, FilterCondition, @@ -14,9 +14,9 @@ from core.workflow.nodes.list_operator.entities import ( Order, OrderByConfig, ) -from core.workflow.nodes.list_operator.exc import InvalidKeyError -from core.workflow.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func -from core.workflow.variables import ArrayFileSegment +from dify_graph.nodes.list_operator.exc import InvalidKeyError +from dify_graph.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func +from dify_graph.variables import ArrayFileSegment from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py b/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py index 47ef289ef3..1b72589cba 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py @@ -1,5 +1,5 @@ from core.model_runtime.entities import ImagePromptMessageContent -from core.workflow.nodes.question_classifier import QuestionClassifierNodeData +from dify_graph.nodes.question_classifier import QuestionClassifierNodeData def test_init_question_classifier_node_data(): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_start_node_json_object.py b/api/tests/unit_tests/core/workflow/nodes/test_start_node_json_object.py index 8c7dc24868..5fd1e33768 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_start_node_json_object.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_start_node_json_object.py @@ -4,12 +4,12 @@ import time import pytest from pydantic import ValidationError as PydanticValidationError -from core.workflow.entities import GraphInitParams -from core.workflow.nodes.start.entities import StartNodeData -from core.workflow.nodes.start.start_node import StartNode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.entities import GraphInitParams +from dify_graph.nodes.start.entities import StartNodeData +from dify_graph.nodes.start.start_node import StartNode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType def make_start_node(user_inputs, variables): diff --git a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py index 678691439f..c6e40bbd84 100644 --- a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py @@ -11,15 +11,15 @@ import pytest from core.model_runtime.entities.llm_entities import LLMUsage from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.utils.message_transformer import ToolFileMessageTransformer -from core.workflow.entities import GraphInitParams -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.node_events import StreamChunkEvent, StreamCompletedEvent -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.segments import ArrayFileSegment +from dify_graph.entities import GraphInitParams +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.node_events import StreamChunkEvent, StreamCompletedEvent +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.segments import ArrayFileSegment if TYPE_CHECKING: # pragma: no cover - imported for type checking only - from core.workflow.nodes.tool.tool_node import ToolNode + from dify_graph.nodes.tool.tool_node import ToolNode @pytest.fixture @@ -31,7 +31,7 @@ def tool_node(monkeypatch) -> ToolNode: ops_stub.TraceTask = object # pragma: no cover - stub attribute monkeypatch.setitem(sys.modules, module_name, ops_stub) - from core.workflow.nodes.tool.tool_node import ToolNode + from dify_graph.nodes.tool.tool_node import ToolNode graph_config: dict[str, Any] = { "nodes": [ diff --git a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v1/test_variable_assigner_v1.py b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v1/test_variable_assigner_v1.py index 8a52f963ef..182172cb9c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v1/test_variable_assigner_v1.py +++ b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v1/test_variable_assigner_v1.py @@ -3,16 +3,16 @@ import uuid from uuid import uuid4 from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.graph_events.node import NodeRunSucceededEvent -from core.workflow.nodes.variable_assigner.common import helpers as common_helpers -from core.workflow.nodes.variable_assigner.v1 import VariableAssignerNode -from core.workflow.nodes.variable_assigner.v1.node_data import WriteMode -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import ArrayStringVariable, StringVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.graph_events.node import NodeRunSucceededEvent +from dify_graph.nodes.variable_assigner.common import helpers as common_helpers +from dify_graph.nodes.variable_assigner.v1 import VariableAssignerNode +from dify_graph.nodes.variable_assigner.v1.node_data import WriteMode +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import ArrayStringVariable, StringVariable from models.enums import UserFrom DEFAULT_NODE_ID = "node_id" diff --git a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_helpers.py b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_helpers.py index 9a874337ed..a7673c5a14 100644 --- a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_helpers.py +++ b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_helpers.py @@ -1,6 +1,6 @@ -from core.workflow.nodes.variable_assigner.v2.enums import Operation -from core.workflow.nodes.variable_assigner.v2.helpers import is_input_value_valid -from core.workflow.variables import SegmentType +from dify_graph.nodes.variable_assigner.v2.enums import Operation +from dify_graph.nodes.variable_assigner.v2.helpers import is_input_value_valid +from dify_graph.variables import SegmentType def test_is_input_value_valid_overwrite_array_string(): diff --git a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_variable_assigner_v2.py b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_variable_assigner_v2.py index 5ed68fe8d0..10eed1786f 100644 --- a/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_variable_assigner_v2.py +++ b/api/tests/unit_tests/core/workflow/nodes/variable_assigner/v2/test_variable_assigner_v2.py @@ -3,14 +3,14 @@ import uuid from uuid import uuid4 from core.app.entities.app_invoke_entities import InvokeFrom -from core.app.workflow.node_factory import DifyNodeFactory -from core.workflow.entities import GraphInitParams -from core.workflow.graph import Graph -from core.workflow.nodes.variable_assigner.v2 import VariableAssignerNode -from core.workflow.nodes.variable_assigner.v2.enums import InputType, Operation -from core.workflow.runtime import GraphRuntimeState, VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import ArrayStringVariable +from core.workflow.node_factory import DifyNodeFactory +from dify_graph.entities import GraphInitParams +from dify_graph.graph import Graph +from dify_graph.nodes.variable_assigner.v2 import VariableAssignerNode +from dify_graph.nodes.variable_assigner.v2.enums import InputType, Operation +from dify_graph.runtime import GraphRuntimeState, VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import ArrayStringVariable from models.enums import UserFrom DEFAULT_NODE_ID = "node_id" diff --git a/api/tests/unit_tests/core/workflow/nodes/webhook/test_entities.py b/api/tests/unit_tests/core/workflow/nodes/webhook/test_entities.py index 4fa9a01b61..410c4993e4 100644 --- a/api/tests/unit_tests/core/workflow/nodes/webhook/test_entities.py +++ b/api/tests/unit_tests/core/workflow/nodes/webhook/test_entities.py @@ -1,7 +1,7 @@ import pytest from pydantic import ValidationError -from core.workflow.nodes.trigger_webhook.entities import ( +from dify_graph.nodes.trigger_webhook.entities import ( ContentType, Method, WebhookBodyParameter, @@ -297,7 +297,7 @@ def test_webhook_body_parameter_edge_cases(): def test_webhook_data_inheritance(): """Test WebhookData inherits from BaseNodeData correctly.""" - from core.workflow.nodes.base import BaseNodeData + from dify_graph.nodes.base import BaseNodeData # Test that WebhookData is a subclass of BaseNodeData assert issubclass(WebhookData, BaseNodeData) diff --git a/api/tests/unit_tests/core/workflow/nodes/webhook/test_exceptions.py b/api/tests/unit_tests/core/workflow/nodes/webhook/test_exceptions.py index 374d5183c8..f2273e441e 100644 --- a/api/tests/unit_tests/core/workflow/nodes/webhook/test_exceptions.py +++ b/api/tests/unit_tests/core/workflow/nodes/webhook/test_exceptions.py @@ -1,7 +1,7 @@ import pytest -from core.workflow.nodes.base.exc import BaseNodeError -from core.workflow.nodes.trigger_webhook.exc import ( +from dify_graph.nodes.base.exc import BaseNodeError +from dify_graph.nodes.trigger_webhook.exc import ( WebhookConfigError, WebhookNodeError, WebhookNotFoundError, @@ -149,7 +149,7 @@ def test_webhook_error_attributes(): assert WebhookConfigError.__name__ == "WebhookConfigError" # Test that all error classes have proper __module__ - expected_module = "core.workflow.nodes.trigger_webhook.exc" + expected_module = "dify_graph.nodes.trigger_webhook.exc" assert WebhookNodeError.__module__ == expected_module assert WebhookTimeoutError.__module__ == expected_module assert WebhookNotFoundError.__module__ == expected_module diff --git a/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_file_conversion.py b/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_file_conversion.py index d8f6b41f89..8aeaf1707c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_file_conversion.py +++ b/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_file_conversion.py @@ -9,18 +9,18 @@ when passing files to downstream LLM nodes. from unittest.mock import Mock, patch from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.nodes.trigger_webhook.entities import ( +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.nodes.trigger_webhook.entities import ( ContentType, Method, WebhookBodyParameter, WebhookData, ) -from core.workflow.nodes.trigger_webhook.node import TriggerWebhookNode -from core.workflow.runtime.graph_runtime_state import GraphRuntimeState -from core.workflow.runtime.variable_pool import VariablePool -from core.workflow.system_variable import SystemVariable +from dify_graph.nodes.trigger_webhook.node import TriggerWebhookNode +from dify_graph.runtime.graph_runtime_state import GraphRuntimeState +from dify_graph.runtime.variable_pool import VariablePool +from dify_graph.system_variable import SystemVariable from models.enums import UserFrom from models.workflow import WorkflowType @@ -129,8 +129,8 @@ def test_webhook_node_file_conversion_to_file_variable(): # Mock the file factory and variable factory with ( patch("factories.file_factory.build_from_mapping") as mock_file_factory, - patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, - patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, + patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, + patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, ): # Setup mocks mock_file_obj = Mock() @@ -321,8 +321,8 @@ def test_webhook_node_file_conversion_mixed_parameters(): with ( patch("factories.file_factory.build_from_mapping") as mock_file_factory, - patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, - patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, + patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, + patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, ): # Setup mocks for file mock_file_obj = Mock() @@ -389,8 +389,8 @@ def test_webhook_node_different_file_types(): with ( patch("factories.file_factory.build_from_mapping") as mock_file_factory, - patch("core.workflow.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, - patch("core.workflow.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, + patch("dify_graph.nodes.trigger_webhook.node.build_segment_with_type") as mock_segment_factory, + patch("dify_graph.nodes.trigger_webhook.node.FileVariable") as mock_file_variable, ): # Setup mocks for all files mock_file_objs = [Mock() for _ in range(3)] diff --git a/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_node.py b/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_node.py index 24d3740b99..a6548ffc27 100644 --- a/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/webhook/test_webhook_node.py @@ -3,21 +3,21 @@ from unittest.mock import patch import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.graph_init_params import GraphInitParams -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.nodes.trigger_webhook.entities import ( +from dify_graph.entities.graph_init_params import GraphInitParams +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionStatus +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.nodes.trigger_webhook.entities import ( ContentType, Method, WebhookBodyParameter, WebhookData, WebhookParameter, ) -from core.workflow.nodes.trigger_webhook.node import TriggerWebhookNode -from core.workflow.runtime.graph_runtime_state import GraphRuntimeState -from core.workflow.runtime.variable_pool import VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import FileVariable, StringVariable +from dify_graph.nodes.trigger_webhook.node import TriggerWebhookNode +from dify_graph.runtime.graph_runtime_state import GraphRuntimeState +from dify_graph.runtime.variable_pool import VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import FileVariable, StringVariable from models.enums import UserFrom from models.workflow import WorkflowType diff --git a/api/tests/unit_tests/core/workflow/test_enums.py b/api/tests/unit_tests/core/workflow/test_enums.py index 078ec5f6ab..e8ce6f60f7 100644 --- a/api/tests/unit_tests/core/workflow/test_enums.py +++ b/api/tests/unit_tests/core/workflow/test_enums.py @@ -1,6 +1,6 @@ """Tests for workflow pause related enums and constants.""" -from core.workflow.enums import ( +from dify_graph.enums import ( WorkflowExecutionStatus, ) diff --git a/api/tests/unit_tests/core/workflow/test_system_variable.py b/api/tests/unit_tests/core/workflow/test_system_variable.py index 93e7c9f68d..8023a0b594 100644 --- a/api/tests/unit_tests/core/workflow/test_system_variable.py +++ b/api/tests/unit_tests/core/workflow/test_system_variable.py @@ -4,9 +4,9 @@ from typing import Any import pytest from pydantic import ValidationError -from core.workflow.file.enums import FileTransferMethod, FileType -from core.workflow.file.models import File -from core.workflow.system_variable import SystemVariable +from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.file.models import File +from dify_graph.system_variable import SystemVariable # Test data constants for SystemVariable serialization tests VALID_BASE_DATA: dict[str, Any] = { diff --git a/api/tests/unit_tests/core/workflow/test_system_variable_read_only_view.py b/api/tests/unit_tests/core/workflow/test_system_variable_read_only_view.py index 743fecaed0..b7a8f2551d 100644 --- a/api/tests/unit_tests/core/workflow/test_system_variable_read_only_view.py +++ b/api/tests/unit_tests/core/workflow/test_system_variable_read_only_view.py @@ -2,8 +2,8 @@ from typing import cast import pytest -from core.workflow.file.models import File, FileTransferMethod, FileType -from core.workflow.system_variable import SystemVariable, SystemVariableReadOnlyView +from dify_graph.file.models import File, FileTransferMethod, FileType +from dify_graph.system_variable import SystemVariable, SystemVariableReadOnlyView class TestSystemVariableReadOnlyView: diff --git a/api/tests/unit_tests/core/workflow/test_variable_pool.py b/api/tests/unit_tests/core/workflow/test_variable_pool.py index 7f2b080498..0fa0d26114 100644 --- a/api/tests/unit_tests/core/workflow/test_variable_pool.py +++ b/api/tests/unit_tests/core/workflow/test_variable_pool.py @@ -3,12 +3,12 @@ from collections import defaultdict import pytest -from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.runtime import VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables import FileSegment, StringSegment -from core.workflow.variables.segments import ( +from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.runtime import VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables import FileSegment, StringSegment +from dify_graph.variables.segments import ( ArrayAnySegment, ArrayFileSegment, ArrayNumberSegment, @@ -19,7 +19,7 @@ from core.workflow.variables.segments import ( NoneSegment, ObjectSegment, ) -from core.workflow.variables.variables import ( +from dify_graph.variables.variables import ( ArrayNumberVariable, ArrayObjectVariable, ArrayStringVariable, diff --git a/api/tests/unit_tests/core/workflow/test_workflow_entry.py b/api/tests/unit_tests/core/workflow/test_workflow_entry.py index 4a71692f1e..0aa6ec3f45 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_entry.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_entry.py @@ -4,18 +4,18 @@ import pytest from configs import dify_config from core.helper.code_executor.code_executor import CodeLanguage -from core.workflow.constants import ( +from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.constants import ( CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID, ) -from core.workflow.file.enums import FileType -from core.workflow.file.models import File, FileTransferMethod -from core.workflow.nodes.code.code_node import CodeNode -from core.workflow.nodes.code.limits import CodeNodeLimits -from core.workflow.runtime import VariablePool -from core.workflow.system_variable import SystemVariable -from core.workflow.variables.variables import StringVariable -from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.file.enums import FileType +from dify_graph.file.models import File, FileTransferMethod +from dify_graph.nodes.code.code_node import CodeNode +from dify_graph.nodes.code.limits import CodeNodeLimits +from dify_graph.runtime import VariablePool +from dify_graph.system_variable import SystemVariable +from dify_graph.variables.variables import StringVariable @pytest.fixture(autouse=True) diff --git a/api/tests/unit_tests/core/workflow/test_workflow_entry_redis_channel.py b/api/tests/unit_tests/core/workflow/test_workflow_entry_redis_channel.py index 12b9bf5f14..3437e585e7 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_entry_redis_channel.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_entry_redis_channel.py @@ -3,9 +3,9 @@ from unittest.mock import MagicMock, patch from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.graph_engine.command_channels.redis_channel import RedisChannel -from core.workflow.runtime import GraphRuntimeState, VariablePool from core.workflow.workflow_entry import WorkflowEntry +from dify_graph.graph_engine.command_channels.redis_channel import RedisChannel +from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import UserFrom diff --git a/api/tests/unit_tests/core/workflow/utils/test_condition.py b/api/tests/unit_tests/core/workflow/utils/test_condition.py index efedf88726..324ad5f674 100644 --- a/api/tests/unit_tests/core/workflow/utils/test_condition.py +++ b/api/tests/unit_tests/core/workflow/utils/test_condition.py @@ -1,6 +1,6 @@ -from core.workflow.runtime import VariablePool -from core.workflow.utils.condition.entities import Condition -from core.workflow.utils.condition.processor import ConditionProcessor +from dify_graph.runtime import VariablePool +from dify_graph.utils.condition.entities import Condition +from dify_graph.utils.condition.processor import ConditionProcessor def test_number_formatting(): diff --git a/api/tests/unit_tests/core/workflow/utils/test_variable_template_parser.py b/api/tests/unit_tests/core/workflow/utils/test_variable_template_parser.py index 83867e22e4..40df9de7fa 100644 --- a/api/tests/unit_tests/core/workflow/utils/test_variable_template_parser.py +++ b/api/tests/unit_tests/core/workflow/utils/test_variable_template_parser.py @@ -1,7 +1,7 @@ import dataclasses -from core.workflow.nodes.base import variable_template_parser -from core.workflow.nodes.base.entities import VariableSelector +from dify_graph.nodes.base import variable_template_parser +from dify_graph.nodes.base.entities import VariableSelector def test_extract_selectors_from_template(): diff --git a/api/tests/unit_tests/factories/test_variable_factory.py b/api/tests/unit_tests/factories/test_variable_factory.py index 87d02cb187..ce6b9232ce 100644 --- a/api/tests/unit_tests/factories/test_variable_factory.py +++ b/api/tests/unit_tests/factories/test_variable_factory.py @@ -7,8 +7,8 @@ import pytest from hypothesis import HealthCheck, given, settings from hypothesis import strategies as st -from core.workflow.file import File, FileTransferMethod, FileType -from core.workflow.variables import ( +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.variables import ( ArrayNumberVariable, ArrayObjectVariable, ArrayStringVariable, @@ -17,8 +17,8 @@ from core.workflow.variables import ( SecretVariable, StringVariable, ) -from core.workflow.variables.exc import VariableError -from core.workflow.variables.segments import ( +from dify_graph.variables.exc import VariableError +from dify_graph.variables.segments import ( ArrayAnySegment, ArrayFileSegment, ArrayNumberSegment, @@ -33,7 +33,7 @@ from core.workflow.variables.segments import ( Segment, StringSegment, ) -from core.workflow.variables.types import SegmentType +from dify_graph.variables.types import SegmentType from factories import variable_factory from factories.variable_factory import TypeMismatchError, build_segment, build_segment_with_type diff --git a/api/tests/unit_tests/libs/_human_input/support.py b/api/tests/unit_tests/libs/_human_input/support.py index bd86c13a2c..3fff54f487 100644 --- a/api/tests/unit_tests/libs/_human_input/support.py +++ b/api/tests/unit_tests/libs/_human_input/support.py @@ -4,8 +4,8 @@ from dataclasses import dataclass, field from datetime import datetime, timedelta from typing import Any -from core.workflow.nodes.human_input.entities import FormInput -from core.workflow.nodes.human_input.enums import TimeoutUnit +from dify_graph.nodes.human_input.entities import FormInput +from dify_graph.nodes.human_input.enums import TimeoutUnit # Exceptions diff --git a/api/tests/unit_tests/libs/_human_input/test_form_service.py b/api/tests/unit_tests/libs/_human_input/test_form_service.py index 15e7d41e85..82598c5c6d 100644 --- a/api/tests/unit_tests/libs/_human_input/test_form_service.py +++ b/api/tests/unit_tests/libs/_human_input/test_form_service.py @@ -6,11 +6,11 @@ from datetime import datetime, timedelta import pytest -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( FormInput, UserAction, ) -from core.workflow.nodes.human_input.enums import ( +from dify_graph.nodes.human_input.enums import ( FormInputType, TimeoutUnit, ) diff --git a/api/tests/unit_tests/libs/_human_input/test_models.py b/api/tests/unit_tests/libs/_human_input/test_models.py index 962eeb9e11..5d14b5eb4e 100644 --- a/api/tests/unit_tests/libs/_human_input/test_models.py +++ b/api/tests/unit_tests/libs/_human_input/test_models.py @@ -6,11 +6,11 @@ from datetime import datetime, timedelta import pytest -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( FormInput, UserAction, ) -from core.workflow.nodes.human_input.enums import ( +from dify_graph.nodes.human_input.enums import ( FormInputType, TimeoutUnit, ) diff --git a/api/tests/unit_tests/libs/test_cron_compatibility.py b/api/tests/unit_tests/libs/test_cron_compatibility.py index 6f3a94f6dc..61103d7935 100644 --- a/api/tests/unit_tests/libs/test_cron_compatibility.py +++ b/api/tests/unit_tests/libs/test_cron_compatibility.py @@ -294,7 +294,7 @@ class TestFrontendBackendIntegration(unittest.TestCase): def test_schedule_service_integration(self): """Test integration with ScheduleService patterns.""" - from core.workflow.nodes.trigger_schedule.entities import VisualConfig + from dify_graph.nodes.trigger_schedule.entities import VisualConfig from services.trigger.schedule_service import ScheduleService # Test enhanced syntax through visual config conversion diff --git a/api/tests/unit_tests/models/test_app_models.py b/api/tests/unit_tests/models/test_app_models.py index 8b96c62dc9..6c619dcf98 100644 --- a/api/tests/unit_tests/models/test_app_models.py +++ b/api/tests/unit_tests/models/test_app_models.py @@ -1204,7 +1204,7 @@ class TestConversationStatusCount: def test_status_count_batch_loading_implementation(self): """Test that status_count uses batch loading instead of N+1 queries.""" # Arrange - from core.workflow.enums import WorkflowExecutionStatus + from dify_graph.enums import WorkflowExecutionStatus app_id = str(uuid4()) conversation_id = str(uuid4()) @@ -1411,7 +1411,7 @@ class TestConversationStatusCount: def test_status_count_paused(self): """Test status_count includes paused workflow runs.""" # Arrange - from core.workflow.enums import WorkflowExecutionStatus + from dify_graph.enums import WorkflowExecutionStatus app_id = str(uuid4()) conversation_id = str(uuid4()) diff --git a/api/tests/unit_tests/models/test_conversation_variable.py b/api/tests/unit_tests/models/test_conversation_variable.py index d44aa56488..7d7674da3c 100644 --- a/api/tests/unit_tests/models/test_conversation_variable.py +++ b/api/tests/unit_tests/models/test_conversation_variable.py @@ -1,6 +1,6 @@ from uuid import uuid4 -from core.workflow.variables import SegmentType +from dify_graph.variables import SegmentType from factories import variable_factory from models import ConversationVariable diff --git a/api/tests/unit_tests/models/test_workflow.py b/api/tests/unit_tests/models/test_workflow.py index 544693da34..f3b72aa128 100644 --- a/api/tests/unit_tests/models/test_workflow.py +++ b/api/tests/unit_tests/models/test_workflow.py @@ -4,10 +4,10 @@ from unittest import mock from uuid import uuid4 from constants import HIDDEN_VALUE -from core.workflow.file.enums import FileTransferMethod, FileType -from core.workflow.file.models import File -from core.workflow.variables import FloatVariable, IntegerVariable, SecretVariable, StringVariable -from core.workflow.variables.segments import IntegerSegment, Segment +from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.file.models import File +from dify_graph.variables import FloatVariable, IntegerVariable, SecretVariable, StringVariable +from dify_graph.variables.segments import IntegerSegment, Segment from factories.variable_factory import build_segment from models.workflow import Workflow, WorkflowDraftVariable, WorkflowNodeExecutionModel, is_system_variable_editable diff --git a/api/tests/unit_tests/models/test_workflow_models.py b/api/tests/unit_tests/models/test_workflow_models.py index 9907cf05c0..f66f0b657d 100644 --- a/api/tests/unit_tests/models/test_workflow_models.py +++ b/api/tests/unit_tests/models/test_workflow_models.py @@ -14,7 +14,7 @@ from uuid import uuid4 import pytest -from core.workflow.enums import ( +from dify_graph.enums import ( NodeType, WorkflowExecutionStatus, WorkflowNodeExecutionStatus, diff --git a/api/tests/unit_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py b/api/tests/unit_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py index 4b5b3b318c..3707ed90be 100644 --- a/api/tests/unit_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py +++ b/api/tests/unit_tests/repositories/test_sqlalchemy_api_workflow_run_repository.py @@ -6,9 +6,9 @@ from unittest.mock import Mock, patch import pytest -from core.workflow.entities.pause_reason import HumanInputRequired, PauseReasonType -from core.workflow.nodes.human_input.entities import FormDefinition, FormInput, UserAction -from core.workflow.nodes.human_input.enums import FormInputType, HumanInputFormStatus +from dify_graph.entities.pause_reason import HumanInputRequired, PauseReasonType +from dify_graph.nodes.human_input.entities import FormDefinition, FormInput, UserAction +from dify_graph.nodes.human_input.enums import FormInputType, HumanInputFormStatus from models.human_input import BackstageRecipientPayload, HumanInputForm, HumanInputFormRecipient, RecipientType from models.workflow import WorkflowPause as WorkflowPauseModel from models.workflow import WorkflowPauseReason diff --git a/api/tests/unit_tests/repositories/test_sqlalchemy_execution_extra_content_repository.py b/api/tests/unit_tests/repositories/test_sqlalchemy_execution_extra_content_repository.py index f5428b46ff..8daf91c538 100644 --- a/api/tests/unit_tests/repositories/test_sqlalchemy_execution_extra_content_repository.py +++ b/api/tests/unit_tests/repositories/test_sqlalchemy_execution_extra_content_repository.py @@ -6,11 +6,11 @@ from datetime import UTC, datetime, timedelta from core.entities.execution_extra_content import HumanInputContent as HumanInputContentDomain from core.entities.execution_extra_content import HumanInputFormSubmissionData -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( FormDefinition, UserAction, ) -from core.workflow.nodes.human_input.enums import HumanInputFormStatus +from dify_graph.nodes.human_input.enums import HumanInputFormStatus from models.execution_extra_content import HumanInputContent as HumanInputContentModel from models.human_input import ConsoleRecipientPayload, HumanInputForm, HumanInputFormRecipient, RecipientType from repositories.sqlalchemy_execution_extra_content_repository import SQLAlchemyExecutionExtraContentRepository diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py index 5cba43714a..10a108d425 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py @@ -14,15 +14,15 @@ from sqlalchemy.orm import Session, sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities import ( +from dify_graph.entities import ( WorkflowNodeExecution, ) -from core.workflow.enums import ( +from dify_graph.enums import ( NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) -from core.workflow.repositories.workflow_node_execution_repository import OrderConfig +from dify_graph.repositories.workflow_node_execution_repository import OrderConfig from models.account import Account, Tenant from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_workflow_node_execution_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_workflow_node_execution_repository.py index 5539856083..95a7751273 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_workflow_node_execution_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_workflow_node_execution_repository.py @@ -11,8 +11,8 @@ from sqlalchemy.orm import sessionmaker from core.repositories.sqlalchemy_workflow_node_execution_repository import ( SQLAlchemyWorkflowNodeExecutionRepository, ) -from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution -from core.workflow.enums import NodeType +from dify_graph.entities.workflow_node_execution import WorkflowNodeExecution +from dify_graph.enums import NodeType from models import Account, WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom diff --git a/api/tests/unit_tests/services/external_dataset_service.py b/api/tests/unit_tests/services/external_dataset_service.py index 57364142ad..afc3b29fca 100644 --- a/api/tests/unit_tests/services/external_dataset_service.py +++ b/api/tests/unit_tests/services/external_dataset_service.py @@ -545,7 +545,7 @@ class TestExternalDatasetServiceProcessExternalApi: params={}, ) - from core.workflow.nodes.http_request.exc import InvalidHttpMethodError + from dify_graph.nodes.http_request.exc import InvalidHttpMethodError with pytest.raises(InvalidHttpMethodError): ExternalDatasetService.process_external_api(settings, files=None) diff --git a/api/tests/unit_tests/services/test_human_input_delivery_test_service.py b/api/tests/unit_tests/services/test_human_input_delivery_test_service.py index e0d6ad1b39..e64d3c5406 100644 --- a/api/tests/unit_tests/services/test_human_input_delivery_test_service.py +++ b/api/tests/unit_tests/services/test_human_input_delivery_test_service.py @@ -2,13 +2,13 @@ from types import SimpleNamespace import pytest -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, ExternalRecipient, ) -from core.workflow.runtime import VariablePool +from dify_graph.runtime import VariablePool from services import human_input_delivery_test_service as service_module from services.human_input_delivery_test_service import ( DeliveryTestContext, diff --git a/api/tests/unit_tests/services/test_human_input_service.py b/api/tests/unit_tests/services/test_human_input_service.py index 5800d029ca..a4c6c50593 100644 --- a/api/tests/unit_tests/services/test_human_input_service.py +++ b/api/tests/unit_tests/services/test_human_input_service.py @@ -9,12 +9,12 @@ from core.repositories.human_input_repository import ( HumanInputFormRecord, HumanInputFormSubmissionRepository, ) -from core.workflow.nodes.human_input.entities import ( +from dify_graph.nodes.human_input.entities import ( FormDefinition, FormInput, UserAction, ) -from core.workflow.nodes.human_input.enums import FormInputType, HumanInputFormKind, HumanInputFormStatus +from dify_graph.nodes.human_input.enums import FormInputType, HumanInputFormKind, HumanInputFormStatus from models.human_input import RecipientType from services.human_input_service import Form, FormExpiredError, HumanInputService, InvalidFormDataError diff --git a/api/tests/unit_tests/services/test_schedule_service.py b/api/tests/unit_tests/services/test_schedule_service.py index e28965ea2c..5e3dd157e6 100644 --- a/api/tests/unit_tests/services/test_schedule_service.py +++ b/api/tests/unit_tests/services/test_schedule_service.py @@ -5,8 +5,8 @@ from unittest.mock import MagicMock, Mock, patch import pytest from sqlalchemy.orm import Session -from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig -from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError +from dify_graph.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig +from dify_graph.nodes.trigger_schedule.exc import ScheduleConfigError from events.event_handlers.sync_workflow_schedule_when_app_published import ( sync_schedule_from_workflow, ) @@ -136,7 +136,7 @@ class TestScheduleService(unittest.TestCase): def test_update_schedule_not_found(self): """Test updating a non-existent schedule raises exception.""" - from core.workflow.nodes.trigger_schedule.exc import ScheduleNotFoundError + from dify_graph.nodes.trigger_schedule.exc import ScheduleNotFoundError mock_session = MagicMock(spec=Session) mock_session.get.return_value = None @@ -172,7 +172,7 @@ class TestScheduleService(unittest.TestCase): def test_delete_schedule_not_found(self): """Test deleting a non-existent schedule raises exception.""" - from core.workflow.nodes.trigger_schedule.exc import ScheduleNotFoundError + from dify_graph.nodes.trigger_schedule.exc import ScheduleNotFoundError mock_session = MagicMock(spec=Session) mock_session.get.return_value = None diff --git a/api/tests/unit_tests/services/test_variable_truncator.py b/api/tests/unit_tests/services/test_variable_truncator.py index 8199d586da..c703ab64d0 100644 --- a/api/tests/unit_tests/services/test_variable_truncator.py +++ b/api/tests/unit_tests/services/test_variable_truncator.py @@ -17,9 +17,9 @@ from uuid import uuid4 import pytest -from core.workflow.file.enums import FileTransferMethod, FileType -from core.workflow.file.models import File -from core.workflow.variables.segments import ( +from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.file.models import File +from dify_graph.variables.segments import ( ArrayFileSegment, ArrayNumberSegment, ArraySegment, diff --git a/api/tests/unit_tests/services/test_workflow_run_service_pause.py b/api/tests/unit_tests/services/test_workflow_run_service_pause.py index 1f92ff590c..27664c7e29 100644 --- a/api/tests/unit_tests/services/test_workflow_run_service_pause.py +++ b/api/tests/unit_tests/services/test_workflow_run_service_pause.py @@ -16,7 +16,7 @@ import pytest from sqlalchemy import Engine from sqlalchemy.orm import Session, sessionmaker -from core.workflow.enums import WorkflowExecutionStatus +from dify_graph.enums import WorkflowExecutionStatus from models.workflow import WorkflowPause from repositories.api_workflow_run_repository import APIWorkflowRunRepository from repositories.sqlalchemy_api_workflow_run_repository import _PrivateWorkflowPauseEntity diff --git a/api/tests/unit_tests/services/test_workflow_service.py b/api/tests/unit_tests/services/test_workflow_service.py index 3a4f2d392a..8820a1acc0 100644 --- a/api/tests/unit_tests/services/test_workflow_service.py +++ b/api/tests/unit_tests/services/test_workflow_service.py @@ -14,8 +14,8 @@ from unittest.mock import MagicMock, patch import pytest -from core.workflow.enums import NodeType -from core.workflow.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNode, HttpRequestNodeConfig +from dify_graph.enums import NodeType +from dify_graph.nodes.http_request import HTTP_REQUEST_CONFIG_FILTER_KEY, HttpRequestNode, HttpRequestNodeConfig from libs.datetime_utils import naive_utc_now from models.model import App, AppMode from models.workflow import Workflow, WorkflowType diff --git a/api/tests/unit_tests/services/workflow/test_draft_var_loader_simple.py b/api/tests/unit_tests/services/workflow/test_draft_var_loader_simple.py index 83642fc209..1e0fdd788b 100644 --- a/api/tests/unit_tests/services/workflow/test_draft_var_loader_simple.py +++ b/api/tests/unit_tests/services/workflow/test_draft_var_loader_simple.py @@ -6,8 +6,8 @@ from unittest.mock import Mock, patch import pytest from sqlalchemy import Engine -from core.workflow.variables.segments import ObjectSegment, StringSegment -from core.workflow.variables.types import SegmentType +from dify_graph.variables.segments import ObjectSegment, StringSegment +from dify_graph.variables.types import SegmentType from models.model import UploadFile from models.workflow import WorkflowDraftVariable, WorkflowDraftVariableFile from services.workflow_draft_variable_service import DraftVarLoader @@ -174,7 +174,7 @@ class TestDraftVarLoaderSimple: mock_storage.load.return_value = test_json_content.encode() with patch.object(WorkflowDraftVariable, "build_segment_with_type") as mock_build_segment: - from core.workflow.variables.segments import FloatSegment + from dify_graph.variables.segments import FloatSegment mock_segment = FloatSegment(value=test_number) mock_build_segment.return_value = mock_segment @@ -224,7 +224,7 @@ class TestDraftVarLoaderSimple: mock_storage.load.return_value = test_json_content.encode() with patch.object(WorkflowDraftVariable, "build_segment_with_type") as mock_build_segment: - from core.workflow.variables.segments import ArrayAnySegment + from dify_graph.variables.segments import ArrayAnySegment mock_segment = ArrayAnySegment(value=test_array) mock_build_segment.return_value = mock_segment diff --git a/api/tests/unit_tests/services/workflow/test_workflow_converter.py b/api/tests/unit_tests/services/workflow/test_workflow_converter.py index 8ccbfbb16e..fefd771546 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_converter.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_converter.py @@ -17,7 +17,7 @@ from core.app.app_config.entities import ( from core.helper import encrypter from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.message_entities import PromptMessageRole -from core.workflow.variables.input_entities import VariableEntity, VariableEntityType +from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint from models.model import AppMode from services.workflow.workflow_converter import WorkflowConverter diff --git a/api/tests/unit_tests/services/workflow/test_workflow_draft_variable_service.py b/api/tests/unit_tests/services/workflow/test_workflow_draft_variable_service.py index 792257848f..4042e05565 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_draft_variable_service.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_draft_variable_service.py @@ -7,10 +7,10 @@ import pytest from sqlalchemy import Engine from sqlalchemy.orm import Session -from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.enums import NodeType -from core.workflow.variables.segments import StringSegment -from core.workflow.variables.types import SegmentType +from dify_graph.constants import SYSTEM_VARIABLE_NODE_ID +from dify_graph.enums import NodeType +from dify_graph.variables.segments import StringSegment +from dify_graph.variables.types import SegmentType from libs.uuid_utils import uuidv7 from models.account import Account from models.enums import DraftVariableType diff --git a/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py b/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py index 844dab8976..6c1adba2b8 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py @@ -12,9 +12,9 @@ import pytest from core.app.app_config.entities import WorkflowUIBasedAppConfig from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity from core.app.layers.pause_state_persist_layer import WorkflowResumptionContext, _WorkflowGenerateEntityWrapper -from core.workflow.entities.pause_reason import HumanInputRequired -from core.workflow.enums import WorkflowExecutionStatus, WorkflowNodeExecutionStatus -from core.workflow.runtime import GraphRuntimeState, VariablePool +from dify_graph.entities.pause_reason import HumanInputRequired +from dify_graph.enums import WorkflowExecutionStatus, WorkflowNodeExecutionStatus +from dify_graph.runtime import GraphRuntimeState, VariablePool from models.enums import CreatorUserRole from models.model import AppMode from models.workflow import WorkflowRun diff --git a/api/tests/unit_tests/services/workflow/test_workflow_human_input_delivery.py b/api/tests/unit_tests/services/workflow/test_workflow_human_input_delivery.py index 5ac5ac8ad2..5d6fa4c137 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_human_input_delivery.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_human_input_delivery.py @@ -5,8 +5,8 @@ from unittest.mock import MagicMock import pytest from sqlalchemy.orm import sessionmaker -from core.workflow.enums import NodeType -from core.workflow.nodes.human_input.entities import ( +from dify_graph.enums import NodeType +from dify_graph.nodes.human_input.entities import ( EmailDeliveryConfig, EmailDeliveryMethod, EmailRecipients, diff --git a/api/tests/unit_tests/services/workflow/test_workflow_service.py b/api/tests/unit_tests/services/workflow/test_workflow_service.py index 015dac257e..83c1f8d9da 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_service.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_service.py @@ -4,9 +4,9 @@ from unittest.mock import MagicMock import pytest -from core.workflow.enums import NodeType -from core.workflow.nodes.human_input.entities import FormInput, HumanInputNodeData, UserAction -from core.workflow.nodes.human_input.enums import FormInputType +from dify_graph.enums import NodeType +from dify_graph.nodes.human_input.entities import FormInput, HumanInputNodeData, UserAction +from dify_graph.nodes.human_input.enums import FormInputType from models.model import App from models.workflow import Workflow from services import workflow_service as workflow_service_module diff --git a/api/tests/unit_tests/tasks/test_human_input_timeout_tasks.py b/api/tests/unit_tests/tasks/test_human_input_timeout_tasks.py index ee0699ba2d..6b07f88c41 100644 --- a/api/tests/unit_tests/tasks/test_human_input_timeout_tasks.py +++ b/api/tests/unit_tests/tasks/test_human_input_timeout_tasks.py @@ -6,7 +6,7 @@ from typing import Any import pytest -from core.workflow.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus +from dify_graph.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus from tasks import human_input_timeout_tasks as task_module diff --git a/api/tests/unit_tests/tasks/test_workflow_node_execution_tasks.py b/api/tests/unit_tests/tasks/test_workflow_node_execution_tasks.py index fd5f0713a4..54be8379d5 100644 --- a/api/tests/unit_tests/tasks/test_workflow_node_execution_tasks.py +++ b/api/tests/unit_tests/tasks/test_workflow_node_execution_tasks.py @@ -11,11 +11,11 @@ # import pytest -# from core.workflow.entities.workflow_node_execution import ( +# from dify_graph.entities.workflow_node_execution import ( # WorkflowNodeExecution, # WorkflowNodeExecutionStatus, # ) -# from core.workflow.enums import NodeType +# from dify_graph.enums import NodeType # from libs.datetime_utils import naive_utc_now # from models import WorkflowNodeExecutionModel # from models.enums import ExecutionOffLoadType From e985e73bdc4ae5fc8c60fa080bac7222c101b0b0 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Mon, 2 Mar 2026 18:49:21 +0800 Subject: [PATCH 017/159] perf: optimize dataset api query speed (#32847) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/controllers/console/datasets/datasets.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/api/controllers/console/datasets/datasets.py b/api/controllers/console/datasets/datasets.py index a06b872846..92a6eede8a 100644 --- a/api/controllers/console/datasets/datasets.py +++ b/api/controllers/console/datasets/datasets.py @@ -53,7 +53,7 @@ from fields.dataset_fields import ( from fields.document_fields import document_status_fields from libs.login import current_account_with_tenant, login_required from models import ApiToken, Dataset, Document, DocumentSegment, UploadFile -from models.dataset import DatasetPermissionEnum +from models.dataset import DatasetPermission, DatasetPermissionEnum from models.provider_ids import ModelProviderID from services.api_token_service import ApiTokenCache from services.dataset_service import DatasetPermissionService, DatasetService, DocumentService @@ -323,6 +323,18 @@ class DatasetListApi(Resource): model_names.append(f"{embedding_model.model}:{embedding_model.provider.provider}") data = cast(list[dict[str, Any]], marshal(datasets, dataset_detail_fields)) + dataset_ids = [item["id"] for item in data if item.get("permission") == "partial_members"] + partial_members_map: dict[str, list[str]] = {} + if dataset_ids: + permissions = db.session.execute( + select(DatasetPermission.dataset_id, DatasetPermission.account_id).where( + DatasetPermission.dataset_id.in_(dataset_ids) + ) + ).all() + + for dataset_id, account_id in permissions: + partial_members_map.setdefault(dataset_id, []).append(account_id) + for item in data: # convert embedding_model_provider to plugin standard format if item["indexing_technique"] == "high_quality" and item["embedding_model_provider"]: @@ -336,8 +348,7 @@ class DatasetListApi(Resource): item["embedding_available"] = True if item.get("permission") == "partial_members": - part_users_list = DatasetPermissionService.get_dataset_partial_member_list(item["id"]) - item.update({"partial_member_list": part_users_list}) + item.update({"partial_member_list": partial_members_map.get(item["id"], [])}) else: item.update({"partial_member_list": []}) From 4fd6b52808584b86f140f5c02ddced7460322764 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Mon, 2 Mar 2026 20:15:32 +0800 Subject: [PATCH 018/159] refactor(api): move model_runtime into dify_graph (#32858) --- .github/CODEOWNERS | 2 +- api/.importlinter | 65 ++++--------------- api/.ruff.toml | 2 +- api/controllers/console/app/audio.py | 2 +- api/controllers/console/app/completion.py | 2 +- api/controllers/console/app/generator.py | 2 +- api/controllers/console/app/message.py | 2 +- api/controllers/console/app/workflow.py | 2 +- api/controllers/console/auth/oauth_server.py | 2 +- api/controllers/console/datasets/datasets.py | 2 +- .../console/datasets/datasets_document.py | 4 +- .../console/datasets/datasets_segments.py | 2 +- .../console/datasets/hit_testing_base.py | 2 +- .../datasets/rag_pipeline/datasource_auth.py | 4 +- .../rag_pipeline/rag_pipeline_workflow.py | 2 +- api/controllers/console/explore/audio.py | 2 +- api/controllers/console/explore/completion.py | 2 +- api/controllers/console/explore/message.py | 2 +- api/controllers/console/explore/trial.py | 2 +- api/controllers/console/explore/workflow.py | 2 +- .../console/workspace/agent_providers.py | 2 +- api/controllers/console/workspace/endpoint.py | 2 +- .../workspace/load_balancing_config.py | 4 +- .../console/workspace/model_providers.py | 6 +- api/controllers/console/workspace/models.py | 6 +- api/controllers/console/workspace/plugin.py | 2 +- .../console/workspace/tool_providers.py | 2 +- .../console/workspace/trigger_providers.py | 2 +- api/controllers/inner_api/plugin/plugin.py | 2 +- api/controllers/service_api/app/audio.py | 2 +- api/controllers/service_api/app/completion.py | 2 +- api/controllers/service_api/app/workflow.py | 2 +- .../service_api/dataset/dataset.py | 2 +- .../service_api/dataset/segment.py | 2 +- .../service_api/workspace/models.py | 2 +- api/controllers/web/audio.py | 2 +- api/controllers/web/completion.py | 2 +- api/controllers/web/message.py | 2 +- api/controllers/web/workflow.py | 2 +- api/core/agent/base_agent_runner.py | 24 +++---- api/core/agent/cot_agent_runner.py | 14 ++-- api/core/agent/cot_chat_agent_runner.py | 8 +-- api/core/agent/cot_completion_agent_runner.py | 4 +- api/core/agent/fc_agent_runner.py | 12 ++-- .../agent/output_parser/cot_output_parser.py | 2 +- .../model_config/converter.py | 6 +- .../easy_ui_based_app/model_config/manager.py | 4 +- .../prompt_template/manager.py | 2 +- api/core/app/app_config/entities.py | 4 +- .../app/apps/advanced_chat/app_generator.py | 2 +- .../advanced_chat/generate_task_pipeline.py | 4 +- api/core/app/apps/agent_chat/app_generator.py | 2 +- api/core/app/apps/agent_chat/app_runner.py | 6 +- .../base_app_generate_response_converter.py | 2 +- api/core/app/apps/base_app_runner.py | 18 ++--- api/core/app/apps/chat/app_generator.py | 2 +- api/core/app/apps/chat/app_runner.py | 2 +- api/core/app/apps/completion/app_generator.py | 2 +- api/core/app/apps/completion/app_runner.py | 2 +- .../app/apps/pipeline/pipeline_generator.py | 2 +- api/core/app/apps/workflow/app_generator.py | 2 +- api/core/app/entities/app_invoke_entities.py | 2 +- api/core/app/entities/queue_entities.py | 2 +- api/core/app/entities/task_entities.py | 2 +- .../hosting_moderation/hosting_moderation.py | 2 +- api/core/app/llm/model_access.py | 2 +- api/core/app/llm/quota.py | 2 +- .../based_generate_task_pipeline.py | 2 +- .../easy_ui_based_generate_task_pipeline.py | 12 ++-- .../base/tts/app_generator_tts_publisher.py | 4 +- api/core/datasource/entities/api_entities.py | 2 +- api/core/entities/model_entities.py | 6 +- api/core/entities/provider_configuration.py | 8 +-- api/core/entities/provider_entities.py | 2 +- api/core/helper/moderation.py | 8 +-- api/core/hosting_configuration.py | 2 +- api/core/indexing_runner.py | 2 +- api/core/llm_generator/llm_generator.py | 8 +-- .../output_parser/structured_output.py | 8 +-- api/core/mcp/utils.py | 2 +- api/core/memory/token_buffer_memory.py | 8 +-- api/core/model_manager.py | 26 ++++---- .../openai_moderation/openai_moderation.py | 2 +- api/core/plugin/backwards_invocation/model.py | 24 +++---- api/core/plugin/entities/marketplace.py | 2 +- api/core/plugin/entities/plugin.py | 2 +- api/core/plugin/entities/plugin_daemon.py | 4 +- api/core/plugin/entities/request.py | 6 +- api/core/plugin/impl/base.py | 16 ++--- api/core/plugin/impl/model.py | 12 ++-- api/core/prompt/advanced_prompt_transform.py | 14 ++-- .../prompt/agent_history_prompt_transform.py | 6 +- .../entities/advanced_prompt_entities.py | 2 +- api/core/prompt/prompt_transform.py | 4 +- api/core/prompt/simple_prompt_transform.py | 10 +-- api/core/prompt/utils/prompt_message_util.py | 4 +- api/core/provider_manager.py | 6 +- .../data_post_processor.py | 4 +- api/core/rag/datasource/retrieval_service.py | 2 +- api/core/rag/datasource/vdb/vector_factory.py | 2 +- api/core/rag/docstore/dataset_docstore.py | 2 +- api/core/rag/embedding/cached_embedding.py | 4 +- .../processor/paragraph_index_processor.py | 18 ++--- api/core/rag/rerank/rerank_model.py | 4 +- api/core/rag/rerank/weight_rerank.py | 2 +- api/core/rag/retrieval/dataset_retrieval.py | 8 +-- .../multi_dataset_function_call_router.py | 4 +- .../router/multi_dataset_react_route.py | 4 +- api/core/rag/splitter/fixed_text_splitter.py | 2 +- ...hemy_workflow_node_execution_repository.py | 2 +- .../builtin_tool/providers/audio/tools/asr.py | 2 +- .../builtin_tool/providers/audio/tools/tts.py | 2 +- api/core/tools/builtin_tool/tool.py | 4 +- api/core/tools/entities/api_entities.py | 2 +- api/core/tools/mcp_tool/tool.py | 2 +- api/core/tools/tool_manager.py | 2 +- .../dataset_multi_retriever_tool.py | 2 +- .../tools/utils/model_invocation_utils.py | 12 ++-- api/core/tools/workflow_as_tool/tool.py | 2 +- api/core/workflow/node_factory.py | 6 +- api/dify_graph/file/file_manager.py | 4 +- api/dify_graph/file/models.py | 2 +- .../event_management/event_handlers.py | 2 +- .../model_runtime/README.md | 0 .../model_runtime/README_CN.md | 0 .../model_runtime/__init__.py | 0 .../model_runtime/callbacks/__init__.py | 0 .../model_runtime/callbacks/base_callback.py | 6 +- .../callbacks/logging_callback.py | 8 +-- .../model_runtime/entities/__init__.py | 0 .../model_runtime/entities/common_entities.py | 0 .../model_runtime/entities/defaults.py | 2 +- .../model_runtime/entities/llm_entities.py | 4 +- .../entities/message_entities.py | 0 .../model_runtime/entities/model_entities.py | 2 +- .../entities/provider_entities.py | 4 +- .../model_runtime/entities/rerank_entities.py | 0 .../entities/text_embedding_entities.py | 2 +- .../model_runtime/errors/__init__.py | 0 .../model_runtime/errors/invoke.py | 0 .../model_runtime/errors/validate.py | 0 .../model_runtime/memory/__init__.py | 0 .../memory/prompt_message_memory.py | 2 +- .../model_providers/__base/__init__.py | 0 .../model_providers/__base/ai_model.py | 10 +-- .../__base/large_language_model.py | 12 ++-- .../__base/moderation_model.py | 4 +- .../model_providers/__base/rerank_model.py | 6 +- .../__base/speech2text_model.py | 4 +- .../__base/text_embedding_model.py | 6 +- .../__base/tokenizers/gpt2_tokenizer.py | 0 .../model_providers/__base/tts_model.py | 4 +- .../model_runtime/model_providers/__init__.py | 0 .../model_providers/_position.yaml | 0 .../model_providers/model_provider_factory.py | 24 +++---- .../schema_validators/__init__.py | 0 .../schema_validators/common_validator.py | 2 +- .../model_credential_schema_validator.py | 6 +- .../provider_credential_schema_validator.py | 4 +- .../model_runtime/utils/__init__.py | 0 .../model_runtime/utils/encoders.py | 0 api/dify_graph/node_events/base.py | 2 +- api/dify_graph/node_events/node.py | 2 +- api/dify_graph/nodes/agent/agent_node.py | 6 +- .../nodes/base/usage_tracking_mixin.py | 2 +- .../nodes/iteration/iteration_node.py | 2 +- .../knowledge_retrieval_node.py | 4 +- api/dify_graph/nodes/llm/entities.py | 2 +- api/dify_graph/nodes/llm/llm_utils.py | 12 ++-- api/dify_graph/nodes/llm/node.py | 48 +++++++------- api/dify_graph/nodes/loop/loop_node.py | 2 +- .../parameter_extractor_node.py | 28 ++++---- .../question_classifier_node.py | 6 +- api/dify_graph/nodes/tool/tool_node.py | 2 +- .../repositories/rag_retrieval_protocol.py | 2 +- api/dify_graph/runtime/graph_runtime_state.py | 2 +- .../runtime/graph_runtime_state_protocol.py | 2 +- api/dify_graph/runtime/read_only_wrappers.py | 2 +- api/extensions/ext_sentry.py | 2 +- ...tore_workflow_node_execution_repository.py | 2 +- api/libs/helper.py | 2 +- api/services/app_dsl_service.py | 2 +- api/services/app_service.py | 4 +- api/services/audio_service.py | 2 +- .../clear_free_plan_tenant_expired_logs.py | 2 +- api/services/dataset_service.py | 4 +- api/services/datasource_provider_service.py | 2 +- .../entities/model_provider_entities.py | 6 +- api/services/hit_testing_service.py | 2 +- api/services/message_service.py | 2 +- api/services/model_load_balancing_service.py | 8 +-- api/services/model_provider_service.py | 4 +- .../rag_pipeline/rag_pipeline_dsl_service.py | 2 +- api/services/summary_index_service.py | 4 +- .../tools/api_tools_manage_service.py | 2 +- .../tools/workflow_tools_manage_service.py | 2 +- api/services/vector_service.py | 2 +- api/services/workflow/workflow_converter.py | 4 +- api/services/workflow_service.py | 4 +- .../batch_create_segment_to_index_task.py | 2 +- .../model_runtime/__mock/plugin_model.py | 21 ++++-- .../workflow/nodes/__mock/model.py | 4 +- .../workflow/nodes/test_llm.py | 12 ++-- .../nodes/test_parameter_extractor.py | 2 +- .../layers/test_pause_state_persist_layer.py | 2 +- .../services/test_dataset_service.py | 2 +- .../test_dataset_service_update_dataset.py | 2 +- .../services/test_model_provider_service.py | 8 +-- .../workflow/test_workflow_converter.py | 2 +- .../workspace/test_load_balancing_config.py | 4 +- .../controllers/service_api/app/test_audio.py | 2 +- .../service_api/app/test_completion.py | 2 +- .../output_parser/test_cot_output_parser.py | 2 +- .../features/file_upload/test_manager.py | 2 +- .../chat/test_base_app_runner_multimodal.py | 2 +- ...st_easy_ui_based_generate_task_pipeline.py | 4 +- .../__base/test_increase_tool_call.py | 10 +-- ...large_language_model_non_stream_parsing.py | 6 +- .../entities/test_llm_entities.py | 2 +- .../core/plugin/test_plugin_runtime.py | 16 ++--- .../prompt/test_advanced_prompt_transform.py | 10 +-- .../test_agent_history_prompt_transform.py | 6 +- .../core/prompt/test_prompt_message.py | 2 +- .../core/prompt/test_prompt_transform.py | 8 +-- .../prompt/test_simple_prompt_transform.py | 2 +- .../rag/embedding/test_embedding_service.py | 8 +-- .../core/rag/indexing/test_indexing_runner.py | 2 +- .../core/rag/rerank/test_reranker.py | 2 +- .../unit_tests/core/test_model_manager.py | 2 +- .../core/test_provider_configuration.py | 6 +- .../unit_tests/core/test_provider_manager.py | 2 +- .../entities/test_graph_runtime_state.py | 2 +- .../graph_engine/layers/test_llm_quota.py | 2 +- .../graph_engine/test_graph_state_snapshot.py | 4 +- .../test_human_input_pause_multi_branch.py | 2 +- .../test_human_input_pause_single_branch.py | 2 +- .../graph_engine/test_if_else_streaming.py | 4 +- .../workflow/graph_engine/test_mock_nodes.py | 2 +- ...rallel_human_input_pause_missing_finish.py | 4 +- .../test_pause_deferred_ready_nodes.py | 4 +- .../test_knowledge_retrieval_node.py | 2 +- .../core/workflow/nodes/llm/test_node.py | 14 ++-- .../core/workflow/nodes/llm/test_scenarios.py | 4 +- .../test_parameter_extractor_node.py | 2 +- .../nodes/test_question_classifier_node.py | 2 +- .../workflow/nodes/tool/test_tool_node.py | 2 +- .../test_sqlalchemy_repository.py | 2 +- .../services/document_service_validation.py | 2 +- .../test_dataset_service_create_dataset.py | 2 +- ...est_model_provider_service_sanitization.py | 6 +- .../workflow/test_workflow_converter.py | 4 +- api/tests/unit_tests/tools/test_mcp_tool.py | 2 +- .../test_structured_output_parser.py | 6 +- 253 files changed, 557 insertions(+), 589 deletions(-) rename api/{core => dify_graph}/model_runtime/README.md (100%) rename api/{core => dify_graph}/model_runtime/README_CN.md (100%) rename api/{core => dify_graph}/model_runtime/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/callbacks/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/callbacks/base_callback.py (94%) rename api/{core => dify_graph}/model_runtime/callbacks/logging_callback.py (94%) rename api/{core => dify_graph}/model_runtime/entities/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/entities/common_entities.py (100%) rename api/{core => dify_graph}/model_runtime/entities/defaults.py (98%) rename api/{core => dify_graph}/model_runtime/entities/llm_entities.py (97%) rename api/{core => dify_graph}/model_runtime/entities/message_entities.py (100%) rename api/{core => dify_graph}/model_runtime/entities/model_entities.py (98%) rename api/{core => dify_graph}/model_runtime/entities/provider_entities.py (95%) rename api/{core => dify_graph}/model_runtime/entities/rerank_entities.py (100%) rename api/{core => dify_graph}/model_runtime/entities/text_embedding_entities.py (89%) rename api/{core => dify_graph}/model_runtime/errors/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/errors/invoke.py (100%) rename api/{core => dify_graph}/model_runtime/errors/validate.py (100%) rename api/{core => dify_graph}/model_runtime/memory/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/memory/prompt_message_memory.py (89%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/ai_model.py (97%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/large_language_model.py (98%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/moderation_model.py (89%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/rerank_model.py (92%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/speech2text_model.py (88%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/text_embedding_model.py (94%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/tokenizers/gpt2_tokenizer.py (100%) rename api/{core => dify_graph}/model_runtime/model_providers/__base/tts_model.py (94%) rename api/{core => dify_graph}/model_runtime/model_providers/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/model_providers/_position.yaml (100%) rename api/{core => dify_graph}/model_runtime/model_providers/model_provider_factory.py (93%) rename api/{core => dify_graph}/model_runtime/schema_validators/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/schema_validators/common_validator.py (97%) rename api/{core => dify_graph}/model_runtime/schema_validators/model_credential_schema_validator.py (78%) rename api/{core => dify_graph}/model_runtime/schema_validators/provider_credential_schema_validator.py (79%) rename api/{core => dify_graph}/model_runtime/utils/__init__.py (100%) rename api/{core => dify_graph}/model_runtime/utils/encoders.py (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bfb1c85436..1bb7d06232 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,7 +36,7 @@ /api/core/workflow/graph/ @laipz8200 @QuantumGhost /api/core/workflow/graph_events/ @laipz8200 @QuantumGhost /api/core/workflow/node_events/ @laipz8200 @QuantumGhost -/api/core/model_runtime/ @laipz8200 @QuantumGhost +/api/dify_graph/model_runtime/ @laipz8200 @QuantumGhost # Backend - Workflow - Nodes (Agent, Iteration, Loop, LLM) /api/core/workflow/nodes/agent/ @Nov1c444 diff --git a/api/.importlinter b/api/.importlinter index 0bba4fb1e0..ebf4ccfbe9 100644 --- a/api/.importlinter +++ b/api/.importlinter @@ -56,6 +56,8 @@ ignore_imports = dify_graph.nodes.llm.file_saver -> extensions.ext_database dify_graph.nodes.llm.node -> extensions.ext_database dify_graph.nodes.tool.tool_node -> extensions.ext_database + dify_graph.model_runtime.model_providers.__base.ai_model -> extensions.ext_redis + dify_graph.model_runtime.model_providers.model_provider_factory -> extensions.ext_redis # TODO(QuantumGhost): use DI to avoid depending on global DB. dify_graph.nodes.human_input.human_input_node -> extensions.ext_database @@ -110,7 +112,7 @@ ignore_imports = dify_graph.nodes.iteration.iteration_node -> core.app.workflow.layers.llm_quota dify_graph.nodes.llm.llm_utils -> core.model_manager dify_graph.nodes.llm.protocols -> core.model_manager - dify_graph.nodes.llm.llm_utils -> core.model_runtime.model_providers.__base.large_language_model + dify_graph.nodes.llm.llm_utils -> dify_graph.model_runtime.model_providers.__base.large_language_model dify_graph.nodes.llm.node -> core.tools.signature dify_graph.nodes.tool.tool_node -> core.callback_handler.workflow_tool_callback_handler dify_graph.nodes.tool.tool_node -> core.tools.tool_engine @@ -123,7 +125,7 @@ ignore_imports = dify_graph.nodes.knowledge_retrieval.knowledge_retrieval_node -> core.app.app_config.entities dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.advanced_prompt_transform dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.prompt.simple_prompt_transform - dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.model_runtime.model_providers.__base.large_language_model + dify_graph.nodes.parameter_extractor.parameter_extractor_node -> dify_graph.model_runtime.model_providers.__base.large_language_model dify_graph.nodes.question_classifier.question_classifier_node -> core.prompt.simple_prompt_transform dify_graph.nodes.parameter_extractor.parameter_extractor_node -> core.model_manager dify_graph.nodes.question_classifier.question_classifier_node -> core.model_manager @@ -163,58 +165,13 @@ ignore_imports = dify_graph.nodes.llm.node -> models.model dify_graph.nodes.agent.agent_node -> services dify_graph.nodes.tool.tool_node -> services - -[importlinter:contract:model-runtime-no-internal-imports] -name = Model Runtime Internal Imports -type = forbidden -source_modules = - core.model_runtime -forbidden_modules = - configs - controllers - extensions - models - services - tasks - core.agent - core.app - core.base - core.callback_handler - core.datasource - core.db - core.entities - core.errors - core.extension - core.external_data_tool - core.file - core.helper - core.hosting_configuration - core.indexing_runner - core.llm_generator - core.logging - core.mcp - core.memory - core.model_manager - core.moderation - core.ops - core.plugin - core.prompt - core.provider_manager - core.rag - core.repositories - core.schemas - core.tools - core.trigger - core.variables - dify_graph -ignore_imports = - core.model_runtime.model_providers.__base.ai_model -> configs - core.model_runtime.model_providers.__base.ai_model -> extensions.ext_redis - core.model_runtime.model_providers.__base.large_language_model -> configs - core.model_runtime.model_providers.__base.text_embedding_model -> core.entities.embedding_type - core.model_runtime.model_providers.model_provider_factory -> configs - core.model_runtime.model_providers.model_provider_factory -> extensions.ext_redis - core.model_runtime.model_providers.model_provider_factory -> models.provider_ids + dify_graph.model_runtime.model_providers.__base.ai_model -> configs + dify_graph.model_runtime.model_providers.__base.ai_model -> extensions.ext_redis + dify_graph.model_runtime.model_providers.__base.large_language_model -> configs + dify_graph.model_runtime.model_providers.__base.text_embedding_model -> core.entities.embedding_type + dify_graph.model_runtime.model_providers.model_provider_factory -> configs + dify_graph.model_runtime.model_providers.model_provider_factory -> extensions.ext_redis + dify_graph.model_runtime.model_providers.model_provider_factory -> models.provider_ids [importlinter:contract:rsc] name = RSC diff --git a/api/.ruff.toml b/api/.ruff.toml index 3301452ad9..b0947eb619 100644 --- a/api/.ruff.toml +++ b/api/.ruff.toml @@ -100,7 +100,7 @@ ignore = [ "configs/*" = [ "N802", # invalid-function-name ] -"core/model_runtime/callbacks/base_callback.py" = ["T201"] +"dify_graph/model_runtime/callbacks/base_callback.py" = ["T201"] "core/workflow/callbacks/workflow_logging_callback.py" = ["T201"] "libs/gmpy2_pkcs10aep_cipher.py" = [ "N803", # invalid-argument-name diff --git a/api/controllers/console/app/audio.py b/api/controllers/console/app/audio.py index 941db325bf..2c5e8d29ee 100644 --- a/api/controllers/console/app/audio.py +++ b/api/controllers/console/app/audio.py @@ -22,7 +22,7 @@ from controllers.console.app.error import ( from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from libs.login import login_required from models import App, AppMode from services.audio_service import AudioService diff --git a/api/controllers/console/app/completion.py b/api/controllers/console/app/completion.py index 2922121a54..4d7ddfea13 100644 --- a/api/controllers/console/app/completion.py +++ b/api/controllers/console/app/completion.py @@ -26,7 +26,7 @@ from core.errors.error import ( QuotaExceededError, ) from core.helper.trace_id_helper import get_external_trace_id -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from libs import helper from libs.helper import uuid_value from libs.login import current_user, login_required diff --git a/api/controllers/console/app/generator.py b/api/controllers/console/app/generator.py index 1ac55b5e8d..af4ac450bb 100644 --- a/api/controllers/console/app/generator.py +++ b/api/controllers/console/app/generator.py @@ -18,7 +18,7 @@ from core.helper.code_executor.javascript.javascript_code_provider import Javasc from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider from core.llm_generator.entities import RuleCodeGeneratePayload, RuleGeneratePayload, RuleStructuredOutputPayload from core.llm_generator.llm_generator import LLMGenerator -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_database import db from libs.login import current_account_with_tenant, login_required from models import App diff --git a/api/controllers/console/app/message.py b/api/controllers/console/app/message.py index 0bea777870..3beea2a385 100644 --- a/api/controllers/console/app/message.py +++ b/api/controllers/console/app/message.py @@ -24,7 +24,7 @@ from controllers.console.wraps import ( ) from core.app.entities.app_invoke_entities import InvokeFrom from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_database import db from fields.raws import FilesContainedField from libs.helper import TimestampField, uuid_value diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index 735616bb6b..9759e0815a 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -21,7 +21,6 @@ from core.app.apps.base_app_queue_manager import AppQueueManager from core.app.apps.workflow.app_generator import SKIP_PREPARE_USER_INPUTS_KEY from core.app.entities.app_invoke_entities import InvokeFrom from core.helper.trace_id_helper import get_external_trace_id -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.impl.exc import PluginInvokeError from core.trigger.debug.event_selectors import ( TriggerDebugEvent, @@ -32,6 +31,7 @@ from core.trigger.debug.event_selectors import ( from dify_graph.enums import NodeType from dify_graph.file.models import File from dify_graph.graph_engine.manager import GraphEngineManager +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from extensions.ext_redis import redis_client from factories import file_factory, variable_factory diff --git a/api/controllers/console/auth/oauth_server.py b/api/controllers/console/auth/oauth_server.py index 38ea5d2dae..6e59d4203c 100644 --- a/api/controllers/console/auth/oauth_server.py +++ b/api/controllers/console/auth/oauth_server.py @@ -8,7 +8,7 @@ from pydantic import BaseModel from werkzeug.exceptions import BadRequest, NotFound from controllers.console.wraps import account_initialization_required, setup_required -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from models import Account from models.model import OAuthProviderApp diff --git a/api/controllers/console/datasets/datasets.py b/api/controllers/console/datasets/datasets.py index 92a6eede8a..45def1ae62 100644 --- a/api/controllers/console/datasets/datasets.py +++ b/api/controllers/console/datasets/datasets.py @@ -25,12 +25,12 @@ from controllers.console.wraps import ( ) from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError from core.indexing_runner import IndexingRunner -from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager from core.rag.datasource.vdb.vector_type import VectorType from core.rag.extractor.entity.datasource_type import DatasourceType from core.rag.extractor.entity.extract_setting import ExtractSetting, NotionInfo, WebsiteInfo from core.rag.retrieval.retrieval_methods import RetrievalMethod +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from fields.app_fields import app_detail_kernel_fields, related_app_list from fields.dataset_fields import ( diff --git a/api/controllers/console/datasets/datasets_document.py b/api/controllers/console/datasets/datasets_document.py index bf097d374a..ee726bc470 100644 --- a/api/controllers/console/datasets/datasets_document.py +++ b/api/controllers/console/datasets/datasets_document.py @@ -24,11 +24,11 @@ from core.errors.error import ( ) from core.indexing_runner import IndexingRunner from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.plugin.impl.exc import PluginDaemonClientSideError from core.rag.extractor.entity.datasource_type import DatasourceType from core.rag.extractor.entity.extract_setting import ExtractSetting, NotionInfo, WebsiteInfo +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from extensions.ext_database import db from fields.dataset_fields import dataset_fields from fields.document_fields import ( diff --git a/api/controllers/console/datasets/datasets_segments.py b/api/controllers/console/datasets/datasets_segments.py index 23a668112d..3fd0f3b712 100644 --- a/api/controllers/console/datasets/datasets_segments.py +++ b/api/controllers/console/datasets/datasets_segments.py @@ -26,7 +26,7 @@ from controllers.console.wraps import ( ) from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from extensions.ext_redis import redis_client from fields.segment_fields import child_chunk_fields, segment_fields diff --git a/api/controllers/console/datasets/hit_testing_base.py b/api/controllers/console/datasets/hit_testing_base.py index db1a874437..99ff49d79d 100644 --- a/api/controllers/console/datasets/hit_testing_base.py +++ b/api/controllers/console/datasets/hit_testing_base.py @@ -19,7 +19,7 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from fields.hit_testing_fields import hit_testing_record_fields from libs.login import current_user from models.account import Account diff --git a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py index 1a47e226e5..a4498005d8 100644 --- a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py +++ b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py @@ -9,9 +9,9 @@ from configs import dify_config from controllers.common.schema import register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required -from core.model_runtime.errors.validate import CredentialsValidateFailedError -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.impl.oauth import OAuthHandler +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from models.provider_ids import DatasourceProviderID from services.datasource_provider_service import DatasourceProviderService diff --git a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py index 29b6b64b94..51cdcc0c7a 100644 --- a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py +++ b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py @@ -33,7 +33,7 @@ from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpErr from core.app.apps.base_app_queue_manager import AppQueueManager from core.app.apps.pipeline.pipeline_generator import PipelineGenerator from core.app.entities.app_invoke_entities import InvokeFrom -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from factories import variable_factory from libs import helper diff --git a/api/controllers/console/explore/audio.py b/api/controllers/console/explore/audio.py index 0311db1584..ffb9e5bb6e 100644 --- a/api/controllers/console/explore/audio.py +++ b/api/controllers/console/explore/audio.py @@ -19,7 +19,7 @@ from controllers.console.app.error import ( ) from controllers.console.explore.wraps import InstalledAppResource from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from services.audio_service import AudioService from services.errors.audio import ( AudioTooLargeServiceError, diff --git a/api/controllers/console/explore/completion.py b/api/controllers/console/explore/completion.py index a6e5b2822a..fcd52d2818 100644 --- a/api/controllers/console/explore/completion.py +++ b/api/controllers/console/explore/completion.py @@ -24,7 +24,7 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_database import db from libs import helper from libs.datetime_utils import naive_utc_now diff --git a/api/controllers/console/explore/message.py b/api/controllers/console/explore/message.py index 88487ac96f..53970dbd3b 100644 --- a/api/controllers/console/explore/message.py +++ b/api/controllers/console/explore/message.py @@ -21,7 +21,7 @@ from controllers.console.explore.error import ( from controllers.console.explore.wraps import InstalledAppResource from core.app.entities.app_invoke_entities import InvokeFrom from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from fields.conversation_fields import ResultResponse from fields.message_fields import MessageInfiniteScrollPagination, MessageListItem, SuggestedQuestionsResponse from libs import helper diff --git a/api/controllers/console/explore/trial.py b/api/controllers/console/explore/trial.py index 7771436641..25bb8ed7fe 100644 --- a/api/controllers/console/explore/trial.py +++ b/api/controllers/console/explore/trial.py @@ -41,8 +41,8 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError from dify_graph.graph_engine.manager import GraphEngineManager +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_database import db from extensions.ext_redis import redis_client from fields.app_fields import ( diff --git a/api/controllers/console/explore/workflow.py b/api/controllers/console/explore/workflow.py index 7e48e43b42..7801cee473 100644 --- a/api/controllers/console/explore/workflow.py +++ b/api/controllers/console/explore/workflow.py @@ -21,8 +21,8 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError from dify_graph.graph_engine.manager import GraphEngineManager +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_redis import redis_client from libs import helper from libs.login import current_account_with_tenant diff --git a/api/controllers/console/workspace/agent_providers.py b/api/controllers/console/workspace/agent_providers.py index 9527fe782e..e2b504751b 100644 --- a/api/controllers/console/workspace/agent_providers.py +++ b/api/controllers/console/workspace/agent_providers.py @@ -2,7 +2,7 @@ from flask_restx import Resource, fields from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, setup_required -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from services.agent_service import AgentService diff --git a/api/controllers/console/workspace/endpoint.py b/api/controllers/console/workspace/endpoint.py index 1897cbdca7..538c5fb561 100644 --- a/api/controllers/console/workspace/endpoint.py +++ b/api/controllers/console/workspace/endpoint.py @@ -7,8 +7,8 @@ from pydantic import BaseModel, Field from controllers.common.schema import register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.impl.exc import PluginPermissionDeniedError +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from services.plugin.endpoint_service import EndpointService diff --git a/api/controllers/console/workspace/load_balancing_config.py b/api/controllers/console/workspace/load_balancing_config.py index ccb60b1461..0a9e54de99 100644 --- a/api/controllers/console/workspace/load_balancing_config.py +++ b/api/controllers/console/workspace/load_balancing_config.py @@ -5,8 +5,8 @@ from werkzeug.exceptions import Forbidden from controllers.common.schema import register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, setup_required -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.validate import CredentialsValidateFailedError +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError from libs.login import current_account_with_tenant, login_required from models import TenantAccountRole from services.model_load_balancing_service import ModelLoadBalancingService diff --git a/api/controllers/console/workspace/model_providers.py b/api/controllers/console/workspace/model_providers.py index 7bada2fa12..db3b02ae94 100644 --- a/api/controllers/console/workspace/model_providers.py +++ b/api/controllers/console/workspace/model_providers.py @@ -7,9 +7,9 @@ from pydantic import BaseModel, Field, field_validator from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.validate import CredentialsValidateFailedError -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.helper import uuid_value from libs.login import current_account_with_tenant, login_required from services.billing_service import BillingService diff --git a/api/controllers/console/workspace/models.py b/api/controllers/console/workspace/models.py index 583e3e3057..d7eceb656c 100644 --- a/api/controllers/console/workspace/models.py +++ b/api/controllers/console/workspace/models.py @@ -8,9 +8,9 @@ from pydantic import BaseModel, Field, field_validator from controllers.common.schema import register_enum_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.validate import CredentialsValidateFailedError -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.helper import uuid_value from libs.login import current_account_with_tenant, login_required from services.model_load_balancing_service import ModelLoadBalancingService diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index d1485bc1c0..2f06f72f29 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -12,8 +12,8 @@ from controllers.common.schema import register_enum_models, register_schema_mode from controllers.console import console_ns from controllers.console.workspace import plugin_permission_required from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.impl.exc import PluginDaemonClientSideError +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from models.account import TenantPluginAutoUpgradeStrategy, TenantPluginPermission from services.plugin.plugin_auto_upgrade_service import PluginAutoUpgradeService diff --git a/api/controllers/console/workspace/tool_providers.py b/api/controllers/console/workspace/tool_providers.py index 5bfa895849..b38f05795a 100644 --- a/api/controllers/console/workspace/tool_providers.py +++ b/api/controllers/console/workspace/tool_providers.py @@ -23,10 +23,10 @@ from core.entities.mcp_provider import MCPAuthentication, MCPConfiguration from core.mcp.auth.auth_flow import auth, handle_callback from core.mcp.error import MCPAuthError, MCPError, MCPRefreshTokenError from core.mcp.mcp_client import MCPClient -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin_daemon import CredentialType from core.plugin.impl.oauth import OAuthHandler from core.tools.entities.tool_entities import ApiProviderSchemaType, WorkflowToolParameterConfiguration +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from libs.helper import alphanumeric, uuid_value from libs.login import current_account_with_tenant, login_required diff --git a/api/controllers/console/workspace/trigger_providers.py b/api/controllers/console/workspace/trigger_providers.py index 6b642af613..ad78d2a623 100644 --- a/api/controllers/console/workspace/trigger_providers.py +++ b/api/controllers/console/workspace/trigger_providers.py @@ -10,11 +10,11 @@ from werkzeug.exceptions import BadRequest, Forbidden from configs import dify_config from controllers.common.schema import register_schema_models from controllers.web.error import NotFoundError -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin_daemon import CredentialType from core.plugin.impl.oauth import OAuthHandler from core.trigger.entities.entities import SubscriptionBuilderUpdater from core.trigger.trigger_manager import TriggerManager +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from libs.login import current_user, login_required from models.account import Account diff --git a/api/controllers/inner_api/plugin/plugin.py b/api/controllers/inner_api/plugin/plugin.py index da1b40f2bd..9b8b3950e6 100644 --- a/api/controllers/inner_api/plugin/plugin.py +++ b/api/controllers/inner_api/plugin/plugin.py @@ -4,7 +4,6 @@ from controllers.console.wraps import setup_required from controllers.inner_api import inner_api_ns from controllers.inner_api.plugin.wraps import get_user_tenant, plugin_data from controllers.inner_api.wraps import plugin_inner_api_only -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.backwards_invocation.app import PluginAppBackwardsInvocation from core.plugin.backwards_invocation.base import BaseBackwardsInvocationResponse from core.plugin.backwards_invocation.encrypt import PluginEncrypter @@ -30,6 +29,7 @@ from core.plugin.entities.request import ( ) from core.tools.entities.tool_entities import ToolProviderType from dify_graph.file.helpers import get_signed_file_url_for_plugin +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from libs.helper import length_prefixed_response from models import Account, Tenant from models.model import EndUser diff --git a/api/controllers/service_api/app/audio.py b/api/controllers/service_api/app/audio.py index e383920460..38d292d0b9 100644 --- a/api/controllers/service_api/app/audio.py +++ b/api/controllers/service_api/app/audio.py @@ -21,7 +21,7 @@ from controllers.service_api.app.error import ( ) from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from models.model import App, EndUser from services.audio_service import AudioService from services.errors.audio import ( diff --git a/api/controllers/service_api/app/completion.py b/api/controllers/service_api/app/completion.py index 9d8431f066..98f09c44a1 100644 --- a/api/controllers/service_api/app/completion.py +++ b/api/controllers/service_api/app/completion.py @@ -28,7 +28,7 @@ from core.errors.error import ( QuotaExceededError, ) from core.helper.trace_id_helper import get_external_trace_id -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from libs import helper from libs.helper import UUIDStrOrEmpty from models.model import App, AppMode, EndUser diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index f58295099f..b2148f4fa1 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -27,9 +27,9 @@ from core.errors.error import ( QuotaExceededError, ) from core.helper.trace_id_helper import get_external_trace_id -from core.model_runtime.errors.invoke import InvokeError from dify_graph.enums import WorkflowExecutionStatus from dify_graph.graph_engine.manager import GraphEngineManager +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_database import db from extensions.ext_redis import redis_client from fields.workflow_app_log_fields import build_workflow_app_log_pagination_model diff --git a/api/controllers/service_api/dataset/dataset.py b/api/controllers/service_api/dataset/dataset.py index c06b81b775..83d07087ab 100644 --- a/api/controllers/service_api/dataset/dataset.py +++ b/api/controllers/service_api/dataset/dataset.py @@ -14,8 +14,8 @@ from controllers.service_api.wraps import ( DatasetApiResource, cloud_edition_billing_rate_limit_check, ) -from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelType from fields.dataset_fields import dataset_detail_fields from fields.tag_fields import DataSetTag from libs.login import current_user diff --git a/api/controllers/service_api/dataset/segment.py b/api/controllers/service_api/dataset/segment.py index 4eb4fed29a..2e3b7fd85e 100644 --- a/api/controllers/service_api/dataset/segment.py +++ b/api/controllers/service_api/dataset/segment.py @@ -17,7 +17,7 @@ from controllers.service_api.wraps import ( ) from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from fields.segment_fields import child_chunk_fields, segment_fields from libs.login import current_account_with_tenant diff --git a/api/controllers/service_api/workspace/models.py b/api/controllers/service_api/workspace/models.py index fffcb47bd4..35aed40a59 100644 --- a/api/controllers/service_api/workspace/models.py +++ b/api/controllers/service_api/workspace/models.py @@ -3,7 +3,7 @@ from flask_restx import Resource from controllers.service_api import service_api_ns from controllers.service_api.wraps import validate_dataset_token -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from services.model_provider_service import ModelProviderService diff --git a/api/controllers/web/audio.py b/api/controllers/web/audio.py index 15828cc208..2b8f752668 100644 --- a/api/controllers/web/audio.py +++ b/api/controllers/web/audio.py @@ -20,7 +20,7 @@ from controllers.web.error import ( ) from controllers.web.wraps import WebApiResource from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from libs.helper import uuid_value from models.model import App from services.audio_service import AudioService diff --git a/api/controllers/web/completion.py b/api/controllers/web/completion.py index a97d745471..8634c1f43c 100644 --- a/api/controllers/web/completion.py +++ b/api/controllers/web/completion.py @@ -25,7 +25,7 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from libs import helper from libs.helper import uuid_value from models.model import AppMode diff --git a/api/controllers/web/message.py b/api/controllers/web/message.py index 80035ba818..bbae1ce266 100644 --- a/api/controllers/web/message.py +++ b/api/controllers/web/message.py @@ -20,7 +20,7 @@ from controllers.web.error import ( from controllers.web.wraps import WebApiResource from core.app.entities.app_invoke_entities import InvokeFrom from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from fields.conversation_fields import ResultResponse from fields.message_fields import SuggestedQuestionsResponse, WebMessageInfiniteScrollPagination, WebMessageListItem from libs import helper diff --git a/api/controllers/web/workflow.py b/api/controllers/web/workflow.py index a4c1ba75eb..508d1a756a 100644 --- a/api/controllers/web/workflow.py +++ b/api/controllers/web/workflow.py @@ -22,8 +22,8 @@ from core.errors.error import ( ProviderTokenNotInitError, QuotaExceededError, ) -from core.model_runtime.errors.invoke import InvokeError from dify_graph.graph_engine.manager import GraphEngineManager +from dify_graph.model_runtime.errors.invoke import InvokeError from extensions.ext_redis import redis_client from libs import helper from models.model import App, AppMode, EndUser diff --git a/api/core/agent/base_agent_runner.py b/api/core/agent/base_agent_runner.py index 22e3843fec..4a8b5f3549 100644 --- a/api/core/agent/base_agent_runner.py +++ b/api/core/agent/base_agent_runner.py @@ -19,7 +19,15 @@ from core.callback_handler.agent_tool_callback_handler import DifyAgentCallbackH from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities import ( +from core.prompt.utils.extract_thread_messages import extract_thread_messages +from core.tools.__base.tool import Tool +from core.tools.entities.tool_entities import ( + ToolParameter, +) +from core.tools.tool_manager import ToolManager +from core.tools.utils.dataset_retriever_tool import DatasetRetrieverTool +from dify_graph.file import file_manager +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, LLMUsage, PromptMessage, @@ -29,17 +37,9 @@ from core.model_runtime.entities import ( ToolPromptMessage, UserPromptMessage, ) -from core.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes -from core.model_runtime.entities.model_entities import ModelFeature -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.prompt.utils.extract_thread_messages import extract_thread_messages -from core.tools.__base.tool import Tool -from core.tools.entities.tool_entities import ( - ToolParameter, -) -from core.tools.tool_manager import ToolManager -from core.tools.utils.dataset_retriever_tool import DatasetRetrieverTool -from dify_graph.file import file_manager +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes +from dify_graph.model_runtime.entities.model_entities import ModelFeature +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from extensions.ext_database import db from factories import file_factory from models.enums import CreatorUserRole diff --git a/api/core/agent/cot_agent_runner.py b/api/core/agent/cot_agent_runner.py index 511406afde..c6ecd5509b 100644 --- a/api/core/agent/cot_agent_runner.py +++ b/api/core/agent/cot_agent_runner.py @@ -9,19 +9,19 @@ from core.agent.entities import AgentScratchpadUnit from core.agent.output_parser.cot_output_parser import CotAgentOutputParser from core.app.apps.base_app_queue_manager import PublishFrom from core.app.entities.queue_entities import QueueAgentThoughtEvent, QueueMessageEndEvent, QueueMessageFileEvent -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage -from core.model_runtime.entities.message_entities import ( +from core.ops.ops_trace_manager import TraceQueueManager +from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform +from core.tools.__base.tool import Tool +from core.tools.entities.tool_entities import ToolInvokeMeta +from core.tools.tool_engine import ToolEngine +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, PromptMessageTool, ToolPromptMessage, UserPromptMessage, ) -from core.ops.ops_trace_manager import TraceQueueManager -from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform -from core.tools.__base.tool import Tool -from core.tools.entities.tool_entities import ToolInvokeMeta -from core.tools.tool_engine import ToolEngine from dify_graph.nodes.agent.exc import AgentMaxIterationError from models.model import Message diff --git a/api/core/agent/cot_chat_agent_runner.py b/api/core/agent/cot_chat_agent_runner.py index b0a0b23fb5..89451a0498 100644 --- a/api/core/agent/cot_chat_agent_runner.py +++ b/api/core/agent/cot_chat_agent_runner.py @@ -1,16 +1,16 @@ import json from core.agent.cot_agent_runner import CotAgentRunner -from core.model_runtime.entities import ( +from dify_graph.file import file_manager +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, PromptMessage, SystemPromptMessage, TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes -from core.model_runtime.utils.encoders import jsonable_encoder -from dify_graph.file import file_manager +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes +from dify_graph.model_runtime.utils.encoders import jsonable_encoder class CotChatAgentRunner(CotAgentRunner): diff --git a/api/core/agent/cot_completion_agent_runner.py b/api/core/agent/cot_completion_agent_runner.py index da9a001d84..3023b9bc4d 100644 --- a/api/core/agent/cot_completion_agent_runner.py +++ b/api/core/agent/cot_completion_agent_runner.py @@ -1,13 +1,13 @@ import json from core.agent.cot_agent_runner import CotAgentRunner -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder class CotCompletionAgentRunner(CotAgentRunner): diff --git a/api/core/agent/fc_agent_runner.py b/api/core/agent/fc_agent_runner.py index 23650cc21e..3271fe319b 100644 --- a/api/core/agent/fc_agent_runner.py +++ b/api/core/agent/fc_agent_runner.py @@ -7,7 +7,11 @@ from typing import Any, Union from core.agent.base_agent_runner import BaseAgentRunner from core.app.apps.base_app_queue_manager import PublishFrom from core.app.entities.queue_entities import QueueAgentThoughtEvent, QueueMessageEndEvent, QueueMessageFileEvent -from core.model_runtime.entities import ( +from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform +from core.tools.entities.tool_entities import ToolInvokeMeta +from core.tools.tool_engine import ToolEngine +from dify_graph.file import file_manager +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, LLMResult, LLMResultChunk, @@ -20,11 +24,7 @@ from core.model_runtime.entities import ( ToolPromptMessage, UserPromptMessage, ) -from core.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes -from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform -from core.tools.entities.tool_entities import ToolInvokeMeta -from core.tools.tool_engine import ToolEngine -from dify_graph.file import file_manager +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes from dify_graph.nodes.agent.exc import AgentMaxIterationError from models.model import Message diff --git a/api/core/agent/output_parser/cot_output_parser.py b/api/core/agent/output_parser/cot_output_parser.py index 7c8f09e6b9..82676f1ebd 100644 --- a/api/core/agent/output_parser/cot_output_parser.py +++ b/api/core/agent/output_parser/cot_output_parser.py @@ -4,7 +4,7 @@ from collections.abc import Generator from typing import Union from core.agent.entities import AgentScratchpadUnit -from core.model_runtime.entities.llm_entities import LLMResultChunk +from dify_graph.model_runtime.entities.llm_entities import LLMResultChunk class CotAgentOutputParser: diff --git a/api/core/app/app_config/easy_ui_based_app/model_config/converter.py b/api/core/app/app_config/easy_ui_based_app/model_config/converter.py index b816c8d7d0..558b6e69a0 100644 --- a/api/core/app/app_config/easy_ui_based_app/model_config/converter.py +++ b/api/core/app/app_config/easy_ui_based_app/model_config/converter.py @@ -4,10 +4,10 @@ from core.app.app_config.entities import EasyUIBasedAppConfig from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.entities.model_entities import ModelStatus from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel class ModelConfigConverter: diff --git a/api/core/app/app_config/easy_ui_based_app/model_config/manager.py b/api/core/app/app_config/easy_ui_based_app/model_config/manager.py index c391a279b5..e4e750c735 100644 --- a/api/core/app/app_config/easy_ui_based_app/model_config/manager.py +++ b/api/core/app/app_config/easy_ui_based_app/model_config/manager.py @@ -2,9 +2,9 @@ from collections.abc import Mapping from typing import Any from core.app.app_config.entities import ModelConfigEntity -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from models.provider_ids import ModelProviderID diff --git a/api/core/app/app_config/easy_ui_based_app/prompt_template/manager.py b/api/core/app/app_config/easy_ui_based_app/prompt_template/manager.py index 21614c010c..01b9601965 100644 --- a/api/core/app/app_config/easy_ui_based_app/prompt_template/manager.py +++ b/api/core/app/app_config/easy_ui_based_app/prompt_template/manager.py @@ -4,8 +4,8 @@ from core.app.app_config.entities import ( AdvancedCompletionPromptTemplateEntity, PromptTemplateEntity, ) -from core.model_runtime.entities.message_entities import PromptMessageRole from core.prompt.simple_prompt_transform import ModelMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from models.model import AppMode diff --git a/api/core/app/app_config/entities.py b/api/core/app/app_config/entities.py index b5de73dadd..f26351d93e 100644 --- a/api/core/app/app_config/entities.py +++ b/api/core/app/app_config/entities.py @@ -4,9 +4,9 @@ from typing import Any, Literal from pydantic import BaseModel, Field -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.file import FileUploadConfig +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.variables.input_entities import VariableEntity as WorkflowVariableEntity from models.model import AppMode diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index ccac77eeaa..05ae1a4d38 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -31,11 +31,11 @@ from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, from core.app.entities.task_entities import ChatbotAppBlockingResponse, ChatbotAppStreamResponse from core.app.layers.pause_state_persist_layer import PauseStateLayerConfig, PauseStatePersistenceLayer from core.helper.trace_id_helper import extract_external_trace_id_from_args -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.prompt.utils.get_thread_messages_length import get_thread_messages_length from core.repositories import DifyCoreRepositoryFactory from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from dify_graph.repositories.draft_variable_repository import ( DraftVariableSaverFactory, ) diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index c19a1e9c0d..f57a0d9b3b 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -63,12 +63,12 @@ from core.app.entities.task_entities import ( from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline from core.app.task_pipeline.message_cycle_manager import MessageCycleManager from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk -from core.model_runtime.entities.llm_entities import LLMUsage -from core.model_runtime.utils.encoders import jsonable_encoder from core.ops.ops_trace_manager import TraceQueueManager from core.repositories.human_input_repository import HumanInputFormRepositoryImpl from dify_graph.entities.pause_reason import HumanInputRequired from dify_graph.enums import WorkflowExecutionStatus +from dify_graph.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.nodes import NodeType from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory from dify_graph.runtime import GraphRuntimeState diff --git a/api/core/app/apps/agent_chat/app_generator.py b/api/core/app/apps/agent_chat/app_generator.py index 7bd3b8a56e..76a067d7b6 100644 --- a/api/core/app/apps/agent_chat/app_generator.py +++ b/api/core/app/apps/agent_chat/app_generator.py @@ -20,8 +20,8 @@ from core.app.apps.exc import GenerateTaskStoppedError from core.app.apps.message_based_app_generator import MessageBasedAppGenerator from core.app.apps.message_based_app_queue_manager import MessageBasedAppQueueManager from core.app.entities.app_invoke_entities import AgentChatAppGenerateEntity, InvokeFrom -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from extensions.ext_database import db from factories import file_factory from libs.flask_utils import preserve_flask_contexts diff --git a/api/core/app/apps/agent_chat/app_runner.py b/api/core/app/apps/agent_chat/app_runner.py index 7309113f27..a81da2e91c 100644 --- a/api/core/app/apps/agent_chat/app_runner.py +++ b/api/core/app/apps/agent_chat/app_runner.py @@ -14,10 +14,10 @@ from core.app.entities.app_invoke_entities import AgentChatAppGenerateEntity from core.app.entities.queue_entities import QueueAnnotationReplyEvent from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.moderation.base import ModerationError +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from extensions.ext_database import db from models.model import App, Conversation, Message diff --git a/api/core/app/apps/base_app_generate_response_converter.py b/api/core/app/apps/base_app_generate_response_converter.py index d1e2f16b6f..77950a832a 100644 --- a/api/core/app/apps/base_app_generate_response_converter.py +++ b/api/core/app/apps/base_app_generate_response_converter.py @@ -6,7 +6,7 @@ from typing import Any, Union from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.task_entities import AppBlockingResponse, AppStreamResponse from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError logger = logging.getLogger(__name__) diff --git a/api/core/app/apps/base_app_runner.py b/api/core/app/apps/base_app_runner.py index 0223d8f9a7..88714f3837 100644 --- a/api/core/app/apps/base_app_runner.py +++ b/api/core/app/apps/base_app_runner.py @@ -24,21 +24,21 @@ from core.app.features.hosting_moderation.hosting_moderation import HostingModer from core.external_data_tool.external_data_fetch import ExternalDataFetch from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage -from core.model_runtime.entities.message_entities import ( - AssistantPromptMessage, - ImagePromptMessageContent, - PromptMessage, - TextPromptMessageContent, -) -from core.model_runtime.entities.model_entities import ModelPropertyKey -from core.model_runtime.errors.invoke import InvokeBadRequestError from core.moderation.input_moderation import InputModeration from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig from core.prompt.simple_prompt_transform import ModelMode, SimplePromptTransform from core.tools.tool_file_manager import ToolFileManager from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( + AssistantPromptMessage, + ImagePromptMessageContent, + PromptMessage, + TextPromptMessageContent, +) +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey +from dify_graph.model_runtime.errors.invoke import InvokeBadRequestError from extensions.ext_database import db from models.enums import CreatorUserRole from models.model import App, AppMode, Message, MessageAnnotation, MessageFile diff --git a/api/core/app/apps/chat/app_generator.py b/api/core/app/apps/chat/app_generator.py index c1251d2feb..91cf54c774 100644 --- a/api/core/app/apps/chat/app_generator.py +++ b/api/core/app/apps/chat/app_generator.py @@ -19,8 +19,8 @@ from core.app.apps.exc import GenerateTaskStoppedError from core.app.apps.message_based_app_generator import MessageBasedAppGenerator from core.app.apps.message_based_app_queue_manager import MessageBasedAppQueueManager from core.app.entities.app_invoke_entities import ChatAppGenerateEntity, InvokeFrom -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from extensions.ext_database import db from factories import file_factory from models import Account diff --git a/api/core/app/apps/chat/app_runner.py b/api/core/app/apps/chat/app_runner.py index 5cf13fbb17..23546a47bb 100644 --- a/api/core/app/apps/chat/app_runner.py +++ b/api/core/app/apps/chat/app_runner.py @@ -13,10 +13,10 @@ from core.app.entities.queue_entities import QueueAnnotationReplyEvent from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities.message_entities import ImagePromptMessageContent from core.moderation.base import ModerationError from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from dify_graph.file import File +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent from extensions.ext_database import db from models.model import App, Conversation, Message diff --git a/api/core/app/apps/completion/app_generator.py b/api/core/app/apps/completion/app_generator.py index 843328f904..e8b0e4f179 100644 --- a/api/core/app/apps/completion/app_generator.py +++ b/api/core/app/apps/completion/app_generator.py @@ -19,8 +19,8 @@ from core.app.apps.exc import GenerateTaskStoppedError from core.app.apps.message_based_app_generator import MessageBasedAppGenerator from core.app.apps.message_based_app_queue_manager import MessageBasedAppQueueManager from core.app.entities.app_invoke_entities import CompletionAppGenerateEntity, InvokeFrom -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from extensions.ext_database import db from factories import file_factory from models import Account, App, EndUser, Message diff --git a/api/core/app/apps/completion/app_runner.py b/api/core/app/apps/completion/app_runner.py index 96bbe532f1..ac05172945 100644 --- a/api/core/app/apps/completion/app_runner.py +++ b/api/core/app/apps/completion/app_runner.py @@ -11,10 +11,10 @@ from core.app.entities.app_invoke_entities import ( ) from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler from core.model_manager import ModelInstance -from core.model_runtime.entities.message_entities import ImagePromptMessageContent from core.moderation.base import ModerationError from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from dify_graph.file import File +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent from extensions.ext_database import db from models.model import App, Message diff --git a/api/core/app/apps/pipeline/pipeline_generator.py b/api/core/app/apps/pipeline/pipeline_generator.py index 6be2d034b5..dcfc1415e8 100644 --- a/api/core/app/apps/pipeline/pipeline_generator.py +++ b/api/core/app/apps/pipeline/pipeline_generator.py @@ -33,9 +33,9 @@ from core.datasource.entities.datasource_entities import ( ) from core.datasource.online_drive.online_drive_plugin import OnlineDriveDatasourcePlugin from core.entities.knowledge_entities import PipelineDataset, PipelineDocument -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.rag.index_processor.constant.built_in_field import BuiltInField from core.repositories.factory import DifyCoreRepositoryFactory +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index 4eee00c999..32a7a3ccec 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -28,10 +28,10 @@ from core.app.entities.task_entities import WorkflowAppBlockingResponse, Workflo from core.app.layers.pause_state_persist_layer import PauseStateLayerConfig, PauseStatePersistenceLayer from core.db.session_factory import session_factory from core.helper.trace_id_helper import extract_external_trace_id_from_args -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.repositories import DifyCoreRepositoryFactory from dify_graph.graph_engine.layers.base import GraphEngineLayer +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError from dify_graph.repositories.draft_variable_repository import DraftVariableSaverFactory from dify_graph.repositories.workflow_execution_repository import WorkflowExecutionRepository from dify_graph.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository diff --git a/api/core/app/entities/app_invoke_entities.py b/api/core/app/entities/app_invoke_entities.py index df906e5e54..7fe6e0c72c 100644 --- a/api/core/app/entities/app_invoke_entities.py +++ b/api/core/app/entities/app_invoke_entities.py @@ -7,8 +7,8 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationInfo, field_validat from constants import UUID_NIL from core.app.app_config.entities import EasyUIBasedAppConfig, WorkflowUIBasedAppConfig from core.entities.provider_configuration import ProviderModelBundle -from core.model_runtime.entities.model_entities import AIModelEntity from dify_graph.file import File, FileUploadConfig +from dify_graph.model_runtime.entities.model_entities import AIModelEntity if TYPE_CHECKING: from core.ops.ops_trace_manager import TraceQueueManager diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index de19b8e6d2..d42df0d1bf 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -5,12 +5,12 @@ from typing import Any from pydantic import BaseModel, ConfigDict, Field -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk from core.rag.entities.citation_metadata import RetrievalSourceMetadata from dify_graph.entities import AgentNodeStrategyInit from dify_graph.entities.pause_reason import PauseReason from dify_graph.entities.workflow_start_reason import WorkflowStartReason from dify_graph.enums import WorkflowNodeExecutionMetadataKey +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk from dify_graph.nodes import NodeType diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index 1f3153fff4..b58dae0ff2 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -4,11 +4,11 @@ from typing import Any from pydantic import BaseModel, ConfigDict, Field -from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage from core.rag.entities.citation_metadata import RetrievalSourceMetadata from dify_graph.entities import AgentNodeStrategyInit from dify_graph.entities.workflow_start_reason import WorkflowStartReason from dify_graph.enums import WorkflowExecutionStatus, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage from dify_graph.nodes.human_input.entities import FormInput, UserAction diff --git a/api/core/app/features/hosting_moderation/hosting_moderation.py b/api/core/app/features/hosting_moderation/hosting_moderation.py index a5a5486581..5ed1fadc41 100644 --- a/api/core/app/features/hosting_moderation/hosting_moderation.py +++ b/api/core/app/features/hosting_moderation/hosting_moderation.py @@ -2,7 +2,7 @@ import logging from core.app.entities.app_invoke_entities import EasyUIBasedAppGenerateEntity from core.helper import moderation -from core.model_runtime.entities.message_entities import PromptMessage +from dify_graph.model_runtime.entities.message_entities import PromptMessage logger = logging.getLogger(__name__) diff --git a/api/core/app/llm/model_access.py b/api/core/app/llm/model_access.py index dc28225b8e..a63ff39fa5 100644 --- a/api/core/app/llm/model_access.py +++ b/api/core/app/llm/model_access.py @@ -5,8 +5,8 @@ from typing import Any from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.errors.error import ProviderTokenNotInitError from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelType from dify_graph.nodes.llm.entities import ModelConfig from dify_graph.nodes.llm.exc import LLMModeRequiredError, ModelNotExistError from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory diff --git a/api/core/app/llm/quota.py b/api/core/app/llm/quota.py index 1c66c8c1ff..7aa3bf15ab 100644 --- a/api/core/app/llm/quota.py +++ b/api/core/app/llm/quota.py @@ -6,7 +6,7 @@ from core.entities.model_entities import ModelStatus from core.entities.provider_entities import ProviderQuotaType, QuotaUnit from core.errors.error import QuotaExceededError from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from extensions.ext_database import db from libs.datetime_utils import naive_utc_now from models.provider import Provider, ProviderType diff --git a/api/core/app/task_pipeline/based_generate_task_pipeline.py b/api/core/app/task_pipeline/based_generate_task_pipeline.py index 26c7e60a4c..0d5e0acec6 100644 --- a/api/core/app/task_pipeline/based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/based_generate_task_pipeline.py @@ -16,8 +16,8 @@ from core.app.entities.task_entities import ( PingStreamResponse, ) from core.errors.error import QuotaExceededError -from core.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeError from core.moderation.output_moderation import ModerationRule, OutputModeration +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeError from models.enums import MessageStatus from models.model import Message diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index d7946d5478..1fa782eb6c 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -46,12 +46,6 @@ from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTas from core.app.task_pipeline.message_cycle_manager import MessageCycleManager from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage -from core.model_runtime.entities.message_entities import ( - AssistantPromptMessage, - TextPromptMessageContent, -) -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.prompt.utils.prompt_message_util import PromptMessageUtil @@ -59,6 +53,12 @@ from core.prompt.utils.prompt_template_parser import PromptTemplateParser from core.tools.signature import sign_tool_file from dify_graph.file import helpers as file_helpers from dify_graph.file.enums import FileTransferMethod +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( + AssistantPromptMessage, + TextPromptMessageContent, +) +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from events.message_event import message_was_created from extensions.ext_database import db from libs.datetime_utils import naive_utc_now diff --git a/api/core/base/tts/app_generator_tts_publisher.py b/api/core/base/tts/app_generator_tts_publisher.py index f83aaa0006..beda515666 100644 --- a/api/core/base/tts/app_generator_tts_publisher.py +++ b/api/core/base/tts/app_generator_tts_publisher.py @@ -15,8 +15,8 @@ from core.app.entities.queue_entities import ( WorkflowQueueMessage, ) from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.message_entities import TextPromptMessageContent -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.message_entities import TextPromptMessageContent +from dify_graph.model_runtime.entities.model_entities import ModelType class AudioTrunk: diff --git a/api/core/datasource/entities/api_entities.py b/api/core/datasource/entities/api_entities.py index 1179537570..4c9ff64479 100644 --- a/api/core/datasource/entities/api_entities.py +++ b/api/core/datasource/entities/api_entities.py @@ -3,8 +3,8 @@ from typing import Literal, Optional from pydantic import BaseModel, Field, field_validator from core.datasource.entities.datasource_entities import DatasourceParameter -from core.model_runtime.utils.encoders import jsonable_encoder from core.tools.entities.common_entities import I18nObject +from dify_graph.model_runtime.utils.encoders import jsonable_encoder class DatasourceApiEntity(BaseModel): diff --git a/api/core/entities/model_entities.py b/api/core/entities/model_entities.py index a123fb0321..3427fc54b1 100644 --- a/api/core/entities/model_entities.py +++ b/api/core/entities/model_entities.py @@ -3,9 +3,9 @@ from enum import StrEnum, auto from pydantic import BaseModel, ConfigDict -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.model_entities import ModelType, ProviderModel -from core.model_runtime.entities.provider_entities import ProviderEntity +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import ModelType, ProviderModel +from dify_graph.model_runtime.entities.provider_entities import ProviderEntity class ModelStatus(StrEnum): diff --git a/api/core/entities/provider_configuration.py b/api/core/entities/provider_configuration.py index 8a26b2e91b..9f8d06e322 100644 --- a/api/core/entities/provider_configuration.py +++ b/api/core/entities/provider_configuration.py @@ -19,15 +19,15 @@ from core.entities.provider_entities import ( ) from core.helper import encrypter from core.helper.model_provider_cache import ProviderCredentialsCache, ProviderCredentialsCacheType -from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType -from core.model_runtime.entities.provider_entities import ( +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType +from dify_graph.model_runtime.entities.provider_entities import ( ConfigurateMethod, CredentialFormSchema, FormType, ProviderEntity, ) -from core.model_runtime.model_providers.__base.ai_model import AIModel -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from libs.datetime_utils import naive_utc_now from models.engine import db from models.provider import ( diff --git a/api/core/entities/provider_entities.py b/api/core/entities/provider_entities.py index 0078ec7e4f..a830f227a9 100644 --- a/api/core/entities/provider_entities.py +++ b/api/core/entities/provider_entities.py @@ -11,8 +11,8 @@ from core.entities.parameter_entities import ( ModelSelectorScope, ToolSelectorScope, ) -from core.model_runtime.entities.model_entities import ModelType from core.tools.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import ModelType class ProviderQuotaType(StrEnum): diff --git a/api/core/helper/moderation.py b/api/core/helper/moderation.py index 86bac4119a..873f6a4093 100644 --- a/api/core/helper/moderation.py +++ b/api/core/helper/moderation.py @@ -4,10 +4,10 @@ from typing import cast from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.entities import DEFAULT_PLUGIN_ID -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.invoke import InvokeBadRequestError -from core.model_runtime.model_providers.__base.moderation_model import ModerationModel -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.invoke import InvokeBadRequestError +from dify_graph.model_runtime.model_providers.__base.moderation_model import ModerationModel +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from extensions.ext_hosting_provider import hosting_configuration from models.provider import ProviderType diff --git a/api/core/hosting_configuration.py b/api/core/hosting_configuration.py index 370e64e385..600a444357 100644 --- a/api/core/hosting_configuration.py +++ b/api/core/hosting_configuration.py @@ -4,7 +4,7 @@ from pydantic import BaseModel from configs import dify_config from core.entities import DEFAULT_PLUGIN_ID from core.entities.provider_entities import ProviderQuotaType, QuotaUnit, RestrictModel -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType class HostingQuota(BaseModel): diff --git a/api/core/indexing_runner.py b/api/core/indexing_runner.py index 4e3ad7bb75..7eebd9ec95 100644 --- a/api/core/indexing_runner.py +++ b/api/core/indexing_runner.py @@ -15,7 +15,6 @@ from configs import dify_config from core.entities.knowledge_entities import IndexingEstimate, PreviewDetail, QAPreviewDetail from core.errors.error import ProviderTokenNotInitError from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.cleaner.clean_processor import CleanProcessor from core.rag.datasource.keyword.keyword_factory import Keyword from core.rag.docstore.dataset_docstore import DatasetDocumentStore @@ -31,6 +30,7 @@ from core.rag.splitter.fixed_text_splitter import ( ) from core.rag.splitter.text_splitter import TextSplitter from core.tools.utils.web_reader_tool import get_image_upload_file_ids +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from extensions.ext_redis import redis_client from extensions.ext_storage import storage diff --git a/api/core/llm_generator/llm_generator.py b/api/core/llm_generator/llm_generator.py index b16a42e390..6a09dbff35 100644 --- a/api/core/llm_generator/llm_generator.py +++ b/api/core/llm_generator/llm_generator.py @@ -23,15 +23,15 @@ from core.llm_generator.prompts import ( WORKFLOW_RULE_CONFIG_PROMPT_GENERATE_TEMPLATE, ) from core.model_manager import ModelManager -from core.model_runtime.entities.llm_entities import LLMResult -from core.model_runtime.entities.message_entities import PromptMessage, SystemPromptMessage, UserPromptMessage -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeError from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.ops.utils import measure_time from core.prompt.utils.prompt_template_parser import PromptTemplateParser from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey +from dify_graph.model_runtime.entities.llm_entities import LLMResult +from dify_graph.model_runtime.entities.message_entities import PromptMessage, SystemPromptMessage, UserPromptMessage +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeError from extensions.ext_database import db from extensions.ext_storage import storage from models import App, Message, WorkflowNodeExecutionModel diff --git a/api/core/llm_generator/output_parser/structured_output.py b/api/core/llm_generator/output_parser/structured_output.py index 686529c3ca..77ea1713ea 100644 --- a/api/core/llm_generator/output_parser/structured_output.py +++ b/api/core/llm_generator/output_parser/structured_output.py @@ -10,22 +10,22 @@ from pydantic import TypeAdapter, ValidationError from core.llm_generator.output_parser.errors import OutputParserError from core.llm_generator.prompts import STRUCTURED_OUTPUT_PROMPT from core.model_manager import ModelInstance -from core.model_runtime.callbacks.base_callback import Callback -from core.model_runtime.entities.llm_entities import ( +from dify_graph.model_runtime.callbacks.base_callback import Callback +from dify_graph.model_runtime.entities.llm_entities import ( LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMResultChunkWithStructuredOutput, LLMResultWithStructuredOutput, ) -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, PromptMessageTool, SystemPromptMessage, TextPromptMessageContent, ) -from core.model_runtime.entities.model_entities import AIModelEntity, ParameterRule +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ParameterRule class ResponseFormat(StrEnum): diff --git a/api/core/mcp/utils.py b/api/core/mcp/utils.py index 84bef7b935..db9cb726d7 100644 --- a/api/core/mcp/utils.py +++ b/api/core/mcp/utils.py @@ -8,7 +8,7 @@ from httpx_sse import connect_sse from configs import dify_config from core.mcp.types import ErrorData, JSONRPCError -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder HTTP_REQUEST_NODE_SSL_VERIFY = dify_config.HTTP_REQUEST_NODE_SSL_VERIFY diff --git a/api/core/memory/token_buffer_memory.py b/api/core/memory/token_buffer_memory.py index 2e93681da0..1156a98af1 100644 --- a/api/core/memory/token_buffer_memory.py +++ b/api/core/memory/token_buffer_memory.py @@ -5,7 +5,9 @@ from sqlalchemy.orm import sessionmaker from core.app.app_config.features.file_upload.manager import FileUploadConfigManager from core.model_manager import ModelInstance -from core.model_runtime.entities import ( +from core.prompt.utils.extract_thread_messages import extract_thread_messages +from dify_graph.file import file_manager +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, ImagePromptMessageContent, PromptMessage, @@ -13,9 +15,7 @@ from core.model_runtime.entities import ( TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.entities.message_entities import PromptMessageContentUnionTypes -from core.prompt.utils.extract_thread_messages import extract_thread_messages -from dify_graph.file import file_manager +from dify_graph.model_runtime.entities.message_entities import PromptMessageContentUnionTypes from extensions.ext_database import db from factories import file_factory from models.model import AppMode, Conversation, Message, MessageFile diff --git a/api/core/model_manager.py b/api/core/model_manager.py index 2b3a3be1b9..0f710a8fcf 100644 --- a/api/core/model_manager.py +++ b/api/core/model_manager.py @@ -7,20 +7,20 @@ from core.entities.embedding_type import EmbeddingInputType from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle from core.entities.provider_entities import ModelLoadBalancingConfiguration from core.errors.error import ProviderTokenNotInitError -from core.model_runtime.callbacks.base_callback import Callback -from core.model_runtime.entities.llm_entities import LLMResult -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool -from core.model_runtime.entities.model_entities import ModelFeature, ModelType -from core.model_runtime.entities.rerank_entities import RerankResult -from core.model_runtime.entities.text_embedding_entities import EmbeddingResult -from core.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeConnectionError, InvokeRateLimitError -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.model_runtime.model_providers.__base.moderation_model import ModerationModel -from core.model_runtime.model_providers.__base.rerank_model import RerankModel -from core.model_runtime.model_providers.__base.speech2text_model import Speech2TextModel -from core.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel -from core.model_runtime.model_providers.__base.tts_model import TTSModel from core.provider_manager import ProviderManager +from dify_graph.model_runtime.callbacks.base_callback import Callback +from dify_graph.model_runtime.entities.llm_entities import LLMResult +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelType +from dify_graph.model_runtime.entities.rerank_entities import RerankResult +from dify_graph.model_runtime.entities.text_embedding_entities import EmbeddingResult +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeConnectionError, InvokeRateLimitError +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel +from dify_graph.model_runtime.model_providers.__base.moderation_model import ModerationModel +from dify_graph.model_runtime.model_providers.__base.rerank_model import RerankModel +from dify_graph.model_runtime.model_providers.__base.speech2text_model import Speech2TextModel +from dify_graph.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel +from dify_graph.model_runtime.model_providers.__base.tts_model import TTSModel from extensions.ext_redis import redis_client from models.provider import ProviderType from services.enterprise.plugin_manager_service import PluginCredentialType diff --git a/api/core/moderation/openai_moderation/openai_moderation.py b/api/core/moderation/openai_moderation/openai_moderation.py index 5cab4841f5..06676f5cf4 100644 --- a/api/core/moderation/openai_moderation/openai_moderation.py +++ b/api/core/moderation/openai_moderation/openai_moderation.py @@ -1,6 +1,6 @@ from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.moderation.base import Moderation, ModerationAction, ModerationInputsResult, ModerationOutputsResult +from dify_graph.model_runtime.entities.model_entities import ModelType class OpenAIModeration(Moderation): diff --git a/api/core/plugin/backwards_invocation/model.py b/api/core/plugin/backwards_invocation/model.py index 4ecc22834d..11c9191bac 100644 --- a/api/core/plugin/backwards_invocation/model.py +++ b/api/core/plugin/backwards_invocation/model.py @@ -5,18 +5,6 @@ from collections.abc import Generator from core.app.llm import deduct_llm_quota from core.llm_generator.output_parser.structured_output import invoke_llm_with_structured_output from core.model_manager import ModelManager -from core.model_runtime.entities.llm_entities import ( - LLMResult, - LLMResultChunk, - LLMResultChunkDelta, - LLMResultChunkWithStructuredOutput, - LLMResultWithStructuredOutput, -) -from core.model_runtime.entities.message_entities import ( - PromptMessage, - SystemPromptMessage, - UserPromptMessage, -) from core.plugin.backwards_invocation.base import BaseBackwardsInvocation from core.plugin.entities.request import ( RequestInvokeLLM, @@ -30,6 +18,18 @@ from core.plugin.entities.request import ( ) from core.tools.entities.tool_entities import ToolProviderType from core.tools.utils.model_invocation_utils import ModelInvocationUtils +from dify_graph.model_runtime.entities.llm_entities import ( + LLMResult, + LLMResultChunk, + LLMResultChunkDelta, + LLMResultChunkWithStructuredOutput, + LLMResultWithStructuredOutput, +) +from dify_graph.model_runtime.entities.message_entities import ( + PromptMessage, + SystemPromptMessage, + UserPromptMessage, +) from models.account import Tenant diff --git a/api/core/plugin/entities/marketplace.py b/api/core/plugin/entities/marketplace.py index cf1f7ff0dd..81e1e12c5f 100644 --- a/api/core/plugin/entities/marketplace.py +++ b/api/core/plugin/entities/marketplace.py @@ -1,10 +1,10 @@ from pydantic import BaseModel, Field, computed_field, model_validator -from core.model_runtime.entities.provider_entities import ProviderEntity from core.plugin.entities.endpoint import EndpointProviderDeclaration from core.plugin.entities.plugin import PluginResourceRequirements from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolProviderEntity +from dify_graph.model_runtime.entities.provider_entities import ProviderEntity class MarketplacePluginDeclaration(BaseModel): diff --git a/api/core/plugin/entities/plugin.py b/api/core/plugin/entities/plugin.py index 9e1a9edf82..7a3780f7de 100644 --- a/api/core/plugin/entities/plugin.py +++ b/api/core/plugin/entities/plugin.py @@ -8,12 +8,12 @@ from pydantic import BaseModel, Field, field_validator, model_validator from core.agent.plugin_entities import AgentStrategyProviderEntity from core.datasource.entities.datasource_entities import DatasourceProviderEntity -from core.model_runtime.entities.provider_entities import ProviderEntity from core.plugin.entities.base import BasePluginEntity from core.plugin.entities.endpoint import EndpointProviderDeclaration from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolProviderEntity from core.trigger.entities.entities import TriggerProviderEntity +from dify_graph.model_runtime.entities.provider_entities import ProviderEntity class PluginInstallationSource(StrEnum): diff --git a/api/core/plugin/entities/plugin_daemon.py b/api/core/plugin/entities/plugin_daemon.py index 6674228dc0..2dc540e6a8 100644 --- a/api/core/plugin/entities/plugin_daemon.py +++ b/api/core/plugin/entities/plugin_daemon.py @@ -10,14 +10,14 @@ from pydantic import BaseModel, ConfigDict, Field from core.agent.plugin_entities import AgentProviderEntityWithPlugin from core.datasource.entities.datasource_entities import DatasourceProviderEntityWithPlugin -from core.model_runtime.entities.model_entities import AIModelEntity -from core.model_runtime.entities.provider_entities import ProviderEntity from core.plugin.entities.base import BasePluginEntity from core.plugin.entities.parameters import PluginParameterOption from core.plugin.entities.plugin import PluginDeclaration, PluginEntity from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolProviderEntityWithPlugin from core.trigger.entities.entities import TriggerProviderEntity +from dify_graph.model_runtime.entities.model_entities import AIModelEntity +from dify_graph.model_runtime.entities.provider_entities import ProviderEntity T = TypeVar("T", bound=(BaseModel | dict | list | bool | str)) diff --git a/api/core/plugin/entities/request.py b/api/core/plugin/entities/request.py index 0a1dc50bfa..c15e9b0385 100644 --- a/api/core/plugin/entities/request.py +++ b/api/core/plugin/entities/request.py @@ -7,7 +7,8 @@ from flask import Response from pydantic import BaseModel, ConfigDict, Field, field_validator from core.entities.provider_entities import BasicProviderConfig -from core.model_runtime.entities.message_entities import ( +from core.plugin.utils.http_parser import deserialize_response +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, PromptMessageRole, @@ -16,8 +17,7 @@ from core.model_runtime.entities.message_entities import ( ToolPromptMessage, UserPromptMessage, ) -from core.model_runtime.entities.model_entities import ModelType -from core.plugin.utils.http_parser import deserialize_response +from dify_graph.model_runtime.entities.model_entities import ModelType from dify_graph.nodes.parameter_extractor.entities import ( ModelConfig as ParameterExtractorModelConfig, ) diff --git a/api/core/plugin/impl/base.py b/api/core/plugin/impl/base.py index 7a6a598a2f..737d204105 100644 --- a/api/core/plugin/impl/base.py +++ b/api/core/plugin/impl/base.py @@ -9,14 +9,6 @@ from pydantic import BaseModel from yarl import URL from configs import dify_config -from core.model_runtime.errors.invoke import ( - InvokeAuthorizationError, - InvokeBadRequestError, - InvokeConnectionError, - InvokeRateLimitError, - InvokeServerUnavailableError, -) -from core.model_runtime.errors.validate import CredentialsValidateFailedError from core.plugin.endpoint.exc import EndpointSetupFailedError from core.plugin.entities.plugin_daemon import PluginDaemonBasicResponse, PluginDaemonError, PluginDaemonInnerError from core.plugin.impl.exc import ( @@ -35,6 +27,14 @@ from core.trigger.errors import ( TriggerPluginInvokeError, TriggerProviderCredentialValidationError, ) +from dify_graph.model_runtime.errors.invoke import ( + InvokeAuthorizationError, + InvokeBadRequestError, + InvokeConnectionError, + InvokeRateLimitError, + InvokeServerUnavailableError, +) +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError plugin_daemon_inner_api_baseurl = URL(str(dify_config.PLUGIN_DAEMON_URL)) _plugin_daemon_timeout_config = cast( diff --git a/api/core/plugin/impl/model.py b/api/core/plugin/impl/model.py index 5d70980967..49ee5d79cb 100644 --- a/api/core/plugin/impl/model.py +++ b/api/core/plugin/impl/model.py @@ -2,12 +2,6 @@ import binascii from collections.abc import Generator, Sequence from typing import IO -from core.model_runtime.entities.llm_entities import LLMResultChunk -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool -from core.model_runtime.entities.model_entities import AIModelEntity -from core.model_runtime.entities.rerank_entities import RerankResult -from core.model_runtime.entities.text_embedding_entities import EmbeddingResult -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin_daemon import ( PluginBasicBooleanResponse, PluginDaemonInnerError, @@ -19,6 +13,12 @@ from core.plugin.entities.plugin_daemon import ( PluginVoicesResponse, ) from core.plugin.impl.base import BasePluginClient +from dify_graph.model_runtime.entities.llm_entities import LLMResultChunk +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool +from dify_graph.model_runtime.entities.model_entities import AIModelEntity +from dify_graph.model_runtime.entities.rerank_entities import RerankResult +from dify_graph.model_runtime.entities.text_embedding_entities import EmbeddingResult +from dify_graph.model_runtime.utils.encoders import jsonable_encoder class PluginModelClient(BasePluginClient): diff --git a/api/core/prompt/advanced_prompt_transform.py b/api/core/prompt/advanced_prompt_transform.py index 1883538dad..ce9f7e64b2 100644 --- a/api/core/prompt/advanced_prompt_transform.py +++ b/api/core/prompt/advanced_prompt_transform.py @@ -5,7 +5,12 @@ from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEnti from core.helper.code_executor.jinja2.jinja2_formatter import Jinja2Formatter from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities import ( +from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig +from core.prompt.prompt_transform import PromptTransform +from core.prompt.utils.prompt_template_parser import PromptTemplateParser +from dify_graph.file import file_manager +from dify_graph.file.models import File +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, PromptMessage, PromptMessageRole, @@ -13,12 +18,7 @@ from core.model_runtime.entities import ( TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes -from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig -from core.prompt.prompt_transform import PromptTransform -from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from dify_graph.file import file_manager -from dify_graph.file.models import File +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent, PromptMessageContentUnionTypes from dify_graph.runtime import VariablePool diff --git a/api/core/prompt/agent_history_prompt_transform.py b/api/core/prompt/agent_history_prompt_transform.py index c1ae47709f..d09a46bfde 100644 --- a/api/core/prompt/agent_history_prompt_transform.py +++ b/api/core/prompt/agent_history_prompt_transform.py @@ -4,13 +4,13 @@ from core.app.entities.app_invoke_entities import ( ModelConfigWithCredentialsEntity, ) from core.memory.token_buffer_memory import TokenBufferMemory -from core.model_runtime.entities.message_entities import ( +from core.prompt.prompt_transform import PromptTransform +from dify_graph.model_runtime.entities.message_entities import ( PromptMessage, SystemPromptMessage, UserPromptMessage, ) -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.prompt.prompt_transform import PromptTransform +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel class AgentHistoryPromptTransform(PromptTransform): diff --git a/api/core/prompt/entities/advanced_prompt_entities.py b/api/core/prompt/entities/advanced_prompt_entities.py index 7094633093..667f5ef099 100644 --- a/api/core/prompt/entities/advanced_prompt_entities.py +++ b/api/core/prompt/entities/advanced_prompt_entities.py @@ -2,7 +2,7 @@ from typing import Literal from pydantic import BaseModel -from core.model_runtime.entities.message_entities import PromptMessageRole +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole class ChatModelMessage(BaseModel): diff --git a/api/core/prompt/prompt_transform.py b/api/core/prompt/prompt_transform.py index 22ef5809bb..951736831f 100644 --- a/api/core/prompt/prompt_transform.py +++ b/api/core/prompt/prompt_transform.py @@ -3,9 +3,9 @@ from typing import Any from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities.message_entities import PromptMessage -from core.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey from core.prompt.entities.advanced_prompt_entities import MemoryConfig +from dify_graph.model_runtime.entities.message_entities import PromptMessage +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey class PromptTransform: diff --git a/api/core/prompt/simple_prompt_transform.py b/api/core/prompt/simple_prompt_transform.py index 53981eb1e1..10c44349ae 100644 --- a/api/core/prompt/simple_prompt_transform.py +++ b/api/core/prompt/simple_prompt_transform.py @@ -7,7 +7,11 @@ from typing import TYPE_CHECKING, Any, cast from core.app.app_config.entities import PromptTemplateEntity from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.memory.token_buffer_memory import TokenBufferMemory -from core.model_runtime.entities.message_entities import ( +from core.prompt.entities.advanced_prompt_entities import MemoryConfig +from core.prompt.prompt_transform import PromptTransform +from core.prompt.utils.prompt_template_parser import PromptTemplateParser +from dify_graph.file import file_manager +from dify_graph.model_runtime.entities.message_entities import ( ImagePromptMessageContent, PromptMessage, PromptMessageContentUnionTypes, @@ -15,10 +19,6 @@ from core.model_runtime.entities.message_entities import ( TextPromptMessageContent, UserPromptMessage, ) -from core.prompt.entities.advanced_prompt_entities import MemoryConfig -from core.prompt.prompt_transform import PromptTransform -from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from dify_graph.file import file_manager from models.model import AppMode if TYPE_CHECKING: diff --git a/api/core/prompt/utils/prompt_message_util.py b/api/core/prompt/utils/prompt_message_util.py index 0a7a467227..85a2201395 100644 --- a/api/core/prompt/utils/prompt_message_util.py +++ b/api/core/prompt/utils/prompt_message_util.py @@ -1,7 +1,8 @@ from collections.abc import Sequence from typing import Any, cast -from core.model_runtime.entities import ( +from core.prompt.simple_prompt_transform import ModelMode +from dify_graph.model_runtime.entities import ( AssistantPromptMessage, AudioPromptMessageContent, ImagePromptMessageContent, @@ -10,7 +11,6 @@ from core.model_runtime.entities import ( PromptMessageRole, TextPromptMessageContent, ) -from core.prompt.simple_prompt_transform import ModelMode class PromptMessageUtil: diff --git a/api/core/provider_manager.py b/api/core/provider_manager.py index fdbfca4330..f82c3a846b 100644 --- a/api/core/provider_manager.py +++ b/api/core/provider_manager.py @@ -28,14 +28,14 @@ from core.entities.provider_entities import ( from core.helper import encrypter from core.helper.model_provider_cache import ProviderCredentialsCache, ProviderCredentialsCacheType from core.helper.position_helper import is_filtered -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ( +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ( ConfigurateMethod, CredentialFormSchema, FormType, ProviderEntity, ) -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from extensions import ext_hosting_provider from extensions.ext_database import db from extensions.ext_redis import redis_client diff --git a/api/core/rag/data_post_processor/data_post_processor.py b/api/core/rag/data_post_processor/data_post_processor.py index bfa8781e9f..2b73ef5f26 100644 --- a/api/core/rag/data_post_processor/data_post_processor.py +++ b/api/core/rag/data_post_processor/data_post_processor.py @@ -1,6 +1,4 @@ from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.rag.data_post_processor.reorder import ReorderRunner from core.rag.index_processor.constant.query_type import QueryType from core.rag.models.document import Document @@ -8,6 +6,8 @@ from core.rag.rerank.entity.weight import KeywordSetting, VectorSetting, Weights from core.rag.rerank.rerank_base import BaseRerankRunner from core.rag.rerank.rerank_factory import RerankRunnerFactory from core.rag.rerank.rerank_type import RerankMode +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.invoke import InvokeAuthorizationError class DataPostProcessor: diff --git a/api/core/rag/datasource/retrieval_service.py b/api/core/rag/datasource/retrieval_service.py index 91c16ce079..e8a3a05e19 100644 --- a/api/core/rag/datasource/retrieval_service.py +++ b/api/core/rag/datasource/retrieval_service.py @@ -10,7 +10,6 @@ from sqlalchemy.orm import Session, load_only from configs import dify_config from core.db.session_factory import session_factory from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.data_post_processor.data_post_processor import DataPostProcessor from core.rag.datasource.keyword.keyword_factory import Keyword from core.rag.datasource.vdb.vector_factory import Vector @@ -23,6 +22,7 @@ from core.rag.models.document import Document from core.rag.rerank.rerank_type import RerankMode from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.tools.signature import sign_upload_file +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.dataset import ( ChildChunk, diff --git a/api/core/rag/datasource/vdb/vector_factory.py b/api/core/rag/datasource/vdb/vector_factory.py index b9772b3c08..3225764693 100644 --- a/api/core/rag/datasource/vdb/vector_factory.py +++ b/api/core/rag/datasource/vdb/vector_factory.py @@ -8,13 +8,13 @@ from sqlalchemy import select from configs import dify_config from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.vdb.vector_base import BaseVector from core.rag.datasource.vdb.vector_type import VectorType from core.rag.embedding.cached_embedding import CacheEmbedding from core.rag.embedding.embedding_base import Embeddings from core.rag.index_processor.constant.doc_type import DocType from core.rag.models.document import Document +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from extensions.ext_redis import redis_client from extensions.ext_storage import storage diff --git a/api/core/rag/docstore/dataset_docstore.py b/api/core/rag/docstore/dataset_docstore.py index 69adac522d..16a5588024 100644 --- a/api/core/rag/docstore/dataset_docstore.py +++ b/api/core/rag/docstore/dataset_docstore.py @@ -6,8 +6,8 @@ from typing import Any from sqlalchemy import func, select from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.models.document import AttachmentDocument, Document +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.dataset import ChildChunk, Dataset, DocumentSegment, SegmentAttachmentBinding diff --git a/api/core/rag/embedding/cached_embedding.py b/api/core/rag/embedding/cached_embedding.py index 0efe19a57c..6d1b65a055 100644 --- a/api/core/rag/embedding/cached_embedding.py +++ b/api/core/rag/embedding/cached_embedding.py @@ -9,9 +9,9 @@ from sqlalchemy.exc import IntegrityError from configs import dify_config from core.entities.embedding_type import EmbeddingInputType from core.model_manager import ModelInstance -from core.model_runtime.entities.model_entities import ModelPropertyKey -from core.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel from core.rag.embedding.embedding_base import Embeddings +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey +from dify_graph.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel from extensions.ext_database import db from extensions.ext_redis import redis_client from libs import helper diff --git a/api/core/rag/index_processor/processor/paragraph_index_processor.py b/api/core/rag/index_processor/processor/paragraph_index_processor.py index 79265cf3ed..9c21dad488 100644 --- a/api/core/rag/index_processor/processor/paragraph_index_processor.py +++ b/api/core/rag/index_processor/processor/paragraph_index_processor.py @@ -12,15 +12,6 @@ from core.app.llm import deduct_llm_quota from core.entities.knowledge_entities import PreviewDetail from core.llm_generator.prompts import DEFAULT_GENERATOR_SUMMARY_PROMPT from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage -from core.model_runtime.entities.message_entities import ( - ImagePromptMessageContent, - PromptMessage, - PromptMessageContentUnionTypes, - TextPromptMessageContent, - UserPromptMessage, -) -from core.model_runtime.entities.model_entities import ModelFeature, ModelType from core.provider_manager import ProviderManager from core.rag.cleaner.clean_processor import CleanProcessor from core.rag.datasource.keyword.keyword_factory import Keyword @@ -36,6 +27,15 @@ from core.rag.models.document import AttachmentDocument, Document, MultimodalGen from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.tools.utils.text_processing_utils import remove_leading_symbols from dify_graph.file import File, FileTransferMethod, FileType, file_manager +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( + ImagePromptMessageContent, + PromptMessage, + PromptMessageContentUnionTypes, + TextPromptMessageContent, + UserPromptMessage, +) +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelType from extensions.ext_database import db from factories.file_factory import build_from_mapping from libs import helper diff --git a/api/core/rag/rerank/rerank_model.py b/api/core/rag/rerank/rerank_model.py index 690e780921..fcb14ffc52 100644 --- a/api/core/rag/rerank/rerank_model.py +++ b/api/core/rag/rerank/rerank_model.py @@ -1,12 +1,12 @@ import base64 from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.rerank_entities import RerankResult from core.rag.index_processor.constant.doc_type import DocType from core.rag.index_processor.constant.query_type import QueryType from core.rag.models.document import Document from core.rag.rerank.rerank_base import BaseRerankRunner +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.rerank_entities import RerankResult from extensions.ext_database import db from extensions.ext_storage import storage from models.model import UploadFile diff --git a/api/core/rag/rerank/weight_rerank.py b/api/core/rag/rerank/weight_rerank.py index 18020608cb..7edd05d2d1 100644 --- a/api/core/rag/rerank/weight_rerank.py +++ b/api/core/rag/rerank/weight_rerank.py @@ -4,7 +4,6 @@ from collections import Counter import numpy as np from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.keyword.jieba.jieba_keyword_table_handler import JiebaKeywordTableHandler from core.rag.embedding.cached_embedding import CacheEmbedding from core.rag.index_processor.constant.doc_type import DocType @@ -12,6 +11,7 @@ from core.rag.index_processor.constant.query_type import QueryType from core.rag.models.document import Document from core.rag.rerank.entity.weight import VectorSetting, Weights from core.rag.rerank.rerank_base import BaseRerankRunner +from dify_graph.model_runtime.entities.model_entities import ModelType class WeightRerankRunner(BaseRerankRunner): diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index 151dfe81b3..b56ff9edef 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -25,10 +25,6 @@ from core.entities.agent_entities import PlanningStrategy from core.entities.model_entities import ModelStatus from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageRole, PromptMessageTool -from core.model_runtime.entities.model_entities import ModelFeature, ModelType -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.ops.utils import measure_time @@ -61,6 +57,10 @@ from core.rag.retrieval.template_prompts import ( from core.tools.signature import sign_upload_file from core.tools.utils.dataset_retriever.dataset_retriever_base_tool import DatasetRetrieverBaseTool from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageRole, PromptMessageTool +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelType +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from dify_graph.nodes.knowledge_retrieval import exc from dify_graph.repositories.rag_retrieval_protocol import ( KnowledgeRetrievalRequest, diff --git a/api/core/rag/retrieval/router/multi_dataset_function_call_router.py b/api/core/rag/retrieval/router/multi_dataset_function_call_router.py index 5f3e1a8cae..23a2ac8386 100644 --- a/api/core/rag/retrieval/router/multi_dataset_function_call_router.py +++ b/api/core/rag/retrieval/router/multi_dataset_function_call_router.py @@ -2,8 +2,8 @@ from typing import Union from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage -from core.model_runtime.entities.message_entities import PromptMessageTool, SystemPromptMessage, UserPromptMessage +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage +from dify_graph.model_runtime.entities.message_entities import PromptMessageTool, SystemPromptMessage, UserPromptMessage class FunctionCallMultiDatasetRouter: diff --git a/api/core/rag/retrieval/router/multi_dataset_react_route.py b/api/core/rag/retrieval/router/multi_dataset_react_route.py index fa2007122d..ea110fa0a7 100644 --- a/api/core/rag/retrieval/router/multi_dataset_react_route.py +++ b/api/core/rag/retrieval/router/multi_dataset_react_route.py @@ -4,12 +4,12 @@ from typing import Union from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.app.llm import deduct_llm_quota from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageRole, PromptMessageTool from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate from core.rag.retrieval.output_parser.react_output import ReactAction from core.rag.retrieval.output_parser.structured_chat import StructuredChatOutputParser +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageRole, PromptMessageTool PREFIX = """Respond to the human as helpfully and accurately as possible. You have access to the following tools:""" diff --git a/api/core/rag/splitter/fixed_text_splitter.py b/api/core/rag/splitter/fixed_text_splitter.py index b65cb14d8e..7a00e8a886 100644 --- a/api/core/rag/splitter/fixed_text_splitter.py +++ b/api/core/rag/splitter/fixed_text_splitter.py @@ -7,7 +7,6 @@ import re from typing import Any from core.model_manager import ModelInstance -from core.model_runtime.model_providers.__base.tokenizers.gpt2_tokenizer import GPT2Tokenizer from core.rag.splitter.text_splitter import ( TS, Collection, @@ -16,6 +15,7 @@ from core.rag.splitter.text_splitter import ( Set, Union, ) +from dify_graph.model_runtime.model_providers.__base.tokenizers.gpt2_tokenizer import GPT2Tokenizer class EnhanceRecursiveCharacterTextSplitter(RecursiveCharacterTextSplitter): diff --git a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py index 85ee9b5083..3fc333038d 100644 --- a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py @@ -17,9 +17,9 @@ from sqlalchemy.orm import sessionmaker from tenacity import before_sleep_log, retry, retry_if_exception, stop_after_attempt from configs import dify_config -from core.model_runtime.utils.encoders import jsonable_encoder from dify_graph.entities import WorkflowNodeExecution from dify_graph.enums import NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.ext_storage import storage diff --git a/api/core/tools/builtin_tool/providers/audio/tools/asr.py b/api/core/tools/builtin_tool/providers/audio/tools/asr.py index b0552fd863..dacc49c746 100644 --- a/api/core/tools/builtin_tool/providers/audio/tools/asr.py +++ b/api/core/tools/builtin_tool/providers/audio/tools/asr.py @@ -3,13 +3,13 @@ from collections.abc import Generator from typing import Any from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.plugin.entities.parameters import PluginParameterOption from core.tools.builtin_tool.tool import BuiltinTool from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter from dify_graph.file.enums import FileType from dify_graph.file.file_manager import download +from dify_graph.model_runtime.entities.model_entities import ModelType from services.model_provider_service import ModelProviderService diff --git a/api/core/tools/builtin_tool/providers/audio/tools/tts.py b/api/core/tools/builtin_tool/providers/audio/tools/tts.py index 5009f7ac21..7818bff0ab 100644 --- a/api/core/tools/builtin_tool/providers/audio/tools/tts.py +++ b/api/core/tools/builtin_tool/providers/audio/tools/tts.py @@ -3,11 +3,11 @@ from collections.abc import Generator from typing import Any from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType from core.plugin.entities.parameters import PluginParameterOption from core.tools.builtin_tool.tool import BuiltinTool from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType from services.model_provider_service import ModelProviderService diff --git a/api/core/tools/builtin_tool/tool.py b/api/core/tools/builtin_tool/tool.py index 51b0407886..00f5931088 100644 --- a/api/core/tools/builtin_tool/tool.py +++ b/api/core/tools/builtin_tool/tool.py @@ -1,11 +1,11 @@ from __future__ import annotations -from core.model_runtime.entities.llm_entities import LLMResult -from core.model_runtime.entities.message_entities import PromptMessage, SystemPromptMessage, UserPromptMessage from core.tools.__base.tool import Tool from core.tools.__base.tool_runtime import ToolRuntime from core.tools.entities.tool_entities import ToolProviderType from core.tools.utils.model_invocation_utils import ModelInvocationUtils +from dify_graph.model_runtime.entities.llm_entities import LLMResult +from dify_graph.model_runtime.entities.message_entities import PromptMessage, SystemPromptMessage, UserPromptMessage _SUMMARY_PROMPT = """You are a professional language researcher, you are interested in the language and you can quickly aimed at the main point of an webpage and reproduce it in your own words but diff --git a/api/core/tools/entities/api_entities.py b/api/core/tools/entities/api_entities.py index 218ffafd55..2545290b57 100644 --- a/api/core/tools/entities/api_entities.py +++ b/api/core/tools/entities/api_entities.py @@ -5,11 +5,11 @@ from typing import Any, Literal from pydantic import BaseModel, Field, field_validator from core.entities.mcp_provider import MCPAuthentication, MCPConfiguration -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin_daemon import CredentialType from core.tools.__base.tool import ToolParameter from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolProviderType +from dify_graph.model_runtime.utils.encoders import jsonable_encoder class ToolApiEntity(BaseModel): diff --git a/api/core/tools/mcp_tool/tool.py b/api/core/tools/mcp_tool/tool.py index 1d439323f2..9025ff6ef1 100644 --- a/api/core/tools/mcp_tool/tool.py +++ b/api/core/tools/mcp_tool/tool.py @@ -17,11 +17,11 @@ from core.mcp.types import ( TextContent, TextResourceContents, ) -from core.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata from core.tools.__base.tool import Tool from core.tools.__base.tool_runtime import ToolRuntime from core.tools.entities.tool_entities import ToolEntity, ToolInvokeMessage, ToolProviderType from core.tools.errors import ToolInvokeError +from dify_graph.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata logger = logging.getLogger(__name__) diff --git a/api/core/tools/tool_manager.py b/api/core/tools/tool_manager.py index 1bb9960e62..323bb0584a 100644 --- a/api/core/tools/tool_manager.py +++ b/api/core/tools/tool_manager.py @@ -37,7 +37,6 @@ from core.agent.entities import AgentToolEntity from core.app.entities.app_invoke_entities import InvokeFrom from core.helper.module_import_helper import load_single_subclass_from_source from core.helper.position_helper import is_filtered -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin_daemon import CredentialType from core.tools.__base.tool import Tool from core.tools.builtin_tool.provider import BuiltinToolProviderController @@ -58,6 +57,7 @@ from core.tools.tool_label_manager import ToolLabelManager from core.tools.utils.configuration import ToolParameterConfigurationManager from core.tools.utils.encryption import create_provider_encrypter, create_tool_provider_encrypter from core.tools.workflow_as_tool.tool import WorkflowTool +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from models.tools import ApiToolProvider, BuiltinToolProvider, WorkflowToolProvider from services.tools.tools_transform_service import ToolTransformService diff --git a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py index 20e10be075..3dbbbe6563 100644 --- a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py +++ b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py @@ -7,13 +7,13 @@ from sqlalchemy import select from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.retrieval_service import RetrievalService from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.rag.models.document import Document as RagDocument from core.rag.rerank.rerank_model import RerankModelRunner from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.tools.utils.dataset_retriever.dataset_retriever_base_tool import DatasetRetrieverBaseTool +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.dataset import Dataset, Document, DocumentSegment diff --git a/api/core/tools/utils/model_invocation_utils.py b/api/core/tools/utils/model_invocation_utils.py index e7fba09359..8f958563bd 100644 --- a/api/core/tools/utils/model_invocation_utils.py +++ b/api/core/tools/utils/model_invocation_utils.py @@ -9,18 +9,18 @@ from decimal import Decimal from typing import cast from core.model_manager import ModelManager -from core.model_runtime.entities.llm_entities import LLMResult -from core.model_runtime.entities.message_entities import PromptMessage -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType -from core.model_runtime.errors.invoke import ( +from dify_graph.model_runtime.entities.llm_entities import LLMResult +from dify_graph.model_runtime.entities.message_entities import PromptMessage +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType +from dify_graph.model_runtime.errors.invoke import ( InvokeAuthorizationError, InvokeBadRequestError, InvokeConnectionError, InvokeRateLimitError, InvokeServerUnavailableError, ) -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from models.tools import ToolModelInvoke diff --git a/api/core/tools/workflow_as_tool/tool.py b/api/core/tools/workflow_as_tool/tool.py index 6b1b48505b..9b9aa7a741 100644 --- a/api/core/tools/workflow_as_tool/tool.py +++ b/api/core/tools/workflow_as_tool/tool.py @@ -8,7 +8,6 @@ from typing import Any, cast from sqlalchemy import select from core.db.session_factory import session_factory -from core.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata from core.tools.__base.tool import Tool from core.tools.__base.tool_runtime import ToolRuntime from core.tools.entities.tool_entities import ( @@ -19,6 +18,7 @@ from core.tools.entities.tool_entities import ( ) from core.tools.errors import ToolInvokeError from dify_graph.file import FILE_MODEL_IDENTITY, File, FileTransferMethod +from dify_graph.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata from factories.file_factory import build_from_mapping from models import Account, Tenant from models.model import App, EndUser diff --git a/api/core/workflow/node_factory.py b/api/core/workflow/node_factory.py index 522e510755..3105ceb04b 100644 --- a/api/core/workflow/node_factory.py +++ b/api/core/workflow/node_factory.py @@ -15,9 +15,6 @@ from core.helper.code_executor.code_executor import ( from core.helper.ssrf_proxy import ssrf_proxy from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.memory import PromptMessageMemory -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.prompt.entities.advanced_prompt_entities import MemoryConfig from core.rag.index_processor.index_processor import IndexProcessor from core.rag.retrieval.dataset_retrieval import DatasetRetrieval @@ -27,6 +24,9 @@ from dify_graph.entities.graph_config import NodeConfigDict from dify_graph.enums import NodeType, SystemVariableKey from dify_graph.file.file_manager import file_manager from dify_graph.graph.graph import NodeFactory +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.memory import PromptMessageMemory +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from dify_graph.nodes.base.node import Node from dify_graph.nodes.code.code_node import CodeNode, WorkflowCodeExecutor from dify_graph.nodes.code.entities import CodeLanguage diff --git a/api/dify_graph/file/file_manager.py b/api/dify_graph/file/file_manager.py index a7719400d9..8d998054db 100644 --- a/api/dify_graph/file/file_manager.py +++ b/api/dify_graph/file/file_manager.py @@ -3,14 +3,14 @@ from __future__ import annotations import base64 from collections.abc import Mapping -from core.model_runtime.entities import ( +from dify_graph.model_runtime.entities import ( AudioPromptMessageContent, DocumentPromptMessageContent, ImagePromptMessageContent, TextPromptMessageContent, VideoPromptMessageContent, ) -from core.model_runtime.entities.message_entities import PromptMessageContentUnionTypes +from dify_graph.model_runtime.entities.message_entities import PromptMessageContentUnionTypes from . import helpers from .enums import FileAttribute diff --git a/api/dify_graph/file/models.py b/api/dify_graph/file/models.py index cd7d3edde8..db12d4f57a 100644 --- a/api/dify_graph/file/models.py +++ b/api/dify_graph/file/models.py @@ -5,7 +5,7 @@ from typing import Any from pydantic import BaseModel, Field, model_validator -from core.model_runtime.entities.message_entities import ImagePromptMessageContent +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent from . import helpers from .constants import FILE_MODEL_IDENTITY diff --git a/api/dify_graph/graph_engine/event_management/event_handlers.py b/api/dify_graph/graph_engine/event_management/event_handlers.py index 92ea793ccb..7f5ad40e0e 100644 --- a/api/dify_graph/graph_engine/event_management/event_handlers.py +++ b/api/dify_graph/graph_engine/event_management/event_handlers.py @@ -7,7 +7,6 @@ from collections.abc import Mapping from functools import singledispatchmethod from typing import TYPE_CHECKING, final -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import ErrorStrategy, NodeExecutionType, NodeState from dify_graph.graph import Graph from dify_graph.graph_events import ( @@ -30,6 +29,7 @@ from dify_graph.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.runtime import GraphRuntimeState from ..domain.graph_execution import GraphExecution diff --git a/api/core/model_runtime/README.md b/api/dify_graph/model_runtime/README.md similarity index 100% rename from api/core/model_runtime/README.md rename to api/dify_graph/model_runtime/README.md diff --git a/api/core/model_runtime/README_CN.md b/api/dify_graph/model_runtime/README_CN.md similarity index 100% rename from api/core/model_runtime/README_CN.md rename to api/dify_graph/model_runtime/README_CN.md diff --git a/api/core/model_runtime/__init__.py b/api/dify_graph/model_runtime/__init__.py similarity index 100% rename from api/core/model_runtime/__init__.py rename to api/dify_graph/model_runtime/__init__.py diff --git a/api/core/model_runtime/callbacks/__init__.py b/api/dify_graph/model_runtime/callbacks/__init__.py similarity index 100% rename from api/core/model_runtime/callbacks/__init__.py rename to api/dify_graph/model_runtime/callbacks/__init__.py diff --git a/api/core/model_runtime/callbacks/base_callback.py b/api/dify_graph/model_runtime/callbacks/base_callback.py similarity index 94% rename from api/core/model_runtime/callbacks/base_callback.py rename to api/dify_graph/model_runtime/callbacks/base_callback.py index a745a91510..20faf3d6cd 100644 --- a/api/core/model_runtime/callbacks/base_callback.py +++ b/api/dify_graph/model_runtime/callbacks/base_callback.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod from collections.abc import Sequence -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel _TEXT_COLOR_MAPPING = { "blue": "36;1", diff --git a/api/core/model_runtime/callbacks/logging_callback.py b/api/dify_graph/model_runtime/callbacks/logging_callback.py similarity index 94% rename from api/core/model_runtime/callbacks/logging_callback.py rename to api/dify_graph/model_runtime/callbacks/logging_callback.py index b366fcc57b..49b9ab27eb 100644 --- a/api/core/model_runtime/callbacks/logging_callback.py +++ b/api/dify_graph/model_runtime/callbacks/logging_callback.py @@ -4,10 +4,10 @@ import sys from collections.abc import Sequence from typing import cast -from core.model_runtime.callbacks.base_callback import Callback -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk -from core.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.callbacks.base_callback import Callback +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk +from dify_graph.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel logger = logging.getLogger(__name__) diff --git a/api/core/model_runtime/entities/__init__.py b/api/dify_graph/model_runtime/entities/__init__.py similarity index 100% rename from api/core/model_runtime/entities/__init__.py rename to api/dify_graph/model_runtime/entities/__init__.py diff --git a/api/core/model_runtime/entities/common_entities.py b/api/dify_graph/model_runtime/entities/common_entities.py similarity index 100% rename from api/core/model_runtime/entities/common_entities.py rename to api/dify_graph/model_runtime/entities/common_entities.py diff --git a/api/core/model_runtime/entities/defaults.py b/api/dify_graph/model_runtime/entities/defaults.py similarity index 98% rename from api/core/model_runtime/entities/defaults.py rename to api/dify_graph/model_runtime/entities/defaults.py index 51c9c51257..53b732e5c6 100644 --- a/api/core/model_runtime/entities/defaults.py +++ b/api/dify_graph/model_runtime/entities/defaults.py @@ -1,4 +1,4 @@ -from core.model_runtime.entities.model_entities import DefaultParameterName +from dify_graph.model_runtime.entities.model_entities import DefaultParameterName PARAMETER_RULE_TEMPLATE: dict[DefaultParameterName, dict] = { DefaultParameterName.TEMPERATURE: { diff --git a/api/core/model_runtime/entities/llm_entities.py b/api/dify_graph/model_runtime/entities/llm_entities.py similarity index 97% rename from api/core/model_runtime/entities/llm_entities.py rename to api/dify_graph/model_runtime/entities/llm_entities.py index 2c7c421eed..eec682a2ae 100644 --- a/api/core/model_runtime/entities/llm_entities.py +++ b/api/dify_graph/model_runtime/entities/llm_entities.py @@ -7,8 +7,8 @@ from typing import Any, TypedDict, Union from pydantic import BaseModel, Field -from core.model_runtime.entities.message_entities import AssistantPromptMessage, PromptMessage -from core.model_runtime.entities.model_entities import ModelUsage, PriceInfo +from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage, PromptMessage +from dify_graph.model_runtime.entities.model_entities import ModelUsage, PriceInfo class LLMMode(StrEnum): diff --git a/api/core/model_runtime/entities/message_entities.py b/api/dify_graph/model_runtime/entities/message_entities.py similarity index 100% rename from api/core/model_runtime/entities/message_entities.py rename to api/dify_graph/model_runtime/entities/message_entities.py diff --git a/api/core/model_runtime/entities/model_entities.py b/api/dify_graph/model_runtime/entities/model_entities.py similarity index 98% rename from api/core/model_runtime/entities/model_entities.py rename to api/dify_graph/model_runtime/entities/model_entities.py index 19194d162c..fbcde6740a 100644 --- a/api/core/model_runtime/entities/model_entities.py +++ b/api/dify_graph/model_runtime/entities/model_entities.py @@ -6,7 +6,7 @@ from typing import Any from pydantic import BaseModel, ConfigDict, model_validator -from core.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.common_entities import I18nObject class ModelType(StrEnum): diff --git a/api/core/model_runtime/entities/provider_entities.py b/api/dify_graph/model_runtime/entities/provider_entities.py similarity index 95% rename from api/core/model_runtime/entities/provider_entities.py rename to api/dify_graph/model_runtime/entities/provider_entities.py index 2d88751668..97a99ea7ce 100644 --- a/api/core/model_runtime/entities/provider_entities.py +++ b/api/dify_graph/model_runtime/entities/provider_entities.py @@ -3,8 +3,8 @@ from enum import StrEnum, auto from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.model_entities import AIModelEntity, ModelType +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelType class ConfigurateMethod(StrEnum): diff --git a/api/core/model_runtime/entities/rerank_entities.py b/api/dify_graph/model_runtime/entities/rerank_entities.py similarity index 100% rename from api/core/model_runtime/entities/rerank_entities.py rename to api/dify_graph/model_runtime/entities/rerank_entities.py diff --git a/api/core/model_runtime/entities/text_embedding_entities.py b/api/dify_graph/model_runtime/entities/text_embedding_entities.py similarity index 89% rename from api/core/model_runtime/entities/text_embedding_entities.py rename to api/dify_graph/model_runtime/entities/text_embedding_entities.py index 854c448250..a0210c169d 100644 --- a/api/core/model_runtime/entities/text_embedding_entities.py +++ b/api/dify_graph/model_runtime/entities/text_embedding_entities.py @@ -2,7 +2,7 @@ from decimal import Decimal from pydantic import BaseModel -from core.model_runtime.entities.model_entities import ModelUsage +from dify_graph.model_runtime.entities.model_entities import ModelUsage class EmbeddingUsage(ModelUsage): diff --git a/api/core/model_runtime/errors/__init__.py b/api/dify_graph/model_runtime/errors/__init__.py similarity index 100% rename from api/core/model_runtime/errors/__init__.py rename to api/dify_graph/model_runtime/errors/__init__.py diff --git a/api/core/model_runtime/errors/invoke.py b/api/dify_graph/model_runtime/errors/invoke.py similarity index 100% rename from api/core/model_runtime/errors/invoke.py rename to api/dify_graph/model_runtime/errors/invoke.py diff --git a/api/core/model_runtime/errors/validate.py b/api/dify_graph/model_runtime/errors/validate.py similarity index 100% rename from api/core/model_runtime/errors/validate.py rename to api/dify_graph/model_runtime/errors/validate.py diff --git a/api/core/model_runtime/memory/__init__.py b/api/dify_graph/model_runtime/memory/__init__.py similarity index 100% rename from api/core/model_runtime/memory/__init__.py rename to api/dify_graph/model_runtime/memory/__init__.py diff --git a/api/core/model_runtime/memory/prompt_message_memory.py b/api/dify_graph/model_runtime/memory/prompt_message_memory.py similarity index 89% rename from api/core/model_runtime/memory/prompt_message_memory.py rename to api/dify_graph/model_runtime/memory/prompt_message_memory.py index 4491ddfd05..a76a7faf71 100644 --- a/api/core/model_runtime/memory/prompt_message_memory.py +++ b/api/dify_graph/model_runtime/memory/prompt_message_memory.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import Sequence from typing import Protocol -from core.model_runtime.entities import PromptMessage +from dify_graph.model_runtime.entities import PromptMessage DEFAULT_MEMORY_MAX_TOKEN_LIMIT = 2000 diff --git a/api/core/model_runtime/model_providers/__base/__init__.py b/api/dify_graph/model_runtime/model_providers/__base/__init__.py similarity index 100% rename from api/core/model_runtime/model_providers/__base/__init__.py rename to api/dify_graph/model_runtime/model_providers/__base/__init__.py diff --git a/api/core/model_runtime/model_providers/__base/ai_model.py b/api/dify_graph/model_runtime/model_providers/__base/ai_model.py similarity index 97% rename from api/core/model_runtime/model_providers/__base/ai_model.py rename to api/dify_graph/model_runtime/model_providers/__base/ai_model.py index c3e50eaddd..ac7ae9925b 100644 --- a/api/core/model_runtime/model_providers/__base/ai_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/ai_model.py @@ -6,9 +6,10 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationError from redis import RedisError from configs import dify_config -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.defaults import PARAMETER_RULE_TEMPLATE -from core.model_runtime.entities.model_entities import ( +from core.plugin.entities.plugin_daemon import PluginModelProviderEntity +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.defaults import PARAMETER_RULE_TEMPLATE +from dify_graph.model_runtime.entities.model_entities import ( AIModelEntity, DefaultParameterName, ModelType, @@ -16,7 +17,7 @@ from core.model_runtime.entities.model_entities import ( PriceInfo, PriceType, ) -from core.model_runtime.errors.invoke import ( +from dify_graph.model_runtime.errors.invoke import ( InvokeAuthorizationError, InvokeBadRequestError, InvokeConnectionError, @@ -24,7 +25,6 @@ from core.model_runtime.errors.invoke import ( InvokeRateLimitError, InvokeServerUnavailableError, ) -from core.plugin.entities.plugin_daemon import PluginModelProviderEntity from extensions.ext_redis import redis_client logger = logging.getLogger(__name__) diff --git a/api/core/model_runtime/model_providers/__base/large_language_model.py b/api/dify_graph/model_runtime/model_providers/__base/large_language_model.py similarity index 98% rename from api/core/model_runtime/model_providers/__base/large_language_model.py rename to api/dify_graph/model_runtime/model_providers/__base/large_language_model.py index c32ab0879e..bf864ca227 100644 --- a/api/core/model_runtime/model_providers/__base/large_language_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/large_language_model.py @@ -7,21 +7,21 @@ from typing import Union from pydantic import ConfigDict from configs import dify_config -from core.model_runtime.callbacks.base_callback import Callback -from core.model_runtime.callbacks.logging_callback import LoggingCallback -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMUsage -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.callbacks.base_callback import Callback +from dify_graph.model_runtime.callbacks.logging_callback import LoggingCallback +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, PromptMessageContentUnionTypes, PromptMessageTool, TextPromptMessageContent, ) -from core.model_runtime.entities.model_entities import ( +from dify_graph.model_runtime.entities.model_entities import ( ModelType, PriceType, ) -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel logger = logging.getLogger(__name__) diff --git a/api/core/model_runtime/model_providers/__base/moderation_model.py b/api/dify_graph/model_runtime/model_providers/__base/moderation_model.py similarity index 89% rename from api/core/model_runtime/model_providers/__base/moderation_model.py rename to api/dify_graph/model_runtime/model_providers/__base/moderation_model.py index 7aff0184f4..5fa3d1634b 100644 --- a/api/core/model_runtime/model_providers/__base/moderation_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/moderation_model.py @@ -2,8 +2,8 @@ import time from pydantic import ConfigDict -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel class ModerationModel(AIModel): diff --git a/api/core/model_runtime/model_providers/__base/rerank_model.py b/api/dify_graph/model_runtime/model_providers/__base/rerank_model.py similarity index 92% rename from api/core/model_runtime/model_providers/__base/rerank_model.py rename to api/dify_graph/model_runtime/model_providers/__base/rerank_model.py index 0a576b832a..5da2b84b95 100644 --- a/api/core/model_runtime/model_providers/__base/rerank_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/rerank_model.py @@ -1,6 +1,6 @@ -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.rerank_entities import RerankResult -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.rerank_entities import RerankResult +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel class RerankModel(AIModel): diff --git a/api/core/model_runtime/model_providers/__base/speech2text_model.py b/api/dify_graph/model_runtime/model_providers/__base/speech2text_model.py similarity index 88% rename from api/core/model_runtime/model_providers/__base/speech2text_model.py rename to api/dify_graph/model_runtime/model_providers/__base/speech2text_model.py index 9d3bf13e79..e69069a85d 100644 --- a/api/core/model_runtime/model_providers/__base/speech2text_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/speech2text_model.py @@ -2,8 +2,8 @@ from typing import IO from pydantic import ConfigDict -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel class Speech2TextModel(AIModel): diff --git a/api/core/model_runtime/model_providers/__base/text_embedding_model.py b/api/dify_graph/model_runtime/model_providers/__base/text_embedding_model.py similarity index 94% rename from api/core/model_runtime/model_providers/__base/text_embedding_model.py rename to api/dify_graph/model_runtime/model_providers/__base/text_embedding_model.py index 4c902e2c11..3438da2ada 100644 --- a/api/core/model_runtime/model_providers/__base/text_embedding_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/text_embedding_model.py @@ -1,9 +1,9 @@ from pydantic import ConfigDict from core.entities.embedding_type import EmbeddingInputType -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType -from core.model_runtime.entities.text_embedding_entities import EmbeddingResult -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType +from dify_graph.model_runtime.entities.text_embedding_entities import EmbeddingResult +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel class TextEmbeddingModel(AIModel): diff --git a/api/core/model_runtime/model_providers/__base/tokenizers/gpt2_tokenizer.py b/api/dify_graph/model_runtime/model_providers/__base/tokenizers/gpt2_tokenizer.py similarity index 100% rename from api/core/model_runtime/model_providers/__base/tokenizers/gpt2_tokenizer.py rename to api/dify_graph/model_runtime/model_providers/__base/tokenizers/gpt2_tokenizer.py diff --git a/api/core/model_runtime/model_providers/__base/tts_model.py b/api/dify_graph/model_runtime/model_providers/__base/tts_model.py similarity index 94% rename from api/core/model_runtime/model_providers/__base/tts_model.py rename to api/dify_graph/model_runtime/model_providers/__base/tts_model.py index a83c8be37c..0656529f22 100644 --- a/api/core/model_runtime/model_providers/__base/tts_model.py +++ b/api/dify_graph/model_runtime/model_providers/__base/tts_model.py @@ -3,8 +3,8 @@ from collections.abc import Iterable from pydantic import ConfigDict -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel logger = logging.getLogger(__name__) diff --git a/api/core/model_runtime/model_providers/__init__.py b/api/dify_graph/model_runtime/model_providers/__init__.py similarity index 100% rename from api/core/model_runtime/model_providers/__init__.py rename to api/dify_graph/model_runtime/model_providers/__init__.py diff --git a/api/core/model_runtime/model_providers/_position.yaml b/api/dify_graph/model_runtime/model_providers/_position.yaml similarity index 100% rename from api/core/model_runtime/model_providers/_position.yaml rename to api/dify_graph/model_runtime/model_providers/_position.yaml diff --git a/api/core/model_runtime/model_providers/model_provider_factory.py b/api/dify_graph/model_runtime/model_providers/model_provider_factory.py similarity index 93% rename from api/core/model_runtime/model_providers/model_provider_factory.py rename to api/dify_graph/model_runtime/model_providers/model_provider_factory.py index 9cfc6889ac..e168fc11d1 100644 --- a/api/core/model_runtime/model_providers/model_provider_factory.py +++ b/api/dify_graph/model_runtime/model_providers/model_provider_factory.py @@ -10,18 +10,20 @@ from redis import RedisError import contexts from configs import dify_config -from core.model_runtime.entities.model_entities import AIModelEntity, ModelType -from core.model_runtime.entities.provider_entities import ProviderConfig, ProviderEntity, SimpleProviderEntity -from core.model_runtime.model_providers.__base.ai_model import AIModel -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.model_runtime.model_providers.__base.moderation_model import ModerationModel -from core.model_runtime.model_providers.__base.rerank_model import RerankModel -from core.model_runtime.model_providers.__base.speech2text_model import Speech2TextModel -from core.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel -from core.model_runtime.model_providers.__base.tts_model import TTSModel -from core.model_runtime.schema_validators.model_credential_schema_validator import ModelCredentialSchemaValidator -from core.model_runtime.schema_validators.provider_credential_schema_validator import ProviderCredentialSchemaValidator from core.plugin.entities.plugin_daemon import PluginModelProviderEntity +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelType +from dify_graph.model_runtime.entities.provider_entities import ProviderConfig, ProviderEntity, SimpleProviderEntity +from dify_graph.model_runtime.model_providers.__base.ai_model import AIModel +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel +from dify_graph.model_runtime.model_providers.__base.moderation_model import ModerationModel +from dify_graph.model_runtime.model_providers.__base.rerank_model import RerankModel +from dify_graph.model_runtime.model_providers.__base.speech2text_model import Speech2TextModel +from dify_graph.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel +from dify_graph.model_runtime.model_providers.__base.tts_model import TTSModel +from dify_graph.model_runtime.schema_validators.model_credential_schema_validator import ModelCredentialSchemaValidator +from dify_graph.model_runtime.schema_validators.provider_credential_schema_validator import ( + ProviderCredentialSchemaValidator, +) from extensions.ext_redis import redis_client from models.provider_ids import ModelProviderID diff --git a/api/core/model_runtime/schema_validators/__init__.py b/api/dify_graph/model_runtime/schema_validators/__init__.py similarity index 100% rename from api/core/model_runtime/schema_validators/__init__.py rename to api/dify_graph/model_runtime/schema_validators/__init__.py diff --git a/api/core/model_runtime/schema_validators/common_validator.py b/api/dify_graph/model_runtime/schema_validators/common_validator.py similarity index 97% rename from api/core/model_runtime/schema_validators/common_validator.py rename to api/dify_graph/model_runtime/schema_validators/common_validator.py index 2caedeaf48..04cdb8e4f7 100644 --- a/api/core/model_runtime/schema_validators/common_validator.py +++ b/api/dify_graph/model_runtime/schema_validators/common_validator.py @@ -1,6 +1,6 @@ from typing import Union, cast -from core.model_runtime.entities.provider_entities import CredentialFormSchema, FormType +from dify_graph.model_runtime.entities.provider_entities import CredentialFormSchema, FormType class CommonValidator: diff --git a/api/core/model_runtime/schema_validators/model_credential_schema_validator.py b/api/dify_graph/model_runtime/schema_validators/model_credential_schema_validator.py similarity index 78% rename from api/core/model_runtime/schema_validators/model_credential_schema_validator.py rename to api/dify_graph/model_runtime/schema_validators/model_credential_schema_validator.py index 0ac935ca31..a97796e98f 100644 --- a/api/core/model_runtime/schema_validators/model_credential_schema_validator.py +++ b/api/dify_graph/model_runtime/schema_validators/model_credential_schema_validator.py @@ -1,6 +1,6 @@ -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ModelCredentialSchema -from core.model_runtime.schema_validators.common_validator import CommonValidator +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ModelCredentialSchema +from dify_graph.model_runtime.schema_validators.common_validator import CommonValidator class ModelCredentialSchemaValidator(CommonValidator): diff --git a/api/core/model_runtime/schema_validators/provider_credential_schema_validator.py b/api/dify_graph/model_runtime/schema_validators/provider_credential_schema_validator.py similarity index 79% rename from api/core/model_runtime/schema_validators/provider_credential_schema_validator.py rename to api/dify_graph/model_runtime/schema_validators/provider_credential_schema_validator.py index 06350f92a9..2fed75a76c 100644 --- a/api/core/model_runtime/schema_validators/provider_credential_schema_validator.py +++ b/api/dify_graph/model_runtime/schema_validators/provider_credential_schema_validator.py @@ -1,5 +1,5 @@ -from core.model_runtime.entities.provider_entities import ProviderCredentialSchema -from core.model_runtime.schema_validators.common_validator import CommonValidator +from dify_graph.model_runtime.entities.provider_entities import ProviderCredentialSchema +from dify_graph.model_runtime.schema_validators.common_validator import CommonValidator class ProviderCredentialSchemaValidator(CommonValidator): diff --git a/api/core/model_runtime/utils/__init__.py b/api/dify_graph/model_runtime/utils/__init__.py similarity index 100% rename from api/core/model_runtime/utils/__init__.py rename to api/dify_graph/model_runtime/utils/__init__.py diff --git a/api/core/model_runtime/utils/encoders.py b/api/dify_graph/model_runtime/utils/encoders.py similarity index 100% rename from api/core/model_runtime/utils/encoders.py rename to api/dify_graph/model_runtime/utils/encoders.py diff --git a/api/dify_graph/node_events/base.py b/api/dify_graph/node_events/base.py index f30c37f2cc..2f6259ae7d 100644 --- a/api/dify_graph/node_events/base.py +++ b/api/dify_graph/node_events/base.py @@ -3,8 +3,8 @@ from typing import Any from pydantic import BaseModel, Field -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.model_runtime.entities.llm_entities import LLMUsage class NodeEventBase(BaseModel): diff --git a/api/dify_graph/node_events/node.py b/api/dify_graph/node_events/node.py index 7f48539255..481e793267 100644 --- a/api/dify_graph/node_events/node.py +++ b/api/dify_graph/node_events/node.py @@ -3,10 +3,10 @@ from datetime import datetime from pydantic import Field -from core.model_runtime.entities.llm_entities import LLMUsage from core.rag.entities.citation_metadata import RetrievalSourceMetadata from dify_graph.entities.pause_reason import PauseReason from dify_graph.file import File +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import NodeRunResult from .base import NodeEventBase diff --git a/api/dify_graph/nodes/agent/agent_node.py b/api/dify_graph/nodes/agent/agent_node.py index 5d4c6526c4..f55871718f 100644 --- a/api/dify_graph/nodes/agent/agent_node.py +++ b/api/dify_graph/nodes/agent/agent_node.py @@ -13,9 +13,6 @@ from core.agent.entities import AgentToolEntity from core.agent.plugin_entities import AgentStrategyParameter from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata -from core.model_runtime.entities.model_entities import AIModelEntity, ModelType -from core.model_runtime.utils.encoders import jsonable_encoder from core.provider_manager import ProviderManager from core.tools.entities.tool_entities import ( ToolIdentity, @@ -32,6 +29,9 @@ from dify_graph.enums import ( WorkflowNodeExecutionStatus, ) from dify_graph.file import File, FileTransferMethod +from dify_graph.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelType +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.node_events import ( AgentLogEvent, NodeEventBase, diff --git a/api/dify_graph/nodes/base/usage_tracking_mixin.py b/api/dify_graph/nodes/base/usage_tracking_mixin.py index f1ba953af5..bd49419fd3 100644 --- a/api/dify_graph/nodes/base/usage_tracking_mixin.py +++ b/api/dify_graph/nodes/base/usage_tracking_mixin.py @@ -1,4 +1,4 @@ -from core.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.runtime import GraphRuntimeState diff --git a/api/dify_graph/nodes/iteration/iteration_node.py b/api/dify_graph/nodes/iteration/iteration_node.py index 5ac25b493d..03d57e3f04 100644 --- a/api/dify_graph/nodes/iteration/iteration_node.py +++ b/api/dify_graph/nodes/iteration/iteration_node.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Any, NewType, cast from typing_extensions import TypeIs -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.constants import CONVERSATION_VARIABLE_NODE_ID from dify_graph.enums import ( NodeExecutionType, @@ -20,6 +19,7 @@ from dify_graph.graph_events import ( GraphRunPartialSucceededEvent, GraphRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import ( IterationFailedEvent, IterationNextEvent, diff --git a/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 86e4a35901..97c013812e 100644 --- a/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/dify_graph/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -3,14 +3,14 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any, Literal from core.app.app_config.entities import DatasetRetrieveConfigEntity -from core.model_runtime.entities.llm_entities import LLMUsage -from core.model_runtime.utils.encoders import jsonable_encoder from dify_graph.entities import GraphInitParams from dify_graph.enums import ( NodeType, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) +from dify_graph.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.node_events import NodeRunResult from dify_graph.nodes.base import LLMUsageTrackingMixin from dify_graph.nodes.base.node import Node diff --git a/api/dify_graph/nodes/llm/entities.py b/api/dify_graph/nodes/llm/entities.py index 74e90fdc7d..707ed8ece0 100644 --- a/api/dify_graph/nodes/llm/entities.py +++ b/api/dify_graph/nodes/llm/entities.py @@ -3,8 +3,8 @@ from typing import Any, Literal from pydantic import BaseModel, Field, field_validator -from core.model_runtime.entities import ImagePromptMessageContent, LLMMode from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig +from dify_graph.model_runtime.entities import ImagePromptMessageContent, LLMMode from dify_graph.nodes.base import BaseNodeData from dify_graph.nodes.base.entities import VariableSelector diff --git a/api/dify_graph/nodes/llm/llm_utils.py b/api/dify_graph/nodes/llm/llm_utils.py index fb64630cd8..ca478a09f8 100644 --- a/api/dify_graph/nodes/llm/llm_utils.py +++ b/api/dify_graph/nodes/llm/llm_utils.py @@ -2,16 +2,16 @@ from collections.abc import Sequence from typing import cast from core.model_manager import ModelInstance -from core.model_runtime.entities import PromptMessageRole -from core.model_runtime.entities.message_entities import ( +from dify_graph.file.models import File +from dify_graph.model_runtime.entities import PromptMessageRole +from dify_graph.model_runtime.entities.message_entities import ( ImagePromptMessageContent, PromptMessage, TextPromptMessageContent, ) -from core.model_runtime.entities.model_entities import AIModelEntity -from core.model_runtime.memory import PromptMessageMemory -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from dify_graph.file.models import File +from dify_graph.model_runtime.entities.model_entities import AIModelEntity +from dify_graph.model_runtime.memory import PromptMessageMemory +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from dify_graph.runtime import VariablePool from dify_graph.variables.segments import ArrayAnySegment, ArrayFileSegment, FileSegment, NoneSegment diff --git a/api/dify_graph/nodes/llm/node.py b/api/dify_graph/nodes/llm/node.py index 0e243bfd3b..65b92b3bcc 100644 --- a/api/dify_graph/nodes/llm/node.py +++ b/api/dify_graph/nodes/llm/node.py @@ -15,30 +15,6 @@ from core.helper.code_executor import CodeExecutor, CodeLanguage from core.llm_generator.output_parser.errors import OutputParserError from core.llm_generator.output_parser.structured_output import invoke_llm_with_structured_output from core.model_manager import ModelInstance -from core.model_runtime.entities import ( - ImagePromptMessageContent, - PromptMessage, - PromptMessageContentType, - TextPromptMessageContent, -) -from core.model_runtime.entities.llm_entities import ( - LLMResult, - LLMResultChunk, - LLMResultChunkWithStructuredOutput, - LLMResultWithStructuredOutput, - LLMStructuredOutput, - LLMUsage, -) -from core.model_runtime.entities.message_entities import ( - AssistantPromptMessage, - PromptMessageContentUnionTypes, - PromptMessageRole, - SystemPromptMessage, - UserPromptMessage, -) -from core.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey -from core.model_runtime.memory import PromptMessageMemory -from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.entities.advanced_prompt_entities import CompletionModelPromptTemplate, MemoryConfig from core.prompt.utils.prompt_message_util import PromptMessageUtil from core.rag.entities.citation_metadata import RetrievalSourceMetadata @@ -52,6 +28,30 @@ from dify_graph.enums import ( WorkflowNodeExecutionStatus, ) from dify_graph.file import File, FileTransferMethod, FileType, file_manager +from dify_graph.model_runtime.entities import ( + ImagePromptMessageContent, + PromptMessage, + PromptMessageContentType, + TextPromptMessageContent, +) +from dify_graph.model_runtime.entities.llm_entities import ( + LLMResult, + LLMResultChunk, + LLMResultChunkWithStructuredOutput, + LLMResultWithStructuredOutput, + LLMStructuredOutput, + LLMUsage, +) +from dify_graph.model_runtime.entities.message_entities import ( + AssistantPromptMessage, + PromptMessageContentUnionTypes, + PromptMessageRole, + SystemPromptMessage, + UserPromptMessage, +) +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey +from dify_graph.model_runtime.memory import PromptMessageMemory +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.node_events import ( ModelInvokeCompletedEvent, NodeEventBase, diff --git a/api/dify_graph/nodes/loop/loop_node.py b/api/dify_graph/nodes/loop/loop_node.py index 9bd79b7947..6ae3b5220d 100644 --- a/api/dify_graph/nodes/loop/loop_node.py +++ b/api/dify_graph/nodes/loop/loop_node.py @@ -5,7 +5,6 @@ from collections.abc import Callable, Generator, Mapping, Sequence from datetime import datetime from typing import TYPE_CHECKING, Any, Literal, cast -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import ( NodeExecutionType, NodeType, @@ -17,6 +16,7 @@ from dify_graph.graph_events import ( GraphRunFailedEvent, NodeRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import ( LoopFailedEvent, LoopNextEvent, diff --git a/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py b/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py index 626f38fc9b..a9b21d83b1 100644 --- a/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/dify_graph/nodes/parameter_extractor/parameter_extractor_node.py @@ -6,20 +6,6 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any, cast from core.model_manager import ModelInstance -from core.model_runtime.entities import ImagePromptMessageContent -from core.model_runtime.entities.llm_entities import LLMUsage -from core.model_runtime.entities.message_entities import ( - AssistantPromptMessage, - PromptMessage, - PromptMessageRole, - PromptMessageTool, - ToolPromptMessage, - UserPromptMessage, -) -from core.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey -from core.model_runtime.memory import PromptMessageMemory -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate from core.prompt.simple_prompt_transform import ModelMode @@ -30,6 +16,20 @@ from dify_graph.enums import ( WorkflowNodeExecutionStatus, ) from dify_graph.file import File +from dify_graph.model_runtime.entities import ImagePromptMessageContent +from dify_graph.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( + AssistantPromptMessage, + PromptMessage, + PromptMessageRole, + PromptMessageTool, + ToolPromptMessage, + UserPromptMessage, +) +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey +from dify_graph.model_runtime.memory import PromptMessageMemory +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.node_events import NodeRunResult from dify_graph.nodes.base import variable_template_parser from dify_graph.nodes.base.node import Node diff --git a/api/dify_graph/nodes/question_classifier/question_classifier_node.py b/api/dify_graph/nodes/question_classifier/question_classifier_node.py index 59b0a97496..03ddf9ab5f 100644 --- a/api/dify_graph/nodes/question_classifier/question_classifier_node.py +++ b/api/dify_graph/nodes/question_classifier/question_classifier_node.py @@ -4,9 +4,6 @@ from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any from core.model_manager import ModelInstance -from core.model_runtime.entities import LLMUsage, ModelPropertyKey, PromptMessageRole -from core.model_runtime.memory import PromptMessageMemory -from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil from dify_graph.entities import GraphInitParams @@ -16,6 +13,9 @@ from dify_graph.enums import ( WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) +from dify_graph.model_runtime.entities import LLMUsage, ModelPropertyKey, PromptMessageRole +from dify_graph.model_runtime.memory import PromptMessageMemory +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.node_events import ModelInvokeCompletedEvent, NodeRunResult from dify_graph.nodes.base.entities import VariableSelector from dify_graph.nodes.base.node import Node diff --git a/api/dify_graph/nodes/tool/tool_node.py b/api/dify_graph/nodes/tool/tool_node.py index 3c072978e9..eee065c311 100644 --- a/api/dify_graph/nodes/tool/tool_node.py +++ b/api/dify_graph/nodes/tool/tool_node.py @@ -5,7 +5,6 @@ from sqlalchemy import select from sqlalchemy.orm import Session from core.callback_handler.workflow_tool_callback_handler import DifyWorkflowCallbackHandler -from core.model_runtime.entities.llm_entities import LLMUsage from core.tools.__base.tool import Tool from core.tools.entities.tool_entities import ToolInvokeMessage, ToolParameter from core.tools.errors import ToolInvokeError @@ -18,6 +17,7 @@ from dify_graph.enums import ( WorkflowNodeExecutionStatus, ) from dify_graph.file import File, FileTransferMethod +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import NodeEventBase, NodeRunResult, StreamChunkEvent, StreamCompletedEvent from dify_graph.nodes.base.node import Node from dify_graph.nodes.base.variable_template_parser import VariableTemplateParser diff --git a/api/dify_graph/repositories/rag_retrieval_protocol.py b/api/dify_graph/repositories/rag_retrieval_protocol.py index 023400cf32..5f3d38167e 100644 --- a/api/dify_graph/repositories/rag_retrieval_protocol.py +++ b/api/dify_graph/repositories/rag_retrieval_protocol.py @@ -2,7 +2,7 @@ from typing import Any, Literal, Protocol from pydantic import BaseModel, Field -from core.model_runtime.entities import LLMUsage +from dify_graph.model_runtime.entities import LLMUsage from dify_graph.nodes.knowledge_retrieval.entities import MetadataFilteringCondition from dify_graph.nodes.llm.entities import ModelConfig diff --git a/api/dify_graph/runtime/graph_runtime_state.py b/api/dify_graph/runtime/graph_runtime_state.py index 541830c58b..6b88dd683c 100644 --- a/api/dify_graph/runtime/graph_runtime_state.py +++ b/api/dify_graph/runtime/graph_runtime_state.py @@ -10,8 +10,8 @@ from typing import TYPE_CHECKING, Any, ClassVar, Protocol from pydantic import BaseModel, Field from pydantic.json import pydantic_encoder -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import NodeExecutionType, NodeState, NodeType +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.runtime.variable_pool import VariablePool if TYPE_CHECKING: diff --git a/api/dify_graph/runtime/graph_runtime_state_protocol.py b/api/dify_graph/runtime/graph_runtime_state_protocol.py index 4590a4205c..7e55ece3f1 100644 --- a/api/dify_graph/runtime/graph_runtime_state_protocol.py +++ b/api/dify_graph/runtime/graph_runtime_state_protocol.py @@ -1,7 +1,7 @@ from collections.abc import Mapping, Sequence from typing import Any, Protocol -from core.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.system_variable import SystemVariableReadOnlyView from dify_graph.variables.segments import Segment diff --git a/api/dify_graph/runtime/read_only_wrappers.py b/api/dify_graph/runtime/read_only_wrappers.py index 8e4a3ed832..ca06d88c3d 100644 --- a/api/dify_graph/runtime/read_only_wrappers.py +++ b/api/dify_graph/runtime/read_only_wrappers.py @@ -4,7 +4,7 @@ from collections.abc import Mapping, Sequence from copy import deepcopy from typing import Any -from core.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.system_variable import SystemVariableReadOnlyView from dify_graph.variables.segments import Segment diff --git a/api/extensions/ext_sentry.py b/api/extensions/ext_sentry.py index c3aa8edf80..9a34acb0c1 100644 --- a/api/extensions/ext_sentry.py +++ b/api/extensions/ext_sentry.py @@ -10,7 +10,7 @@ def init_app(app: DifyApp): from sentry_sdk.integrations.flask import FlaskIntegration from werkzeug.exceptions import HTTPException - from core.model_runtime.errors.invoke import InvokeRateLimitError + from dify_graph.model_runtime.errors.invoke import InvokeRateLimitError def before_send(event, hint): if "exc_info" in hint: diff --git a/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py b/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py index b660a6c54a..bd1c08d96e 100644 --- a/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py +++ b/api/extensions/logstore/repositories/logstore_workflow_node_execution_repository.py @@ -16,11 +16,11 @@ from typing import Any, Union from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker -from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from dify_graph.entities import WorkflowNodeExecution from dify_graph.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from dify_graph.enums import NodeType +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository from dify_graph.workflow_type_encoder import WorkflowRuntimeTypeConverter from extensions.logstore.aliyun_logstore import AliyunLogStore diff --git a/api/libs/helper.py b/api/libs/helper.py index 39f1931299..6151eb0940 100644 --- a/api/libs/helper.py +++ b/api/libs/helper.py @@ -21,8 +21,8 @@ from pydantic.functional_validators import AfterValidator from configs import dify_config from core.app.features.rate_limiting.rate_limit import RateLimitGenerator -from core.model_runtime.utils.encoders import jsonable_encoder from dify_graph.file import helpers as file_helpers +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_redis import redis_client if TYPE_CHECKING: diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index ad5a91e74b..5790c8b9ec 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -18,9 +18,9 @@ from sqlalchemy.orm import Session from configs import dify_config from core.helper import ssrf_proxy -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import PluginDependency from dify_graph.enums import NodeType +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData from dify_graph.nodes.llm.entities import LLMNodeData from dify_graph.nodes.parameter_extractor.entities import ParameterExtractorNodeData diff --git a/api/services/app_service.py b/api/services/app_service.py index e57253f8b6..ce6826ef5c 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -10,10 +10,10 @@ from constants.model_template import default_app_templates from core.agent.entities import AgentToolEntity from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelPropertyKey, ModelType -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from core.tools.tool_manager import ToolManager from core.tools.utils.configuration import ToolParameterConfigurationManager +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey, ModelType +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from events.app_event import app_was_created from extensions.ext_database import db from libs.datetime_utils import naive_utc_now diff --git a/api/services/audio_service.py b/api/services/audio_service.py index a95361cebd..1b698fad17 100644 --- a/api/services/audio_service.py +++ b/api/services/audio_service.py @@ -8,7 +8,7 @@ from werkzeug.datastructures import FileStorage from constants import AUDIO_EXTENSIONS from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.enums import MessageStatus from models.model import App, AppMode, Message diff --git a/api/services/clear_free_plan_tenant_expired_logs.py b/api/services/clear_free_plan_tenant_expired_logs.py index aefc34fcae..0e0eab00ad 100644 --- a/api/services/clear_free_plan_tenant_expired_logs.py +++ b/api/services/clear_free_plan_tenant_expired_logs.py @@ -10,7 +10,7 @@ from sqlalchemy import select from sqlalchemy.orm import Session, sessionmaker from configs import dify_config -from core.model_runtime.utils.encoders import jsonable_encoder +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from enums.cloud_plan import CloudPlan from extensions.ext_database import db from extensions.ext_storage import storage diff --git a/api/services/dataset_service.py b/api/services/dataset_service.py index 66a49226ba..3a7d483a9d 100644 --- a/api/services/dataset_service.py +++ b/api/services/dataset_service.py @@ -20,12 +20,12 @@ from core.db.session_factory import session_factory from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError from core.helper.name_generator import generate_incremental_name from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelFeature, ModelType -from core.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel from core.rag.index_processor.constant.built_in_field import BuiltInField from core.rag.index_processor.constant.index_type import IndexStructureType from core.rag.retrieval.retrieval_methods import RetrievalMethod from dify_graph.file import helpers as file_helpers +from dify_graph.model_runtime.entities.model_entities import ModelFeature, ModelType +from dify_graph.model_runtime.model_providers.__base.text_embedding_model import TextEmbeddingModel from enums.cloud_plan import CloudPlan from events.dataset_event import dataset_was_deleted from events.document_event import document_was_deleted diff --git a/api/services/datasource_provider_service.py b/api/services/datasource_provider_service.py index eeb14072bd..95a50f0512 100644 --- a/api/services/datasource_provider_service.py +++ b/api/services/datasource_provider_service.py @@ -10,11 +10,11 @@ from constants import HIDDEN_VALUE, UNKNOWN_VALUE from core.helper import encrypter from core.helper.name_generator import generate_incremental_name from core.helper.provider_cache import NoOpProviderCredentialCache -from core.model_runtime.entities.provider_entities import FormType from core.plugin.entities.plugin_daemon import CredentialType from core.plugin.impl.datasource import PluginDatasourceManager from core.plugin.impl.oauth import OAuthHandler from core.tools.utils.encryption import ProviderConfigCache, ProviderConfigEncrypter, create_provider_encrypter +from dify_graph.model_runtime.entities.provider_entities import FormType from extensions.ext_database import db from extensions.ext_redis import redis_client from models.oauth import DatasourceOauthParamConfig, DatasourceOauthTenantParamConfig, DatasourceProvider diff --git a/api/services/entities/model_provider_entities.py b/api/services/entities/model_provider_entities.py index a29d848ac5..9dd595f516 100644 --- a/api/services/entities/model_provider_entities.py +++ b/api/services/entities/model_provider_entities.py @@ -15,9 +15,9 @@ from core.entities.provider_entities import ( QuotaConfiguration, UnaddedModelConfiguration, ) -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ( +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ( ConfigurateMethod, ModelCredentialSchema, ProviderCredentialSchema, diff --git a/api/services/hit_testing_service.py b/api/services/hit_testing_service.py index 8cbf3a25c3..c00c76a826 100644 --- a/api/services/hit_testing_service.py +++ b/api/services/hit_testing_service.py @@ -4,12 +4,12 @@ import time from typing import Any from core.app.app_config.entities import ModelConfig -from core.model_runtime.entities import LLMMode from core.rag.datasource.retrieval_service import RetrievalService from core.rag.index_processor.constant.query_type import QueryType from core.rag.models.document import Document from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from core.rag.retrieval.retrieval_methods import RetrievalMethod +from dify_graph.model_runtime.entities import LLMMode from extensions.ext_database import db from models import Account from models.dataset import Dataset, DatasetQuery diff --git a/api/services/message_service.py b/api/services/message_service.py index ce699e79d4..789b6c2f8c 100644 --- a/api/services/message_service.py +++ b/api/services/message_service.py @@ -9,10 +9,10 @@ from core.app.entities.app_invoke_entities import InvokeFrom from core.llm_generator.llm_generator import LLMGenerator from core.memory.token_buffer_memory import TokenBufferMemory from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.ops.utils import measure_time +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from libs.infinite_scroll_pagination import InfiniteScrollPagination from models import Account diff --git a/api/services/model_load_balancing_service.py b/api/services/model_load_balancing_service.py index 69da3bfb79..2133dc5b3a 100644 --- a/api/services/model_load_balancing_service.py +++ b/api/services/model_load_balancing_service.py @@ -10,13 +10,13 @@ from core.entities.provider_configuration import ProviderConfiguration from core.helper import encrypter from core.helper.model_provider_cache import ProviderCredentialsCache, ProviderCredentialsCacheType from core.model_manager import LBModelManager -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ( +from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ( ModelCredentialSchema, ProviderCredentialSchema, ) -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory -from core.provider_manager import ProviderManager +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from extensions.ext_database import db from libs.datetime_utils import naive_utc_now from models.provider import LoadBalancingModelConfig, ProviderCredential, ProviderModelCredential diff --git a/api/services/model_provider_service.py b/api/services/model_provider_service.py index edd1004b82..0ddd6b9b1a 100644 --- a/api/services/model_provider_service.py +++ b/api/services/model_provider_service.py @@ -1,9 +1,9 @@ import logging from core.entities.model_entities import ModelWithProviderEntity, ProviderModelWithStatusEntity -from core.model_runtime.entities.model_entities import ModelType, ParameterRule -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelType, ParameterRule +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from models.provider import ProviderType from services.entities.model_provider_entities import ( CustomConfigurationResponse, diff --git a/api/services/rag_pipeline/rag_pipeline_dsl_service.py b/api/services/rag_pipeline/rag_pipeline_dsl_service.py index 0a257a587d..58bb4b7c90 100644 --- a/api/services/rag_pipeline/rag_pipeline_dsl_service.py +++ b/api/services/rag_pipeline/rag_pipeline_dsl_service.py @@ -21,9 +21,9 @@ from sqlalchemy.orm import Session from core.helper import ssrf_proxy from core.helper.name_generator import generate_incremental_name -from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import PluginDependency from dify_graph.enums import NodeType +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.nodes.datasource.entities import DatasourceNodeData from dify_graph.nodes.knowledge_retrieval.entities import KnowledgeRetrievalNodeData from dify_graph.nodes.llm.entities import LLMNodeData diff --git a/api/services/summary_index_service.py b/api/services/summary_index_service.py index 7c03ceed5b..eb78be8f88 100644 --- a/api/services/summary_index_service.py +++ b/api/services/summary_index_service.py @@ -10,11 +10,11 @@ from sqlalchemy.orm import Session from core.db.session_factory import session_factory from core.model_manager import ModelManager -from core.model_runtime.entities.llm_entities import LLMUsage -from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.vdb.vector_factory import Vector from core.rag.index_processor.constant.doc_type import DocType from core.rag.models.document import Document +from dify_graph.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.model_entities import ModelType from libs import helper from models.dataset import Dataset, DocumentSegment, DocumentSegmentSummary from models.dataset import Document as DatasetDocument diff --git a/api/services/tools/api_tools_manage_service.py b/api/services/tools/api_tools_manage_service.py index c32157919b..dc883f0daa 100644 --- a/api/services/tools/api_tools_manage_service.py +++ b/api/services/tools/api_tools_manage_service.py @@ -7,7 +7,6 @@ from httpx import get from sqlalchemy import select from core.entities.provider_entities import ProviderConfig -from core.model_runtime.utils.encoders import jsonable_encoder from core.tools.__base.tool_runtime import ToolRuntime from core.tools.custom_tool.provider import ApiToolProviderController from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity @@ -21,6 +20,7 @@ from core.tools.tool_label_manager import ToolLabelManager from core.tools.tool_manager import ToolManager from core.tools.utils.encryption import create_tool_provider_encrypter from core.tools.utils.parser import ApiBasedToolSchemaParser +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from models.tools import ApiToolProvider from services.tools.tools_transform_service import ToolTransformService diff --git a/api/services/tools/workflow_tools_manage_service.py b/api/services/tools/workflow_tools_manage_service.py index ff0b276f77..101b2fe5a2 100644 --- a/api/services/tools/workflow_tools_manage_service.py +++ b/api/services/tools/workflow_tools_manage_service.py @@ -5,7 +5,6 @@ from datetime import datetime from sqlalchemy import or_, select from sqlalchemy.orm import Session -from core.model_runtime.utils.encoders import jsonable_encoder from core.tools.__base.tool_provider import ToolProviderController from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity from core.tools.entities.tool_entities import WorkflowToolParameterConfiguration @@ -13,6 +12,7 @@ from core.tools.tool_label_manager import ToolLabelManager from core.tools.utils.workflow_configuration_sync import WorkflowToolConfigurationUtils from core.tools.workflow_as_tool.provider import WorkflowToolProviderController from core.tools.workflow_as_tool.tool import WorkflowTool +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from extensions.ext_database import db from models.model import App from models.tools import WorkflowToolProvider diff --git a/api/services/vector_service.py b/api/services/vector_service.py index f1fa33cb75..73bb46b797 100644 --- a/api/services/vector_service.py +++ b/api/services/vector_service.py @@ -1,7 +1,6 @@ import logging from core.model_manager import ModelInstance, ModelManager -from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.keyword.keyword_factory import Keyword from core.rag.datasource.vdb.vector_factory import Vector from core.rag.index_processor.constant.doc_type import DocType @@ -9,6 +8,7 @@ from core.rag.index_processor.constant.index_type import IndexStructureType from core.rag.index_processor.index_processor_base import BaseIndexProcessor from core.rag.index_processor.index_processor_factory import IndexProcessorFactory from core.rag.models.document import AttachmentDocument, Document +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models import UploadFile from models.dataset import ChildChunk, Dataset, DatasetProcessRule, DocumentSegment, SegmentAttachmentBinding diff --git a/api/services/workflow/workflow_converter.py b/api/services/workflow/workflow_converter.py index 8b4b3318e1..0153046acc 100644 --- a/api/services/workflow/workflow_converter.py +++ b/api/services/workflow/workflow_converter.py @@ -13,11 +13,11 @@ from core.app.apps.agent_chat.app_config_manager import AgentChatAppConfigManage from core.app.apps.chat.app_config_manager import ChatAppConfigManager from core.app.apps.completion.app_config_manager import CompletionAppConfigManager from core.helper import encrypter -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.simple_prompt_transform import SimplePromptTransform from core.prompt.utils.prompt_template_parser import PromptTemplateParser from dify_graph.file.models import FileUploadConfig +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.nodes import NodeType from dify_graph.variables.input_entities import VariableEntity from events.app_event import app_was_created diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index 2bf291da54..a7f0b036c6 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -438,8 +438,8 @@ class WorkflowService: """ try: from core.model_manager import ModelManager - from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager + from dify_graph.model_runtime.entities.model_entities import ModelType # Get model instance to validate provider+model combination model_manager = ModelManager() @@ -558,8 +558,8 @@ class WorkflowService: :return: True if load balancing is enabled, False otherwise """ try: - from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager + from dify_graph.model_runtime.entities.model_entities import ModelType # Get provider configurations provider_manager = ProviderManager() diff --git a/api/tasks/batch_create_segment_to_index_task.py b/api/tasks/batch_create_segment_to_index_task.py index f69f17b16d..49dee00919 100644 --- a/api/tasks/batch_create_segment_to_index_task.py +++ b/api/tasks/batch_create_segment_to_index_task.py @@ -11,7 +11,7 @@ from sqlalchemy import func from core.db.session_factory import session_factory from core.model_manager import ModelManager -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_redis import redis_client from extensions.ext_storage import storage from libs import helper diff --git a/api/tests/integration_tests/model_runtime/__mock/plugin_model.py b/api/tests/integration_tests/model_runtime/__mock/plugin_model.py index 5012defdad..4e184c93fd 100644 --- a/api/tests/integration_tests/model_runtime/__mock/plugin_model.py +++ b/api/tests/integration_tests/model_runtime/__mock/plugin_model.py @@ -4,20 +4,27 @@ from collections.abc import Generator, Sequence from decimal import Decimal from json import dumps +from core.plugin.entities.plugin_daemon import PluginModelProviderEntity +from core.plugin.impl.model import PluginModelClient + # import monkeypatch -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.llm_entities import LLMMode, LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage -from core.model_runtime.entities.message_entities import AssistantPromptMessage, PromptMessage, PromptMessageTool -from core.model_runtime.entities.model_entities import ( +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.llm_entities import ( + LLMMode, + LLMResult, + LLMResultChunk, + LLMResultChunkDelta, + LLMUsage, +) +from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage, PromptMessage, PromptMessageTool +from dify_graph.model_runtime.entities.model_entities import ( AIModelEntity, FetchFrom, ModelFeature, ModelPropertyKey, ModelType, ) -from core.model_runtime.entities.provider_entities import ConfigurateMethod, ProviderEntity -from core.plugin.entities.plugin_daemon import PluginModelProviderEntity -from core.plugin.impl.model import PluginModelClient +from dify_graph.model_runtime.entities.provider_entities import ConfigurateMethod, ProviderEntity class MockModelClass(PluginModelClient): diff --git a/api/tests/integration_tests/workflow/nodes/__mock/model.py b/api/tests/integration_tests/workflow/nodes/__mock/model.py index cdecdf41d2..5b0f86fed1 100644 --- a/api/tests/integration_tests/workflow/nodes/__mock/model.py +++ b/api/tests/integration_tests/workflow/nodes/__mock/model.py @@ -4,8 +4,8 @@ from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEnti from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle from core.entities.provider_entities import CustomConfiguration, CustomProviderConfiguration, SystemConfiguration from core.model_manager import ModelInstance -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from models.provider import ProviderType diff --git a/api/tests/integration_tests/workflow/nodes/test_llm.py b/api/tests/integration_tests/workflow/nodes/test_llm.py index 07783792d1..fda31d516b 100644 --- a/api/tests/integration_tests/workflow/nodes/test_llm.py +++ b/api/tests/integration_tests/workflow/nodes/test_llm.py @@ -113,8 +113,8 @@ def test_execute_llm(): from decimal import Decimal from unittest.mock import MagicMock - from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage - from core.model_runtime.entities.message_entities import AssistantPromptMessage + from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage + from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage # Create mock model instance mock_model_instance = MagicMock(spec=ModelInstance) @@ -158,7 +158,7 @@ def test_execute_llm(): # Mock fetch_prompt_messages to avoid database calls def mock_fetch_prompt_messages_1(**_kwargs): - from core.model_runtime.entities.message_entities import SystemPromptMessage, UserPromptMessage + from dify_graph.model_runtime.entities.message_entities import SystemPromptMessage, UserPromptMessage return [ SystemPromptMessage(content="you are a helpful assistant. today's weather is sunny."), @@ -229,8 +229,8 @@ def test_execute_llm_with_jinja2(): from decimal import Decimal from unittest.mock import MagicMock - from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage - from core.model_runtime.entities.message_entities import AssistantPromptMessage + from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMUsage + from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage # Create mock model instance mock_model_instance = MagicMock(spec=ModelInstance) @@ -274,7 +274,7 @@ def test_execute_llm_with_jinja2(): # Mock fetch_prompt_messages to avoid database calls def mock_fetch_prompt_messages_2(**_kwargs): - from core.model_runtime.entities.message_entities import SystemPromptMessage, UserPromptMessage + from dify_graph.model_runtime.entities.message_entities import SystemPromptMessage, UserPromptMessage return [ SystemPromptMessage(content="you are a helpful assistant. today's weather is sunny."), diff --git a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py index 7a3f5bc58e..09e560578e 100644 --- a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py +++ b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py @@ -5,9 +5,9 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.model_manager import ModelInstance -from core.model_runtime.entities import AssistantPromptMessage, UserPromptMessage from dify_graph.entities import GraphInitParams from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.model_runtime.entities import AssistantPromptMessage, UserPromptMessage from dify_graph.nodes.llm.protocols import CredentialsProvider, ModelFactory from dify_graph.nodes.parameter_extractor.parameter_extractor_node import ParameterExtractorNode from dify_graph.runtime import GraphRuntimeState, VariablePool diff --git a/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py b/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py index 5d6fcf4775..96fb7ea293 100644 --- a/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py +++ b/api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py @@ -31,12 +31,12 @@ from core.app.layers.pause_state_persist_layer import ( PauseStatePersistenceLayer, WorkflowResumptionContext, ) -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.entities.pause_reason import SchedulingPause from dify_graph.enums import WorkflowExecutionStatus from dify_graph.graph_engine.entities.commands import GraphEngineCommand from dify_graph.graph_engine.layers.base import GraphEngineLayerNotInitializedError from dify_graph.graph_events.graph import GraphRunPausedEvent +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.runtime.graph_runtime_state import GraphRuntimeState from dify_graph.runtime.graph_runtime_state_protocol import ReadOnlyGraphRuntimeState from dify_graph.runtime.read_only_wrappers import ReadOnlyGraphRuntimeStateWrapper diff --git a/api/tests/test_containers_integration_tests/services/test_dataset_service.py b/api/tests/test_containers_integration_tests/services/test_dataset_service.py index f05c47913e..0ca649b36d 100644 --- a/api/tests/test_containers_integration_tests/services/test_dataset_service.py +++ b/api/tests/test_containers_integration_tests/services/test_dataset_service.py @@ -10,8 +10,8 @@ from uuid import uuid4 import pytest -from core.model_runtime.entities.model_entities import ModelType from core.rag.retrieval.retrieval_methods import RetrievalMethod +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.account import Account, Tenant, TenantAccountJoin, TenantAccountRole from models.dataset import Dataset, DatasetPermissionEnum, Document, ExternalKnowledgeBindings diff --git a/api/tests/test_containers_integration_tests/services/test_dataset_service_update_dataset.py b/api/tests/test_containers_integration_tests/services/test_dataset_service_update_dataset.py index f6d9dfddae..7f9135bb81 100644 --- a/api/tests/test_containers_integration_tests/services/test_dataset_service_update_dataset.py +++ b/api/tests/test_containers_integration_tests/services/test_dataset_service_update_dataset.py @@ -3,7 +3,7 @@ from uuid import uuid4 import pytest -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_database import db from models.account import Account, Tenant, TenantAccountJoin, TenantAccountRole from models.dataset import Dataset, ExternalKnowledgeBindings diff --git a/api/tests/test_containers_integration_tests/services/test_model_provider_service.py b/api/tests/test_containers_integration_tests/services/test_model_provider_service.py index f7044f7d45..7a4662055c 100644 --- a/api/tests/test_containers_integration_tests/services/test_model_provider_service.py +++ b/api/tests/test_containers_integration_tests/services/test_model_provider_service.py @@ -4,7 +4,7 @@ import pytest from faker import Faker from core.entities.model_entities import ModelStatus -from core.model_runtime.entities.model_entities import FetchFrom, ModelType +from dify_graph.model_runtime.entities.model_entities import FetchFrom, ModelType from models import Account, Tenant, TenantAccountJoin, TenantAccountRole from models.provider import Provider, ProviderModel, ProviderModelSetting, ProviderType from services.model_provider_service import ModelProviderService @@ -407,8 +407,8 @@ class TestModelProviderService: # Create mock models from core.entities.model_entities import ModelWithProviderEntity, SimpleModelProviderEntity - from core.model_runtime.entities.common_entities import I18nObject - from core.model_runtime.entities.provider_entities import ProviderEntity + from dify_graph.model_runtime.entities.common_entities import I18nObject + from dify_graph.model_runtime.entities.provider_entities import ProviderEntity # Create real model objects instead of mocks provider_entity_1 = SimpleModelProviderEntity( @@ -643,7 +643,7 @@ class TestModelProviderService: # Create mock default model response from core.entities.model_entities import DefaultModelEntity, DefaultModelProviderEntity - from core.model_runtime.entities.common_entities import I18nObject + from dify_graph.model_runtime.entities.common_entities import I18nObject mock_default_model = DefaultModelEntity( model="gpt-3.5-turbo", diff --git a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py index c2cf249d61..0c2ccaa051 100644 --- a/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py +++ b/api/tests/test_containers_integration_tests/services/workflow/test_workflow_converter.py @@ -11,8 +11,8 @@ from core.app.app_config.entities import ( ModelConfigEntity, PromptTemplateEntity, ) -from core.model_runtime.entities.llm_entities import LLMMode from core.prompt.utils.prompt_template_parser import PromptTemplateParser +from dify_graph.model_runtime.entities.llm_entities import LLMMode from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models import Account, Tenant from models.api_based_extension import APIBasedExtension diff --git a/api/tests/unit_tests/controllers/console/workspace/test_load_balancing_config.py b/api/tests/unit_tests/controllers/console/workspace/test_load_balancing_config.py index 59b6614d5e..f2e57eb65f 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_load_balancing_config.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_load_balancing_config.py @@ -13,8 +13,8 @@ from flask import Flask from flask.views import MethodView from werkzeug.exceptions import Forbidden -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.errors.validate import CredentialsValidateFailedError +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError if not hasattr(builtins, "MethodView"): builtins.MethodView = MethodView # type: ignore[attr-defined] diff --git a/api/tests/unit_tests/controllers/service_api/app/test_audio.py b/api/tests/unit_tests/controllers/service_api/app/test_audio.py index b70e70105c..1923ab7fa7 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_audio.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_audio.py @@ -29,7 +29,7 @@ from controllers.service_api.app.error import ( UnsupportedAudioTypeError, ) from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from services.audio_service import AudioService from services.errors.app_model_config import AppModelConfigBrokenError from services.errors.audio import ( diff --git a/api/tests/unit_tests/controllers/service_api/app/test_completion.py b/api/tests/unit_tests/controllers/service_api/app/test_completion.py index c5b1cbc127..4e4482f704 100644 --- a/api/tests/unit_tests/controllers/service_api/app/test_completion.py +++ b/api/tests/unit_tests/controllers/service_api/app/test_completion.py @@ -34,7 +34,7 @@ from controllers.service_api.app.error import ( NotChatAppError, ) from core.errors.error import QuotaExceededError -from core.model_runtime.errors.invoke import InvokeError +from dify_graph.model_runtime.errors.invoke import InvokeError from models.model import App, AppMode, EndUser from services.app_generate_service import AppGenerateService from services.app_task_service import AppTaskService diff --git a/api/tests/unit_tests/core/agent/output_parser/test_cot_output_parser.py b/api/tests/unit_tests/core/agent/output_parser/test_cot_output_parser.py index 4a613e35b0..ba8c903f65 100644 --- a/api/tests/unit_tests/core/agent/output_parser/test_cot_output_parser.py +++ b/api/tests/unit_tests/core/agent/output_parser/test_cot_output_parser.py @@ -3,7 +3,7 @@ from collections.abc import Generator from core.agent.entities import AgentScratchpadUnit from core.agent.output_parser.cot_output_parser import CotAgentOutputParser -from core.model_runtime.entities.llm_entities import AssistantPromptMessage, LLMResultChunk, LLMResultChunkDelta +from dify_graph.model_runtime.entities.llm_entities import AssistantPromptMessage, LLMResultChunk, LLMResultChunkDelta def mock_llm_response(text) -> Generator[LLMResultChunk, None, None]: diff --git a/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py b/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py index a20725c5b0..de99833aac 100644 --- a/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py +++ b/api/tests/unit_tests/core/app/app_config/features/file_upload/test_manager.py @@ -1,6 +1,6 @@ from core.app.app_config.features.file_upload.manager import FileUploadConfigManager -from core.model_runtime.entities.message_entities import ImagePromptMessageContent from dify_graph.file.models import FileTransferMethod, FileUploadConfig, ImageConfig +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent def test_convert_with_vision(): diff --git a/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py b/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py index e85e6e98d9..67b3777c40 100644 --- a/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py +++ b/api/tests/unit_tests/core/app/apps/chat/test_base_app_runner_multimodal.py @@ -9,8 +9,8 @@ from core.app.apps.base_app_queue_manager import PublishFrom from core.app.apps.base_app_runner import AppRunner from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueMessageFileEvent -from core.model_runtime.entities.message_entities import ImagePromptMessageContent from dify_graph.file.enums import FileTransferMethod, FileType +from dify_graph.model_runtime.entities.message_entities import ImagePromptMessageContent from models.enums import CreatorUserRole diff --git a/api/tests/unit_tests/core/app/task_pipeline/test_easy_ui_based_generate_task_pipeline.py b/api/tests/unit_tests/core/app/task_pipeline/test_easy_ui_based_generate_task_pipeline.py index 40f58c9ddf..13fbca6e26 100644 --- a/api/tests/unit_tests/core/app/task_pipeline/test_easy_ui_based_generate_task_pipeline.py +++ b/api/tests/unit_tests/core/app/task_pipeline/test_easy_ui_based_generate_task_pipeline.py @@ -25,9 +25,9 @@ from core.app.entities.task_entities import ( ) from core.app.task_pipeline.easy_ui_based_generate_task_pipeline import EasyUIBasedGenerateTaskPipeline from core.base.tts import AppGeneratorTTSPublisher -from core.model_runtime.entities.llm_entities import LLMResult as RuntimeLLMResult -from core.model_runtime.entities.message_entities import TextPromptMessageContent from core.ops.ops_trace_manager import TraceQueueManager +from dify_graph.model_runtime.entities.llm_entities import LLMResult as RuntimeLLMResult +from dify_graph.model_runtime.entities.message_entities import TextPromptMessageContent from models.model import AppMode diff --git a/api/tests/unit_tests/core/model_runtime/__base/test_increase_tool_call.py b/api/tests/unit_tests/core/model_runtime/__base/test_increase_tool_call.py index 5fbdabceed..d42b7ca0d9 100644 --- a/api/tests/unit_tests/core/model_runtime/__base/test_increase_tool_call.py +++ b/api/tests/unit_tests/core/model_runtime/__base/test_increase_tool_call.py @@ -2,8 +2,8 @@ from unittest.mock import MagicMock, patch import pytest -from core.model_runtime.entities.message_entities import AssistantPromptMessage -from core.model_runtime.model_providers.__base.large_language_model import _increase_tool_call +from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage +from dify_graph.model_runtime.model_providers.__base.large_language_model import _increase_tool_call ToolCall = AssistantPromptMessage.ToolCall @@ -97,7 +97,9 @@ def test__increase_tool_call(): # case 4: mock_id_generator = MagicMock() mock_id_generator.side_effect = [_exp_case.id for _exp_case in EXPECTED_CASE_4] - with patch("core.model_runtime.model_providers.__base.large_language_model._gen_tool_call_id", mock_id_generator): + with patch( + "dify_graph.model_runtime.model_providers.__base.large_language_model._gen_tool_call_id", mock_id_generator + ): _run_case(INPUTS_CASE_4, EXPECTED_CASE_4) @@ -107,6 +109,6 @@ def test__increase_tool_call__no_id_no_name_first_delta_should_raise(): ToolCall(id="", type="function", function=ToolCall.ToolCallFunction(name="func_foo", arguments='"value"}')), ] actual: list[ToolCall] = [] - with patch("core.model_runtime.model_providers.__base.large_language_model._gen_tool_call_id", MagicMock()): + with patch("dify_graph.model_runtime.model_providers.__base.large_language_model._gen_tool_call_id", MagicMock()): with pytest.raises(ValueError): _increase_tool_call(inputs, actual) diff --git a/api/tests/unit_tests/core/model_runtime/__base/test_large_language_model_non_stream_parsing.py b/api/tests/unit_tests/core/model_runtime/__base/test_large_language_model_non_stream_parsing.py index 09d527cb12..8dcfd10ec6 100644 --- a/api/tests/unit_tests/core/model_runtime/__base/test_large_language_model_non_stream_parsing.py +++ b/api/tests/unit_tests/core/model_runtime/__base/test_large_language_model_non_stream_parsing.py @@ -1,10 +1,10 @@ -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.model_providers.__base.large_language_model import _normalize_non_stream_plugin_result +from dify_graph.model_runtime.model_providers.__base.large_language_model import _normalize_non_stream_plugin_result def _make_chunk( diff --git a/api/tests/unit_tests/core/model_runtime/entities/test_llm_entities.py b/api/tests/unit_tests/core/model_runtime/entities/test_llm_entities.py index c10f7b89c3..4e435cb4c6 100644 --- a/api/tests/unit_tests/core/model_runtime/entities/test_llm_entities.py +++ b/api/tests/unit_tests/core/model_runtime/entities/test_llm_entities.py @@ -2,7 +2,7 @@ from decimal import Decimal -from core.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata +from dify_graph.model_runtime.entities.llm_entities import LLMUsage, LLMUsageMetadata class TestLLMUsage: diff --git a/api/tests/unit_tests/core/plugin/test_plugin_runtime.py b/api/tests/unit_tests/core/plugin/test_plugin_runtime.py index 9e871fcb74..4f038d4a5b 100644 --- a/api/tests/unit_tests/core/plugin/test_plugin_runtime.py +++ b/api/tests/unit_tests/core/plugin/test_plugin_runtime.py @@ -19,14 +19,6 @@ import httpx import pytest from pydantic import BaseModel -from core.model_runtime.errors.invoke import ( - InvokeAuthorizationError, - InvokeBadRequestError, - InvokeConnectionError, - InvokeRateLimitError, - InvokeServerUnavailableError, -) -from core.model_runtime.errors.validate import CredentialsValidateFailedError from core.plugin.entities.plugin_daemon import ( CredentialType, PluginDaemonInnerError, @@ -44,6 +36,14 @@ from core.plugin.impl.exc import ( ) from core.plugin.impl.plugin import PluginInstaller from core.plugin.impl.tool import PluginToolManager +from dify_graph.model_runtime.errors.invoke import ( + InvokeAuthorizationError, + InvokeBadRequestError, + InvokeConnectionError, + InvokeRateLimitError, + InvokeServerUnavailableError, +) +from dify_graph.model_runtime.errors.validate import CredentialsValidateFailedError class TestPluginRuntimeExecution: diff --git a/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py b/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py index 786264513c..3e184cbf21 100644 --- a/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py +++ b/api/tests/unit_tests/core/prompt/test_advanced_prompt_transform.py @@ -5,16 +5,16 @@ import pytest from configs import dify_config from core.app.app_config.entities import ModelConfigEntity from core.memory.token_buffer_memory import TokenBufferMemory -from core.model_runtime.entities.message_entities import ( +from core.prompt.advanced_prompt_transform import AdvancedPromptTransform +from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig +from core.prompt.utils.prompt_template_parser import PromptTemplateParser +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, ImagePromptMessageContent, PromptMessageRole, UserPromptMessage, ) -from core.prompt.advanced_prompt_transform import AdvancedPromptTransform -from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig -from core.prompt.utils.prompt_template_parser import PromptTemplateParser -from dify_graph.file import File, FileTransferMethod, FileType from models.model import Conversation diff --git a/api/tests/unit_tests/core/prompt/test_agent_history_prompt_transform.py b/api/tests/unit_tests/core/prompt/test_agent_history_prompt_transform.py index d157a41d2c..634703740c 100644 --- a/api/tests/unit_tests/core/prompt/test_agent_history_prompt_transform.py +++ b/api/tests/unit_tests/core/prompt/test_agent_history_prompt_transform.py @@ -5,14 +5,14 @@ from core.app.entities.app_invoke_entities import ( ) from core.entities.provider_configuration import ProviderModelBundle from core.memory.token_buffer_memory import TokenBufferMemory -from core.model_runtime.entities.message_entities import ( +from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, SystemPromptMessage, ToolPromptMessage, UserPromptMessage, ) -from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.prompt.agent_history_prompt_transform import AgentHistoryPromptTransform +from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from models.model import Conversation diff --git a/api/tests/unit_tests/core/prompt/test_prompt_message.py b/api/tests/unit_tests/core/prompt/test_prompt_message.py index e5da51d733..4136816562 100644 --- a/api/tests/unit_tests/core/prompt/test_prompt_message.py +++ b/api/tests/unit_tests/core/prompt/test_prompt_message.py @@ -1,4 +1,4 @@ -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.entities.message_entities import ( ImagePromptMessageContent, TextPromptMessageContent, UserPromptMessage, diff --git a/api/tests/unit_tests/core/prompt/test_prompt_transform.py b/api/tests/unit_tests/core/prompt/test_prompt_transform.py index 16896a0c6c..7976120547 100644 --- a/api/tests/unit_tests/core/prompt/test_prompt_transform.py +++ b/api/tests/unit_tests/core/prompt/test_prompt_transform.py @@ -2,10 +2,10 @@ # from core.app.app_config.entities import ModelConfigEntity # from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle -# from core.model_runtime.entities.message_entities import UserPromptMessage -# from core.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey, ParameterRule -# from core.model_runtime.entities.provider_entities import ProviderEntity -# from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel +# from dify_graph.model_runtime.entities.message_entities import UserPromptMessage +# from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey, ParameterRule +# from dify_graph.model_runtime.entities.provider_entities import ProviderEntity +# from dify_graph.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel # from core.prompt.prompt_transform import PromptTransform diff --git a/api/tests/unit_tests/core/prompt/test_simple_prompt_transform.py b/api/tests/unit_tests/core/prompt/test_simple_prompt_transform.py index c822ecbe78..2ef66e8a96 100644 --- a/api/tests/unit_tests/core/prompt/test_simple_prompt_transform.py +++ b/api/tests/unit_tests/core/prompt/test_simple_prompt_transform.py @@ -2,8 +2,8 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.memory.token_buffer_memory import TokenBufferMemory -from core.model_runtime.entities.message_entities import AssistantPromptMessage, UserPromptMessage from core.prompt.simple_prompt_transform import SimplePromptTransform +from dify_graph.model_runtime.entities.message_entities import AssistantPromptMessage, UserPromptMessage from models.model import AppMode, Conversation diff --git a/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py b/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py index 63596bc320..6e71f0c61f 100644 --- a/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py +++ b/api/tests/unit_tests/core/rag/embedding/test_embedding_service.py @@ -52,14 +52,14 @@ import pytest from sqlalchemy.exc import IntegrityError from core.entities.embedding_type import EmbeddingInputType -from core.model_runtime.entities.model_entities import ModelPropertyKey -from core.model_runtime.entities.text_embedding_entities import EmbeddingResult, EmbeddingUsage -from core.model_runtime.errors.invoke import ( +from core.rag.embedding.cached_embedding import CacheEmbedding +from dify_graph.model_runtime.entities.model_entities import ModelPropertyKey +from dify_graph.model_runtime.entities.text_embedding_entities import EmbeddingResult, EmbeddingUsage +from dify_graph.model_runtime.errors.invoke import ( InvokeAuthorizationError, InvokeConnectionError, InvokeRateLimitError, ) -from core.rag.embedding.cached_embedding import CacheEmbedding from models.dataset import Embedding diff --git a/api/tests/unit_tests/core/rag/indexing/test_indexing_runner.py b/api/tests/unit_tests/core/rag/indexing/test_indexing_runner.py index c00fee8fe5..b011ade884 100644 --- a/api/tests/unit_tests/core/rag/indexing/test_indexing_runner.py +++ b/api/tests/unit_tests/core/rag/indexing/test_indexing_runner.py @@ -61,9 +61,9 @@ from core.indexing_runner import ( DocumentIsPausedError, IndexingRunner, ) -from core.model_runtime.entities.model_entities import ModelType from core.rag.index_processor.constant.index_type import IndexStructureType from core.rag.models.document import ChildDocument, Document +from dify_graph.model_runtime.entities.model_entities import ModelType from libs.datetime_utils import naive_utc_now from models.dataset import Dataset, DatasetProcessRule from models.dataset import Document as DatasetDocument diff --git a/api/tests/unit_tests/core/rag/rerank/test_reranker.py b/api/tests/unit_tests/core/rag/rerank/test_reranker.py index e4597e7f8c..0e53482c51 100644 --- a/api/tests/unit_tests/core/rag/rerank/test_reranker.py +++ b/api/tests/unit_tests/core/rag/rerank/test_reranker.py @@ -17,13 +17,13 @@ from unittest.mock import MagicMock, Mock, patch import pytest from core.model_manager import ModelInstance -from core.model_runtime.entities.rerank_entities import RerankDocument, RerankResult from core.rag.models.document import Document from core.rag.rerank.entity.weight import KeywordSetting, VectorSetting, Weights from core.rag.rerank.rerank_factory import RerankRunnerFactory from core.rag.rerank.rerank_model import RerankModelRunner from core.rag.rerank.rerank_type import RerankMode from core.rag.rerank.weight_rerank import WeightRerankRunner +from dify_graph.model_runtime.entities.rerank_entities import RerankDocument, RerankResult def create_mock_model_instance(): diff --git a/api/tests/unit_tests/core/test_model_manager.py b/api/tests/unit_tests/core/test_model_manager.py index 5a7547e85c..92e4b58473 100644 --- a/api/tests/unit_tests/core/test_model_manager.py +++ b/api/tests/unit_tests/core/test_model_manager.py @@ -6,7 +6,7 @@ from pytest_mock import MockerFixture from core.entities.provider_entities import ModelLoadBalancingConfiguration from core.model_manager import LBModelManager -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from extensions.ext_redis import redis_client diff --git a/api/tests/unit_tests/core/test_provider_configuration.py b/api/tests/unit_tests/core/test_provider_configuration.py index 636fac7a40..90ed1647aa 100644 --- a/api/tests/unit_tests/core/test_provider_configuration.py +++ b/api/tests/unit_tests/core/test_provider_configuration.py @@ -12,9 +12,9 @@ from core.entities.provider_entities import ( RestrictModel, SystemConfiguration, ) -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ( +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ( ConfigurateMethod, CredentialFormSchema, FormOption, diff --git a/api/tests/unit_tests/core/test_provider_manager.py b/api/tests/unit_tests/core/test_provider_manager.py index 3163d53b87..3abfb8c9f8 100644 --- a/api/tests/unit_tests/core/test_provider_manager.py +++ b/api/tests/unit_tests/core/test_provider_manager.py @@ -2,8 +2,8 @@ import pytest from pytest_mock import MockerFixture from core.entities.provider_entities import ModelSettings -from core.model_runtime.entities.model_entities import ModelType from core.provider_manager import ProviderManager +from dify_graph.model_runtime.entities.model_entities import ModelType from models.provider import LoadBalancingModelConfig, ProviderModelSetting diff --git a/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py b/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py index b472ffdf1f..0df4927697 100644 --- a/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py +++ b/api/tests/unit_tests/core/workflow/entities/test_graph_runtime_state.py @@ -4,7 +4,7 @@ from unittest.mock import MagicMock, patch import pytest -from core.model_runtime.entities.llm_entities import LLMUsage +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper, VariablePool diff --git a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py index 2b882512c9..352e270fe4 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py @@ -4,10 +4,10 @@ from unittest.mock import MagicMock, patch from core.app.workflow.layers.llm_quota import LLMQuotaLayer from core.errors.error import QuotaExceededError -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import NodeType, WorkflowNodeExecutionStatus from dify_graph.graph_engine.entities.commands import CommandType from dify_graph.graph_events.node import NodeRunSucceededEvent +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import NodeRunResult diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py index 0403e91461..84e033156d 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_state_snapshot.py @@ -1,13 +1,13 @@ import time from collections.abc import Mapping -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.enums import NodeState from dify_graph.graph import Graph from dify_graph.graph_engine.graph_state_manager import GraphStateManager from dify_graph.graph_engine.ready_queue import InMemoryReadyQueue +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.end.end_node import EndNode from dify_graph.nodes.end.entities import EndNodeData from dify_graph.nodes.llm.entities import ( diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py index 9c075c31f4..695e99c1cf 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_multi_branch.py @@ -4,7 +4,6 @@ from collections.abc import Iterable from unittest import mock from unittest.mock import MagicMock -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.graph import Graph from dify_graph.graph_events import ( @@ -17,6 +16,7 @@ from dify_graph.graph_events import ( NodeRunSucceededEvent, ) from dify_graph.graph_events.node import NodeRunHumanInputFormFilledEvent +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType from dify_graph.nodes.end.end_node import EndNode from dify_graph.nodes.end.entities import EndNodeData diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py index 4f458a41d9..0275062c41 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_human_input_pause_single_branch.py @@ -3,7 +3,6 @@ import time from unittest import mock from unittest.mock import MagicMock -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.graph import Graph from dify_graph.graph_events import ( @@ -16,6 +15,7 @@ from dify_graph.graph_events import ( NodeRunSucceededEvent, ) from dify_graph.graph_events.node import NodeRunHumanInputFormFilledEvent +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType from dify_graph.nodes.end.end_node import EndNode from dify_graph.nodes.end.entities import EndNodeData diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py b/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py index de5d87ddad..fbcb8d7155 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_if_else_streaming.py @@ -1,8 +1,6 @@ import time from unittest import mock -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.graph import Graph from dify_graph.graph_events import ( @@ -12,6 +10,8 @@ from dify_graph.graph_events import ( NodeRunStreamChunkEvent, NodeRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.base.entities import OutputVariableEntity, OutputVariableType from dify_graph.nodes.end.end_node import EndNode from dify_graph.nodes.end.entities import EndNodeData diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py index 2c46cc53be..ad71227205 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_mock_nodes.py @@ -11,8 +11,8 @@ from typing import TYPE_CHECKING, Any, Optional from unittest.mock import MagicMock from core.model_manager import ModelInstance -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.enums import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import NodeRunResult, StreamChunkEvent, StreamCompletedEvent from dify_graph.nodes.agent import AgentNode from dify_graph.nodes.code import CodeNode diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py index 9d05dc5bd0..910292b52c 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_parallel_human_input_pause_missing_finish.py @@ -4,8 +4,6 @@ from dataclasses import dataclass from datetime import datetime, timedelta from typing import Any -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.entities.workflow_start_reason import WorkflowStartReason from dify_graph.graph import Graph @@ -19,6 +17,8 @@ from dify_graph.graph_events import ( NodeRunStartedEvent, NodeRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction from dify_graph.nodes.human_input.enums import HumanInputFormStatus from dify_graph.nodes.human_input.human_input_node import HumanInputNode diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py index ab212a9403..e5a9a29a1f 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_pause_deferred_ready_nodes.py @@ -4,8 +4,6 @@ from dataclasses import dataclass from datetime import datetime, timedelta from typing import Any -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.entities import GraphInitParams from dify_graph.entities.workflow_start_reason import WorkflowStartReason from dify_graph.graph import Graph @@ -18,6 +16,8 @@ from dify_graph.graph_events import ( NodeRunStartedEvent, NodeRunSucceededEvent, ) +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.nodes.end.end_node import EndNode from dify_graph.nodes.end.entities import EndNodeData from dify_graph.nodes.human_input.entities import HumanInputNodeData, UserAction diff --git a/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py b/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py index 5dcf36ed6a..98246ccb2f 100644 --- a/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/knowledge_retrieval/test_knowledge_retrieval_node.py @@ -5,9 +5,9 @@ from unittest.mock import Mock import pytest from core.app.entities.app_invoke_entities import InvokeFrom -from core.model_runtime.entities.llm_entities import LLMUsage from dify_graph.entities import GraphInitParams from dify_graph.enums import WorkflowNodeExecutionStatus +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.nodes.knowledge_retrieval.entities import ( KnowledgeRetrievalNodeData, MultipleRetrievalConfig, diff --git a/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py b/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py index aac5c296d8..18ec3c0dc4 100644 --- a/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/llm/test_node.py @@ -10,8 +10,11 @@ from core.app.llm.model_access import DifyCredentialsProvider, DifyModelFactory, from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle from core.entities.provider_entities import CustomConfiguration, SystemConfiguration from core.model_manager import ModelInstance -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.message_entities import ( +from core.prompt.entities.advanced_prompt_entities import MemoryConfig +from dify_graph.entities import GraphInitParams +from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, ImagePromptMessageContent, PromptMessage, @@ -19,11 +22,8 @@ from core.model_runtime.entities.message_entities import ( TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType -from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory -from core.prompt.entities.advanced_prompt_entities import MemoryConfig -from dify_graph.entities import GraphInitParams -from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType +from dify_graph.model_runtime.model_providers.model_provider_factory import ModelProviderFactory from dify_graph.nodes.llm import llm_utils from dify_graph.nodes.llm.entities import ( ContextConfig, diff --git a/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py b/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py index 44dbabb116..e40d565ef5 100644 --- a/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py +++ b/api/tests/unit_tests/core/workflow/nodes/llm/test_scenarios.py @@ -2,9 +2,9 @@ from collections.abc import Mapping, Sequence from pydantic import BaseModel, Field -from core.model_runtime.entities.message_entities import PromptMessage -from core.model_runtime.entities.model_entities import ModelFeature from dify_graph.file import File +from dify_graph.model_runtime.entities.message_entities import PromptMessage +from dify_graph.model_runtime.entities.model_entities import ModelFeature from dify_graph.nodes.llm.entities import LLMNodeChatModelMessage diff --git a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py index 110fdeedfb..7eca531b62 100644 --- a/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/parameter_extractor/test_parameter_extractor_node.py @@ -7,7 +7,7 @@ from typing import Any import pytest -from core.model_runtime.entities import LLMMode +from dify_graph.model_runtime.entities import LLMMode from dify_graph.nodes.llm import ModelConfig, VisionConfig from dify_graph.nodes.parameter_extractor.entities import ParameterConfig, ParameterExtractorNodeData from dify_graph.nodes.parameter_extractor.exc import ( diff --git a/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py b/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py index 1b72589cba..4dfec5ef60 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_question_classifier_node.py @@ -1,4 +1,4 @@ -from core.model_runtime.entities import ImagePromptMessageContent +from dify_graph.model_runtime.entities import ImagePromptMessageContent from dify_graph.nodes.question_classifier import QuestionClassifierNodeData diff --git a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py index c6e40bbd84..3d88baa272 100644 --- a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py @@ -8,11 +8,11 @@ from unittest.mock import MagicMock, patch import pytest -from core.model_runtime.entities.llm_entities import LLMUsage from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.utils.message_transformer import ToolFileMessageTransformer from dify_graph.entities import GraphInitParams from dify_graph.file import File, FileTransferMethod, FileType +from dify_graph.model_runtime.entities.llm_entities import LLMUsage from dify_graph.node_events import StreamChunkEvent, StreamCompletedEvent from dify_graph.runtime import GraphRuntimeState, VariablePool from dify_graph.system_variable import SystemVariable diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py index 10a108d425..06703b8e38 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py @@ -12,7 +12,6 @@ import pytest from pytest_mock import MockerFixture from sqlalchemy.orm import Session, sessionmaker -from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from dify_graph.entities import ( WorkflowNodeExecution, @@ -22,6 +21,7 @@ from dify_graph.enums import ( WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) +from dify_graph.model_runtime.utils.encoders import jsonable_encoder from dify_graph.repositories.workflow_node_execution_repository import OrderConfig from models.account import Account, Tenant from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom diff --git a/api/tests/unit_tests/services/document_service_validation.py b/api/tests/unit_tests/services/document_service_validation.py index 4923e29d73..6829691507 100644 --- a/api/tests/unit_tests/services/document_service_validation.py +++ b/api/tests/unit_tests/services/document_service_validation.py @@ -111,7 +111,7 @@ from unittest.mock import Mock, patch import pytest from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from models.dataset import Dataset, DatasetProcessRule, Document from services.dataset_service import DatasetService, DocumentService from services.entities.knowledge_entities.knowledge_entities import ( diff --git a/api/tests/unit_tests/services/test_dataset_service_create_dataset.py b/api/tests/unit_tests/services/test_dataset_service_create_dataset.py index 7c7a70f962..87a0d6b678 100644 --- a/api/tests/unit_tests/services/test_dataset_service_create_dataset.py +++ b/api/tests/unit_tests/services/test_dataset_service_create_dataset.py @@ -13,7 +13,7 @@ from uuid import uuid4 import pytest -from core.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.model_entities import ModelType from models.account import Account from models.dataset import Dataset, Pipeline from services.dataset_service import DatasetService diff --git a/api/tests/unit_tests/services/test_model_provider_service_sanitization.py b/api/tests/unit_tests/services/test_model_provider_service_sanitization.py index e2360b116d..6a6b63f003 100644 --- a/api/tests/unit_tests/services/test_model_provider_service_sanitization.py +++ b/api/tests/unit_tests/services/test_model_provider_service_sanitization.py @@ -3,9 +3,9 @@ import types import pytest from core.entities.provider_entities import CredentialConfiguration, CustomModelConfiguration -from core.model_runtime.entities.common_entities import I18nObject -from core.model_runtime.entities.model_entities import ModelType -from core.model_runtime.entities.provider_entities import ConfigurateMethod +from dify_graph.model_runtime.entities.common_entities import I18nObject +from dify_graph.model_runtime.entities.model_entities import ModelType +from dify_graph.model_runtime.entities.provider_entities import ConfigurateMethod from models.provider import ProviderType from services.model_provider_service import ModelProviderService diff --git a/api/tests/unit_tests/services/workflow/test_workflow_converter.py b/api/tests/unit_tests/services/workflow/test_workflow_converter.py index fefd771546..a847c2b4d1 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_converter.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_converter.py @@ -15,8 +15,8 @@ from core.app.app_config.entities import ( PromptTemplateEntity, ) from core.helper import encrypter -from core.model_runtime.entities.llm_entities import LLMMode -from core.model_runtime.entities.message_entities import PromptMessageRole +from dify_graph.model_runtime.entities.llm_entities import LLMMode +from dify_graph.model_runtime.entities.message_entities import PromptMessageRole from dify_graph.variables.input_entities import VariableEntity, VariableEntityType from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint from models.model import AppMode diff --git a/api/tests/unit_tests/tools/test_mcp_tool.py b/api/tests/unit_tests/tools/test_mcp_tool.py index 5930b63f58..fa9c6af287 100644 --- a/api/tests/unit_tests/tools/test_mcp_tool.py +++ b/api/tests/unit_tests/tools/test_mcp_tool.py @@ -13,11 +13,11 @@ from core.mcp.types import ( TextContent, TextResourceContents, ) -from core.model_runtime.entities.llm_entities import LLMUsage from core.tools.__base.tool_runtime import ToolRuntime from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_entities import ToolEntity, ToolIdentity, ToolInvokeMessage from core.tools.mcp_tool.tool import MCPTool +from dify_graph.model_runtime.entities.llm_entities import LLMUsage def _make_mcp_tool(output_schema: dict | None = None) -> MCPTool: diff --git a/api/tests/unit_tests/utils/structured_output_parser/test_structured_output_parser.py b/api/tests/unit_tests/utils/structured_output_parser/test_structured_output_parser.py index 9a0dbfa2d8..7ec1343f98 100644 --- a/api/tests/unit_tests/utils/structured_output_parser/test_structured_output_parser.py +++ b/api/tests/unit_tests/utils/structured_output_parser/test_structured_output_parser.py @@ -5,7 +5,7 @@ import pytest from core.llm_generator.output_parser.errors import OutputParserError from core.llm_generator.output_parser.structured_output import invoke_llm_with_structured_output -from core.model_runtime.entities.llm_entities import ( +from dify_graph.model_runtime.entities.llm_entities import ( LLMResult, LLMResultChunk, LLMResultChunkDelta, @@ -13,13 +13,13 @@ from core.model_runtime.entities.llm_entities import ( LLMResultWithStructuredOutput, LLMUsage, ) -from core.model_runtime.entities.message_entities import ( +from dify_graph.model_runtime.entities.message_entities import ( AssistantPromptMessage, SystemPromptMessage, TextPromptMessageContent, UserPromptMessage, ) -from core.model_runtime.entities.model_entities import AIModelEntity, ModelType +from dify_graph.model_runtime.entities.model_entities import AIModelEntity, ModelType def create_mock_usage(prompt_tokens: int = 10, completion_tokens: int = 5) -> LLMUsage: From d6ab36ff1ea263bc1249520b31e379f5e7985d10 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Tue, 3 Mar 2026 11:21:04 +0800 Subject: [PATCH 019/159] chore: update vinext, add workaround (#32878) --- .../components/devtools/react-scan/loader.tsx | 20 +-- .../components/devtools/react-scan/scan.tsx | 22 --- .../plugins/marketplace/hydration-server.tsx | 4 + web/app/layout.tsx | 3 +- web/app/sw.ts | 1 - web/package.json | 4 +- web/pnpm-lock.yaml | 144 +++++++----------- 7 files changed, 74 insertions(+), 124 deletions(-) delete mode 100644 web/app/components/devtools/react-scan/scan.tsx diff --git a/web/app/components/devtools/react-scan/loader.tsx b/web/app/components/devtools/react-scan/loader.tsx index ee702216f7..a5956d7825 100644 --- a/web/app/components/devtools/react-scan/loader.tsx +++ b/web/app/components/devtools/react-scan/loader.tsx @@ -1,21 +1,15 @@ -'use client' - -import { lazy, Suspense } from 'react' +import Script from 'next/script' import { IS_DEV } from '@/config' -const ReactScan = lazy(() => - import('./scan').then(module => ({ - default: module.ReactScan, - })), -) - -export const ReactScanLoader = () => { +export function ReactScanLoader() { if (!IS_DEV) return null return ( - - - + ') - }) - - it('renders empty script tag when child value is undefined', () => { - const node: ScriptNode = { - children: [{}], - } - - const { container } = render( - , - ) - - expect(container.textContent).toBe('') - }) - - it('renders empty script tag when children array is empty', () => { - const node: ScriptNode = { - children: [], - } - - const { container } = render( - , - ) - - expect(container.textContent).toBe('') - }) - - it('preserves multiline script content', () => { - const multi = `console.log("line1"); -console.log("line2");` - - const node: ScriptNode = { - children: [{ value: multi }], - } - - const { container } = render( - , - ) - - expect(container.textContent).toBe(``) - }) - - it('has displayName set correctly', () => { - expect(ScriptBlock.displayName).toBe('ScriptBlock') - }) -}) diff --git a/web/app/components/base/markdown-blocks/code-block.tsx b/web/app/components/base/markdown-blocks/code-block.tsx index 744a578ff6..837929cfff 100644 --- a/web/app/components/base/markdown-blocks/code-block.tsx +++ b/web/app/components/base/markdown-blocks/code-block.tsx @@ -399,7 +399,6 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any }} language={match?.[1]} showLineNumbers - PreTag="div" > {content} @@ -413,7 +412,7 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any return (
-
{languageShowName}
+
{languageShowName}
{language === 'svg' && } diff --git a/web/app/components/base/markdown-blocks/form.tsx b/web/app/components/base/markdown-blocks/form.tsx index bce05bc585..36597cd13c 100644 --- a/web/app/components/base/markdown-blocks/form.tsx +++ b/web/app/components/base/markdown-blocks/form.tsx @@ -1,14 +1,16 @@ +import type { Dayjs } from 'dayjs' +import type { ButtonProps } from '@/app/components/base/button' import * as React from 'react' -import { useEffect, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' import Button from '@/app/components/base/button' import { useChatContext } from '@/app/components/base/chat/chat/context' import Checkbox from '@/app/components/base/checkbox' import DatePicker from '@/app/components/base/date-and-time-picker/date-picker' import TimePicker from '@/app/components/base/date-and-time-picker/time-picker' -import { formatDateForOutput } from '@/app/components/base/date-and-time-picker/utils/dayjs' +import { formatDateForOutput, toDayjs } from '@/app/components/base/date-and-time-picker/utils/dayjs' import Input from '@/app/components/base/input' -import Select from '@/app/components/base/select' import Textarea from '@/app/components/base/textarea' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/app/components/base/ui/select' enum DATA_FORMAT { TEXT = 'text', @@ -32,238 +34,359 @@ enum SUPPORTED_TYPES { SELECT = 'select', HIDDEN = 'hidden', } -const MarkdownForm = ({ node }: any) => { - const { onSend } = useChatContext() - const [formValues, setFormValues] = useState<{ [key: string]: any }>({}) +const SUPPORTED_TYPES_SET = new Set(Object.values(SUPPORTED_TYPES)) - useEffect(() => { - const initialValues: { [key: string]: any } = {} - node.children.forEach((child: any) => { - if ([SUPPORTED_TAGS.INPUT, SUPPORTED_TAGS.TEXTAREA].includes(child.tagName)) { - initialValues[child.properties.name] - = (child.tagName === SUPPORTED_TAGS.INPUT && child.properties.type === SUPPORTED_TYPES.HIDDEN) - ? (child.properties.value || '') - : child.properties.value - } - }) - setFormValues(initialValues) - }, [node.children]) +const SAFE_NAME_RE = /^[a-z][\w-]*$/i +const PROTOTYPE_POISON_KEYS = new Set(['__proto__', 'constructor', 'prototype']) - const getFormValues = (children: any) => { - const values: { [key: string]: any } = {} - children.forEach((child: any) => { - if ([SUPPORTED_TAGS.INPUT, SUPPORTED_TAGS.TEXTAREA].includes(child.tagName)) { - let value = formValues[child.properties.name] +function isSafeName(name: unknown): name is string { + return typeof name === 'string' + && name.length > 0 + && name.length <= 128 + && SAFE_NAME_RE.test(name) + && !PROTOTYPE_POISON_KEYS.has(name) +} - if (child.tagName === SUPPORTED_TAGS.INPUT - && (child.properties.type === SUPPORTED_TYPES.DATE || child.properties.type === SUPPORTED_TYPES.DATETIME)) { - if (value && typeof value.format === 'function') { - // Format date output consistently - const includeTime = child.properties.type === SUPPORTED_TYPES.DATETIME - value = formatDateForOutput(value, includeTime) - } - } +const VALID_BUTTON_VARIANTS = new Set([ + 'primary', + 'warning', + 'secondary', + 'secondary-accent', + 'ghost', + 'ghost-accent', + 'tertiary', +]) +const VALID_BUTTON_SIZES = new Set(['small', 'medium', 'large']) - values[child.properties.name] = value - } - }) - return values - } +type HastText = { + type: 'text' + value: string +} - const onSubmit = (e: any) => { - e.preventDefault() - const format = node.properties.dataFormat || DATA_FORMAT.TEXT - const result = getFormValues(node.children) +type HastElement = { + type: 'element' + tagName: string + properties: Record + children: Array +} - if (format === DATA_FORMAT.JSON) { - onSend?.(JSON.stringify(result)) +type FormValue = string | boolean | Dayjs | undefined +type FormValues = Record +type EditState = { + source: HastElement[] + edits: FormValues +} + +function getTextContent(node: HastElement): string { + const textChild = node.children.find((c): c is HastText => c.type === 'text') + return textChild?.value ?? '' +} + +function str(val: unknown): string { + if (val == null) + return '' + return String(val) +} + +function computeInitialFormValues(children: HastElement[]): FormValues { + const init: FormValues = Object.create(null) as FormValues + for (const child of children) { + if (child.tagName !== SUPPORTED_TAGS.INPUT && child.tagName !== SUPPORTED_TAGS.TEXTAREA) + continue + const name = child.properties.name + if (!isSafeName(name)) + continue + + const type = child.tagName === SUPPORTED_TAGS.INPUT ? str(child.properties.type) : '' + + if (type === SUPPORTED_TYPES.HIDDEN) { + init[name] = str(child.properties.value) + } + else if (type === SUPPORTED_TYPES.DATE || type === SUPPORTED_TYPES.DATETIME || type === SUPPORTED_TYPES.TIME) { + const raw = child.properties.value + init[name] = raw != null ? toDayjs(String(raw)) : undefined + } + else if (type === SUPPORTED_TYPES.CHECKBOX) { + const { checked, value } = child.properties + init[name] = !!checked || value === true || value === 'true' } else { - const textResult = Object.entries(result) - .map(([key, value]) => `${key}: ${value}`) - .join('\n') - onSend?.(textResult) + init[name] = child.properties.value != null ? str(child.properties.value) : undefined } } + return init +} + +function getElementKey(child: HastElement, index: number): string { + const tag = child.tagName + const name = str(child.properties.name) + const htmlFor = str(child.properties.htmlFor) + const type = str(child.properties.type) + + if (tag === SUPPORTED_TAGS.LABEL) + return `label-${index}-${htmlFor || name}` + if (tag === SUPPORTED_TAGS.INPUT) + return `input-${index}-${type}-${name}` + if (tag === SUPPORTED_TAGS.TEXTAREA) + return `textarea-${index}-${name}` + if (tag === SUPPORTED_TAGS.BUTTON) + return `button-${index}-${getTextContent(child)}` + return `${tag}-${index}` +} + +const MarkdownForm = ({ node }: { node: HastElement }) => { + const typedNode = node + const { onSend } = useChatContext() + const [isSubmitting, setIsSubmitting] = useState(false) + + const elementChildren = useMemo( + () => typedNode.children.filter((c): c is HastElement => c.type === 'element'), + [typedNode.children], + ) + + const baseFormValues = useMemo( + () => computeInitialFormValues(elementChildren), + [elementChildren], + ) + + const [editState, setEditState] = useState(() => ({ + source: elementChildren, + edits: {}, + })) + + const formValues = useMemo(() => { + if (editState.source === elementChildren) + return { ...baseFormValues, ...editState.edits } + return baseFormValues + }, [editState, baseFormValues, elementChildren]) + + const updateValue = useCallback((name: string, value: FormValue) => { + if (!isSafeName(name)) + return + setEditState(prev => ({ + source: elementChildren, + edits: { + ...(prev.source === elementChildren ? prev.edits : {}), + [name]: value, + }, + })) + }, [elementChildren]) + + const getFormOutput = useCallback((): Record => { + const out = Object.create(null) as Record + for (const child of elementChildren) { + if (child.tagName !== SUPPORTED_TAGS.INPUT && child.tagName !== SUPPORTED_TAGS.TEXTAREA) + continue + const name = child.properties.name + if (!isSafeName(name)) + continue + let value: FormValue = formValues[name] + if ( + child.tagName === SUPPORTED_TAGS.INPUT + && (child.properties.type === SUPPORTED_TYPES.DATE || child.properties.type === SUPPORTED_TYPES.DATETIME) + && value != null + && typeof value === 'object' + && 'format' in value + ) { + const includeTime = child.properties.type === SUPPORTED_TYPES.DATETIME + value = formatDateForOutput(value as Dayjs, includeTime) + } + if (typeof value === 'boolean') + out[name] = value + else + out[name] = value != null ? String(value) : undefined + } + return out + }, [elementChildren, formValues]) + + const onSubmit = useCallback((e: React.MouseEvent) => { + e.preventDefault() + if (isSubmitting) + return + setIsSubmitting(true) + try { + const format = str(typedNode.properties.dataFormat) || DATA_FORMAT.TEXT + const result = getFormOutput() + if (format === DATA_FORMAT.JSON) { + onSend?.(JSON.stringify(result)) + } + else { + const textResult = Object.entries(result) + .map(([key, value]) => `${key}: ${value}`) + .join('\n') + onSend?.(textResult) + } + } + catch { + setIsSubmitting(false) + } + }, [isSubmitting, typedNode.properties.dataFormat, getFormOutput, onSend]) + return (
{ + onSubmit={(e) => { e.preventDefault() e.stopPropagation() }} > - {node.children.filter((i: any) => i.type === 'element').map((child: any, index: number) => { + {elementChildren.map((child, index) => { + const key = getElementKey(child, index) if (child.tagName === SUPPORTED_TAGS.LABEL) { return ( ) } - if (child.tagName === SUPPORTED_TAGS.INPUT && Object.values(SUPPORTED_TYPES).includes(child.properties.type)) { - if (child.properties.type === SUPPORTED_TYPES.DATE || child.properties.type === SUPPORTED_TYPES.DATETIME) { + + if (child.tagName === SUPPORTED_TAGS.INPUT && SUPPORTED_TYPES_SET.has(str(child.properties.type))) { + const name = str(child.properties.name) + if (!isSafeName(name)) + return null + + const type = str(child.properties.type) as SUPPORTED_TYPES + + if (type === SUPPORTED_TYPES.DATE || type === SUPPORTED_TYPES.DATETIME) { return ( { - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: date, - })) - }} - onClear={() => { - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: undefined, - })) - }} + key={key} + value={formValues[name] as Dayjs | undefined} + needTimePicker={type === SUPPORTED_TYPES.DATETIME} + onChange={date => updateValue(name, date)} + onClear={() => updateValue(name, undefined)} /> ) } - if (child.properties.type === SUPPORTED_TYPES.TIME) { + if (type === SUPPORTED_TYPES.TIME) { return ( { - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: time, - })) - }} - onClear={() => { - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: undefined, - })) - }} + key={key} + value={formValues[name] as Dayjs | string | undefined} + onChange={time => updateValue(name, time)} + onClear={() => updateValue(name, undefined)} /> ) } - if (child.properties.type === SUPPORTED_TYPES.CHECKBOX) { + if (type === SUPPORTED_TYPES.CHECKBOX) { return ( -
+
{ - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: !prevValues[child.properties.name], - })) - }} - id={child.properties.name} + checked={!!formValues[name]} + onCheck={() => updateValue(name, !formValues[name])} + id={name} /> - {child.properties.dataTip || child.properties['data-tip'] || ''} + {str(child.properties.dataTip || child.properties['data-tip'])}
) } - if (child.properties.type === SUPPORTED_TYPES.SELECT) { + if (type === SUPPORTED_TYPES.SELECT) { + const rawOptions = child.properties.dataOptions || child.properties['data-options'] || [] + let options: string[] = [] + if (typeof rawOptions === 'string') { + try { + const parsed: unknown = JSON.parse(rawOptions) + if (Array.isArray(parsed)) + options = parsed.filter((o): o is string => typeof o === 'string') + } + catch (error) { + console.error('Failed to parse data-options JSON:', rawOptions, error) + options = [] + } + } + else if (Array.isArray(rawOptions)) { + options = rawOptions.filter((o): o is string => typeof o === 'string') + } return ( ) } - if (child.properties.type === SUPPORTED_TYPES.HIDDEN) { + if (type === SUPPORTED_TYPES.HIDDEN) { return ( ) } return ( { - setFormValues(prevValues => ({ - ...prevValues, - [child.properties.name]: e.target.value, - })) - }} + key={key} + type={type} + name={name} + placeholder={str(child.properties.placeholder)} + value={str(formValues[name])} + onChange={e => updateValue(name, e.target.value)} /> ) } + if (child.tagName === SUPPORTED_TAGS.TEXTAREA) { + const name = str(child.properties.name) + if (!isSafeName(name)) + return null return (