Skip to content

feat(rag): add opt-in wolfxl reader for .xlsx extraction - #44849

Closed
wolfiesch wants to merge 4 commits into
langgenius:mainfrom
wolfiesch:feat/optional-wolfxl-xlsx-20261026
Closed

wolfiesch wants to merge 4 commits into
langgenius:mainfrom
wolfiesch:feat/optional-wolfxl-xlsx-20261026

Conversation

@wolfiesch

@wolfiesch wolfiesch commented Oct 27, 2026 •

Copy link
Copy Markdown

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue
  3. Use the correct syntax to link this PR to its associated issue.

Summary

Some .xlsx uploads index nothing today, and no error is raised. openpyxl 3.1.5 does not read Strict Open XML workbooks (the ISO/IEC 29500 Strict namespace, which Excel writes from "Save As > Strict Open XML Spreadsheet"). ExcelExtractor sees no cells and returns zero documents. Several other workbooks make openpyxl raise inside its style parser, so their upload fails.

This PR adds wolfxl as an optional, non-default reader for .xlsx extraction. It adds a xlsx-wolfxl = ["wolfxl>=2.0.35,<2.1"] dependency group and a guarded import; uv sync --project api --group xlsx-wolfxl opts in. If wolfxl is not installed, openpyxl remains the reader, and default installs and Docker images are unchanged. Errors inside an installed wolfxl package and workbook parse failures propagate without retrying another reader. The .xls path is unchanged.

I maintain wolfxl. Decision needed from maintainers: whether to accept wolfxl as an optional, non-default xlsx-wolfxl dependency group. Fixes #44848

This branch is stacked on #45182 (first commit), a reader-independent fix for trailing image-only rows. Review that PR first; once it merges, this diff is the reader change only.

Files openpyxl cannot read

Apache POI test fixtures at 4f3c25563919e7efa4a75feccf6cef1ac3d05a04, run through the extractor with wolfxl 2.0.35 and openpyxl 3.1.5. Reference: LibreOffice converts each file to transitional .xlsx, which openpyxl then reads through the same extractor.

File openpyxl on original wolfxl Reference wolfxl vs reference
57914.xlsx (Strict) 0 docs 1 1 identical
SampleSS.strict.xlsx 0 docs 2 2 identical
SimpleStrict.xlsx 0 docs 7 7 one date cell differs1
sample.strict.xlsx 0 docs 12 12 identical
picture.xlsx TypeError 9 9 identical
style-alternate-content.xlsx TypeError 24 24 identical
LIBRE_OFFICE-128382-0.xlsx TypeError 32 32 2 pivot labels differ2

Not claimed: sample-beta.xlsx (pre-release Excel 2007 beta namespace) also returns 0 documents with openpyxl. wolfxl reads only its numeric column, and LibreOffice reads nothing. invalid_cell_reference.xlsx raises ValueError in openpyxl and yields 0 documents in both wolfxl and the reference. duplicate-filename-case-insensitive.xlsx is the only fixture openpyxl reads and wolfxl rejects: wolfxl deliberately refuses duplicate ZIP member names.

Across all 353 .xlsx fixtures (wolfxl 2.0.35, Linux and macOS): 312 identical document hash, count, and image-count results; the 5 zero-document files above; 30 files where both readers raise; 4 wolfxl-only reads; 1 openpyxl-only read; 1 hostile input (a shared-strings memory bomb) that neither reader survives. Every per-file result matches the earlier 2.0.17 sweep. This is not a full parity or bounded-memory proof.

Appendix: speed

On 300,000 rows x 7 columns, the extraction loop runs 2.1x (macOS) to 2.5x (Linux) faster with wolfxl 2.0.35 than with openpyxl 3.1.5, with lower peak memory on both:

Platform openpyxl median s wolfxl median s Peak RSS MiB, openpyxl / wolfxl
Linux x86_64 (Ryzen 9950X3D), CPython 3.13.15 14.808 5.863 946.9 / 737.5
macOS arm64 (M4 Pro), CPython 3.13.9 12.800 6.130 1030.7 / 759.6

Five fresh-process runs per arm, alternating, warm page cache, no discarded warmup; every run produced the same 300,000 documents. Timing covers a standalone copy of the extractor loop at 12ab116fffd4706c20eb618d706cc71e094b519e and excludes imports, Document construction, database, and storage. The input is 11.7 MB, under the default 15 MB UPLOAD_FILE_SIZE_LIMIT. On a 300-row input wolfxl takes 10 to 11 ms against 12 to 13 ms, with about 1 MiB higher peak RSS. Evidence archive with inputs, drivers, raw timing samples, per-file corpus results, and host details: dify-xlsx-evidence-2.0.35.zip (SHA256 2b07ed76f5bc7ffcdca5984e460bbfe135c95728b2b2de17e6613978958a869f); its README has the rerun commands, and sha256sum -c SHA256SUMS.txt verifies it.

