cnhkmcp 2.3.1__py3-none-any.whl → 2.3.3__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 (105) hide show
  1. cnhkmcp/__init__.py +1 -1
  2. cnhkmcp/untracked/AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221/BRAIN_AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221Mac_Linux/321/207/320/231/320/230/321/206/320/254/320/274.zip +0 -0
  3. cnhkmcp/untracked/AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221//321/205/320/237/320/234/321/205/320/227/342/225/227/321/205/320/276/320/231/321/210/320/263/320/225AI/321/206/320/231/320/243/321/205/342/225/226/320/265/321/204/342/225/221/342/225/221_Windows/321/207/320/231/320/230/321/206/320/254/320/274.exe +0 -0
  4. cnhkmcp/untracked/APP/Tranformer/parsetab.py +60 -0
  5. cnhkmcp/untracked/APP/Tranformer/validator.py +78 -4
  6. cnhkmcp/untracked/APP/static/inspiration.js +41 -3
  7. cnhkmcp/untracked/APP/templates/index.html +26 -0
  8. cnhkmcp/untracked/APP/trailSomeAlphas/ace.log +1 -0
  9. cnhkmcp/untracked/APP/trailSomeAlphas/enhance_template.py +132 -6
  10. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-data-feature-engineering/SKILL.md +17 -0
  11. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-data-feature-engineering/output_report/GLB_delay1_fundamental28_ideas.md +384 -0
  12. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-data-feature-engineering/output_report/GLB_delay1_fundamental72_ideas.md +292 -239
  13. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/final_expressions.json +41 -0
  14. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874844124598400.json +7 -0
  15. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874844589448700.json +8 -0
  16. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874845048996700.json +8 -0
  17. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874845510819100.json +12 -0
  18. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874845978315000.json +10 -0
  19. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874846459411100.json +10 -0
  20. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874846924915700.json +8 -0
  21. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874847399137200.json +8 -0
  22. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874847858960800.json +10 -0
  23. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874848327921300.json +8 -0
  24. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874848810818000.json +8 -0
  25. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874849327754300.json +7 -0
  26. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874849795807500.json +8 -0
  27. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874850272279500.json +8 -0
  28. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874850757124200.json +7 -0
  29. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_1_idea_1769874851224506800.json +8 -0
  30. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental28_GLB_delay1/fundamental28_GLB_delay1.csv +930 -0
  31. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/final_expressions.json +74 -136
  32. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852468022627100.json +22 -0
  33. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852468554457600.json +14 -0
  34. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852469133324600.json +8 -0
  35. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852469704433900.json +10 -0
  36. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852470248911900.json +10 -0
  37. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852470805192900.json +8 -0
  38. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852471380158000.json +10 -0
  39. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852471944247400.json +22 -0
  40. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852472483548800.json +14 -0
  41. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852473053891800.json +22 -0
  42. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852473617716000.json +22 -0
  43. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852474172815700.json +14 -0
  44. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852474735778500.json +10 -0
  45. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852475315478500.json +14 -0
  46. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852475912897000.json +8 -0
  47. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852476474911100.json +10 -0
  48. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852978914367200.json +10 -0
  49. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852979426164800.json +10 -0
  50. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852979945511100.json +10 -0
  51. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852980480251500.json +10 -0
  52. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769852981007315500.json +10 -0
  53. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769854621979784200.json +10 -0
  54. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769854622483457900.json +10 -0
  55. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769854623010559800.json +10 -0
  56. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769854623572902300.json +5 -0
  57. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769854624091016000.json +10 -0
  58. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_delay1.csv.bak_1769852868 +330 -0
  59. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_delay1.csv.bak_1769854511 +330 -0
  60. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/ace.log +13 -0
  61. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/scripts/validator.py +80 -4
  62. cnhkmcp/untracked/APP/trailSomeAlphas/skills/template_final_enhance/op/321/206/320/220/342/225/227/321/207/342/225/227/320/243.md +24 -18
  63. cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +14 -0
  64. cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/parsetab.py +60 -0
  65. cnhkmcp/untracked/skills/alpha-expression-verifier/scripts/validator.py +78 -4
  66. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/.gitignore +14 -0
  67. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/SKILL.md +76 -0
  68. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/ace.log +0 -0
  69. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/ace_lib.py +1512 -0
  70. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/config.json +6 -0
  71. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/fundamental28_GLB_1_idea_1769874845978315000.json +10 -0
  72. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/helpful_functions.py +180 -0
  73. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/__init__.py +0 -0
  74. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/build_alpha_list.py +86 -0
  75. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/fetch_sim_options.py +51 -0
  76. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/load_credentials.py +93 -0
  77. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/parse_idea_file.py +85 -0
  78. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/process_template.py +80 -0
  79. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/scripts/resolve_settings.py +94 -0
  80. cnhkmcp/untracked/skills/brain-inspectTemplate-create-Setting/sim_options_snapshot.json +414 -0
  81. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/METADATA +1 -1
  82. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/RECORD +86 -41
  83. cnhkmcp/untracked/APP/simulator/wqb20260130130030.log +0 -210
  84. cnhkmcp/untracked/APP/simulator/wqb20260130131757.log +0 -104
  85. cnhkmcp/untracked/APP/simulator/wqb20260130172245.log +0 -70
  86. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759441444909600.json +0 -38
  87. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759441920092000.json +0 -14
  88. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759442418767100.json +0 -14
  89. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759442902507600.json +0 -14
  90. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759443377036200.json +0 -10
  91. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759443845377000.json +0 -14
  92. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759444313546700.json +0 -10
  93. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759444784598600.json +0 -14
  94. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759445274311200.json +0 -14
  95. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759445747421700.json +0 -10
  96. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759446222137800.json +0 -22
  97. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759446686222600.json +0 -14
  98. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759447154698500.json +0 -10
  99. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759447629677000.json +0 -10
  100. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759448102331200.json +0 -10
  101. cnhkmcp/untracked/APP/trailSomeAlphas/skills/brain-feature-implementation/data/fundamental72_GLB_delay1/fundamental72_GLB_1_idea_1769759448573382000.json +0 -14
  102. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/WHEEL +0 -0
  103. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/entry_points.txt +0 -0
  104. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/licenses/LICENSE +0 -0
  105. {cnhkmcp-2.3.1.dist-info → cnhkmcp-2.3.3.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,16 @@
1
1
  2026-01-30 01:46:34,276 - ace - ERROR -
2
2
  Incorrect email or password
3
3
 
4
+ 2026-01-31 17:23:24,903 - ace - ERROR -
5
+ Incorrect email or password
6
+
7
+ 2026-01-31 17:23:25,385 - ace - ERROR -
8
+ Incorrect email or password
9
+
10
+ 2026-01-31 17:23:25,859 - ace - ERROR -
11
+ Incorrect email or password
12
+
13
+ 2026-01-31 17:23:26,330 - ace - ERROR -
14
+ Incorrect email or password
15
+
16
+ 2026-01-31 23:49:39,982 - ace - WARNING - No fields found: region=GLB, delay=1, universe=TOPDIV3000, type=VECTOR, dataset.id=fundamental28
@@ -170,7 +170,10 @@ supported_functions = {
170
170
  'scale_down': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'constant']},
