langchain-chaos-middleware 0.1.4__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.
chaos_middleware.py ADDED
@@ -0,0 +1,158 @@
1
+ import os
2
+ import random
3
+ from typing import List, Optional, Any, Type, Callable
4
+ try:
5
+ from typing import TypedDict
6
+ except ImportError:
7
+ from typing_extensions import TypedDict
8
+
9
+ # Import LangChain v1 middleware types
10
+ try:
11
+ from langchain.agents.middleware import (
12
+ AgentMiddleware,
13
+ ModelRequest,
14
+ ModelResponse,
15
+ )
16
+ # ToolCallRequest might be in a different location or named differently
17
+ # We'll handle this gracefully
18
+ try:
19
+ from langchain.agents.middleware import ToolCallRequest
20
+ except ImportError:
21
+ # If ToolCallRequest doesn't exist, we'll use the request object directly
22
+ ToolCallRequest = Any
23
+ except ImportError:
24
+ # Fallback for development/testing without LangChain installed
25
+ class AgentMiddleware:
26
+ pass
27
+ ModelRequest = Any
28
+ ModelResponse = Any
29
+ ToolCallRequest = Any
30
+
31
+ class ChaosConfig(TypedDict):
32
+ """Configuration for the Chaos Monkey Middleware.
33
+
34
+ Attributes:
35
+ failure_rate: Probability of failure (0.0 to 1.0). Default is 0.1.
36
+ exception_types: List of exception classes to choose from when failing.
37
+ include_tools: List of tool names to target. If None, all tools are targeted.
38
+ exclude_tools: List of tool names to exclude from chaos.
39
+ seed: Random seed for reproducibility.
40
+ safety_key: Environment variable name that must be "true" to enable chaos. Default: "ENABLE_CHAOS".
41
+ """
42
+ failure_rate: float
43
+ exception_types: List[Type[Exception]]
44
+ include_tools: Optional[List[str]]
45
+ exclude_tools: List[str]
46
+ seed: Optional[int]
47
+ safety_key: str
48
+
49
+ class ChaosMiddleware(AgentMiddleware):
50
+ """Middleware that injects random failures into tool and model calls.
51
+
52
+ This middleware is designed to test the resilience of an agent by simulating
53
+ network errors, service outages, or other unexpected exceptions.
54
+
55
+ !!!Important!!!
56
+ The middleware will ONLY be active if the environment variable specified
57
+ by `safety_key` (default: "ENABLE_CHAOS") is set to "true".
58
+ """
59
+ def __init__(self, config: ChaosConfig):
60
+ self.config = config
61
+ self.failure_rate = config.get("failure_rate", 0.1)
62
+ self.exception_types = config.get("exception_types", [])
63
+ self.include_tools = config.get("include_tools", None)
64
+ self.exclude_tools = config.get("exclude_tools", [])
65
+ self.seed = config.get("seed", None)
66
+ self.safety_key = config.get("safety_key", "ENABLE_CHAOS")
67
+
68
+ if self.seed is not None:
69
+ random.seed(self.seed)
70
+
71
+ def wrap_tool_call(
72
+ self,
73
+ request: ToolCallRequest,
74
+ handler: Callable[[ToolCallRequest], Any]
75
+ ) -> Any:
76
+ """Intercepts tool calls and potentially raises an exception.
77
+
78
+ Args:
79
+ request: The ToolCallRequest object containing tool information.
80
+ handler: The next handler in the chain.
81
+
82
+ Returns:
83
+ The result of the handler if no exception is raised.
84
+
85
+ Raises:
86
+ Exception: A random exception from `exception_types` if chaos is triggered.
87
+ """
88
+ # Safety Check
89
+ if os.environ.get(self.safety_key, "").lower() != "true":
90
+ return handler(request)
91
+
92
+ # Extract tool name from request
93
+ # The request object should have a 'tool' attribute with the BaseTool instance
94
+ tool_name = getattr(request, 'tool', None)
95
+ if tool_name is not None:
96
+ tool_name = getattr(tool_name, 'name', str(tool_name))
97
+
98
+ # Target Check
99
+ if tool_name and tool_name in self.exclude_tools:
100
+ return handler(request)
101
+
102
+ if self.include_tools is not None and (not tool_name or tool_name not in self.include_tools):
103
+ return handler(request)
104
+
105
+ # Roll Dice
106
+ if random.random() <= self.failure_rate:
107
+ if self.exception_types:
108
+ # Instantiate the exception class
109
+ raise random.choice(self.exception_types)()
110
+ else:
111
+ raise Exception("Chaos Monkey triggered!")
112
+
113
+ return handler(request)
114
+
115
+ def wrap_model_call(
116
+ self,
117
+ request: ModelRequest,
118
+ handler: Callable[[ModelRequest], ModelResponse]
119
+ ) -> ModelResponse:
120
+ """Intercepts model calls and potentially raises an exception.
121
+
122
+ Args:
123
+ request: The ModelRequest object.
124
+ handler: The next handler in the chain.
125
+
126
+ Returns:
127
+ The ModelResponse if no exception is raised.
128
+
129
+ Raises:
130
+ Exception: A random exception from `exception_types` if chaos is triggered.
131
+ """
132
+ # Safety Check
133
+ if os.environ.get(self.safety_key, "").lower() != "true":
134
+ return handler(request)
135
+
136
+ # Roll Dice
137
+ if random.random() <= self.failure_rate:
138
+ if self.exception_types:
139
+ # Instantiate the exception class
140
+ raise random.choice(self.exception_types)()
141
+ else:
142
+ raise Exception("Chaos Monkey triggered on model call!")
143
+
144
+ return handler(request)
145
+
146
+ # Custom Exceptions for Chaos
147
+ class RateLimitError(Exception):
148
+ """Simulated Rate Limit Error"""
149
+ pass
150
+
151
+ class ServiceUnavailableError(Exception):
152
+ """Simulated Service Unavailable Error"""
153
+ pass
154
+
155
+ # Default Exception Profiles
156
+ NETWORK_ERRORS = [TimeoutError, ConnectionError]
157
+ LLM_ERRORS = [RateLimitError, ServiceUnavailableError]
158
+ CRITICAL_ERRORS = [ValueError, KeyError]
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-chaos-middleware
3
+ Version: 0.1.4
4
+ Summary: Chaos testing middleware for LangChain agents
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: langchain>=1.0.0
8
+ Requires-Dist: langgraph>=1.0.0
9
+
10
+ # LangChain Chaos Middleware ( Chaos Monkey )
11
+
12
+ A middleware for LangChain agents that intentionally injects failures (exceptions) into tool and model calls to test agent resilience.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Features](#features)
17
+ - [Installation](#installation)
18
+ - [Usage](#usage)
19
+ - [Basic Example](#basic-example)
20
+ - [Configuration](#configuration)
21
+ - [Default Exception Profiles](#default-exception-profiles)
22
+ - [Custom Exception Profiles](#custom-exception-profiles)
23
+ - [Understanding Failure Rates](#understanding-failure-rates)
24
+ - [Important Note for Production](#important-note-for-production)
25
+ - [For Developers](#for-developers)
26
+ - [Setting Up the Development Environment](#setting-up-the-development-environment)
27
+ - [Running Tests](#running-tests)
28
+ - [Test Coverage](#test-coverage)
29
+ - [Contributing](#contributing)
30
+
31
+ ## Features
32
+
33
+ - **Failure Injection**: Randomly raises exceptions based on a configurable failure rate.
34
+ - **Targeted Chaos**: Include or exclude specific tools from chaos.
35
+ - **Safety Mechanism**: Requires an environment variable (`ENABLE_CHAOS=true`) to be active, preventing accidental production issues.
36
+ - **Customizable Exceptions**: Choose which exceptions to raise (e.g., network errors, rate limits).
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install langchain-chaos-middleware
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ### Basic Example
47
+
48
+ ```python
49
+ import os
50
+ from langchain.agents import create_agent
51
+ from chaos_middleware import ChaosMiddleware, NETWORK_ERRORS
52
+
53
+ # 1. Enable Chaos (Safety Check)
54
+ os.environ["ENABLE_CHAOS"] = "true"
55
+
56
+ # 2. Configure Middleware
57
+ chaos_config = {
58
+ "failure_rate": 0.2, # 20% chance of failure
59
+ "exception_types": NETWORK_ERRORS,
60
+ "exclude_tools": ["save_memory"], # Don't break critical tools
61
+ }
62
+ chaos = ChaosMiddleware(chaos_config)
63
+
64
+ # 3. Inject into Agent
65
+ agent = create_agent(
66
+ model="gpt-4o",
67
+ tools=[...],
68
+ middleware=[chaos]
69
+ )
70
+
71
+ # 4. Run Agent
72
+ # The agent will now experience random network errors!
73
+ ```
74
+
75
+ ## Configuration
76
+
77
+ The `ChaosMiddleware` is initialized with a `ChaosConfig` dictionary:
78
+
79
+ | Key | Type | Default | Description |
80
+ | :--- | :--- | :--- | :--- |
81
+ | `failure_rate` | `float` | `0.1` | Probability of failure (0.0 to 1.0). |
82
+ | `exception_types` | `List[Exception]` | `[]` | List of exceptions to randomly choose from. |
83
+ | `include_tools` | `List[str]` | `None` | If set, only these tools will be targeted. |
84
+ | `exclude_tools` | `List[str]` | `[]` | These tools will NEVER fail. |
85
+ | `seed` | `int` | `None` | Random seed for reproducible chaos. |
86
+ | `safety_key` | `str` | `"ENABLE_CHAOS"` | Env var name required to enable the middleware. |
87
+
88
+ ## Default Exception Profiles
89
+
90
+ The library provides pre-built lists of exceptions for common scenarios:
91
+
92
+ - `NETWORK_ERRORS`: `[TimeoutError, ConnectionError]`
93
+ - `LLM_ERRORS`: `[RateLimitError, ServiceUnavailableError]`
94
+ - `CRITICAL_ERRORS`: `[ValueError, KeyError]`
95
+
96
+ ## Custom Exception Profiles
97
+
98
+ You can define your own lists of exceptions to simulate specific scenarios (e.g., database failures, custom API errors). Just create a list of exception classes and pass it to the `exception_types` configuration:
99
+
100
+ ```python
101
+ class DatabaseError(Exception):
102
+ pass
103
+
104
+ MY_DB_ERRORS = [DatabaseError]
105
+
106
+ config = {
107
+ "exception_types": MY_DB_ERRORS,
108
+ # ...
109
+ }
110
+ ```
111
+
112
+ ## Understanding Failure Rates
113
+
114
+ The `failure_rate` applies to **each individual tool call**, not to the entire agent task. If your agent needs to call multiple tools to complete a task, the overall success rate will be lower than you might expect.
115
+
116
+ **Example**: With a 20% failure rate per tool:
117
+ - **Single tool call**: 80% chance of success
118
+ - **Two tool calls**: 80% × 80% = **64% chance of success**
119
+ - **Three tool calls**: 80% × 80% × 80% = **51% chance of success**
120
+
121
+ This means that even with a "low" 20% failure rate, an agent that needs to call 3 tools has nearly a 50% chance of experiencing at least one failure during the task.
122
+
123
+ **Tip**: Start with a low failure rate (e.g., 10-20%) and observe how it affects your agent's overall success rate before increasing it.
124
+
125
+ ## Important Note for Production
126
+
127
+ To prevent accidental chaos in production, the middleware checks for an environment variable (default: `ENABLE_CHAOS`). If this variable is not set to `"true"`, the middleware acts as a pass-through and does nothing.
128
+
129
+ ## For Developers
130
+
131
+ ### Setting Up the Development Environment
132
+
133
+ 1. **Clone the repository**:
134
+ ```bash
135
+ git clone https://github.com/iroy2000/langchain-chaos-middleware.git
136
+ cd langchain-chaos-middleware
137
+ ```
138
+
139
+ 2. **Create a virtual environment**:
140
+ ```bash
141
+ python3 -m venv .venv
142
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
143
+ ```
144
+
145
+ 3. **Install dependencies**:
146
+ ```bash
147
+ # Install the package dependencies
148
+ .venv/bin/pip install langchain langgraph
149
+
150
+ # Install test dependencies
151
+ .venv/bin/pip install python-dotenv langchain-openai
152
+ ```
153
+
154
+ ### Running Tests
155
+
156
+ The project includes unit tests to verify the middleware functionality.
157
+
158
+ **Run all tests**:
159
+ ```bash
160
+ .venv/bin/python -m unittest discover tests
161
+ ```
162
+
163
+ **Run only unit tests**:
164
+ ```bash
165
+ .venv/bin/python -m unittest tests.test_unit
166
+ ```
167
+
168
+ **Run integration tests** (requires OpenAI API key):
169
+ ```bash
170
+ # Create a .env file with your OpenAI API key
171
+ echo "OPENAI_API_KEY=your-key-here" > .env
172
+
173
+ # Run the integration test
174
+ .venv/bin/python tests/test_integration.py
175
+ ```
176
+
177
+ ### Test Coverage
178
+
179
+ The test suite includes:
180
+ - **Safety mechanism tests**: Verifies chaos is disabled without the safety key
181
+ - **Failure injection tests**: Confirms failures are injected at the configured rate
182
+ - **Tool filtering tests**: Validates include/exclude tool lists work correctly
183
+ - **Model call tests**: Ensures chaos applies to model calls as well
184
+
185
+ ### Contributing
186
+
187
+ Contributions are welcome! Please ensure all tests pass before submitting a pull request:
188
+
189
+ ```bash
190
+ .venv/bin/python -m unittest discover tests
191
+ ```
@@ -0,0 +1,5 @@
1
+ chaos_middleware.py,sha256=jdpWXc7-Uzr0-icueqICsq6Ns0JSdPNTUJUvGiO3Emg,5589
2
+ langchain_chaos_middleware-0.1.4.dist-info/METADATA,sha256=VMAVfAYikBVRkV3uDImilGuLVnyhTaCQ8XuZaqRLFc8,6127
3
+ langchain_chaos_middleware-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
4
+ langchain_chaos_middleware-0.1.4.dist-info/top_level.txt,sha256=52Tu5Ki3CseAj-exVyTM2tIDqBejIWQnJBHRgnrkyRU,17
5
+ langchain_chaos_middleware-0.1.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ chaos_middleware