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

1""" 

2AgentOS v0.80 统一配置系统。 

3v0.80新增: BenchmarkCfg。 

4v0.70基线: PluginsCfg, GeminiCfg, ContractsCfg, OrchestratorCfg, ScorerCfg。 

5v0.60基线: GuardrailsCfg, RateLimitCfg, StateMachineCfg, ResilienceCfg。 

6""" 

7 

8from __future__ import annotations 

9 

10import os 

11from dataclasses import dataclass, field, fields 

12 

13 

14@dataclass 

15class ModelConfig: 

16 """LLM 模型配置。""" 

17 

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 = "" 

25 

26 

27@dataclass 

28class LoopCfg: 

29 """Agent 主循环配置。""" 

30 

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 

37 

38 

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 

49 

50 

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"]) 

58 

59 

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" 

67 

68 

69@dataclass 

70class MCPServersCfg: 

71 """MCP 服务器列表配置。""" 

72 servers: list[dict] = field(default_factory=list) 

73 

74 

75@dataclass 

76class ReflectionCfg: 

77 """反思循环配置。""" 

78 enabled: bool = True 

79 frequency: int = 3 

80 max_loops: int = 3 

81 enable_self_critique: bool = True 

82 

83 

84@dataclass 

85class CostCfg: 

86 """成本控制配置。""" 

87 enabled: bool = True 

88 budget_limit: float = 0.0 

89 warn_threshold: float = 0.8 

90 

91 

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" 

99 

100 

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: ["*"]) 

108 

109 

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 

118 

119 

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 

129 

130 

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 

139 

140 

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 

148 

149 

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 

157 

158 

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" 

167 

168 

169@dataclass 

170class GuardrailsCfg: 

171 """安全护栏配置。""" 

172 enabled: bool = True 

173 block_pii: bool = True 

174 block_injection: bool = True 

175 moderation_threshold: str = "medium" 

176 

177 

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 

188 

189 

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 

198 

199 

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 

208 

209 

210# ── v0.70 新增配置段 ──────────────────────────────────────────────────── 

211 

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 

220 

221 

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" 

231 

232 

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 

241 

242 

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" 

251 

252 

253@dataclass 

254class ScorerCfg: 

255 """评分器配置。""" 

256 enabled: bool = True 

257 strategy: str = "composite" 

258 pass_threshold: float = 0.6 

259 enable_semantic: bool = True 

260 

261 

262# ── v0.80 新增配置段 ──────────────────────────────────────────────────── 

263 

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 

273 

274 

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 

282 

283 

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 

291 

292 

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" 

300 

301 

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 

310 

311 

312@dataclass 

313class AgentOSConfig: 

314 """AgentOS v0.90 总配置。""" 

315 

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" 

347 

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 

357 

358 

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 

373 

374 

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) 

385 

386 

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)