control-zero 0.2.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.
Files changed (44) hide show
  1. control_zero/__init__.py +31 -0
  2. control_zero/client.py +584 -0
  3. control_zero/integrations/crewai/__init__.py +53 -0
  4. control_zero/integrations/crewai/agent.py +267 -0
  5. control_zero/integrations/crewai/crew.py +381 -0
  6. control_zero/integrations/crewai/task.py +291 -0
  7. control_zero/integrations/crewai/tool.py +299 -0
  8. control_zero/integrations/langchain/__init__.py +58 -0
  9. control_zero/integrations/langchain/agent.py +311 -0
  10. control_zero/integrations/langchain/callbacks.py +441 -0
  11. control_zero/integrations/langchain/chain.py +319 -0
  12. control_zero/integrations/langchain/graph.py +441 -0
  13. control_zero/integrations/langchain/tool.py +271 -0
  14. control_zero/llm/__init__.py +77 -0
  15. control_zero/llm/anthropic/__init__.py +35 -0
  16. control_zero/llm/anthropic/client.py +136 -0
  17. control_zero/llm/anthropic/messages.py +375 -0
  18. control_zero/llm/base.py +551 -0
  19. control_zero/llm/cohere/__init__.py +32 -0
  20. control_zero/llm/cohere/client.py +402 -0
  21. control_zero/llm/gemini/__init__.py +34 -0
  22. control_zero/llm/gemini/client.py +486 -0
  23. control_zero/llm/groq/__init__.py +32 -0
  24. control_zero/llm/groq/client.py +330 -0
  25. control_zero/llm/mistral/__init__.py +32 -0
  26. control_zero/llm/mistral/client.py +319 -0
  27. control_zero/llm/ollama/__init__.py +31 -0
  28. control_zero/llm/ollama/client.py +439 -0
  29. control_zero/llm/openai/__init__.py +34 -0
  30. control_zero/llm/openai/chat.py +331 -0
  31. control_zero/llm/openai/client.py +182 -0
  32. control_zero/logging/__init__.py +5 -0
  33. control_zero/logging/async_logger.py +65 -0
  34. control_zero/mcp/__init__.py +5 -0
  35. control_zero/mcp/middleware.py +148 -0
  36. control_zero/policy/__init__.py +5 -0
  37. control_zero/policy/enforcer.py +99 -0
  38. control_zero/secrets/__init__.py +5 -0
  39. control_zero/secrets/manager.py +77 -0
  40. control_zero/types.py +51 -0
  41. control_zero-0.2.0.dist-info/METADATA +216 -0
  42. control_zero-0.2.0.dist-info/RECORD +44 -0
  43. control_zero-0.2.0.dist-info/WHEEL +4 -0
  44. control_zero-0.2.0.dist-info/licenses/LICENSE +17 -0