171
171
 
172
172
  # Arithmetic 类别函数
173
- 'add': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'boolean']}, # add(x, y, filter=false)
173
+ # add(x, y, ..., filter=false)
174
+ # NOTE: add() is variadic (>=2 terms) with an optional boolean filter flag.
175
+ # We validate it with custom logic in validate_function().
176
+ 'add': {'min_args': 2, 'max_args': 101, 'arg_types': ['expression'] * 101},
174
177
  'multiply': {'min_args': 2, 'max_args': 100, 'arg_types': ['expression'] * 99 + ['boolean'], 'param_names': ['x', 'y', 'filter']}, # multiply(x, y, ..., filter=false)
175
178
  'sign': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
176
179
  'subtract': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'boolean']}, # subtract(x, y, filter=false)
@@ -501,6 +504,10 @@ class ExpressionValidator:
501
504
  if not function_info:
502
505
  return [f"未知函数: {function_name}"]
503
506
 
507
+ # Custom validation for variadic functions with optional flags
508
+ if function_name == 'add':
509
+ return self._validate_add(args, is_in_group_arg)
510
+
504
511
  errors = []
505
512
 
506
513
  # 检查参数数量
@@ -591,9 +598,9 @@ class ExpressionValidator:
591
598
  if arg.node_type != 'number':
592
599
  errors.append(f"参数 {arg_index+1} 应该是一个数字,但得到 {arg.node_type}")
593
600
  elif expected_type == 'boolean':
594
- # 布尔值可以是数字(0/1)
595
- if arg.node_type != 'number':
596
- errors.append(f"参数 {arg_index+1} 应该是一个布尔值(0/1),但得到 {arg.node_type}")
601
+ # 布尔值可以是 true/false 或数字(0/1)
602
+ if arg.node_type not in {'boolean', 'number'}:
603
+ errors.append(f"参数 {arg_index+1} 应该是一个布尔值(true/false 或 0/1),但得到 {arg.node_type}")
597
604
  elif expected_type == 'field':
598
605
  if arg.node_type != 'field' and arg.node_type != 'category':
599
606
  # 允许field或category作为字段参数
@@ -610,6 +617,75 @@ class ExpressionValidator:
610
617
  # group函数的category参数可以是任何类型(field、category等),不进行类型校验
611
618
 
612
619
  return errors
