feat: 增加 MCP 研究模板保存工具
This commit is contained in:
@@ -53,6 +53,12 @@ class ResearchAccess:
|
||||
"confirmation": "调用者须已获本批执行授权;直接提交后返回稳定运行 ID",
|
||||
"duplicate_policies": ["reject", "rerun"], "permissions": sorted(self.principal.scopes),
|
||||
"metadata_only": True, "actual_platform_allowance": None,
|
||||
"templates": {
|
||||
"create_with": "create_research_template", "required_scope": "research:write",
|
||||
"authored_by": "caller", "max_source_items": 20,
|
||||
"source_items_with": "get_backtest_results", "starts_backtests": False,
|
||||
"web_url": f"{self.public_origin}/#templates",
|
||||
},
|
||||
"submission_check": {
|
||||
"check_with": "check_submission", "read_with": "get_submission_check",
|
||||
"job_with": "get_refresh_job", "max_targets": 1,
|
||||
@@ -220,6 +226,18 @@ class ResearchAccess:
|
||||
async def history(self, args):
|
||||
return await self.evidence.history(args)
|
||||
|
||||
async def create_template(self, args):
|
||||
"""Persist the caller's template and evidence without model or queue execution."""
|
||||
from .templates import create_template
|
||||
|
||||
previous, digest = await self.previous("create_research_template", args)
|
||||
if previous:
|
||||
return previous.response
|
||||
result = await create_template(self.db, args, self.principal)
|
||||
result["web_url"] = f"{self.public_origin}/#templates"
|
||||
return await self.remember("create_research_template", args, digest, result,
|
||||
business_id=result["template_id"])
|
||||
|
||||
async def previous(self, operation, args):
|
||||
# PostgreSQL row lock is shared with HTTP start and catalog/job creation.
|
||||
account = await self.db.scalar(select(Account).where(Account.id == self.principal.account_id).with_for_update())
|
||||
@@ -233,13 +251,13 @@ class ResearchAccess:
|
||||
raise ResearchError("IDEMPOTENCY_CONFLICT", "幂等键已用于不同内容")
|
||||
return row, digest
|
||||
|
||||
async def remember(self, operation, args, digest, result):
|
||||
async def remember(self, operation, args, digest, result, *, business_id, wake=None):
|
||||
result["_meta"] = {"schema_version": 1, "observed_at": now().isoformat(), "source": "system"}
|
||||
self.db.add(ResearchRequest(id=str(uuid4()), account_id=self.principal.account_id,
|
||||
operation=operation, idempotency_key=args.idempotency_key, digest=digest,
|
||||
business_id=result["backtest_run_id"], response=encode_snapshot(result)))
|
||||
business_id=business_id, response=encode_snapshot(result)))
|
||||
await self.db.flush()
|
||||
self.wake = "backtests"
|
||||
self.wake = wake
|
||||
return result
|
||||
|
||||
async def validate_settings(self, candidates):
|
||||
@@ -286,7 +304,8 @@ class ResearchAccess:
|
||||
result = {**result, "input_digest": digest, "batch_count": preview["batch_count"],
|
||||
"duplicates": {"within_batch": within, "historical_matches": history["total"]},
|
||||
"validation": validation, "web_url": self.run_url(result["backtest_run_id"])}
|
||||
return await self.remember("submit_backtests", args, digest, result)
|
||||
return await self.remember("submit_backtests", args, digest, result,
|
||||
business_id=result["backtest_run_id"], wake="backtests")
|
||||
|
||||
async def run(self, args):
|
||||
result = await self.backtests.run(args.run_id)
|
||||
@@ -325,4 +344,5 @@ class ResearchAccess:
|
||||
"indefinite_account_block_cleared": args.action == "resume" and bool(before["scheduler"]["blocked_reason"])
|
||||
and before["scheduler"]["blocked_until"] is None,
|
||||
"note": "暂停/停止仅阻止后续提交;已提交模拟继续采集。recover 不重新提交。"}
|
||||
return await self.remember("control_backtest", args, digest, result)
|
||||
return await self.remember("control_backtest", args, digest, result,
|
||||
business_id=result["backtest_run_id"], wake="backtests")
|
||||
|
||||
Reference in New Issue
Block a user