quantnodes 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. QuantNodes/__init__.py +15 -0
  2. QuantNodes/__main__.py +14 -0
  3. QuantNodes/agent/__init__.py +158 -0
  4. QuantNodes/agent/agents/__init__.py +13 -0
  5. QuantNodes/agent/agents/definition.py +180 -0
  6. QuantNodes/agent/agents/manager.py +73 -0
  7. QuantNodes/agent/config/__init__.py +34 -0
  8. QuantNodes/agent/config/executor.py +958 -0
  9. QuantNodes/agent/config/loader.py +427 -0
  10. QuantNodes/agent/config/templates/bollinger_bands.yaml +84 -0
  11. QuantNodes/agent/config/templates/dual_ma.yaml +72 -0
  12. QuantNodes/agent/config/templates/empty.yaml +56 -0
  13. QuantNodes/agent/config/templates/mean_reversion.yaml +47 -0
  14. QuantNodes/agent/config/templates/mean_reversion_zscore.yaml +90 -0
  15. QuantNodes/agent/config/templates/momentum.yaml +81 -0
  16. QuantNodes/agent/config/templates/momentum_breakout.yaml +84 -0
  17. QuantNodes/agent/config/templates/rsi_strategy.yaml +72 -0
  18. QuantNodes/agent/config/templates/volume_price.yaml +86 -0
  19. QuantNodes/agent/config/types.py +156 -0
  20. QuantNodes/agent/config_mapper.py +293 -0
  21. QuantNodes/agent/core/__init__.py +19 -0
  22. QuantNodes/agent/core/dream.py +47 -0
  23. QuantNodes/agent/core/quant_dream.py +274 -0
  24. QuantNodes/agent/cron_jobs.py +314 -0
  25. QuantNodes/agent/nanobot_bridge.py +242 -0
  26. QuantNodes/agent/permission/__init__.py +30 -0
  27. QuantNodes/agent/permission/defaults.py +36 -0
  28. QuantNodes/agent/permission/evaluate.py +41 -0
  29. QuantNodes/agent/permission/models.py +59 -0
  30. QuantNodes/agent/permission/service.py +133 -0
  31. QuantNodes/agent/providers/__init__.py +11 -0
  32. QuantNodes/agent/providers/base.py +102 -0
  33. QuantNodes/agent/providers/quantnodes.py +610 -0
  34. QuantNodes/agent/providers/rate_limiter.py +326 -0
  35. QuantNodes/agent/providers/registry.py +163 -0
  36. QuantNodes/agent/skills/__init__.py +20 -0
  37. QuantNodes/agent/skills/base.py +118 -0
  38. QuantNodes/agent/skills/bridge.py +73 -0
  39. QuantNodes/agent/skills/factor/__init__.py +14 -0
  40. QuantNodes/agent/skills/factor/correlation.py +99 -0
  41. QuantNodes/agent/skills/factor/group_backtest.py +114 -0
  42. QuantNodes/agent/skills/factor/ic_analysis.py +106 -0
  43. QuantNodes/agent/skills/loader.py +107 -0
  44. QuantNodes/agent/skills/registry.py +105 -0
  45. QuantNodes/agent/skills/strategy/__init__.py +16 -0
  46. QuantNodes/agent/skills/strategy/bollinger.py +86 -0
  47. QuantNodes/agent/skills/strategy/dual_ma.py +82 -0
  48. QuantNodes/agent/skills/strategy/momentum.py +74 -0
  49. QuantNodes/agent/skills/strategy/rsi_reversal.py +99 -0
  50. QuantNodes/agent/skills_quant/__init__.py +14 -0
  51. QuantNodes/agent/skills_quant/backtest-analyze/SKILL.md +42 -0
  52. QuantNodes/agent/skills_quant/config-driven/SKILL.md +72 -0
  53. QuantNodes/agent/skills_quant/factor-research/SKILL.md +40 -0
  54. QuantNodes/agent/skills_quant/quant-dream/SKILL.md +55 -0
  55. QuantNodes/agent/skills_quant/risk-management/SKILL.md +45 -0
  56. QuantNodes/agent/skills_quant/strategy-design/SKILL.md +43 -0
  57. QuantNodes/agent/templates/__init__.py +4 -0
  58. QuantNodes/agent/tools/__init__.py +173 -0
  59. QuantNodes/agent/tools/_workspace.py +51 -0
  60. QuantNodes/agent/tools/alpha_backtest.py +328 -0
  61. QuantNodes/agent/tools/alpha_evaluate.py +493 -0
  62. QuantNodes/agent/tools/backtest.py +226 -0
  63. QuantNodes/agent/tools/base.py +133 -0
  64. QuantNodes/agent/tools/code_search.py +207 -0
  65. QuantNodes/agent/tools/config_backtest.py +401 -0
  66. QuantNodes/agent/tools/context.py +97 -0
  67. QuantNodes/agent/tools/dream_skill.py +77 -0
  68. QuantNodes/agent/tools/echo.py +38 -0
  69. QuantNodes/agent/tools/factor.py +231 -0
  70. QuantNodes/agent/tools/file_ops.py +201 -0
  71. QuantNodes/agent/tools/git_ops.py +190 -0
  72. QuantNodes/agent/tools/operator_lookup.py +218 -0
  73. QuantNodes/agent/tools/output_truncation.py +77 -0
  74. QuantNodes/agent/tools/path_check.py +43 -0
  75. QuantNodes/agent/tools/pipeline.py +62 -0
  76. QuantNodes/agent/tools/registry.py +150 -0
  77. QuantNodes/agent/tools/sandbox.py +62 -0
  78. QuantNodes/agent/tools/shell_safety.py +63 -0
  79. QuantNodes/agent/tools/strategy.py +106 -0
  80. QuantNodes/agent/tools/task.py +171 -0
  81. QuantNodes/agent/tools/web_fetch.py +142 -0
  82. QuantNodes/agent/tools/web_search.py +114 -0
  83. QuantNodes/agent/tools/wiki.py +370 -0
  84. QuantNodes/agent/utils/__init__.py +11 -0
  85. QuantNodes/agent/utils/helpers.py +43 -0
  86. QuantNodes/agent/utils/prompt_templates.py +30 -0
  87. QuantNodes/agent/workflows/__init__.py +20 -0
  88. QuantNodes/agent/workflows/implementations/__init__.py +8 -0
  89. QuantNodes/agent/workflows/implementations/alpha_gpt.py +508 -0
  90. QuantNodes/agent/workflows/implementations/mcts.py +442 -0
  91. QuantNodes/agent/workflows/parsers.py +44 -0
  92. QuantNodes/agent/workflows/registry.py +119 -0
  93. QuantNodes/agent/workflows/step_agent.py +219 -0
  94. QuantNodes/agent/workflows/tool.py +198 -0
  95. QuantNodes/ai/__init__.py +93 -0
  96. QuantNodes/ai/llm/__init__.py +75 -0
  97. QuantNodes/ai/llm/base.py +233 -0
  98. QuantNodes/ai/llm/decorators.py +281 -0
  99. QuantNodes/ai/llm/gateway.py +571 -0
  100. QuantNodes/ai/llm/null.py +76 -0
  101. QuantNodes/ai/llm/openai.py +435 -0
  102. QuantNodes/ai/optimizer.py +405 -0
  103. QuantNodes/ai/prompts/__init__.py +229 -0
  104. QuantNodes/ai/sandbox.py +371 -0
  105. QuantNodes/ai/sandbox_pandas_bridge.py +150 -0
  106. QuantNodes/ai/strategy_gen.py +396 -0
  107. QuantNodes/backtest/__init__.py +64 -0
  108. QuantNodes/backtest/backtest_node.py +188 -0
  109. QuantNodes/backtest/broker_node.py +378 -0
  110. QuantNodes/backtest/config_runner.py +397 -0
  111. QuantNodes/backtest/config_strategy.py +64 -0
  112. QuantNodes/backtest/risk_node.py +360 -0
  113. QuantNodes/backtest/strategy_node.py +268 -0
  114. QuantNodes/cache_node/__init__.py +19 -0
  115. QuantNodes/cache_node/base.py +244 -0
  116. QuantNodes/cache_node/cache_store.py +99 -0
  117. QuantNodes/cache_node/metadata.py +100 -0
  118. QuantNodes/cli/__init__.py +109 -0
  119. QuantNodes/cli/_helpers.py +511 -0
  120. QuantNodes/cli/command.py +110 -0
  121. QuantNodes/cli/commands/__init__.py +69 -0
  122. QuantNodes/cli/commands/agent.py +158 -0
  123. QuantNodes/cli/commands/alpha.py +951 -0
  124. QuantNodes/cli/commands/chat.py +38 -0
  125. QuantNodes/cli/commands/evolve.py +120 -0
  126. QuantNodes/cli/commands/factor.py +569 -0
  127. QuantNodes/cli/commands/init.py +190 -0
  128. QuantNodes/cli/commands/run.py +259 -0
  129. QuantNodes/cli/commands/serve.py +398 -0
  130. QuantNodes/cli/commands/version.py +120 -0
  131. QuantNodes/cli/enhanced.py +146 -0
  132. QuantNodes/conf_node/__init__.py +37 -0
  133. QuantNodes/conf_node/base.py +120 -0
  134. QuantNodes/conf_node/env_config.py +132 -0
  135. QuantNodes/conf_node/ini_config.py +70 -0
  136. QuantNodes/conf_node/json_config.py +69 -0
  137. QuantNodes/conf_node/yaml_config.py +78 -0
  138. QuantNodes/constants.py +17 -0
  139. QuantNodes/core/__init__.py +196 -0
  140. QuantNodes/core/_lookback_helpers.py +49 -0
  141. QuantNodes/core/ast_parser.py +198 -0
  142. QuantNodes/core/base.py +61 -0
  143. QuantNodes/core/cache_manager.py +344 -0
  144. QuantNodes/core/cache_utils.py +150 -0
  145. QuantNodes/core/cond_builder.py +53 -0
  146. QuantNodes/core/config.py +170 -0
  147. QuantNodes/core/constants.py +48 -0
  148. QuantNodes/core/control.py +412 -0
  149. QuantNodes/core/data_preprocessing.py +453 -0
  150. QuantNodes/core/data_source.py +46 -0
  151. QuantNodes/core/events.py +178 -0
  152. QuantNodes/core/evolution/__init__.py +22 -0
  153. QuantNodes/core/evolution/loop.py +583 -0
  154. QuantNodes/core/evolution/operators.py +289 -0
  155. QuantNodes/core/evolution/settings.py +44 -0
  156. QuantNodes/core/expression.py +841 -0
  157. QuantNodes/core/feedback/__init__.py +38 -0
  158. QuantNodes/core/feedback/channels.py +182 -0
  159. QuantNodes/core/feedback/collector.py +91 -0
  160. QuantNodes/core/feedback/dataclass.py +239 -0
  161. QuantNodes/core/feedback/llm_judge.py +138 -0
  162. QuantNodes/core/knowledge/__init__.py +69 -0
  163. QuantNodes/core/knowledge/knowledge_base.py +217 -0
  164. QuantNodes/core/knowledge/lineage_compress.py +196 -0
  165. QuantNodes/core/knowledge/lineage_expand.py +123 -0
  166. QuantNodes/core/knowledge/metrics/__init__.py +43 -0
  167. QuantNodes/core/knowledge/metrics/evaluator.py +176 -0
  168. QuantNodes/core/knowledge/metrics/metrics.py +220 -0
  169. QuantNodes/core/knowledge/rag_prompt.py +196 -0
  170. QuantNodes/core/knowledge/retriever.py +209 -0
  171. QuantNodes/core/lambda_node.py +81 -0
  172. QuantNodes/core/monitoring/__init__.py +22 -0
  173. QuantNodes/core/monitoring/collector.py +292 -0
  174. QuantNodes/core/monitoring/dashboard.py +365 -0
  175. QuantNodes/core/node.py +375 -0
  176. QuantNodes/core/pandas_utils.py +504 -0
  177. QuantNodes/core/parallel/__init__.py +15 -0
  178. QuantNodes/core/parallel/worker.py +140 -0
  179. QuantNodes/core/parallel/worker_process.py +265 -0
  180. QuantNodes/core/path_utils.py +73 -0
  181. QuantNodes/core/pipeline.py +328 -0
  182. QuantNodes/core/plugin.py +135 -0
  183. QuantNodes/core/quality_gate/__init__.py +32 -0
  184. QuantNodes/core/quality_gate/complexity.py +94 -0
  185. QuantNodes/core/quality_gate/consistency.py +26 -0
  186. QuantNodes/core/quality_gate/node.py +97 -0
  187. QuantNodes/core/quality_gate/redundancy.py +51 -0
  188. QuantNodes/core/quality_gate/settings.py +43 -0
  189. QuantNodes/core/quality_gate/zoo.py +98 -0
  190. QuantNodes/core/serializable.py +116 -0
  191. QuantNodes/core/serialization.py +673 -0
  192. QuantNodes/core/tools.py +333 -0
  193. QuantNodes/core/trajectory/__init__.py +25 -0
  194. QuantNodes/core/trajectory/entry.py +116 -0
  195. QuantNodes/core/trajectory/lineage.py +67 -0
  196. QuantNodes/core/trajectory/pool.py +211 -0
  197. QuantNodes/core/trajectory/selector.py +140 -0
  198. QuantNodes/core/visualization/__init__.py +33 -0
  199. QuantNodes/core/visualization/builder.py +233 -0
  200. QuantNodes/core/visualization/gate_breakdown.py +140 -0
  201. QuantNodes/core/visualization/lineage_dag.py +203 -0
  202. QuantNodes/core/visualization/metric_distribution.py +125 -0
  203. QuantNodes/core/visualization/report.py +68 -0
  204. QuantNodes/database_node/__init__.py +69 -0
  205. QuantNodes/database_node/base.py +135 -0
  206. QuantNodes/database_node/clickhouse_node.py +272 -0
  207. QuantNodes/database_node/csv_node.py +83 -0
  208. QuantNodes/database_node/duckdb_node.py +86 -0
  209. QuantNodes/database_node/factory.py +83 -0
  210. QuantNodes/database_node/mysql_node.py +100 -0
  211. QuantNodes/database_node/parquet_node.py +75 -0
  212. QuantNodes/database_node/sqlite_node.py +67 -0
  213. QuantNodes/factor_node/__init__.py +50 -0
  214. QuantNodes/factor_node/factor.py +563 -0
  215. QuantNodes/factor_node/factor_db.py +421 -0
  216. QuantNodes/factor_node/factor_functions/__init__.py +252 -0
  217. QuantNodes/factor_node/factor_functions/_helpers.py +358 -0
  218. QuantNodes/factor_node/factor_functions/_helpers_debug.py +317 -0
  219. QuantNodes/factor_node/factor_functions/composite_ops.py +136 -0
  220. QuantNodes/factor_node/factor_functions/math_ops.py +433 -0
  221. QuantNodes/factor_node/factor_functions/section_ops.py +290 -0
  222. QuantNodes/factor_node/factor_functions/talib_ops.py +1293 -0
  223. QuantNodes/factor_node/factor_functions/time_ops.py +535 -0
  224. QuantNodes/factor_node/factor_operation.py +1115 -0
  225. QuantNodes/factor_node/factor_table.py +1073 -0
  226. QuantNodes/factor_node/quant_nodes_object.py +60 -0
  227. QuantNodes/mcp_server/__init__.py +27 -0
  228. QuantNodes/mcp_server/__main__.py +4 -0
  229. QuantNodes/mcp_server/server.py +272 -0
  230. QuantNodes/methods/__init__.py +28 -0
  231. QuantNodes/methods/pipeline.py +100 -0
  232. QuantNodes/methods/sandbox.py +102 -0
  233. QuantNodes/monitor/__init__.py +27 -0
  234. QuantNodes/monitor/agent_tools/__init__.py +5 -0
  235. QuantNodes/monitor/agent_tools/monitor_tool.py +98 -0
  236. QuantNodes/monitor/agent_tools/schedule_tool.py +98 -0
  237. QuantNodes/monitor/agent_tools/version_tool.py +133 -0
  238. QuantNodes/monitor/monitor/__init__.py +6 -0
  239. QuantNodes/monitor/monitor/alerter.py +60 -0
  240. QuantNodes/monitor/monitor/collector.py +164 -0
  241. QuantNodes/monitor/monitor/dashboard.py +115 -0
  242. QuantNodes/monitor/monitor/drift.py +190 -0
  243. QuantNodes/monitor/scheduler/__init__.py +4 -0
  244. QuantNodes/monitor/scheduler/runner.py +133 -0
  245. QuantNodes/monitor/scheduler/scheduler.py +184 -0
  246. QuantNodes/monitor/storage/__init__.py +16 -0
  247. QuantNodes/monitor/storage/models.py +70 -0
  248. QuantNodes/monitor/storage/repository.py +407 -0
  249. QuantNodes/monitor/version/__init__.py +4 -0
  250. QuantNodes/monitor/version/diff.py +81 -0
  251. QuantNodes/monitor/version/version_manager.py +182 -0
  252. QuantNodes/operator_node/__init__.py +28 -0
  253. QuantNodes/operator_node/base.py +97 -0
  254. QuantNodes/operator_node/query_node.py +129 -0
  255. QuantNodes/operator_node/sql_builder.py +125 -0
  256. QuantNodes/operator_node/sql_utils.py +172 -0
  257. QuantNodes/operator_node/transform.py +130 -0
  258. QuantNodes/operators/__init__.py +90 -0
  259. QuantNodes/operators/_engine.py +108 -0
  260. QuantNodes/operators/composite.py +161 -0
  261. QuantNodes/operators/composite_dag.py +667 -0
  262. QuantNodes/operators/composite_dag_ops.py +343 -0
  263. QuantNodes/operators/composite_dag_pandas_ops.py +382 -0
  264. QuantNodes/operators/custom.py +408 -0
  265. QuantNodes/operators/facade.py +164 -0
  266. QuantNodes/operators/math.py +163 -0
  267. QuantNodes/operators/proxy.py +29 -0
  268. QuantNodes/operators/registry.py +144 -0
  269. QuantNodes/operators/section.py +99 -0
  270. QuantNodes/operators/talib.py +757 -0
  271. QuantNodes/operators/templates.py +95 -0
  272. QuantNodes/operators/time_series.py +136 -0
  273. QuantNodes/prompts/__init__.py +20 -0
  274. QuantNodes/prompts/backtest/__init__.py +12 -0
  275. QuantNodes/prompts/backtest/factor_based.py +86 -0
  276. QuantNodes/prompts/backtest/standard.py +73 -0
  277. QuantNodes/prompts/factor/__init__.py +14 -0
  278. QuantNodes/prompts/factor/correlation.py +77 -0
  279. QuantNodes/prompts/factor/group_backtest.py +86 -0
  280. QuantNodes/prompts/factor/ic_analysis.py +91 -0
  281. QuantNodes/prompts/strategy/__init__.py +18 -0
  282. QuantNodes/prompts/strategy/market_neutral.py +96 -0
  283. QuantNodes/prompts/strategy/mean_reversion.py +107 -0
  284. QuantNodes/prompts/strategy/momentum.py +160 -0
  285. QuantNodes/prompts/strategy/pairs_trading.py +107 -0
  286. QuantNodes/prompts/strategy/trend_following.py +96 -0
  287. QuantNodes/research/README.md +106 -0
  288. QuantNodes/research/__init__.py +154 -0
  289. QuantNodes/research/_legacy_3c/__init__.py +61 -0
  290. QuantNodes/research/_legacy_3c/auto_researcher.py +289 -0
  291. QuantNodes/research/_legacy_3c/factor_evaluator.py +560 -0
  292. QuantNodes/research/_legacy_3c/factor_miner.py +318 -0
  293. QuantNodes/research/_legacy_3c/mcts_search.py +324 -0
  294. QuantNodes/research/factor_test/__init__.py +25 -0
  295. QuantNodes/research/factor_test/config.py +184 -0
  296. QuantNodes/research/factor_test/config_builder.py +276 -0
  297. QuantNodes/research/factor_test/e2e/data_prep.py +163 -0
  298. QuantNodes/research/factor_test/e2e/run_evolution_e2e.py +309 -0
  299. QuantNodes/research/factor_test/evolution_adapter.py +231 -0
  300. QuantNodes/research/factor_test/feedback_wrapper.py +102 -0
  301. QuantNodes/research/factor_test/ifind_db/__init__.py +7 -0
  302. QuantNodes/research/factor_test/ifind_db/fetcher.py +224 -0
  303. QuantNodes/research/factor_test/ifind_db/ifind_database.py +689 -0
  304. QuantNodes/research/factor_test/nodes/__init__.py +1 -0
  305. QuantNodes/research/factor_test/nodes/_base.py +91 -0
  306. QuantNodes/research/factor_test/nodes/adjust_date_node.py +48 -0
  307. QuantNodes/research/factor_test/nodes/configs.py +240 -0
  308. QuantNodes/research/factor_test/nodes/factor_neutralize_node.py +87 -0
  309. QuantNodes/research/factor_test/nodes/factor_preprocess_node.py +222 -0
  310. QuantNodes/research/factor_test/nodes/factor_score_node.py +141 -0
  311. QuantNodes/research/factor_test/nodes/factor_test_report_node.py +153 -0
  312. QuantNodes/research/factor_test/nodes/group_analyzer_node.py +317 -0
  313. QuantNodes/research/factor_test/nodes/ic_analyzer_node.py +112 -0
  314. QuantNodes/research/factor_test/nodes/load_data_node.py +100 -0
  315. QuantNodes/research/factor_test/nodes/long_short_node.py +93 -0
  316. QuantNodes/research/factor_test/nodes/neutralizers.py +222 -0
  317. QuantNodes/research/factor_test/nodes/preprocess_strategies.py +277 -0
  318. QuantNodes/research/factor_test/nodes/risk_correlation_node.py +112 -0
  319. QuantNodes/research/factor_test/nodes/sample_pool_filter_node.py +110 -0
  320. QuantNodes/research/factor_test/nodes/tradability_filter_node.py +92 -0
  321. QuantNodes/research/factor_test/pipeline_runner.py +305 -0
  322. QuantNodes/research/factor_test/pipeline_spec.py +216 -0
  323. QuantNodes/research/factor_test/utils/__init__.py +26 -0
  324. QuantNodes/research/factor_test/utils/constants.py +86 -0
  325. QuantNodes/research/factor_test/utils/data_loader.py +141 -0
  326. QuantNodes/research/factor_test/utils/date_utils.py +232 -0
  327. QuantNodes/research/factor_test/utils/file_loaders.py +150 -0
  328. QuantNodes/research/factor_test/utils/labels.py +37 -0
  329. QuantNodes/research/factor_test/utils/metrics_extractor.py +55 -0
  330. QuantNodes/research/factor_test/utils/performance_metrics.py +175 -0
  331. QuantNodes/research/factor_test/utils/safe_load.py +106 -0
  332. QuantNodes/research/quant_alpha/CHANGELOG.md +80 -0
  333. QuantNodes/research/quant_alpha/README.md +142 -0
  334. QuantNodes/research/quant_alpha/__init__.py +45 -0
  335. QuantNodes/research/quant_alpha/adapters/__init__.py +99 -0
  336. QuantNodes/research/quant_alpha/adapters/calculator.py +503 -0
  337. QuantNodes/research/quant_alpha/adapters/expression.py +387 -0
  338. QuantNodes/research/quant_alpha/alpha101_design/__init__.py +50 -0
  339. QuantNodes/research/quant_alpha/alpha101_design/few_shot_examples.py +243 -0
  340. QuantNodes/research/quant_alpha/alpha101_design/philosophy.py +474 -0
  341. QuantNodes/research/quant_alpha/alpha158_design/__init__.py +63 -0
  342. QuantNodes/research/quant_alpha/alpha158_design/few_shot_examples.py +219 -0
  343. QuantNodes/research/quant_alpha/alpha158_design/philosophy.py +240 -0
  344. QuantNodes/research/quant_alpha/evaluation/__init__.py +47 -0
  345. QuantNodes/research/quant_alpha/evaluation/baselines/__init__.py +8 -0
  346. QuantNodes/research/quant_alpha/evaluation/baselines/g1_handcrafted.py +135 -0
  347. QuantNodes/research/quant_alpha/evaluation/baselines/g2_llm_only.py +269 -0
  348. QuantNodes/research/quant_alpha/evaluation/baselines/g3_alpha_gpt.py +152 -0
  349. QuantNodes/research/quant_alpha/evaluation/clickhouse_data_loader.py +227 -0
  350. QuantNodes/research/quant_alpha/evaluation/contracts.py +376 -0
  351. QuantNodes/research/quant_alpha/evaluation/evaluators/__init__.py +6 -0
  352. QuantNodes/research/quant_alpha/evaluation/evaluators/polars_evaluator.py +545 -0
  353. QuantNodes/research/quant_alpha/evaluation/mock_data_loader.py +226 -0
  354. QuantNodes/research/quant_alpha/evaluation/runner.py +243 -0
  355. QuantNodes/research/quant_alpha/llm/__init__.py +38 -0
  356. QuantNodes/research/quant_alpha/llm/parser.py +681 -0
  357. QuantNodes/research/quant_alpha/logic_driven_pipeline.py +411 -0
  358. QuantNodes/research/quant_alpha/logic_mining/__init__.py +74 -0
  359. QuantNodes/research/quant_alpha/logic_mining/compiler.py +457 -0
  360. QuantNodes/research/quant_alpha/logic_mining/generator.py +366 -0
  361. QuantNodes/research/quant_alpha/logic_mining/models.py +252 -0
  362. QuantNodes/research/quant_alpha/logic_mining/parser.py +287 -0
  363. QuantNodes/research/quant_alpha/logic_mining/pipelines.py +297 -0
  364. QuantNodes/research/quant_alpha/logic_mining/sources.py +149 -0
  365. QuantNodes/research/quant_alpha/mcts/__init__.py +66 -0
  366. QuantNodes/research/quant_alpha/mcts/cache.py +262 -0
  367. QuantNodes/research/quant_alpha/mcts/extension_ops.py +320 -0
  368. QuantNodes/research/quant_alpha/mcts/feedback.py +825 -0
  369. QuantNodes/research/quant_alpha/mcts/op_prior.py +180 -0
  370. QuantNodes/research/quant_alpha/mcts/search.py +540 -0
  371. QuantNodes/research/quant_alpha/mcts/tree.py +201 -0
  372. QuantNodes/research/quant_alpha/operator_vocab/__init__.py +50 -0
  373. QuantNodes/research/quant_alpha/operator_vocab/config.py +54 -0
  374. QuantNodes/research/quant_alpha/operator_vocab/metadata.py +263 -0
  375. QuantNodes/research/quant_alpha/operator_vocab/vocabulary.py +481 -0
  376. QuantNodes/research/quant_alpha/pipeline.py +1027 -0
  377. QuantNodes/research/quant_alpha/types/__init__.py +27 -0
  378. QuantNodes/research/quant_alpha/types/constants.py +28 -0
  379. QuantNodes/research/quant_alpha/types/state.py +205 -0
  380. QuantNodes/research/quant_alpha/workflow/__init__.py +32 -0
  381. QuantNodes/research/quant_alpha/workflow/alpha_gpt.py +911 -0
  382. QuantNodes/research/quant_alpha/workflow/alpha_logics.py +416 -0
  383. QuantNodes/research/quant_alpha/workflow/state.py +27 -0
  384. QuantNodes/research/report_reproducer.py +485 -0
  385. QuantNodes/research/wiki.py +1155 -0
  386. QuantNodes/symbolic/__init__.py +51 -0
  387. QuantNodes/symbolic/compiler.py +113 -0
  388. QuantNodes/symbolic/dialect.py +260 -0
  389. QuantNodes/symbolic/executor.py +147 -0
  390. QuantNodes/symbolic/expression.py +234 -0
  391. QuantNodes/symbolic/functions.py +433 -0
  392. QuantNodes/symbolic/optimizer.py +165 -0
  393. QuantNodes/ui_node/__init__.py +30 -0
  394. QuantNodes/ui_node/base.py +222 -0
  395. quantnodes-3.0.0.dist-info/METADATA +463 -0
  396. quantnodes-3.0.0.dist-info/RECORD +399 -0
  397. quantnodes-3.0.0.dist-info/WHEEL +5 -0
  398. quantnodes-3.0.0.dist-info/entry_points.txt +24 -0
  399. quantnodes-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,326 @@
