Coverage for agentos/config/loader.py: 85%
284 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-02 09:59 +0800
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-02 09:59 +0800
1"""
2AgentOS v0.80 统一配置系统。
3v0.80新增: BenchmarkCfg。
4v0.70基线: PluginsCfg, GeminiCfg, ContractsCfg, OrchestratorCfg, ScorerCfg。
5v0.60基线: GuardrailsCfg, RateLimitCfg, StateMachineCfg, ResilienceCfg。
6"""
8from __future__ import annotations
10import os
11from dataclasses import dataclass, field, fields
14@dataclass
15class ModelConfig:
16 """LLM 模型配置。"""
18 default: str = "deepseek-v3.1"
19 fallback_chain: list[str] = field(default_factory=lambda: ["kimi-k2.6", "qwen-3.6-plus"])
20 auto_select: bool = True
21 max_retries: int = 3
22 request_timeout: int = 120
23 api_base: str = ""
24 api_key: str = ""
27@dataclass
28class LoopCfg:
29 """Agent 主循环配置。"""
31 max_iterations: int = 100
32 max_retries_per_step: int = 2
33 step_timeout_seconds: int = 120
34 enable_streaming: bool = False
35 enable_checkpoints: bool = True
36 checkpoint_interval: int = 5
39@dataclass
40class MemoryCfg:
41 """记忆系统配置。"""
42 short_term_capacity: int = 50
43 long_term_enabled: bool = True
44 long_term_max_entries: int = 100000
45 vector_dim: int = 1536
46 vector_backend: str = "faiss"
47 vector_persist_dir: str = "./vector_data"
48 compression_interval: int = 20
51@dataclass
52class SecurityCfg:
53 """安全策略配置。"""
54 sandbox_enabled: bool = False
55 sandbox_image: str = "agentos-sandbox:latest"
56 max_file_size_mb: int = 100
57 allowed_paths: list[str] = field(default_factory=lambda: [".", "/tmp/agentos"])
60@dataclass
61class ObservabilityCfg:
62 """可观测性配置。"""
63 tracer_enabled: bool = True
64 tracer_backend: str = "console"
65 langsmith_api_key: str = ""
66 log_level: str = "INFO"
69@dataclass
70class MCPServersCfg:
71 """MCP 服务器列表配置。"""
72 servers: list[dict] = field(default_factory=list)
75@dataclass
76class ReflectionCfg:
77 """反思循环配置。"""
78 enabled: bool = True
79 frequency: int = 3
80 max_loops: int = 3
81 enable_self_critique: bool = True
84@dataclass
85class CostCfg:
86 """成本控制配置。"""
87 enabled: bool = True
88 budget_limit: float = 0.0
89 warn_threshold: float = 0.8
92@dataclass
93class FeedbackCfg:
94 """反馈回路配置。"""
95 enabled: bool = True
96 human_in_the_loop: bool = False
97 approval_trigger: str = "high_risk"
98 storage_path: str = "./feedback_data.jsonl"
101@dataclass
102class APICfg:
103 """API 服务配置。"""
104 enabled: bool = True
105 host: str = "0.0.0.0"
106 port: int = 8080
107 cors_origins: list[str] = field(default_factory=lambda: ["*"])
110@dataclass
111class SwarmCfg:
112 """Swarm 多 Agent 协作配置。"""
113 enabled: bool = True
114 topology: str = "sequential" # sequential|parallel|debate|hierarchical|broadcast
115 max_parallel_agents: int = 4
116 enable_communication: bool = True
117 enable_blackboard: bool = True
120@dataclass
121class QueueCfg:
122 """任务队列配置。"""
123 enabled: bool = False
124 backend: str = "memory" # memory|redis
125 redis_url: str = "redis://localhost:6379/0"
126 concurrency: int = 4
127 max_retries: int = 3
128 retry_backoff: str = "exponential" # exponential|linear|fixed
131@dataclass
132class CacheCfg:
133 """语义缓存配置。"""
134 enabled: bool = True
135 lru_size: int = 500
136 semantic_enabled: bool = True
137 similarity_threshold: float = 0.92
138 default_ttl: float = 3600
141@dataclass
142class ExperimentCfg:
143 """A/B 实验配置。"""
144 enabled: bool = False
145 auto_evaluator: str = "llm_judge"
146 trials_per_variant: int = 3
147 shuffle_trials: bool = True
150@dataclass
151class MultimodalCfg:
152 """多模态处理配置。"""
153 enabled: bool = True
154 max_image_size: int = 2048
155 whisper_model: str = "base"
156 document_parser: str = "auto" # auto|PyPDF2|unstructured
159@dataclass
160class MCPServerCfg:
161 """MCP 服务端配置。"""
162 enabled: bool = False
163 transport: str = "stdio"
164 host: str = "0.0.0.0"
165 port: int = 9000
166 server_name: str = "AgentOS-MCP-Server"
169@dataclass
170class GuardrailsCfg:
171 """安全护栏配置。"""
172 enabled: bool = True
173 block_pii: bool = True
174 block_injection: bool = True
175 moderation_threshold: str = "medium"
178@dataclass
179class RateLimitCfg:
180 """限流配置。"""
181 enabled: bool = True
182 strategy: str = "token_bucket"
183 max_requests: int = 60
184 per_seconds: float = 60.0
185 burst_size: int = 10
186 max_concurrent: int = 5
187 queue_timeout: float = 30.0
190@dataclass
191class StateMachineCfg:
192 """状态机配置。"""
193 max_thinking_time: float = 300.0
194 max_acting_time: float = 120.0
195 max_observing_time: float = 60.0
196 max_total_time: float = 3600.0
197 auto_recover: bool = True
200@dataclass
201class ResilienceCfg:
202 """弹性容错配置。"""
203 retry_max: int = 3
204 retry_base_delay: float = 1.0
205 retry_max_delay: float = 30.0
206 circuit_failure_threshold: int = 5
207 circuit_timeout: float = 30.0
210# ── v0.70 新增配置段 ────────────────────────────────────────────────────
212@dataclass
213class PluginsCfg:
214 """插件系统配置。"""
215 enabled: bool = True
216 plugins_dir: str = "./plugins"
217 auto_discover: bool = True
218 hot_reload: bool = False
219 max_plugins: int = 50
222@dataclass
223class GeminiCfg:
224 """Gemini 模型配置。"""
225 enabled: bool = True
226 api_key: str = ""
227 default_model: str = "gemini-2.5-flash"
228 vision_enabled: bool = True
229 max_image_size: int = 4096
230 safety_threshold: str = "BLOCK_ONLY_HIGH"
233@dataclass
234class ContractsCfg:
235 """能力契约配置。"""
236 enabled: bool = True
237 auto_discover: bool = True
238 heartbeat_interval: float = 30.0
239 stale_timeout: float = 300.0
240 max_registered: int = 100
243@dataclass
244class OrchestratorCfg:
245 """编排器配置。"""
246 enabled: bool = True
247 global_timeout: float = 300.0
248 default_retries: int = 3
249 max_concurrent_tools: int = 10
250 dag_export_dir: str = "./dags"
253@dataclass
254class ScorerCfg:
255 """评分器配置。"""
256 enabled: bool = True
257 strategy: str = "composite"
258 pass_threshold: float = 0.6
259 enable_semantic: bool = True
262# ── v0.80 新增配置段 ────────────────────────────────────────────────────
264@dataclass
265class BenchmarkCfg:
266 """性能基准配置。"""
267 enabled: bool = True
268 output_dir: str = "./benchmarks"
269 warmup_iterations: int = 3
270 measure_iterations: int = 10
271 concurrency_levels: list[int] = field(default_factory=lambda: [1, 4, 8])
272 timeout_per_run: float = 30.0
275@dataclass
276class HealthCfg:
277 """健康检查配置。"""
278 readiness_enabled: bool = True
279 liveness_enabled: bool = True
280 disk_threshold_mb: int = 100
281 memory_threshold_mb: int = 50
284@dataclass
285class AuditCfg:
286 """安全审计配置。"""
287 enabled: bool = False
288 severity_threshold: str = "medium"
289 report_format: str = "markdown"
290 auto_scan_on_startup: bool = False
293@dataclass
294class DeployCfg:
295 """部署配置。"""
296 base_image: str = "python:3.11-slim"
297 port: int = 8000
298 workers: int = 4
299 healthcheck_endpoint: str = "/health"
302@dataclass
303class MiddlewareCfg:
304 """中间件配置。"""
305 cors_enabled: bool = True
306 cors_origins: list = field(default_factory=lambda: ["*"])
307 auth_enabled: bool = False
308 request_logging: bool = True
309 rate_limit_rpm: int = 0
312@dataclass
313class AgentOSConfig:
314 """AgentOS v0.90 总配置。"""
316 model: ModelConfig = field(default_factory=ModelConfig)
317 loop: LoopCfg = field(default_factory=LoopCfg)
318 memory: MemoryCfg = field(default_factory=MemoryCfg)
319 security: SecurityCfg = field(default_factory=SecurityCfg)
320 observability: ObservabilityCfg = field(default_factory=ObservabilityCfg)
321 mcp: MCPServersCfg = field(default_factory=MCPServersCfg)
322 reflection: ReflectionCfg = field(default_factory=ReflectionCfg)
323 cost: CostCfg = field(default_factory=CostCfg)
324 feedback: FeedbackCfg = field(default_factory=FeedbackCfg)
325 api: APICfg = field(default_factory=APICfg)
326 swarm: SwarmCfg = field(default_factory=SwarmCfg)
327 queue: QueueCfg = field(default_factory=QueueCfg)
328 cache: CacheCfg = field(default_factory=CacheCfg)
329 experiment: ExperimentCfg = field(default_factory=ExperimentCfg)
330 multimodal: MultimodalCfg = field(default_factory=MultimodalCfg)
331 mcp_server: MCPServerCfg = field(default_factory=MCPServerCfg)
332 guardrails: GuardrailsCfg = field(default_factory=GuardrailsCfg)
333 rate_limit: RateLimitCfg = field(default_factory=RateLimitCfg)
334 state_machine: StateMachineCfg = field(default_factory=StateMachineCfg)
335 resilience: ResilienceCfg = field(default_factory=ResilienceCfg)
336 plugins: PluginsCfg = field(default_factory=PluginsCfg)
337 gemini: GeminiCfg = field(default_factory=GeminiCfg)
338 contracts: ContractsCfg = field(default_factory=ContractsCfg)
339 orchestrator: OrchestratorCfg = field(default_factory=OrchestratorCfg)
340 scorer: ScorerCfg = field(default_factory=ScorerCfg)
341 benchmark: BenchmarkCfg = field(default_factory=BenchmarkCfg)
342 health: HealthCfg = field(default_factory=HealthCfg)
343 audit: AuditCfg = field(default_factory=AuditCfg)
344 deploy: DeployCfg = field(default_factory=DeployCfg)
345 middleware: MiddlewareCfg = field(default_factory=MiddlewareCfg)
346 version: str = "0.90.0"
348 def to_dict(self) -> dict:
349 result = {}
350 for f in fields(self):
351 val = getattr(self, f.name)
352 if hasattr(val, "__dataclass_fields__"):
353 result[f.name] = {ff.name: getattr(val, ff.name) for ff in fields(val)}
354 else:
355 result[f.name] = val
356 return result
359def load_config(path: str | None = None) -> AgentOSConfig:
360 config = AgentOSConfig()
361 if path and os.path.exists(path):
362 try:
363 import yaml
364 with open(path) as f:
365 data = yaml.safe_load(f)
366 _merge(config, data)
367 except ImportError:
368 pass
369 except Exception:
370 pass
371 _override_from_env(config)
372 return config
375def _merge(config: AgentOSConfig, data: dict):
376 for key, val in data.items():
377 if hasattr(config, key):
378 section = getattr(config, key)
379 if hasattr(section, "__dataclass_fields__") and isinstance(val, dict):
380 for sk, sv in val.items():
381 if hasattr(section, sk):
382 setattr(section, sk, sv)
383 else:
384 setattr(config, key, val)
387def _override_from_env(config: AgentOSConfig):
388 env_map = {
389 "AGENTOS_MODEL": ("model", "default"),
390 "AGENTOS_MAX_ITERATIONS": ("loop", "max_iterations"),
391 "AGENTOS_ENABLE_STREAMING": ("loop", "enable_streaming"),
392 "AGENTOS_LOG_LEVEL": ("observability", "log_level"),
393 "AGENTOS_BUDGET_LIMIT": ("cost", "budget_limit"),
394 "AGENTOS_ENABLE_REFLECTION": ("reflection", "enabled"),
395 "AGENTOS_ENABLE_COST_TRACKING": ("cost", "enabled"),
396 "AGENTOS_API_PORT": ("api", "port"),
397 "AGENTOS_SWARM_TOPOLOGY": ("swarm", "topology"),
398 "AGENTOS_SWARM_MAX_PARALLEL": ("swarm", "max_parallel_agents"),
399 "AGENTOS_CACHE_LRU_SIZE": ("cache", "lru_size"),
400 "AGENTOS_CACHE_SEMANTIC": ("cache", "semantic_enabled"),
401 "AGENTOS_QUEUE_CONCURRENCY": ("queue", "concurrency"),
402 "AGENTOS_MCP_SERVER_PORT": ("mcp_server", "port"),
403 "AGENTOS_PLUGINS_DIR": ("plugins", "plugins_dir"),
404 "AGENTOS_PLUGINS_HOT_RELOAD": ("plugins", "hot_reload"),
405 "AGENTOS_GEMINI_API_KEY": ("gemini", "api_key"),
406 "AGENTOS_GEMINI_MODEL": ("gemini", "default_model"),
407 "AGENTOS_CONTRACTS_ENABLED": ("contracts", "enabled"),
408 "AGENTOS_ORCHESTRATOR_TIMEOUT": ("orchestrator", "global_timeout"),
409 "AGENTOS_SCORER_STRATEGY": ("scorer", "strategy"),
410 "AGENTOS_SCORER_THRESHOLD": ("scorer", "pass_threshold"),
411 }
412 for env_key, (section, field_name) in env_map.items():
413 val = os.environ.get(env_key)
414 if val is not None:
415 sec = getattr(config, section)
416 default_type = type(getattr(type(sec)(), field_name, ""))
417 if default_type is bool:
418 val_typed = val.lower() in ("1", "true", "yes")
419 elif default_type is float:
420 val_typed = float(val)
421 elif default_type is int:
422 val_typed = int(val)
423 else:
424 val_typed = val
425 setattr(sec, field_name, val_typed)