620
+
621
+ def _validate_add(self, args: List[Any], is_in_group_arg: bool = False) -> List[str]:
622
+ """Validate add(x, y, ..., filter=false).
623
+
624
+ Rules:
625
+ - At least 2 positional expression terms.
626
+ - Optional filter flag can be provided as:
627
+ - named argument: filter=<boolean>
628
+ - last positional argument: <boolean>
629
+ """
630
+ errors: List[str] = []
631
+
632
+ if len(args) < 2:
633
+ return [f"函数 add 需要至少 2 个参数,但只提供了 {len(args)}"]
634
+
635
+ named_filter_nodes: List[ASTNode] = []
636
+ positional_nodes: List[ASTNode] = []
637
+
638
+ for arg in args:
639
+ if isinstance(arg, dict) and arg.get('type') == 'named':
640
+ name = arg.get('name')
641
+ value = arg.get('value')
642
+ if name != 'filter':
643
+ errors.append(f"函数 add 不存在参数 '{name}'")
644
+ continue
645
+ if not hasattr(value, 'node_type'):
646
+ errors.append("函数 add 的参数 filter 格式错误")
647
+ continue
648
+ named_filter_nodes.append(value)
649
+ elif isinstance(arg, dict) and arg.get('type') == 'positional':
650
+ value = arg.get('value')
651
+ if hasattr(value, 'node_type'):
652
+ positional_nodes.append(value)
653
+ else:
654
+ errors.append("函数 add 的位置参数格式错误")
655
+ elif hasattr(arg, 'node_type'):
656
+ positional_nodes.append(arg)
657
+ else:
658
+ errors.append("函数 add 的参数格式错误")
659
+
660
+ if len(named_filter_nodes) > 1:
661
+ errors.append("函数 add 的参数 'filter' 只能出现一次")
662
+
663
+ positional_filter_node: Optional[ASTNode] = None
664
+ # Only infer a positional filter flag when:
665
+ # - no named filter is provided
666
+ # - there are at least 3 positional args (x, y, filter)
667
+ # - the last arg is boolean or numeric 0/1
668
+ if not named_filter_nodes and len(positional_nodes) >= 3:
669
+ last = positional_nodes[-1]
670
+ if last.node_type == 'boolean' or (last.node_type == 'number' and last.value in {0, 1}):
671
+ positional_filter_node = positional_nodes.pop()
672
+
673
+ if len(positional_nodes) < 2:
674
+ errors.append(f"函数 add 需要至少 2 个输入项(不含filter),但只提供了 {len(positional_nodes)}")
675
+
676
+ # Validate all term inputs as expressions (no-op, but keep recursion behavior consistent)
677
+ for idx, node in enumerate(positional_nodes):
678
+ errors.extend(self._validate_arg_type(node, 'expression', idx, 'add', is_in_group_arg))
679
+
680
+ # Validate filter, if present (named takes precedence; if both present, that's an error)
681
+ if positional_filter_node is not None and named_filter_nodes:
682
+ errors.append("函数 add 的 filter 不能同时用位置参数和命名参数传递")
683
+ if positional_filter_node is not None:
684
+ errors.extend(self._validate_arg_type(positional_filter_node, 'boolean', len(positional_nodes), 'add', is_in_group_arg))
685
+ if named_filter_nodes:
686
+ errors.extend(self._validate_arg_type(named_filter_nodes[0], 'boolean', len(positional_nodes), 'add', is_in_group_arg))
687
+
688
+ return errors
613
689
 
614
690
  def validate_ast(self, ast: Optional[ASTNode], is_in_group_arg: bool = False) -> List[str]:
615
691
  """递归验证抽象语法树"""
@@ -194,27 +194,36 @@ days_from_last_change(A) / last_diff_value(A,d)
194
194
  场景:
195
195
  因子是“事件驱动型”的(评级变动、ESG 评级更新等),只在变动后若干天内才有信号;
196
196
  可以构造“距上次变化时间”的信号。
197
- 七、Reduce / Combo 等(reduce_ / combo_a / self_corr 等)*
197
+ 七、Vector Operator*
198
+ 这些用于处理“向量类型数据”,需要先生成统计特征才能用。
198
199
 
199
- 这些更多在多因子/多 Alpha 组合层面用,但单因子也有场景:
200
+ 补充:常用 Vector Operators(Combo, Regular)
200
201
 
201
- reduce_*(avg / max / min / stddev / percentage等)
202
+ > 一句话描述:Vector 字段(例如一只股票一天里的一串向量值)不能直接参与普通的算术/时序/截面运算,通常需要先用 `vec_*` 把它“降维”为标量特征(均值/分位/波动/偏度等),再进入后续流程。
202
203
 
