2026-09-08 19:28:44 +08:00
|
|
|
|
import type { PageContext, UIAction } from "./types";
|
2026-09-10 12:22:26 +08:00
|
|
|
|
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);
|
2026-09-12 01:24:02 +08:00
|
|
|
|
add("input", "固定输入", context.input_snapshot_id);
|
2026-09-10 12:22:26 +08:00
|
|
|
|
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
|
|
|
|
|
|
? ["解释当前数据集的字段和适用场景"]
|
2026-09-12 01:24:02 +08:00
|
|
|
|
: context.input_snapshot_id
|
2026-09-10 12:22:26 +08:00
|
|
|
|
? [
|
|
|
|
|
|
"分析这个固定输入中的字段,提出可验证的研究假设",
|
|
|
|
|
|
"基于这个固定输入构建候选,并预览回测",
|
|
|
|
|
|
]
|
|
|
|
|
|
: [
|
|
|
|
|
|
"解释当前数据集的字段和适用场景",
|
|
|
|
|
|
"如何选择字段并保存为固定研究输入?",
|
|
|
|
|
|
];
|
|
|
|
|
|
case "templates":
|
|
|
|
|
|
return [
|
|
|
|
|
|
"解释当前模板的经济含义和变量组合",
|
|
|
|
|
|
"检查当前研究输入与模板是否匹配",
|
|
|
|
|
|
];
|
|
|
|
|
|
case "variants":
|
|
|
|
|
|
return [
|
|
|
|
|
|
"分析种子 Alpha,提出结构与字段变体思路",
|
|
|
|
|
|
"比较结构变体与市场设置变体的适用场景",
|
|
|
|
|
|
];
|
|
|
|
|
|
case "features":
|
|
|
|
|
|
return ["解释当前特征方案的处理步骤", "根据固定输入提出可验证的特征假设"];
|
|
|
|
|
|
default:
|
|
|
|
|
|
return [
|
|
|
|
|
|
"查询当前研究对象与已有结果",
|
|
|
|
|
|
"介绍从字段选择到候选回测的研究流程",
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-09-08 19:28:44 +08:00
|
|
|
|
|
2026-09-09 16:18:27 +08:00
|
|
|
|
export type WorkspacePage = PageContext["page"] | "mcp-keys";
|
|
|
|
|
|
const contextLabels: Record<
|
|
|
|
|
|
PageContext["page"],
|
|
|
|
|
|
(context: PageContext) => string
|
|
|
|
|
|
> = {
|
2026-09-12 01:24:02 +08:00
|
|
|
|
fields: () => "上下文:字段目录",
|
|
|
|
|
|
preparations: () => "上下文:数据准备",
|
2026-09-09 18:20:08 +08:00
|
|
|
|
home: () => "上下文:首页看板",
|
2026-09-08 19:28:44 +08:00
|
|
|
|
alphas: (context) =>
|
|
|
|
|
|
`上下文:${context.alpha_id ? `Alpha ${context.alpha_id}` : "Alpha 列表"}${context.selected_ids?.length ? ` · 已选 ${context.selected_ids.length} 条` : ""}`,
|
2026-09-08 21:29:21 +08:00
|
|
|
|
operators: () => "上下文:算子库",
|
|
|
|
|
|
templates: (context) =>
|
|
|
|
|
|
`上下文:模板工坊${context.research_asset_id ? ` · ${context.research_asset_id}` : ""}${context.research_experiment_id ? ` · 实验 ${context.research_experiment_id}` : ""}`,
|
2026-09-08 22:42:29 +08:00
|
|
|
|
quantflow: (context) =>
|
|
|
|
|
|
`上下文:QuantFlow${context.research_run_id ? ` · ${context.research_run_id}` : ""}`,
|
2026-09-08 22:16:05 +08:00
|
|
|
|
pipeline: (context) =>
|
|
|
|
|
|
`上下文:研究流水线${context.research_run_id ? ` · ${context.research_run_id}` : ""}`,
|
2026-09-08 21:52:46 +08:00
|
|
|
|
features: () => "上下文:特征工程",
|
2026-09-08 21:29:21 +08:00
|
|
|
|
variants: () => "上下文:Alpha 变体",
|
2026-09-08 19:28:44 +08:00
|
|
|
|
account: () => "上下文:个人信息页",
|
|
|
|
|
|
backtests: () => "上下文:回测研究",
|
|
|
|
|
|
datasets: (context) =>
|
2026-09-12 01:24:02 +08:00
|
|
|
|
`上下文:${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 ? " · 请先保存字段选择" : ""}(不发送未保存备注)`,
|
2026-09-08 19:28:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export function contextLabel(context: PageContext): string {
|
|
|
|
|
|
return contextLabels[context.page](context);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function pageFromHash(hash: string): WorkspacePage {
|
2026-09-09 16:18:27 +08:00
|
|
|
|
const value = hash.replace(/^#/, "").split("?")[0];
|
2026-09-09 09:29:30 +08:00
|
|
|
|
const page = value.startsWith("quantflow/") ? "quantflow" : value;
|
2026-09-09 16:18:27 +08:00
|
|
|
|
if (page === "mcp-keys") return page;
|
2026-09-09 18:20:08 +08:00
|
|
|
|
return Object.hasOwn(contextLabels, page) ? (page as WorkspacePage) : "home";
|
2026-09-08 19:28:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type Destination = {
|
|
|
|
|
|
page?: WorkspacePage;
|
|
|
|
|
|
chat: "open" | "close" | "responsive";
|
|
|
|
|
|
};
|
|
|
|
|
|
// Exhaustive action destinations prevent a new action silently falling into Alpha.
|
|
|
|
|
|
const destinations: Record<UIAction["type"], Destination> = {
|
2026-09-08 21:52:46 +08:00
|
|
|
|
open_feature: { page: "features", chat: "responsive" },
|
2026-09-08 21:29:21 +08:00
|
|
|
|
open_template: { page: "templates", chat: "responsive" },
|
|
|
|
|
|
open_experiment: { page: "templates", chat: "responsive" },
|
|
|
|
|
|
open_variant: { page: "variants", chat: "responsive" },
|
2026-09-08 19:28:44 +08:00
|
|
|
|
open_conversation: { chat: "open" },
|
2026-09-12 01:24:02 +08:00
|
|
|
|
open_research_input: { page: "preparations", chat: "close" },
|
2026-09-08 19:28:44 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|