fix: skip canvas SSE fetch in chat shared page to eliminate spurious 103 error (#14190)

## What does this PR do?

Fixes the `hint : 103 Only owner of canvas authorized for this
operation` error that appears when opening a **Chat** shared link
(`/chats/share?shared_id=...&from=chat`).

## Root Cause

The Chat shared page (`web/src/pages/next-chats/share/index.tsx`)
unconditionally calls `useFetchFlowSSE()`, which requests
`/api/canvas/getsse/{sharedId}`. This is an Agent Canvas endpoint that
validates canvas ownership. When sharing a **Chat** dialog (not an
Agent):

1. `sharedId` is a `dialog_id`, not a `canvas_id`
2. The API token's `tenant_id` doesn't match any canvas owner
3. The backend returns `code: 103, message: "Only owner of canvas
authorized for this operation."`
4. The global error interceptor in `request.ts` displays it as a
notification: `hint : 103 Only owner of canvas authorized for this
operation.`

## Changes

- **`web/src/hooks/use-agent-request.ts`**: Added an `enabled` parameter
to `useFetchFlowSSE` so callers can conditionally skip the query.
- **`web/src/pages/next-chats/share/index.tsx`**: Only enable
`useFetchFlowSSE` when `from === SharedFrom.Agent`. For Chat shares, the
hook is disabled, avoiding the unnecessary canvas API call entirely.

## Related Issue

Closes #14115

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

---------

Signed-off-by: noob <yixiao121314@outlook.com>
This commit is contained in:
euvre
2026-04-27 03:27:39 +00:00
committed by GitHub
parent 3ad3241ae0
commit 33bb464ce3
5 changed files with 10 additions and 11 deletions

View File

@@ -794,7 +794,7 @@ export function useCancelConversation() {
return { data, loading, cancelConversation: mutateAsync };
}
export const useFetchSharedAgent = (): {
export const useFetchFlowSSE = (): {
data: IFlow;
loading: boolean;
refetch: () => void;
@@ -808,6 +808,7 @@ export const useFetchSharedAgent = (): {
} = useQuery({
queryKey: [AgentApiAction.FetchSharedAgent, sharedId],
initialData: {} as IFlow,
enabled: !!sharedId,
refetchOnReconnect: false,
refetchOnMount: false,
refetchOnWindowFocus: false,

View File

@@ -1265,7 +1265,8 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
includeHeadingContentTip:
'启用后,标题下的直接内容将作为一个独立的块保留。子块仅保留标题路径。',
rootAsHeading: '将首个切片设为 H0 标题',
rootAsHeadingTip: '将首个切片设为全局标题,以确保整个文档层级结构中拥有一致的上下文信息。该功能尤其适用于首段包含关键信息的简历。',
rootAsHeadingTip:
'将首个切片设为全局标题,以确保整个文档层级结构中拥有一致的上下文信息。该功能尤其适用于首段包含关键信息的简历。',
hierarchyTip: `构建标题树并生成独立的块,每个块携带其完整的祖先标题路径(例如 第1部分 第3章 第2节 + 正文)。\n
适用场景:具有独立的、结构性重要章节的文档——如法律条款、法规、合同和技术规范——其中每个块即使没有上下文也能通过其结构位置来识别。`,
groupTip: `在选定的标题级别将文档扁平分割,并自动合并相邻的小节以保持内容连续性。不注入父标题路径。\n

View File

@@ -4,8 +4,7 @@ import MessageItem from '@/components/message-item';
import PdfSheet from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { useSyncThemeFromParams } from '@/components/theme-provider';
import { MessageType, SharedFrom } from '@/constants/chat';
import { useFetchSharedAgent } from '@/hooks/use-agent-request';
import { MessageType } from '@/constants/chat';
import { useFetchExternalChatInfo } from '@/hooks/use-chat-request';
import i18n, { changeLanguageAsync } from '@/locales/config';
import { buildMessageUuidWithRole } from '@/utils/chat';
@@ -20,7 +19,6 @@ import { buildMessageItemReference } from '../utils';
const ChatContainer = () => {
const {
sharedId: conversationId,
from,
locale,
theme,
visibleAvatar,
@@ -44,15 +42,13 @@ const ChatContainer = () => {
const sendDisabled = useSendButtonDisabled(value);
const { data: chatInfo } = useFetchExternalChatInfo();
const { data: flowData } = useFetchSharedAgent();
React.useEffect(() => {
if (locale && i18n.language !== locale) {
changeLanguageAsync(locale);
}
}, [locale, visibleAvatar]);
const avatarDialogSrc =
from === SharedFrom.Agent ? flowData?.avatar : chatInfo.avatar;
const avatarDialogSrc = chatInfo.avatar;
if (!conversationId) {
return <div>empty</div>;

View File

@@ -144,7 +144,7 @@ const SourceDetailPage = () => {
];
}, [detail, runSchedule]);
const { addLoading, handleAddOk } = useAddDataSource({isEdit:true});
const { addLoading, handleAddOk } = useAddDataSource({ isEdit: true });
const onSubmit = useCallback(() => {
formRef?.current?.submit();

View File

@@ -3,7 +3,8 @@ import { useSetModalState } from '@/hooks/common-hooks';
import { useGetPaginationWithRouter } from '@/hooks/logic-hooks';
import dataSourceService, {
dataSourceRebuild,
dataSourceResume, dataSourceUpdate,
dataSourceResume,
dataSourceUpdate,
deleteDataSource,
featchDataSourceDetail,
getDataSourceLogs,
@@ -68,7 +69,7 @@ export const useListDataSource = () => {
return { list, categorizedList: updatedDataSourceTemplates, isFetching };
};
export const useAddDataSource = ({isEdit=false}:{isEdit?:boolean} ) => {
export const useAddDataSource = ({ isEdit = false }: { isEdit?: boolean }) => {
const [addSource, setAddSource] = useState<IDataSorceInfo | undefined>(
undefined,
);