agentstamp 1.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.
- agentstamp-1.1.0/PKG-INFO +135 -0
- agentstamp-1.1.0/README.md +104 -0
- agentstamp-1.1.0/agentstamp.egg-info/PKG-INFO +135 -0
- agentstamp-1.1.0/agentstamp.egg-info/SOURCES.txt +9 -0
- agentstamp-1.1.0/agentstamp.egg-info/dependency_links.txt +1 -0
- agentstamp-1.1.0/agentstamp.egg-info/requires.txt +1 -0
- agentstamp-1.1.0/agentstamp.egg-info/top_level.txt +1 -0
- agentstamp-1.1.0/agentstamp_crewai.py +374 -0
- agentstamp-1.1.0/pyproject.toml +38 -0
- agentstamp-1.1.0/setup.cfg +4 -0
- agentstamp-1.1.0/setup.py +23 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentstamp
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Identity lifecycle SDK for Python AI agents — trust stamps, registry, heartbeats, auto-renewal
|
|
5
|
+
Home-page: https://agentstamp.org
|
|
6
|
+
Author: Vinay Bhosle
|
|
7
|
+
Author-email: Vinay Bhosle <vinay@agentstamp.org>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://agentstamp.org
|
|
10
|
+
Project-URL: Repository, https://github.com/AgentstampHQ/agentstamp-python
|
|
11
|
+
Project-URL: Documentation, https://agentstamp.org
|
|
12
|
+
Project-URL: npm SDK, https://www.npmjs.com/package/agentstamp-verify
|
|
13
|
+
Keywords: agentstamp,ai-agents,crewai,autogen,langgraph,identity,trust,verification,x402,reputation
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
24
|
+
Classifier: Topic :: Security
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Requires-Dist: requests>=2.20.0
|
|
28
|
+
Dynamic: author
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# agentstamp
|
|
33
|
+
|
|
34
|
+
Identity lifecycle SDK for Python AI agents. Works with CrewAI, AutoGen, LangGraph, and any Python agent framework.
|
|
35
|
+
|
|
36
|
+
Register your agent, mint trust stamps, send heartbeats, and auto-renew — in 3 lines.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install agentstamp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
48
|
+
|
|
49
|
+
lifecycle = AgentStampLifecycle(
|
|
50
|
+
wallet_address="0xYourWalletAddress",
|
|
51
|
+
name="MyAgent",
|
|
52
|
+
description="What your agent does",
|
|
53
|
+
category="research",
|
|
54
|
+
)
|
|
55
|
+
lifecycle.start() # stamps + registers + heartbeats + auto-renew
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
That's it. Your agent now has:
|
|
59
|
+
- A cryptographic identity stamp (Ed25519)
|
|
60
|
+
- A public registry listing
|
|
61
|
+
- Heartbeat-based uptime reputation
|
|
62
|
+
- Auto-renewal before expiry
|
|
63
|
+
|
|
64
|
+
## Verify Other Agents
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
trust = lifecycle.check_trust("0xOtherAgentWallet")
|
|
68
|
+
if trust.get("trusted"):
|
|
69
|
+
print(f"Verified: {trust['agent']['name']} (score: {trust['reputation']['score']})")
|
|
70
|
+
else:
|
|
71
|
+
print("Unverified agent — proceed with caution")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Gate Functions Behind Verification
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from agentstamp_crewai import stamp_verified
|
|
78
|
+
|
|
79
|
+
@stamp_verified(lifecycle)
|
|
80
|
+
def sensitive_operation(data: str) -> str:
|
|
81
|
+
"""Only runs if the agent is AgentStamp verified."""
|
|
82
|
+
return process(data)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## CrewAI Integration
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from crewai import Agent, Task, Crew
|
|
89
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
90
|
+
|
|
91
|
+
# Start lifecycle
|
|
92
|
+
lifecycle = AgentStampLifecycle(
|
|
93
|
+
wallet_address="0x...",
|
|
94
|
+
name="ResearchBot",
|
|
95
|
+
description="Finds and summarizes papers",
|
|
96
|
+
category="research",
|
|
97
|
+
)
|
|
98
|
+
lifecycle.start()
|
|
99
|
+
|
|
100
|
+
# Create CrewAI agent as normal
|
|
101
|
+
agent = Agent(
|
|
102
|
+
role="Researcher",
|
|
103
|
+
goal="Find relevant papers",
|
|
104
|
+
backstory="Expert research assistant",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Check trust before collaborating with other agents
|
|
108
|
+
trust = lifecycle.check_trust("0xCollaboratorWallet")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Configuration
|
|
112
|
+
|
|
113
|
+
| Parameter | Default | Description |
|
|
114
|
+
|-----------|---------|-------------|
|
|
115
|
+
| `wallet_address` | required | Your agent's wallet address (EVM or Solana) |
|
|
116
|
+
| `name` | required | Agent display name |
|
|
117
|
+
| `description` | required | What your agent does |
|
|
118
|
+
| `category` | `"other"` | `research`, `trading`, `social`, `infrastructure`, etc. |
|
|
119
|
+
| `heartbeat_interval` | `300` | Seconds between heartbeats |
|
|
120
|
+
| `renew_before_days` | `2` | Days before expiry to auto-renew |
|
|
121
|
+
| `verbose` | `True` | Print lifecycle logs |
|
|
122
|
+
|
|
123
|
+
## Badge
|
|
124
|
+
|
|
125
|
+
Add a trust badge to your README:
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+

|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Links
|
|
132
|
+
|
|
133
|
+
- [AgentStamp](https://agentstamp.org) — Platform
|
|
134
|
+
- [npm SDK](https://www.npmjs.com/package/agentstamp-verify) — TypeScript/Node.js SDK
|
|
135
|
+
- [API Docs](https://agentstamp.org/api/v1/trust/check/0x...) — Trust check endpoint
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# agentstamp
|
|
2
|
+
|
|
3
|
+
Identity lifecycle SDK for Python AI agents. Works with CrewAI, AutoGen, LangGraph, and any Python agent framework.
|
|
4
|
+
|
|
5
|
+
Register your agent, mint trust stamps, send heartbeats, and auto-renew — in 3 lines.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install agentstamp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
17
|
+
|
|
18
|
+
lifecycle = AgentStampLifecycle(
|
|
19
|
+
wallet_address="0xYourWalletAddress",
|
|
20
|
+
name="MyAgent",
|
|
21
|
+
description="What your agent does",
|
|
22
|
+
category="research",
|
|
23
|
+
)
|
|
24
|
+
lifecycle.start() # stamps + registers + heartbeats + auto-renew
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That's it. Your agent now has:
|
|
28
|
+
- A cryptographic identity stamp (Ed25519)
|
|
29
|
+
- A public registry listing
|
|
30
|
+
- Heartbeat-based uptime reputation
|
|
31
|
+
- Auto-renewal before expiry
|
|
32
|
+
|
|
33
|
+
## Verify Other Agents
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
trust = lifecycle.check_trust("0xOtherAgentWallet")
|
|
37
|
+
if trust.get("trusted"):
|
|
38
|
+
print(f"Verified: {trust['agent']['name']} (score: {trust['reputation']['score']})")
|
|
39
|
+
else:
|
|
40
|
+
print("Unverified agent — proceed with caution")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Gate Functions Behind Verification
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from agentstamp_crewai import stamp_verified
|
|
47
|
+
|
|
48
|
+
@stamp_verified(lifecycle)
|
|
49
|
+
def sensitive_operation(data: str) -> str:
|
|
50
|
+
"""Only runs if the agent is AgentStamp verified."""
|
|
51
|
+
return process(data)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## CrewAI Integration
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from crewai import Agent, Task, Crew
|
|
58
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
59
|
+
|
|
60
|
+
# Start lifecycle
|
|
61
|
+
lifecycle = AgentStampLifecycle(
|
|
62
|
+
wallet_address="0x...",
|
|
63
|
+
name="ResearchBot",
|
|
64
|
+
description="Finds and summarizes papers",
|
|
65
|
+
category="research",
|
|
66
|
+
)
|
|
67
|
+
lifecycle.start()
|
|
68
|
+
|
|
69
|
+
# Create CrewAI agent as normal
|
|
70
|
+
agent = Agent(
|
|
71
|
+
role="Researcher",
|
|
72
|
+
goal="Find relevant papers",
|
|
73
|
+
backstory="Expert research assistant",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Check trust before collaborating with other agents
|
|
77
|
+
trust = lifecycle.check_trust("0xCollaboratorWallet")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
| Parameter | Default | Description |
|
|
83
|
+
|-----------|---------|-------------|
|
|
84
|
+
| `wallet_address` | required | Your agent's wallet address (EVM or Solana) |
|
|
85
|
+
| `name` | required | Agent display name |
|
|
86
|
+
| `description` | required | What your agent does |
|
|
87
|
+
| `category` | `"other"` | `research`, `trading`, `social`, `infrastructure`, etc. |
|
|
88
|
+
| `heartbeat_interval` | `300` | Seconds between heartbeats |
|
|
89
|
+
| `renew_before_days` | `2` | Days before expiry to auto-renew |
|
|
90
|
+
| `verbose` | `True` | Print lifecycle logs |
|
|
91
|
+
|
|
92
|
+
## Badge
|
|
93
|
+
|
|
94
|
+
Add a trust badge to your README:
|
|
95
|
+
|
|
96
|
+
```markdown
|
|
97
|
+

|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Links
|
|
101
|
+
|
|
102
|
+
- [AgentStamp](https://agentstamp.org) — Platform
|
|
103
|
+
- [npm SDK](https://www.npmjs.com/package/agentstamp-verify) — TypeScript/Node.js SDK
|
|
104
|
+
- [API Docs](https://agentstamp.org/api/v1/trust/check/0x...) — Trust check endpoint
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentstamp
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Identity lifecycle SDK for Python AI agents — trust stamps, registry, heartbeats, auto-renewal
|
|
5
|
+
Home-page: https://agentstamp.org
|
|
6
|
+
Author: Vinay Bhosle
|
|
7
|
+
Author-email: Vinay Bhosle <vinay@agentstamp.org>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://agentstamp.org
|
|
10
|
+
Project-URL: Repository, https://github.com/AgentstampHQ/agentstamp-python
|
|
11
|
+
Project-URL: Documentation, https://agentstamp.org
|
|
12
|
+
Project-URL: npm SDK, https://www.npmjs.com/package/agentstamp-verify
|
|
13
|
+
Keywords: agentstamp,ai-agents,crewai,autogen,langgraph,identity,trust,verification,x402,reputation
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
24
|
+
Classifier: Topic :: Security
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Requires-Dist: requests>=2.20.0
|
|
28
|
+
Dynamic: author
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# agentstamp
|
|
33
|
+
|
|
34
|
+
Identity lifecycle SDK for Python AI agents. Works with CrewAI, AutoGen, LangGraph, and any Python agent framework.
|
|
35
|
+
|
|
36
|
+
Register your agent, mint trust stamps, send heartbeats, and auto-renew — in 3 lines.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install agentstamp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
48
|
+
|
|
49
|
+
lifecycle = AgentStampLifecycle(
|
|
50
|
+
wallet_address="0xYourWalletAddress",
|
|
51
|
+
name="MyAgent",
|
|
52
|
+
description="What your agent does",
|
|
53
|
+
category="research",
|
|
54
|
+
)
|
|
55
|
+
lifecycle.start() # stamps + registers + heartbeats + auto-renew
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
That's it. Your agent now has:
|
|
59
|
+
- A cryptographic identity stamp (Ed25519)
|
|
60
|
+
- A public registry listing
|
|
61
|
+
- Heartbeat-based uptime reputation
|
|
62
|
+
- Auto-renewal before expiry
|
|
63
|
+
|
|
64
|
+
## Verify Other Agents
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
trust = lifecycle.check_trust("0xOtherAgentWallet")
|
|
68
|
+
if trust.get("trusted"):
|
|
69
|
+
print(f"Verified: {trust['agent']['name']} (score: {trust['reputation']['score']})")
|
|
70
|
+
else:
|
|
71
|
+
print("Unverified agent — proceed with caution")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Gate Functions Behind Verification
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from agentstamp_crewai import stamp_verified
|
|
78
|
+
|
|
79
|
+
@stamp_verified(lifecycle)
|
|
80
|
+
def sensitive_operation(data: str) -> str:
|
|
81
|
+
"""Only runs if the agent is AgentStamp verified."""
|
|
82
|
+
return process(data)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## CrewAI Integration
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from crewai import Agent, Task, Crew
|
|
89
|
+
from agentstamp_crewai import AgentStampLifecycle
|
|
90
|
+
|
|
91
|
+
# Start lifecycle
|
|
92
|
+
lifecycle = AgentStampLifecycle(
|
|
93
|
+
wallet_address="0x...",
|
|
94
|
+
name="ResearchBot",
|
|
95
|
+
description="Finds and summarizes papers",
|
|
96
|
+
category="research",
|
|
97
|
+
)
|
|
98
|
+
lifecycle.start()
|
|
99
|
+
|
|
100
|
+
# Create CrewAI agent as normal
|
|
101
|
+
agent = Agent(
|
|
102
|
+
role="Researcher",
|
|
103
|
+
goal="Find relevant papers",
|
|
104
|
+
backstory="Expert research assistant",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Check trust before collaborating with other agents
|
|
108
|
+
trust = lifecycle.check_trust("0xCollaboratorWallet")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Configuration
|
|
112
|
+
|
|
113
|
+
| Parameter | Default | Description |
|
|
114
|
+
|-----------|---------|-------------|
|
|
115
|
+
| `wallet_address` | required | Your agent's wallet address (EVM or Solana) |
|
|
116
|
+
| `name` | required | Agent display name |
|
|
117
|
+
| `description` | required | What your agent does |
|
|
118
|
+
| `category` | `"other"` | `research`, `trading`, `social`, `infrastructure`, etc. |
|
|
119
|
+
| `heartbeat_interval` | `300` | Seconds between heartbeats |
|
|
120
|
+
| `renew_before_days` | `2` | Days before expiry to auto-renew |
|
|
121
|
+
| `verbose` | `True` | Print lifecycle logs |
|
|
122
|
+
|
|
123
|
+
## Badge
|
|
124
|
+
|
|
125
|
+
Add a trust badge to your README:
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+

|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Links
|
|
132
|
+
|
|
133
|
+
- [AgentStamp](https://agentstamp.org) — Platform
|
|
134
|
+
- [npm SDK](https://www.npmjs.com/package/agentstamp-verify) — TypeScript/Node.js SDK
|
|
135
|
+
- [API Docs](https://agentstamp.org/api/v1/trust/check/0x...) — Trust check endpoint
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.20.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agentstamp_crewai
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AgentStamp + CrewAI Integration
|
|
3
|
+
|
|
4
|
+
Drop-in identity lifecycle for CrewAI agents.
|
|
5
|
+
Auto-registers your agent on first run, sends heartbeats, and auto-renews.
|
|
6
|
+
|
|
7
|
+
Install:
|
|
8
|
+
pip install requests
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
from agentstamp_crewai import AgentStampLifecycle, stamp_verified_tool
|
|
12
|
+
|
|
13
|
+
# Auto-register on startup
|
|
14
|
+
lifecycle = AgentStampLifecycle(
|
|
15
|
+
wallet_address="0x...",
|
|
16
|
+
name="MyResearchAgent",
|
|
17
|
+
description="Finds and summarizes research papers",
|
|
18
|
+
category="research",
|
|
19
|
+
)
|
|
20
|
+
lifecycle.start() # stamps + registers + heartbeats + auto-renew
|
|
21
|
+
|
|
22
|
+
# Use as a CrewAI tool
|
|
23
|
+
@stamp_verified_tool
|
|
24
|
+
def my_api_call(query: str) -> str:
|
|
25
|
+
'''Makes an API call only if the caller is AgentStamp verified.'''
|
|
26
|
+
return do_the_thing(query)
|
|
27
|
+
|
|
28
|
+
# Or check trust manually
|
|
29
|
+
trust = lifecycle.check_trust("0x_other_agent_wallet")
|
|
30
|
+
if trust["trusted"]:
|
|
31
|
+
proceed()
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
import time
|
|
36
|
+
import threading
|
|
37
|
+
from typing import Optional, Callable, Any
|
|
38
|
+
import requests
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
AGENTSTAMP_API = "https://agentstamp.org"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AgentStampLifecycle:
|
|
45
|
+
"""
|
|
46
|
+
Manages the full AgentStamp identity lifecycle for a CrewAI agent.
|
|
47
|
+
|
|
48
|
+
- Auto-registers (free stamp + free directory listing) on first run
|
|
49
|
+
- Sends periodic heartbeats for uptime reputation
|
|
50
|
+
- Auto-renews stamps and registrations before they expire
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
wallet_address: str,
|
|
56
|
+
name: str,
|
|
57
|
+
description: str,
|
|
58
|
+
category: str = "other",
|
|
59
|
+
capabilities: Optional[list] = None,
|
|
60
|
+
endpoint_url: Optional[str] = None,
|
|
61
|
+
base_url: str = AGENTSTAMP_API,
|
|
62
|
+
heartbeat_interval: int = 300, # seconds
|
|
63
|
+
renew_before_days: int = 2,
|
|
64
|
+
renew_check_interval: int = 3600, # seconds
|
|
65
|
+
verbose: bool = True,
|
|
66
|
+
on_registered: Optional[Callable] = None,
|
|
67
|
+
on_renewed: Optional[Callable] = None,
|
|
68
|
+
on_error: Optional[Callable] = None,
|
|
69
|
+
):
|
|
70
|
+
self.wallet_address = wallet_address
|
|
71
|
+
self.name = name
|
|
72
|
+
self.description = description
|
|
73
|
+
self.category = category
|
|
74
|
+
self.capabilities = capabilities or []
|
|
75
|
+
self.endpoint_url = endpoint_url
|
|
76
|
+
self.base_url = base_url.rstrip("/")
|
|
77
|
+
self.heartbeat_interval = heartbeat_interval
|
|
78
|
+
self.renew_before_days = renew_before_days
|
|
79
|
+
self.renew_check_interval = renew_check_interval
|
|
80
|
+
self.verbose = verbose
|
|
81
|
+
self.on_registered = on_registered
|
|
82
|
+
self.on_renewed = on_renewed
|
|
83
|
+
self.on_error = on_error
|
|
84
|
+
|
|
85
|
+
# State
|
|
86
|
+
self.agent_id: Optional[str] = None
|
|
87
|
+
self.stamp_id: Optional[str] = None
|
|
88
|
+
self.stamp_expires_at: Optional[str] = None
|
|
89
|
+
self.registration_expires_at: Optional[str] = None
|
|
90
|
+
self.heartbeat_count: int = 0
|
|
91
|
+
self.initialized: bool = False
|
|
92
|
+
|
|
93
|
+
# Timers
|
|
94
|
+
self._heartbeat_timer: Optional[threading.Timer] = None
|
|
95
|
+
self._renew_timer: Optional[threading.Timer] = None
|
|
96
|
+
self._shutdown = False
|
|
97
|
+
|
|
98
|
+
def start(self) -> dict:
|
|
99
|
+
"""Initialize + heartbeat + auto-renew in one call."""
|
|
100
|
+
state = self.initialize()
|
|
101
|
+
self.enable_heartbeat()
|
|
102
|
+
self.enable_auto_renew()
|
|
103
|
+
return state
|
|
104
|
+
|
|
105
|
+
def initialize(self) -> dict:
|
|
106
|
+
"""Mint a free stamp and register if not already done."""
|
|
107
|
+
self._log("Initializing agent lifecycle...")
|
|
108
|
+
|
|
109
|
+
# Check if already registered
|
|
110
|
+
if self._check_existing():
|
|
111
|
+
self._log(f"Agent already registered: {self.agent_id}")
|
|
112
|
+
self.initialized = True
|
|
113
|
+
return self.get_state()
|
|
114
|
+
|
|
115
|
+
# Step 1: Mint free stamp
|
|
116
|
+
try:
|
|
117
|
+
self._log("Minting free stamp...")
|
|
118
|
+
resp = requests.post(
|
|
119
|
+
f"{self.base_url}/api/v1/stamp/mint/free",
|
|
120
|
+
json={"wallet_address": self.wallet_address},
|
|
121
|
+
headers={
|
|
122
|
+
"x-wallet-address": self.wallet_address,
|
|
123
|
+
"User-Agent": "agentstamp-crewai/1.0.0",
|
|
124
|
+
},
|
|
125
|
+
timeout=10,
|
|
126
|
+
)
|
|
127
|
+
data = resp.json()
|
|
128
|
+
if data.get("success") and data.get("stamp"):
|
|
129
|
+
self.stamp_id = data["stamp"]["id"]
|
|
130
|
+
self.stamp_expires_at = data["stamp"]["expires_at"]
|
|
131
|
+
self._log(f"Stamp minted: {self.stamp_id}")
|
|
132
|
+
elif "cooldown" in str(data.get("error", "")):
|
|
133
|
+
self._log("Free stamp cooldown active — already stamped")
|
|
134
|
+
except Exception as e:
|
|
135
|
+
self._handle_error(e, "mint_stamp")
|
|
136
|
+
|
|
137
|
+
# Step 2: Register in directory
|
|
138
|
+
try:
|
|
139
|
+
self._log("Registering agent in directory...")
|
|
140
|
+
resp = requests.post(
|
|
141
|
+
f"{self.base_url}/api/v1/registry/register/free",
|
|
142
|
+
json={
|
|
143
|
+
"wallet_address": self.wallet_address,
|
|
144
|
+
"name": self.name,
|
|
145
|
+
"description": self.description,
|
|
146
|
+
"category": self.category,
|
|
147
|
+
"capabilities": self.capabilities,
|
|
148
|
+
"endpoint_url": self.endpoint_url,
|
|
149
|
+
},
|
|
150
|
+
headers={
|
|
151
|
+
"x-wallet-address": self.wallet_address,
|
|
152
|
+
"User-Agent": "agentstamp-crewai/1.0.0",
|
|
153
|
+
},
|
|
154
|
+
timeout=10,
|
|
155
|
+
)
|
|
156
|
+
data = resp.json()
|
|
157
|
+
if data.get("success") and data.get("agent"):
|
|
158
|
+
self.agent_id = data["agent"]["id"]
|
|
159
|
+
self.registration_expires_at = data["agent"]["expires_at"]
|
|
160
|
+
self._log(f"Agent registered: {self.agent_id}")
|
|
161
|
+
if self.on_registered:
|
|
162
|
+
self.on_registered({"agent_id": self.agent_id, "stamp_id": self.stamp_id})
|
|
163
|
+
elif "cooldown" in str(data.get("error", "")):
|
|
164
|
+
self._log("Free registration cooldown active — already registered")
|
|
165
|
+
self._check_existing()
|
|
166
|
+
except Exception as e:
|
|
167
|
+
self._handle_error(e, "register")
|
|
168
|
+
|
|
169
|
+
self.initialized = True
|
|
170
|
+
return self.get_state()
|
|
171
|
+
|
|
172
|
+
def enable_heartbeat(self, interval: Optional[int] = None) -> None:
|
|
173
|
+
"""Send periodic heartbeats to maintain uptime score."""
|
|
174
|
+
if self._heartbeat_timer is not None:
|
|
175
|
+
return
|
|
176
|
+
interval = interval or self.heartbeat_interval
|
|
177
|
+
self._log(f"Heartbeat enabled (every {interval}s)")
|
|
178
|
+
self._send_heartbeat()
|
|
179
|
+
self._schedule_heartbeat(interval)
|
|
180
|
+
|
|
181
|
+
def enable_auto_renew(self, check_interval: Optional[int] = None) -> None:
|
|
182
|
+
"""Periodically check and renew stamps/registrations before expiry."""
|
|
183
|
+
if self._renew_timer is not None:
|
|
184
|
+
return
|
|
185
|
+
interval = check_interval or self.renew_check_interval
|
|
186
|
+
self._log(f"Auto-renewal enabled (check every {interval}s)")
|
|
187
|
+
self._check_and_renew()
|
|
188
|
+
self._schedule_renew(interval)
|
|
189
|
+
|
|
190
|
+
def check_trust(self, wallet_address: str) -> dict:
|
|
191
|
+
"""Check the trust status of another agent."""
|
|
192
|
+
try:
|
|
193
|
+
resp = requests.get(
|
|
194
|
+
f"{self.base_url}/api/v1/trust/check/{wallet_address}",
|
|
195
|
+
headers={"User-Agent": "agentstamp-crewai/1.0.0"},
|
|
196
|
+
timeout=5,
|
|
197
|
+
)
|
|
198
|
+
return resp.json()
|
|
199
|
+
except Exception as e:
|
|
200
|
+
return {"trusted": False, "error": str(e)}
|
|
201
|
+
|
|
202
|
+
def shutdown(self) -> None:
|
|
203
|
+
"""Stop all background timers."""
|
|
204
|
+
self._shutdown = True
|
|
205
|
+
if self._heartbeat_timer:
|
|
206
|
+
self._heartbeat_timer.cancel()
|
|
207
|
+
self._heartbeat_timer = None
|
|
208
|
+
if self._renew_timer:
|
|
209
|
+
self._renew_timer.cancel()
|
|
210
|
+
self._renew_timer = None
|
|
211
|
+
self._log("Lifecycle shut down")
|
|
212
|
+
|
|
213
|
+
def get_state(self) -> dict:
|
|
214
|
+
return {
|
|
215
|
+
"initialized": self.initialized,
|
|
216
|
+
"agent_id": self.agent_id,
|
|
217
|
+
"stamp_id": self.stamp_id,
|
|
218
|
+
"stamp_expires_at": self.stamp_expires_at,
|
|
219
|
+
"registration_expires_at": self.registration_expires_at,
|
|
220
|
+
"heartbeat_count": self.heartbeat_count,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# --- Private ---
|
|
224
|
+
|
|
225
|
+
def _check_existing(self) -> bool:
|
|
226
|
+
try:
|
|
227
|
+
resp = requests.get(
|
|
228
|
+
f"{self.base_url}/api/v1/trust/check/{self.wallet_address}",
|
|
229
|
+
headers={"User-Agent": "agentstamp-crewai/1.0.0"},
|
|
230
|
+
timeout=5,
|
|
231
|
+
)
|
|
232
|
+
data = resp.json()
|
|
233
|
+
if data.get("agent"):
|
|
234
|
+
self.agent_id = data["agent"].get("id")
|
|
235
|
+
if data.get("stamp"):
|
|
236
|
+
self.stamp_id = data["stamp"].get("id")
|
|
237
|
+
self.stamp_expires_at = data["stamp"].get("expires_at")
|
|
238
|
+
return data.get("trusted", False) or data.get("agent") is not None
|
|
239
|
+
except Exception:
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
def _send_heartbeat(self) -> None:
|
|
243
|
+
if not self.agent_id or self._shutdown:
|
|
244
|
+
return
|
|
245
|
+
try:
|
|
246
|
+
requests.post(
|
|
247
|
+
f"{self.base_url}/api/v1/registry/heartbeat/{self.agent_id}",
|
|
248
|
+
headers={"User-Agent": "agentstamp-crewai/1.0.0"},
|
|
249
|
+
timeout=5,
|
|
250
|
+
)
|
|
251
|
+
self.heartbeat_count += 1
|
|
252
|
+
self._log(f"Heartbeat #{self.heartbeat_count} sent")
|
|
253
|
+
except Exception as e:
|
|
254
|
+
self._handle_error(e, "heartbeat")
|
|
255
|
+
|
|
256
|
+
def _schedule_heartbeat(self, interval: int) -> None:
|
|
257
|
+
if self._shutdown:
|
|
258
|
+
return
|
|
259
|
+
self._heartbeat_timer = threading.Timer(interval, self._heartbeat_tick, [interval])
|
|
260
|
+
self._heartbeat_timer.daemon = True
|
|
261
|
+
self._heartbeat_timer.start()
|
|
262
|
+
|
|
263
|
+
def _heartbeat_tick(self, interval: int) -> None:
|
|
264
|
+
if self._shutdown:
|
|
265
|
+
return
|
|
266
|
+
self._send_heartbeat()
|
|
267
|
+
self._schedule_heartbeat(interval)
|
|
268
|
+
|
|
269
|
+
def _check_and_renew(self) -> None:
|
|
270
|
+
if self._shutdown:
|
|
271
|
+
return
|
|
272
|
+
now = time.time()
|
|
273
|
+
threshold = self.renew_before_days * 86400
|
|
274
|
+
|
|
275
|
+
# Check stamp
|
|
276
|
+
if self.stamp_expires_at:
|
|
277
|
+
try:
|
|
278
|
+
from datetime import datetime
|
|
279
|
+
expiry = datetime.fromisoformat(self.stamp_expires_at.replace("Z", "+00:00")).timestamp()
|
|
280
|
+
if expiry - now < threshold:
|
|
281
|
+
self._log("Stamp expiring soon — renewing...")
|
|
282
|
+
resp = requests.post(
|
|
283
|
+
f"{self.base_url}/api/v1/stamp/mint/free",
|
|
284
|
+
json={"wallet_address": self.wallet_address},
|
|
285
|
+
headers={"x-wallet-address": self.wallet_address, "User-Agent": "agentstamp-crewai/1.0.0"},
|
|
286
|
+
timeout=10,
|
|
287
|
+
)
|
|
288
|
+
data = resp.json()
|
|
289
|
+
if data.get("success") and data.get("stamp"):
|
|
290
|
+
self.stamp_id = data["stamp"]["id"]
|
|
291
|
+
self.stamp_expires_at = data["stamp"]["expires_at"]
|
|
292
|
+
self._log(f"Stamp renewed: {self.stamp_id}")
|
|
293
|
+
if self.on_renewed:
|
|
294
|
+
self.on_renewed({"type": "stamp", "expires_at": self.stamp_expires_at})
|
|
295
|
+
except Exception as e:
|
|
296
|
+
self._handle_error(e, "renew_stamp")
|
|
297
|
+
|
|
298
|
+
# Check registration
|
|
299
|
+
if self.registration_expires_at:
|
|
300
|
+
try:
|
|
301
|
+
from datetime import datetime
|
|
302
|
+
expiry = datetime.fromisoformat(self.registration_expires_at.replace("Z", "+00:00")).timestamp()
|
|
303
|
+
if expiry - now < threshold:
|
|
304
|
+
self._log("Registration expiring soon — renewing...")
|
|
305
|
+
resp = requests.post(
|
|
306
|
+
f"{self.base_url}/api/v1/registry/register/free",
|
|
307
|
+
json={
|
|
308
|
+
"wallet_address": self.wallet_address,
|
|
309
|
+
"name": self.name,
|
|
310
|
+
"description": self.description,
|
|
311
|
+
"category": self.category,
|
|
312
|
+
"capabilities": self.capabilities,
|
|
313
|
+
},
|
|
314
|
+
headers={"x-wallet-address": self.wallet_address, "User-Agent": "agentstamp-crewai/1.0.0"},
|
|
315
|
+
timeout=10,
|
|
316
|
+
)
|
|
317
|
+
data = resp.json()
|
|
318
|
+
if data.get("success") and data.get("agent"):
|
|
319
|
+
self.agent_id = data["agent"]["id"]
|
|
320
|
+
self.registration_expires_at = data["agent"]["expires_at"]
|
|
321
|
+
self._log(f"Registration renewed: {self.agent_id}")
|
|
322
|
+
if self.on_renewed:
|
|
323
|
+
self.on_renewed({"type": "registration", "expires_at": self.registration_expires_at})
|
|
324
|
+
except Exception as e:
|
|
325
|
+
self._handle_error(e, "renew_registration")
|
|
326
|
+
|
|
327
|
+
def _schedule_renew(self, interval: int) -> None:
|
|
328
|
+
if self._shutdown:
|
|
329
|
+
return
|
|
330
|
+
self._renew_timer = threading.Timer(interval, self._renew_tick, [interval])
|
|
331
|
+
self._renew_timer.daemon = True
|
|
332
|
+
self._renew_timer.start()
|
|
333
|
+
|
|
334
|
+
def _renew_tick(self, interval: int) -> None:
|
|
335
|
+
if self._shutdown:
|
|
336
|
+
return
|
|
337
|
+
self._check_and_renew()
|
|
338
|
+
self._schedule_renew(interval)
|
|
339
|
+
|
|
340
|
+
def _handle_error(self, err: Exception, context: str) -> None:
|
|
341
|
+
self._log(f"Error [{context}]: {err}", is_error=True)
|
|
342
|
+
if self.on_error:
|
|
343
|
+
self.on_error(err, context)
|
|
344
|
+
|
|
345
|
+
def _log(self, message: str, is_error: bool = False) -> None:
|
|
346
|
+
if self.verbose:
|
|
347
|
+
prefix = f"[AgentStamp:{self.name}]"
|
|
348
|
+
if is_error:
|
|
349
|
+
print(f"\033[91m{prefix} {message}\033[0m")
|
|
350
|
+
else:
|
|
351
|
+
print(f"\033[96m{prefix} {message}\033[0m")
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def stamp_verified(lifecycle: AgentStampLifecycle):
|
|
355
|
+
"""
|
|
356
|
+
Decorator: only execute a function if the agent is AgentStamp verified.
|
|
357
|
+
|
|
358
|
+
Usage:
|
|
359
|
+
lifecycle = AgentStampLifecycle(...)
|
|
360
|
+
lifecycle.start()
|
|
361
|
+
|
|
362
|
+
@stamp_verified(lifecycle)
|
|
363
|
+
def my_tool(query: str) -> str:
|
|
364
|
+
return "result"
|
|
365
|
+
"""
|
|
366
|
+
def decorator(func: Callable) -> Callable:
|
|
367
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
368
|
+
if not lifecycle.initialized or not lifecycle.agent_id:
|
|
369
|
+
return "Error: Agent not registered with AgentStamp. Call lifecycle.start() first."
|
|
370
|
+
return func(*args, **kwargs)
|
|
371
|
+
wrapper.__name__ = func.__name__
|
|
372
|
+
wrapper.__doc__ = func.__doc__
|
|
373
|
+
return wrapper
|
|
374
|
+
return decorator
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agentstamp"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "Identity lifecycle SDK for Python AI agents — trust stamps, registry, heartbeats, auto-renewal"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Vinay Bhosle", email = "vinay@agentstamp.org"}
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"agentstamp", "ai-agents", "crewai", "autogen", "langgraph",
|
|
17
|
+
"identity", "trust", "verification", "x402", "reputation"
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.8",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Software Development :: Libraries",
|
|
30
|
+
"Topic :: Security",
|
|
31
|
+
]
|
|
32
|
+
dependencies = ["requests>=2.20.0"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://agentstamp.org"
|
|
36
|
+
Repository = "https://github.com/AgentstampHQ/agentstamp-python"
|
|
37
|
+
Documentation = "https://agentstamp.org"
|
|
38
|
+
"npm SDK" = "https://www.npmjs.com/package/agentstamp-verify"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="agentstamp",
|
|
5
|
+
version="1.1.0",
|
|
6
|
+
description="AgentStamp identity lifecycle for Python AI agents (CrewAI, AutoGen, etc.)",
|
|
7
|
+
long_description=open("README.md").read() if __import__("os").path.exists("README.md") else "",
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="Vinay Bhosle",
|
|
10
|
+
author_email="vinay@agentstamp.org",
|
|
11
|
+
url="https://agentstamp.org",
|
|
12
|
+
py_modules=["agentstamp_crewai"],
|
|
13
|
+
install_requires=["requests>=2.20.0"],
|
|
14
|
+
python_requires=">=3.8",
|
|
15
|
+
license="MIT",
|
|
16
|
+
keywords=["agentstamp", "ai-agents", "crewai", "identity", "trust", "verification"],
|
|
17
|
+
classifiers=[
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
],
|
|
23
|
+
)
|