import type { AgentResult, RunnerErrorEnvelope, TaskInput } from '@cutie-crypto/connector-core'; import type { StrategyExecutionCapability, StrategyExecutionCapabilityPair } from './strategy-execution-capability'; import type { StrategyArtifactCallbackFields, StrategyExecutionRequest } from './strategy-execution-wire'; type JsonObject = Record; export interface ExternalBacktestSubmitConfig { server_url: string; connector_token: string; backtest_provider?: BacktestProviderConfig; backtest_tools?: BacktestToolConfig[]; /** W3.9 §11.1: 用于查 source.max_timeout_ms 作为调用 provider 的 cap */ backtest_provider_sources?: BacktestProviderSource[]; } export type BacktestProviderKind = 'none' | 'smoke' | 'external_http'; export interface BacktestProviderConfig { kind?: BacktestProviderKind; provider_name?: string; engine_name?: string; engine_version?: string; data_source?: string; endpoint?: string; api_key?: string; timeout_ms?: number; } /** W3.9 §5.1/§5.2 catalog wrapper types (P0 主线允许的枚举) */ export type BacktestWrapperType = 'python_inprocess' | 'local_cli' | 'local_http'; /** W3.9 §5.1/§5.2 数据源描述对象(脱敏后 snapshot 上报) */ export interface BacktestToolDataSource { type?: string; name?: string; description?: string; coverage_hint?: string; external_unverified?: boolean; } /** W3.9 §5.1/§5.2 execution 执行策略字段 */ export interface BacktestToolExecution { mode?: string; timeout_ms?: number; max_range_days?: number; /** 单次回测的 K 线根数上限。短周期(15m/30m)比 max_range_days 更早撞上的是根数 * 上限,UI 要拿它换算出「该周期最多回测多少天」。这一层漏掉字段会静默丢弃—— * 0918 实测就是这样让 15m 面板仍显示 365 天。加字段要同时改 normalizeCatalogExecution、 * 心跳 catalog 白名单和 buildSnapshotExecution 四处。 */ max_bars?: number; max_parallel_runs?: number; async_supported?: boolean; } /** W3.9 §5.2 adapter 字段(脱敏后保留 working_dir_policy / requires_manual_export) */ export interface BacktestToolAdapter { requires_manual_export?: boolean; working_dir_policy?: string; } /** W3.9 §5.2 output_schema 字段(声明 provider 可能返回什么) */ export interface BacktestToolOutputSchema { metrics?: string[]; artifacts?: string[]; series?: string[]; tables?: string[]; } /** W3.9 §5.2 report_capabilities 字段 */ export interface BacktestToolReportCapabilities { report_url?: boolean; /** §5.1: report_capabilities.scope P0 只能是 none 或 local_machine_only */ scope?: 'none' | 'local_machine_only' | null; formats?: string[]; retention_hint?: string; } /** W3.9 §5.2 security 字段(脱敏后保留 network_scope / secrets_stay_local / live_trading) */ export interface BacktestToolSecurity { network_scope?: string; secrets_stay_local?: boolean; live_trading?: boolean; } export interface BacktestToolConfig { tool_id: string; kind: BacktestProviderKind; name?: string; description?: string; wrapper_type?: BacktestWrapperType; provider_name?: string; engine_name?: string; engine_version?: string; data_source?: string; data_source_obj?: BacktestToolDataSource | null; endpoint?: string; api_key?: string; timeout_ms?: number; markets?: string[]; timeframes?: string[]; supported_symbols?: string[]; default?: boolean; health?: 'ok' | 'unavailable' | 'error'; param_schema?: Record | null; output_schema?: BacktestToolOutputSchema | null; execution?: BacktestToolExecution | null; adapter?: BacktestToolAdapter | null; report_capabilities?: BacktestToolReportCapabilities | null; security?: BacktestToolSecurity | null; failure_codes?: string[]; expected_outputs?: string[]; source_id?: string; last_seen_at?: number; /** * 62-1 SPEC §2:该 tool 所属 source 最近一次健康探测(fetchBacktestProviderHealth) * 捕获缓存的 provider 安装 revision / 进程指纹,供派单执行时构造完整性证据 * wire 字段(provider_revision / provider_process_fingerprint)——"本次 run 使用 * 该 run 前最近一次健康探测值",不在派单时同步重新探测。legacy/manual 配置 * (未走 catalog/健康探测周期)时保持 undefined,证据诚实缺失。 */ provider_revision?: string; provider_process_fingerprint?: string; /** 62-2 SPEC §5.2:Provider catalog 通过严格校验后缓存的完整 capability pair。 */ strategy_execution_capability?: StrategyExecutionCapability; strategy_execution_capability_hash?: string; } export interface BacktestProviderSource { id: string; kind: 'external_http'; base_url: string; catalog_url: string; backtest_url: string; api_key: string; timeout_ms: number; /** W3.9 §11.1 tool 未声明 execution.timeout_ms 时的缺省值 */ max_timeout_ms?: number; enabled: boolean; } export interface NormalizedBacktestProviderConfig { kind: BacktestProviderKind; provider_name?: string; engine_name?: string; engine_version?: string; data_source?: string; endpoint?: string; api_key?: string; timeout_ms?: number; /** 62-1 SPEC §2:选中 tool 缓存的最近一次健康探测 provider revision / 进程指纹(见 BacktestToolConfig 同名字段) */ provider_revision?: string; provider_process_fingerprint?: string; } export interface NormalizedBacktestEnvelope { run_id: string; draft_id?: string; provider_name: string; engine_name: string; engine_version: string; data_source: string; report_url?: string; symbol: string; market: string; timeframe: string; start_time?: string | number; end_time?: string | number; initial_capital: number; fee_rate?: number; slippage_bps?: number; params: JsonObject; strategy: JsonObject; assumptions: JsonObject; limitations: JsonObject; raw_envelope: JsonObject; /** 62-1 SPEC §2:server 派单时生成,connector 必须在全部回写(含失败)原样回传(防重放串单) */ dispatch_nonce?: string; /** * 62-1 SPEC §1.2:派单时锁定的受管 provider revision 期望值(server 从 anchor * 复制)。仅供 connector 端诊断参考——回写核对由 server 用 wire 的 * provider_revision 与 anchor 比对,connector 不需要也不在 wire 上回传本字段。 * 老 server(3.9.4 及更早)不下发时为 undefined;server 显式下发 null 表示 * 派单时受管 runtime 未上报过 revision。 */ expected_provider_revision?: string | null; } export interface ExternalBacktestResult extends Partial { run_id: string; result_status: 'success' | 'failed'; provider_name: string; provider_run_id: string; engine_name: string; engine_version: string; data_source: string; result_hash: string; /** W3.9 §7: scrub 后的相对 path/ref(去掉 scheme/host/port),绝不含 provider host */ report_url?: string; /** W3.9 §7: report_url 可见性范围(如 local_machine_only),由 provider 声明,connector 透传 */ report_url_scope?: string; error_type?: string; error_message?: string; metrics: JsonObject; equity_curve: JsonObject[]; trades: JsonObject[]; assumptions: JsonObject; limitations: JsonObject; raw_report: JsonObject; /** * 62-1 SPEC §2 逐 run 完整性 wire 证据(Connector 3.9.5+):可得才带,缺就不带 * ——不伪造。成功/失败通用;失败路径至少带 dispatch_nonce(若 envelope 提供)。 * smoke provider 诚实缺失,不产生任何证据字段。 */ dispatch_nonce?: string; executed_params_hash?: string; provider_revision?: string; connector_version?: string; provider_process_fingerprint?: string; data_manifest_json?: string; data_manifest_hash?: string; result_hash_normalized?: string; } interface StrategyArtifactExecutionContext { request: StrategyExecutionRequest; capability: StrategyExecutionCapabilityPair; } export interface ExternalBacktestSubmissionResult { ok: boolean; status_code: number; response_body: string; err_code?: number; err_msg?: string; } export interface BacktestProviderHealthResponse { ok: boolean; provider_id?: string; engine_name?: string; engine_version?: string; data_ready?: boolean; checked_at?: number; error_type?: string; error_message?: string; /** 62-1 SPEC §2:provider 安装 commit/tree hash(AgentDash sync 落盘的 revision) */ provider_revision?: string; /** 62-1 SPEC §2:provider 真实进程指纹 */ process_fingerprint?: string; } export interface BacktestProviderHealthIssue { error_type: string; error_message: string; } export interface BacktestProviderCatalogTool { tool_id: string; kind?: BacktestProviderKind; name?: string; description?: string; wrapper_type?: string; provider_name?: string; engine_name?: string; engine_version?: string; /** §5.1 provider 可声明对象形式 data_source;W3.8 参考实现是 string */ data_source?: string | BacktestToolDataSource | null; markets?: string[]; timeframes?: string[]; supported_symbols?: string[]; symbols?: string[]; /** §5.1 provider catalog 用 is_default;兼容 W3.8 旧 default 字段 */ is_default?: boolean; default?: boolean; /** §5.1: health 不允许出现在 provider catalog,由 connector 派生(读到也忽略) */ health?: 'ok' | 'unavailable' | 'error'; param_schema?: Record | null; output_schema?: BacktestToolOutputSchema | null; execution?: BacktestToolExecution | null; adapter?: BacktestToolAdapter | null; report_capabilities?: BacktestToolReportCapabilities | null; security?: BacktestToolSecurity | null; failure_codes?: string[]; expected_outputs?: string[]; /** 62-2 SPEC §5.2:两字段 all-or-none;运行时必须按完整 payload 严格校验。 */ strategy_execution_capability?: unknown; strategy_execution_capability_hash?: unknown; } export interface BacktestProviderCatalogResponse { schema?: string; tools?: BacktestProviderCatalogTool[]; } /** W3.9 §11.1 connector 调 provider 的硬上限 timeout cap(绝对上限,source.max_timeout_ms 也不得超过它) */ export declare const CONNECTOR_MAX_TIMEOUT_MS = 300000; export interface ProviderHttpError { ok: false; error_type: string; error_message: string; } export type ProviderHttpResult = { ok: true; data: T; } | ProviderHttpError; export interface BacktestProviderSourceRefreshConfig { backtest_provider_sources?: BacktestProviderSource[]; backtest_tools?: BacktestToolConfig[]; } export interface BacktestProviderRefreshResult { tools: BacktestToolConfig[]; unreachable: Array<{ source_id: string; error_type: string; error_message: string; }>; conflicts: Array<{ tool_id: string; existing_source_id: string; conflicting_source_id: string; }>; /** W3.9 §5.1 被 catalog 校验拒绝的 tool(未知 wrapper_type / 非 sync / live_trading=true / 缺必填等) */ rejected: Array<{ source_id: string; tool_id: string; reason: string; }>; /** 62-2:legacy tool 可保留,但无效 capability pair 被剥离并记录诊断。 */ capability_rejected: Array<{ source_id: string; tool_id: string; reason: string; }>; } export declare const RESULT_V2_SCHEMA = "cutie.backtest_result.v2"; /** * cutie.backtest_result.v2 data_manifest 结构校验(SPEC §2 冻结)。 * 返回 null 表示通过,否则返回不合规原因。 */ export declare function validateDataManifest(manifest: unknown): string | null; /** * cutie.backtest_result.v2 顶层结构校验(SPEC §2 冻结):顶层恰好 5 键; * trades 每笔恰好 10 键、seq 从 1 连续、side ∈ {long,short};equity_curve * 非空每点 {ts,equity};metrics 恰好 3 键且 trade_count == trades.length; * data_manifest 见 validateDataManifest。返回 null 表示通过。 */ export declare function validateResultV2(payload: unknown): string | null; /** * L2(Codex 建议 AND,核实后保留 OR): * server `strategy_backtest_service._build_envelope` 永远同时下发 scene='backtest_run' + * task_type='strategy.backtest.run',二者成对,不会独立出现。但 wire 协议把 `task.scene` * 标为可选(protocol.ts: `scene?`,core 用 `task.scene ?? task.payload.scene` 兜底), * 旧/边缘 server 可能只带其一。改 AND 会让"只带 task_type 缺 scene"的回测任务静默走普通 * agent 答复路径(更糟:回测被当自然语言回答,永远不打 /external-result)。 * * 两个匹配串(scene=backtest_run / task_type=strategy.backtest.run)都是回测专属,无其它 * scene/task_type 复用,所以 OR 没有 false-positive 面。结论:保留 OR(任一信号都正确路由)。 */ export declare function isBacktestRunTask(input: TaskInput): boolean; export declare function normalizeBacktestProviderConfig(config?: BacktestProviderConfig | null): NormalizedBacktestProviderConfig; export declare function isBacktestProviderAvailable(config?: BacktestProviderConfig | null): boolean; export declare function getBacktestCapabilities(config?: BacktestProviderConfig | null, tools?: unknown): string[]; /** * 检查 BacktestToolConfig 是否健康(可用)。 * 参考 isExternalHttpProviderConfigured 逻辑:smoke 总是可用, * external_http 需要 endpoint + api_key 且 endpoint 是 loopback/private 合法 URL(H3)。 */ export declare function isBacktestToolHealthy(tool: BacktestToolConfig): boolean; export declare function fetchBacktestProviderHealth(source: BacktestProviderSource): Promise>; /** * Provider 只有同时明确声明 `ok=true` 和 `data_ready=true` 才能提供回测。 * * `ok` 表示服务进程能响应,`data_ready` 表示实际行情依赖已就绪;后者为 false * 或缺失时 fail-closed,避免把“HTTP 活着但没有可用数据”的 Provider 注册成健康工具。 */ export declare function getBacktestProviderHealthIssue(health: BacktestProviderHealthResponse): BacktestProviderHealthIssue | null; export declare function fetchBacktestProviderCatalog(source: BacktestProviderSource): Promise>; /** * W3.9 §5.1: 校验 provider catalog tool 是否满足 P0 正式 schema。 * 返回 null 表示通过,返回 string 表示拒绝原因。 * * 校验项: * - 必填字段(tool_id / markets / timeframes 数组) * - wrapper_type ∈ {python_inprocess, local_cli, local_http} * - execution.mode == 'sync'(P0 只支持同步) * - security.live_trading == false(true 的 provider 不得注册) * - param_schema 必须是 JSON Schema subset(object 形态) */ export declare function validateProviderCatalogTool(tool: BacktestProviderCatalogTool): string | null; /** * W3.9 §6.1: connector 用本地 catalog 的 param_schema 二次校验 provider_params。 * 返回 null 表示通过,返回 string 表示违例原因(用于 INVALID_PARAMS failed result)。 * * P0 JSON Schema subset:object / string / number / integer / boolean / enum / default / minimum / maximum / required。 * - param_schema 缺失或非对象 → 跳过校验(不约束)。 * - additionalProperties=false(或默认)时拒绝未声明字段。 * - required 字段缺失(且无 default)→ 拒绝。 * - 类型不符 / 不在 enum / 越界 → 拒绝。 */ export declare function validateProviderParams(params: JsonObject | undefined, schema: Record | null | undefined): string | null; export declare function refreshBacktestProviderSources(config: BacktestProviderSourceRefreshConfig): Promise; /** * 返回可用于 artifact 请求/心跳的缓存 pair。每次消费前重新校验,防止磁盘配置 * 被手改、旧缓存与最新 health revision 漂移,或 generic scrub 破坏 payload/hash。 */ export declare function getBacktestToolStrategyCapability(tool: BacktestToolConfig): StrategyExecutionCapabilityPair | undefined; /** * Artifact dispatch is allowed only for the exact pair that survives the complete * heartbeat catalog builder. This keeps task routing aligned with the 32 KiB catalog * rule (which removes every capability pair rather than truncating by tool order). */ export declare function getAdvertisedBacktestToolStrategyCapability(tool: BacktestToolConfig, tools: BacktestToolConfig[]): StrategyExecutionCapabilityPair | undefined; export declare function buildBacktestToolsCatalog(tools: unknown): string; /** * 62-1 SPEC §2:心跳 backtest 相关字段的共享构造,openclaw/hermes/cutie 三个 * platform adapter 的 augmentHeartbeat 复用(不各自重复一份同样的 if/字段拼接)。 * `provider_revision` 与 `backtest_tools_json` 同位置新增,已知才带:取当前 * default tool 缓存的最近一次健康探测 revision,缺省时退而取任一已知 revision * 的 tool。connector runtime 是"单进程可能承载多 scene"但 62-1 场景下每个 * runtime 通常只对应一个受管 provider 安装,因此心跳层面只上报单值。 */ export declare function buildBacktestHeartbeatFields(tools: unknown): { backtest_tools_json?: string; provider_revision?: string; }; /** Current Connector register/heartbeat semantics: absence is an empty replacement. */ export declare function buildCurrentBacktestHeartbeatFields(tools: unknown): { backtest_tools_json?: string; provider_revision?: string; }; /** * 当 config 没有 backtest_tools 但有 backtest_provider 且 kind != 'none' 时, * 从 legacy provider 合成一条 tool(tool_id = 'legacy.default')。 */ export declare function synthesizeToolsFromLegacyProvider(provider: BacktestProviderConfig): BacktestToolConfig[]; export interface ResolvedProvider { provider?: NormalizedBacktestProviderConfig; /** W3.9 §11.1: 选中的 tool(带 execution 元数据),用于 enforce timeout / range / parallel;legacy fallback 时为 undefined */ tool?: BacktestToolConfig; error?: { type: RunnerErrorEnvelope['error_type']; message: string; }; } /** * W3.7d: 按 provider_tool_id 查找工具配置,支持多 runner 路由。 * * 路由优先级: * 1. toolId 非空 + backtest_tools 存在 → 精确匹配 * 2. toolId 为空 + backtest_tools 存在 → default=true 的工具 * 3. fallback → 旧 backtest_provider */ export declare function resolveProvider(toolId: string | undefined, config: ExternalBacktestSubmitConfig): ResolvedProvider; /** * 把 BacktestToolConfig 转成 NormalizedBacktestProviderConfig, * 用于 runSmokeBacktest / runExternalHttpBacktest 执行。 */ export declare function toolConfigToProvider(tool: BacktestToolConfig): NormalizedBacktestProviderConfig; /** * W3.9 §11.1: 计算调用 provider 的 effective timeout。 * effective = min(tool.execution.timeout_ms ?? source.timeout_ms ?? 120000, * connector.max_timeout_ms ?? 300000) * * @param toolTimeoutMs tool.execution.timeout_ms(首选) * @param sourceTimeoutMs source 默认 timeout(缺省值) * @param maxTimeoutMs connector 硬上限 cap(source.max_timeout_ms ?? 300000) */ export declare function computeEffectiveBacktestTimeout(toolTimeoutMs: number | undefined, sourceTimeoutMs: number | undefined, maxTimeoutMs: number | undefined): number; /** * W3.9 §12: 判断 host 是否为 loopback 或 RFC1918 私网段(信任边界唯一守卫)。 * 允许:127.0.0.0/8、::1、localhost / *.localhost、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。 * 拒绝:公网 IP、公网域名、云 metadata 端点(169.254.169.254 等 link-local)。 * * 放在 backtest.ts(信任边界模块)作为唯一实现:cli 配置(add / legacy)、 * runtime fallback(isExternalHttpProviderConfigured)、postExternalHttpBacktest 都经过它。 */ export declare function isLoopbackOrPrivateHost(hostname: string): boolean; export declare function isExternalHttpProviderConfigured(providerConfig?: BacktestProviderConfig | NormalizedBacktestProviderConfig | null): boolean; export declare function handleBacktestRunTask(input: TaskInput, config: ExternalBacktestSubmitConfig): Promise; export declare function normalizeBacktestEnvelope(input: TaskInput): NormalizedBacktestEnvelope; export declare function runSmokeBacktest(envelope: NormalizedBacktestEnvelope, providerConfig?: BacktestProviderConfig | NormalizedBacktestProviderConfig | null): ExternalBacktestResult; export declare function runExternalHttpBacktest(envelope: NormalizedBacktestEnvelope, providerConfig: NormalizedBacktestProviderConfig, timeoutMs?: number, artifactContext?: StrategyArtifactExecutionContext): Promise; export declare function buildExternalBacktestResultPayload(result: ExternalBacktestResult): Record; export declare function submitExternalBacktestResult(config: ExternalBacktestSubmitConfig, result: ExternalBacktestResult, timeoutMs?: number): Promise; /** * W3.9 §7: 把 provider 返回的 report_url 规范化为相对 path/ref。 * * - 相对 path/ref(不含 scheme/host)→ 原样保留 * - 绝对 URL(loopback / RFC1918 / 公网)→ 去掉 scheme/host/port,只保留 pathname(+search) * - 本机绝对文件路径(/Users/... 等)→ scrub 成 undefined(§7 禁止把绝对路径当 report_url) * * 保留 report_url_scope 由调用方单独处理。 */ export declare function scrubReportUrl(reportUrl: string | undefined): string | undefined; export {};