import type { PageContext, UIAction } from "./types"; import type { ResearchReference } from "./ResearchInput"; /** Only expose context already sent by the transport; never include unsaved notes. */ export function contextReferences(context: PageContext): ResearchReference[] { const refs: ResearchReference[] = []; const add = (id: string, label: string, value?: string | null) => { if (value) refs.push({ id, name: `${label}:${value}` }); }; const scope = context.catalog_scope; if (scope) add("scope", "范围", `${scope.region}/${scope.universe}/D${scope.delay}`); add("dataset", "数据集", context.dataset_id); add("field", "字段", context.field_id); add("input", "固定输入", context.input_snapshot_id); add("version", "集合版本", context.collection_version); add("asset", "研究素材", context.research_asset_id); add("experiment", "实验", context.research_experiment_id); add("alpha", "Alpha", context.alpha_id); add("run", "研究运行", context.research_run_id); add("backtest", "回测", context.backtest_run_id); if (context.selected_ids?.length) add("selection", "已选 Alpha", `${context.selected_ids.length} 条`); return refs; } export function researchPrompts(context: PageContext): string[] { switch (context.page) { case "datasets": return context.unsaved_field_selection ? ["解释当前数据集的字段和适用场景"] : context.input_snapshot_id ? [ "分析这个固定输入中的字段,提出可验证的研究假设", "基于这个固定输入构建候选,并预览回测", ] : [ "解释当前数据集的字段和适用场景", "如何选择字段并保存为固定研究输入?", ]; case "templates": return [ "解释当前模板的经济含义和变量组合", "检查当前研究输入与模板是否匹配", ]; case "variants": return [ "分析种子 Alpha,提出结构与字段变体思路", "比较结构变体与市场设置变体的适用场景", ]; case "features": return ["解释当前特征方案的处理步骤", "根据固定输入提出可验证的特征假设"]; default: return [ "查询当前研究对象与已有结果", "介绍从字段选择到候选回测的研究流程", ]; } } export type WorkspacePage = PageContext["page"] | "mcp-keys"; const contextLabels: Record< PageContext["page"], (context: PageContext) => string > = { fields: () => "上下文:字段目录", preparations: () => "上下文:数据准备", home: () => "上下文:首页看板", alphas: (context) => `上下文:${context.alpha_id ? `Alpha ${context.alpha_id}` : "Alpha 列表"}${context.selected_ids?.length ? ` · 已选 ${context.selected_ids.length} 条` : ""}`, operators: () => "上下文:算子库", templates: (context) => `上下文:模板工坊${context.research_asset_id ? ` · ${context.research_asset_id}` : ""}${context.research_experiment_id ? ` · 实验 ${context.research_experiment_id}` : ""}`, quantflow: (context) => `上下文:QuantFlow${context.research_run_id ? ` · ${context.research_run_id}` : ""}`, pipeline: (context) => `上下文:研究流水线${context.research_run_id ? ` · ${context.research_run_id}` : ""}`, features: () => "上下文:特征工程", variants: () => "上下文:Alpha 变体", account: () => "上下文:个人信息页", backtests: () => "上下文:回测研究", datasets: (context) => `上下文:${context.dataset_id ?? "数据目录"}${context.catalog_scope ? ` · ${context.catalog_scope.region}/${context.catalog_scope.universe}/D${context.catalog_scope.delay}` : ""}${context.input_snapshot_id ? " · 固定研究输入" : context.unsaved_field_selection ? " · 请先保存字段选择" : ""}(不发送未保存备注)`, }; export function contextLabel(context: PageContext): string { return contextLabels[context.page](context); } export function pageFromHash(hash: string): WorkspacePage { const value = hash.replace(/^#/, "").split("?")[0]; const page = value.startsWith("quantflow/") ? "quantflow" : value; if (page === "mcp-keys") return page; return Object.hasOwn(contextLabels, page) ? (page as WorkspacePage) : "home"; } type Destination = { page?: WorkspacePage; chat: "open" | "close" | "responsive"; }; // Exhaustive action destinations prevent a new action silently falling into Alpha. const destinations: Record = { open_feature: { page: "features", chat: "responsive" }, open_template: { page: "templates", chat: "responsive" }, open_experiment: { page: "templates", chat: "responsive" }, open_variant: { page: "variants", chat: "responsive" }, open_conversation: { chat: "open" }, open_research_input: { page: "preparations", chat: "close" }, open_backtest: { page: "backtests", chat: "responsive" }, open_backtest_preview: { page: "backtests", chat: "responsive" }, open_alpha: { page: "alphas", chat: "responsive" }, apply_filters: { page: "alphas", chat: "responsive" }, }; export function actionDestination(action: UIAction): Destination | undefined { return Object.hasOwn(destinations, action.type) ? destinations[action.type] : undefined; }