feat(mindspace): 0630004 空间 UI、聊天连接、微信分享与 Agent 能力

含 MindSpace 三列布局与统计修复、聊天加载态与连接降级、平台页脚标记与 og:site_name 微信卡片、勾选资料删除 Agent 接口及内部话术过滤。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-30 09:30:51 +08:00
parent b1b8d3afc6
commit 722b18326f
53 changed files with 2450 additions and 313 deletions
+70 -29
View File
@@ -61,6 +61,7 @@ import { normalizeConversationMessages, normalizeUserMessageForApi } from '../ut
const API = '/api';
const DEFAULT_API_TIMEOUT_MS = 20_000;
const AGENT_CONNECT_TIMEOUT_MS = 60_000;
const AGENT_RUNS_PATH = '/agent/runs';
export type AgentRun = {
@@ -184,10 +185,14 @@ function notifyUnauthorized() {
unauthorizedHandler();
}
async function fetchWithTimeout(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
async function fetchWithTimeout(
input: RequestInfo | URL,
init?: RequestInit,
timeoutMs = DEFAULT_API_TIMEOUT_MS,
): Promise<Response> {
const controller = new AbortController();
const upstreamSignal = init?.signal;
const timeout = window.setTimeout(() => controller.abort(), DEFAULT_API_TIMEOUT_MS);
const timeout = window.setTimeout(() => controller.abort(), timeoutMs);
const abortFromUpstream = () => controller.abort();
if (upstreamSignal) {
@@ -267,16 +272,24 @@ function sanitizeSessionEvent(event: SessionEvent): SessionEvent {
return { ...event, error: sanitizeUserFacingErrorMessage(event.error) };
}
async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
async function apiFetch<T>(
path: string,
init?: RequestInit,
options?: { timeoutMs?: number },
): Promise<T> {
let res: Response;
try {
res = await fetchWithTimeout(`${API}${path}`, {
...init,
headers: {
'Content-Type': 'application/json',
...init?.headers,
res = await fetchWithTimeout(
`${API}${path}`,
{
...init,
headers: {
'Content-Type': 'application/json',
...init?.headers,
},
},
});
options?.timeoutMs,
);
} catch (err) {
throw new ApiError(0, formatNetworkError(err));
}
@@ -313,10 +326,14 @@ async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
}
export async function startSession(): Promise<Session> {
return apiFetch<Session>('/agent/start', {
method: 'POST',
body: JSON.stringify({}),
});
return apiFetch<Session>(
'/agent/start',
{
method: 'POST',
body: JSON.stringify({}),
},
{ timeoutMs: AGENT_CONNECT_TIMEOUT_MS },
);
}
export async function bootstrapProjectMemory(
@@ -929,6 +946,7 @@ export async function saveChatMessageAsPage(input: {
selectedLinkIndex?: number;
acknowledgedFindingIds?: string[];
replacePageId?: string;
saveAsNew?: boolean;
}): Promise<ChatSaveResult> {
const result = await apiFetch<{ data: ChatSaveResult }>(
'/mindspace/v1/pages/save-from-chat',
@@ -945,6 +963,7 @@ export async function saveChatMessageAsPage(input: {
acknowledged_finding_ids: input.acknowledgedFindingIds,
page_type: input.templateId === 'report' ? 'report' : 'article',
replace_page_id: input.replacePageId,
save_as_new: input.saveAsNew ?? false,
}),
},
);
@@ -1018,6 +1037,20 @@ export async function updateMindSpacePage(
return result.data;
}
export async function rewriteMindSpacePageDownloadLinks(
pageId: string,
content: string,
): Promise<string> {
const result = await apiFetch<{ data: { html: string } }>(
`/mindspace/v1/pages/${encodeURIComponent(pageId)}/rewrite-download-links`,
{
method: 'POST',
body: JSON.stringify({ content }),
},
);
return result.data.html;
}
export async function fetchMindSpacePageDraftPreview(
pageId: string,
input: {
@@ -2112,14 +2145,18 @@ export async function resumeSession(
sessionId: string,
options?: { skipReconcile?: boolean },
): Promise<Session> {
const result = await apiFetch<{ session: Session }>('/agent/resume', {
method: 'POST',
body: JSON.stringify({
session_id: sessionId,
load_model_and_extensions: true,
...(options?.skipReconcile ? { skip_reconcile: true } : {}),
}),
});
const result = await apiFetch<{ session: Session }>(
'/agent/resume',
{
method: 'POST',
body: JSON.stringify({
session_id: sessionId,
load_model_and_extensions: true,
...(options?.skipReconcile ? { skip_reconcile: true } : {}),
}),
},
{ timeoutMs: AGENT_CONNECT_TIMEOUT_MS },
);
return result.session;
}
@@ -2211,14 +2248,18 @@ export async function createAgentRun(
requestId: string,
userMessage: Message,
): Promise<AgentRun> {
const result = await apiFetch<{ run: AgentRun }>(AGENT_RUNS_PATH, {
method: 'POST',
body: JSON.stringify({
session_id: sessionId,
request_id: requestId,
user_message: normalizeUserMessageForApi(userMessage),
}),
});
const result = await apiFetch<{ run: AgentRun }>(
AGENT_RUNS_PATH,
{
method: 'POST',
body: JSON.stringify({
session_id: sessionId,
request_id: requestId,
user_message: normalizeUserMessageForApi(userMessage),
}),
},
{ timeoutMs: AGENT_CONNECT_TIMEOUT_MS },
);
return result.run;
}