@@ -0,0 +1,148 @@
1
+ """MCP middleware for intercepting and wrapping MCP calls."""
2
+
3
+ from typing import Any, Callable, Optional
4
+ import time
5
+
6
+ from control_zero.types import AuditLogEntry
7
+ from control_zero.policy import PolicyDecision, PolicyDeniedError
8
+
9
+
10
+ class MCPMiddleware:
11
+ """
12
+ Middleware for wrapping MCP client calls.
13
+
14
+ This intercepts calls to MCP servers and:
15
+ 1. Checks policies before execution
16
+ 2. Injects secrets into the request
17
+ 3. Logs the call for audit
18
+
19
+ Usage:
20
+ from mcp import Client
21
+ from control_zero import ControlZeroClient, MCPMiddleware
22
+
23
+ cz = ControlZeroClient(api_key="cz_live_xxx")
24
+ await cz.initialize()
25
+
26
+ mcp_client = Client()
27
+ wrapped_client = MCPMiddleware(cz).wrap(mcp_client)
28
+
29
+ # Use wrapped client normally
30
+ result = await wrapped_client.call_tool("github", "list_issues")
31
+ """
32
+
33
+ def __init__(self, control_zero_client: Any):
34
+ """
35
+ Initialize the middleware.
36
+
37
+ Args:
38
+ control_zero_client: The ControlZeroClient instance
39
+ """
40
+ self._cz = control_zero_client
41
+
42
+ def wrap(self, mcp_client: Any) -> Any:
43
+ """
44
+ Wrap an MCP client with Control Zero middleware.
45
+
46
+ Args:
47
+ mcp_client: The MCP client to wrap
48
+
49
+ Returns:
50
+ The wrapped client
51
+ """
52
+ # Store reference to original call_tool
53
+ original_call_tool = getattr(mcp_client, "call_tool", None)
54
+
55
+ if original_call_tool is None:
56
+ raise ValueError("MCP client must have a call_tool method")
57
+
58
+ # Create wrapped version
59
+ async def wrapped_call_tool(
60
+ tool: str,
61
+ method: str,
62
+ arguments: Optional[dict[str, Any]] = None,
63
+ **kwargs: Any,
64
+ ) -> Any:
65
+ return await self._intercept_call(
66
+ original_call_tool,
67
+ tool,
68
+ method,
69
+ arguments,
70
+ **kwargs,
71
+ )
72
+
73
+ # Replace the method
74
+ mcp_client.call_tool = wrapped_call_tool
75
+
76
+ return mcp_client
77
+
78
+ async def _intercept_call(
79
+ self,
80
+ original_fn: Callable[..., Any],
81
+ tool: str,
82
+ method: str,
83
+ arguments: Optional[dict[str, Any]],
84
+ **kwargs: Any,
85
+ ) -> Any:
86
+ """Intercept and wrap an MCP call."""
87
+ start = time.perf_counter()
88
+
89
+ # Check policy
90
+ decision = self._cz._policy_cache.evaluate(tool, method)
91
+ if decision.effect == "deny":
92
+ await self._log(tool, method, "denied", 0, decision)
93
+ raise PolicyDeniedError(decision)
94
+
95
+ # Get secrets for this tool
96
+ secrets = self._cz._secrets.get_for_tool(tool)
97
+
98
+ # Inject secrets into arguments or kwargs
99
+ if secrets:
100
+ if arguments is None:
101
+ arguments = {}
102
+ arguments["_secrets"] = secrets
103
+
104
+ try:
105
+ # Call original function
106
+ result = await original_fn(tool, method, arguments, **kwargs)
107
+
108
+ latency_ms = int((time.perf_counter() - start) * 1000)
109
+ await self._log(tool, method, "success", latency_ms, decision)
110
+
111
+ return result
112
+
113
+ except PolicyDeniedError:
114
+ raise
115
+ except Exception as e:
116
+ latency_ms = int((time.perf_counter() - start) * 1000)
117
+ await self._log(
118
+ tool, method, "error", latency_ms, decision,
119
+ error_type=type(e).__name__,
120
+ error_message=str(e),
121
+ )
122
+ raise
123
+
124
+ async def _log(
125
+ self,
126
+ tool: str,
127
+ method: str,
128
+ status: str,
129
+ latency_ms: int,
130
+ decision: PolicyDecision,
131
+ error_type: Optional[str] = None,
132
+ error_message: Optional[str] = None,
133
+ ) -> None:
134
+ """Log the call."""
135
+ entry = AuditLogEntry(
136
+ tool_name=tool,
137
+ method_name=method,
138
+ latency_ms=latency_ms,
139
+ status=status,
140
+ policy_decision=decision.effect,
141
+ policy_id=decision.policy_id,
142
+ error_type=error_type,
143
+ error_message=error_message,
144
+ )
145
+
146
+ # Queue for async sending
147
+ if hasattr(self._cz, "_queue"):
148
+ await self._cz._queue.put(entry)
@@ -0,0 +1,5 @@
1
+ """Policy enforcement for Control Zero SDK."""
2
+
3
+ from control_zero.policy.enforcer import PolicyCache, PolicyDecision, PolicyDeniedError
4
+
5
+ __all__ = ["PolicyCache", "PolicyDecision", "PolicyDeniedError"]
@@ -0,0 +1,99 @@
1
+ """Local policy cache and enforcement."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+ from control_zero.types import PolicyRule
7
+
8
+
9
+ @dataclass
10
+ class PolicyDecision:
11
+ """Result of a policy evaluation."""
12
+ effect: str # "allow" or "deny"
13
+ policy_id: Optional[str] = None
14
+ reason: Optional[str] = None
15
+
16
+
17
+ class PolicyDeniedError(Exception):
18
+ """Raised when a policy denies an action."""
19
+
20
+ def __init__(self, decision: PolicyDecision):
21
+ self.decision = decision
22
+ super().__init__(
23
+ f"Policy denied: {decision.reason or 'no reason provided'}"
24
+ )
25
+
26
+
27
+ class PolicyCache:
28
+ """
29
+ Local cache of policies for fast evaluation.
30
+
31
+ Policies are fetched from Control Zero on init and cached locally.
32
+ The SDK evaluates policies before every tool call to enforce access control.
33
+ """
34
+
35
+ def __init__(self):
36
+ self._policies: list[PolicyRule] = []
37
+
38
+ def load(self, policies: list[PolicyRule]) -> None:
39
+ """Load policies into the cache."""
40
+ self._policies = policies
41
+
42
+ def evaluate(self, tool: str, method: str) -> PolicyDecision:
43
+ """
44
+ Evaluate policies for a tool call.
45
+
46
+ Args:
47
+ tool: The tool name
48
+ method: The method name
49
+
50
+ Returns:
51
+ PolicyDecision with effect "allow" or "deny"
52
+ """
53
+ action = f"{tool}:{method}"
54
+
55
+ # Check each policy in order
56
+ for policy in self._policies:
57
+ if self._matches_action(policy.actions, action):
58
+ return PolicyDecision(
59
+ effect=policy.effect,
60
+ policy_id=policy.id,
61
+ reason=f"Matched policy {policy.id}",
62
+ )
63
+
64
+ # Default: allow if no policy matches
65
+ return PolicyDecision(
66
+ effect="allow",
67
+ reason="No matching policy",
68
+ )
69
+
70
+ def _matches_action(self, policy_actions: list[str], action: str) -> bool:
71
+ """Check if an action matches any of the policy actions."""
72
+ tool, method = action.split(":", 1)
73
+
74
+ for pa in policy_actions:
75
+ # Exact match
76
+ if pa == action:
77
+ return True
78
+
79
+ # Wildcard match
80
+ if pa == "*":
81
+ return True
82
+
83
+ # Tool wildcard: "github:*"
84
+ if pa.endswith(":*"):
85
+ policy_tool = pa[:-2]
86
+ if policy_tool == tool:
87
+ return True
88
+
89
+ # Method wildcard: "*:read"
90
+ if pa.startswith("*:"):
91
+ policy_method = pa[2:]
92
+ if policy_method == method:
93
+ return True
94
+
95
+ return False
96
+
97
+ def clear(self) -> None:
98
+ """Clear the policy cache."""
99
+ self._policies.clear()
@@ -0,0 +1,5 @@
1
+ """Secrets management for Control Zero SDK."""
2
+
3
+ from control_zero.secrets.manager import SecretManager
4
+
5
+ __all__ = ["SecretManager"]
@@ -0,0 +1,77 @@
1
+ """In-memory secrets manager with secure handling."""
2
+
3
+ import base64
4
+ import os
5
+ from typing import Optional
6
+
7
+ from control_zero.types import ToolConfig
8
+
9
+
10
+ class SecretManager:
11
+ """
12
+ Manages decrypted secrets in memory.
13
+
14
+ Secrets are:
15
+ 1. Received encrypted from Control Zero
16
+ 2. Decrypted using the session key
17
+ 3. Held in memory only (never written to disk)
18
+ 4. Wiped from memory when the session ends
19
+ """
20
+
21
+ def __init__(self):
22
+ # Store secrets by tool name
23
+ self._secrets: dict[str, dict[str, str]] = {}
24
+ self._session_key: Optional[bytes] = None
25
+
26
+ def set_session_key(self, key: bytes) -> None:
27
+ """Set the session key for decryption."""
28
+ self._session_key = key
29
+
30
+ def load_tool_secrets(self, tool: ToolConfig) -> None:
31
+ """Load and decrypt secrets for a tool."""
32
+ tool_secrets: dict[str, str] = {}
33
+
34
+ for secret in tool.secrets:
35
+ # In production, decrypt with session key
36
+ # For now, treat encrypted_value as base64-encoded plaintext
37
+ try:
38
+ decrypted = base64.b64decode(secret.encrypted_value).decode("utf-8")
39
+ except Exception:
40
+ # If not base64, use as-is (for development)
41
+ decrypted = secret.encrypted_value
42
+
43
+ tool_secrets[secret.name] = decrypted
44
+
45
+ self._secrets[tool.name] = tool_secrets
46
+
47
+ def get_for_tool(self, tool_name: str) -> dict[str, str]:
48
+ """Get all secrets for a tool."""
49
+ return self._secrets.get(tool_name, {})
50
+
51
+ def get_secret(self, tool_name: str, secret_name: str) -> Optional[str]:
52
+ """Get a specific secret."""
53
+ tool_secrets = self._secrets.get(tool_name, {})
54
+ return tool_secrets.get(secret_name)
55
+
56
+ def wipe(self) -> None:
57
+ """Securely wipe all secrets from memory."""
58
+ # Overwrite with random data before clearing
59
+ for tool_name in list(self._secrets.keys()):
60
+ for secret_name in list(self._secrets[tool_name].keys()):
61
+ # Overwrite the string content
62
+ secret_len = len(self._secrets[tool_name][secret_name])
63
+ self._secrets[tool_name][secret_name] = os.urandom(secret_len).hex()
64
+
65
+ self._secrets[tool_name].clear()
66
+
67
+ self._secrets.clear()
68
+
69
+ # Clear session key
70
+ if self._session_key:
71
+ key_len = len(self._session_key)
72
+ self._session_key = os.urandom(key_len)
73
+ self._session_key = None
74
+
75
+ def __del__(self):
76
+ """Ensure secrets are wiped on garbage collection."""
77
+ self.wipe()
control_zero/types.py ADDED
@@ -0,0 +1,51 @@
1
+ """Type definitions for Control Zero SDK."""
2
+
3
+ from datetime import datetime
4
+ from typing import Any, Optional
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class SecretValue(BaseModel):
9
+ """An encrypted secret value."""
10
+ name: str
11
+ encrypted_value: str
12
+
13
+
14
+ class ToolConfig(BaseModel):
15
+ """Configuration for an MCP tool."""
16
+ name: str
17
+ methods: list[str] = Field(default_factory=list)
18
+ auth_type: str = "managed" # "managed" or "passthrough"
19
+ auth_header: Optional[str] = None
20
+ secrets: list[SecretValue] = Field(default_factory=list)
21
+
22
+
23
+ class PolicyRule(BaseModel):
24
+ """A policy rule for access control."""
25
+ id: str
26
+ effect: str # "allow" or "deny"
27
+ actions: list[str] = Field(default_factory=list)
28
+
29
+
30
+ class SessionConfig(BaseModel):
31
+ """Configuration returned from SDK init."""
32
+ project_id: str
33
+ agent_id: str
34
+ session_token: str
35
+ tools: list[ToolConfig] = Field(default_factory=list)
36
+ policies: list[PolicyRule] = Field(default_factory=list)
37
+ config: dict[str, Any] = Field(default_factory=dict)
38
+
39
+
40
+ class AuditLogEntry(BaseModel):
41
+ """An audit log entry for tool calls."""
42
+ timestamp: datetime = Field(default_factory=datetime.utcnow)
43
+ tool_name: str
44
+ method_name: str
45
+ latency_ms: int
46
+ status: str # "success", "denied", "error"
47
+ policy_decision: str = "allow"
48
+ policy_id: Optional[str] = None
49
+ error_type: Optional[str] = None
50
+ error_message: Optional[str] = None
51
+ tags: dict[str, str] = Field(default_factory=dict)
@@ -0,0 +1,216 @@
1
+ Metadata-Version: 2.4
2
+ Name: control-zero
3
+ Version: 0.2.0
4
+ Summary: Enterprise MCP governance SDK - secrets, policies, and observability
5
+ Project-URL: Homepage, https://controlzero.dev
6
+ Project-URL: Documentation, https://docs.controlzero.dev
7
+ Author-email: Control Zero <hello@controlzero.dev>
8
+ License: Proprietary
9
+ License-File: LICENSE
10
+ Keywords: governance,mcp,observability,policy,secrets
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.9
19
+ Requires-Dist: cryptography>=41.0.0
20
+ Requires-Dist: httpx>=0.25.0
21
+ Requires-Dist: pydantic>=2.0.0
22
+ Provides-Extra: all
23
+ Requires-Dist: anthropic>=0.20.0; extra == 'all'
24
+ Requires-Dist: crewai>=0.30.0; extra == 'all'
25
+ Requires-Dist: langchain-core>=0.1.0; extra == 'all'
26
+ Requires-Dist: langchain>=0.1.0; extra == 'all'
27
+ Requires-Dist: langgraph>=0.0.20; extra == 'all'
28
+ Requires-Dist: mcp>=0.1.0; extra == 'all'
29
+ Requires-Dist: openai>=1.0.0; extra == 'all'
30
+ Provides-Extra: crewai
31
+ Requires-Dist: crewai>=0.30.0; extra == 'crewai'
32
+ Provides-Extra: dev
33
+ Requires-Dist: anthropic>=0.20.0; extra == 'dev'
34
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
35
+ Requires-Dist: openai>=1.0.0; extra == 'dev'
36
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
37
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
38
+ Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
39
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
40
+ Requires-Dist: respx>=0.20.0; extra == 'dev'
41
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
42
+ Provides-Extra: langchain
43
+ Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
44
+ Requires-Dist: langchain>=0.1.0; extra == 'langchain'
45
+ Requires-Dist: langgraph>=0.0.20; extra == 'langchain'
46
+ Provides-Extra: mcp
47
+ Requires-Dist: mcp>=0.1.0; extra == 'mcp'
48
+ Description-Content-Type: text/markdown
49
+
50
+ # Control Zero Python SDK
51
+
52
+ Enterprise MCP governance - secrets, policies, and observability for AI agents.
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install control-zero
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ```python
63
+ from control_zero import ControlZeroClient
64
+
65
+ # Initialize with your API key
66
+ client = ControlZeroClient(api_key="cz_live_xxx")
67
+
68
+ # This fetches config, secrets, and policies from Control Zero
69
+ client.initialize()
70
+
71
+ # Call MCP tools - secrets are injected automatically!
72
+ result = client.call_tool("github", "list_issues", {"repo": "acme/app"})
73
+
74
+ # Close when done (flushes logs)
75
+ client.close()
76
+ ```
77
+
78
+ ## Features
79
+
80
+ ### Automatic Secret Injection
81
+
82
+ Secrets configured in the Control Zero dashboard are automatically:
83
+ 1. Fetched encrypted from the server
84
+ 2. Decrypted in memory
85
+ 3. Injected into your MCP calls
86
+ 4. Wiped from memory on session end
87
+
88
+ ```python
89
+ # No need to manage secrets in your code!
90
+ # GitHub PAT is automatically injected
91
+ result = client.call_tool("github", "create_issue", {
92
+ "repo": "acme/app",
93
+ "title": "Bug report",
94
+ })
95
+ ```
96
+
97
+ ### Policy Enforcement
98
+
99
+ Policies defined in the dashboard are enforced locally:
100
+
101
+ ```python
102
+ from control_zero import PolicyDeniedError
103
+
104
+ try:
105
+ result = client.call_tool("stripe", "create_charge", {...})
106
+ except PolicyDeniedError as e:
107
+ print(f"Denied: {e.decision.reason}")
108
+ ```
109
+
110
+ ### Audit Logging
111
+
112
+ All tool calls are automatically logged for compliance:
113
+
114
+ - Timestamp, tool, method
115
+ - Latency and status
116
+ - Policy decisions
117
+ - Errors (without sensitive data)
118
+
119
+ Logs are batched and sent asynchronously to avoid impacting performance.
120
+
121
+ ## Async Usage
122
+
123
+ ```python
124
+ from control_zero import AsyncControlZeroClient
125
+
126
+ async with AsyncControlZeroClient(api_key="cz_live_xxx") as client:
127
+ result = await client.call_tool("github", "list_issues", {"repo": "acme/app"})
128
+ ```
129
+
130
+ ## MCP Client Wrapping
131
+
132
+ Wrap an existing MCP client:
133
+
134
+ ```python
135
+ from mcp import Client
136
+ from control_zero import ControlZeroClient, MCPMiddleware
137
+
138
+ # Initialize Control Zero
139
+ cz = ControlZeroClient(api_key="cz_live_xxx")
140
+ cz.initialize()
141
+
142
+ # Wrap your MCP client
143
+ mcp = Client()
144
+ wrapped = MCPMiddleware(cz).wrap(mcp)
145
+
146
+ # Use wrapped client - all calls go through Control Zero
147
+ result = await wrapped.call_tool("github", "list_issues")
148
+ ```
149
+
150
+ ## Configuration
151
+
152
+ ```python
153
+ client = ControlZeroClient(
154
+ api_key="cz_live_xxx", # Required
155
+ agent_name="marketing-bot", # Optional, for logging
156
+ base_url="https://api.controlzero.dev", # Or self-hosted
157
+ )
158
+ ```
159
+
160
+ ## API Key Types
161
+
162
+ - `cz_live_*` - Production keys (real secrets, real logging)
163
+ - `cz_test_*` - Test keys (mock responses, test logging)
164
+
165
+ ## Security
166
+
167
+ - Secrets are held in memory only, never written to disk
168
+ - Memory is securely wiped on session end
169
+ - All communication is encrypted (TLS)
170
+ - Policies are enforced locally for low latency
171
+
172
+ ## Development
173
+
174
+ ### Running Tests
175
+
176
+ ```bash
177
+ # Install dev dependencies
178
+ pip install -e ".[dev]"
179
+
180
+ # Run all tests
181
+ python -m pytest tests/ -v
182
+
183
+ # Run with coverage
184
+ python -m pytest tests/ --cov=control_zero --cov-report=term-missing
185
+
186
+ # Run specific test files
187
+ python -m pytest tests/test_types.py -v
188
+ python -m pytest tests/test_policy.py -v
189
+ python -m pytest tests/test_secrets.py -v
190
+ python -m pytest tests/test_client.py -v
191
+ ```
192
+
193
+ ### Code Quality
194
+
195
+ ```bash
196
+ # Format and lint
197
+ ruff check --fix .
198
+ ruff format .
199
+
200
+ # Type checking
201
+ mypy control_zero/
202
+ ```
203
+
204
+ ## Examples
205
+
206
+ See the [examples/](./examples/) directory for complete usage examples:
207
+
208
+ - **slack_bot.py** - Secure Slack messaging with channel restrictions
209
+ - **database_agent.py** - PostgreSQL with read-only policies
210
+ - **analytics_agent.py** - ClickHouse queries with governance
211
+ - **github_agent.py** - GitHub operations with branch protection
212
+ - **multi_tool_agent.py** - Complete multi-tool workflow
213
+
214
+ ## License
215
+
216
+ Proprietary - Control Zero, Inc.
@@ -0,0 +1,44 @@
1
+ control_zero/__init__.py,sha256=DMNACbWO97maJHYzHxTtsv5mzVNGCyOfU5_Of4t_Tnw,902
2
+ control_zero/client.py,sha256=xC7lyEqx5WsaL7lOUwO2cHSQOsiV_HIXj8EbMgzpo7Q,20503
3
+ control_zero/types.py,sha256=osJfsVNoNSTM9h1gnYBCSDAmdC_vTrD2yTFcZGS6zVU,1505
4
+ control_zero/integrations/crewai/__init__.py,sha256=olaRH8myZpZ8-qruWIiDNs6HrLDO1C6Z2LYjJViJzsQ,1244
5
+ control_zero/integrations/crewai/agent.py,sha256=EWY3sq4aG9HHbFJREkWDLn1f-GJZuv5gaeNJHYUVCYg,7772
6
+ control_zero/integrations/crewai/crew.py,sha256=NgMksCotezh-S6mcXVJhj3JD8zIc4tVqHbEiasjv-II,11241
7
+ control_zero/integrations/crewai/task.py,sha256=T61O67VwNyl88kTomn5tcs9W1QCAq8K0WS666tRFUT0,8542
8
+ control_zero/integrations/crewai/tool.py,sha256=VgVVIrFykoDhkZ1pU7xQU-qugAE89yIxZQ57nj9BJpg,8803
9
+ control_zero/integrations/langchain/__init__.py,sha256=Hz8wOmjPdU4sTCQYM7QBQz1i-0KM5m24S-kDUi0DjFc,1555
10
+ control_zero/integrations/langchain/agent.py,sha256=hI7x8K65qyUhTbE-lxJtOh0WqI8FYWlXwydp2yU9_UM,9460
11
+ control_zero/integrations/langchain/callbacks.py,sha256=3cQvX_7KQL_34eMWpIpqBbFff71FP0ihH_Ygf4chLTQ,12645
12
+ control_zero/integrations/langchain/chain.py,sha256=5JWy08JtMTUuqIGiNlSrCt4igBFBNshnjqjVdlTWS14,9747
13
+ control_zero/integrations/langchain/graph.py,sha256=iU5dh4VCTLbF0Oqg1hjZ7cAJtC9IwygEa7z6JAjegJ4,13618
14
+ control_zero/integrations/langchain/tool.py,sha256=Y20MpZNIVWNTNMa7asYwicbSfVyPOyMXp54YSJwSiRw,7633
15
+ control_zero/llm/__init__.py,sha256=_NgSQ6K54umBjL1_i--E6989ZVOAiDc-4xs9qW2JPQc,1965
16
+ control_zero/llm/base.py,sha256=CHHdrVcE32yeybrcVoPzlcs9YEUz6H7nzG5vTblruec,19675
17
+ control_zero/llm/anthropic/__init__.py,sha256=yzqsfqmnuXMxGpXbzOQiyIV5-WR2PXD7JqhdPyxXIeo,1038
18
+ control_zero/llm/anthropic/client.py,sha256=d4yoUI2OMRSSpekxfgNnDFy8Xk4Cq_m5N04UKKlPVFI,4156
19
+ control_zero/llm/anthropic/messages.py,sha256=V_3F0MdVo1uXFkNDhmQx8FuLzND421HMyqpxozCxfEE,13956
20
+ control_zero/llm/cohere/__init__.py,sha256=rcQUnPc3tFPLsnNm3PVbvKlY4IsaEU4yOsL_t2UJMso,881
21
+ control_zero/llm/cohere/client.py,sha256=ECHMc754BOsIr_dUVf7FDk6lZZi4bJjINATNEjqMvG4,12822
22
+ control_zero/llm/gemini/__init__.py,sha256=y8FUmrFmrdwwROcQjXuXQlXJBww2Rk6VAmEx_9U7x78,887
23
+ control_zero/llm/gemini/client.py,sha256=-9ymNeZz_GzmtXEqhW9r_7NPHgvUBUrQ0z-EzT2NkhY,17337
24
+ control_zero/llm/groq/__init__.py,sha256=pHj2jUEvS4M4HYo0h6I5imw4ctVDbT44Rb8RU0Etk8Q,865
25
+ control_zero/llm/groq/client.py,sha256=G4qgU2AwfnmC6IJiCOQEH9VrVGMmMy1QsYMlMn3nNYM,11195
26
+ control_zero/llm/mistral/__init__.py,sha256=BhIqAkIQ_LU3F-rDZEXd177dyjIotkiid531ETc8bSQ,919
27
+ control_zero/llm/mistral/client.py,sha256=LwHLA6pC1QaAq8QhVsLGZPP3gKg-f9MDQtVzQwZAamA,10768
28
+ control_zero/llm/ollama/__init__.py,sha256=GLPD8tgqsSku4XtvmRlCce2aKcPLdgtuaN0AaTON5P0,797
29
+ control_zero/llm/ollama/client.py,sha256=M2cwmLvjD_MupAArjhmBFuNv799ea8UJSk2sQp51W6s,13671
30
+ control_zero/llm/openai/__init__.py,sha256=3W4htjS--GBi-fdQDOruuanbvzmVBMWmuReKCw_WZiQ,967
31
+ control_zero/llm/openai/chat.py,sha256=uBQVimVFd8Dd5uYz--uwjZ_2Hhw4hRpHInyHvAvSmrM,12576
32
+ control_zero/llm/openai/client.py,sha256=yHYirEivmAqF1NIgEYF_9fcNJUCzs_pcGVTnr4sOPdE,5274
33
+ control_zero/logging/__init__.py,sha256=GtbB9WBhHB-av7OcSrvqaXl-8KYZLKEXpVjKEJzbyDM,128
34
+ control_zero/logging/async_logger.py,sha256=A2BvsD3bEnJJ6_8UxiIKMlBY8eTzTz9H_lRKR-RSFWU,1977
35
+ control_zero/mcp/__init__.py,sha256=mUFuysBHmVe4rtRwrPGcfQJLnZggmRXOn3a2alwFck4,127
36
+ control_zero/mcp/middleware.py,sha256=6S5paoWjODOkYO-YpLMQ9ThoB5S_3Nf6ASoSN4KjWJw,4268
37
+ control_zero/policy/__init__.py,sha256=Ex0TGXRBRcO-Tv4r5IRQgpfw1vri8-SwigE2gwHXUUQ,202
38
+ control_zero/policy/enforcer.py,sha256=iedLkTtHEHIb8SY5b-Ii71R6plHLv8OYnl1wMEy6a1M,2766
39
+ control_zero/secrets/__init__.py,sha256=esYdDAuk7j7wMIbPsFq36JpzMtYNq5aYXnu3-FQUBoo,132
40
+ control_zero/secrets/manager.py,sha256=Kby3x1SBqG_5JLY4eyFpE2tiVQ-9UyuF58MfKkTTIcU,2597
41
+ control_zero-0.2.0.dist-info/METADATA,sha256=Q_o4_LwMq4-nqOWelS5SjLM-kWDDchq5Xa11g7e5E60,5793
42
+ control_zero-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
43
+ control_zero-0.2.0.dist-info/licenses/LICENSE,sha256=I_jItrMUVjobSKqIUgcU8NFUA2ttg8-ylLkqwuVZXt8,741
44
+ control_zero-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2024 Control Zero
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.