Verification

Head 28c4c7e115 on upstream main dca4024e5777f44a8cc4937f898483c11ecbd62d, macOS arm64, CPython 3.13.15, wolfxl 2.0.35. Environments: uv sync --project api --exact --dev, plus --group xlsx-wolfxl for opt-in.

  • pytest tests/unit_tests/core/rag/extractor/test_excel_extractor.py: 12 passed in each environment. Default asserts wolfxl absent and the openpyxl loader; opt-in asserts the wolfxl 2.0.35 loader.
  • make type-check-core with UV_NO_SYNC=1: passed with wolfxl absent and installed.
  • ruff check and ruff format --check on the changed files, uv lock --check: passed.

Full make lint, make test, and frontend checks were not run locally.

Screenshots

Before After
Not applicable: backend-only change Not applicable: backend-only change

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've verified the change and added or updated tests where meaningful regression risk justifies coverage.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and vp staged (frontend) to appease the lint gods

Footnotes

  1. The Strict file stores the cell as an ISO date (t="d", 1990-01-01). wolfxl reads it as a date, as openpyxl does for that cell type, and indexes 1990-01-01. LibreOffice converts it to a serial datetime, which the reference indexes as 1990-01-01 00:00:00. ↩

  2. wolfxl indexes the labels stored in the file (Row titles, Grand Total). LibreOffice regenerates them on conversion (Item, Total Result). ↩

@github-actions github-actions Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-10-30 13:10:37.366332530 +0000
+++ /tmp/pyrefly_pr.txt	2026-10-30 13:10:21.966184713 +0000
@@ -162,28 +162,10 @@
   --> providers/vdb/vdb-tencent/tests/e2e_tests/conftest.py:95:33
 ERROR Object of class `ModuleType` has no attribute `VectorType` [missing-attribute]
   --> providers/vdb/vdb-tidb-vector/tests/unit_tests/src/dify_vdb_tidb_vector/test_tidb_vector.py:77:5
-ERROR Unpacked keyword argument `str` is not assignable to parameter `port` with type `int | None` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `grpc_port` with type `int` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `prefer_grpc` with type `bool` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `https` with type `bool | None` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `timeout` with type `int | None` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `force_disable_check_same_thread` with type `bool` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `grpc_options` with type `dict[str, Any] | None` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR Unpacked keyword argument `str` is not assignable to parameter `auth_token_provider` with type `(() -> Awaitable[str]) | (() -> str) | None` in function `qdrant_client.qdrant_client.QdrantClient.__init__` [bad-argument-type]
-  --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_on_qdrant_vector.py:93:51
-ERROR `None` is not subscriptable [unsupported-operation]
-   --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_service.py:152:20
-ERROR `None` is not subscriptable [unsupported-operation]
-   --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_service.py:153:35
-ERROR Argument `Any | None` is not assignable to parameter `cluster_response` with type `Mapping[str, Any]` in function `TidbService.extract_qdrant_endpoint` [bad-argument-type]
-   --> providers/vdb/vdb-tidb-on-qdrant/src/dify_vdb_tidb_on_qdrant/tidb_service.py:154:75
+ERROR Argument `ModuleSpec | None` is not assignable to parameter `spec` with type `ModuleSpec` in function `_frozen_importlib.module_from_spec` [bad-argument-type]
+  --> tests/unit_tests/migrations/versions/test_2025_07_02_2332-1c9ba48be8e4_add_uuidv7_function_in_sql.py:31:46
+ERROR Object of class `NoneType` has no attribute `loader` [missing-attribute]
+  --> tests/unit_tests/migrations/versions/test_2025_07_02_2332-1c9ba48be8e4_add_uuidv7_function_in_sql.py:32:5
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/controllers/console/app/test_chat_conversation_status_count_api.py:75:16
 ERROR Argument `Literal['app-run']` is not assignable to parameter `triggered_from` with type `SQLCoreOperations[WorkflowRunTriggeredFrom] | WorkflowRunTriggeredFrom` in function `models.workflow.WorkflowRun.__init__` [bad-argument-type]
