feat: integrate chatbox research with datasets and backtests

This commit is contained in:
yuxuanhui
2026-09-08 12:43:00 +08:00
parent 43336ad960
commit aef8e1d310
37 changed files with 1421 additions and 42 deletions
+35 -2
View File
@@ -19,6 +19,7 @@ import {
stateLabels,
} from "../api";
import { BacktestToolCard } from "../backtests/BacktestToolCard";
import { CatalogToolCard } from "../research/CatalogToolCard";
import { PnlChart } from "../components/PnlChart";
import type { Alpha, Job, Pnl, Research } from "../types";
import { chatTransport } from "./transport";
@@ -45,6 +46,7 @@ export function ChatPanel({
onWidth,
timezone,
jobs,
action,
}: {
open: boolean;
context: PageContext;
@@ -56,6 +58,7 @@ export function ChatPanel({
onWidth: (width: number) => void;
timezone?: string;
jobs: Job[];
action: UIAction | null;
}) {
const [settings, setSettings] = useState<ModelSettings | null>(null);
const [conversations, setConversations] = useState<Conversation[]>([]);
@@ -179,6 +182,32 @@ export function ChatPanel({
setLoading(true);
void refreshConversation().finally(() => setLoading(false));
}, [conversationId, refreshConversation]);
useEffect(() => {
if (action?.type !== "open_conversation") return;
let live = true;
void api<ConversationDetail>(
`/ai/conversations/${encodeURIComponent(action.conversation_id)}`,
)
.then(async (detail) => {
if (!live) return;
await chat.stop();
if (!live) return;
setConversations((items) =>
items.some((item) => item.id === detail.id)
? items
: [{ id: detail.id, title: detail.title }, ...items],
);
setConversationId(detail.id);
setText("");
setFailure("");
})
.catch((e) => {
if (live) setFailure(e.message);
});
return () => {
live = false;
};
}, [action]);
const streaming = chat.status === "streaming" || chat.status === "submitted";
const activeRun = runs.find((run) =>
["running", "waiting_approval"].includes(run.status),
@@ -375,7 +404,10 @@ export function ChatPanel({
{!chat.messages.length && (
<div className="ai-empty">
<h3>从当前研究出发</h3>
<p>可以让我筛选 Alpha、解释已有指标,或提出研究记录修改。</p>
<p>
可以让我选择数据字段、构建候选并预览回测,也可以查询 Alpha
和已有结果。
</p>
{!conversationId && (
<Button
type="tertiary"
@@ -440,7 +472,7 @@ export function ChatPanel({
{context.page === "backtests"
? "上下文:回测研究"
: context.page === "datasets"
? "上下文:数据目录(未发送字段与备注)"
? `上下文:${context.dataset_id ?? "数据目录"}${context.catalog_scope ? ` · ${context.catalog_scope.region}/${context.catalog_scope.universe}/D${context.catalog_scope.delay}` : ""}${context.template_input_id ? " · 固定研究输入" : context.unsaved_field_selection ? " · 请先保存字段选择" : ""}(不发送未保存备注)`
: context.page === "account"
? "上下文:个人信息页"
: `上下文:${context.alpha_id ? `Alpha ${context.alpha_id}` : "Alpha 列表"}${context.selected_ids?.length ? ` · 已选 ${context.selected_ids.length} 条` : ""}`}
@@ -547,6 +579,7 @@ function BusinessCard({
{call.name.includes("backtest") && (
<BacktestToolCard call={call} onAction={onAction} />
)}
<CatalogToolCard call={call} onAction={onAction} />
{call.preview.targets?.map((target) => (
<details
key={target.alpha_id}
+21
View File
@@ -12,6 +12,17 @@ export type ModelSettings = {
};
export type PageContext = {
page: "alphas" | "account" | "datasets" | "backtests";
catalog_scope?: {
instrument_type: string;
region: string;
universe: string;
delay: number;
};
dataset_id?: string;
field_id?: string;
collection_version?: string;
template_input_id?: string;
unsaved_field_selection?: boolean;
backtest_run_id?: string;
backtest_preview_id?: string;
backtest_draft_id?: string;
@@ -23,6 +34,8 @@ export type AlphaUIAction =
| { type: "open_alpha"; alpha_id: string; nonce: number }
| { type: "apply_filters"; filters: Record<string, unknown>; nonce: number };
export type UIAction =
| { type: "open_conversation"; conversation_id: string; nonce: number }
| { type: "open_research_input"; input_id: string; nonce: number }
| { type: "open_backtest"; run_id: string; nonce: number }
| { type: "open_backtest_preview"; preview_id: string; nonce: number }
| { type: "open_alpha"; alpha_id: string; nonce: number }
@@ -75,6 +88,14 @@ export const runLabels: Record<string, string> = {
interrupted: "执行中断",
};
export const toolLabels: Record<string, string> = {
get_catalog_scopes: "读取研究范围",
search_catalog: "查询数据集与字段",
get_catalog_detail: "读取数据详情",
prepare_research_input: "固定研究输入",
get_research_input: "读取固定研究输入",
prepare_research_backtest: "构建研究候选与预览",
get_backtest_draft: "读取候选草稿",
get_alpha_sources: "查询 Alpha 研究来源",
get_backtest_capabilities: "读取回测能力",
prepare_backtest: "准备回测预览",
get_backtest_preview: "查看回测预览",