203
- 场景:
204
- 你想从一个“多维度向量”提炼单值,例如同一公司的多条 ESG 子项合成一个指标;
205
- 或在历史上把 A 的波动性/偏度/峰度作为新的单因子。
206
- combo_a(alphas, ...)
204
+ - `vec_avg(x)`(base):对向量求均值。例:输入 (2,3,5,6,3,8,10) 输出 37/7=5.29
205
+ - `vec_sum(x)`(base):对向量求和。例:输入 (2,3,5,6,3,8,10) 输出 37
206
+ - `vec_count(x)`(genius):向量元素个数
207
+ - `vec_choose(x, nth=k)`(genius):取向量中第 k 个元素(从 0 开始计数)
208
+ - `vec_max(x)`(genius):向量最大值
209
+ - `vec_min(x)`(genius):向量最小值
210
+ - `vec_range(x)`(genius):向量极差(max-min)
211
+ - `vec_stddev(x)`(genius):向量标准差
212
+ - `vec_ir(x)`(genius):向量信息比率(均值/标准差)
213
+ - `vec_skewness(x)`(genius):向量偏度
214
+ - `vec_kurtosis(x)`(genius):向量峰度
215
+ - `vec_norm(x)`(genius):向量范数(所有元素绝对值之和)
216
+ - `vec_percentage(x, percentage=0.5)`(genius):向量分位数(如 0.5 为中位数)
217
+ - `vec_powersum(x, constant=2)`(genius):向量幂和(对每个元素做幂后求和)
218
+ - `vec_filter(vec, value=nan)`(genius):按值过滤向量(可一次过滤多个值,例如 `"nan 0 10"`)。注意:输出仍然是 VECTOR 类型(还未降维)。
219
+
220
+ 注意:
221
+ - Vector type 数据不能直接用;你必须先用一个 `vec_*` 把它变成标量特征后再做后续组合。
222
+ - `vec_*` 只能作用在 VECTOR 类型数据上;普通 MATRIX 字段不能直接喂给 `vec_*`。
207
223
 
208
- 场景:
209
- 多个不同构造方式的同主题因子(比如多个 ESG 变体)组合,提升稳健性;
210
- 单一指标不够可靠,想自动根据历史 IR 给权重。
211
- self_corr(A)
212
224
 
213
- 场景:
214
- 研究同因子在截面上的相关结构,比如 ESG 因子和某个 sector pattern 是否极度重叠;
215
- 更偏研究/调试,不是直接构造单因子。
216
- 小结(对应你说的那些“现实情景”):
217
225
 
226
+ 小结:
218
227
  只头部/尾部有信号:
219
228
  想起:rank + bucket + 逻辑算子(greater/less/if_else/trade_when)、right_tail / left_tail。
220
229
  中间区间是噪音:
@@ -396,11 +405,8 @@ ts_delta(B,d) / days_from_last_change(B)
396
405
  例如 volume 爆量那几天放大 A,平时保持中立:
397
406
  b_spike = greater(ts_delta(B,1), thresh)
398
407
  core = trade_when(b_spike, 1.5*A, A)。
399
- 七、Reduce / Combo 等
400
408
 
401
- 多数用于多维/多因子的情况,不再一一展开;简单原则:
402
409
 
403
- 若 B 其实是一组值(如多个 volume 相关字段),先用 reduce_avg/reduce_max 合成一个 B_agg,再按前面逻辑当作单一 B 处理。
404
410
  最后给一个总的“使用从属 B 的模板公式”
405
411
 
406
412
  可以抽象成:
@@ -2683,6 +2683,13 @@ def inspiration_enhance_template():
2683
2683
  api_key = request.form.get('apiKey')
2684
2684
  base_url = request.form.get('baseUrl')
2685
2685
  model = request.form.get('model')
2686
+ data_type = request.form.get('dataType') or 'MATRIX'
2687
+
2688
+ session_id = request.headers.get('Session-ID') or flask_session.get('brain_session_id')
2689
+ session_info = brain_sessions.get(session_id) if session_id else None
2690
+
2691
+ if data_type not in ("MATRIX", "VECTOR"):
2692
+ data_type = "MATRIX"
2686
2693
 
2687
2694
  if not idea_files or not api_key:
2688
2695
  return jsonify({'success': False, 'error': 'Missing ideaFiles or apiKey'}), 400
@@ -2722,12 +2729,19 @@ def inspiration_enhance_template():
2722
2729
  env = os.environ.copy()
2723
2730
  env['IDEA_JSON'] = idea_path
2724
2731
  env['MOONSHOT_API_KEY'] = api_key
2732
+ env['DATA_TYPE'] = str(data_type)
2725
2733
  if base_url:
2726
2734
  env['MOONSHOT_BASE_URL'] = base_url
2727
2735
  if model:
2728
2736
  env['MOONSHOT_MODEL'] = model
2729
2737
  env['PYTHONIOENCODING'] = 'utf-8'
2730
2738
 
2739
+ # Inherit BRAIN auth from the logged-in web session (same as run-pipeline).
2740
+ # Do NOT accept raw credentials from the enhance form.
2741
+ if session_info and session_info.get('username') and session_info.get('password'):
2742
+ env['BRAIN_USERNAME'] = session_info['username']
2743
+ env['BRAIN_PASSWORD'] = session_info['password']
2744
+
2731
2745
  log_queue.put(f"=== 开始处理: {name} ({idx}/{total}) ===")