@@ -198,6 +180,8 @@
    --> tests/e2e_tests/containers/controllers/console/app/test_chat_conversation_status_count_api.py:123:27
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `MessageStatus | SQLCoreOperations[MessageStatus]` in function `models.model.Message.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/controllers/console/app/test_chat_conversation_status_count_api.py:125:16
+ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
+  --> tests/e2e_tests/containers/controllers/console/app/test_conversation_read_timestamp.py:28:16
 ERROR Returned type `set[str | None]` is not assignable to declared return type `set[str]` [bad-return]
    --> tests/e2e_tests/containers/controllers/console/test_apikey.py:221:16
 ERROR Object of class `FunctionType` has no attribute `__handler__` [missing-attribute]
@@ -217,7 +201,7 @@
 ERROR Object of class `FunctionType` has no attribute `__handler__` [missing-attribute]
    --> tests/e2e_tests/containers/controllers/openapi/test_account_sessions.py:153:17
 ERROR Object of class `FunctionType` has no attribute `__handler__` [missing-attribute]
-  --> tests/e2e_tests/containers/controllers/openapi/test_app_run.py:46:13
+  --> tests/e2e_tests/containers/controllers/openapi/test_app_run.py:41:22
 ERROR Object of class `FunctionType` has no attribute `__handler__` [missing-attribute]
   --> tests/e2e_tests/containers/controllers/openapi/test_workspaces.py:27:22
 ERROR Object of class `FunctionType` has no attribute `__handler__` [missing-attribute]
@@ -309,7 +293,7 @@
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
    --> tests/e2e_tests/containers/core/rag/retrieval/test_dataset_retrieval_integration.py:598:23
 ERROR Argument `str` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/core/workflow/test_human_input_resume_node_execution.py:187:23
+   --> tests/e2e_tests/containers/core/workflow/test_human_input_resume_node_execution.py:186:23
 ERROR Argument `Literal['owner']` is not assignable to parameter `role` with type `SQLCoreOperations[TenantAccountRole] | TenantAccountRole` in function `models.account.TenantAccountJoin.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/helpers/execution_extra_content.py:48:14
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
@@ -335,7 +319,7 @@
 ERROR Argument `Literal['workflow-run']` is not assignable to parameter `triggered_from` with type `SQLCoreOperations[WorkflowNodeExecutionTriggeredFrom] | WorkflowNodeExecutionTriggeredFrom` in function `models.workflow.WorkflowNodeExecutionModel.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_api_workflow_node_execution_repository.py:39:24
 ERROR Generator function should return `Generator` [bad-return]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_api_workflow_run_repository.py:150:56
+   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_api_workflow_run_repository.py:151:56
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:103:14
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
@@ -344,50 +328,6 @@
    --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:125:14
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:130:16
-ERROR Object of class `HumanInputFormReference` has no attribute `submitted` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:348:16
-ERROR Object of class `HumanInputFormReference` has no attribute `form_submission_data` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:350:16
-ERROR Object of class `object` has no attribute `action_id` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:351:16
-ERROR Object of class `object` has no attribute `action_text` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:352:16
-ERROR Object of class `object` has no attribute `rendered_content` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:353:16
-ERROR Object of class `object` has no attribute `node_id` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:354:16
-ERROR Object of class `object` has no attribute `node_title` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:355:16
-ERROR Object of class `HumanInputFormReference` has no attribute `form_submission_data` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:386:16
-ERROR Object of class `object` has no attribute `submitted_data` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:387:16
-ERROR Object of class `HumanInputFormReference` has no attribute `form_submission_data` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:474:16
-ERROR Object of class `object` has no attribute `submitted_data` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:475:16
-ERROR Object of class `object` has no attribute `rendered_content` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:476:16
-ERROR Object of class `HumanInputFormReference` has no attribute `submitted` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:517:16
-ERROR Object of class `HumanInputFormReference` has no attribute `form_definition` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:519:16
-ERROR Object of class `object` has no attribute `form_id` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:521:16
-ERROR Object of class `object` has no attribute `node_id` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:522:16
-ERROR Object of class `object` has no attribute `node_title` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:523:16
-ERROR Object of class `object` has no attribute `form_content` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:524:16
-ERROR Object of class `object` has no attribute `display_in_ui` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:525:16
-ERROR Object of class `object` has no attribute `form_token` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:526:16
-ERROR Object of class `object` has no attribute `resolved_default_values` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:527:16
-ERROR Object of class `object` has no attribute `expiration_time` [missing-attribute]
-   --> tests/e2e_tests/containers/repositories/test_sqlalchemy_execution_extra_content_repository.py:528:16
 ERROR Argument `str | None` is not assignable to parameter `tenant_id` with type `str` in function `_create_node_execution_model` [bad-argument-type]
    --> tests/e2e_tests/containers/repositories/test_sqlalchemy_workflow_node_execution_repository.py:184:23
 ERROR Argument `str | None` is not assignable to parameter `tenant_id` with type `str` in function `_create_node_execution_model` [bad-argument-type]
@@ -468,6 +408,38 @@
    --> tests/e2e_tests/containers/services/test_agent_service.py:953:24
 ERROR Argument `str | None` is not assignable to parameter `created_by` with type `SQLCoreOperations[str] | str` in function `models.model.MessageAgentThought.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/services/test_agent_service.py:993:24
+ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:103:38
+ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:106:81
+ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:144:20
+ERROR Argument `Literal[0]` is not assignable to parameter `message_unit_price` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:173:32
+ERROR Argument `float` is not assignable to parameter `message_price_unit` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:174:32
+ERROR Argument `Literal[0]` is not assignable to parameter `answer_unit_price` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:177:31
+ERROR Argument `float` is not assignable to parameter `answer_price_unit` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:178:31
+ERROR Argument `Literal[0]` is not assignable to parameter `total_price` with type `Decimal | SQLCoreOperations[Decimal | None] | None` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:181:25
+ERROR Argument `dict[str, str | None]` is not assignable to parameter `args` with type `InsertAnnotationArgs` in function `services.annotation_service.AppAnnotationService.insert_app_annotation_directly` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:245:65
+ERROR Object of class `str` has no attribute `decode` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:730:33
+ERROR Object of class `int` has no attribute `lower` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_annotation_service.py:959:27
+ERROR Object of class `int` has no attribute `lower` [missing-attribute]
+    --> tests/e2e_tests/containers/services/test_annotation_service.py:1005:27
+ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `id` [bad-typed-dict-key]
+    --> tests/e2e_tests/containers/services/test_annotation_service.py:1047:23
+ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `score_threshold` [bad-typed-dict-key]
+    --> tests/e2e_tests/containers/services/test_annotation_service.py:1048:23
+ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `embedding_model` [bad-typed-dict-key]
+    --> tests/e2e_tests/containers/services/test_annotation_service.py:1049:23
+ERROR TypedDict `AnnotationSettingDisabledDict` does not have key `embedding_model` [bad-typed-dict-key]
+    --> tests/e2e_tests/containers/services/test_annotation_service.py:1050:23
 ERROR Unpacked keyword argument `AppMode | IconType | bool | str | Any` is not assignable to parameter `access_mode` with type `str | None` in function `models.model.App.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/services/test_app_dsl_service.py:109:15
 ERROR Unpacked keyword argument `AppMode | IconType | bool | str | Any` is not assignable to parameter `has_draft_trigger` with type `bool` in function `models.model.App.__init__` [bad-argument-type]
@@ -535,25 +507,25 @@
 ERROR Argument `Literal['workflow']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
     --> tests/e2e_tests/containers/services/test_app_dsl_service.py:1336:20
 ERROR Argument `list[SimpleNamespace]` is not assignable to parameter `dsl_dependencies` with type `list[PluginDependency]` in function `services.app_dsl_service.AppDslService.get_leaked_dependencies` [bad-argument-type]
-    --> tests/e2e_tests/containers/services/test_app_dsl_service.py:1618:73
+    --> tests/e2e_tests/containers/services/test_app_dsl_service.py:1611:73
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:196:38
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:199:38
 ERROR Argument `str | None` is not assignable to parameter `created_by` with type `SQLCoreOperations[str] | str` in function `models.workflow.Workflow.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:223:24
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:226:24
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:497:23
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:500:23
 ERROR Argument `Literal['invalid_mode']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:576:20
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:579:20
 WARN Module `sqlalchemy.exc` exists, but was not imported explicitly. You are relying on other modules to load it. [implicit-import]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:583:41
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:586:41
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:837:18
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:840:18
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:869:18
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:872:18
 ERROR Argument `dict[str, dict[str, str]]` is not assignable to parameter `args` with type `LoopNodeRunPayload` in function `services.app_generate_service.AppGenerateService.generate_single_loop` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_app_generate_service.py:900:22
