capybala 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
capybala/__init__.py ADDED
@@ -0,0 +1,68 @@
1
+ """
2
+ 🦫 Capybala: Autonomous Agent Self-Healing & Deadlock-Resolution Runtime
3
+ Context-Aware Pruning for Yielding & Backtrack-Aligned Loop Avoidance
4
+ """
5
+
6
+ # The Requests-Grade Core API (Clean, Zero-Magic)
7
+ from .api import watch, heal, validate, repair
8
+
9
+ # Core Engine
10
+ from .detector import DeadlockDetector, DeadlockEvent, DeadlockEmergencyStop
11
+ from .pruner import ContextPruner, PruneResult
12
+ from .healer import AgentHealer, HealingPrescription
13
+
14
+ # Proactive Engine, Adaptive Policy & Semantic Attractor Manifold
15
+ from .validator import SchemaValidator, repair_json_string
16
+ from .proactive import SearchOptimizer
17
+ from .policy import DeadlockPolicy, DeadlockMode
18
+ from .attractor import SemanticAttractorDetector
19
+
20
+ # Framework Integrations (Universal ABS Middleware)
21
+ from .integrations import (
22
+ CapybalaLangGraphMiddleware,
23
+ capybala_node,
24
+ CapybalaCrewCallback,
25
+ CapybalaAutoGenFilter,
26
+ )
27
+
28
+ # Legacy / Base Adapters
29
+ from .adapters import (
30
+ BaseAgentAdapter,
31
+ CapybalaGuard,
32
+ LlamaStackCapybalaMiddleware,
33
+ CapybalaCallbackHandler
34
+ )
35
+
36
+ __version__ = "0.8.0"
37
+ __all__ = [
38
+ # Top-Level DX
39
+ "watch",
40
+ "heal",
41
+ "validate",
42
+ "repair",
43
+ # Core Engine
44
+ "DeadlockDetector",
45
+ "DeadlockEvent",
46
+ "DeadlockEmergencyStop",
47
+ "ContextPruner",
48
+ "PruneResult",
49
+ "AgentHealer",
50
+ "HealingPrescription",
51
+ # Proactive, Adaptive & Manifold
52
+ "SchemaValidator",
53
+ "repair_json_string",
54
+ "SearchOptimizer",
55
+ "DeadlockPolicy",
56
+ "DeadlockMode",
57
+ "SemanticAttractorDetector",
58
+ # Universal Integrations
59
+ "CapybalaLangGraphMiddleware",
60
+ "capybala_node",
61
+ "CapybalaCrewCallback",
62
+ "CapybalaAutoGenFilter",
63
+ # Adapters
64
+ "BaseAgentAdapter",
65
+ "CapybalaGuard",
66
+ "LlamaStackCapybalaMiddleware",
67
+ "CapybalaCallbackHandler",
68
+ ]
@@ -0,0 +1,17 @@
1
+ """
2
+ Universal Agent Adapters for Capybala.
3
+ """
4
+
5
+ from .base import BaseAgentAdapter
6
+ from .generic import CapybalaGuard, capybala_watch
7
+ from .llama_stack import LlamaStackCapybalaMiddleware
8
+ from .langchain import CapybalaCallbackHandler
9
+
10
+ __all__ = [
11
+ "BaseAgentAdapter",
12
+ "CapybalaGuard",
13
+ "capybala_watch",
14
+ "LlamaStackCapybalaMiddleware",
15
+ "CapybalaCallbackHandler"
16
+ ]
17
+
@@ -0,0 +1,101 @@
1
+ """
2
+ capybala.adapters.base
3
+ ~~~~~~~~~~~~~~~~~~~~~~
4
+ Abstract Base Adapter for universal agent framework integration.
5
+ Combines Detector, Pruner, and Healer into a unified lifecycle interceptor.
6
+ Enforces Circuit Breakers against infinite healing loops.
7
+ """
8
+
9
+ from abc import ABC, abstractmethod
10
+ from typing import List, Dict, Any, Tuple, Optional
11
+ from ..detector import DeadlockDetector, DeadlockEvent, DeadlockEmergencyStop
12
+ from ..pruner import ContextPruner, PruneResult
13
+ from ..healer import AgentHealer, HealingPrescription
14
+
15
+
16
+ class BaseAgentAdapter(ABC):
17
+ """
18
+ Base lifecycle adapter connecting Capybala to any AI agent runtime.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ repetition_threshold: int = 3,
24
+ oscillation_threshold: int = 2,
25
+ supervisor_model: str = "meta-llama/llama-3.2-1b-instruct",
26
+ supervisor_client: Optional[Any] = None,
27
+ use_supervisor_llm: bool = False,
28
+ max_interventions: int = 5,
29
+ circuit_breaker_enabled: bool = True,
30
+ ):
31
+ self.detector = DeadlockDetector(
32
+ repetition_threshold=repetition_threshold,
33
+ oscillation_threshold=oscillation_threshold,
34
+ max_interventions=max_interventions,
35
+ circuit_breaker_enabled=circuit_breaker_enabled,
36
+ )
37
+ self.pruner = ContextPruner()
38
+ self.healer = AgentHealer(
39
+ supervisor_client=supervisor_client,
40
+ supervisor_model=supervisor_model,
41
+ )
42
+ self.use_supervisor_llm = use_supervisor_llm
43
+ self.interventions_count = 0
44
+ self.total_tokens_recovered = 0
45
+ self.is_circuit_broken = False
46
+
47
+ def intercept_step(
48
+ self,
49
+ action: str,
50
+ observation: str,
51
+ messages: List[Dict[str, Any]],
52
+ task_prompt: str = ""
53
+ ) -> Tuple[bool, List[Dict[str, Any]], Optional[HealingPrescription]]:
54
+ """
55
+ Intercepts an agent's execution step.
56
+
57
+ Parameters:
58
+ - action: The tool call or terminal command the agent executed.
59
+ - observation: The environment response / traceback output.
60
+ - messages: The running conversation history.
61
+ - task_prompt: The initial objective description.
62
+
63
+ Returns:
64
+ - (is_rescued, updated_messages, optional_prescription)
65
+ """
66
+ event = self.detector.check(action, observation)
67
+
68
+ if not event.is_deadlock:
69
+ return False, messages, None
70
+
71
+ # Deadlock detected! Execute Capybala self-healing protocol:
72
+ self.interventions_count += 1
73
+ if event.is_circuit_broken:
74
+ self.is_circuit_broken = True
75
+
76
+ # 1. Formulate strategic Doctor Prescription with progressive escalation
77
+ rx = self.healer.prescribe(
78
+ deadlock_pattern=event.pattern_type or "unknown",
79
+ failing_action=action,
80
+ error_signature=observation,
81
+ task_prompt=task_prompt,
82
+ use_supervisor_llm=self.use_supervisor_llm,
83
+ escalation_level=event.consecutive_deadlocks or 1,
84
+ )
85
+
86
+ # 2. Execute Atomic Checkpoint Rollback with Domain Guidance
87
+ prune_result = self.pruner.rollback_and_reflect(
88
+ messages=messages,
89
+ failing_action=action,
90
+ deadlock_details=event.details,
91
+ reflection_guidance=rx.recommended_pivot,
92
+ rollback_turns=event.repetition_count * 2,
93
+ )
94
+ self.total_tokens_recovered += prune_result.tokens_saved_estimate
95
+
96
+ return True, prune_result.pruned_messages, rx
97
+
98
+ def reset(self):
99
+ """Resets detector state for a new conversation turn."""
100
+ self.detector.reset()
101
+ self.is_circuit_broken = False
@@ -0,0 +1,114 @@
1
+ """
2
+ capybala.adapters.generic
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Generic adapter for raw message lists, OpenAI API, Anthropic, Ollama, and custom agent loops.
5
+ Provides both an object wrapper (`CapybalaGuard`) and a decorator (`@capybala_watch`).
6
+ """
7
+
8
+ import functools
9
+ from typing import List, Dict, Any, Optional, Callable
10
+ from .base import BaseAgentAdapter
11
+ from ..healer import HealingPrescription
12
+
13
+
14
+ class CapybalaGuard(BaseAgentAdapter):
15
+ """
16
+ Lightweight runtime guard wrapping an agent's active conversation messages.
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ messages: List[Dict[str, Any]],
22
+ task_prompt: str = "",
23
+ repetition_threshold: int = 3,
24
+ oscillation_threshold: int = 2,
25
+ supervisor_model: str = "meta-llama/llama-3.2-1b-instruct",
26
+ supervisor_client: Optional[Any] = None,
27
+ use_supervisor_llm: bool = False,
28
+ max_interventions: int = 5,
29
+ circuit_breaker_enabled: bool = True,
30
+ ):
31
+ super().__init__(
32
+ repetition_threshold=repetition_threshold,
33
+ oscillation_threshold=oscillation_threshold,
34
+ supervisor_model=supervisor_model,
35
+ supervisor_client=supervisor_client,
36
+ use_supervisor_llm=use_supervisor_llm,
37
+ max_interventions=max_interventions,
38
+ circuit_breaker_enabled=circuit_breaker_enabled,
39
+ )
40
+ self.messages = messages
41
+ self.task_prompt = task_prompt
42
+ self.latest_prescription: Optional[HealingPrescription] = None
43
+ self.is_deadlocked: bool = False
44
+
45
+ def step(self, action: str, observation: str) -> bool:
46
+ """
47
+ Record an action and observation turn.
48
+ If a deadlock is identified, self-heals in-place and updates `self.messages`.
49
+
50
+ Returns:
51
+ - True if a deadlock was intercepted and healed, False otherwise.
52
+ """
53
+ is_rescued, updated_msgs, rx = self.intercept_step(
54
+ action=action,
55
+ observation=observation,
56
+ messages=self.messages,
57
+ task_prompt=self.task_prompt
58
+ )
59
+
60
+ if is_rescued:
61
+ self.messages.clear()
62
+ self.messages.extend(updated_msgs)
63
+ self.latest_prescription = rx
64
+ self.is_deadlocked = True
65
+ return True
66
+
67
+ self.is_deadlocked = False
68
+ return False
69
+
70
+ def __enter__(self):
71
+ return self
72
+
73
+ def __exit__(self, exc_type, exc_val, exc_tb):
74
+ pass
75
+
76
+
77
+ def capybala_watch(
78
+ repetition_threshold: int = 3,
79
+ use_supervisor_llm: bool = False,
80
+ supervisor_model: str = "meta-llama/llama-3.2-1b-instruct"
81
+ ):
82
+ """
83
+ Function decorator to automatically attach Capybala deadlock detection
84
+ and self-healing to an autonomous agent step function.
85
+ """
86
+ def decorator(func: Callable):
87
+ adapter = BaseAgentAdapter(
88
+ repetition_threshold=repetition_threshold,
89
+ use_supervisor_llm=use_supervisor_llm,
90
+ supervisor_model=supervisor_model
91
+ )
92
+
93
+ @functools.wraps(func)
94
+ def wrapper(*args, **kwargs):
95
+ # Expecting kwargs or args containing 'action', 'observation', and 'messages'
96
+ action = kwargs.get("action", "")
97
+ observation = kwargs.get("observation", "")
98
+ messages = kwargs.get("messages", None)
99
+
100
+ if messages is not None and action:
101
+ rescued, updated_msgs, rx = adapter.intercept_step(
102
+ action=action,
103
+ observation=observation,
104
+ messages=messages
105
+ )
106
+ if rescued:
107
+ kwargs["messages"] = updated_msgs
108
+ kwargs["capybala_healed"] = True
109
+ kwargs["prescription"] = rx
110
+
111
+ return func(*args, **kwargs)
112
+ return wrapper
113
+ return decorator
114
+
@@ -0,0 +1,78 @@
1
+ """
2
+ capybala.adapters.langchain
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ LangChain & LangGraph integration for Capybala.
5
+ Provides a drop-in CallbackHandler that tracks tool loops and alerts/heals agents.
6
+ """
7
+
8
+ from typing import Dict, Any, List, Optional
9
+ from .base import BaseAgentAdapter
10
+ from ..healer import HealingPrescription
11
+
12
+ # Optional duck-typed inheritance from langchain_core if installed
13
+ try:
14
+ from langchain_core.callbacks.base import BaseCallbackHandler
15
+ except ImportError:
16
+ class BaseCallbackHandler: # type: ignore
17
+ """Fallback base class when langchain is not installed."""
18
+ pass
19
+
20
+
21
+ class CapybalaCallbackHandler(BaseCallbackHandler, BaseAgentAdapter):
22
+ """
23
+ Drop-in LangChain CallbackHandler that watches tool calls for cognitive deadlocks.
24
+ Usage:
25
+ agent_executor = create_react_agent(..., callbacks=[CapybalaCallbackHandler()])
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ repetition_threshold: int = 3,
31
+ supervisor_model: str = "meta-llama/llama-3.2-1b-instruct",
32
+ use_supervisor_llm: bool = False,
33
+ ):
34
+ BaseCallbackHandler.__init__(self)
35
+ BaseAgentAdapter.__init__(
36
+ self,
37
+ repetition_threshold=repetition_threshold,
38
+ supervisor_model=supervisor_model,
39
+ use_supervisor_llm=use_supervisor_llm,
40
+ )
41
+ self.last_action_name: str = ""
42
+ self.last_action_input: str = ""
43
+ self.deadlock_triggered: bool = False
44
+ self.last_prescription: Optional[HealingPrescription] = None
45
+
46
+ def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> None:
47
+ """Called when a LangChain tool starts running."""
48
+ self.last_action_name = serialized.get("name", "tool")
49
+ self.last_action_input = str(input_str)
50
+
51
+ def on_tool_end(self, output: str, **kwargs: Any) -> None:
52
+ """Called when a LangChain tool finishes running."""
53
+ action = f"{self.last_action_name}: {self.last_action_input}"
54
+ event = self.detector.check(action, str(output))
55
+
56
+ if event.is_deadlock:
57
+ self.deadlock_triggered = True
58
+ rx = self.healer.prescribe(
59
+ deadlock_pattern=event.pattern_type or "tool_loop",
60
+ failing_action=action,
61
+ error_signature=str(output)
62
+ )
63
+ self.last_prescription = rx
64
+
65
+ def on_tool_error(self, error: BaseException, **kwargs: Any) -> None:
66
+ """Called when a LangChain tool encounters an unhandled exception."""
67
+ action = f"{self.last_action_name}: {self.last_action_input}"
68
+ event = self.detector.check(action, f"{type(error).__name__}: {str(error)}")
69
+
70
+ if event.is_deadlock:
71
+ self.deadlock_triggered = True
72
+ rx = self.healer.prescribe(
73
+ deadlock_pattern=event.pattern_type or "tool_error_loop",
74
+ failing_action=action,
75
+ error_signature=str(error)
76
+ )
77
+ self.last_prescription = rx
78
+
@@ -0,0 +1,72 @@
1
+ """
2
+ capybala.adapters.llama_stack
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ Native Meta Llama Stack Agent Middleware.
5
+ Seamlessly integrates with Llama Stack Agent sessions, intercepting runaway
6
+ tool loops and pruning context windows on Llama-3.1-70B/405B agents using
7
+ an out-of-band Llama-3.2-1B/3B supervisor.
8
+ """
9
+
10
+ from typing import List, Dict, Any, Optional, Tuple
11
+ from .base import BaseAgentAdapter
12
+ from ..healer import HealingPrescription
13
+
14
+
15
+ class LlamaStackCapybalaMiddleware(BaseAgentAdapter):
16
+ """
17
+ Middleware for Meta Llama Stack Agent runtimes.
18
+ Can be used as a turn interceptor in Llama Stack Agent loops.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ repetition_threshold: int = 3,
24
+ supervisor_model: str = "meta-llama/llama-3.2-1b-instruct",
25
+ supervisor_client: Optional[Any] = None,
26
+ use_supervisor_llm: bool = False,
27
+ ):
28
+ super().__init__(
29
+ repetition_threshold=repetition_threshold,
30
+ supervisor_model=supervisor_model,
31
+ supervisor_client=supervisor_client,
32
+ use_supervisor_llm=use_supervisor_llm,
33
+ )
34
+
35
+ def on_tool_step(
36
+ self,
37
+ tool_name: str,
38
+ tool_arguments: Dict[str, Any],
39
+ tool_output: str,
40
+ session_turns: List[Dict[str, Any]]
41
+ ) -> Tuple[bool, List[Dict[str, Any]], Optional[HealingPrescription]]:
42
+ """
43
+ Intercepts a Llama Stack tool execution step.
44
+
45
+ Parameters:
46
+ - tool_name: Name of tool called (e.g. 'execute_code', 'terminal')
47
+ - tool_arguments: Dict of arguments passed to tool
48
+ - tool_output: The environment response or stdout/stderr
49
+ - session_turns: Llama Stack message list for current agent session
50
+
51
+ Returns:
52
+ - (is_deadlocked, rescued_turns, optional_prescription)
53
+ """
54
+ # Create a canonical representation of the action
55
+ action_signature = f"{tool_name}({tool_arguments})"
56
+
57
+ return self.intercept_step(
58
+ action=action_signature,
59
+ observation=tool_output,
60
+ messages=session_turns
61
+ )
62
+
63
+ def wrap_turn_request(self, agent_client: Any, session_id: str, turn_request: Dict[str, Any]) -> Any:
64
+ """
65
+ Helper method to wrap a Llama Stack client agent.turn.create call.
66
+ """
67
+ # Standalone pass-through hook for Llama Stack client integration
68
+ return agent_client.agents.turn.create(
69
+ session_id=session_id,
70
+ **turn_request
71
+ )
72
+