2732
2746
  proc = subprocess.Popen(
2733
2747
  [sys.executable, enhance_script],
@@ -0,0 +1,60 @@
1
+
2
+ # parsetab.py
3
+ # This file is automatically generated. Do not edit.
4
+ # pylint: disable=W,C,R
5
+ _tabversion = '3.10'
6
+
7
+ _lr_method = 'LALR'
8
+
9
+ _lr_signature = 'ASSIGN BOOLEAN CATEGORY COMMA DIVIDE EQUAL FIELD FUNCTION GREATER GREATEREQUAL IDENTIFIER LESS LESSEQUAL LPAREN MINUS NOTEQUAL NUMBER PLUS RPAREN STRING TIMESexpression : comparison\n| expression EQUAL comparison\n| expression NOTEQUAL comparison\n| expression GREATER comparison\n| expression LESS comparison\n| expression GREATEREQUAL comparison\n| expression LESSEQUAL comparisoncomparison : term\n| comparison PLUS term\n| comparison MINUS termterm : factor\n| term TIMES factor\n| term DIVIDE factorfactor : NUMBER\n| STRING\n| FIELD\n| CATEGORY\n| IDENTIFIER\n| BOOLEAN\n| MINUS factor\n| LPAREN expression RPAREN\n| function_callfunction_call : FUNCTION LPAREN args RPARENargs : arg_list\n| emptyarg_list : arg\n| arg_list COMMA argarg : expression\n| IDENTIFIER ASSIGN expressionempty :'
10
+
11
+ _lr_action_items = {'NUMBER':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,]),'STRING':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,]),'FIELD':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,]),'CATEGORY':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,]),'IDENTIFIER':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[10,10,10,10,10,10,10,10,10,10,10,10,10,44,44,10,]),'BOOLEAN':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,]),'MINUS':([0,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,35,36,37,38,44,45,46,47,],[4,22,-8,4,-11,-14,-15,-16,-17,-18,-19,4,-22,4,4,4,4,4,4,4,4,4,4,-20,4,22,22,22,22,22,22,-9,-10,-12,-13,-21,-18,-23,4,4,]),'LPAREN':([0,4,12,14,15,16,17,18,19,20,21,22,23,24,27,46,47,],[12,12,12,27,12,12,12,12,12,12,12,12,12,12,12,12,12,]),'FUNCTION':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,]),'$end':([1,2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,45,],[0,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,-23,]),'EQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[15,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,15,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,15,-18,-23,15,]),'NOTEQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[16,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,16,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,16,-18,-23,16,]),'GREATER':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[17,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,17,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,17,-18,-23,17,]),'LESS':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[18,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,18,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,18,-18,-23,18,]),'GREATEREQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[19,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,19,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,19,-18,-23,19,]),'LESSEQUAL':([1,2,3,5,6,7,8,9,10,11,13,25,26,28,29,30,31,32,33,34,35,36,37,38,43,44,45,49,],[20,-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,20,-18,-23,20,]),'RPAREN':([2,3,5,6,7,8,9,10,11,13,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,48,49,],[-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,38,-30,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,45,-24,-25,-26,-28,-18,-23,-27,-29,]),'COMMA':([2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,40,42,43,44,45,48,49,],[-1,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,-2,-3,-4,-5,-6,-7,-9,-10,-12,-13,-21,46,-26,-28,-18,-23,-27,-29,]),'PLUS':([2,3,5,6,7,8,9,10,11,13,25,28,29,30,31,32,33,34,35,36,37,38,44,45,],[21,-8,-11,-14,-15,-16,-17,-18,-19,-22,-20,21,21,21,21,21,21,-9,-10,-12,-13,-21,-18,-23,]),'TIMES':([3,5,6,7,8,9,10,11,13,25,34,35,36,37,38,44,45,],[23,-11,-14,-15,-16,-17,-18,-19,-22,-20,23,23,-12,-13,-21,-18,-23,]),'DIVIDE':([3,5,6,7,8,9,10,11,13,25,34,35,36,37,38,44,45,],[24,-11,-14,-15,-16,-17,-18,-19,-22,-20,24,24,-12,-13,-21,-18,-23,]),'ASSIGN':([44,],[47,]),}
12
+
13
+ _lr_action = {}
14
+ for _k, _v in _lr_action_items.items():
15
+ for _x,_y in zip(_v[0],_v[1]):
16
+ if not _x in _lr_action: _lr_action[_x] = {}
17
+ _lr_action[_x][_k] = _y
18
+ del _lr_action_items
19
+
20
+ _lr_goto_items = {'expression':([0,12,27,46,47,],[1,26,43,43,49,]),'comparison':([0,12,15,16,17,18,19,20,27,46,47,],[2,2,28,29,30,31,32,33,2,2,2,]),'term':([0,12,15,16,17,18,19,20,21,22,27,46,47,],[3,3,3,3,3,3,3,3,34,35,3,3,3,]),'factor':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[5,25,5,5,5,5,5,5,5,5,5,36,37,5,5,5,]),'function_call':([0,4,12,15,16,17,18,19,20,21,22,23,24,27,46,47,],[13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,]),'args':([27,],[39,]),'arg_list':([27,],[40,]),'empty':([27,],[41,]),'arg':([27,46,],[42,48,]),}
21
+
22
+ _lr_goto = {}
23
+ for _k, _v in _lr_goto_items.items():
24
+ for _x, _y in zip(_v[0], _v[1]):
25
+ if not _x in _lr_goto: _lr_goto[_x] = {}
26
+ _lr_goto[_x][_k] = _y
27
+ del _lr_goto_items
28
+ _lr_productions = [
29
+ ("S' -> expression","S'",1,None,None,None),
30
+ ('expression -> comparison','expression',1,'p_expression','validator.py',386),
31
+ ('expression -> expression EQUAL comparison','expression',3,'p_expression','validator.py',387),
32
+ ('expression -> expression NOTEQUAL comparison','expression',3,'p_expression','validator.py',388),
33
+ ('expression -> expression GREATER comparison','expression',3,'p_expression','validator.py',389),
34
+ ('expression -> expression LESS comparison','expression',3,'p_expression','validator.py',390),
35
+ ('expression -> expression GREATEREQUAL comparison','expression',3,'p_expression','validator.py',391),
36
+ ('expression -> expression LESSEQUAL comparison','expression',3,'p_expression','validator.py',392),
37
+ ('comparison -> term','comparison',1,'p_comparison','validator.py',399),
38
+ ('comparison -> comparison PLUS term','comparison',3,'p_comparison','validator.py',400),
39
+ ('comparison -> comparison MINUS term','comparison',3,'p_comparison','validator.py',401),
40
+ ('term -> factor','term',1,'p_term','validator.py',408),
41
+ ('term -> term TIMES factor','term',3,'p_term','validator.py',409),
42
+ ('term -> term DIVIDE factor','term',3,'p_term','validator.py',410),
43
+ ('factor -> NUMBER','factor',1,'p_factor','validator.py',417),
44
+ ('factor -> STRING','factor',1,'p_factor','validator.py',418),
45
+ ('factor -> FIELD','factor',1,'p_factor','validator.py',419),
46
+ ('factor -> CATEGORY','factor',1,'p_factor','validator.py',420),
47
+ ('factor -> IDENTIFIER','factor',1,'p_factor','validator.py',421),
48
+ ('factor -> BOOLEAN','factor',1,'p_factor','validator.py',422),
49
+ ('factor -> MINUS factor','factor',2,'p_factor','validator.py',423),
50
+ ('factor -> LPAREN expression RPAREN','factor',3,'p_factor','validator.py',424),
51
+ ('factor -> function_call','factor',1,'p_factor','validator.py',425),
52
+ ('function_call -> FUNCTION LPAREN args RPAREN','function_call',4,'p_function_call','validator.py',453),
53
+ ('args -> arg_list','args',1,'p_args','validator.py',457),
54
+ ('args -> empty','args',1,'p_args','validator.py',458),
55
+ ('arg_list -> arg','arg_list',1,'p_arg_list','validator.py',465),
56
+ ('arg_list -> arg_list COMMA arg','arg_list',3,'p_arg_list','validator.py',466),
57
+ ('arg -> expression','arg',1,'p_arg','validator.py',473),
58
+ ('arg -> IDENTIFIER ASSIGN expression','arg',3,'p_arg','validator.py',474),
59
+ ('empty -> <empty>','empty',0,'p_empty','validator.py',481),
60
+ ]
@@ -170,7 +170,10 @@ supported_functions = {
170
170
  'scale_down': {'min_args': 2, 'max_args': 2, 'arg_types': ['expression', 'number'], 'param_names': ['x', 'constant']},
171
171
 
172
172
  # Arithmetic 类别函数
173
- 'add': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'boolean']}, # add(x, y, filter=false)
173
+ # add(x, y, ..., filter=false)
174
+ # NOTE: add() is variadic (>=2 terms) with an optional boolean filter flag.
175
+ # We validate it with custom logic in validate_function().
176
+ 'add': {'min_args': 2, 'max_args': 101, 'arg_types': ['expression'] * 101},
174
177
  'multiply': {'min_args': 2, 'max_args': 100, 'arg_types': ['expression'] * 99 + ['boolean'], 'param_names': ['x', 'y', 'filter']}, # multiply(x, y, ..., filter=false)