+   --> tests/e2e_tests/containers/services/test_app_generate_service.py:903:22
 ERROR Argument `Literal['agent-chat']` is not assignable to parameter `value` with type `AppMode | SQLCoreOperations[AppMode]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-    --> tests/e2e_tests/containers/services/test_app_generate_service.py:1017:20
+    --> tests/e2e_tests/containers/services/test_app_generate_service.py:1020:20
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
   --> tests/e2e_tests/containers/services/test_app_service.py:86:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
@@ -685,17 +657,27 @@
 ERROR Argument `Literal['web-app']` is not assignable to parameter `invoke_from` with type `InvokeFrom | SQLCoreOperations[InvokeFrom | None] | None` in function `models.model.Message.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_audio_service_db.py:94:21
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
-  --> tests/e2e_tests/containers/services/test_conversation_service.py:50:18
+  --> tests/e2e_tests/containers/services/test_conversation_service.py:55:18
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
-  --> tests/e2e_tests/containers/services/test_conversation_service.py:51:23
+  --> tests/e2e_tests/containers/services/test_conversation_service.py:56:23
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_conversation_service.py:106:20
+   --> tests/e2e_tests/containers/services/test_conversation_service.py:111:20
 ERROR Argument `Literal['debugger', 'explore', 'openapi', 'published', 'service-api', 'trigger', 'validation', 'web-app']` is not assignable to parameter `invoke_from` with type `InvokeFrom | SQLCoreOperations[InvokeFrom | None] | None` in function `models.model.Conversation.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_conversation_service.py:107:25
+   --> tests/e2e_tests/containers/services/test_conversation_service.py:112:25
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `MessageStatus | SQLCoreOperations[MessageStatus]` in function `models.model.Message.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_conversation_service.py:153:20
+   --> tests/e2e_tests/containers/services/test_conversation_service.py:158:20
 ERROR Argument `Literal[core.app.entities.app_invoke_entities.InvokeFrom.WEB_APP]` is not assignable to parameter `invoke_from` with type `models.enums.InvokeFrom | SQLCoreOperations[models.enums.InvokeFrom | None] | None` in function `models.model.Message.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_conversation_service.py:154:25
+   --> tests/e2e_tests/containers/services/test_conversation_service.py:159:25
+ERROR Argument `Literal['owner']` is not assignable to parameter `role` with type `SQLCoreOperations[TenantAccountRole] | TenantAccountRole` in function `models.account.TenantAccountJoin.__init__` [bad-argument-type]
+  --> tests/e2e_tests/containers/services/test_conversation_service_variables.py:46:18
+ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
+  --> tests/e2e_tests/containers/services/test_conversation_service_variables.py:56:18
+ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
+  --> tests/e2e_tests/containers/services/test_conversation_service_variables.py:57:23
+ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_conversation_service_variables.py:114:20
+ERROR Argument `Literal['debugger', 'explore', 'openapi', 'published', 'service-api', 'trigger', 'validation', 'web-app']` is not assignable to parameter `invoke_from` with type `InvokeFrom | SQLCoreOperations[InvokeFrom | None] | None` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_conversation_service_variables.py:115:25
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_dataset_permission_service.py:39:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -749,53 +731,57 @@
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
    --> tests/e2e_tests/containers/services/test_end_user_service.py:430:27
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:131:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:130:20
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:132:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:131:20
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:202:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:201:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:203:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:202:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:511:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:510:20
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:512:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:511:20
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:600:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:599:20
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:601:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:600:20
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_feature_service.py:698:20
+ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
    --> tests/e2e_tests/containers/services/test_feature_service.py:699:20
+ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
+   --> tests/e2e_tests/containers/services/test_feature_service.py:746:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:700:20
+   --> tests/e2e_tests/containers/services/test_feature_service.py:747:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:740:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:795:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:741:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:796:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:857:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:912:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_feature_service.py:858:16
+   --> tests/e2e_tests/containers/services/test_feature_service.py:913:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1176:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1231:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1177:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1232:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1287:20
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1342:20
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1288:20
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1343:20
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1496:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1551:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1497:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1552:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1550:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1608:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1551:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1609:16
 ERROR Object of class `NoneType` has no attribute `size` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1653:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1715:16
 ERROR Object of class `NoneType` has no attribute `limit` [missing-attribute]
-    --> tests/e2e_tests/containers/services/test_feature_service.py:1654:16
+    --> tests/e2e_tests/containers/services/test_feature_service.py:1716:16
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_file_service.py:67:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -814,206 +800,54 @@
   --> tests/e2e_tests/containers/services/test_message_export_service.py:93:18
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_message_export_service.py:96:20
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:48:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:49:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:50:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:51:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:52:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:55:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:56:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:57:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:58:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:98:12
-ERROR Cannot index into `bool` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR Cannot index into `float` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR Cannot index into `int` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR Cannot index into `str` [bad-index]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR `None` is not subscriptable [unsupported-operation]
-  --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:99:12
-ERROR Cannot index into `bool` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR Cannot index into `float` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR Cannot index into `int` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR Cannot index into `str` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:100:12
-ERROR Cannot index into `bool` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR Cannot index into `float` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR Cannot index into `int` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR Cannot index into `str` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:101:12
-ERROR Cannot index into `bool` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
-ERROR Cannot index into `float` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
-ERROR Cannot index into `int` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
-ERROR Cannot index into `list[JsonValue]` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
-ERROR Cannot index into `str` [bad-index]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
-ERROR `None` is not subscriptable [unsupported-operation]
-   --> tests/e2e_tests/containers/services/test_message_service_execution_extra_content.py:102:12
+ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
+  --> tests/e2e_tests/containers/services/test_message_service.py:70:38
+ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
+  --> tests/e2e_tests/containers/services/test_message_service.py:73:81
+ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:102:20
+ERROR Argument `Literal[0]` is not assignable to parameter `message_unit_price` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:131:32
+ERROR Argument `float` is not assignable to parameter `message_price_unit` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:132:32
+ERROR Argument `Literal[0]` is not assignable to parameter `answer_unit_price` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:135:31
+ERROR Argument `float` is not assignable to parameter `answer_price_unit` with type `Decimal | SQLCoreOperations[Decimal]` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:136:31
+ERROR Argument `Literal[0]` is not assignable to parameter `total_price` with type `Decimal | SQLCoreOperations[Decimal | None] | None` in function `models.model.Message.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_message_service.py:139:25
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `MessageStatus | SQLCoreOperations[MessageStatus]` in function `models.model.Message.__init__` [bad-argument-type]
-  --> tests/e2e_tests/containers/services/test_message_service_extra_contents.py:44:16
+  --> tests/e2e_tests/containers/services/test_message_service_extra_contents.py:40:16
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:129:20
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:128:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:137:20
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:136:20
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:160:18
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:159:18
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.Conversation.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:182:18
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:181:18
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:185:20
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:184:20
 ERROR Argument `Literal['local_file']` is not assignable to parameter `transfer_method` with type `FileTransferMethod | SQLCoreOperations[FileTransferMethod]` in function `models.model.MessageFile.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:267:29
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:266:29
 ERROR Argument `Literal['end_user']` is not assignable to parameter `created_by_role` with type `CreatorUserRole | SQLCoreOperations[CreatorUserRole]` in function `models.model.MessageFile.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:270:29
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:269:29
 ERROR Argument `Literal['end_user']` is not assignable to parameter `created_by_role` with type `CreatorUserRole | SQLCoreOperations[CreatorUserRole]` in function `models.web.SavedMessage.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:279:29
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:278:29
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:613:13
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:628:13
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:614:13
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:632:13
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:901:13
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:942:13
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:902:13
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:946:13
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:903:13
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:950:13
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:907:22
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:957:22
 ERROR Object of class `str` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:907:52
+   --> tests/e2e_tests/containers/services/test_messages_clean_service.py:957:52
 ERROR Argument `Literal['active']` is not assignable to parameter `status` with type `AccountStatus | SQLCoreOperations[AccountStatus]` in function `models.account.Account.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_model_load_balancing_service.py:84:20
 ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `SQLCoreOperations[TenantStatus] | TenantStatus` in function `models.account.Tenant.__init__` [bad-argument-type]
