crewai.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. """
  2. lambdagent_guard.crewai — CrewAI guard wrapper (I12).
  3. Usage:
  4. from lambdagent_guard import guard_crewai
  5. crew = Crew(agents=[researcher, writer], tasks=[...])
  6. guarded = guard_crewai(crew, cost_budget=10.0)
  7. result = guarded.kickoff()
  8. Catches: CrewAI #3847 (max_iter broken), #737 (tool result lost), #1355 (10x cost)
  9. """
  10. from __future__ import annotations
  11. from typing import Any, Callable, Optional
  12. from .core import GuardConfig, RuntimeMonitor, run_compile_checks
  13. import warnings
  14. def guard_crewai(
  15. crew,
  16. cost_budget: float = float("inf"),
  17. parallel_safety: bool = True,
  18. terminate_check: bool = True,
  19. loop_detection: bool = True,
  20. cost_alert: Optional[Callable[[float], None]] = None,
  21. ):
  22. """
  23. Wrap a CrewAI Crew with lambdagent safety guards.
  24. Args:
  25. crew: CrewAI Crew object
  26. cost_budget: Max cost in USD
  27. parallel_safety: Check agent store independence
  28. terminate_check: Verify termination conditions exist
  29. """
  30. guard_cfg = GuardConfig(
  31. cost_budget=cost_budget,
  32. parallel_safety=parallel_safety,
  33. terminate_check=terminate_check,
  34. loop_detection=loop_detection,
  35. cost_alert=cost_alert,
  36. )
  37. # Phase 1: Compile-time checks
  38. try:
  39. from lambdagent.extractors import extract_config
  40. config = extract_config(crew, framework="crewai")
  41. issues = run_compile_checks(config, guard_cfg)
  42. for issue in issues:
  43. warnings.warn(f"[lambdagent-guard] {issue}")
  44. except Exception as e:
  45. warnings.warn(f"[lambdagent-guard] Compile check skipped: {e}")
  46. # Phase 2: Runtime hooks — wrap kickoff()
  47. monitor = RuntimeMonitor(guard_cfg)
  48. original_kickoff = crew.kickoff
  49. def guarded_kickoff(*args, **kwargs):
  50. # Hook into each agent's execution
  51. for agent in getattr(crew, 'agents', []):
  52. _hook_crewai_agent(agent, monitor)
  53. result = original_kickoff(*args, **kwargs)
  54. return result
  55. crew.kickoff = guarded_kickoff
  56. crew._lambdagent_monitor = monitor
  57. return crew
  58. def _hook_crewai_agent(agent, monitor: RuntimeMonitor):
  59. """Hook into a CrewAI agent's execute_task if available."""
  60. if hasattr(agent, 'execute_task'):
  61. original = agent.execute_task
  62. def guarded_execute(*args, **kwargs):
  63. result = original(*args, **kwargs)
  64. monitor.on_step({
  65. "output": str(result)[:500],
  66. "tokens": 0,
  67. })
  68. return result
  69. agent.execute_task = guarded_execute