175
178
  'sign': {'min_args': 1, 'max_args': 1, 'arg_types': ['expression']},
176
179
  'subtract': {'min_args': 2, 'max_args': 3, 'arg_types': ['expression', 'expression', 'boolean']}, # subtract(x, y, filter=false)
@@ -501,6 +504,10 @@ class ExpressionValidator:
501
504
  if not function_info:
502
505
  return [f"未知函数: {function_name}"]
503
506
 
507
+ # Custom validation for variadic functions with optional flags
508
+ if function_name == 'add':
509
+ return self._validate_add(args, is_in_group_arg)
510
+
504
511
  errors = []
505
512
 
506
513
  # 检查参数数量
@@ -591,9 +598,9 @@ class ExpressionValidator:
591
598
  if arg.node_type != 'number':
592
599
  errors.append(f"参数 {arg_index+1} 应该是一个数字,但得到 {arg.node_type}")
593
600
  elif expected_type == 'boolean':
594
- # 布尔值可以是数字(0/1)
595
- if arg.node_type != 'number':
596
- errors.append(f"参数 {arg_index+1} 应该是一个布尔值(0/1),但得到 {arg.node_type}")
601
+ # 布尔值可以是 true/false 或数字(0/1)
602
+ if arg.node_type not in {'boolean', 'number'}:
603
+ errors.append(f"参数 {arg_index+1} 应该是一个布尔值(true/false 或 0/1),但得到 {arg.node_type}")
597
604
  elif expected_type == 'field':