@@ -1048,6 +882,20 @@
    --> tests/e2e_tests/containers/services/test_schedule_service.py:353:26
 ERROR Argument `SimpleNamespace` is not assignable to parameter `workflow` with type `Workflow` in function `events.event_handlers.sync_workflow_schedule_when_app_published.sync_schedule_from_workflow` [bad-argument-type]
    --> tests/e2e_tests/containers/services/test_schedule_service.py:382:22
+ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
+  --> tests/e2e_tests/containers/services/test_web_conversation_service.py:91:38
+ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:139:18
+ERROR Argument `Literal['normal']` is not assignable to parameter `status` with type `ConversationStatus | SQLCoreOperations[ConversationStatus]` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:146:20
+ERROR Argument `Literal[core.app.entities.app_invoke_entities.InvokeFrom.WEB_APP]` is not assignable to parameter `invoke_from` with type `models.enums.InvokeFrom | SQLCoreOperations[models.enums.InvokeFrom | None] | None` in function `models.model.Conversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:147:25
+ERROR Argument `Literal['account']` is not assignable to parameter `created_by_role` with type `CreatorUserRole | SQLCoreOperations[CreatorUserRole]` in function `models.web.PinnedConversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:215:29
+ERROR Argument `Literal['account']` is not assignable to parameter `created_by_role` with type `CreatorUserRole | SQLCoreOperations[CreatorUserRole]` in function `models.web.PinnedConversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:221:29
+ERROR Argument `Literal['account']` is not assignable to parameter `created_by_role` with type `CreatorUserRole | SQLCoreOperations[CreatorUserRole]` in function `models.web.PinnedConversation.__init__` [bad-argument-type]
+   --> tests/e2e_tests/containers/services/test_web_conversation_service.py:270:29
 ERROR Argument `Literal['chat']` is not assignable to parameter `mode` with type `AppMode | SQLCoreOperations[AppMode]` in function `models.model.App.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_webapp_auth_service.py:45:14
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
@@ -1165,37 +1013,37 @@
 ERROR Argument `str | None` is not assignable to parameter `user_id` with type `str` in function `services.workflow_draft_variable_service.WorkflowDraftVariableService.get_node_variable` [bad-argument-type]
    --> tests/e2e_tests/containers/services/test_workflow_draft_variable_service.py:935:21
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:124:38
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:123:38
 ERROR Argument `str | Unknown` is not assignable to parameter `triggered_from` with type `SQLCoreOperations[WorkflowRunTriggeredFrom] | WorkflowRunTriggeredFrom` in function `models.workflow.WorkflowRun.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:153:28
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:152:28
 ERROR Argument `Literal['succeeded']` is not assignable to parameter `status` with type `SQLCoreOperations[WorkflowExecutionStatus] | WorkflowExecutionStatus` in function `models.workflow.WorkflowRun.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:157:20
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:156:20
 ERROR Argument `float` is not assignable to parameter `value` with type `Decimal | SQLCoreOperations[Decimal]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:210:38
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:209:38
 ERROR Argument `float` is not assignable to parameter `value` with type `Decimal | SQLCoreOperations[Decimal]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:211:37
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:210:37
 ERROR Argument `float` is not assignable to parameter `value` with type `Decimal | SQLCoreOperations[Decimal]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:212:38
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:211:38
 ERROR Argument `float` is not assignable to parameter `value` with type `Decimal | SQLCoreOperations[Decimal]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:213:37
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:212:37
 ERROR Argument `Literal['normal']` is not assignable to parameter `value` with type `MessageStatus | SQLCoreOperations[MessageStatus]` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:215:26
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:214:26
 ERROR Argument `dict[str, int | None]` is not assignable to parameter `args` with type `WorkflowRunListArgs` in function `services.workflow_run_service.WorkflowRunService.get_paginate_workflow_runs` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:256:18
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:255:18
 ERROR Argument `dict[Unknown, Unknown]` is not assignable to parameter `args` with type `WorkflowRunListArgs` in function `services.workflow_run_service.WorkflowRunService.get_paginate_workflow_runs` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:349:18
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:348:18
 ERROR Argument `dict[str, int | None]` is not assignable to parameter `args` with type `WorkflowRunListArgs` in function `services.workflow_run_service.WorkflowRunService.get_paginate_advanced_chat_workflow_runs` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:400:18
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:399:18
 ERROR Argument `Literal['workflow-run']` is not assignable to parameter `triggered_from` with type `SQLCoreOperations[WorkflowNodeExecutionTriggeredFrom] | WorkflowNodeExecutionTriggeredFrom` in function `models.workflow.WorkflowNodeExecutionModel.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:519:32
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:518:32
 ERROR Argument `Literal['workflow-run']` is not assignable to parameter `triggered_from` with type `SQLCoreOperations[WorkflowNodeExecutionTriggeredFrom] | WorkflowNodeExecutionTriggeredFrom` in function `models.workflow.WorkflowNodeExecutionModel.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:541:28
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:540:28
 ERROR Object of class `NoneType` has no attribute `startswith` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:581:20
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:580:20
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:619:38
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:618:38
 ERROR Object of class `NoneType` has no attribute `id` [missing-attribute]
