(self, **inputs: Any)
| 121 | return normalized |
| 122 | |
| 123 | async def run(self, **inputs: Any) -> dict[str, Any]: |
| 124 | topic: str = inputs["topic"] |
| 125 | experiment_blueprint: dict = inputs.get("experiment_blueprint", {}) |
| 126 | setup_output: dict = inputs.get("setup_output", {}) |
| 127 | |
| 128 | self.log("Starting coding: generating runnable experiment") |
| 129 | |
| 130 | adaptive_context = self.build_adaptive_context( |
| 131 | "coding", |
| 132 | topic=topic, |
| 133 | blueprint=experiment_blueprint, |
| 134 | text=json.dumps(experiment_blueprint, ensure_ascii=False)[:5000], |
| 135 | tags=[topic, "coding", self.workspace.manifest.paper_mode.value], |
| 136 | ) |
| 137 | |
| 138 | code_dir = self.workspace.path / "experiment" |
| 139 | code_dir.mkdir(exist_ok=True) |
| 140 | (code_dir / "configs").mkdir(exist_ok=True) |
| 141 | matrix_path = code_dir / "configs" / "experiment_matrix.json" |
| 142 | matrix_payload = { |
| 143 | "experiment_matrix": experiment_blueprint.get("experiment_matrix", []), |
| 144 | "required_artifacts": experiment_blueprint.get("required_artifacts", []), |
| 145 | "minimum_success_criteria": experiment_blueprint.get("minimum_success_criteria", {}), |
| 146 | } |
| 147 | matrix_path.write_text(json.dumps(matrix_payload, indent=2, ensure_ascii=False), encoding="utf-8") |
| 148 | |
| 149 | # Step 1: Design the experiment code plan |
| 150 | code_plan = await self._design_code_plan( |
| 151 | topic, experiment_blueprint, setup_output, |
| 152 | adaptive_context=adaptive_context, |
| 153 | ) |
| 154 | self.log(f"Code plan: {len(code_plan.get('files', []))} files") |
| 155 | |
| 156 | # Step 2: Generate each file (parallel for speed) |
| 157 | valid_specs = [] |
| 158 | seen_spec_paths: set[str] = set() |
| 159 | for spec in code_plan.get("files", []): |
| 160 | if not isinstance(spec, dict) or not spec.get("path"): |
| 161 | continue |
| 162 | normalized_path = self._normalize_project_file_path(str(spec.get("path") or "")) |
| 163 | if not normalized_path or normalized_path in seen_spec_paths: |
| 164 | continue |
| 165 | seen_spec_paths.add(normalized_path) |
| 166 | valid_specs.append({**spec, "path": normalized_path}) |
| 167 | self.log(f" Generating {len(valid_specs)} files in parallel") |
| 168 | contents = await asyncio.gather(*( |
| 169 | self._generate_file(spec, code_plan, experiment_blueprint, setup_output) |
| 170 | for spec in valid_specs |
| 171 | )) |
| 172 | |
| 173 | generated_files = ["configs/experiment_matrix.json"] |
| 174 | for spec, content in zip(valid_specs, contents): |
| 175 | filepath = spec["path"] |
| 176 | full_path = code_dir / filepath |
| 177 | full_path.parent.mkdir(parents=True, exist_ok=True) |
| 178 | full_path.write_text(content, encoding="utf-8") |
| 179 | generated_files.append(str(filepath)) |
| 180 | self.log(f"Generated: {filepath}") |
no test coverage detected