598
605
  if arg.node_type != 'field' and arg.node_type != 'category':
599
606
  # 允许field或category作为字段参数
@@ -610,6 +617,73 @@ class ExpressionValidator:
610
617
  # group函数的category参数可以是任何类型(field、category等),不进行类型校验
611
618
 
612
619
  return errors
620
+
621
+ def _validate_add(self, args: List[Any], is_in_group_arg: bool = False) -> List[str]:
622
+ """Validate add(x, y, ..., filter=false).
623
+
624
+ Rules:
625
+ - At least 2 positional expression terms.
626
+ - Optional filter flag can be provided as:
627
+ - named argument: filter=<boolean>
628
+ - last positional argument: <boolean> or 0/1
629
+ """
630
+ errors: List[str] = []
631
+
632
+ if len(args) < 2:
633
+ return [f"函数 add 需要至少 2 个参数,但只提供了 {len(args)}"]
634
+
635
+ named_filter_nodes: List[ASTNode] = []
636
+ positional_nodes: List[ASTNode] = []
637
+
638
+ for arg in args:
639
+ if isinstance(arg, dict) and arg.get('type') == 'named':
640
+ name = arg.get('name')
641
+ value = arg.get('value')
642
+ if name != 'filter':
643
+ errors.append(f"函数 add 不存在参数 '{name}'")
644
+ continue
645
+ if not hasattr(value, 'node_type'):
646
+ errors.append("函数 add 的参数 filter 格式错误")
647
+ continue
648
+ named_filter_nodes.append(value)
649
+ elif isinstance(arg, dict) and arg.get('type') == 'positional':
650
+ value = arg.get('value')
651
+ if hasattr(value, 'node_type'):
652
+ positional_nodes.append(value)
653
+ else:
654
+ errors.append("函数 add 的位置参数格式错误")
655
+ elif hasattr(arg, 'node_type'):
656
+ positional_nodes.append(arg)
657
+ else:
658
+ errors.append("函数 add 的参数格式错误")
659
+
660
+ if len(named_filter_nodes) > 1:
661
+ errors.append("函数 add 的参数 'filter' 只能出现一次")
662
+
663
+ positional_filter_node: Optional[ASTNode] = None
664
+ # Only infer a positional filter flag when:
665
+ # - no named filter is provided
666
+ # - there are at least 3 positional args (x, y, filter)
667
+ # - the last arg is boolean or numeric 0/1
668
+ if not named_filter_nodes and len(positional_nodes) >= 3:
669
+ last = positional_nodes[-1]
670
+ if last.node_type == 'boolean' or (last.node_type == 'number' and last.value in {0, 1}):
671
+ positional_filter_node = positional_nodes.pop()
672
+
673
+ if len(positional_nodes) < 2:
674
+ errors.append(f"函数 add 需要至少 2 个输入项(不含filter),但只提供了 {len(positional_nodes)}")
675
+
676
+ for idx, node in enumerate(positional_nodes):
677
+ errors.extend(self._validate_arg_type(node, 'expression', idx, 'add', is_in_group_arg))
678
+
679
+ if positional_filter_node is not None and named_filter_nodes:
680
+ errors.append("函数 add 的 filter 不能同时用位置参数和命名参数传递")
681
+ if positional_filter_node is not None:
682
+ errors.extend(self._validate_arg_type(positional_filter_node, 'boolean', len(positional_nodes), 'add', is_in_group_arg))
683
+ if named_filter_nodes:
684
+ errors.extend(self._validate_arg_type(named_filter_nodes[0], 'boolean', len(positional_nodes), 'add', is_in_group_arg))
685
+
686
+ return errors
613
687
 