-   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:671:38
+   --> tests/e2e_tests/containers/services/test_workflow_run_service.py:670:38
 ERROR Argument `str | None` is not assignable to parameter `value` with type `SQLCoreOperations[str] | str` in function `sqlalchemy.orm.base.Mapped.__set__` [bad-argument-type]
   --> tests/e2e_tests/containers/services/test_workflow_service.py:81:21
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
@@ -1649,21 +1497,21 @@
 ERROR Argument `Literal['emoji']` is not assignable to parameter `icon_type` with type `IconType | SQLCoreOperations[IconType | None] | None` in function `models.model.App.__init__` [bad-argument-type]
   --> tests/e2e_tests/containers/trigger/conftest.py:66:19
 ERROR Argument `dict[str, str | dict[str, str | dict[str, str]]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `core.trigger.debug.event_selectors.TriggerDebugEventPoller.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:306:21
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:304:21
 ERROR Argument `MockPluginSubscription` is not assignable to parameter `subscription` with type `TriggerSubscription` in function `tasks.trigger_processing_tasks.dispatch_trigger_debug_event` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:357:26
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:355:26
 ERROR Argument `dict[str, str | dict[str, dict[Unknown, Unknown] | str]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `core.trigger.debug.event_selectors.TriggerDebugEventPoller.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:471:21
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:469:21
 ERROR Argument `dict[str, Any]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `services.trigger.schedule_service.ScheduleService.to_schedule_config` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:666:49
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:664:49
 ERROR Argument `Literal['api-key']` is not assignable to parameter `credential_type` with type `CredentialType | SQLCoreOperations[CredentialType]` in function `models.trigger.TriggerSubscription.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:735:25
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:733:25
 ERROR Cannot set item in `str` [unsupported-operation]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:741:5
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:739:5
 ERROR Argument `Literal['api-key']` is not assignable to parameter `credential_type` with type `CredentialType | SQLCoreOperations[CredentialType]` in function `models.trigger.TriggerSubscription.__init__` [bad-argument-type]
