mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
fix: unblock v0.98.0 release workflow
This commit is contained in:
@@ -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 分类扫描",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user