Coverage for agentos/config/loader.py: 85%
284 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-08 12:20 +0800
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-08 12:20 +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 """记忆系统配置。"""
43 short_term_capacity: int = 50
44 long_term_enabled: bool = True
45 long_term_max_entries: int = 100000
46 vector_dim: int = 1536
47 vector_backend: str = "faiss"
48 vector_persist_dir: str = "./vector_data"
49 compression_interval: int = 20
52@dataclass
53class SecurityCfg:
54 """安全策略配置。"""
56 sandbox_enabled: bool = False
57 sandbox_image: str = "agentos-sandbox:latest"
58 max_file_size_mb: int = 100
59 allowed_paths: list[str] = field(default_factory=lambda: [".", "/tmp/agentos"])
62@dataclass
63class ObservabilityCfg:
64 """可观测性配置。"""
66 tracer_enabled: bool = True
67 tracer_backend: str = "console"
68 langsmith_api_key: str = ""
69 log_level: str = "INFO"
72@dataclass
73class MCPServersCfg:
74 """MCP 服务器列表配置。"""
76 servers: list[dict] = field(default_factory=list)
79@dataclass
80class ReflectionCfg:
81 """反思循环配置。"""
83 enabled: bool = True
84 frequency: int = 3
85 max_loops: int = 3
86 enable_self_critique: bool = True
89@dataclass
90class CostCfg:
91 """成本控制配置。"""
93 enabled: bool = True
94 budget_limit: float = 0.0
95 warn_threshold: float = 0.8
98@dataclass
99class FeedbackCfg:
100 """反馈回路配置。"""
102 enabled: bool = True
103 human_in_the_loop: bool = False
104 approval_trigger: str = "high_risk"
105 storage_path: str = "./feedback_data.jsonl"
108@dataclass
109class APICfg:
110 """API 服务配置。"""
112 enabled: bool = True
113 host: str = "0.0.0.0"
114 port: int = 8080
115 cors_origins: list[str] = field(default_factory=lambda: ["*"])
118@dataclass
119class SwarmCfg:
120 """Swarm 多 Agent 协作配置。"""
122 enabled: bool = True
123 topology: str = "sequential" # sequential|parallel|debate|hierarchical|broadcast
124 max_parallel_agents: int = 4
125 enable_communication: bool = True
126 enable_blackboard: bool = True
129@dataclass
130class QueueCfg:
131 """任务队列配置。"""
133 enabled: bool = False
134 backend: str = "memory" # memory|redis
135 redis_url: str = "redis://localhost:6379/0"
136 concurrency: int = 4
137 max_retries: int = 3
138 retry_backoff: str = "exponential" # exponential|linear|fixed
141@dataclass
142class CacheCfg:
143 """语义缓存配置。"""
145 enabled: bool = True
146 lru_size: int = 500
147 semantic_enabled: bool = True
148 similarity_threshold: float = 0.92
149 default_ttl: float = 3600
152@dataclass
153class ExperimentCfg:
154 """A/B 实验配置。"""
156 enabled: bool = False
157 auto_evaluator: str = "llm_judge"
158 trials_per_variant: int = 3
159 shuffle_trials: bool = True
162@dataclass
163class MultimodalCfg:
164 """多模态处理配置。"""
166 enabled: bool = True
167 max_image_size: int = 2048
168 whisper_model: str = "base"
169 document_parser: str = "auto" # auto|PyPDF2|unstructured
172@dataclass
173class MCPServerCfg:
174 """MCP 服务端配置。"""
176 enabled: bool = False
177 transport: str = "stdio"
178 host: str = "0.0.0.0"
179 port: int = 9000
180 server_name: str = "AgentOS-MCP-Server"
183@dataclass
184class GuardrailsCfg:
185 """安全护栏配置。"""
187 enabled: bool = True
188 block_pii: bool = True
189 block_injection: bool = True
190 moderation_threshold: str = "medium"
193@dataclass
194class RateLimitCfg:
195 """限流配置。"""
197 enabled: bool = True
198 strategy: str = "token_bucket"
199 max_requests: int = 60
200 per_seconds: float = 60.0
201 burst_size: int = 10
202 max_concurrent: int = 5
203 queue_timeout: float = 30.0
206@dataclass
207class StateMachineCfg:
208 """状态机配置。"""
210 max_thinking_time: float = 300.0
211 max_acting_time: float = 120.0
212 max_observing_time: float = 60.0
213 max_total_time: float = 3600.0
214 auto_recover: bool = True
217@dataclass
218class ResilienceCfg:
219 """弹性容错配置。"""
221 retry_max: int = 3
222 retry_base_delay: float = 1.0
223 retry_max_delay: float = 30.0
224 circuit_failure_threshold: int = 5
225 circuit_timeout: float = 30.0
228# ── v0.70 新增配置段 ────────────────────────────────────────────────────
231@dataclass
232class PluginsCfg:
233 """插件系统配置。"""
235 enabled: bool = True
236 plugins_dir: str = "./plugins"
237 auto_discover: bool = True
238 hot_reload: bool = False
239 max_plugins: int = 50
242@dataclass
243class GeminiCfg:
244 """Gemini 模型配置。"""
246 enabled: bool = True
247 api_key: str = ""
248 default_model: str = "gemini-2.5-flash"
249 vision_enabled: bool = True
250 max_image_size: int = 4096
251 safety_threshold: str = "BLOCK_ONLY_HIGH"
254@dataclass
255class ContractsCfg:
256 """能力契约配置。"""
258 enabled: bool = True
259 auto_discover: bool = True
260 heartbeat_interval: float = 30.0
261 stale_timeout: float = 300.0
262 max_registered: int = 100
265@dataclass
266class OrchestratorCfg:
267 """编排器配置。"""
269 enabled: bool = True
270 global_timeout: float = 300.0
271 default_retries: int = 3
272 max_concurrent_tools: int = 10
273 dag_export_dir: str = "./dags"
276@dataclass
277class ScorerCfg:
278 """评分器配置。"""
280 enabled: bool = True
281 strategy: str = "composite"
282 pass_threshold: float = 0.6
283 enable_semantic: bool = True
286# ── v0.80 新增配置段 ────────────────────────────────────────────────────
289@dataclass
290class BenchmarkCfg:
291 """性能基准配置。"""
293 enabled: bool = True
294 output_dir: str = "./benchmarks"
295 warmup_iterations: int = 3
296 measure_iterations: int = 10
297 concurrency_levels: list[int] = field(default_factory=lambda: [1, 4, 8])
298 timeout_per_run: float = 30.0
301@dataclass
302class HealthCfg:
303 """健康检查配置。"""
305 readiness_enabled: bool = True
306 liveness_enabled: bool = True
307 disk_threshold_mb: int = 100
308 memory_threshold_mb: int = 50
311@dataclass
312class AuditCfg:
313 """安全审计配置。"""
315 enabled: bool = False
316 severity_threshold: str = "medium"
317 report_format: str = "markdown"
318 auto_scan_on_startup: bool = False
321@dataclass
322class DeployCfg:
323 """部署配置。"""
325 base_image: str = "python:3.11-slim"
326 port: int = 8000
327 workers: int = 4
328 healthcheck_endpoint: str = "/health"
331@dataclass
332class MiddlewareCfg:
333 """中间件配置。"""
335 cors_enabled: bool = True
336 cors_origins: list = field(default_factory=lambda: ["*"])
337 auth_enabled: bool = False
338 request_logging: bool = True
339 rate_limit_rpm: int = 0
342@dataclass
343class AgentOSConfig:
344 """AgentOS v0.90 总配置。"""
346 model: ModelConfig = field(default_factory=ModelConfig)
347 loop: LoopCfg = field(default_factory=LoopCfg)
348 memory: MemoryCfg = field(default_factory=MemoryCfg)
349 security: SecurityCfg = field(default_factory=SecurityCfg)
350 observability: ObservabilityCfg = field(default_factory=ObservabilityCfg)
351 mcp: MCPServersCfg = field(default_factory=MCPServersCfg)
352 reflection: ReflectionCfg = field(default_factory=ReflectionCfg)
353 cost: CostCfg = field(default_factory=CostCfg)
354 feedback: FeedbackCfg = field(default_factory=FeedbackCfg)
355 api: APICfg = field(default_factory=APICfg)
356 swarm: SwarmCfg = field(default_factory=SwarmCfg)
357 queue: QueueCfg = field(default_factory=QueueCfg)
358 cache: CacheCfg = field(default_factory=CacheCfg)
359 experiment: ExperimentCfg = field(default_factory=ExperimentCfg)
360 multimodal: MultimodalCfg = field(default_factory=MultimodalCfg)
361 mcp_server: MCPServerCfg = field(default_factory=MCPServerCfg)
362 guardrails: GuardrailsCfg = field(default_factory=GuardrailsCfg)
363 rate_limit: RateLimitCfg = field(default_factory=RateLimitCfg)
364 state_machine: StateMachineCfg = field(default_factory=StateMachineCfg)
365 resilience: ResilienceCfg = field(default_factory=ResilienceCfg)
366 plugins: PluginsCfg = field(default_factory=PluginsCfg)
367 gemini: GeminiCfg = field(default_factory=GeminiCfg)
368 contracts: ContractsCfg = field(default_factory=ContractsCfg)
369 orchestrator: OrchestratorCfg = field(default_factory=OrchestratorCfg)
370 scorer: ScorerCfg = field(default_factory=ScorerCfg)
371 benchmark: BenchmarkCfg = field(default_factory=BenchmarkCfg)
372 health: HealthCfg = field(default_factory=HealthCfg)
373 audit: AuditCfg = field(default_factory=AuditCfg)
374 deploy: DeployCfg = field(default_factory=DeployCfg)
375 middleware: MiddlewareCfg = field(default_factory=MiddlewareCfg)
376 version: str = "0.90.0"
378 def to_dict(self) -> dict:
379 result = {}
380 for f in fields(self):
381 val = getattr(self, f.name)
382 if hasattr(val, "__dataclass_fields__"):
383 result[f.name] = {ff.name: getattr(val, ff.name) for ff in fields(val)}
384 else:
385 result[f.name] = val
386 return result
389def load_config(path: str | None = None) -> AgentOSConfig:
390 config = AgentOSConfig()
391 if path and os.path.exists(path):
392 try:
393 import yaml
395 with open(path) as f:
396 data = yaml.safe_load(f)
397 _merge(config, data)
398 except ImportError:
399 pass
400 except Exception:
401 pass
402 _override_from_env(config)
403 return config
406def _merge(config: AgentOSConfig, data: dict):
407 for key, val in data.items():
408 if hasattr(config, key):
409 section = getattr(config, key)
410 if hasattr(section, "__dataclass_fields__") and isinstance(val, dict):
411 for sk, sv in val.items():
412 if hasattr(section, sk):
413 setattr(section, sk, sv)
414 else:
415 setattr(config, key, val)
418def _override_from_env(config: AgentOSConfig):
419 env_map = {
420 "AGENTOS_MODEL": ("model", "default"),
421 "AGENTOS_MAX_ITERATIONS": ("loop", "max_iterations"),
422 "AGENTOS_ENABLE_STREAMING": ("loop", "enable_streaming"),
423 "AGENTOS_LOG_LEVEL": ("observability", "log_level"),
424 "AGENTOS_BUDGET_LIMIT": ("cost", "budget_limit"),
425 "AGENTOS_ENABLE_REFLECTION": ("reflection", "enabled"),
426 "AGENTOS_ENABLE_COST_TRACKING": ("cost", "enabled"),
427 "AGENTOS_API_PORT": ("api", "port"),
428 "AGENTOS_SWARM_TOPOLOGY": ("swarm", "topology"),
429 "AGENTOS_SWARM_MAX_PARALLEL": ("swarm", "max_parallel_agents"),
430 "AGENTOS_CACHE_LRU_SIZE": ("cache", "lru_size"),
431 "AGENTOS_CACHE_SEMANTIC": ("cache", "semantic_enabled"),
432 "AGENTOS_QUEUE_CONCURRENCY": ("queue", "concurrency"),
433 "AGENTOS_MCP_SERVER_PORT": ("mcp_server", "port"),
434 "AGENTOS_PLUGINS_DIR": ("plugins", "plugins_dir"),
435 "AGENTOS_PLUGINS_HOT_RELOAD": ("plugins", "hot_reload"),
436 "AGENTOS_GEMINI_API_KEY": ("gemini", "api_key"),
437 "AGENTOS_GEMINI_MODEL": ("gemini", "default_model"),
438 "AGENTOS_CONTRACTS_ENABLED": ("contracts", "enabled"),
439 "AGENTOS_ORCHESTRATOR_TIMEOUT": ("orchestrator", "global_timeout"),
440 "AGENTOS_SCORER_STRATEGY": ("scorer", "strategy"),
441 "AGENTOS_SCORER_THRESHOLD": ("scorer", "pass_threshold"),
442 }
443 for env_key, (section, field_name) in env_map.items():
444 val = os.environ.get(env_key)
445 if val is not None:
446 sec = getattr(config, section)
447 default_type = type(getattr(type(sec)(), field_name, ""))
448 if default_type is bool:
449 val_typed = val.lower() in ("1", "true", "yes")
450 elif default_type is float:
451 val_typed = float(val)
452 elif default_type is int:
453 val_typed = int(val)
454 else:
455 val_typed = val
456 setattr(sec, field_name, val_typed)