-   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:832:25
+   --> tests/e2e_tests/containers/trigger/test_trigger_e2e.py:830:25
 ERROR Argument `dict[str, str | dict[str, dict[Unknown, Unknown] | str]]` is not assignable to parameter `node_config` with type `NodeConfigDict` in function `core.trigger.debug.\n\n... (truncated) ...

@github-actions

Copy link
Copy Markdown
Contributor

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 81.45% 79.29% -2.16%
Strict coverage 81.09% 78.97% -2.12%
Typed symbols 85,141 75,109 -10,032
Untyped symbols 19,479 19,700 +221
Modules 4385 3943 -442

@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.46%. Comparing base (adb27d0) to head (2542aaf).
⚠️ Report is 171 commits behind head on main.

Files with missing lines Patch % Lines
api/core/rag/extractor/excel_extractor.py 66.66% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #44849      +/-   ##
==========================================
- Coverage   89.46%   89.46%   -0.01%     
==========================================
  Files        5998     5998              
  Lines      376054   376059       +5     
  Branches    76181    76182       +1     
==========================================
+ Hits       336437   336438       +1     
- Misses      33593    33597       +4     
  Partials     6024     6024              
Flag Coverage Δ
api 89.28% <66.66%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wolfiesch
wolfiesch force-pushed the feat/optional-wolfxl-xlsx-20261026 branch from 2542aaf to b7ba050 Compare October 31, 2026 00:28
@github-actions github-actions Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Oct 31, 2026
@wolfiesch
wolfiesch marked this pull request as ready for review October 31, 2026 01:16
@wolfiesch
wolfiesch requested a review from a team October 31, 2026 01:16
@wolfiesch
wolfiesch force-pushed the feat/optional-wolfxl-xlsx-20261026 branch from d674a81 to 935970f Compare October 31, 2026 01:46
2.0.35 returns date-only t="d" cells as datetime.date, matching openpyxl.
@wylswz

wylswz commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Thanks @wolfiesch for the very thorough write-up and benchmark evidence — the Strict OOXML gap you describe is real and the test corpus is genuinely useful.

We're going to close this one, though. Dify's extractor sits in the upload path of every instance, so we keep its dependency surface deliberately small and boring. For a new reader we need confidence in the long-term health of the library itself, not just in its current correctness: wolfxl is a very young project (first release this year, low adoption, effectively single-maintainer), and its activity record isn't yet strong enough for us to rely on timely fixes for parser security issues and CVEs. That's a guarantee we can get from openpyxl today, and one we'd be on the hook for if we promoted wolfxl to a recommended option.

There's also a maintenance cost that doesn't disappear just because the group is opt-in: we'd own the abstraction layer, the test matrix, and the triage of every future workbook-parse report that lands with wolfxl installed.
None of this says the library is bad — the corpus results speak for themselves. If wolfxl gains broader adoption, a documented security-response policy, and a track record of prompt fixes, we'd be glad to look again. In the meantime, closing this so the discussion doesn't sit open indefinitely.

Thanks again for taking the time to build such a careful case for it.

@wylswz wylswz closed this Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optional wolfxl reader for .xlsx files in ExcelExtractor

2 participants