fix: unblock v0.98.0 release workflow

This commit is contained in:
coso
2026-03-29 14:34:26 +08:00
parent deceacc699
commit 149e63c2f7
9 changed files with 147 additions and 50 deletions
+126
View File
@@ -0,0 +1,126 @@
import { Suspense } from "react";
import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { AgentPageParams, Page } from "@/types/page";
import { AppPageContent } from "./AppPageContent";
const latestAgentChatProps = vi.hoisted(
() =>
({
value: null as Record<string, unknown> | null,
}) as { value: Record<string, unknown> | null },
);
vi.mock("./agent/chat", () => ({
AgentChatPage: (props: Record<string, unknown>) => {
latestAgentChatProps.value = props;
return <div data-testid="agent-chat-page" />;
},
}));
interface MountedContent {
container: HTMLDivElement;
root: Root;
}
const mountedContents: MountedContent[] = [];
function renderContent(pageParams: AgentPageParams) {
const container = document.createElement("div");
document.body.appendChild(container);
const root = createRoot(container);
act(() => {
root.render(
<Suspense fallback={<div data-testid="page-loading" />}>
<AppPageContent
currentPage="agent"
pageParams={pageParams}
onNavigate={vi.fn() as (page: Page) => void}
onAgentHasMessagesChange={vi.fn()}
/>
</Suspense>,
);
});
mountedContents.push({ container, root });
return container;
}
async function flushEffects(times = 6) {
await act(async () => {
for (let index = 0; index < times; index += 1) {
await Promise.resolve();
}
});
}
describe("AppPageContent", () => {
beforeEach(() => {
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
latestAgentChatProps.value = null;
});
afterEach(() => {
while (mountedContents.length > 0) {
const mounted = mountedContents.pop();
if (!mounted) {
continue;
}
act(() => {
mounted.root.unmount();
});
mounted.container.remove();
}
vi.clearAllMocks();
vi.unstubAllGlobals();
});
it("agent 页面应把 initialSiteSkillLaunch 透传给 AgentChatPage", async () => {
const pageParams: AgentPageParams = {
agentEntry: "claw",
projectId: "project-1",
contentId: "content-1",
theme: "general",
newChatAt: 1234567890,
initialSiteSkillLaunch: {
adapterName: "linux-do/categories",
args: {
limit: 10,
},
autoRun: true,
profileKey: "attached-linux-do",
targetId: "tab-linux-do",
requireAttachedSession: true,
saveTitle: "Linux.do 分类扫描",
skillTitle: "Linux.do 分类扫描",
},
};
renderContent(pageParams);
await flushEffects();
expect(latestAgentChatProps.value).toMatchObject({
projectId: "project-1",
contentId: "content-1",
agentEntry: "claw",
theme: "general",
newChatAt: 1234567890,
initialSiteSkillLaunch: {
adapterName: "linux-do/categories",
args: {
limit: 10,
},
autoRun: true,
profileKey: "attached-linux-do",
targetId: "tab-linux-do",
requireAttachedSession: true,
saveTitle: "Linux.do 分类扫描",
skillTitle: "Linux.do 分类扫描",
},
});
});
});
+1
View File
@@ -215,6 +215,7 @@ export function AppPageContent({
entryBannerMessage={agentPageParams.entryBannerMessage}
immersiveHome={agentPageParams.immersiveHome}
openBrowserAssistOnMount={agentPageParams.openBrowserAssistOnMount}
initialSiteSkillLaunch={agentPageParams.initialSiteSkillLaunch}
theme={agentPageParams.theme}
lockTheme={agentPageParams.lockTheme}
fromResources={agentPageParams.fromResources}
@@ -681,23 +681,7 @@ function extractCompactThinkingParts(item: Extract<
};
}
const displayText = resolveThinkingDisplayText(item);
const parsed = parseAIResponse(displayText, false);
if (parsed.hasA2UI || parsed.hasPending) {
return null;
}
const lines = displayText
.split(/\r?\n/)
.map((line) => line.trim())
.filter(Boolean);
const [title = item.status === "in_progress" ? "思考中" : "已完成思考", ...rest] =
lines;
return {
title,
detail: rest.join("\n").trim(),
};
return null;
}
function GroupedThinkingRow({
@@ -429,7 +429,10 @@ export function EmptyStateComposerPanel({
) : null}
{activeSkill ? (
<SkillBadge skill={activeSkill} onClear={clearActiveSkill} />
<SkillBadge
skill={activeSkill}
onClear={clearActiveSkill ?? (() => undefined)}
/>
) : null}
{shouldShowTeamSuggestion ? (
@@ -202,11 +202,12 @@ export function ServiceSkillLaunchDialog({
setSiteLaunchReadiness({ phase: "idle" });
return;
}
const siteCapabilityBinding = skill.siteCapabilityBinding;
setSiteLaunchReadiness({ phase: "checking" });
try {
const result = await siteGetAdapterLaunchReadiness({
adapter_name: skill.siteCapabilityBinding.adapterName,
adapter_name: siteCapabilityBinding.adapterName,
});
setSiteLaunchReadiness({
phase: result.status === "ready" ? "ready" : "blocked",
@@ -221,17 +222,18 @@ export function ServiceSkillLaunchDialog({
}, [open, skill]);
useEffect(() => {
if (!open || !skill || !isSiteSkill) {
if (!open || !skill || !isServiceSkillExecutableAsSiteAdapter(skill)) {
setSiteLaunchReadiness({ phase: "idle" });
return;
}
const siteCapabilityBinding = skill.siteCapabilityBinding;
let cancelled = false;
void (async () => {
setSiteLaunchReadiness({ phase: "checking" });
try {
const result = await siteGetAdapterLaunchReadiness({
adapter_name: skill.siteCapabilityBinding.adapterName,
adapter_name: siteCapabilityBinding.adapterName,
});
if (cancelled) {
return;
@@ -254,7 +256,7 @@ export function ServiceSkillLaunchDialog({
return () => {
cancelled = true;
};
}, [isSiteSkill, open, skill]);
}, [open, skill]);
const readinessToneClass =
siteLaunchReadiness.phase === "ready"
@@ -42,6 +42,7 @@ export type {
ServiceSkillType,
};
export type { SkillCatalogExecutionKind, SkillCatalogGroup };
export type ServiceSkillGroup = SkillCatalogGroup;
export type ServiceSkillTone = "slate" | "sky" | "emerald" | "amber";
@@ -105,18 +105,6 @@ function shouldAutoOpenPassiveBrowserAssist(
);
}
function shouldAutoOpenBrowserAssistCanvas(
artifact: Artifact | null,
launching: boolean,
sessionState: BrowserAssistSessionState | null,
): boolean {
if (shouldAutoOpenPassiveBrowserAssist(artifact, launching)) {
return true;
}
return Boolean(sessionState?.sessionId?.trim());
}
type EnsureBrowserAssistCanvasHandler = (
sourceText: string,
options?: {
@@ -429,7 +417,6 @@ export function useWorkspaceBrowserAssistRuntime({
void (async () => {
try {
setBrowserAssistLaunching(true);
setSiteSkillExecutionState({
phase: "running",
adapterName: initialSiteSkillLaunch.adapterName,
@@ -541,9 +528,7 @@ export function useWorkspaceBrowserAssistRuntime({
{ id: toastId },
);
} finally {
if (!cancelled) {
setBrowserAssistLaunching(false);
}
// 站点技能执行不应驱动浏览器画布的“启动中”状态。
}
})();
@@ -1030,11 +1015,7 @@ export function useWorkspaceBrowserAssistRuntime({
browserAssistSessionState.profileKey || generalBrowserAssistProfileKey
}:${browserAssistSessionState.url || currentUrl || "pending"}`;
if (
shouldAutoOpenBrowserAssistCanvas(
nextArtifact,
browserAssistLaunching,
browserAssistSessionState,
) &&
shouldAutoOpenPassiveBrowserAssist(nextArtifact, browserAssistLaunching) &&
autoOpenedBrowserAssistSessionIdRef.current !== autoOpenKey
) {
autoOpenedBrowserAssistSessionIdRef.current = autoOpenKey;
@@ -291,13 +291,12 @@ export function useWorkspaceConversationSceneRuntime({
.map((line) => `> ${line}`)
.join("\n")}\n\n`;
setInput((previous) => {
if (!previous.trim()) {
return quotedBlock;
}
if (!input.trim()) {
setInput(quotedBlock);
return;
}
return `${previous.trimEnd()}\n\n${quotedBlock}`;
});
setInput(`${input.trimEnd()}\n\n${quotedBlock}`);
};
const teamWorkspaceDockLayoutMode =
+1 -1
View File
@@ -41,7 +41,7 @@ describe("http-client listenViaHttpEvent", () => {
vi.resetModules();
MockEventSource.instances = [];
vi.stubEnv("MODE", "development");
vi.stubEnv("DEV", "true");
vi.stubEnv("DEV", true);
vi.stubEnv("VITEST", "");
vi.stubGlobal("EventSource", MockEventSource as unknown as typeof EventSource);
});