feat(ui,docs): Agent 流式侧栏 + 结果区/MCP 点/确认条 + 官网文案
- 侧栏消费 Agent SSE:时间线边 append、正文 ▌、停止按钮 - 「在结果区打开」不抢编辑器 focus;MCP 活跃点;写操作确认条 - 文档/落地页补充 Ask|Agent 与 npx @rlwj-lab/opsxdb-mcp(不宣传默认可写)
This commit is contained in:
1 parent
2336c9433c
commit
979efb606d
9 files changed
+580
-92
No files matched your search
+50
-3
@@ -189,6 +189,14 @@ export type ConfirmRequest = {
|
||||
items?: string[];
|
||||
};
|
||||
|
||||
export type AiAgentQueryResultView = {
|
||||
columns: string[];
|
||||
rows: Record<string, unknown>[];
|
||||
rowCount: number;
|
||||
sql?: string;
|
||||
tool?: string;
|
||||
};
|
||||
|
||||
export type AiAgentStepView = {
|
||||
tool: string;
|
||||
args?: string;
|
||||
@@ -196,6 +204,10 @@ export type AiAgentStepView = {
|
||||
summary: string;
|
||||
error?: string;
|
||||
ms: number;
|
||||
pending?: boolean;
|
||||
needConfirm?: boolean;
|
||||
confirmSql?: string;
|
||||
result?: AiAgentQueryResultView;
|
||||
};
|
||||
|
||||
export type AiMessage = {
|
||||
@@ -205,6 +217,7 @@ export type AiMessage = {
|
||||
at: string;
|
||||
/** Agent 工具步骤时间线(仅 assistant) */
|
||||
steps?: AiAgentStepView[];
|
||||
streaming?: boolean;
|
||||
};
|
||||
|
||||
export type AiChatMode = "ask" | "agent";
|
||||
@@ -320,11 +333,14 @@ type State = {
|
||||
updateActiveSql: (sql: string) => void;
|
||||
/** AI 异步返回只写入原标签;用户编辑或切库后跳过。 */
|
||||
updateTabSqlIfUnchanged: (id: string, originalSql: string, connectionId: string | undefined, database: string | undefined, sql: string) => boolean;
|
||||
pushAi: (role: AiMessage["role"], content: string, steps?: AiAgentStepView[]) => void;
|
||||
pushAi: (role: AiMessage["role"], content: string, steps?: AiAgentStepView[], extra?: Partial<AiMessage>) => string;
|
||||
patchAiMessage: (id: string, patch: Partial<AiMessage> | ((m: AiMessage) => AiMessage)) => void;
|
||||
setSession: (connectionId: string, sessionId: string | null) => void;
|
||||
pushHistory: (item: Omit<QueryHistoryItem, "id" | "at"> & { at?: number }) => void;
|
||||
clearHistory: () => void;
|
||||
setResultSets: (items: ResultSetItem[]) => void;
|
||||
/** AI「在结果区打开」:新开/切换结果页,不改 SQL Tab、不抢编辑器 focus */
|
||||
openAiResultSet: (label: string, sql: string, result: QueryResult) => void;
|
||||
selectResultSet: (id: string) => void;
|
||||
/** C5/G3:局部更新某个结果集(翻页结果、视图持久化);若为激活项同步 result */
|
||||
updateResultSet: (id: string, patch: Partial<Omit<ResultSetItem, "id">>) => void;
|
||||
@@ -894,14 +910,33 @@ export const useWorkspaceStore = create<State>((set, get) => ({
|
||||
return true;
|
||||
},
|
||||
|
||||
pushAi: (role, content, steps) =>
|
||||
pushAi: (role, content, steps, extra) => {
|
||||
const id = crypto.randomUUID();
|
||||
set((s) => ({
|
||||
aiMessages: [
|
||||
...s.aiMessages,
|
||||
{ id: crypto.randomUUID(), role, content, at: new Date().toLocaleTimeString(), steps },
|
||||
{
|
||||
id,
|
||||
role,
|
||||
content,
|
||||
at: new Date().toLocaleTimeString(),
|
||||
steps,
|
||||
...extra,
|
||||
},
|
||||
],
|
||||
}));
|
||||
return id;
|
||||
},
|
||||
|
||||
patchAiMessage: (id, patch) =>
|
||||
set((s) => ({
|
||||
aiMessages: s.aiMessages.map((m) => {
|
||||
if (m.id !== id) return m;
|
||||
return typeof patch === "function" ? patch(m) : { ...m, ...patch };
|
||||
}),
|
||||
})),
|
||||
|
||||
|
||||
setSession: (connectionId, sessionId) => {
|
||||
const sessions = { ...get().sessions };
|
||||
if (sessionId) sessions[connectionId] = sessionId;
|
||||
@@ -942,6 +977,18 @@ export const useWorkspaceStore = create<State>((set, get) => ({
|
||||
resultTab: "data",
|
||||
});
|
||||
},
|
||||
openAiResultSet: (label, sql, result) => {
|
||||
const id = crypto.randomUUID();
|
||||
const item: ResultSetItem = { id, label: label || "AI 结果", sql: sql || "", result };
|
||||
const prev = get().resultSets.filter((x) => x.id !== id);
|
||||
set({
|
||||
resultSets: [item, ...prev].slice(0, 30),
|
||||
activeResultSetId: id,
|
||||
result,
|
||||
resultTab: "data",
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
selectResultSet: (id) => {
|
||||
const item = get().resultSets.find((x) => x.id === id);
|
||||
|
||||
Reference in new issue
Block a user