crewai-forge 0.1.0__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.
- crewai_forge-0.1.0/PKG-INFO +105 -0
- crewai_forge-0.1.0/README.md +84 -0
- crewai_forge-0.1.0/crewai_forge.egg-info/PKG-INFO +105 -0
- crewai_forge-0.1.0/crewai_forge.egg-info/SOURCES.txt +11 -0
- crewai_forge-0.1.0/crewai_forge.egg-info/dependency_links.txt +1 -0
- crewai_forge-0.1.0/crewai_forge.egg-info/requires.txt +2 -0
- crewai_forge-0.1.0/crewai_forge.egg-info/top_level.txt +1 -0
- crewai_forge-0.1.0/forge_crewai/__init__.py +33 -0
- crewai_forge-0.1.0/forge_crewai/guardrail.py +88 -0
- crewai_forge-0.1.0/forge_crewai/hooks.py +132 -0
- crewai_forge-0.1.0/forge_crewai/tool.py +121 -0
- crewai_forge-0.1.0/pyproject.toml +33 -0
- crewai_forge-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crewai-forge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Forge Verify tools and guardrails for CrewAI — verify every agent action before execution
|
|
5
|
+
Author-email: Veritera AI <engineering@veritera.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://veritera.ai
|
|
8
|
+
Project-URL: Documentation, https://veritera.ai/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/VeriteraAI/crewai-forge
|
|
10
|
+
Keywords: veritera,forge,crewai,guardrail,verification,ai-safety
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: veritera>=0.2.0
|
|
20
|
+
Requires-Dist: crewai>=0.80.0
|
|
21
|
+
|
|
22
|
+
# crewai-forge
|
|
23
|
+
|
|
24
|
+
Forge Verify tools and guardrails for [CrewAI](https://github.com/crewAIInc/crewAI). Verify every AI agent action against your policies **before** execution.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install crewai-forge
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import os
|
|
36
|
+
from crewai import Agent, Task, Crew
|
|
37
|
+
from forge_crewai import ForgeVerifyTool, forge_task_guardrail
|
|
38
|
+
|
|
39
|
+
os.environ["VERITERA_API_KEY"] = "vt_live_..."
|
|
40
|
+
|
|
41
|
+
# Create a Forge verification tool
|
|
42
|
+
verify = ForgeVerifyTool(policy="finance-controls")
|
|
43
|
+
|
|
44
|
+
# Give it to your agent
|
|
45
|
+
analyst = Agent(
|
|
46
|
+
role="Financial Analyst",
|
|
47
|
+
goal="Process financial transactions safely",
|
|
48
|
+
tools=[verify],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Add a task guardrail for output validation
|
|
52
|
+
task = Task(
|
|
53
|
+
description="Process the refund for order #12345",
|
|
54
|
+
agent=analyst,
|
|
55
|
+
guardrail=forge_task_guardrail(policy="finance-controls"),
|
|
56
|
+
guardrail_max_retries=3,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
crew = Crew(agents=[analyst], tasks=[task])
|
|
60
|
+
result = crew.kickoff()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Three Integration Points
|
|
64
|
+
|
|
65
|
+
### 1. Agent Tool — verify before acting
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from forge_crewai import ForgeVerifyTool
|
|
69
|
+
|
|
70
|
+
tool = ForgeVerifyTool(policy="finance-controls")
|
|
71
|
+
agent = Agent(role="Analyst", tools=[tool])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The agent calls `forge_verify(action="payment.create", params='{"amount": 500}')` before executing sensitive actions.
|
|
75
|
+
|
|
76
|
+
### 2. Task Guardrail — validate output
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from forge_crewai import forge_task_guardrail
|
|
80
|
+
|
|
81
|
+
task = Task(
|
|
82
|
+
description="Draft customer email",
|
|
83
|
+
agent=support_agent,
|
|
84
|
+
guardrail=forge_task_guardrail(policy="communication-policy"),
|
|
85
|
+
guardrail_max_retries=3,
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If the output violates your policy, CrewAI automatically retries the task.
|
|
90
|
+
|
|
91
|
+
### 3. LLM Hooks — intercept at the model level
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from forge_crewai import forge_before_llm, forge_after_llm
|
|
95
|
+
|
|
96
|
+
# Block LLM calls that violate policy
|
|
97
|
+
forge_before_llm(policy="safety-controls", max_iterations=10)
|
|
98
|
+
|
|
99
|
+
# Audit all LLM responses
|
|
100
|
+
forge_after_llm(policy="audit-trail")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT — [Veritera AI](https://veritera.ai)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# crewai-forge
|
|
2
|
+
|
|
3
|
+
Forge Verify tools and guardrails for [CrewAI](https://github.com/crewAIInc/crewAI). Verify every AI agent action against your policies **before** execution.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install crewai-forge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import os
|
|
15
|
+
from crewai import Agent, Task, Crew
|
|
16
|
+
from forge_crewai import ForgeVerifyTool, forge_task_guardrail
|
|
17
|
+
|
|
18
|
+
os.environ["VERITERA_API_KEY"] = "vt_live_..."
|
|
19
|
+
|
|
20
|
+
# Create a Forge verification tool
|
|
21
|
+
verify = ForgeVerifyTool(policy="finance-controls")
|
|
22
|
+
|
|
23
|
+
# Give it to your agent
|
|
24
|
+
analyst = Agent(
|
|
25
|
+
role="Financial Analyst",
|
|
26
|
+
goal="Process financial transactions safely",
|
|
27
|
+
tools=[verify],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Add a task guardrail for output validation
|
|
31
|
+
task = Task(
|
|
32
|
+
description="Process the refund for order #12345",
|
|
33
|
+
agent=analyst,
|
|
34
|
+
guardrail=forge_task_guardrail(policy="finance-controls"),
|
|
35
|
+
guardrail_max_retries=3,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
crew = Crew(agents=[analyst], tasks=[task])
|
|
39
|
+
result = crew.kickoff()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Three Integration Points
|
|
43
|
+
|
|
44
|
+
### 1. Agent Tool — verify before acting
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from forge_crewai import ForgeVerifyTool
|
|
48
|
+
|
|
49
|
+
tool = ForgeVerifyTool(policy="finance-controls")
|
|
50
|
+
agent = Agent(role="Analyst", tools=[tool])
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The agent calls `forge_verify(action="payment.create", params='{"amount": 500}')` before executing sensitive actions.
|
|
54
|
+
|
|
55
|
+
### 2. Task Guardrail — validate output
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from forge_crewai import forge_task_guardrail
|
|
59
|
+
|
|
60
|
+
task = Task(
|
|
61
|
+
description="Draft customer email",
|
|
62
|
+
agent=support_agent,
|
|
63
|
+
guardrail=forge_task_guardrail(policy="communication-policy"),
|
|
64
|
+
guardrail_max_retries=3,
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If the output violates your policy, CrewAI automatically retries the task.
|
|
69
|
+
|
|
70
|
+
### 3. LLM Hooks — intercept at the model level
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from forge_crewai import forge_before_llm, forge_after_llm
|
|
74
|
+
|
|
75
|
+
# Block LLM calls that violate policy
|
|
76
|
+
forge_before_llm(policy="safety-controls", max_iterations=10)
|
|
77
|
+
|
|
78
|
+
# Audit all LLM responses
|
|
79
|
+
forge_after_llm(policy="audit-trail")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT — [Veritera AI](https://veritera.ai)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crewai-forge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Forge Verify tools and guardrails for CrewAI — verify every agent action before execution
|
|
5
|
+
Author-email: Veritera AI <engineering@veritera.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://veritera.ai
|
|
8
|
+
Project-URL: Documentation, https://veritera.ai/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/VeriteraAI/crewai-forge
|
|
10
|
+
Keywords: veritera,forge,crewai,guardrail,verification,ai-safety
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: veritera>=0.2.0
|
|
20
|
+
Requires-Dist: crewai>=0.80.0
|
|
21
|
+
|
|
22
|
+
# crewai-forge
|
|
23
|
+
|
|
24
|
+
Forge Verify tools and guardrails for [CrewAI](https://github.com/crewAIInc/crewAI). Verify every AI agent action against your policies **before** execution.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install crewai-forge
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import os
|
|
36
|
+
from crewai import Agent, Task, Crew
|
|
37
|
+
from forge_crewai import ForgeVerifyTool, forge_task_guardrail
|
|
38
|
+
|
|
39
|
+
os.environ["VERITERA_API_KEY"] = "vt_live_..."
|
|
40
|
+
|
|
41
|
+
# Create a Forge verification tool
|
|
42
|
+
verify = ForgeVerifyTool(policy="finance-controls")
|
|
43
|
+
|
|
44
|
+
# Give it to your agent
|
|
45
|
+
analyst = Agent(
|
|
46
|
+
role="Financial Analyst",
|
|
47
|
+
goal="Process financial transactions safely",
|
|
48
|
+
tools=[verify],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Add a task guardrail for output validation
|
|
52
|
+
task = Task(
|
|
53
|
+
description="Process the refund for order #12345",
|
|
54
|
+
agent=analyst,
|
|
55
|
+
guardrail=forge_task_guardrail(policy="finance-controls"),
|
|
56
|
+
guardrail_max_retries=3,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
crew = Crew(agents=[analyst], tasks=[task])
|
|
60
|
+
result = crew.kickoff()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Three Integration Points
|
|
64
|
+
|
|
65
|
+
### 1. Agent Tool — verify before acting
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from forge_crewai import ForgeVerifyTool
|
|
69
|
+
|
|
70
|
+
tool = ForgeVerifyTool(policy="finance-controls")
|
|
71
|
+
agent = Agent(role="Analyst", tools=[tool])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The agent calls `forge_verify(action="payment.create", params='{"amount": 500}')` before executing sensitive actions.
|
|
75
|
+
|
|
76
|
+
### 2. Task Guardrail — validate output
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from forge_crewai import forge_task_guardrail
|
|
80
|
+
|
|
81
|
+
task = Task(
|
|
82
|
+
description="Draft customer email",
|
|
83
|
+
agent=support_agent,
|
|
84
|
+
guardrail=forge_task_guardrail(policy="communication-policy"),
|
|
85
|
+
guardrail_max_retries=3,
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If the output violates your policy, CrewAI automatically retries the task.
|
|
90
|
+
|
|
91
|
+
### 3. LLM Hooks — intercept at the model level
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from forge_crewai import forge_before_llm, forge_after_llm
|
|
95
|
+
|
|
96
|
+
# Block LLM calls that violate policy
|
|
97
|
+
forge_before_llm(policy="safety-controls", max_iterations=10)
|
|
98
|
+
|
|
99
|
+
# Audit all LLM responses
|
|
100
|
+
forge_after_llm(policy="audit-trail")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT — [Veritera AI](https://veritera.ai)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
crewai_forge.egg-info/PKG-INFO
|
|
4
|
+
crewai_forge.egg-info/SOURCES.txt
|
|
5
|
+
crewai_forge.egg-info/dependency_links.txt
|
|
6
|
+
crewai_forge.egg-info/requires.txt
|
|
7
|
+
crewai_forge.egg-info/top_level.txt
|
|
8
|
+
forge_crewai/__init__.py
|
|
9
|
+
forge_crewai/guardrail.py
|
|
10
|
+
forge_crewai/hooks.py
|
|
11
|
+
forge_crewai/tool.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
forge_crewai
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Forge Verify tools and guardrails for CrewAI.
|
|
2
|
+
|
|
3
|
+
Three integration points:
|
|
4
|
+
|
|
5
|
+
1. ForgeVerifyTool — a CrewAI tool agents can use to verify actions
|
|
6
|
+
2. forge_task_guardrail — validates task output against Forge policies
|
|
7
|
+
3. forge_before_llm / forge_after_llm — LLM call hooks for pre/post verification
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from forge_crewai import ForgeVerifyTool, forge_task_guardrail
|
|
11
|
+
|
|
12
|
+
tool = ForgeVerifyTool(policy="finance-controls")
|
|
13
|
+
agent = Agent(role="...", tools=[tool])
|
|
14
|
+
|
|
15
|
+
task = Task(
|
|
16
|
+
description="...",
|
|
17
|
+
agent=agent,
|
|
18
|
+
guardrail=forge_task_guardrail(policy="finance-controls"),
|
|
19
|
+
)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__version__ = "0.1.0"
|
|
23
|
+
|
|
24
|
+
from .tool import ForgeVerifyTool
|
|
25
|
+
from .guardrail import forge_task_guardrail
|
|
26
|
+
from .hooks import forge_before_llm, forge_after_llm
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"ForgeVerifyTool",
|
|
30
|
+
"forge_task_guardrail",
|
|
31
|
+
"forge_before_llm",
|
|
32
|
+
"forge_after_llm",
|
|
33
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Forge task guardrail for CrewAI.
|
|
2
|
+
|
|
3
|
+
Validates task output against Forge policies. If the output violates a policy,
|
|
4
|
+
the task is retried (up to guardrail_max_retries).
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
task = Task(
|
|
8
|
+
description="Process customer refund",
|
|
9
|
+
agent=finance_agent,
|
|
10
|
+
guardrail=forge_task_guardrail(policy="finance-controls"),
|
|
11
|
+
guardrail_max_retries=3,
|
|
12
|
+
)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
from typing import Any, Optional, Tuple
|
|
20
|
+
|
|
21
|
+
from veritera import Forge
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger("forge_crewai")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def forge_task_guardrail(
|
|
27
|
+
api_key: Optional[str] = None,
|
|
28
|
+
base_url: str = "https://veritera.ai",
|
|
29
|
+
agent_id: str = "crewai-agent",
|
|
30
|
+
policy: Optional[str] = None,
|
|
31
|
+
fail_closed: bool = True,
|
|
32
|
+
):
|
|
33
|
+
"""Create a CrewAI task guardrail that validates output through Forge.
|
|
34
|
+
|
|
35
|
+
Returns a function compatible with Task(guardrail=...).
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
api_key: Forge API key (or set VERITERA_API_KEY env var).
|
|
39
|
+
base_url: Forge API endpoint.
|
|
40
|
+
agent_id: Identifier for this agent in Forge audit logs.
|
|
41
|
+
policy: Policy to evaluate against.
|
|
42
|
+
fail_closed: If True, reject output when Forge API is unreachable.
|
|
43
|
+
"""
|
|
44
|
+
key = api_key or os.environ.get("VERITERA_API_KEY", "")
|
|
45
|
+
client = Forge(
|
|
46
|
+
api_key=key,
|
|
47
|
+
base_url=base_url,
|
|
48
|
+
fail_closed=fail_closed,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def _guardrail(result: Any) -> Tuple[bool, Any]:
|
|
52
|
+
"""Validate task output against Forge policies.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
(True, output) if approved.
|
|
56
|
+
(False, feedback) if denied — CrewAI will retry the task.
|
|
57
|
+
"""
|
|
58
|
+
output_text = result.raw if hasattr(result, "raw") else str(result)
|
|
59
|
+
description = result.description if hasattr(result, "description") else ""
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
verification = client.verify_sync(
|
|
63
|
+
action="task.complete",
|
|
64
|
+
agent_id=agent_id,
|
|
65
|
+
params={
|
|
66
|
+
"output": output_text[:3000],
|
|
67
|
+
"task": description[:500],
|
|
68
|
+
},
|
|
69
|
+
policy=policy,
|
|
70
|
+
)
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
logger.error("Forge task guardrail error: %s", exc)
|
|
73
|
+
if fail_closed:
|
|
74
|
+
return (False, f"Task output blocked — verification unavailable: {exc}")
|
|
75
|
+
return (True, output_text)
|
|
76
|
+
|
|
77
|
+
if verification.verified:
|
|
78
|
+
logger.debug("Forge APPROVED task output (proof=%s)", verification.proof_id)
|
|
79
|
+
return (True, output_text)
|
|
80
|
+
|
|
81
|
+
reason = verification.reason or "Policy violation"
|
|
82
|
+
logger.warning("Forge DENIED task output: %s", reason)
|
|
83
|
+
return (
|
|
84
|
+
False,
|
|
85
|
+
f"Forge policy violation: {reason}. Please revise your output to comply with the policy.",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return _guardrail
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Forge LLM call hooks for CrewAI.
|
|
2
|
+
|
|
3
|
+
Intercept LLM calls at the lowest level — before the model runs and after it responds.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from forge_crewai import forge_before_llm, forge_after_llm
|
|
7
|
+
|
|
8
|
+
# Register hooks (they apply globally to all CrewAI agents)
|
|
9
|
+
forge_before_llm(policy="safety-controls")
|
|
10
|
+
forge_after_llm() # audit all responses
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
from veritera import Forge
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("forge_crewai")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def forge_before_llm(
|
|
25
|
+
api_key: Optional[str] = None,
|
|
26
|
+
base_url: str = "https://veritera.ai",
|
|
27
|
+
agent_id: str = "crewai-agent",
|
|
28
|
+
policy: Optional[str] = None,
|
|
29
|
+
fail_closed: bool = True,
|
|
30
|
+
max_iterations: Optional[int] = None,
|
|
31
|
+
):
|
|
32
|
+
"""Register a CrewAI @before_llm_call hook that verifies through Forge.
|
|
33
|
+
|
|
34
|
+
This hook runs before every LLM call in the crew. It can block execution
|
|
35
|
+
by returning False.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
api_key: Forge API key (or set VERITERA_API_KEY env var).
|
|
39
|
+
policy: Policy to evaluate against.
|
|
40
|
+
fail_closed: If True, block LLM calls when Forge API is unreachable.
|
|
41
|
+
max_iterations: If set, block after this many iterations (safety limit).
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
from crewai.hooks import before_llm_call, LLMCallHookContext
|
|
45
|
+
except ImportError:
|
|
46
|
+
logger.warning("CrewAI hooks not available — requires crewai>=0.80")
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
key = api_key or os.environ.get("VERITERA_API_KEY", "")
|
|
50
|
+
client = Forge(api_key=key, base_url=base_url, fail_closed=fail_closed)
|
|
51
|
+
|
|
52
|
+
@before_llm_call
|
|
53
|
+
def _forge_pre_check(context: LLMCallHookContext):
|
|
54
|
+
# Safety limit on iterations
|
|
55
|
+
if max_iterations and hasattr(context, "iterations"):
|
|
56
|
+
if context.iterations > max_iterations:
|
|
57
|
+
logger.warning("Forge: iteration limit exceeded (%d)", context.iterations)
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
agent_role = context.agent.role if hasattr(context, "agent") and context.agent else "unknown"
|
|
61
|
+
task_desc = ""
|
|
62
|
+
if hasattr(context, "task") and context.task:
|
|
63
|
+
task_desc = getattr(context.task, "description", "")[:500]
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
result = client.verify_sync(
|
|
67
|
+
action=f"llm.call.{agent_role}",
|
|
68
|
+
agent_id=agent_id,
|
|
69
|
+
params={
|
|
70
|
+
"agent_role": agent_role,
|
|
71
|
+
"task": task_desc,
|
|
72
|
+
"iterations": getattr(context, "iterations", 0),
|
|
73
|
+
},
|
|
74
|
+
policy=policy,
|
|
75
|
+
)
|
|
76
|
+
except Exception as exc:
|
|
77
|
+
logger.error("Forge before_llm_call error: %s", exc)
|
|
78
|
+
return None if not fail_closed else False
|
|
79
|
+
|
|
80
|
+
if not result.verified:
|
|
81
|
+
logger.warning("Forge DENIED LLM call for %s: %s", agent_role, result.reason)
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
return None # Allow
|
|
85
|
+
|
|
86
|
+
return _forge_pre_check
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def forge_after_llm(
|
|
90
|
+
api_key: Optional[str] = None,
|
|
91
|
+
base_url: str = "https://veritera.ai",
|
|
92
|
+
agent_id: str = "crewai-agent",
|
|
93
|
+
policy: Optional[str] = None,
|
|
94
|
+
):
|
|
95
|
+
"""Register a CrewAI @after_llm_call hook that audits responses through Forge.
|
|
96
|
+
|
|
97
|
+
This hook logs every LLM response to the Forge audit trail.
|
|
98
|
+
It does not block — use forge_before_llm for blocking.
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
from crewai.hooks import after_llm_call, LLMCallHookContext
|
|
102
|
+
except ImportError:
|
|
103
|
+
logger.warning("CrewAI hooks not available — requires crewai>=0.80")
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
key = api_key or os.environ.get("VERITERA_API_KEY", "")
|
|
107
|
+
client = Forge(api_key=key, base_url=base_url, fail_closed=False)
|
|
108
|
+
|
|
109
|
+
@after_llm_call
|
|
110
|
+
def _forge_post_audit(context: LLMCallHookContext):
|
|
111
|
+
response_text = getattr(context, "response", "")
|
|
112
|
+
if response_text:
|
|
113
|
+
response_text = str(response_text)[:2000]
|
|
114
|
+
|
|
115
|
+
agent_role = context.agent.role if hasattr(context, "agent") and context.agent else "unknown"
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
client.verify_sync(
|
|
119
|
+
action=f"llm.response.{agent_role}",
|
|
120
|
+
agent_id=agent_id,
|
|
121
|
+
params={
|
|
122
|
+
"response_preview": response_text[:500],
|
|
123
|
+
"agent_role": agent_role,
|
|
124
|
+
},
|
|
125
|
+
policy=policy,
|
|
126
|
+
)
|
|
127
|
+
except Exception as exc:
|
|
128
|
+
logger.debug("Forge after_llm_call audit error (non-blocking): %s", exc)
|
|
129
|
+
|
|
130
|
+
return None # Keep original response
|
|
131
|
+
|
|
132
|
+
return _forge_post_audit
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Forge Verify tool for CrewAI agents.
|
|
2
|
+
|
|
3
|
+
A CrewAI BaseTool that verifies actions through the Forge /v1/verify API.
|
|
4
|
+
Agents use this tool to check whether an action is allowed before executing it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
from typing import Any, Optional, Type
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel, Field
|
|
15
|
+
from veritera import Forge
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("forge_crewai")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ForgeVerifyInput(BaseModel):
|
|
21
|
+
"""Input schema for the Forge Verify tool."""
|
|
22
|
+
action: str = Field(
|
|
23
|
+
...,
|
|
24
|
+
description="The action to verify (e.g. 'payment.create', 'email.send', 'db.delete')"
|
|
25
|
+
)
|
|
26
|
+
params: str = Field(
|
|
27
|
+
default="{}",
|
|
28
|
+
description="JSON string of action parameters (e.g. '{\"amount\": 100, \"to\": \"user@example.com\"}')"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ForgeVerifyTool:
|
|
33
|
+
"""CrewAI tool that verifies agent actions through Forge policies.
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
from forge_crewai import ForgeVerifyTool
|
|
37
|
+
|
|
38
|
+
tool = ForgeVerifyTool(policy="finance-controls")
|
|
39
|
+
agent = Agent(
|
|
40
|
+
role="Financial Analyst",
|
|
41
|
+
tools=[tool],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
api_key: Forge API key (or set VERITERA_API_KEY env var).
|
|
46
|
+
base_url: Forge API endpoint.
|
|
47
|
+
agent_id: Identifier for this agent in Forge audit logs.
|
|
48
|
+
policy: Default policy to evaluate against.
|
|
49
|
+
fail_closed: If True (default), deny when Forge API is unreachable.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
name: str = "forge_verify"
|
|
53
|
+
description: str = (
|
|
54
|
+
"Verify an AI agent action against security policies before executing it. "
|
|
55
|
+
"Call this BEFORE performing any sensitive action (payments, emails, deletions, API calls). "
|
|
56
|
+
"Returns APPROVED or DENIED with a reason."
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
api_key: Optional[str] = None,
|
|
62
|
+
base_url: str = "https://veritera.ai",
|
|
63
|
+
agent_id: str = "crewai-agent",
|
|
64
|
+
policy: Optional[str] = None,
|
|
65
|
+
fail_closed: bool = True,
|
|
66
|
+
timeout: float = 10.0,
|
|
67
|
+
):
|
|
68
|
+
key = api_key or os.environ.get("VERITERA_API_KEY", "")
|
|
69
|
+
if not key:
|
|
70
|
+
raise ValueError(
|
|
71
|
+
"Forge API key required. Pass api_key= or set VERITERA_API_KEY env var."
|
|
72
|
+
)
|
|
73
|
+
self._client = Forge(
|
|
74
|
+
api_key=key,
|
|
75
|
+
base_url=base_url,
|
|
76
|
+
timeout=timeout,
|
|
77
|
+
fail_closed=fail_closed,
|
|
78
|
+
)
|
|
79
|
+
self._agent_id = agent_id
|
|
80
|
+
self._policy = policy
|
|
81
|
+
|
|
82
|
+
def run(self, action: str, params: str = "{}") -> str:
|
|
83
|
+
"""Verify an action against Forge policies.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
action: The action identifier (e.g. 'payment.create').
|
|
87
|
+
params: JSON string of action parameters.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Verification result string (APPROVED or DENIED with details).
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
parsed_params = json.loads(params) if isinstance(params, str) else params
|
|
94
|
+
except (json.JSONDecodeError, TypeError):
|
|
95
|
+
parsed_params = {"raw": str(params)}
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
result = self._client.verify_sync(
|
|
99
|
+
action=action,
|
|
100
|
+
agent_id=self._agent_id,
|
|
101
|
+
params=parsed_params,
|
|
102
|
+
policy=self._policy,
|
|
103
|
+
)
|
|
104
|
+
except Exception as exc:
|
|
105
|
+
logger.error("Forge verify error: %s", exc)
|
|
106
|
+
return f"ERROR: Verification unavailable — {exc}"
|
|
107
|
+
|
|
108
|
+
if result.verified:
|
|
109
|
+
logger.debug("Forge APPROVED: %s", action)
|
|
110
|
+
return (
|
|
111
|
+
f"APPROVED: {result.verdict} | "
|
|
112
|
+
f"proof_id: {result.proof_id} | "
|
|
113
|
+
f"latency: {result.latency_ms}ms"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
logger.warning("Forge DENIED: %s — %s", action, result.reason)
|
|
117
|
+
return (
|
|
118
|
+
f"DENIED: {result.reason} | "
|
|
119
|
+
f"proof_id: {result.proof_id} | "
|
|
120
|
+
f"Do NOT proceed with this action."
|
|
121
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "crewai-forge"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Forge Verify tools and guardrails for CrewAI — verify every agent action before execution"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [{name = "Veritera AI", email = "engineering@veritera.ai"}]
|
|
9
|
+
keywords = ["veritera", "forge", "crewai", "guardrail", "verification", "ai-safety"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Topic :: Security",
|
|
16
|
+
"Topic :: Software Development :: Libraries",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"veritera>=0.2.0",
|
|
20
|
+
"crewai>=0.80.0",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://veritera.ai"
|
|
25
|
+
Documentation = "https://veritera.ai/docs"
|
|
26
|
+
Repository = "https://github.com/VeriteraAI/crewai-forge"
|
|
27
|
+
|
|
28
|
+
[build-system]
|
|
29
|
+
requires = ["setuptools>=68.0"]
|
|
30
|
+
build-backend = "setuptools.build_meta"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
include = ["forge_crewai*"]
|