bidda-shield 0.1.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.
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bidda-shield
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bidda Compliance Intelligence SDK — LangChain, AutoGen, CrewAI integration
|
|
5
|
+
Home-page: https://bidda.com
|
|
6
|
+
Author: Bidda Intelligence
|
|
7
|
+
Author-email: api@bidda.com
|
|
8
|
+
Project-URL: Homepage, https://bidda.com
|
|
9
|
+
Project-URL: Documentation, https://bidda.com/developers
|
|
10
|
+
Project-URL: Source, https://git.bidda.com/Bidda-Ai/bidda-shield
|
|
11
|
+
Project-URL: Registry, https://bidda.com/intelligence
|
|
12
|
+
Project-URL: MCP Server, https://bidda.com/mcp
|
|
13
|
+
Keywords: compliance,GDPR,EU AI Act,LangChain,AutoGen,CrewAI,regulatory,legal,AI safety
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: httpx>=0.24.0
|
|
28
|
+
Provides-Extra: langchain
|
|
29
|
+
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
30
|
+
Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
|
|
31
|
+
Requires-Dist: pydantic>=2.0; extra == "langchain"
|
|
32
|
+
Provides-Extra: autogen
|
|
33
|
+
Requires-Dist: pyautogen>=0.2.0; extra == "autogen"
|
|
34
|
+
Provides-Extra: crewai
|
|
35
|
+
Requires-Dist: crewai>=0.28.0; extra == "crewai"
|
|
36
|
+
Requires-Dist: crewai-tools>=0.1.0; extra == "crewai"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: langchain>=0.1.0; extra == "all"
|
|
39
|
+
Requires-Dist: langchain-core>=0.1.0; extra == "all"
|
|
40
|
+
Requires-Dist: pydantic>=2.0; extra == "all"
|
|
41
|
+
Requires-Dist: pyautogen>=0.2.0; extra == "all"
|
|
42
|
+
Requires-Dist: crewai>=0.28.0; extra == "all"
|
|
43
|
+
Requires-Dist: crewai-tools>=0.1.0; extra == "all"
|
|
44
|
+
Dynamic: author
|
|
45
|
+
Dynamic: author-email
|
|
46
|
+
Dynamic: classifier
|
|
47
|
+
Dynamic: description
|
|
48
|
+
Dynamic: description-content-type
|
|
49
|
+
Dynamic: home-page
|
|
50
|
+
Dynamic: keywords
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
Dynamic: project-url
|
|
53
|
+
Dynamic: provides-extra
|
|
54
|
+
Dynamic: requires-dist
|
|
55
|
+
Dynamic: requires-python
|
|
56
|
+
Dynamic: summary
|
|
57
|
+
|
|
58
|
+
# bidda-shield
|
|
59
|
+
|
|
60
|
+
**Verified compliance intelligence for AI agents.** Stop your LangChain, AutoGen, and CrewAI agents from hallucinating legal requirements.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install bidda-shield
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## The problem
|
|
69
|
+
|
|
70
|
+
AI agents making decisions about hiring, credit scoring, data processing, or content moderation are operating under dozens of overlapping regulations — GDPR, EU AI Act, HIPAA, CCPA, Basel III. When an agent gets the legal logic wrong, it isn't just a bug. It's a regulatory liability event.
|
|
71
|
+
|
|
72
|
+
LLMs hallucinate regulations. bidda-shield doesn't.
|
|
73
|
+
|
|
74
|
+
Every compliance node in the Bidda registry traces to a specific clause of a primary legal instrument, verified against the source URL, and drift-checked weekly. No inference. No approximation.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quickstart
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from bidda_shield import BiddaShield
|
|
82
|
+
|
|
83
|
+
shield = BiddaShield()
|
|
84
|
+
|
|
85
|
+
# Find the compliance node most relevant to your agent's action
|
|
86
|
+
result = shield.check_compliance("process biometric data for access control")
|
|
87
|
+
print(result["title"]) # EU AI Act Article 5 — Prohibited AI Practices
|
|
88
|
+
print(result["bluf"]) # Plain-English summary of the legal obligation
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## LangChain
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from langchain.agents import initialize_agent, AgentType
|
|
97
|
+
from langchain_openai import ChatOpenAI
|
|
98
|
+
from bidda_shield import BiddaLangChainTool
|
|
99
|
+
|
|
100
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
101
|
+
tool = BiddaLangChainTool()
|
|
102
|
+
|
|
103
|
+
agent = initialize_agent(
|
|
104
|
+
tools=[tool],
|
|
105
|
+
llm=llm,
|
|
106
|
+
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
|
|
107
|
+
verbose=True,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
agent.run(
|
|
111
|
+
"My agent is about to make an automated credit decision. "
|
|
112
|
+
"What regulations apply and what do they require?"
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The tool returns the regulation title, domain, plain-English summary (BLUF), and a link to the full verified node — for $0.01 USDC per full unlock.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## AutoGen
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
import autogen
|
|
124
|
+
from bidda_shield import BiddaAutoGenTool
|
|
125
|
+
|
|
126
|
+
config_list = [{"model": "gpt-4o", "api_key": "YOUR_OPENAI_KEY"}]
|
|
127
|
+
|
|
128
|
+
bidda_tool = BiddaAutoGenTool()
|
|
129
|
+
|
|
130
|
+
assistant = autogen.AssistantAgent(
|
|
131
|
+
name="compliance_assistant",
|
|
132
|
+
llm_config={
|
|
133
|
+
"config_list": config_list,
|
|
134
|
+
"functions": [bidda_tool.function_schema],
|
|
135
|
+
},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
user_proxy = autogen.UserProxyAgent(
|
|
139
|
+
name="user",
|
|
140
|
+
human_input_mode="NEVER",
|
|
141
|
+
function_map={"bidda_compliance_lookup": bidda_tool.execute},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
user_proxy.initiate_chat(
|
|
145
|
+
assistant,
|
|
146
|
+
message="What does GDPR Article 22 require for automated decision-making?",
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## CrewAI
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from crewai import Agent, Task, Crew
|
|
156
|
+
from bidda_shield import BiddaCrewAITool
|
|
157
|
+
|
|
158
|
+
compliance_tool = BiddaCrewAITool()
|
|
159
|
+
|
|
160
|
+
compliance_officer = Agent(
|
|
161
|
+
role="Chief Compliance Officer",
|
|
162
|
+
goal="Ensure all AI agent actions comply with applicable regulations",
|
|
163
|
+
backstory="Expert in GDPR, EU AI Act, HIPAA, and global data protection law.",
|
|
164
|
+
tools=[compliance_tool],
|
|
165
|
+
verbose=True,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
task = Task(
|
|
169
|
+
description="Review the agent action 'train a model on employee performance data' and identify all applicable regulations.",
|
|
170
|
+
agent=compliance_officer,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
crew = Crew(agents=[compliance_officer], tasks=[task])
|
|
174
|
+
crew.kickoff()
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Direct API usage
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from bidda_shield import BiddaShield
|
|
183
|
+
|
|
184
|
+
shield = BiddaShield()
|
|
185
|
+
|
|
186
|
+
# Search by keyword
|
|
187
|
+
nodes = shield.search_nodes("automated decision making")
|
|
188
|
+
for n in nodes:
|
|
189
|
+
print(n["node_id"], "—", n["title"])
|
|
190
|
+
|
|
191
|
+
# Get a specific node (free discovery tier)
|
|
192
|
+
node = shield.get_node("gdpr-article-22-automated-decisions")
|
|
193
|
+
print(node["bluf"])
|
|
194
|
+
|
|
195
|
+
# Get full vault data (requires Skyfire JWT or USDC payment — $0.01)
|
|
196
|
+
shield_paid = BiddaShield(skyfire_token="YOUR_SKYFIRE_JWT")
|
|
197
|
+
full_node = shield_paid.get_node("gdpr-article-22-automated-decisions", vault=True)
|
|
198
|
+
print(full_node["deterministic_workflow"]) # Step-by-step legal compliance logic
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## What's in a full node
|
|
204
|
+
|
|
205
|
+
Each vault-tier node contains:
|
|
206
|
+
|
|
207
|
+
- **BLUF** — plain-English summary of the legal obligation
|
|
208
|
+
- **deterministic_workflow** — step-by-step compliance checklist derived from the primary legal text
|
|
209
|
+
- **actionable_schema** — machine-readable compliance checkpoints
|
|
210
|
+
- **primary_citations** — exact section references to the legal instrument
|
|
211
|
+
- **crosswalks** — mappings to NIST, ISO, and peer standards
|
|
212
|
+
- **dependencies** — other regulations this one depends on or triggers
|
|
213
|
+
- **verification** — source URL, jurisdiction, instrument type, integrity hash
|
|
214
|
+
|
|
215
|
+
All content traces to a real primary legal source. No secondary commentary. No paraphrasing.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Payment
|
|
220
|
+
|
|
221
|
+
- **Discovery tier** (free): node ID, title, domain, plain-English summary
|
|
222
|
+
- **Vault tier** ($0.01 USDC per node): full deterministic logic, citations, crosswalks, workflow
|
|
223
|
+
|
|
224
|
+
Pay with:
|
|
225
|
+
- **Skyfire** — pass a `skyfire-pay-id` bearer token (agent-native, no wallet required)
|
|
226
|
+
- **L402 / Base USDC** — send $0.01 to the Bidda Base wallet, pass the tx hash
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
# With Skyfire
|
|
230
|
+
shield = BiddaShield(skyfire_token=os.getenv("BIDDA_SKYFIRE_TOKEN"))
|
|
231
|
+
|
|
232
|
+
# With Base tx hash
|
|
233
|
+
shield = BiddaShield(base_tx_hash="0xYOUR_TRANSACTION_HASH")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Install options
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# Core (no framework dependencies)
|
|
242
|
+
pip install bidda-shield
|
|
243
|
+
|
|
244
|
+
# With LangChain
|
|
245
|
+
pip install "bidda-shield[langchain]"
|
|
246
|
+
|
|
247
|
+
# With AutoGen
|
|
248
|
+
pip install "bidda-shield[autogen]"
|
|
249
|
+
|
|
250
|
+
# With CrewAI
|
|
251
|
+
pip install "bidda-shield[crewai]"
|
|
252
|
+
|
|
253
|
+
# Everything
|
|
254
|
+
pip install "bidda-shield[all]"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Registry coverage
|
|
260
|
+
|
|
261
|
+
- **4,600+ verified nodes** across 31 regulatory pillars
|
|
262
|
+
- **Pillars:** AI Governance, Cybersecurity, Banking & Finance, Healthcare, Legal & IP, ESG, Workplace, Aviation & Defense, Crypto, Cloud, and 21 more
|
|
263
|
+
- **Jurisdictions:** EU, US, UK, Germany, Australia, Singapore, South Africa, and global instruments
|
|
264
|
+
- **Sources:** EU AI Act, GDPR, NIST CSF, ISO 27001, Basel III/IV, HIPAA, DORA, NIS2, FATF, and 150+ authority bodies
|
|
265
|
+
|
|
266
|
+
Full registry: [bidda.com/intelligence](https://bidda.com/intelligence)
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Links
|
|
271
|
+
|
|
272
|
+
- Registry: [bidda.com](https://bidda.com)
|
|
273
|
+
- API docs: [bidda.com/developers](https://bidda.com/developers)
|
|
274
|
+
- MCP server: `https://bidda.com/mcp` (Claude.ai, Claude Desktop, any MCP client)
|
|
275
|
+
- Source: [git.bidda.com/Bidda-Ai/bidda-shield](https://git.bidda.com/Bidda-Ai/bidda-shield)
|
|
276
|
+
- Support: [api@bidda.com](mailto:api@bidda.com)
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## License
|
|
281
|
+
|
|
282
|
+
MIT — use freely, attribution appreciated.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
bidda_shield.py,sha256=pXl7bwjQWKz9dVW7sggk4N7cET_7rTUWKwbyHmdRs7c,13421
|
|
2
|
+
bidda_shield-0.1.0.dist-info/licenses/LICENSE,sha256=UAN_Gqn6B6doggwWpBlfMZC9RcDTG28IcVpg6agcphY,1083
|
|
3
|
+
bidda_shield-0.1.0.dist-info/METADATA,sha256=AjQTLUUjuPco8vdSNbzVP4JW-xb5_D7phqR9Kcdmzlw,8809
|
|
4
|
+
bidda_shield-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
bidda_shield-0.1.0.dist-info/top_level.txt,sha256=whaDbCykzJxK1gmeq9UKFMO_MBIF0OL_9lEDuYSuJNA,13
|
|
6
|
+
bidda_shield-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bidda Intelligence PTY LTD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bidda_shield
|
bidda_shield.py
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bidda-shield: Bidda Compliance Intelligence SDK
|
|
3
|
+
|
|
4
|
+
Integrates with LangChain, AutoGen, and CrewAI to give AI agents
|
|
5
|
+
real-time access to verified compliance intelligence from bidda.com.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from bidda_shield import BiddaShield, BiddaLangChainTool
|
|
9
|
+
|
|
10
|
+
# Basic usage
|
|
11
|
+
shield = BiddaShield()
|
|
12
|
+
node = shield.get_node("gdpr-article-5-data-principles")
|
|
13
|
+
print(node["bluf"])
|
|
14
|
+
|
|
15
|
+
# LangChain Tool
|
|
16
|
+
from langchain.agents import initialize_agent, AgentType
|
|
17
|
+
from langchain_openai import ChatOpenAI
|
|
18
|
+
tool = BiddaLangChainTool()
|
|
19
|
+
agent = initialize_agent([tool], ChatOpenAI(), agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION)
|
|
20
|
+
|
|
21
|
+
# AutoGen Tool
|
|
22
|
+
from autogen import AssistantAgent, UserProxyAgent
|
|
23
|
+
tool = BiddaAutoGenTool()
|
|
24
|
+
|
|
25
|
+
# CrewAI Tool
|
|
26
|
+
from crewai import Agent
|
|
27
|
+
tool = BiddaCrewAITool()
|
|
28
|
+
compliance_agent = Agent(role="Compliance Officer", tools=[tool])
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import os
|
|
34
|
+
import json
|
|
35
|
+
import time
|
|
36
|
+
import hashlib
|
|
37
|
+
import logging
|
|
38
|
+
from typing import Optional, Any
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
import httpx
|
|
42
|
+
_HAS_HTTPX = True
|
|
43
|
+
except ImportError:
|
|
44
|
+
import urllib.request
|
|
45
|
+
_HAS_HTTPX = False
|
|
46
|
+
|
|
47
|
+
logger = logging.getLogger("bidda_shield")
|
|
48
|
+
|
|
49
|
+
BIDDA_API_BASE = "https://bidda.com/api/v1"
|
|
50
|
+
DISCOVERY_SUFFIX = "/nodes"
|
|
51
|
+
VAULT_SUFFIX = "/vault/nodes"
|
|
52
|
+
DEFAULT_TIMEOUT = 10
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class BiddaError(Exception):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class PaymentRequired(BiddaError):
|
|
60
|
+
"""Raised when a vault node requires payment (x402 / L402)."""
|
|
61
|
+
def __init__(self, node_id: str, cost_usd: str):
|
|
62
|
+
self.node_id = node_id
|
|
63
|
+
self.cost_usd = cost_usd
|
|
64
|
+
super().__init__(
|
|
65
|
+
f"Node '{node_id}' requires payment: ${cost_usd} USDC. "
|
|
66
|
+
"Pass a Skyfire JWT via skyfire_token= or a Base tx hash via base_tx_hash=."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class BiddaShield:
|
|
71
|
+
"""
|
|
72
|
+
Core Bidda client.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
skyfire_token : str, optional
|
|
77
|
+
Skyfire pay+jwt bearer token for autonomous agent payments.
|
|
78
|
+
Set BIDDA_SKYFIRE_TOKEN env var to avoid passing it explicitly.
|
|
79
|
+
base_tx_hash : str, optional
|
|
80
|
+
Base USDC transaction hash (0x...) for L402 settlement.
|
|
81
|
+
timeout : int
|
|
82
|
+
HTTP timeout in seconds.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
skyfire_token: Optional[str] = None,
|
|
88
|
+
base_tx_hash: Optional[str] = None,
|
|
89
|
+
timeout: int = DEFAULT_TIMEOUT,
|
|
90
|
+
):
|
|
91
|
+
self.skyfire_token = skyfire_token or os.getenv("BIDDA_SKYFIRE_TOKEN")
|
|
92
|
+
self.base_tx_hash = base_tx_hash
|
|
93
|
+
self.timeout = timeout
|
|
94
|
+
|
|
95
|
+
def _headers(self) -> dict[str, str]:
|
|
96
|
+
h: dict[str, str] = {"Accept": "application/json"}
|
|
97
|
+
if self.skyfire_token:
|
|
98
|
+
h["skyfire-pay-id"] = self.skyfire_token
|
|
99
|
+
if self.base_tx_hash:
|
|
100
|
+
h["x-base-tx-hash"] = self.base_tx_hash
|
|
101
|
+
return h
|
|
102
|
+
|
|
103
|
+
def _get(self, url: str) -> dict:
|
|
104
|
+
if _HAS_HTTPX:
|
|
105
|
+
resp = httpx.get(url, headers=self._headers(), timeout=self.timeout)
|
|
106
|
+
if resp.status_code == 402:
|
|
107
|
+
raise PaymentRequired("unknown", "0.01")
|
|
108
|
+
resp.raise_for_status()
|
|
109
|
+
return resp.json()
|
|
110
|
+
else:
|
|
111
|
+
req = urllib.request.Request(url, headers=self._headers())
|
|
112
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as r:
|
|
113
|
+
return json.loads(r.read())
|
|
114
|
+
|
|
115
|
+
# ── Public API ─────────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
def get_node(self, node_id: str, vault: bool = False) -> dict:
|
|
118
|
+
"""
|
|
119
|
+
Fetch a compliance node by ID.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
node_id : str
|
|
124
|
+
The node identifier, e.g. 'gdpr-article-5-data-principles'.
|
|
125
|
+
vault : bool
|
|
126
|
+
If True, fetch the full 13-key vault payload (requires payment token).
|
|
127
|
+
If False (default), fetch the free 6-field discovery record.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
dict
|
|
132
|
+
Node data. Vault nodes include deterministic_workflow,
|
|
133
|
+
actionable_schema, primary_citations, and all crosswalks.
|
|
134
|
+
"""
|
|
135
|
+
if vault:
|
|
136
|
+
url = f"{BIDDA_API_BASE}{VAULT_SUFFIX}/{node_id}.json"
|
|
137
|
+
else:
|
|
138
|
+
url = f"{BIDDA_API_BASE}{DISCOVERY_SUFFIX}/{node_id}.json"
|
|
139
|
+
return self._get(url)
|
|
140
|
+
|
|
141
|
+
def search_nodes(self, query: str, pillar: Optional[str] = None) -> list[dict]:
|
|
142
|
+
"""
|
|
143
|
+
Search the discovery index for nodes matching a query string.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
query : str
|
|
148
|
+
Search term (regulation name, keyword, or topic).
|
|
149
|
+
pillar : str, optional
|
|
150
|
+
Filter by pillar slug, e.g. 'cybersecurity', 'ai-governance'.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
list[dict]
|
|
155
|
+
Matching discovery-tier node records (6 fields each).
|
|
156
|
+
"""
|
|
157
|
+
index = self._get(f"{BIDDA_API_BASE}{DISCOVERY_SUFFIX}/index.json")
|
|
158
|
+
q = query.lower()
|
|
159
|
+
results = [
|
|
160
|
+
n for n in index
|
|
161
|
+
if q in n.get("title", "").lower()
|
|
162
|
+
or q in n.get("bluf", "").lower()
|
|
163
|
+
or q in n.get("domain", "").lower()
|
|
164
|
+
]
|
|
165
|
+
if pillar:
|
|
166
|
+
results = [n for n in results if pillar.lower() in n.get("domain", "").lower()]
|
|
167
|
+
return results
|
|
168
|
+
|
|
169
|
+
def list_pillars(self) -> list[str]:
|
|
170
|
+
"""Return the list of active sovereign pillars."""
|
|
171
|
+
index = self._get(f"{BIDDA_API_BASE}{DISCOVERY_SUFFIX}/index.json")
|
|
172
|
+
return sorted({n.get("domain", "") for n in index if n.get("domain")})
|
|
173
|
+
|
|
174
|
+
def check_compliance(
|
|
175
|
+
self,
|
|
176
|
+
agent_action: str,
|
|
177
|
+
regulation: Optional[str] = None,
|
|
178
|
+
vault: bool = False,
|
|
179
|
+
) -> dict:
|
|
180
|
+
"""
|
|
181
|
+
High-level method: find and return the most relevant compliance node
|
|
182
|
+
for a described agent action.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
agent_action : str
|
|
187
|
+
What the agent is about to do, e.g. "process biometric data for access control".
|
|
188
|
+
regulation : str, optional
|
|
189
|
+
Narrow to a specific regulation, e.g. "GDPR".
|
|
190
|
+
vault : bool
|
|
191
|
+
Whether to return vault-tier data (requires payment token).
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
dict
|
|
196
|
+
The most relevant node's data, or an empty dict if nothing matches.
|
|
197
|
+
"""
|
|
198
|
+
query = f"{agent_action} {regulation or ''}".strip()
|
|
199
|
+
results = self.search_nodes(query)
|
|
200
|
+
if not results:
|
|
201
|
+
return {}
|
|
202
|
+
best = results[0]
|
|
203
|
+
if vault:
|
|
204
|
+
return self.get_node(best["node_id"], vault=True)
|
|
205
|
+
return best
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# ── LangChain Tool ─────────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
from langchain.tools import BaseTool
|
|
212
|
+
from pydantic import BaseModel, Field
|
|
213
|
+
|
|
214
|
+
class _BiddaInput(BaseModel):
|
|
215
|
+
query: str = Field(description="Regulation name, keyword, or compliance topic to look up.")
|
|
216
|
+
|
|
217
|
+
class BiddaLangChainTool(BaseTool):
|
|
218
|
+
"""
|
|
219
|
+
LangChain Tool: Bidda Compliance Intelligence
|
|
220
|
+
|
|
221
|
+
Gives a LangChain agent access to verified regulatory compliance nodes
|
|
222
|
+
from bidda.com. Returns source-cited, drift-free legal logic.
|
|
223
|
+
|
|
224
|
+
Example:
|
|
225
|
+
from bidda_shield import BiddaLangChainTool
|
|
226
|
+
tool = BiddaLangChainTool(skyfire_token="your-jwt")
|
|
227
|
+
"""
|
|
228
|
+
name: str = "bidda_compliance"
|
|
229
|
+
description: str = (
|
|
230
|
+
"Look up verified compliance intelligence for any regulation, law, or standard. "
|
|
231
|
+
"Use this tool when you need to know what a regulation requires, "
|
|
232
|
+
"what the legal obligations are, or which compliance framework applies "
|
|
233
|
+
"to a specific AI action, data processing activity, or business operation. "
|
|
234
|
+
"Returns source-cited, drift-free regulatory logic from primary legal instruments. "
|
|
235
|
+
"Input: a regulation name, keyword, or compliance topic."
|
|
236
|
+
)
|
|
237
|
+
args_schema: type[BaseModel] = _BiddaInput
|
|
238
|
+
|
|
239
|
+
skyfire_token: Optional[str] = None
|
|
240
|
+
base_tx_hash: Optional[str] = None
|
|
241
|
+
|
|
242
|
+
def _run(self, query: str) -> str:
|
|
243
|
+
client = BiddaShield(skyfire_token=self.skyfire_token, base_tx_hash=self.base_tx_hash)
|
|
244
|
+
results = client.search_nodes(query)
|
|
245
|
+
if not results:
|
|
246
|
+
return f"No compliance nodes found for '{query}'. Try a broader search term."
|
|
247
|
+
top = results[0]
|
|
248
|
+
lines = [
|
|
249
|
+
f"Regulation: {top.get('title', 'Unknown')}",
|
|
250
|
+
f"Domain: {top.get('domain', 'Unknown')}",
|
|
251
|
+
f"Summary: {top.get('bluf', 'No summary available.')}",
|
|
252
|
+
f"Node ID: {top.get('node_id', '')}",
|
|
253
|
+
f"Full details (paid): https://bidda.com/intelligence/{top.get('node_id', '')}",
|
|
254
|
+
]
|
|
255
|
+
if len(results) > 1:
|
|
256
|
+
lines.append(f"Related nodes: {', '.join(r['node_id'] for r in results[1:4])}")
|
|
257
|
+
return "\n".join(lines)
|
|
258
|
+
|
|
259
|
+
async def _arun(self, query: str) -> str:
|
|
260
|
+
return self._run(query)
|
|
261
|
+
|
|
262
|
+
except ImportError:
|
|
263
|
+
class BiddaLangChainTool: # type: ignore
|
|
264
|
+
"""LangChain not installed. Install with: pip install langchain"""
|
|
265
|
+
def __init__(self, **_):
|
|
266
|
+
raise ImportError("LangChain not installed. Run: pip install langchain langchain-core")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# ── AutoGen Tool ───────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
class BiddaAutoGenTool:
|
|
272
|
+
"""
|
|
273
|
+
AutoGen-compatible Bidda compliance tool.
|
|
274
|
+
|
|
275
|
+
Registers a function that AutoGen agents can call to look up
|
|
276
|
+
compliance intelligence.
|
|
277
|
+
|
|
278
|
+
Example:
|
|
279
|
+
import autogen
|
|
280
|
+
from bidda_shield import BiddaAutoGenTool
|
|
281
|
+
|
|
282
|
+
tool = BiddaAutoGenTool()
|
|
283
|
+
assistant = autogen.AssistantAgent(
|
|
284
|
+
name="compliance_assistant",
|
|
285
|
+
llm_config={"functions": [tool.function_schema]},
|
|
286
|
+
)
|
|
287
|
+
tool.register(assistant)
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
def __init__(self, skyfire_token: Optional[str] = None):
|
|
291
|
+
self._client = BiddaShield(skyfire_token=skyfire_token)
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def function_schema(self) -> dict:
|
|
295
|
+
return {
|
|
296
|
+
"name": "bidda_compliance_lookup",
|
|
297
|
+
"description": (
|
|
298
|
+
"Look up verified compliance intelligence for any regulation, law, standard, "
|
|
299
|
+
"or compliance topic. Returns source-cited legal obligations from primary instruments."
|
|
300
|
+
),
|
|
301
|
+
"parameters": {
|
|
302
|
+
"type": "object",
|
|
303
|
+
"properties": {
|
|
304
|
+
"query": {
|
|
305
|
+
"type": "string",
|
|
306
|
+
"description": "Regulation name, keyword, or compliance topic.",
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
"required": ["query"],
|
|
310
|
+
},
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
def execute(self, query: str) -> str:
|
|
314
|
+
results = self._client.search_nodes(query)
|
|
315
|
+
if not results:
|
|
316
|
+
return json.dumps({"error": f"No nodes found for: {query}"})
|
|
317
|
+
top = results[0]
|
|
318
|
+
return json.dumps({
|
|
319
|
+
"title": top.get("title"),
|
|
320
|
+
"domain": top.get("domain"),
|
|
321
|
+
"bluf": top.get("bluf"),
|
|
322
|
+
"node_id": top.get("node_id"),
|
|
323
|
+
"url": f"https://bidda.com/intelligence/{top.get('node_id')}",
|
|
324
|
+
"related": [r["node_id"] for r in results[1:4]],
|
|
325
|
+
}, indent=2)
|
|
326
|
+
|
|
327
|
+
def register(self, agent: Any) -> None:
|
|
328
|
+
"""Register this tool with an AutoGen agent."""
|
|
329
|
+
try:
|
|
330
|
+
agent.register_function(
|
|
331
|
+
function_map={"bidda_compliance_lookup": lambda q: self.execute(q)}
|
|
332
|
+
)
|
|
333
|
+
except AttributeError:
|
|
334
|
+
raise RuntimeError("Agent does not support register_function. Check your AutoGen version.")
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
# ── CrewAI Tool ────────────────────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
from crewai_tools import BaseTool as CrewBaseTool # type: ignore
|
|
341
|
+
|
|
342
|
+
class BiddaCrewAITool(CrewBaseTool):
|
|
343
|
+
name: str = "Bidda Compliance Lookup"
|
|
344
|
+
description: str = (
|
|
345
|
+
"Look up verified compliance intelligence for any regulation, law, or standard. "
|
|
346
|
+
"Returns source-cited legal obligations from primary instruments. Zero hallucination."
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
skyfire_token: Optional[str] = None
|
|
350
|
+
|
|
351
|
+
def _run(self, query: str) -> str:
|
|
352
|
+
client = BiddaShield(skyfire_token=self.skyfire_token)
|
|
353
|
+
results = client.search_nodes(query)
|
|
354
|
+
if not results:
|
|
355
|
+
return f"No nodes found for: {query}"
|
|
356
|
+
top = results[0]
|
|
357
|
+
return (
|
|
358
|
+
f"Regulation: {top.get('title')}\n"
|
|
359
|
+
f"Domain: {top.get('domain')}\n"
|
|
360
|
+
f"Summary: {top.get('bluf')}\n"
|
|
361
|
+
f"Full node: https://bidda.com/intelligence/{top.get('node_id')}\n"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
except ImportError:
|
|
365
|
+
class BiddaCrewAITool: # type: ignore
|
|
366
|
+
"""crewai-tools not installed. Install with: pip install crewai-tools"""
|
|
367
|
+
def __init__(self, **_):
|
|
368
|
+
raise ImportError("crewai-tools not installed. Run: pip install crewai crewai-tools")
|