refactor: unify AI capabilities and workspace integration
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
"""Domain-owned AI capabilities; caller owns authorization and transactions."""
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import HTTPException
|
||||
from pydantic import Field
|
||||
|
||||
from ..ai.capabilities import Capability, EmptyArgs
|
||||
from ..schemas import Contract
|
||||
from .contracts import ControlInput, PreviewInput, RerunInput, StartInput
|
||||
|
||||
|
||||
class BacktestRunArgs(Contract):
|
||||
run_id: str = Field(min_length=1, max_length=36)
|
||||
|
||||
|
||||
class BacktestListArgs(Contract):
|
||||
limit: int = Field(default=20, ge=1, le=100)
|
||||
offset: int = Field(default=0, ge=0)
|
||||
source: str | None = Field(default=None, max_length=100)
|
||||
reference: str | None = Field(default=None, max_length=200)
|
||||
research_id: str | None = Field(default=None, max_length=200)
|
||||
|
||||
|
||||
class BacktestDraftArgs(Contract):
|
||||
draft_id: str = Field(min_length=1, max_length=36)
|
||||
limit: int = Field(default=25, ge=1, le=100)
|
||||
offset: int = Field(default=0, ge=0)
|
||||
|
||||
|
||||
class BacktestResultsArgs(BacktestRunArgs):
|
||||
limit: int = Field(default=20, ge=1, le=100)
|
||||
offset: int = Field(default=0, ge=0)
|
||||
|
||||
|
||||
class BacktestPreviewArgs(Contract):
|
||||
preview_id: str = Field(min_length=1, max_length=36)
|
||||
limit: int = Field(default=20, ge=1, le=100)
|
||||
offset: int = Field(default=0, ge=0)
|
||||
|
||||
|
||||
class BacktestControlArgs(BacktestRunArgs):
|
||||
action: Literal["pause", "resume", "stop", "recover"]
|
||||
|
||||
|
||||
class BacktestRerunArgs(BacktestRunArgs):
|
||||
item_ids: list[str] = Field(min_length=1, max_length=100)
|
||||
|
||||
|
||||
async def draft(ctx, args):
|
||||
data = await ctx.business.backtests.draft(args.draft_id)
|
||||
candidates = data.pop("candidates")
|
||||
return {
|
||||
**data,
|
||||
"items": candidates[args.offset : args.offset + args.limit],
|
||||
"total": len(candidates),
|
||||
"limit": args.limit,
|
||||
"offset": args.offset,
|
||||
"has_more": args.offset + args.limit < len(candidates),
|
||||
}
|
||||
|
||||
|
||||
async def results(ctx, args):
|
||||
data = await ctx.business.backtests.results(**args.model_dump())
|
||||
# Keep the established card shape; complete raw snapshots remain available by business reference.
|
||||
for item in data["items"]:
|
||||
if item["result"]:
|
||||
snapshot = item["result"].pop("snapshot")
|
||||
item["result"].update({k: snapshot.get(k) for k in ("is", "os", "checks", "dateCreated")})
|
||||
return data
|
||||
|
||||
|
||||
async def preview_start(ctx, args):
|
||||
return {"backtest": await ctx.business.backtests.get_preview(args.preview_id)}
|
||||
|
||||
|
||||
async def start(ctx, args, preview):
|
||||
current = await ctx.business.backtests.get_preview(args.preview_id)
|
||||
if current["digest"] != preview["backtest"]["digest"] or current["version"] != args.version:
|
||||
raise HTTPException(409, "回测预览不匹配,请重新确认")
|
||||
return await ctx.business.backtests.start(args)
|
||||
|
||||
|
||||
async def preview_control(ctx, args):
|
||||
return {"backtest_run": await ctx.business.backtests.run(args.run_id), "action": args.action}
|
||||
|
||||
|
||||
async def control(ctx, args, preview):
|
||||
return await ctx.business.backtests.control(
|
||||
args.run_id, ControlInput(action=args.action, version=preview["backtest_run"]["version"])
|
||||
)
|
||||
|
||||
|
||||
async def wake_backtests(runner, result):
|
||||
"""Only committed, confirmed runs can wake the existing backtest lane."""
|
||||
runner.backtests.wake.set()
|
||||
|
||||
|
||||
INSTRUCTIONS = "回测先读取能力再准备固定候选预览,每次运行确认一次;后续候选新建预览。停止生成不取消回测。\n回测结果追问用 get_backtest/get_backtest_results。上下文或历史没有运行 ID 时,可用 list_backtests 按 source=chatbox 和会话 reference 找回;不得把启动返回当作结果。"
|
||||
|
||||
|
||||
CAPABILITIES = (
|
||||
Capability(
|
||||
name="get_backtest_draft",
|
||||
schema=BacktestDraftArgs,
|
||||
description="分页读取已有候选草稿、版本和来源,随后按 draft_id/draft_version 准备预览。",
|
||||
label="读取候选草稿",
|
||||
renderer="catalog",
|
||||
effect="query",
|
||||
handler=draft,
|
||||
),
|
||||
Capability(
|
||||
name="get_backtest_capabilities",
|
||||
schema=EmptyArgs,
|
||||
description="读取回测输入 schema、支持类型和本地调度配置,不代表平台剩余额度。",
|
||||
label="读取回测能力",
|
||||
renderer="backtest",
|
||||
effect="query",
|
||||
handler=lambda ctx, args: ctx.business.backtests.capabilities(),
|
||||
),
|
||||
Capability(
|
||||
name="prepare_backtest",
|
||||
schema=PreviewInput,
|
||||
description="准备服务端固定回测预览,可用 inline 候选或草稿引用;只保存预览,不提交平台,不需要执行确认。",
|
||||
label="准备回测预览",
|
||||
renderer="backtest",
|
||||
effect="prepare",
|
||||
handler=lambda ctx, args: ctx.business.backtests.preview(args),
|
||||
refresh=("backtests",),
|
||||
),
|
||||
Capability(
|
||||
name="get_backtest_preview",
|
||||
schema=BacktestPreviewArgs,
|
||||
description="分页读取完整固定预览,确认前核对表达式和最终参数。",
|
||||
label="查看回测预览",
|
||||
renderer="backtest",
|
||||
effect="query",
|
||||
handler=lambda ctx, args: ctx.business.backtests.get_preview(**args.model_dump()),
|
||||
),
|
||||
Capability(
|
||||
name="start_backtest",
|
||||
schema=StartInput,
|
||||
description="对已保存预览请求一次用户确认,确认后后台运行全部固定候选,立即返回运行 ID;禁止循环等待。",
|
||||
label="启动固定回测",
|
||||
renderer="backtest",
|
||||
effect="confirm",
|
||||
preview=preview_start,
|
||||
execute=start,
|
||||
after_commit=wake_backtests,
|
||||
refresh=("backtests",),
|
||||
),
|
||||
Capability(
|
||||
name="list_backtests",
|
||||
schema=BacktestListArgs,
|
||||
description="分页查询回测运行与统计,可按来源筛选。",
|
||||
label="查询回测运行",
|
||||
renderer="backtest",
|
||||
effect="query",
|
||||
handler=lambda ctx, args: ctx.business.backtests.runs(**args.model_dump()),
|
||||
),
|
||||
Capability(
|
||||
name="get_backtest",
|
||||
schema=BacktestRunArgs,
|
||||
description="查询指定运行的真实进度,不循环等待完成。",
|
||||
label="查看回测进度",
|
||||
renderer="backtest",
|
||||
effect="query",
|
||||
handler=lambda ctx, args: ctx.business.backtests.run(args.run_id),
|
||||
),
|
||||
Capability(
|
||||
name="get_backtest_results",
|
||||
schema=BacktestResultsArgs,
|
||||
description="分页读取逐项状态、历史指标和错误;未知结果不能推测为成功。",
|
||||
label="读取回测结果",
|
||||
renderer="backtest",
|
||||
effect="query",
|
||||
handler=results,
|
||||
),
|
||||
Capability(
|
||||
name="control_backtest",
|
||||
schema=BacktestControlArgs,
|
||||
description="预览并确认暂停/继续/停止剩余项/找回原任务;不远端取消,不重新提交。",
|
||||
label="控制回测运行",
|
||||
renderer="backtest",
|
||||
effect="confirm",
|
||||
preview=preview_control,
|
||||
execute=control,
|
||||
after_commit=wake_backtests,
|
||||
refresh=("backtests",),
|
||||
),
|
||||
Capability(
|
||||
name="prepare_backtest_rerun",
|
||||
schema=BacktestRerunArgs,
|
||||
description="从明确指定的已结束回测项准备新预览,保留来源;不会自动启动。",
|
||||
label="准备重跑预览",
|
||||
renderer="backtest",
|
||||
effect="prepare",
|
||||
handler=lambda ctx, args: ctx.business.backtests.rerun(
|
||||
args.run_id, RerunInput(item_ids=args.item_ids)
|
||||
),
|
||||
refresh=("backtests",),
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user