fischer-agentkit/src/agentkit/orchestrator/pipeline_loader.py

74 lines
2.3 KiB
Python

"""Pipeline Loader - YAML 加载器"""
import logging
from pathlib import Path
import yaml
from agentkit.orchestrator.pipeline_schema import Pipeline, PipelineStage
logger = logging.getLogger(__name__)
class PipelineLoader:
"""Pipeline YAML 加载器"""
def __init__(self, pipelines_dir: str | Path | None = None):
self._pipelines_dir = Path(pipelines_dir) if pipelines_dir else Path("pipelines")
def load(self, pipeline_name: str) -> Pipeline:
"""从 YAML 文件加载 Pipeline"""
yaml_path = self._pipelines_dir / f"{pipeline_name}.yaml"
if not yaml_path.exists():
yaml_path = self._pipelines_dir / f"{pipeline_name}.yml"
if not yaml_path.exists():
raise FileNotFoundError(
f"Pipeline '{pipeline_name}' not found in {self._pipelines_dir}"
)
content = yaml_path.read_text(encoding="utf-8")
return self.load_from_yaml(content, pipeline_name)
def load_from_yaml(self, yaml_content: str, pipeline_name: str | None = None) -> Pipeline:
"""从 YAML 字符串加载 Pipeline"""
data = yaml.safe_load(yaml_content)
stages = []
for stage_data in data.get("stages", []):
stages.append(PipelineStage(**stage_data))
return Pipeline(
name=data.get("name", pipeline_name or "unnamed"),
version=data.get("version", "1.0.0"),
description=data.get("description", ""),
stages=stages,
variables=data.get("variables", {}),
)
@staticmethod
def validate_dag(stages: list[PipelineStage]) -> bool:
"""验证 DAG 无环"""
stage_names = {s.name for s in stages}
visited = set()
path = set()
def dfs(name: str) -> bool:
if name in path:
return False
if name in visited:
return True
path.add(name)
stage = next((s for s in stages if s.name == name), None)
if stage:
for dep in stage.depends_on:
if dep not in stage_names:
return False
if not dfs(dep):
return False
path.remove(name)
visited.add(name)
return True
return all(dfs(name) for name in stage_names)