diff --git a/api/core/tools/tool_engine.py b/api/core/tools/tool_engine.py index 13fd579e20..3f57a346cd 100644 --- a/api/core/tools/tool_engine.py +++ b/api/core/tools/tool_engine.py @@ -1,5 +1,6 @@ import contextlib import json +import logging from collections.abc import Generator, Iterable from copy import deepcopy from datetime import UTC, datetime @@ -36,6 +37,8 @@ from extensions.ext_database import db from models.enums import CreatorUserRole from models.model import Message, MessageFile +logger = logging.getLogger(__name__) + class ToolEngine: """ @@ -123,25 +126,31 @@ class ToolEngine: # transform tool invoke message to get LLM friendly message return plain_text, message_files, meta except ToolProviderCredentialValidationError as e: + logger.error(e, exc_info=True) error_response = "Please check your tool provider credentials" agent_tool_callback.on_tool_error(e) except (ToolNotFoundError, ToolNotSupportedError, ToolProviderNotFoundError) as e: error_response = f"there is not a tool named {tool.entity.identity.name}" + logger.error(e, exc_info=True) agent_tool_callback.on_tool_error(e) except ToolParameterValidationError as e: error_response = f"tool parameters validation error: {e}, please check your tool parameters" agent_tool_callback.on_tool_error(e) + logger.error(e, exc_info=True) except ToolInvokeError as e: error_response = f"tool invoke error: {e}" agent_tool_callback.on_tool_error(e) + logger.error(e, exc_info=True) except ToolEngineInvokeError as e: meta = e.meta error_response = f"tool invoke error: {meta.error}" agent_tool_callback.on_tool_error(e) + logger.error(e, exc_info=True) return error_response, [], meta except Exception as e: error_response = f"unknown error: {e}" agent_tool_callback.on_tool_error(e) + logger.error(e, exc_info=True) return error_response, [], ToolInvokeMeta.error_instance(error_response) diff --git a/api/core/tools/workflow_as_tool/tool.py b/api/core/tools/workflow_as_tool/tool.py index 283744b43b..9c1ceff145 100644 --- a/api/core/tools/workflow_as_tool/tool.py +++ b/api/core/tools/workflow_as_tool/tool.py @@ -20,7 +20,6 @@ from core.tools.entities.tool_entities import ( ) from core.tools.errors import ToolInvokeError from factories.file_factory import build_from_mapping -from libs.login import current_user from models import Account, Tenant from models.model import App, EndUser from models.workflow import Workflow @@ -28,21 +27,6 @@ from models.workflow import Workflow logger = logging.getLogger(__name__) -def _try_resolve_user_from_request() -> Account | EndUser | None: - """ - Try to resolve user from Flask request context. - - Returns None if not in a request context or if user is not available. - """ - # Note: `current_user` is a LocalProxy. Never compare it with None directly. - # Use _get_current_object() to dereference the proxy - user = getattr(current_user, "_get_current_object", lambda: current_user)() - # Check if we got a valid user object - if user is not None and hasattr(user, "id"): - return user - return None - - class WorkflowTool(Tool): """ Workflow tool. @@ -223,12 +207,6 @@ class WorkflowTool(Tool): Returns: Account | EndUser | None: The resolved user object, or None if resolution fails. """ - # Try to resolve user from request context first - user = _try_resolve_user_from_request() - if user is not None: - return user - - # Fall back to database resolution return self._resolve_user_from_database(user_id=user_id) def _resolve_user_from_database(self, user_id: str) -> Account | EndUser | None: diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 1543bce714..62516a797d 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -95,6 +95,7 @@ import { import SyncingDataModal from './syncing-data-modal' import { ControlMode, + WorkflowRunningStatus, } from './types' import { setupScrollToNodeListener } from './utils/node-navigation' import { WorkflowHistoryProvider } from './workflow-history-store' @@ -231,11 +232,20 @@ export const Workflow: FC = memo(({ const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft() const handleSyncWorkflowDraftWhenPageClose = useCallback(() => { - if (document.visibilityState === 'hidden') + if (document.visibilityState === 'hidden') { syncWorkflowDraftWhenPageClose() + return + } + + if (document.visibilityState === 'visible') { + const { isListening, workflowRunningData } = workflowStore.getState() + const status = workflowRunningData?.result?.status + // Avoid resetting UI state when user comes back while a run is active or listening for triggers + if (isListening || status === WorkflowRunningStatus.Running) + return - else if (document.visibilityState === 'visible') setTimeout(() => handleRefreshWorkflowDraft(), 500) + } }, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft, workflowStore]) // Also add beforeunload handler as additional safety net for tab close diff --git a/web/package.json b/web/package.json index 955d1ade1d..69cc08bd32 100644 --- a/web/package.json +++ b/web/package.json @@ -215,7 +215,7 @@ "eslint-plugin-storybook": "10.1.11", "eslint-plugin-tailwindcss": "3.18.2", "husky": "9.1.7", - "jsdom": "27.4.0", + "jsdom": "27.3.0", "jsdom-testing-mocks": "1.16.0", "knip": "5.78.0", "lint-staged": "15.5.2", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 45d1ed5db0..c98b57ee48 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -369,7 +369,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 7.0.1 - version: 7.0.1(@eslint-react/eslint-plugin@2.7.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.1.4)(@vue/compiler-sfc@3.5.25)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@1.21.7)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@1.21.7)))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 7.0.1(@eslint-react/eslint-plugin@2.7.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.1.4)(@vue/compiler-sfc@3.5.25)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@1.21.7)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@1.21.7)))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@chromatic-com/storybook': specifier: 4.1.1 version: 4.1.1(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) @@ -498,7 +498,7 @@ importers: version: 5.1.2(vite@7.3.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/coverage-v8': specifier: 4.0.17 - version: 4.0.17(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.0.17(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) autoprefixer: specifier: 10.4.21 version: 10.4.21(postcss@8.5.6) @@ -533,8 +533,8 @@ importers: specifier: 9.1.7 version: 9.1.7 jsdom: - specifier: 27.4.0 - version: 27.4.0(canvas@3.2.0) + specifier: 27.3.0 + version: 27.3.0(canvas@3.2.0) jsdom-testing-mocks: specifier: 1.16.0 version: 1.16.0 @@ -582,7 +582,7 @@ importers: version: 6.0.4(typescript@5.9.3)(vite@7.3.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vitest: specifier: 4.0.17 - version: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) packages: @@ -1726,15 +1726,6 @@ packages: resolution: {integrity: sha512-hZ2uC1jbf6JMSsF2ZklhRQqf6GLpYyux6DlzegnW/aFlpu6qJj5GO7ub7WOETCrEl6pl6DAX7RgTgj/fyG+6BQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@exodus/bytes@1.9.0': - resolution: {integrity: sha512-lagqsvnk09NKogQaN/XrtlWeUF8SRhT12odMvbTIIaVObqzwAogL6jhR4DAp0gPuKoM1AOVrKUshJpRdpMFrww==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -5797,9 +5788,9 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -6129,8 +6120,8 @@ packages: resolution: {integrity: sha512-wLrulXiLpjmcUYOYGEvz4XARkrmdVpyxzdBl9IAMbQ+ib2/UhUTRCn49McdNfXLff2ysGBUms49ZKX0LR1Q0gg==} engines: {node: '>=14'} - jsdom@27.4.0: - resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} + jsdom@27.3.0: + resolution: {integrity: sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.2.0 @@ -8504,6 +8495,11 @@ packages: webpack-cli: optional: true + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} @@ -8833,7 +8829,7 @@ snapshots: idb: 8.0.3 tslib: 2.8.1 - '@antfu/eslint-config@7.0.1(@eslint-react/eslint-plugin@2.7.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.1.4)(@vue/compiler-sfc@3.5.25)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@1.21.7)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@1.21.7)))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@antfu/eslint-config@7.0.1(@eslint-react/eslint-plugin@2.7.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(@next/eslint-plugin-next@16.1.4)(@vue/compiler-sfc@3.5.25)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@1.21.7)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@1.21.7)))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@antfu/install-pkg': 1.1.0 '@clack/prompts': 0.11.0 @@ -8842,7 +8838,7 @@ snapshots: '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@1.21.7)) '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.6.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/eslint-plugin': 1.6.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) ansis: 4.2.0 cac: 6.7.14 eslint: 9.39.2(jiti@1.21.7) @@ -10089,8 +10085,6 @@ snapshots: '@eslint/core': 1.0.1 levn: 0.4.1 - '@exodus/bytes@1.9.0': {} - '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -12392,7 +12386,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.17(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.0.17(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.17 @@ -12404,16 +12398,16 @@ snapshots: obug: 2.1.1 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)(vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@typescript-eslint/scope-manager': 8.53.0 '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) eslint: 9.39.2(jiti@1.21.7) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -14704,11 +14698,9 @@ snapshots: dependencies: react-is: 16.13.1 - html-encoding-sniffer@6.0.0: + html-encoding-sniffer@4.0.0: dependencies: - '@exodus/bytes': 1.9.0 - transitivePeerDependencies: - - '@noble/hashes' + whatwg-encoding: 3.1.1 html-entities@2.6.0: {} @@ -14975,15 +14967,14 @@ snapshots: bezier-easing: 2.1.0 css-mediaquery: 0.1.2 - jsdom@27.4.0(canvas@3.2.0): + jsdom@27.3.0(canvas@3.2.0): dependencies: '@acemir/cssom': 0.9.31 '@asamuzakjp/dom-selector': 6.7.6 - '@exodus/bytes': 1.9.0 cssstyle: 5.3.7 data-urls: 6.0.1 decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 + html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 @@ -14993,6 +14984,7 @@ snapshots: tough-cookie: 6.0.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 + whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 15.1.0 ws: 8.19.0 @@ -15000,7 +14992,6 @@ snapshots: optionalDependencies: canvas: 3.2.0 transitivePeerDependencies: - - '@noble/hashes' - bufferutil - supports-color - utf-8-validate @@ -17721,7 +17712,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 - vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.4.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.17(@types/node@18.15.0)(happy-dom@20.0.11)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.0))(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.17 '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.93.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -17746,7 +17737,7 @@ snapshots: optionalDependencies: '@types/node': 18.15.0 happy-dom: 20.0.11 - jsdom: 27.4.0(canvas@3.2.0) + jsdom: 27.3.0(canvas@3.2.0) transitivePeerDependencies: - jiti - less @@ -17883,6 +17874,10 @@ snapshots: - esbuild - uglify-js + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-mimetype@3.0.0: optional: true