1
+ # coding=utf-8
2
+ """
3
+ 速率限制模块 (Rate Limiter)
4
+
5
+ 提供 Token Bucket 算法实现,用于控制 LLM API 请求频率。
6
+ 解决 OpenRouter 免费账号的严格速率限制问题(每天 50 次请求)。
7
+ """
8
+
9
+ import time
10
+ import asyncio
11
+ import threading
12
+
13
+
14
+ class TokenBucket:
15
+ """同步令牌桶速率限制器
16
+
17
+ 用于多线程环境下的请求频率控制。
18
+
19
+ Args:
20
+ requests_per_second: 每秒允许的请求数(免费账号建议 0.5)
21
+ burst: 突发容量,允许的最大突发请求数
22
+ """
23
+
24
+ def __init__(self, requests_per_second: float = 0.5, burst: int = 1):
25
+ """
26
+ Args:
27
+ requests_per_second: 每秒允许的请求数,默认 0.5 即每2秒1次请求
28
+ burst: 突发容量,默认 1 表示每次最多处理1个请求
29
+ """
30
+ if requests_per_second <= 0:
31
+ raise ValueError("requests_per_second must be positive")
32
+ if burst < 1:
33
+ raise ValueError("burst must be at least 1")
34
+
35
+ self.rate = requests_per_second
36
+ self.burst = burst
37
+ self.tokens = float(burst)
38
+ self.last_update = time.time()
39
+ self.lock = threading.Lock()
40
+
41
+ def _refill(self) -> None:
42
+ """补充令牌"""
43
+ now = time.time()
44
+ elapsed = now - self.last_update
45
+ self.tokens = min(self.burst, self.tokens + elapsed * self.rate)
46
+ self.last_update = now
47
+
48
+ def acquire(self, blocking: bool = True) -> bool:
49
+ """获取令牌
50
+
51
+ Args:
52
+ blocking: 是否阻塞等待令牌可用
53
+
54
+ Returns:
55
+ True if token acquired, False if not (non-blocking mode only)
56
+ """
57
+ with self.lock:
58
+ self._refill()
59
+
60
+ if self.tokens >= 1:
61
+ self.tokens -= 1
62
+ return True
63
+
64
+ if not blocking:
65
+ return False
66
+
67
+ wait_time = (1 - self.tokens) / self.rate
68
+ time.sleep(wait_time)
69
+ self.tokens = 0
70
+ return True
71
+
72
+ def try_acquire(self) -> bool:
73
+ """非阻塞尝试获取令牌"""
74
+ return self.acquire(blocking=False)
75
+
76
+ @property
77
+ def available_tokens(self) -> float:
78
+ """当前可用令牌数"""
79
+ with self.lock:
80
+ self._refill()
81
+ return self.tokens
82
+
83
+
84
+ class AsyncTokenBucket:
85
+ """异步令牌桶速率限制器
86
+
87
+ 用于 asyncio 环境下的请求频率控制。
88
+
89
+ Args:
90
+ requests_per_second: 每秒允许的请求数(免费账号建议 0.5)
91
+ burst: 突发容量
92
+ """
93
+
94
+ def __init__(self, requests_per_second: float = 0.5, burst: int = 1):
95
+ """
96
+ Args:
97
+ requests_per_second: 每秒允许的请求数,默认 0.5 即每2秒1次请求
98
+ burst: 突发容量,默认 1
99
+ """
100
+ if requests_per_second <= 0:
101
+ raise ValueError("requests_per_second must be positive")
102
+ if burst < 1:
103
+ raise ValueError("burst must be at least 1")
104
+
105
+ self.rate = requests_per_second
106
+ self.burst = burst
107
+ self.tokens = float(burst)
108
+ self.last_update = time.time()
109
+ self.lock = asyncio.Lock()
110
+
111
+ async def _refill(self) -> None:
112
+ """补充令牌"""
113
+ now = time.time()
114
+ elapsed = now - self.last_update
115
+ self.tokens = min(self.burst, self.tokens + elapsed * self.rate)
116
+ self.last_update = now
117
+
118
+ async def acquire(self) -> None:
119
+ """获取令牌,必要时等待
120
+
121
+ 这是阻塞方法,会等待直到令牌可用。
122
+ """
123
+ async with self.lock:
124
+ await self._refill()
125
+
126
+ if self.tokens >= 1:
127
+ self.tokens -= 1
128
+ return
129
+
130
+ wait_time = (1 - self.tokens) / self.rate
131
+ await asyncio.sleep(wait_time)
132
+ self.tokens = 0
133
+
134
+ async def try_acquire(self) -> bool:
135
+ """非阻塞尝试获取令牌
136
+
137
+ Returns:
138
+ True if token acquired, False otherwise
139
+ """
140
+ async with self.lock:
141
+ await self._refill()
142
+
143
+ if self.tokens >= 1:
144
+ self.tokens -= 1
145
+ return True
146
+
147
+ return False
148
+
149
+ async def wait_time(self) -> float:
150
+ """计算获取令牌需要等待的时间
151
+
152
+ Returns:
153
+ 等待时间(秒),如果立即可用则返回 0
154
+ """
155
+ async with self.lock:
156
+ await self._refill()
157
+
158
+ if self.tokens >= 1:
159
+ return 0.0
160
+
161
+ return (1 - self.tokens) / self.rate
162
+
163
+ @property
164
+ def available_tokens(self) -> float:
165
+ """当前可用令牌数(非线程安全,仅供调试)"""
166
+ return self.tokens
167
+
168
+
169
+ class SlidingWindowRateLimiter:
170
+ """滑动窗口速率限制器
171
+
172
+ 另一种速率限制实现,在固定时间窗口内限制请求数。
173
+
174
+ Args:
175
+ max_requests: 时间窗口内最大请求数
176
+ window_seconds: 时间窗口长度(秒)
177
+ """
178
+
179
+ def __init__(self, max_requests: int = 10, window_seconds: float = 60.0):
180
+ if max_requests <= 0:
181
+ raise ValueError("max_requests must be positive")
182
+ if window_seconds <= 0:
183
+ raise ValueError("window_seconds must be positive")
184
+
185
+ self.max_requests = max_requests
186
+ self.window_seconds = window_seconds
187
+ self.requests: list[float] = []
188
+ self.lock = threading.Lock()
189
+
190
+ def _clean_old_requests(self) -> None:
191
+ """清除过期请求记录"""
192
+ now = time.time()
193
+ cutoff = now - self.window_seconds
194
+ self.requests = [t for t in self.requests if t > cutoff]
195
+
196
+ def acquire(self, blocking: bool = True) -> bool:
197
+ """获取许可"""
198
+ with self.lock:
199
+ self._clean_old_requests()
200
+
201
+ if len(self.requests) < self.max_requests:
202
+ self.requests.append(time.time())
203
+ return True
204
+
205
+ if not blocking:
206
+ return False
207
+
208
+ oldest = self.requests[0]
209
+ wait_time = oldest + self.window_seconds - time.time()
210
+ if wait_time > 0:
211
+ time.sleep(wait_time)
212
+
213
+ self._clean_old_requests()
214
+ self.requests.append(time.time())
215
+ return True
216
+
217
+ def try_acquire(self) -> bool:
218
+ """非阻塞尝试获取许可"""
219
+ return self.acquire(blocking=False)
220
+
221
+
222
+ class AsyncSlidingWindowRateLimiter:
223
+ """异步滑动窗口速率限制器"""
224
+
225
+ def __init__(self, max_requests: int = 10, window_seconds: float = 60.0):
226
+ self.max_requests = max_requests
227
+ self.window_seconds = window_seconds
228
+ self.requests: list[float] = []
229
+ self.lock = asyncio.Lock()
230
+
231
+ async def _clean_old_requests(self) -> None:
232
+ """清除过期请求记录"""
233
+ now = time.time()
234
+ cutoff = now - self.window_seconds
235
+ self.requests = [t for t in self.requests if t > cutoff]
236
+
237
+ async def acquire(self) -> None:
238
+ """获取许可"""
239
+ async with self.lock:
240
+ await self._clean_old_requests()
241
+
242
+ if len(self.requests) < self.max_requests:
243
+ self.requests.append(time.time())
244
+ return
245
+
246
+ oldest = self.requests[0]
247
+ wait_time = oldest + self.window_seconds - time.time()
248
+ if wait_time > 0:
249
+ await asyncio.sleep(wait_time)
250
+
251
+ await self._clean_old_requests()
252
+ self.requests.append(time.time())
253
+
254
+ async def try_acquire(self) -> bool:
255
+ """非阻塞尝试获取许可"""
256
+ async with self.lock:
257
+ await self._clean_old_requests()
258
+
259
+ if len(self.requests) < self.max_requests:
260
+ self.requests.append(time.time())
261
+ return True
262
+
263
+ return False
264
+
265
+
266
+ class AdaptiveRateLimiter:
267
+ """自适应速率限制器
268
+
269
+ 根据 API 响应自动调整请求速率。
270
+ 当检测到限流错误时自动降低速率,正常时逐步提升。
271
+
272
+ Args:
273
+ initial_rps: 初始速率(每秒请求数)
274
+ min_rps: 最小速率
275
+ max_rps: 最大速率
276
+ increase_factor: 正常时速率增加因子
277
+ decrease_factor: 触发限流时速率降低因子
278
+ """
279
+
280
+ def __init__(
281
+ self,
282
+ initial_rps: float = 0.5,
283
+ min_rps: float = 0.1,
284
+ max_rps: float = 2.0,
285
+ increase_factor: float = 1.1,
286
+ decrease_factor: float = 0.5,
287
+ ):
288
+ self.current_rps = initial_rps
289
+ self.min_rps = min_rps
290
+ self.max_rps = max_rps
291
+ self.increase_factor = increase_factor
292
+ self.decrease_factor = decrease_factor
293
+ self.last_adjust_time = time.time()
294
+ self.lock = threading.Lock()
295
+
296
+ self._bucket = TokenBucket(initial_rps, burst=1)
297
+
298
+ def report_success(self) -> None:
299
+ """报告成功调用,适当提高速率"""
300
+ with self.lock:
301
+ now = time.time()
302
+ if now - self.last_adjust_time >= 1.0:
303
+ self.current_rps = min(self.max_rps, self.current_rps * self.increase_factor)
304
+ self._bucket = TokenBucket(self.current_rps, burst=1)
305
+ self.last_adjust_time = now
306
+
307
+ def report_rate_limit(self) -> None:
308
+ """报告限流错误,大幅降低速率"""
309
+ with self.lock:
310
+ self.current_rps = max(self.min_rps, self.current_rps * self.decrease_factor)
311
+ self._bucket = TokenBucket(self.current_rps, burst=1)
312
+
313
+ def report_server_error(self) -> None:
314
+ """报告服务器错误,中等降低速率"""
315
+ with self.lock:
316
+ self.current_rps = max(self.min_rps, self.current_rps * 0.7)
317
+ self._bucket = TokenBucket(self.current_rps, burst=1)
318
+
319
+ def acquire(self, blocking: bool = True) -> bool:
320
+ """获取令牌"""
321
+ return self._bucket.acquire(blocking)
322
+
323
+ @property
324
+ def current_rate(self) -> float:
325
+ """当前速率"""
326
+ return self.current_rps
@@ -0,0 +1,163 @@
1
+ # coding=utf-8
2
+ """
3
+ Provider 注册表
4
+
5
+ 管理多 LLM Provider 配置,按 model 名路由到正确的 provider。
6
+ 支持优先级排序和 fallback 机制。
7
+ """
8
+
9
+ import logging
10
+ from dataclasses import dataclass, field
11
+ from typing import Dict, List, Optional
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ @dataclass
17
+ class ProviderConfig:
18
+ """单个 Provider 配置"""
19
+ name: str
20
+ api_key: str
21
+ api_base: str
22
+ models: List[str] = field(default_factory=list)
23
+ extra_headers: Dict[str, str] = field(default_factory=dict)
24
+ priority: int = 1
25
+ timeout: int = 60
26
+ max_retries: int = 3
27
+
28
+
29
+ class ProviderRegistry:
30
+ """Provider 注册表 — 管理多 Provider 配置,按 model 路由"""
31
+
32
+ def __init__(self):
33
+ self._providers: Dict[str, ProviderConfig] = {}
34
+ self._default_provider: Optional[str] = None
35
+
36
+ @classmethod
37
+ def from_settings(cls, agent_config: dict) -> "ProviderRegistry":
38
+ """从 settings.json 的 agent 节点加载
39
+
40
+ 支持两种模式:
41
+ 1. 新模式:agent.providers 字典配置多 provider
42
+ 2. 旧模式:agent.api_key + agent.api_base 单 provider(向后兼容)
43
+ """
44
+ registry = cls()
45
+ providers_data = agent_config.get("providers", {})
46
+
47
+ for name, pconfig in providers_data.items():
48
+ registry.register(ProviderConfig(
49
+ name=name,
50
+ api_key=pconfig.get("api_key", ""),
51
+ api_base=pconfig.get("api_base", ""),
52
+ models=pconfig.get("models", []),
53
+ extra_headers=pconfig.get("extra_headers", {}),
54
+ priority=pconfig.get("priority", 1),
55
+ timeout=pconfig.get("timeout", 60),
56
+ max_retries=pconfig.get("max_retries", 3),
57
+ ))
58
+
59
+ registry._default_provider = agent_config.get("provider")
60
+
61
+ # 向后兼容:无 providers 配置时,用顶层字段创建单 provider
62
+ if not providers_data and agent_config.get("api_key"):
63
+ default_name = registry._default_provider or "default"
64
+ model = agent_config.get("model", "")
65
+ registry.register(ProviderConfig(
66
+ name=default_name,
67
+ api_key=agent_config.get("api_key", ""),
68
+ api_base=agent_config.get("api_base", ""),
69
+ models=[model] if model else [],
70
+ priority=1,
71
+ timeout=agent_config.get("llm_timeout", 60),
72
+ max_retries=agent_config.get("llm_max_retries", 3),
73
+ ))
74
+ registry._default_provider = default_name
75
+
76
+ return registry
77
+
78
+ def register(self, config: ProviderConfig) -> None:
79
+ """注册一个 Provider"""
80
+ self._providers[config.name] = config
81
+
82
+ def get(self, name: str) -> Optional[ProviderConfig]:
83
+ """获取指定名称的 Provider"""
84
+ return self._providers.get(name)
85
+
86
+ def resolve(self, model: Optional[str] = None) -> Optional[ProviderConfig]:
87
+ """根据 model 名找到最优 provider
88
+
89
+ 路由逻辑:
90
+ 1. model=None → 返回默认 provider
91
+ 2. 默认 provider 的 models 中匹配 → 优先返回
92
+ 3. 所有 provider 中匹配 → 按 priority 排序(数字小优先)
93
+ 4. 都找不到 → 返回默认 provider 兜底
94
+ """
95
+ if not self._providers:
96
+ return None
97
+
98
+ # 1. model=None → 默认 provider
99
+ if model is None:
100
+ return self._get_default_or_first()
101
+
102
+ # 2. 默认 provider 优先
103
+ default = self._providers.get(self._default_provider)
104
+ if default and model in default.models:
105
+ return default
106
+
107
+ # 3. 所有 provider 中按 priority 排序
108
+ candidates = [
109
+ p for p in self._providers.values()
110
+ if model in p.models
111
+ ]
112
+ if candidates:
113
+ candidates.sort(key=lambda p: p.priority)
114
+ return candidates[0]
115
+
116
+ # 4. 兜底:返回默认 provider
117
+ return self._get_default_or_first()
118
+
119
+ def _get_default_or_first(self) -> Optional[ProviderConfig]:
120
+ """获取默认 provider,无默认则返回第一个"""
121
+ default = self._providers.get(self._default_provider)
122
+ if default:
123
+ return default
124
+ if self._providers:
125
+ return next(iter(self._providers.values()))
126
+ return None
127
+
128
+ def list_providers(self) -> List[ProviderConfig]:
129
+ """列出所有已注册的 Provider"""
130
+ return list(self._providers.values())
131
+
132
+ def get_models_map(self) -> Dict[str, List[str]]:
133
+ """获取 provider → models 映射"""
134
+ return {
135
+ name: config.models
136
+ for name, config in self._providers.items()
137
+ }
138
+
139
+ def get_client(self, config: ProviderConfig):
140
+ """为指定 provider 创建 OpenAIClient"""
141
+ from QuantNodes.ai.llm.openai import OpenAIClient
142
+ return OpenAIClient(
143
+ api_key=config.api_key,
144
+ base_url=config.api_base,
145
+ timeout=config.timeout,
146
+ max_retries=config.max_retries,
147
+ extra_headers=config.extra_headers,
148
+ )
149
+
150
+ def get_default_client(self):
151
+ """获取默认 provider 的 client"""
152
+ config = self._get_default_or_first()
153
+ if config:
154
+ return self.get_client(config)
155
+ return None
156
+
157
+ @property
158
+ def default_provider_name(self) -> Optional[str]:
159
+ return self._default_provider
160
+
161
+ def __repr__(self) -> str:
162
+ providers_str = ", ".join(self._providers.keys())
163
+ return f"ProviderRegistry(default={self._default_provider}, providers=[{providers_str}])"
@@ -0,0 +1,20 @@
1
+ # coding=utf-8
2
+ """
3
+ Skill System - Phase 4.1
4
+
5
+ Skills: Strategy skills, Factor skills, Dream system
6
+ """
7
+
8
+ from .base import Skill, SkillCategory, SkillStatus, SkillMetadata, SkillResult
9
+ from .registry import SkillRegistry
10
+ from .loader import SkillLoader
11
+
12
+ __all__ = [
13
+ "Skill",
14
+ "SkillCategory",
15
+ "SkillStatus",
16
+ "SkillMetadata",
17
+ "SkillResult",
18
+ "SkillRegistry",
19
+ "SkillLoader",
20
+ ]
@@ -0,0 +1,118 @@
1
+ # coding=utf-8
2
+ """
3
+ Skill System Base Classes
4
+
5
+ Phase 4.1: Skill Infrastructure
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from dataclasses import dataclass, field
10
+ from typing import Any, Dict, List, Optional
11
+ from datetime import datetime
12
+ from enum import Enum
13
+
14
+
15
+ class SkillCategory(Enum):
16
+ STRATEGY = "strategy"
17
+ FACTOR = "factor"
18
+ ANALYSIS = "analysis"
19
+ DREAM = "dream"
20
+
21
+
22
+ class SkillStatus(Enum):
23
+ ACTIVE = "active"
24
+ DEPRECATED = "deprecated"
25
+ EXPERIMENTAL = "experimental"
26
+
27
+
28
+ @dataclass
29
+ class SkillMetadata:
30
+ name: str
31
+ description: str
32
+ category: SkillCategory
33
+ version: str = "1.0"
34
+ author: str = ""
35
+ tags: List[str] = field(default_factory=list)
36
+ examples: List[str] = field(default_factory=list)
37
+ dependencies: List[str] = field(default_factory=list)
38
+ status: SkillStatus = SkillStatus.ACTIVE
39
+ created_at: str = ""
40
+ updated_at: str = ""
41
+
42
+ def __post_init__(self):
43
+ if not self.created_at:
44
+ self.created_at = datetime.now().isoformat()
45
+ if not self.updated_at:
46
+ self.updated_at = self.created_at
47
+
48
+
49
+ @dataclass
50
+ class SkillResult:
51
+ success: bool
52
+ data: Any = None
53
+ error: str = ""
54
+ metadata: Dict[str, Any] = field(default_factory=dict)
55
+ execution_time_ms: float = 0.0
56
+
57
+ def to_dict(self) -> Dict:
58
+ return {
59
+ "success": self.success,
60
+ "data": self.data,
61
+ "error": self.error,
62
+ "metadata": self.metadata,
63
+ "execution_time_ms": self.execution_time_ms,
64
+ }
65
+
66
+
67
+ class Skill(ABC):
68
+ """Skill Abstract Base Class"""
69
+
70
+ def __init__(self):
71
+ self._metadata: Optional[SkillMetadata] = None
72
+
73
+ @property
74
+ @abstractmethod
75
+ def metadata(self) -> SkillMetadata:
76
+ """Return skill metadata"""
77
+ pass
78
+
79
+ @property
80
+ def name(self) -> str:
81
+ return self.metadata.name
82
+
83
+ @property
84
+ def description(self) -> str:
85
+ return self.metadata.description
86
+
87
+ @property
88
+ def category(self) -> SkillCategory:
89
+ return self.metadata.category
90
+
91
+ @abstractmethod
92
+ async def execute(self, context: Dict[str, Any]) -> SkillResult:
93
+ """Execute the skill"""
94
+ pass
95
+
96
+ def validate_context(
97
+ self, context: Dict[str, Any], required_keys: List[str]
98
+ ) -> bool:
99
+ """Validate if context contains required keys"""
100
+ return all(k in context for k in required_keys)
101
+
102
+ def get_example_prompts(self) -> List[str]:
103
+ """Return example prompts"""
104
+ return self.metadata.examples
105
+
106
+ def to_tool_schema(self) -> Dict[str, Any]:
107
+ """Convert to nanobot Tool Schema"""
108
+ return {
109
+ "name": self.name,
110
+ "description": self.description,
111
+ "parameters": self.get_parameters_schema(),
112
+ "category": self.category.value,
113
+ }
114
+
115
+ @abstractmethod
116
+ def get_parameters_schema(self) -> Dict[str, Any]:
117
+ """Return parameter Schema"""
118
+ pass
@@ -0,0 +1,73 @@
1
+ # coding=utf-8
2
+ """
3
+ Skill → Tool Bridge
4
+
5
+ 将 Skill 自动转换为 Agent Tool 并注册到 ToolRegistry。
6
+ """
7
+
8
+ import logging
9
+ from typing import Any, Dict
10
+
11
+ from ..skills.base import Skill, SkillResult
12
+ from ..skills.registry import SkillRegistry
13
+ from ..tools.base import Tool
14
+ from ..tools.registry import ToolRegistry
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class SkillToolAdapter(Tool):
20
+ """将 Skill 适配为 Tool 接口"""
21
+
22
+ def __init__(self, skill: Skill):
23
+ self._skill = skill
24
+
25
+ @property
26
+ def name(self) -> str:
27
+ return f"skill_{self._skill.metadata.name}"
28
+
29
+ @property
30
+ def description(self) -> str:
31
+ return self._skill.metadata.description
32
+
33
+ @property
34
+ def parameters(self) -> Dict[str, Any]:
35
+ return self._skill.get_parameters_schema()
36
+
37
+ @property
38
+ def read_only(self) -> bool:
39
+ return True
40
+
41
+ async def execute(self, **kwargs: Any) -> Any:
42
+ try:
43
+ result: SkillResult = await self._skill.execute(kwargs)
44
+ return result.to_dict()
45
+ except Exception as e:
46
+ logger.error("Skill %s execution failed: %s", self._skill.name, e)
47
+ return {"success": False, "error": str(e), "data": None}
48
+
49
+
50
+ class SkillToolBridge:
51
+ """将 SkillRegistry 中的 Skill 注册为 Agent Tool"""
52
+
53
+ def __init__(self, skill_registry: SkillRegistry, tool_registry: ToolRegistry):
54
+ self.skill_registry = skill_registry
55
+ self.tool_registry = tool_registry
56
+
57
+ def register_all(self) -> int:
58
+ """将所有 Skill 注册为 Tool,返回注册数量"""
59
+ count = 0
60
+ for skill in self.skill_registry.list_all():
61
+ tool = SkillToolAdapter(skill)
62
+ self.tool_registry.register(tool)
63
+ count += 1
64
+ return count
65
+
66
+ def unregister_all(self) -> int:
67
+ """移除所有 SkillToolAdapter"""
68
+ count = 0
69
+ for tool in list(self.tool_registry.list_tools()):
70
+ if isinstance(tool, SkillToolAdapter):
71
+ self.tool_registry.unregister(tool.name)
72
+ count += 1
73
+ return count