614
688
  def validate_ast(self, ast: Optional[ASTNode], is_in_group_arg: bool = False) -> List[str]:
615
689
  """递归验证抽象语法树"""
@@ -0,0 +1,14 @@
1
+ # Local secrets
2
+ config.json
3
+
4
+ # Snapshots / outputs
5
+ sim_options_snapshot.json
6
+ processed_templates/
7
+
8
+ # Python
9
+ __pycache__/
10
+ *.pyc
11
+ .pytest_cache/
12
+
13
+ # Logs
14
+ *.log
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: brain-inspecttemplate-create-setting
3
+ description: >-
4
+ Reads a BRAIN template/idea JSON (template/idea/expression_list) like
5
+ fundamental28_GLB_1_idea_<timestamp>.json, fetches valid simulation setting options
6
+ via ace_lib.get_instrument_type_region_delay, resolves region/delay/universe/neutralization,
7
+ and builds an Alpha list JSON (one Alpha per expression) using ace_lib.generate_alpha.
8
+ Use when user asks to inspect template files, attach settings, create alpha list, or validate settings.
9
+ user-invocable: true
10
+ ---
11
+
12
+ # brain-inspectTemplate-create-Setting
13
+
14
+ This skill is designed for *stable, repeatable runs*.
15
+
16
+ ## Deterministic vs AI responsibilities
17
+
18
+ Deterministic (scripts):
19
+ - **Entry Point**: `scripts/process_template.py` handles the initial flow (Part 1).
20
+ - **Part 1 Output**: `settings_candidates.json` containing valid platform options for the detected Region/Delay.
21
+ - **Part 2 Output**: `alpha_list.json` (generated iteratively by AI).
22
+
23
+ AI reasoning (Critical Step):
24
+ - **Input**: The AI must read `idea_context.json` (to understand intent) AND `settings_candidates.json` (to see valid options).
25
+ - **Loop**: The AI can decide on **multiple** setting combinations if the idea is ambiguous or worth testing broadly.
26
+ - e.g., Run 1: `Universe=TOP3000`, `Neutralization=INDUSTRY`
27
+ - e.g., Run 2: `Universe=TOPDIV3000`, `Neutralization=MARKET`
28
+ - **Action**: For EACH chosen setting, call `scripts/build_alpha_list.py` passing the settings as a JSON string.
29
+ - The script will **APPEND** to `alpha_list.json`, allowing comprehensive test coverage.
30
+
31
+ ## Config / credentials check (startup)
32
+
33
+ To connect to BRAIN API (only needed for fetching sim options), provide credentials via one of:
34
+ 1) Environment variables: `BRAIN_USERNAME` (or `BRAIN_EMAIL`) and `BRAIN_PASSWORD`
35
+ 2) `config.json` next to this file (see `config.example.json`)
36
+ 3) `~/secrets/platform-brain.json` (keys: `email`/`password`)
37
+
38
+ Never commit real credentials. Keep `config.json` local.
39
+
40
+ ## Run steps
41
+
42
+ **Important**: Always navigate to the skill directory first, as scripts rely on relative paths.
43
+
44
+ ### One-click Processing (Recommended)
45
+ 1. **Navigate to skill folder**:
46
+ `cd "path/to/brain-inspectTemplate-create-Setting"`
47
+
48
+ 2. **Run wrapper script**:
49
+ Use the wrapper script to generate all artifacts in a dedicated folder (e.g., `processed_templates/<filename>/`).
50
+
51
+ `C:/Python313/python.exe scripts/process_template.py --file <absolute_path_to_input_json>`
52
+
53
+ *Example*:
54
+ `C:/Python313/python.exe scripts/process_template.py --file "C:/Users/user/Downloads/fundamental28_GLB_1_idea_...json"`
55
+
56
+ This will:
57
+ 1. Parse the idea file.
58
+ 2. Fetch simulation options (if `sim_options_snapshot.json` missing in root).
59
+ 3. Resolve settings.
60
+ 4. Generate the Alpha list.
61
+
62
+ ### Manual Steps (Debug)
63
+
64
+ From this folder:
65
+
66
+ 1) Parse idea JSON
67
+ - `C:/Python313/python.exe scripts/parse_idea_file.py --input fundamental28_GLB_1_idea_1769874845978315000.json --out idea_context.json`
68
+
69
+ 2) Fetch sim options snapshot (requires credentials)
70
+ - `C:/Python313/python.exe scripts/fetch_sim_options.py --out sim_options_snapshot.json`
71
+
72
+ 3) Resolve settings
73
+ - `C:/Python313/python.exe scripts/resolve_settings.py --idea idea_context.json --options sim_options_snapshot.json --out resolved_settings.json`
74
+
75
+ 4) Build alpha list
76
+ - `C:/Python313/python.exe scripts/build_alpha_list.py --idea idea_context.json --settings resolved_settings.json --out alpha_list.json`