cortexhub 0.1.5__py3-none-any.whl → 0.1.7__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.
@@ -94,13 +94,6 @@ class ClaudeAgentsAdapter(ToolAdapter):
94
94
  return
95
95
 
96
96
  cortex_hub = self.cortex_hub
97
- tools = self._discover_tools()
98
- if tools:
99
- cortex_hub.backend.register_tool_inventory(
100
- agent_id=cortex_hub.agent_id,
101
- framework=self.framework_name,
102
- tools=tools,
103
- )
104
97
 
105
98
  # Store original decorator
106
99
  if not hasattr(claude_agent_sdk, _ORIGINAL_TOOL_ATTR):
@@ -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
- guardrail_configs["pii"] = GuardrailConfig(
175
- action=gc.get("action", "redact"),
176
- pii_types=gc.get("pii_types"),
177
- custom_patterns=custom_patterns if custom_patterns else None,
178
- redaction_scope=gc.get("redaction_scope", "both"),
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
- guardrail_configs["secrets"] = GuardrailConfig(
191
- action=gc.get("action", "redact"),
192
- secret_types=gc.get("secret_types"),
193
- custom_patterns=custom_patterns if custom_patterns else None,
194
- redaction_scope=gc.get("redaction_scope", "both"),
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
  *,
cortexhub/client.py CHANGED
@@ -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(
cortexhub/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for CortexHub SDK."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.1.5"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortexhub
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: CortexHub Python SDK - Policy-as-Code for AI Agents
5
5
  Project-URL: Homepage, https://cortexhub.ai
6
6
  Project-URL: Documentation, https://docs.cortexhub.ai
@@ -1,21 +1,21 @@
1
1
  cortexhub/__init__.py,sha256=hnwsiUy5BT3QaPNK5yXqex6zRzZlok43S04y-dkNWSE,4376
2
2
  cortexhub/auto_protect.py,sha256=yW-iW9cdGg-fM8EtR_Z9UkMczn51U8BKh5pOBgV1VqE,3951
3
- cortexhub/client.py,sha256=LNS63p8jFD3GASOKCQISZR4au52o4NmINF3hv1sTpxg,96968
3
+ cortexhub/client.py,sha256=360lxIPd52r0k7ZuuUc68xsEZHPeibU_BoUBrkTotHE,96990
4
4
  cortexhub/config.py,sha256=kpwVMTRcSisJy8HHBL3ZBeQoMN3lE7zziRzEYaq92LI,941
5
5
  cortexhub/errors.py,sha256=hsknLHaVCqk5MkpXvahxYIUshDt2VGZfbBWRronFvVM,3697
6
6
  cortexhub/frameworks.py,sha256=WCPokPRVafLqe73MDbJasi8FyNHTM2T4wfaBg0LuWoM,2223
7
7
  cortexhub/pipeline.py,sha256=EvkrEz7dGnzc0tlv02B3Kx2KQfdX4gsTuhUxj-MwuFI,3256
8
- cortexhub/version.py,sha256=L1gsFyWfMZYvly7nYjyH0nlWRAsm65S61_B-imDPgXE,68
8
+ cortexhub/version.py,sha256=5kkypMZTwNSkQR5pPfUn4kRFz3PtN8_HpqYKHbJkghg,68
9
9
  cortexhub/adapters/__init__.py,sha256=Lb6RquGPGs4exdfSB6Qb6q6HyGczozuLWSaLCtgZdyo,130
10
10
  cortexhub/adapters/base.py,sha256=_ODoJFLQLYnowse3MHQk8bN9KjE1oQr8QDNNlvPSwSs,4094
11
- cortexhub/adapters/claude_agents.py,sha256=RzFxMCylL3yCgnTASKnpa5F60t0RD-IrvoDfpRKYPFY,23038
12
- cortexhub/adapters/crewai.py,sha256=SuyMBF9bzrqDq58ZsGZV-3uAzaAtlLD3xEeyMB2Hgig,24899
13
- cortexhub/adapters/langgraph.py,sha256=X0UutdATOowXcZYRv_ImiJGSO97MKgYcuxFKV-jTxJA,20850
14
- cortexhub/adapters/openai_agents.py,sha256=63rNZ8HItZdoxERk1BTYzzpVe8Qq_8j56jfrEICzjpU,21511
11
+ cortexhub/adapters/claude_agents.py,sha256=AfuySr-nl06U3L2nY3ie5fbA8tQNDEE5I3u47B4dp30,22761
12
+ cortexhub/adapters/crewai.py,sha256=-8s27SU-_Z1c2D-jgVa1VfrtDbEDub3g6ahBcG5wy-U,24622
13
+ cortexhub/adapters/langgraph.py,sha256=Dq3qoMQy2MT2C9KqggVUoZF9iYuoA72LBe4kV7JYGzU,20635
14
+ cortexhub/adapters/openai_agents.py,sha256=vk9oZfS59TVCUmh5HxbWtesaZJo21wpu62Wu-upEz3E,21234
15
15
  cortexhub/audit/__init__.py,sha256=tKE9CdpAIpP04oeLOza96jwZs4er5G5bRBWGibvh4Xw,545
16
16
  cortexhub/audit/events.py,sha256=w1uHbYzwBTDRm8gKAY_TQlXHjUj2nZt-iXk0NcqzRak,5965
17
17
  cortexhub/backend/__init__.py,sha256=Yt5fcaW24l6YwPCLvKbcKAXhhrWTUjwgqJsLOIzgIAo,133
18
- cortexhub/backend/client.py,sha256=dYd2aWJORysrEfJ5T_QPLwvs0xUQLrhMVT4FWUVOg6c,13680
18
+ cortexhub/backend/client.py,sha256=542TKmKoGCOG54RdFLj4ur675LOxwhACFmtCFQ4eWgw,15310
19
19
  cortexhub/context/__init__.py,sha256=BWoR2s4ogOs1YXPFBO7e8_UOZ_5AWYfMlv5PTVORN2Y,144
20
20
  cortexhub/context/enricher.py,sha256=cComyfE10EbaCAI8KLM0ED6j-wKYBc26MRnIn-dxhmU,5322
21
21
  cortexhub/guardrails/__init__.py,sha256=RH1u8w3FFLd6u7-OYgj42PqAJO9jXsl8-tcLiL24uOo,103
@@ -33,7 +33,7 @@ cortexhub/policy/models.py,sha256=81NPX36yru0AZ22Wivytv3uxlwir4VsTN4MZgq4bdiA,38
33
33
  cortexhub/policy/sync.py,sha256=7kAc3rd5WftipR8XKwvU8SwukIoY-0gcGW2fsf-ij_I,5999
34
34
  cortexhub/telemetry/__init__.py,sha256=RSY38hHnYtbRURLoWAhbYYxYMtCItVYZBNN6Bfny8uA,1049
35
35
  cortexhub/telemetry/otel.py,sha256=T2pC-K_S_KmrLvfcd3oHMbEwC5ibGZ-PXTZSY0xJgcQ,16633
36
- cortexhub-0.1.5.dist-info/METADATA,sha256=oZPJ9gFAkIQ6D7jYLElFa9gobzaz3yyqqTGgsMRb7MM,8539
37
- cortexhub-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
38
- cortexhub-0.1.5.dist-info/licenses/LICENSE,sha256=R-lPsEVN69q2o19ge2_O9Vt9cJuGM557oEYX3XdnvIk,1066
39
- cortexhub-0.1.5.dist-info/RECORD,,
36
+ cortexhub-0.1.7.dist-info/METADATA,sha256=x54ffWpQLv-bKw22CYva6pzEabJUC82xJ1sVJBy-b0w,8539
37
+ cortexhub-0.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
+ cortexhub-0.1.7.dist-info/licenses/LICENSE,sha256=R-lPsEVN69q2o19ge2_O9Vt9cJuGM557oEYX3XdnvIk,1066
39
+ cortexhub-0.1.7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.28.0
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any