chore(release): v0.3.41
智能体抽屉读 ?open= 上下文、回复链接用抽屉地址;抽屉打开不亮焦点框;语句统计重复 key。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
78a4d562f0
commit
1ade49fe8e
22 files changed
+62
-33
No files matched your search
@@ -40,6 +40,7 @@ import { Markdown } from "~/components/agentui/markdown.tsx";
|
||||
import { MessageMarker, MessageTyping } from "~/components/agentui/message.tsx";
|
||||
import { StreamingResponse } from "~/components/agentui/streaming-response.tsx";
|
||||
import { consolePath } from "~/components/console/nav.ts";
|
||||
import { recordPath } from "~/components/console/record-sheet.tsx";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { TechInfo } from "~/components/console/tech-info.tsx";
|
||||
import { formatUsd } from "~/components/schedules/labels.ts";
|
||||
@@ -673,14 +674,14 @@ export function resultFacts(report: GoalReport | null): ResultFact[] {
|
||||
const only = r.downloads.length === 1 ? r.downloads[0] : undefined;
|
||||
facts.push({
|
||||
text: `提交了 ${downloads} 个下载`,
|
||||
to: only ? `/console/downloads/${only.downloadTaskId}` : r.downloads.length ? "/console/downloads" : undefined,
|
||||
to: only ? recordPath("downloads", only.downloadTaskId) : r.downloads.length ? "/console/downloads" : undefined,
|
||||
});
|
||||
}
|
||||
if (done.length) {
|
||||
const only = done.length === 1 ? done[0] : undefined;
|
||||
facts.push({
|
||||
text: `完成 ${done.length} 次整理`,
|
||||
to: only ? `/console/organize/${only.recordId}` : "/console/organize",
|
||||
to: only ? recordPath("organize", only.recordId) : "/console/organize",
|
||||
});
|
||||
}
|
||||
if (r.imported && r.imported !== done.length) facts.push({ text: `已整理 ${r.imported} 个` });
|
||||
|
||||
@@ -109,7 +109,7 @@ export function AgentDrawer() {
|
||||
const content = useRef<HTMLDivElement>(null);
|
||||
// 记下最近的非智能体页面:会话页「在侧边打开」回到这里
|
||||
useEffect(() => noteAgentReturnPath(pathname, search), [pathname, search]);
|
||||
useEffect(() => syncAgentContextToPath(pathname), [pathname]);
|
||||
useEffect(() => syncAgentContextToPath(pathname, search), [pathname, search]);
|
||||
const name = useContextName(context);
|
||||
const mock = agentMockEnabled();
|
||||
// 目标前缀带名称和 ID:名称给人看,ID 给模型用
|
||||
@@ -210,7 +210,7 @@ export function AgentDrawer() {
|
||||
|
||||
/** 顶栏胶囊里的智能体按钮(没有侧栏的窄屏):与快捷键、侧栏入口同一套切换(页面内按钮用 openAgentDrawer 传更完整的上下文) */
|
||||
export function AgentDrawerTrigger({ className }: { className?: string }) {
|
||||
const { pathname } = useLocation();
|
||||
const { pathname, search } = useLocation();
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -219,7 +219,7 @@ export function AgentDrawerTrigger({ className }: { className?: string }) {
|
||||
title={`智能体(${agentShortcutLabel()})`}
|
||||
className={className}
|
||||
{...{ [AGENT_LAUNCHER_ATTR]: "" }}
|
||||
onClick={() => toggleAgentDrawer(pathname)}
|
||||
onClick={() => toggleAgentDrawer(pathname, search)}
|
||||
>
|
||||
<Bot />
|
||||
</Button>
|
||||
|
||||
@@ -80,6 +80,11 @@ describe("侧栏上下文", () => {
|
||||
expect(ctx?.taskId).toBe("5b4e76e0-f27f-4e7a-8e08-71486387df1d");
|
||||
expect(contextFromPath("/console/sites/hdhome")?.siteId).toBe("hdhome");
|
||||
expect(contextFromPath("/console/agent")).toBeNull();
|
||||
// 列表页的记录抽屉(?open=)与日志页的任务抽屉(?run=)
|
||||
expect(contextFromPath("/console/sites", "?open=hdhome&tab=rss")?.siteId).toBe("hdhome");
|
||||
expect(contextFromPath("/console/organize", "?open=r1")?.recordId).toBe("r1");
|
||||
expect(contextFromPath("/console/logs", "?type=task&run=t9")?.taskId).toBe("t9");
|
||||
expect(contextFromPath("/console/sites", "?tab=rss")).toBeNull();
|
||||
const goal = `${contextPrefix(ctx)}排查这个任务`;
|
||||
expect(splitContextGoal(goal)).toEqual({ context: expect.stringContaining("taskId="), text: "排查这个任务" });
|
||||
});
|
||||
|
||||
@@ -662,7 +662,7 @@ describe("实际结果行(FIX-9):只列系统核实的事实", () => {
|
||||
createElement(ResultLine, { run: RUN, report: done, live: withText("提交了 2 个下载,整理了 1 个。") }),
|
||||
);
|
||||
expect(text(html).replace(/\s*、\s*/g, "、")).toContain("提交了 2 个下载、完成 1 次整理、1 个进行中 · 41 秒");
|
||||
expect(html).toContain(`href="/console/organize/${ID(3)}"`);
|
||||
expect(html).toContain(`href="/console/organize?open=${ID(3)}"`);
|
||||
expect(html).toContain('href="/console/downloads"');
|
||||
expect(html).not.toContain("与汇报不一致");
|
||||
});
|
||||
|
||||
@@ -87,9 +87,9 @@ export function newAgentConversation() {
|
||||
* 抽屉开着时路由变了(浏览器前进后退、会话里的链接):还在新对话、上下文是按路由推断的,就换成新页面的对象;
|
||||
* 页面按钮带进来的上下文、已经在看的会话不动。
|
||||
*/
|
||||
export function syncAgentContextToPath(pathname: string) {
|
||||
export function syncAgentContextToPath(pathname: string, search = "") {
|
||||
if (!state.open || state.runId || (state.context && !state.context.fromPath)) return;
|
||||
const next = contextFromPath(pathname);
|
||||
const next = contextFromPath(pathname, search);
|
||||
if (JSON.stringify(next) === JSON.stringify(state.context)) return;
|
||||
state = { ...state, context: next };
|
||||
emit();
|
||||
@@ -144,17 +144,24 @@ function focusAgentPageInput(): boolean {
|
||||
}
|
||||
|
||||
/** 快捷键 / 侧栏主入口 / 顶栏胶囊里的按钮共用的切换 */
|
||||
export function toggleAgentDrawer(pathname: string) {
|
||||
export function toggleAgentDrawer(pathname: string, search = "") {
|
||||
const action = toggleAction(state, pathname);
|
||||
if (action === "close") setAgentDrawerOpen(false);
|
||||
// 智能体页面本身就是会话:聚焦页面的输入框,找不到输入框才开抽屉
|
||||
else if (action === "focus-page" && focusAgentPageInput()) return;
|
||||
else if (state.runId) setAgentDrawerOpen(true);
|
||||
else openAgentDrawer(contextFromPath(pathname));
|
||||
else openAgentDrawer(contextFromPath(pathname, search));
|
||||
}
|
||||
|
||||
/** 按当前路由推断页面上下文(顶栏按钮用;页面内按钮直接传更完整的上下文) */
|
||||
export function contextFromPath(pathname: string): AgentContext | null {
|
||||
export function contextFromPath(pathname: string, search = ""): AgentContext | null {
|
||||
// 列表页上开着的记录抽屉(?open=,console-ia §9)等同于旧的详情页;日志页的任务抽屉是 ?run=
|
||||
const q = new URLSearchParams(search);
|
||||
const open = q.get("open");
|
||||
const listPage = pathname.match(/^\/console\/(sites|downloads|organize)\/?$/);
|
||||
if (listPage && open) return contextFromPath(`/console/${listPage[1]}/${open}`);
|
||||
const run = q.get("run");
|
||||
if (/^\/console\/logs\/?$/.test(pathname) && run) return contextFromPath(`/console/engine/${run}`);
|
||||
const m = pathname.match(/^\/console\/(library|sites|tasks|downloads|organize|engine)\/([^/?#]+)/);
|
||||
if (!m) return null;
|
||||
const [, kind, id] = m as unknown as [string, string, string];
|
||||
|
||||
Reference in new issue
Block a user