agent0-sdk 1.0.0__py3-none-any.whl → 1.0.2__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.
- agent0_sdk/__init__.py +1 -1
- agent0_sdk/core/agent.py +10 -9
- agent0_sdk/core/contracts.py +2 -1
- agent0_sdk/core/feedback_manager.py +147 -92
- agent0_sdk/core/indexer.py +2 -1
- agent0_sdk/core/ipfs_client.py +8 -6
- agent0_sdk/core/sdk.py +55 -138
- {agent0_sdk-1.0.0.dist-info → agent0_sdk-1.0.2.dist-info}/METADATA +29 -23
- agent0_sdk-1.0.2.dist-info/RECORD +19 -0
- agent0_sdk-1.0.0.dist-info/RECORD +0 -19
- {agent0_sdk-1.0.0.dist-info → agent0_sdk-1.0.2.dist-info}/WHEEL +0 -0
- {agent0_sdk-1.0.0.dist-info → agent0_sdk-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {agent0_sdk-1.0.0.dist-info → agent0_sdk-1.0.2.dist-info}/top_level.txt +0 -0
agent0_sdk/__init__.py
CHANGED
agent0_sdk/core/agent.py
CHANGED
|
@@ -327,7 +327,8 @@ class Agent:
|
|
|
327
327
|
oasf_endpoint = Endpoint(
|
|
328
328
|
type=EndpointType.OASF,
|
|
329
329
|
value="https://github.com/agntcy/oasf/",
|
|
330
|
-
|
|
330
|
+
# Version string follows ERC-8004 spec example ("0.8")
|
|
331
|
+
meta={"version": "0.8", "skills": [], "domains": []}
|
|
331
332
|
)
|
|
332
333
|
self.registration_file.endpoints.append(oasf_endpoint)
|
|
333
334
|
return oasf_endpoint
|
|
@@ -529,14 +530,14 @@ class Agent:
|
|
|
529
530
|
raise ValueError("Wallet address cannot be empty. Use a non-zero address.")
|
|
530
531
|
|
|
531
532
|
# Validate address format
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
533
|
+
if not addr.startswith("0x") or len(addr) != 42:
|
|
534
|
+
raise ValueError(f"Invalid Ethereum address format: {addr}. Must be 42 characters starting with '0x'")
|
|
535
|
+
|
|
536
|
+
# Validate hexadecimal characters
|
|
537
|
+
try:
|
|
538
|
+
int(addr[2:], 16)
|
|
539
|
+
except ValueError:
|
|
540
|
+
raise ValueError(f"Invalid hexadecimal characters in address: {addr}")
|
|
540
541
|
|
|
541
542
|
# Determine chain ID to use (local bookkeeping)
|
|
542
543
|
if chainId is None:
|
agent0_sdk/core/contracts.py
CHANGED
|
@@ -346,7 +346,8 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
346
346
|
{"indexed": True, "internalType": "address", "name": "clientAddress", "type": "address"},
|
|
347
347
|
{"indexed": False, "internalType": "uint64", "name": "feedbackIndex", "type": "uint64"},
|
|
348
348
|
{"indexed": False, "internalType": "uint8", "name": "score", "type": "uint8"},
|
|
349
|
-
{"indexed": True, "internalType": "string", "name": "
|
|
349
|
+
{"indexed": True, "internalType": "string", "name": "indexedTag1", "type": "string"},
|
|
350
|
+
{"indexed": False, "internalType": "string", "name": "tag1", "type": "string"},
|
|
350
351
|
{"indexed": False, "internalType": "string", "name": "tag2", "type": "string"},
|
|
351
352
|
{"indexed": False, "internalType": "string", "name": "endpoint", "type": "string"},
|
|
352
353
|
{"indexed": False, "internalType": "string", "name": "feedbackURI", "type": "string"},
|
|
@@ -8,7 +8,7 @@ import json
|
|
|
8
8
|
import logging
|
|
9
9
|
import time
|
|
10
10
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
11
|
-
from datetime import datetime
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
12
|
|
|
13
13
|
from .models import (
|
|
14
14
|
AgentId, Address, URI, Timestamp, IdemKey,
|
|
@@ -40,77 +40,66 @@ class FeedbackManager:
|
|
|
40
40
|
self.subgraph_client = subgraph_client
|
|
41
41
|
self.indexer = indexer
|
|
42
42
|
|
|
43
|
-
def
|
|
44
|
-
|
|
45
|
-
agentId: AgentId,
|
|
46
|
-
score: Optional[int] = None, # 0-100
|
|
47
|
-
tags: List[str] = None,
|
|
48
|
-
text: Optional[str] = None,
|
|
49
|
-
capability: Optional[str] = None,
|
|
50
|
-
name: Optional[str] = None,
|
|
51
|
-
skill: Optional[str] = None,
|
|
52
|
-
task: Optional[str] = None,
|
|
53
|
-
endpoint: Optional[str] = None,
|
|
54
|
-
domain: Optional[str] = None,
|
|
55
|
-
context: Optional[Dict[str, Any]] = None,
|
|
56
|
-
proofOfPayment: Optional[Dict[str, Any]] = None,
|
|
57
|
-
extra: Optional[Dict[str, Any]] = None,
|
|
58
|
-
) -> Dict[str, Any]:
|
|
59
|
-
"""Prepare feedback file (local file/object) according to spec."""
|
|
60
|
-
if tags is None:
|
|
61
|
-
tags = []
|
|
62
|
-
|
|
63
|
-
# Parse agent ID to get token ID
|
|
64
|
-
if ":" in agentId:
|
|
65
|
-
tokenId = int(agentId.split(":")[-1])
|
|
66
|
-
else:
|
|
67
|
-
tokenId = int(agentId)
|
|
68
|
-
|
|
69
|
-
# Get current timestamp in ISO format
|
|
70
|
-
createdAt = datetime.fromtimestamp(time.time()).isoformat() + "Z"
|
|
71
|
-
|
|
72
|
-
# Build feedback data according to spec
|
|
73
|
-
feedbackData = {
|
|
74
|
-
# MUST FIELDS
|
|
75
|
-
"agentRegistry": f"eip155:{self.web3_client.chain_id}:{self.identity_registry.address if self.identity_registry else '0x0'}",
|
|
76
|
-
"agentId": tokenId,
|
|
77
|
-
"clientAddress": f"eip155:{self.web3_client.chain_id}:{self.web3_client.account.address}",
|
|
78
|
-
"createdAt": createdAt,
|
|
79
|
-
"score": int(score) if score else 0, # Score as integer (0-100)
|
|
80
|
-
|
|
81
|
-
# MAY FIELDS
|
|
82
|
-
"tag1": tags[0] if tags else None,
|
|
83
|
-
"tag2": tags[1] if len(tags) > 1 else None,
|
|
84
|
-
"endpoint": endpoint,
|
|
85
|
-
"domain": domain,
|
|
86
|
-
"skill": skill,
|
|
87
|
-
"context": context,
|
|
88
|
-
"task": task,
|
|
89
|
-
"capability": capability,
|
|
90
|
-
"name": name,
|
|
91
|
-
"proofOfPayment": proofOfPayment,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
# Remove None values to keep the structure clean
|
|
95
|
-
feedbackData = {k: v for k, v in feedbackData.items() if v is not None}
|
|
43
|
+
def prepareFeedbackFile(self, input: Dict[str, Any]) -> Dict[str, Any]:
|
|
44
|
+
"""Prepare an off-chain feedback file payload (no on-chain fields).
|
|
96
45
|
|
|
97
|
-
|
|
98
|
-
|
|
46
|
+
This intentionally does NOT attempt to represent on-chain fields like:
|
|
47
|
+
score/tag1/tag2/endpoint (on-chain value), or registry-derived fields.
|
|
99
48
|
|
|
100
|
-
|
|
49
|
+
It may validate/normalize and remove None values.
|
|
50
|
+
"""
|
|
51
|
+
if input is None:
|
|
52
|
+
raise ValueError("prepareFeedbackFile input cannot be None")
|
|
53
|
+
if not isinstance(input, dict):
|
|
54
|
+
raise TypeError(f"prepareFeedbackFile input must be a dict, got {type(input)}")
|
|
55
|
+
|
|
56
|
+
# Shallow copy and strip None values
|
|
57
|
+
out: Dict[str, Any] = {k: v for k, v in dict(input).items() if v is not None}
|
|
58
|
+
|
|
59
|
+
# Minimal normalization for known optional fields
|
|
60
|
+
if "endpoint" in out and out["endpoint"] is not None and not isinstance(out["endpoint"], str):
|
|
61
|
+
out["endpoint"] = str(out["endpoint"])
|
|
62
|
+
if "domain" in out and out["domain"] is not None and not isinstance(out["domain"], str):
|
|
63
|
+
out["domain"] = str(out["domain"])
|
|
64
|
+
|
|
65
|
+
return out
|
|
101
66
|
|
|
102
67
|
def giveFeedback(
|
|
103
68
|
self,
|
|
104
69
|
agentId: AgentId,
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
score: int,
|
|
71
|
+
tag1: Optional[str] = None,
|
|
72
|
+
tag2: Optional[str] = None,
|
|
73
|
+
endpoint: Optional[str] = None,
|
|
74
|
+
feedbackFile: Optional[Dict[str, Any]] = None,
|
|
107
75
|
) -> Feedback:
|
|
108
76
|
"""Give feedback (maps 8004 endpoint)."""
|
|
109
|
-
# Parse
|
|
110
|
-
|
|
111
|
-
|
|
77
|
+
# Parse agentId into (chainId, tokenId)
|
|
78
|
+
agent_chain_id: Optional[int] = None
|
|
79
|
+
tokenId: int
|
|
80
|
+
if isinstance(agentId, str) and agentId.startswith("eip155:"):
|
|
81
|
+
parts = agentId.split(":")
|
|
82
|
+
if len(parts) != 3:
|
|
83
|
+
raise ValueError(f"Invalid AgentId (expected eip155:chainId:tokenId): {agentId}")
|
|
84
|
+
agent_chain_id = int(parts[1])
|
|
85
|
+
tokenId = int(parts[2])
|
|
86
|
+
elif isinstance(agentId, str) and ":" in agentId:
|
|
87
|
+
parts = agentId.split(":")
|
|
88
|
+
if len(parts) != 2:
|
|
89
|
+
raise ValueError(f"Invalid AgentId (expected chainId:tokenId): {agentId}")
|
|
90
|
+
agent_chain_id = int(parts[0])
|
|
91
|
+
tokenId = int(parts[1])
|
|
112
92
|
else:
|
|
113
93
|
tokenId = int(agentId)
|
|
94
|
+
agent_chain_id = int(self.web3_client.chain_id)
|
|
95
|
+
|
|
96
|
+
# Ensure we are submitting the tx on the agent's chain
|
|
97
|
+
if int(self.web3_client.chain_id) != int(agent_chain_id):
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"Chain mismatch for giveFeedback: agentId={agentId} targets chainId={agent_chain_id}, "
|
|
100
|
+
f"but web3 client is connected to chainId={self.web3_client.chain_id}. "
|
|
101
|
+
f"Initialize the SDK/Web3Client for chainId={agent_chain_id}."
|
|
102
|
+
)
|
|
114
103
|
|
|
115
104
|
# Get client address (the one giving feedback)
|
|
116
105
|
# Keep in checksum format for blockchain calls (web3.py requirement)
|
|
@@ -128,30 +117,94 @@ class FeedbackManager:
|
|
|
128
117
|
except Exception as e:
|
|
129
118
|
raise ValueError(f"Failed to get feedback index: {e}")
|
|
130
119
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
120
|
+
if score is None:
|
|
121
|
+
raise ValueError("score is required")
|
|
122
|
+
if not isinstance(score, int):
|
|
123
|
+
# Allow numeric strings / floats if passed accidentally
|
|
124
|
+
score = int(score)
|
|
125
|
+
|
|
126
|
+
tag1 = tag1 or ""
|
|
127
|
+
tag2 = tag2 or ""
|
|
128
|
+
|
|
129
|
+
feedback_file: Optional[Dict[str, Any]] = feedbackFile
|
|
130
|
+
if feedback_file is not None and not isinstance(feedback_file, dict):
|
|
131
|
+
raise TypeError(f"feedbackFile must be a dict when provided, got {type(feedback_file)}")
|
|
132
|
+
|
|
133
|
+
# Endpoint precedence: explicit arg > file endpoint > empty string
|
|
134
|
+
if endpoint:
|
|
135
|
+
endpoint_onchain = endpoint
|
|
136
|
+
elif feedback_file and isinstance(feedback_file.get("endpoint"), str) and feedback_file.get("endpoint"):
|
|
137
|
+
endpoint_onchain = feedback_file.get("endpoint")
|
|
138
|
+
else:
|
|
139
|
+
endpoint_onchain = ""
|
|
140
|
+
|
|
141
|
+
# If uploading a file and we have an explicit endpoint, inject it for consistency
|
|
142
|
+
if feedback_file is not None and endpoint and isinstance(endpoint, str):
|
|
143
|
+
feedback_file = dict(feedback_file)
|
|
144
|
+
feedback_file["endpoint"] = endpoint
|
|
136
145
|
|
|
137
146
|
# Handle off-chain file storage
|
|
138
147
|
feedbackUri = ""
|
|
139
148
|
feedbackHash = b"\x00" * 32 # Default empty hash
|
|
140
149
|
|
|
141
|
-
if
|
|
142
|
-
|
|
150
|
+
if feedback_file is not None:
|
|
151
|
+
if not self.ipfs_client:
|
|
152
|
+
raise ValueError("feedbackFile was provided, but no IPFS client is configured")
|
|
153
|
+
|
|
154
|
+
# Store an ERC-8004 compliant feedback file on IPFS (explicit opt-in)
|
|
143
155
|
try:
|
|
144
156
|
logger.debug("Storing feedback file on IPFS")
|
|
145
|
-
|
|
157
|
+
# createdAt MUST be present in the off-chain file; use provided value if valid, else now (UTC).
|
|
158
|
+
created_at = feedback_file.get("createdAt")
|
|
159
|
+
if not isinstance(created_at, str) or not created_at:
|
|
160
|
+
created_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
161
|
+
|
|
162
|
+
identity_registry_address = "0x0"
|
|
163
|
+
try:
|
|
164
|
+
if self.identity_registry is not None:
|
|
165
|
+
identity_registry_address = str(getattr(self.identity_registry, "address", "0x0"))
|
|
166
|
+
except Exception:
|
|
167
|
+
identity_registry_address = "0x0"
|
|
168
|
+
|
|
169
|
+
# Remove any user-provided copies of the envelope keys; SDK-owned values must win
|
|
170
|
+
rich = dict(feedback_file)
|
|
171
|
+
for k in [
|
|
172
|
+
"agentRegistry",
|
|
173
|
+
"agentId",
|
|
174
|
+
"clientAddress",
|
|
175
|
+
"createdAt",
|
|
176
|
+
"score",
|
|
177
|
+
"tag1",
|
|
178
|
+
"tag2",
|
|
179
|
+
"endpoint",
|
|
180
|
+
]:
|
|
181
|
+
rich.pop(k, None)
|
|
182
|
+
|
|
183
|
+
file_for_storage: Dict[str, Any] = {
|
|
184
|
+
# MUST fields (spec)
|
|
185
|
+
"agentRegistry": f"eip155:{agent_chain_id}:{identity_registry_address}",
|
|
186
|
+
"agentId": tokenId,
|
|
187
|
+
"clientAddress": f"eip155:{agent_chain_id}:{clientAddress}",
|
|
188
|
+
"createdAt": created_at,
|
|
189
|
+
"score": int(score),
|
|
190
|
+
|
|
191
|
+
# OPTIONAL fields that mirror on-chain
|
|
192
|
+
**({"tag1": tag1} if tag1 else {}),
|
|
193
|
+
**({"tag2": tag2} if tag2 else {}),
|
|
194
|
+
**({"endpoint": endpoint_onchain} if endpoint_onchain else {}),
|
|
195
|
+
|
|
196
|
+
# Rich/off-chain fields
|
|
197
|
+
**rich,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
cid = self.ipfs_client.addFeedbackFile(file_for_storage)
|
|
146
201
|
feedbackUri = f"ipfs://{cid}"
|
|
147
|
-
feedbackHash = self.web3_client.keccak256(
|
|
202
|
+
feedbackHash = self.web3_client.keccak256(
|
|
203
|
+
json.dumps(file_for_storage, sort_keys=True).encode()
|
|
204
|
+
)
|
|
148
205
|
logger.debug(f"Feedback file stored on IPFS: {cid}")
|
|
149
206
|
except Exception as e:
|
|
150
|
-
|
|
151
|
-
# Continue without IPFS storage
|
|
152
|
-
elif feedbackFile.get("context") or feedbackFile.get("capability") or feedbackFile.get("name"):
|
|
153
|
-
# If we have rich data but no IPFS, we need to store it somewhere
|
|
154
|
-
raise ValueError("Rich feedback data requires IPFS client for storage")
|
|
207
|
+
raise ValueError(f"Failed to store feedback on IPFS: {e}")
|
|
155
208
|
|
|
156
209
|
# Submit to blockchain with new signature: giveFeedback(agentId, score, tag1, tag2, endpoint, feedbackURI, feedbackHash)
|
|
157
210
|
try:
|
|
@@ -162,7 +215,7 @@ class FeedbackManager:
|
|
|
162
215
|
score,
|
|
163
216
|
tag1,
|
|
164
217
|
tag2,
|
|
165
|
-
|
|
218
|
+
endpoint_onchain,
|
|
166
219
|
feedbackUri,
|
|
167
220
|
feedbackHash
|
|
168
221
|
)
|
|
@@ -176,24 +229,25 @@ class FeedbackManager:
|
|
|
176
229
|
# Create feedback object (address normalization happens in Feedback.create_id)
|
|
177
230
|
feedbackId = Feedback.create_id(agentId, clientAddress, feedbackIndex)
|
|
178
231
|
|
|
232
|
+
ff: Dict[str, Any] = feedback_file or {}
|
|
179
233
|
return Feedback(
|
|
180
234
|
id=feedbackId,
|
|
181
235
|
agentId=agentId,
|
|
182
236
|
reviewer=clientAddress, # create_id normalizes the ID; reviewer field can remain as-is
|
|
183
237
|
score=int(score) if score and score > 0 else None,
|
|
184
238
|
tags=[tag1, tag2] if tag1 or tag2 else [],
|
|
185
|
-
text=
|
|
186
|
-
context=
|
|
187
|
-
proofOfPayment=
|
|
239
|
+
text=ff.get("text"),
|
|
240
|
+
context=ff.get("context"),
|
|
241
|
+
proofOfPayment=ff.get("proofOfPayment"),
|
|
188
242
|
fileURI=feedbackUri if feedbackUri else None,
|
|
189
|
-
endpoint=
|
|
243
|
+
endpoint=endpoint_onchain if endpoint_onchain else None,
|
|
190
244
|
createdAt=int(time.time()),
|
|
191
245
|
isRevoked=False,
|
|
192
246
|
# Off-chain only fields
|
|
193
|
-
capability=
|
|
194
|
-
name=
|
|
195
|
-
skill=
|
|
196
|
-
task=
|
|
247
|
+
capability=ff.get("capability"),
|
|
248
|
+
name=ff.get("name"),
|
|
249
|
+
skill=ff.get("skill"),
|
|
250
|
+
task=ff.get("task")
|
|
197
251
|
)
|
|
198
252
|
|
|
199
253
|
def getFeedback(
|
|
@@ -210,14 +264,14 @@ class FeedbackManager:
|
|
|
210
264
|
except Exception as e:
|
|
211
265
|
logger.debug(f"Indexer/subgraph get_feedback failed, falling back to blockchain: {e}")
|
|
212
266
|
return self._get_feedback_from_blockchain(agentId, clientAddress, feedbackIndex)
|
|
213
|
-
|
|
267
|
+
|
|
214
268
|
if self.subgraph_client:
|
|
215
269
|
try:
|
|
216
270
|
return self._get_feedback_from_subgraph(agentId, clientAddress, feedbackIndex)
|
|
217
271
|
except Exception as e:
|
|
218
272
|
logger.debug(f"Subgraph get feedback failed, falling back to blockchain: {e}")
|
|
219
273
|
return self._get_feedback_from_blockchain(agentId, clientAddress, feedbackIndex)
|
|
220
|
-
|
|
274
|
+
|
|
221
275
|
return self._get_feedback_from_blockchain(agentId, clientAddress, feedbackIndex)
|
|
222
276
|
|
|
223
277
|
def _get_feedback_from_subgraph(
|
|
@@ -267,9 +321,9 @@ class FeedbackManager:
|
|
|
267
321
|
tag1 = feedback_data.get('tag1') or feedback_file.get('tag1')
|
|
268
322
|
tag2 = feedback_data.get('tag2') or feedback_file.get('tag2')
|
|
269
323
|
if isinstance(tag1, str) and tag1:
|
|
270
|
-
|
|
324
|
+
tags.append(tag1)
|
|
271
325
|
if isinstance(tag2, str) and tag2:
|
|
272
|
-
|
|
326
|
+
tags.append(tag2)
|
|
273
327
|
|
|
274
328
|
return Feedback(
|
|
275
329
|
id=Feedback.create_id(agentId, clientAddress, feedbackIndex), # create_id now normalizes
|
|
@@ -287,7 +341,8 @@ class FeedbackManager:
|
|
|
287
341
|
'txHash': feedback_file.get('proofOfPaymentTxHash'),
|
|
288
342
|
} if feedback_file.get('proofOfPaymentFromAddress') else None,
|
|
289
343
|
fileURI=feedback_data.get('feedbackURI') or feedback_data.get('feedbackUri'), # Handle both old and new field names
|
|
290
|
-
endpoint
|
|
344
|
+
# Prefer on-chain endpoint; fall back to off-chain file endpoint if missing
|
|
345
|
+
endpoint=feedback_data.get('endpoint') or feedback_file.get('endpoint'),
|
|
291
346
|
createdAt=feedback_data.get('createdAt', int(time.time())),
|
|
292
347
|
answers=answers,
|
|
293
348
|
isRevoked=feedback_data.get('isRevoked', False),
|
|
@@ -509,9 +564,9 @@ class FeedbackManager:
|
|
|
509
564
|
tag1 = fb_data.get('tag1') or feedback_file.get('tag1')
|
|
510
565
|
tag2 = fb_data.get('tag2') or feedback_file.get('tag2')
|
|
511
566
|
if isinstance(tag1, str) and tag1:
|
|
512
|
-
|
|
567
|
+
tags_list.append(tag1)
|
|
513
568
|
if isinstance(tag2, str) and tag2:
|
|
514
|
-
|
|
569
|
+
tags_list.append(tag2)
|
|
515
570
|
|
|
516
571
|
# Parse agentId from feedback ID
|
|
517
572
|
feedback_id = fb_data['id']
|
agent0_sdk/core/indexer.py
CHANGED
|
@@ -1094,7 +1094,8 @@ class AgentIndexer:
|
|
|
1094
1094
|
'txHash': feedback_file.get('proofOfPaymentTxHash'),
|
|
1095
1095
|
} if feedback_file.get('proofOfPaymentFromAddress') else None,
|
|
1096
1096
|
fileURI=feedback_data.get('feedbackURI') or feedback_data.get('feedbackUri'), # Handle both old and new field names
|
|
1097
|
-
endpoint
|
|
1097
|
+
# Prefer on-chain endpoint; fall back to off-chain file endpoint if missing
|
|
1098
|
+
endpoint=feedback_data.get('endpoint') or feedback_file.get('endpoint'),
|
|
1098
1099
|
createdAt=feedback_data.get('createdAt', int(time.time())),
|
|
1099
1100
|
answers=answers,
|
|
1100
1101
|
isRevoked=feedback_data.get('isRevoked', False),
|
agent0_sdk/core/ipfs_client.py
CHANGED
|
@@ -160,7 +160,7 @@ class IPFSClient:
|
|
|
160
160
|
# add_str returns the CID directly as a string
|
|
161
161
|
return result if isinstance(result, str) else result['Hash']
|
|
162
162
|
|
|
163
|
-
def _pin_to_pinata(self, data: str) -> str:
|
|
163
|
+
def _pin_to_pinata(self, data: str, file_name: str = "file.json") -> str:
|
|
164
164
|
"""Pin data to Pinata using JWT authentication with v3 API."""
|
|
165
165
|
import requests
|
|
166
166
|
import tempfile
|
|
@@ -185,7 +185,7 @@ class IPFSClient:
|
|
|
185
185
|
# Prepare the file for upload with public network setting
|
|
186
186
|
with open(temp_path, 'rb') as file:
|
|
187
187
|
files = {
|
|
188
|
-
'file': (
|
|
188
|
+
'file': (file_name, file, 'application/json')
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
# Add network parameter to make file public
|
|
@@ -233,8 +233,9 @@ class IPFSClient:
|
|
|
233
233
|
|
|
234
234
|
def add(self, data: str, **kwargs) -> str:
|
|
235
235
|
"""Add data to IPFS and return CID."""
|
|
236
|
+
file_name = kwargs.pop("file_name", None)
|
|
236
237
|
if self.pinata_enabled:
|
|
237
|
-
return self._pin_to_pinata(data)
|
|
238
|
+
return self._pin_to_pinata(data, file_name=file_name or "file.json")
|
|
238
239
|
elif self.filecoin_pin_enabled:
|
|
239
240
|
# Create temporary file for Filecoin Pin
|
|
240
241
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
|
|
@@ -251,11 +252,12 @@ class IPFSClient:
|
|
|
251
252
|
|
|
252
253
|
def add_file(self, filepath: str, **kwargs) -> str:
|
|
253
254
|
"""Add file to IPFS and return CID."""
|
|
255
|
+
file_name = kwargs.pop("file_name", None)
|
|
254
256
|
if self.pinata_enabled:
|
|
255
257
|
# Read file and send to Pinata
|
|
256
258
|
with open(filepath, 'r') as f:
|
|
257
259
|
data = f.read()
|
|
258
|
-
return self._pin_to_pinata(data)
|
|
260
|
+
return self._pin_to_pinata(data, file_name=file_name or "file.json")
|
|
259
261
|
elif self.filecoin_pin_enabled:
|
|
260
262
|
return self._pin_to_filecoin(filepath)
|
|
261
263
|
else:
|
|
@@ -332,7 +334,7 @@ class IPFSClient:
|
|
|
332
334
|
def addRegistrationFile(self, registrationFile: "RegistrationFile", chainId: Optional[int] = None, identityRegistryAddress: Optional[str] = None, **kwargs) -> str:
|
|
333
335
|
"""Add registration file to IPFS and return CID."""
|
|
334
336
|
data = registrationFile.to_dict(chain_id=chainId, identity_registry_address=identityRegistryAddress)
|
|
335
|
-
return self.add_json(data, **kwargs)
|
|
337
|
+
return self.add_json(data, file_name="agent-registration.json", **kwargs)
|
|
336
338
|
|
|
337
339
|
def getRegistrationFile(self, cid: str) -> "RegistrationFile":
|
|
338
340
|
"""Get registration file from IPFS by CID."""
|
|
@@ -342,7 +344,7 @@ class IPFSClient:
|
|
|
342
344
|
|
|
343
345
|
def addFeedbackFile(self, feedbackData: Dict[str, Any], **kwargs) -> str:
|
|
344
346
|
"""Add feedback file to IPFS and return CID."""
|
|
345
|
-
return self.add_json(feedbackData, **kwargs)
|
|
347
|
+
return self.add_json(feedbackData, file_name="feedback.json", **kwargs)
|
|
346
348
|
|
|
347
349
|
def getFeedbackFile(self, cid: str) -> Dict[str, Any]:
|
|
348
350
|
"""Get feedback file from IPFS by CID."""
|
agent0_sdk/core/sdk.py
CHANGED
|
@@ -491,111 +491,8 @@ class SDK:
|
|
|
491
491
|
|
|
492
492
|
return self.indexer.search_agents(params, sort, page_size, cursor)
|
|
493
493
|
|
|
494
|
-
# Feedback methods
|
|
495
|
-
def prepareFeedback(
|
|
496
|
-
self,
|
|
497
|
-
agentId: AgentId,
|
|
498
|
-
score: Optional[int] = None, # 0-100
|
|
499
|
-
tags: List[str] = None,
|
|
500
|
-
text: Optional[str] = None,
|
|
501
|
-
capability: Optional[str] = None,
|
|
502
|
-
name: Optional[str] = None,
|
|
503
|
-
skill: Optional[str] = None,
|
|
504
|
-
task: Optional[str] = None,
|
|
505
|
-
context: Optional[Dict[str, Any]] = None,
|
|
506
|
-
proofOfPayment: Optional[Dict[str, Any]] = None,
|
|
507
|
-
extra: Optional[Dict[str, Any]] = None,
|
|
508
|
-
) -> Dict[str, Any]:
|
|
509
|
-
"""Prepare feedback file (local file/object)."""
|
|
510
|
-
return self.feedback_manager.prepareFeedback(
|
|
511
|
-
agentId=agentId,
|
|
512
|
-
score=score,
|
|
513
|
-
tags=tags,
|
|
514
|
-
text=text,
|
|
515
|
-
capability=capability,
|
|
516
|
-
name=name,
|
|
517
|
-
skill=skill,
|
|
518
|
-
task=task,
|
|
519
|
-
context=context,
|
|
520
|
-
proofOfPayment=proofOfPayment,
|
|
521
|
-
extra=extra
|
|
522
|
-
)
|
|
523
|
-
|
|
524
|
-
def giveFeedback(
|
|
525
|
-
self,
|
|
526
|
-
agentId: AgentId,
|
|
527
|
-
feedbackFile: Dict[str, Any],
|
|
528
|
-
idem: Optional[IdemKey] = None,
|
|
529
|
-
feedback_auth: Optional[bytes] = None,
|
|
530
|
-
) -> Feedback:
|
|
531
|
-
"""Give feedback (maps 8004 endpoint)."""
|
|
532
|
-
return self.feedback_manager.giveFeedback(
|
|
533
|
-
agentId=agentId,
|
|
534
|
-
feedbackFile=feedbackFile,
|
|
535
|
-
idem=idem,
|
|
536
|
-
feedback_auth=feedback_auth
|
|
537
|
-
)
|
|
538
|
-
|
|
539
|
-
def getFeedback(self, feedbackId: str) -> Feedback:
|
|
540
|
-
"""Get single feedback by ID string."""
|
|
541
|
-
# Parse feedback ID
|
|
542
|
-
agentId, clientAddress, feedbackIndex = Feedback.from_id_string(feedbackId)
|
|
543
|
-
return self.feedback_manager.getFeedback(agentId, clientAddress, feedbackIndex)
|
|
544
|
-
|
|
545
|
-
def searchFeedback(
|
|
546
|
-
self,
|
|
547
|
-
agentId: AgentId,
|
|
548
|
-
reviewers: Optional[List[Address]] = None,
|
|
549
|
-
tags: Optional[List[str]] = None,
|
|
550
|
-
capabilities: Optional[List[str]] = None,
|
|
551
|
-
skills: Optional[List[str]] = None,
|
|
552
|
-
tasks: Optional[List[str]] = None,
|
|
553
|
-
names: Optional[List[str]] = None,
|
|
554
|
-
minScore: Optional[int] = None,
|
|
555
|
-
maxScore: Optional[int] = None,
|
|
556
|
-
include_revoked: bool = False,
|
|
557
|
-
first: int = 100,
|
|
558
|
-
skip: int = 0,
|
|
559
|
-
) -> List[Feedback]:
|
|
560
|
-
"""Search feedback for an agent."""
|
|
561
|
-
return self.feedback_manager.searchFeedback(
|
|
562
|
-
agentId=agentId,
|
|
563
|
-
clientAddresses=reviewers,
|
|
564
|
-
tags=tags,
|
|
565
|
-
capabilities=capabilities,
|
|
566
|
-
skills=skills,
|
|
567
|
-
tasks=tasks,
|
|
568
|
-
names=names,
|
|
569
|
-
minScore=minScore,
|
|
570
|
-
maxScore=maxScore,
|
|
571
|
-
include_revoked=include_revoked,
|
|
572
|
-
first=first,
|
|
573
|
-
skip=skip
|
|
574
|
-
)
|
|
575
|
-
|
|
576
|
-
def revokeFeedback(
|
|
577
|
-
self,
|
|
578
|
-
feedbackId: str,
|
|
579
|
-
reason: Optional[str] = None,
|
|
580
|
-
idem: Optional[IdemKey] = None,
|
|
581
|
-
) -> Dict[str, Any]:
|
|
582
|
-
"""Revoke feedback."""
|
|
583
|
-
# Parse feedback ID
|
|
584
|
-
agentId, clientAddress, feedbackIndex = Feedback.from_id_string(feedbackId)
|
|
585
|
-
return self.feedback_manager.revokeFeedback(agentId, feedbackIndex)
|
|
586
|
-
|
|
587
|
-
def appendResponse(
|
|
588
|
-
self,
|
|
589
|
-
feedbackId: str,
|
|
590
|
-
response: Dict[str, Any],
|
|
591
|
-
idem: Optional[IdemKey] = None,
|
|
592
|
-
) -> Feedback:
|
|
593
|
-
"""Append a response/follow-up to existing feedback."""
|
|
594
|
-
# Parse feedback ID
|
|
595
|
-
agentId, clientAddress, feedbackIndex = Feedback.from_id_string(feedbackId)
|
|
596
|
-
return self.feedback_manager.appendResponse(agentId, clientAddress, feedbackIndex, response)
|
|
494
|
+
# Feedback methods are defined later in this class (single authoritative API).
|
|
597
495
|
|
|
598
|
-
|
|
599
496
|
def searchAgentsByReputation(
|
|
600
497
|
self,
|
|
601
498
|
agents: Optional[List[AgentId]] = None,
|
|
@@ -884,46 +781,35 @@ class SDK:
|
|
|
884
781
|
}
|
|
885
782
|
|
|
886
783
|
# Feedback methods - delegate to feedback_manager
|
|
887
|
-
def
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
"""Sign feedback authorization for a client."""
|
|
895
|
-
return self.feedback_manager.signFeedbackAuth(
|
|
896
|
-
agentId, clientAddress, indexLimit, expiryHours
|
|
897
|
-
)
|
|
898
|
-
|
|
899
|
-
def prepareFeedback(
|
|
900
|
-
self,
|
|
901
|
-
agentId: "AgentId",
|
|
902
|
-
score: Optional[int] = None, # 0-100
|
|
903
|
-
tags: List[str] = None,
|
|
904
|
-
text: Optional[str] = None,
|
|
905
|
-
capability: Optional[str] = None,
|
|
906
|
-
name: Optional[str] = None,
|
|
907
|
-
skill: Optional[str] = None,
|
|
908
|
-
task: Optional[str] = None,
|
|
909
|
-
context: Optional[Dict[str, Any]] = None,
|
|
910
|
-
proofOfPayment: Optional[Dict[str, Any]] = None,
|
|
911
|
-
extra: Optional[Dict[str, Any]] = None,
|
|
912
|
-
) -> Dict[str, Any]:
|
|
913
|
-
"""Prepare feedback file (local file/object) according to spec."""
|
|
914
|
-
return self.feedback_manager.prepareFeedback(
|
|
915
|
-
agentId, score, tags, text, capability, name, skill, task, context, proofOfPayment, extra
|
|
916
|
-
)
|
|
784
|
+
def prepareFeedbackFile(self, input: Dict[str, Any]) -> Dict[str, Any]:
|
|
785
|
+
"""Prepare an off-chain feedback file payload.
|
|
786
|
+
|
|
787
|
+
This is intentionally off-chain-only; it does not attempt to represent
|
|
788
|
+
the on-chain fields (score/tag1/tag2/endpoint-on-chain).
|
|
789
|
+
"""
|
|
790
|
+
return self.feedback_manager.prepareFeedbackFile(input)
|
|
917
791
|
|
|
918
792
|
def giveFeedback(
|
|
919
793
|
self,
|
|
920
794
|
agentId: "AgentId",
|
|
921
|
-
|
|
922
|
-
|
|
795
|
+
score: int,
|
|
796
|
+
tag1: Optional[str] = None,
|
|
797
|
+
tag2: Optional[str] = None,
|
|
798
|
+
endpoint: Optional[str] = None,
|
|
799
|
+
feedbackFile: Optional[Dict[str, Any]] = None,
|
|
923
800
|
) -> "Feedback":
|
|
924
|
-
"""Give feedback (
|
|
801
|
+
"""Give feedback (on-chain first; optional off-chain file upload).
|
|
802
|
+
|
|
803
|
+
- If feedbackFile is None: submit on-chain only (no upload even if IPFS is configured).
|
|
804
|
+
- If feedbackFile is provided: requires IPFS configured; uploads and commits URI/hash on-chain.
|
|
805
|
+
"""
|
|
925
806
|
return self.feedback_manager.giveFeedback(
|
|
926
|
-
agentId,
|
|
807
|
+
agentId=agentId,
|
|
808
|
+
score=score,
|
|
809
|
+
tag1=tag1,
|
|
810
|
+
tag2=tag2,
|
|
811
|
+
endpoint=endpoint,
|
|
812
|
+
feedbackFile=feedbackFile,
|
|
927
813
|
)
|
|
928
814
|
|
|
929
815
|
def getFeedback(
|
|
@@ -936,6 +822,37 @@ class SDK:
|
|
|
936
822
|
return self.feedback_manager.getFeedback(
|
|
937
823
|
agentId, clientAddress, feedbackIndex
|
|
938
824
|
)
|
|
825
|
+
|
|
826
|
+
def searchFeedback(
|
|
827
|
+
self,
|
|
828
|
+
agentId: "AgentId",
|
|
829
|
+
reviewers: Optional[List["Address"]] = None,
|
|
830
|
+
tags: Optional[List[str]] = None,
|
|
831
|
+
capabilities: Optional[List[str]] = None,
|
|
832
|
+
skills: Optional[List[str]] = None,
|
|
833
|
+
tasks: Optional[List[str]] = None,
|
|
834
|
+
names: Optional[List[str]] = None,
|
|
835
|
+
minScore: Optional[int] = None,
|
|
836
|
+
maxScore: Optional[int] = None,
|
|
837
|
+
include_revoked: bool = False,
|
|
838
|
+
first: int = 100,
|
|
839
|
+
skip: int = 0,
|
|
840
|
+
) -> List["Feedback"]:
|
|
841
|
+
"""Search feedback for an agent."""
|
|
842
|
+
return self.feedback_manager.searchFeedback(
|
|
843
|
+
agentId=agentId,
|
|
844
|
+
clientAddresses=reviewers,
|
|
845
|
+
tags=tags,
|
|
846
|
+
capabilities=capabilities,
|
|
847
|
+
skills=skills,
|
|
848
|
+
tasks=tasks,
|
|
849
|
+
names=names,
|
|
850
|
+
minScore=minScore,
|
|
851
|
+
maxScore=maxScore,
|
|
852
|
+
include_revoked=include_revoked,
|
|
853
|
+
first=first,
|
|
854
|
+
skip=skip,
|
|
855
|
+
)
|
|
939
856
|
|
|
940
857
|
def revokeFeedback(
|
|
941
858
|
self,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent0-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Python SDK for agent portability, discovery and trust based on ERC-8004
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Agent0 Team <team@ag0.xyz>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
8
|
Copyright (c) 2025 Marco De Rossi
|
|
@@ -76,7 +76,7 @@ Agent0 is the SDK for agentic economies. It enables agents to register, advertis
|
|
|
76
76
|
|
|
77
77
|
## What Does Agent0 SDK Do?
|
|
78
78
|
|
|
79
|
-
Agent0 SDK
|
|
79
|
+
Agent0 SDK enables you to:
|
|
80
80
|
|
|
81
81
|
- **Create and manage agent identities** - Register your AI agent on-chain with a unique identity, configure presentation fields (name, description, image), set wallet addresses, and manage trust models with x402 support
|
|
82
82
|
- **Advertise agent capabilities** - Publish MCP and A2A endpoints, with automated extraction of MCP tools and A2A skills from endpoints
|
|
@@ -86,11 +86,7 @@ Agent0 SDK v0.31 enables you to:
|
|
|
86
86
|
- **Cross-chain registration** - One-line registration with IPFS nodes, Pinata, Filecoin, or HTTP URIs
|
|
87
87
|
- **Public indexing** - Subgraph indexing both on-chain and IPFS data for fast search and retrieval
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Agent0 SDK v0.31 is in **alpha** with bugs and is not production ready. We're actively testing and improving it.
|
|
92
|
-
|
|
93
|
-
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco.derossi@consensys.net
|
|
89
|
+
**Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [Agent0 channel](https://t.me/agent0kitchen) | Email: team@ag0.xyz
|
|
94
90
|
|
|
95
91
|
## Installation
|
|
96
92
|
|
|
@@ -156,11 +152,6 @@ agent.addSkill("natural_language_processing/natural_language_generation/summariz
|
|
|
156
152
|
agent.addDomain("finance_and_business/investment_services", validate_oasf=True)
|
|
157
153
|
agent.addDomain("technology/data_science/data_science", validate_oasf=True)
|
|
158
154
|
|
|
159
|
-
# Configure wallet and trust
|
|
160
|
-
# Note: agentWallet is an on-chain verified attribute. setAgentWallet() is on-chain only.
|
|
161
|
-
# EOAs: the NEW wallet must sign an EIP-712 message. If you pass new_wallet_signer, the SDK will
|
|
162
|
-
# build + sign the typed data automatically.
|
|
163
|
-
# If the current SDK signer address matches the new wallet, it can auto-sign without new_wallet_signer.
|
|
164
155
|
agent.setTrust(reputation=True, cryptoEconomic=True)
|
|
165
156
|
|
|
166
157
|
# Add metadata and set status
|
|
@@ -222,19 +213,31 @@ agent_summary = sdk.getAgent("11155111:123")
|
|
|
222
213
|
### 5. Give and Retrieve Feedback
|
|
223
214
|
|
|
224
215
|
```python
|
|
225
|
-
#
|
|
226
|
-
|
|
216
|
+
# On-chain-only feedback (no off-chain upload, even if IPFS is configured)
|
|
217
|
+
feedback = sdk.giveFeedback(
|
|
227
218
|
agentId="11155111:123",
|
|
228
219
|
score=85, # 0-100 (mandatory)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
name="code_generation", # Optional: MCP tool name
|
|
233
|
-
skill="python" # Optional: A2A skill
|
|
220
|
+
tag1="data_analyst", # Optional: tags are strings
|
|
221
|
+
tag2="finance",
|
|
222
|
+
endpoint="https://example.com/endpoint", # Optional: saved on-chain
|
|
234
223
|
)
|
|
235
224
|
|
|
236
|
-
#
|
|
237
|
-
|
|
225
|
+
# Rich feedback (optional off-chain file + on-chain fields)
|
|
226
|
+
feedback_file = sdk.prepareFeedbackFile({
|
|
227
|
+
"capability": "tools", # Optional: MCP capability
|
|
228
|
+
"name": "code_generation", # Optional: MCP tool name
|
|
229
|
+
"skill": "python", # Optional: A2A skill
|
|
230
|
+
"text": "Great agent!", # Optional
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
feedback = sdk.giveFeedback(
|
|
234
|
+
agentId="11155111:123",
|
|
235
|
+
score=85,
|
|
236
|
+
tag1="data_analyst",
|
|
237
|
+
tag2="finance",
|
|
238
|
+
endpoint="https://example.com/endpoint",
|
|
239
|
+
feedbackFile=feedback_file, # If provided, requires IPFS configured
|
|
240
|
+
)
|
|
238
241
|
|
|
239
242
|
# Search feedback
|
|
240
243
|
results = sdk.searchFeedback(
|
|
@@ -314,7 +317,7 @@ OASF skills and domains appear in your agent's registration file:
|
|
|
314
317
|
{
|
|
315
318
|
"name": "OASF",
|
|
316
319
|
"endpoint": "https://github.com/agntcy/oasf/",
|
|
317
|
-
"version": "
|
|
320
|
+
"version": "0.8",
|
|
318
321
|
"skills": [
|
|
319
322
|
"advanced_reasoning_planning/strategic_planning",
|
|
320
323
|
"data_engineering/data_transformation_pipeline"
|
|
@@ -361,6 +364,9 @@ Complete working examples are available in the `tests/` directory:
|
|
|
361
364
|
- `test_feedback.py` - Complete feedback flow with IPFS storage
|
|
362
365
|
- `test_search.py` - Agent search and discovery
|
|
363
366
|
- `test_transfer.py` - Agent ownership transfer
|
|
367
|
+
- `test_oasf_management.py` - OASF skills/domains management (unit tests)
|
|
368
|
+
- `test_real_public_servers.py` - Endpoint crawler against real public MCP/A2A servers
|
|
369
|
+
- `test_multi_chain.py` - Multi-chain read-only operations (subgraph-based)
|
|
364
370
|
|
|
365
371
|
## Documentation
|
|
366
372
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
agent0_sdk/__init__.py,sha256=qmIKaQIVmgJk0tOa-kGdj0qxdTKdb6msPnrIPX0SO-g,919
|
|
2
|
+
agent0_sdk/core/agent.py,sha256=NJo0pjigXznP0zDIrpryrL7pMj5bVvZIhfv4abKtUKk,45157
|
|
3
|
+
agent0_sdk/core/contracts.py,sha256=N7lN29zgV_sfValX8515OUm1Lvu6O185gK863dFPCj0,21717
|
|
4
|
+
agent0_sdk/core/endpoint_crawler.py,sha256=QBkFc3tBSQqHj6PtSTZ5D3_HVB00KJZJdxE3uYpI9po,13611
|
|
5
|
+
agent0_sdk/core/feedback_manager.py,sha256=RFl9EYa-GtLahYatIzMf-IOO_X3oLTCk5B6UH8CM_Ic,40704
|
|
6
|
+
agent0_sdk/core/indexer.py,sha256=09NhrPM5dxaBWOsVgBwjzJFpg9Bg9hAastc2YQ0UmHM,70447
|
|
7
|
+
agent0_sdk/core/ipfs_client.py,sha256=17XXMpJgLWhcNUSkmduAZt409c8oJXlj9C_eTGVk-Io,14185
|
|
8
|
+
agent0_sdk/core/models.py,sha256=1BSAX2LVbw0kL_qHK7DxBrIFx8PF3wQvzkzblcQTMUg,12042
|
|
9
|
+
agent0_sdk/core/oasf_validator.py,sha256=ZOtYYzQd7cJj3eJegi7Ch5ydoapJEjaJSxMvwzKSp5o,2980
|
|
10
|
+
agent0_sdk/core/sdk.py,sha256=JhYBNj78JxGhPHeOVl9atdxDZqInnGKy2D5DylO4ImU,38223
|
|
11
|
+
agent0_sdk/core/subgraph_client.py,sha256=VSK9gCB5uYc2OqAVQ659IgeF0N-tXwxPUbv7NK8Kz0U,29575
|
|
12
|
+
agent0_sdk/core/web3_client.py,sha256=h7s-Al3E1xfbb3QNcPvmQBotKJRg23Jm9xot4emr-hU,12283
|
|
13
|
+
agent0_sdk/taxonomies/all_domains.json,sha256=buM8_6mpY8_AMbBIPzM-gtu14Tl30QDmhuQxxrlJU4c,74625
|
|
14
|
+
agent0_sdk/taxonomies/all_skills.json,sha256=WVsutw3fqoj1jfDPru3CyWTr1kc1a5-EhBOWPfXnEi8,47483
|
|
15
|
+
agent0_sdk-1.0.2.dist-info/licenses/LICENSE,sha256=rhZZbZm_Ovz4Oa9LNQ-ms8a1tA36wWh90ZkC0OR7WMw,1072
|
|
16
|
+
agent0_sdk-1.0.2.dist-info/METADATA,sha256=llO2PMTI8QMCcz-Lae0EjqlB9gZ6v_gwQfbGhVxnM24,14565
|
|
17
|
+
agent0_sdk-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
agent0_sdk-1.0.2.dist-info/top_level.txt,sha256=p4520WUKNfhU0lVWJgkrB_jdeUfvHSY3K18k4oYLNfI,11
|
|
19
|
+
agent0_sdk-1.0.2.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
agent0_sdk/__init__.py,sha256=kzO10wMLu-eClp-rKDuUJg9y8DAkSxoLdbcaTSKocKk,919
|
|
2
|
-
agent0_sdk/core/agent.py,sha256=L8pDTXUWZ5ZmFgGjBwdheKTvMcGu9SlUP9MQD9TQ0MU,45061
|
|
3
|
-
agent0_sdk/core/contracts.py,sha256=euFfjnmpYHNfzzQFvYTvSI-xJGgzFTo2CNny6YaUKTg,21618
|
|
4
|
-
agent0_sdk/core/endpoint_crawler.py,sha256=QBkFc3tBSQqHj6PtSTZ5D3_HVB00KJZJdxE3uYpI9po,13611
|
|
5
|
-
agent0_sdk/core/feedback_manager.py,sha256=ndGROPISrQvfKjwrWiB_xJ9QIh0cLs4oHh666Ru-A_8,37650
|
|
6
|
-
agent0_sdk/core/indexer.py,sha256=BUL4QbbL9sN8eZ1osUdIn_Kgj-MF0SET8RtjbBERQm0,70326
|
|
7
|
-
agent0_sdk/core/ipfs_client.py,sha256=fml1ai1BdBkgb95xAkf-ft8QsahV1HL30hBYRz7rQwI,13929
|
|
8
|
-
agent0_sdk/core/models.py,sha256=1BSAX2LVbw0kL_qHK7DxBrIFx8PF3wQvzkzblcQTMUg,12042
|
|
9
|
-
agent0_sdk/core/oasf_validator.py,sha256=ZOtYYzQd7cJj3eJegi7Ch5ydoapJEjaJSxMvwzKSp5o,2980
|
|
10
|
-
agent0_sdk/core/sdk.py,sha256=c9vSKTer50aJr8VcJ6huj6N1pTRwCUtbCxl5G_5oXhk,40955
|
|
11
|
-
agent0_sdk/core/subgraph_client.py,sha256=VSK9gCB5uYc2OqAVQ659IgeF0N-tXwxPUbv7NK8Kz0U,29575
|
|
12
|
-
agent0_sdk/core/web3_client.py,sha256=h7s-Al3E1xfbb3QNcPvmQBotKJRg23Jm9xot4emr-hU,12283
|
|
13
|
-
agent0_sdk/taxonomies/all_domains.json,sha256=buM8_6mpY8_AMbBIPzM-gtu14Tl30QDmhuQxxrlJU4c,74625
|
|
14
|
-
agent0_sdk/taxonomies/all_skills.json,sha256=WVsutw3fqoj1jfDPru3CyWTr1kc1a5-EhBOWPfXnEi8,47483
|
|
15
|
-
agent0_sdk-1.0.0.dist-info/licenses/LICENSE,sha256=rhZZbZm_Ovz4Oa9LNQ-ms8a1tA36wWh90ZkC0OR7WMw,1072
|
|
16
|
-
agent0_sdk-1.0.0.dist-info/METADATA,sha256=N42e7yZDJiRjDhLhCbzgLPV2mNK45a_zmN-fz1wMD18,14555
|
|
17
|
-
agent0_sdk-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
-
agent0_sdk-1.0.0.dist-info/top_level.txt,sha256=p4520WUKNfhU0lVWJgkrB_jdeUfvHSY3K18k4oYLNfI,11
|
|
19
|
-
agent0_sdk-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|