cortexhub 0.1.4__tar.gz → 0.1.7__tar.gz
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.
- {cortexhub-0.1.4 → cortexhub-0.1.7}/PKG-INFO +1 -1
- {cortexhub-0.1.4 → cortexhub-0.1.7}/pyproject.toml +1 -1
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/claude_agents.py +12 -8
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/crewai.py +0 -7
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/langgraph.py +0 -6
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/openai_agents.py +0 -7
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/backend/client.py +58 -39
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/client.py +1 -1
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/version.py +1 -1
- {cortexhub-0.1.4 → cortexhub-0.1.7}/.gitignore +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/LICENSE +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/README.md +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/adapters/base.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/audit/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/audit/events.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/auto_protect.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/backend/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/config.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/context/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/context/enricher.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/errors.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/frameworks.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/guardrails/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/guardrails/injection.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/guardrails/pii.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/guardrails/secrets.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/interceptors/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/interceptors/llm.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/interceptors/mcp.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/pipeline.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/effects.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/evaluator.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/loader.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/models.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/policy/sync.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/telemetry/__init__.py +0 -0
- {cortexhub-0.1.4 → cortexhub-0.1.7}/src/cortexhub/telemetry/otel.py +0 -0
|
@@ -73,6 +73,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
73
73
|
def __init__(self, cortex_hub: Any):
|
|
74
74
|
super().__init__(cortex_hub)
|
|
75
75
|
self._hook_spans: dict[str, Any] = {}
|
|
76
|
+
self._active_run_session_id: str | None = None
|
|
76
77
|
|
|
77
78
|
def _get_framework_modules(self) -> list[str]:
|
|
78
79
|
return ["claude_agent_sdk"]
|
|
@@ -93,13 +94,6 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
93
94
|
return
|
|
94
95
|
|
|
95
96
|
cortex_hub = self.cortex_hub
|
|
96
|
-
tools = self._discover_tools()
|
|
97
|
-
if tools:
|
|
98
|
-
cortex_hub.backend.register_tool_inventory(
|
|
99
|
-
agent_id=cortex_hub.agent_id,
|
|
100
|
-
framework=self.framework_name,
|
|
101
|
-
tools=tools,
|
|
102
|
-
)
|
|
103
97
|
|
|
104
98
|
# Store original decorator
|
|
105
99
|
if not hasattr(claude_agent_sdk, _ORIGINAL_TOOL_ATTR):
|
|
@@ -206,6 +200,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
206
200
|
try:
|
|
207
201
|
import claude_agent_sdk
|
|
208
202
|
from claude_agent_sdk import ClaudeSDKClient, ResultMessage
|
|
203
|
+
adapter = self
|
|
209
204
|
|
|
210
205
|
if getattr(claude_agent_sdk, _PATCHED_RUN_ATTR, False):
|
|
211
206
|
return
|
|
@@ -218,6 +213,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
218
213
|
status = None
|
|
219
214
|
failed = False
|
|
220
215
|
cortex_hub.start_run(framework="claude_agents")
|
|
216
|
+
adapter._active_run_session_id = cortex_hub.session_id
|
|
221
217
|
try:
|
|
222
218
|
async for message in original_query(*args, **kwargs):
|
|
223
219
|
if isinstance(message, ResultMessage):
|
|
@@ -231,6 +227,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
231
227
|
status = "failed"
|
|
232
228
|
if status:
|
|
233
229
|
cortex_hub.finish_run(framework="claude_agents", status=status)
|
|
230
|
+
adapter._active_run_session_id = None
|
|
234
231
|
|
|
235
232
|
claude_agent_sdk.query = patched_query
|
|
236
233
|
|
|
@@ -251,10 +248,12 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
251
248
|
|
|
252
249
|
async def patched_client_query(self, *args, **kwargs):
|
|
253
250
|
cortex_hub.start_run(framework="claude_agents")
|
|
251
|
+
adapter._active_run_session_id = cortex_hub.session_id
|
|
254
252
|
try:
|
|
255
253
|
return await original_client_query(self, *args, **kwargs)
|
|
256
254
|
except Exception:
|
|
257
255
|
cortex_hub.finish_run(framework="claude_agents", status="failed")
|
|
256
|
+
adapter._active_run_session_id = None
|
|
258
257
|
raise
|
|
259
258
|
|
|
260
259
|
async def patched_receive_response(self, *args, **kwargs):
|
|
@@ -273,6 +272,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
273
272
|
status = "failed"
|
|
274
273
|
if status:
|
|
275
274
|
cortex_hub.finish_run(framework="claude_agents", status=status)
|
|
275
|
+
adapter._active_run_session_id = None
|
|
276
276
|
|
|
277
277
|
ClaudeSDKClient.query = patched_client_query
|
|
278
278
|
ClaudeSDKClient.receive_response = patched_receive_response
|
|
@@ -303,6 +303,10 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
303
303
|
"""
|
|
304
304
|
cortex_hub = self.cortex_hub
|
|
305
305
|
span_store = self._hook_spans
|
|
306
|
+
adapter = self
|
|
307
|
+
|
|
308
|
+
def _current_session_id() -> str:
|
|
309
|
+
return adapter._active_run_session_id or cortex_hub.session_id
|
|
306
310
|
|
|
307
311
|
def _start_tool_span(
|
|
308
312
|
*,
|
|
@@ -316,7 +320,7 @@ class ClaudeAgentsAdapter(ToolAdapter):
|
|
|
316
320
|
name="tool.invoke",
|
|
317
321
|
kind=SpanKind.INTERNAL,
|
|
318
322
|
)
|
|
319
|
-
span.set_attribute("cortexhub.session.id",
|
|
323
|
+
span.set_attribute("cortexhub.session.id", _current_session_id())
|
|
320
324
|
span.set_attribute("cortexhub.agent.id", cortex_hub.agent_id)
|
|
321
325
|
span.set_attribute("cortexhub.tool.name", tool_name)
|
|
322
326
|
span.set_attribute("cortexhub.tool.framework", "claude_agents")
|
|
@@ -70,13 +70,6 @@ class CrewAIAdapter(ToolAdapter):
|
|
|
70
70
|
from crewai.tools.structured_tool import CrewStructuredTool
|
|
71
71
|
|
|
72
72
|
cortex_hub = self.cortex_hub
|
|
73
|
-
tools = self._discover_tools()
|
|
74
|
-
if tools:
|
|
75
|
-
cortex_hub.backend.register_tool_inventory(
|
|
76
|
-
agent_id=cortex_hub.agent_id,
|
|
77
|
-
framework=self.framework_name,
|
|
78
|
-
tools=tools,
|
|
79
|
-
)
|
|
80
73
|
|
|
81
74
|
# Patch CrewStructuredTool.invoke (primary execution path)
|
|
82
75
|
if not getattr(CrewStructuredTool, _PATCHED_ATTR, False):
|
|
@@ -411,12 +411,6 @@ class LangGraphAdapter(ToolAdapter):
|
|
|
411
411
|
name = tool.get("name") or "unknown_tool"
|
|
412
412
|
self._discovered_tools[name] = tool
|
|
413
413
|
|
|
414
|
-
self.cortex_hub.backend.register_tool_inventory(
|
|
415
|
-
agent_id=self.cortex_hub.agent_id,
|
|
416
|
-
framework=self.framework_name,
|
|
417
|
-
tools=list(self._discovered_tools.values()),
|
|
418
|
-
)
|
|
419
|
-
|
|
420
414
|
def _normalize_tools(self, tools: Any) -> list[dict[str, Any]]:
|
|
421
415
|
"""Convert tool objects to inventory payloads."""
|
|
422
416
|
normalized: list[dict[str, Any]] = []
|
|
@@ -67,13 +67,6 @@ class OpenAIAgentsAdapter(ToolAdapter):
|
|
|
67
67
|
return
|
|
68
68
|
|
|
69
69
|
cortex_hub = self.cortex_hub
|
|
70
|
-
tools = self._discover_tools()
|
|
71
|
-
if tools:
|
|
72
|
-
cortex_hub.backend.register_tool_inventory(
|
|
73
|
-
agent_id=cortex_hub.agent_id,
|
|
74
|
-
framework=self.framework_name,
|
|
75
|
-
tools=tools,
|
|
76
|
-
)
|
|
77
70
|
|
|
78
71
|
# Store original function_tool decorator
|
|
79
72
|
if not hasattr(tool_module, _ORIGINAL_FUNCTION_TOOL_ATTR):
|
|
@@ -7,7 +7,6 @@ import httpx
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
|
|
10
|
-
from cortexhub.version import __version__
|
|
11
10
|
|
|
12
11
|
logger = structlog.get_logger(__name__)
|
|
13
12
|
|
|
@@ -92,7 +91,7 @@ class BackendClient:
|
|
|
92
91
|
timeout=10.0,
|
|
93
92
|
)
|
|
94
93
|
|
|
95
|
-
def validate_api_key(self) -> tuple[bool, SDKConfig | None]:
|
|
94
|
+
def validate_api_key(self, *, agent_id: str | None = None) -> tuple[bool, SDKConfig | None]:
|
|
96
95
|
"""Validate API key with backend and get SDK configuration.
|
|
97
96
|
|
|
98
97
|
Returns:
|
|
@@ -127,7 +126,46 @@ class BackendClient:
|
|
|
127
126
|
|
|
128
127
|
# Convert policy objects to Cedar string if needed
|
|
129
128
|
raw_policies = policies_data.get("policies", [])
|
|
129
|
+
if agent_id:
|
|
130
|
+
raw_policies = [
|
|
131
|
+
policy for policy in raw_policies if policy.get("agent_id") == agent_id
|
|
132
|
+
]
|
|
130
133
|
guardrail_configs: dict[str, GuardrailConfig] = {}
|
|
134
|
+
|
|
135
|
+
def _merge_guardrail_config(
|
|
136
|
+
existing: GuardrailConfig | None,
|
|
137
|
+
incoming: GuardrailConfig,
|
|
138
|
+
) -> GuardrailConfig:
|
|
139
|
+
if not existing:
|
|
140
|
+
return incoming
|
|
141
|
+
priority = {"block": 3, "redact": 2, "allow": 1}
|
|
142
|
+
action = (
|
|
143
|
+
incoming.action
|
|
144
|
+
if priority.get(incoming.action, 0) > priority.get(existing.action, 0)
|
|
145
|
+
else existing.action
|
|
146
|
+
)
|
|
147
|
+
if existing.pii_types is None or incoming.pii_types is None:
|
|
148
|
+
pii_types = None
|
|
149
|
+
else:
|
|
150
|
+
pii_types = sorted(set(existing.pii_types + incoming.pii_types))
|
|
151
|
+
if existing.secret_types is None or incoming.secret_types is None:
|
|
152
|
+
secret_types = None
|
|
153
|
+
else:
|
|
154
|
+
secret_types = sorted(set(existing.secret_types + incoming.secret_types))
|
|
155
|
+
custom_patterns = (existing.custom_patterns or []) + (incoming.custom_patterns or [])
|
|
156
|
+
if existing.redaction_scope == "both" or incoming.redaction_scope == "both":
|
|
157
|
+
redaction_scope = "both"
|
|
158
|
+
elif existing.redaction_scope != incoming.redaction_scope:
|
|
159
|
+
redaction_scope = "both"
|
|
160
|
+
else:
|
|
161
|
+
redaction_scope = existing.redaction_scope
|
|
162
|
+
return GuardrailConfig(
|
|
163
|
+
action=action,
|
|
164
|
+
pii_types=pii_types,
|
|
165
|
+
secret_types=secret_types,
|
|
166
|
+
custom_patterns=custom_patterns,
|
|
167
|
+
redaction_scope=redaction_scope,
|
|
168
|
+
)
|
|
131
169
|
|
|
132
170
|
if isinstance(raw_policies, list):
|
|
133
171
|
# Backend returns list of policy objects - extract Cedar code
|
|
@@ -171,12 +209,16 @@ class BackendClient:
|
|
|
171
209
|
description=cp.get("description"),
|
|
172
210
|
enabled=cp.get("enabled", True),
|
|
173
211
|
))
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
212
|
+
merged = _merge_guardrail_config(
|
|
213
|
+
guardrail_configs.get("pii"),
|
|
214
|
+
GuardrailConfig(
|
|
215
|
+
action=gc.get("action", "redact"),
|
|
216
|
+
pii_types=gc.get("pii_types"),
|
|
217
|
+
custom_patterns=custom_patterns if custom_patterns else None,
|
|
218
|
+
redaction_scope=gc.get("redaction_scope", "both"),
|
|
219
|
+
),
|
|
179
220
|
)
|
|
221
|
+
guardrail_configs["pii"] = merged
|
|
180
222
|
elif "secrets" in policy_key:
|
|
181
223
|
custom_patterns = []
|
|
182
224
|
raw_patterns = gc.get("custom_patterns") or []
|
|
@@ -187,12 +229,16 @@ class BackendClient:
|
|
|
187
229
|
description=cp.get("description"),
|
|
188
230
|
enabled=cp.get("enabled", True),
|
|
189
231
|
))
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
merged = _merge_guardrail_config(
|
|
233
|
+
guardrail_configs.get("secrets"),
|
|
234
|
+
GuardrailConfig(
|
|
235
|
+
action=gc.get("action", "redact"),
|
|
236
|
+
secret_types=gc.get("secret_types"),
|
|
237
|
+
custom_patterns=custom_patterns if custom_patterns else None,
|
|
238
|
+
redaction_scope=gc.get("redaction_scope", "both"),
|
|
239
|
+
),
|
|
195
240
|
)
|
|
241
|
+
guardrail_configs["secrets"] = merged
|
|
196
242
|
policies_str = "\n".join(cedar_parts)
|
|
197
243
|
else:
|
|
198
244
|
policies_str = raw_policies or ""
|
|
@@ -254,33 +300,6 @@ class BackendClient:
|
|
|
254
300
|
if self._client:
|
|
255
301
|
self._client.close()
|
|
256
302
|
|
|
257
|
-
def register_tool_inventory(
|
|
258
|
-
self,
|
|
259
|
-
*,
|
|
260
|
-
agent_id: str,
|
|
261
|
-
framework: str,
|
|
262
|
-
tools: list[dict],
|
|
263
|
-
) -> dict[str, Any]:
|
|
264
|
-
"""Register agent tool inventory on init. Overwrites previous."""
|
|
265
|
-
|
|
266
|
-
if not self._client:
|
|
267
|
-
return {"agent_id": agent_id, "tools_count": 0}
|
|
268
|
-
|
|
269
|
-
try:
|
|
270
|
-
response = self._client.post(
|
|
271
|
-
"/tool-inventory",
|
|
272
|
-
json={
|
|
273
|
-
"agent_id": agent_id,
|
|
274
|
-
"framework": framework,
|
|
275
|
-
"sdk_version": __version__,
|
|
276
|
-
"tools": tools,
|
|
277
|
-
},
|
|
278
|
-
)
|
|
279
|
-
return response.json()
|
|
280
|
-
except Exception as e:
|
|
281
|
-
logger.warning("Failed to register tool inventory", error=str(e))
|
|
282
|
-
return {"agent_id": agent_id, "tools_count": len(tools)}
|
|
283
|
-
|
|
284
303
|
def create_approval(
|
|
285
304
|
self,
|
|
286
305
|
*,
|
|
@@ -159,7 +159,7 @@ class CortexHub:
|
|
|
159
159
|
|
|
160
160
|
# Validate API key and get configuration (including policies)
|
|
161
161
|
self.backend = BackendClient(self.api_key, self.api_base_url)
|
|
162
|
-
is_valid, sdk_config = self.backend.validate_api_key()
|
|
162
|
+
is_valid, sdk_config = self.backend.validate_api_key(agent_id=self.agent_id)
|
|
163
163
|
|
|
164
164
|
if not is_valid:
|
|
165
165
|
raise ConfigurationError(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|