agent0-sdk 1.2.0__py3-none-any.whl → 1.4.1__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 +6 -1
- agent0_sdk/core/agent.py +232 -180
- agent0_sdk/core/contracts.py +13 -7
- agent0_sdk/core/feedback_manager.py +98 -55
- agent0_sdk/core/indexer.py +73 -19
- agent0_sdk/core/models.py +4 -3
- agent0_sdk/core/sdk.py +42 -14
- agent0_sdk/core/subgraph_client.py +9 -3
- agent0_sdk/core/transaction_handle.py +71 -0
- agent0_sdk/core/value_encoding.py +3 -3
- agent0_sdk/core/web3_client.py +44 -4
- {agent0_sdk-1.2.0.dist-info → agent0_sdk-1.4.1.dist-info}/METADATA +26 -10
- agent0_sdk-1.4.1.dist-info/RECORD +21 -0
- {agent0_sdk-1.2.0.dist-info → agent0_sdk-1.4.1.dist-info}/WHEEL +1 -1
- agent0_sdk-1.2.0.dist-info/RECORD +0 -20
- {agent0_sdk-1.2.0.dist-info → agent0_sdk-1.4.1.dist-info}/licenses/LICENSE +0 -0
- {agent0_sdk-1.2.0.dist-info → agent0_sdk-1.4.1.dist-info}/top_level.txt +0 -0
agent0_sdk/core/contracts.py
CHANGED
|
@@ -159,7 +159,7 @@ IDENTITY_REGISTRY_ABI = [
|
|
|
159
159
|
{"internalType": "uint256", "name": "agentId", "type": "uint256"}
|
|
160
160
|
],
|
|
161
161
|
"name": "getAgentWallet",
|
|
162
|
-
"outputs": [{"internalType": "
|
|
162
|
+
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
|
|
163
163
|
"stateMutability": "view",
|
|
164
164
|
"type": "function"
|
|
165
165
|
},
|
|
@@ -231,7 +231,7 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
231
231
|
{
|
|
232
232
|
"inputs": [
|
|
233
233
|
{"internalType": "uint256", "name": "agentId", "type": "uint256"},
|
|
234
|
-
{"internalType": "
|
|
234
|
+
{"internalType": "int128", "name": "value", "type": "int128"},
|
|
235
235
|
{"internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
|
|
236
236
|
{"internalType": "string", "name": "tag1", "type": "string"},
|
|
237
237
|
{"internalType": "string", "name": "tag2", "type": "string"},
|
|
@@ -285,7 +285,7 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
285
285
|
],
|
|
286
286
|
"name": "readFeedback",
|
|
287
287
|
"outputs": [
|
|
288
|
-
{"internalType": "
|
|
288
|
+
{"internalType": "int128", "name": "value", "type": "int128"},
|
|
289
289
|
{"internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
|
|
290
290
|
{"internalType": "string", "name": "tag1", "type": "string"},
|
|
291
291
|
{"internalType": "string", "name": "tag2", "type": "string"},
|
|
@@ -304,7 +304,7 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
304
304
|
"name": "getSummary",
|
|
305
305
|
"outputs": [
|
|
306
306
|
{"internalType": "uint64", "name": "count", "type": "uint64"},
|
|
307
|
-
{"internalType": "
|
|
307
|
+
{"internalType": "int128", "name": "summaryValue", "type": "int128"},
|
|
308
308
|
{"internalType": "uint8", "name": "summaryValueDecimals", "type": "uint8"}
|
|
309
309
|
],
|
|
310
310
|
"stateMutability": "view",
|
|
@@ -322,7 +322,7 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
322
322
|
"outputs": [
|
|
323
323
|
{"internalType": "address[]", "name": "clients", "type": "address[]"},
|
|
324
324
|
{"internalType": "uint64[]", "name": "feedbackIndexes", "type": "uint64[]"},
|
|
325
|
-
{"internalType": "
|
|
325
|
+
{"internalType": "int128[]", "name": "values", "type": "int128[]"},
|
|
326
326
|
{"internalType": "uint8[]", "name": "valueDecimals", "type": "uint8[]"},
|
|
327
327
|
{"internalType": "string[]", "name": "tag1s", "type": "string[]"},
|
|
328
328
|
{"internalType": "string[]", "name": "tag2s", "type": "string[]"},
|
|
@@ -358,7 +358,7 @@ REPUTATION_REGISTRY_ABI = [
|
|
|
358
358
|
{"indexed": True, "internalType": "uint256", "name": "agentId", "type": "uint256"},
|
|
359
359
|
{"indexed": True, "internalType": "address", "name": "clientAddress", "type": "address"},
|
|
360
360
|
{"indexed": False, "internalType": "uint64", "name": "feedbackIndex", "type": "uint64"},
|
|
361
|
-
{"indexed": False, "internalType": "
|
|
361
|
+
{"indexed": False, "internalType": "int128", "name": "value", "type": "int128"},
|
|
362
362
|
{"indexed": False, "internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
|
|
363
363
|
{"indexed": True, "internalType": "string", "name": "indexedTag1", "type": "string"},
|
|
364
364
|
{"indexed": False, "internalType": "string", "name": "tag1", "type": "string"},
|
|
@@ -514,6 +514,11 @@ VALIDATION_REGISTRY_ABI = [
|
|
|
514
514
|
# Contract registry for different chains
|
|
515
515
|
# Updated addresses from: https://github.com/erc-8004/erc-8004-contracts
|
|
516
516
|
DEFAULT_REGISTRIES: Dict[int, Dict[str, str]] = {
|
|
517
|
+
1: { # Ethereum Mainnet
|
|
518
|
+
"IDENTITY": "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
519
|
+
"REPUTATION": "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
|
|
520
|
+
# "VALIDATION": "0x...", # Set when deployed/enabled
|
|
521
|
+
},
|
|
517
522
|
11155111: { # Ethereum Sepolia
|
|
518
523
|
"IDENTITY": "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
519
524
|
"REPUTATION": "0x8004B663056A597Dffe9eCcC1965A193B7388713",
|
|
@@ -540,8 +545,9 @@ DEFAULT_REGISTRIES: Dict[int, Dict[str, str]] = {
|
|
|
540
545
|
# Default subgraph URLs for different chains
|
|
541
546
|
# Note: Subgraph URLs may need to be updated when new contracts are deployed
|
|
542
547
|
DEFAULT_SUBGRAPH_URLS: Dict[int, str] = {
|
|
548
|
+
1: "https://gateway.thegraph.com/api/7fd2e7d89ce3ef24cd0d4590298f0b2c/subgraphs/id/FX78UzofJFr5h2Udznv7pZ2uLG1JBbYsPm7eecRSYnty", # Ethereum Mainnet
|
|
543
549
|
11155111: "https://gateway.thegraph.com/api/00a452ad3cd1900273ea62c1bf283f93/subgraphs/id/6wQRC7geo9XYAhckfmfo8kbMRLeWU8KQd3XsJqFKmZLT", # Ethereum Sepolia
|
|
544
550
|
# Other chains temporarily disabled - subgraphs to be updated
|
|
545
551
|
# 84532: "https://gateway.thegraph.com/api/...", # Base Sepolia - To be updated
|
|
546
552
|
# 80002: "https://gateway.thegraph.com/api/...", # Polygon Amoy - To be updated
|
|
547
|
-
}
|
|
553
|
+
}
|
|
@@ -17,6 +17,7 @@ from .models import (
|
|
|
17
17
|
from .web3_client import Web3Client
|
|
18
18
|
from .ipfs_client import IPFSClient
|
|
19
19
|
from .value_encoding import encode_feedback_value, decode_feedback_value
|
|
20
|
+
from .transaction_handle import TransactionHandle
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger(__name__)
|
|
22
23
|
|
|
@@ -73,7 +74,7 @@ class FeedbackManager:
|
|
|
73
74
|
tag2: Optional[str] = None,
|
|
74
75
|
endpoint: Optional[str] = None,
|
|
75
76
|
feedbackFile: Optional[Dict[str, Any]] = None,
|
|
76
|
-
) -> Feedback:
|
|
77
|
+
) -> TransactionHandle[Feedback]:
|
|
77
78
|
"""Give feedback (maps 8004 endpoint)."""
|
|
78
79
|
# Parse agentId into (chainId, tokenId)
|
|
79
80
|
agent_chain_id: Optional[int] = None
|
|
@@ -185,7 +186,7 @@ class FeedbackManager:
|
|
|
185
186
|
"clientAddress": f"eip155:{agent_chain_id}:{clientAddress}",
|
|
186
187
|
"createdAt": created_at,
|
|
187
188
|
# On-chain fields (store raw+decimals for precision)
|
|
188
|
-
"value":
|
|
189
|
+
"value": int(value_raw),
|
|
189
190
|
"valueDecimals": int(value_decimals),
|
|
190
191
|
|
|
191
192
|
# OPTIONAL fields that mirror on-chain
|
|
@@ -220,35 +221,34 @@ class FeedbackManager:
|
|
|
220
221
|
feedbackUri,
|
|
221
222
|
feedbackHash
|
|
222
223
|
)
|
|
223
|
-
|
|
224
|
-
# Wait for transaction confirmation
|
|
225
|
-
receipt = self.web3_client.wait_for_transaction(txHash)
|
|
226
|
-
|
|
227
224
|
except Exception as e:
|
|
228
225
|
raise ValueError(f"Failed to submit feedback to blockchain: {e}")
|
|
229
|
-
|
|
230
|
-
# Create
|
|
226
|
+
|
|
227
|
+
# Create a tx handle; build the Feedback object on confirmation.
|
|
231
228
|
feedbackId = Feedback.create_id(agentId, clientAddress, feedbackIndex)
|
|
232
|
-
|
|
233
229
|
ff: Dict[str, Any] = feedback_file or {}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
230
|
+
|
|
231
|
+
return TransactionHandle(
|
|
232
|
+
web3_client=self.web3_client,
|
|
233
|
+
tx_hash=txHash,
|
|
234
|
+
compute_result=lambda _receipt: Feedback(
|
|
235
|
+
id=feedbackId,
|
|
236
|
+
agentId=agentId,
|
|
237
|
+
reviewer=clientAddress,
|
|
238
|
+
value=decode_feedback_value(value_raw, value_decimals),
|
|
239
|
+
tags=[tag1, tag2] if tag1 or tag2 else [],
|
|
240
|
+
text=ff.get("text"),
|
|
241
|
+
context=ff.get("context"),
|
|
242
|
+
proofOfPayment=ff.get("proofOfPayment"),
|
|
243
|
+
fileURI=feedbackUri if feedbackUri else None,
|
|
244
|
+
endpoint=endpoint_onchain if endpoint_onchain else None,
|
|
245
|
+
createdAt=int(time.time()),
|
|
246
|
+
isRevoked=False,
|
|
247
|
+
capability=ff.get("capability"),
|
|
248
|
+
name=ff.get("name"),
|
|
249
|
+
skill=ff.get("skill"),
|
|
250
|
+
task=ff.get("task"),
|
|
251
|
+
),
|
|
252
252
|
)
|
|
253
253
|
|
|
254
254
|
def getFeedback(
|
|
@@ -412,7 +412,7 @@ class FeedbackManager:
|
|
|
412
412
|
|
|
413
413
|
def searchFeedback(
|
|
414
414
|
self,
|
|
415
|
-
agentId: AgentId,
|
|
415
|
+
agentId: Optional[AgentId] = None,
|
|
416
416
|
clientAddresses: Optional[List[Address]] = None,
|
|
417
417
|
tags: Optional[List[str]] = None,
|
|
418
418
|
capabilities: Optional[List[str]] = None,
|
|
@@ -424,25 +424,68 @@ class FeedbackManager:
|
|
|
424
424
|
include_revoked: bool = False,
|
|
425
425
|
first: int = 100,
|
|
426
426
|
skip: int = 0,
|
|
427
|
+
agents: Optional[List[AgentId]] = None,
|
|
427
428
|
) -> List[Feedback]:
|
|
428
|
-
"""Search feedback
|
|
429
|
+
"""Search feedback.
|
|
430
|
+
|
|
431
|
+
Backwards compatible:
|
|
432
|
+
- `agentId` was previously required; it is now optional.
|
|
433
|
+
|
|
434
|
+
New:
|
|
435
|
+
- `agents` supports searching across multiple agents.
|
|
436
|
+
- If neither `agentId` nor `agents` are provided, the query can still run via subgraph
|
|
437
|
+
using other filters like `clientAddresses` (reviewers), tags, etc.
|
|
438
|
+
"""
|
|
429
439
|
# Use indexer for subgraph queries (unified search interface)
|
|
430
440
|
if self.indexer and self.subgraph_client:
|
|
431
441
|
# Indexer handles subgraph queries for unified search architecture
|
|
432
442
|
# This enables future semantic search capabilities
|
|
433
443
|
return self.indexer.search_feedback(
|
|
434
|
-
agentId,
|
|
435
|
-
|
|
444
|
+
agentId,
|
|
445
|
+
clientAddresses,
|
|
446
|
+
tags,
|
|
447
|
+
capabilities,
|
|
448
|
+
skills,
|
|
449
|
+
tasks,
|
|
450
|
+
names,
|
|
451
|
+
minValue,
|
|
452
|
+
maxValue,
|
|
453
|
+
include_revoked,
|
|
454
|
+
first,
|
|
455
|
+
skip,
|
|
456
|
+
agents=agents,
|
|
436
457
|
)
|
|
437
458
|
|
|
438
459
|
# Fallback: direct subgraph access (if indexer not available)
|
|
439
460
|
if self.subgraph_client:
|
|
440
461
|
return self._search_feedback_subgraph(
|
|
441
|
-
agentId,
|
|
442
|
-
|
|
462
|
+
agentId,
|
|
463
|
+
clientAddresses,
|
|
464
|
+
tags,
|
|
465
|
+
capabilities,
|
|
466
|
+
skills,
|
|
467
|
+
tasks,
|
|
468
|
+
names,
|
|
469
|
+
minValue,
|
|
470
|
+
maxValue,
|
|
471
|
+
include_revoked,
|
|
472
|
+
first,
|
|
473
|
+
skip,
|
|
474
|
+
agents=agents,
|
|
443
475
|
)
|
|
444
476
|
|
|
445
|
-
# Fallback to blockchain
|
|
477
|
+
# Fallback to blockchain (requires a specific agent)
|
|
478
|
+
if not agentId and not agents:
|
|
479
|
+
raise ValueError(
|
|
480
|
+
"searchFeedback requires a subgraph when searching without agentId/agents."
|
|
481
|
+
)
|
|
482
|
+
if not agentId and agents and len(agents) == 1:
|
|
483
|
+
agentId = agents[0]
|
|
484
|
+
if not agentId:
|
|
485
|
+
raise ValueError(
|
|
486
|
+
"Blockchain fallback only supports searching a single agent; provide agentId or a single-item agents=[...]."
|
|
487
|
+
)
|
|
488
|
+
|
|
446
489
|
# Parse agent ID
|
|
447
490
|
if ":" in agentId:
|
|
448
491
|
tokenId = int(agentId.split(":")[-1])
|
|
@@ -505,7 +548,7 @@ class FeedbackManager:
|
|
|
505
548
|
|
|
506
549
|
def _search_feedback_subgraph(
|
|
507
550
|
self,
|
|
508
|
-
agentId: AgentId,
|
|
551
|
+
agentId: Optional[AgentId],
|
|
509
552
|
clientAddresses: Optional[List[Address]],
|
|
510
553
|
tags: Optional[List[str]],
|
|
511
554
|
capabilities: Optional[List[str]],
|
|
@@ -517,11 +560,18 @@ class FeedbackManager:
|
|
|
517
560
|
include_revoked: bool,
|
|
518
561
|
first: int,
|
|
519
562
|
skip: int,
|
|
563
|
+
agents: Optional[List[AgentId]] = None,
|
|
520
564
|
) -> List[Feedback]:
|
|
521
565
|
"""Search feedback using subgraph."""
|
|
566
|
+
merged_agents: Optional[List[AgentId]] = None
|
|
567
|
+
if agents:
|
|
568
|
+
merged_agents = list(agents)
|
|
569
|
+
if agentId:
|
|
570
|
+
merged_agents = (merged_agents or []) + [agentId]
|
|
571
|
+
|
|
522
572
|
# Create SearchFeedbackParams
|
|
523
573
|
params = SearchFeedbackParams(
|
|
524
|
-
agents=
|
|
574
|
+
agents=merged_agents,
|
|
525
575
|
reviewers=clientAddresses,
|
|
526
576
|
tags=tags,
|
|
527
577
|
capabilities=capabilities,
|
|
@@ -613,7 +663,7 @@ class FeedbackManager:
|
|
|
613
663
|
self,
|
|
614
664
|
agentId: AgentId,
|
|
615
665
|
feedbackIndex: int,
|
|
616
|
-
) ->
|
|
666
|
+
) -> TransactionHandle[Feedback]:
|
|
617
667
|
"""Revoke feedback."""
|
|
618
668
|
# Parse agent ID
|
|
619
669
|
if ":" in agentId:
|
|
@@ -630,17 +680,11 @@ class FeedbackManager:
|
|
|
630
680
|
tokenId,
|
|
631
681
|
feedbackIndex
|
|
632
682
|
)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
"agentId": agentId,
|
|
639
|
-
"clientAddress": clientAddress,
|
|
640
|
-
"feedbackIndex": feedbackIndex,
|
|
641
|
-
"status": "revoked"
|
|
642
|
-
}
|
|
643
|
-
|
|
683
|
+
return TransactionHandle(
|
|
684
|
+
web3_client=self.web3_client,
|
|
685
|
+
tx_hash=txHash,
|
|
686
|
+
compute_result=lambda _receipt: self.getFeedback(agentId, clientAddress, feedbackIndex),
|
|
687
|
+
)
|
|
644
688
|
except Exception as e:
|
|
645
689
|
raise ValueError(f"Failed to revoke feedback: {e}")
|
|
646
690
|
|
|
@@ -650,7 +694,7 @@ class FeedbackManager:
|
|
|
650
694
|
clientAddress: Address,
|
|
651
695
|
feedbackIndex: int,
|
|
652
696
|
response: Dict[str, Any],
|
|
653
|
-
) -> Feedback:
|
|
697
|
+
) -> TransactionHandle[Feedback]:
|
|
654
698
|
"""Append a response/follow-up to existing feedback."""
|
|
655
699
|
# Parse agent ID
|
|
656
700
|
if ":" in agentId:
|
|
@@ -681,12 +725,11 @@ class FeedbackManager:
|
|
|
681
725
|
responseUri, # Note: contract uses responseURI but variable name kept for compatibility
|
|
682
726
|
responseHash
|
|
683
727
|
)
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
728
|
+
return TransactionHandle(
|
|
729
|
+
web3_client=self.web3_client,
|
|
730
|
+
tx_hash=txHash,
|
|
731
|
+
compute_result=lambda _receipt: self.getFeedback(agentId, clientAddress, feedbackIndex),
|
|
732
|
+
)
|
|
690
733
|
except Exception as e:
|
|
691
734
|
raise ValueError(f"Failed to append response: {e}")
|
|
692
735
|
|
agent0_sdk/core/indexer.py
CHANGED
|
@@ -433,7 +433,7 @@ class AgentIndexer:
|
|
|
433
433
|
mcpPrompts=reg_file.get('mcpPrompts', []),
|
|
434
434
|
mcpResources=reg_file.get('mcpResources', []),
|
|
435
435
|
active=reg_file.get('active', True),
|
|
436
|
-
x402support=reg_file.get('x402support', False),
|
|
436
|
+
x402support=reg_file.get('x402Support', reg_file.get('x402support', False)),
|
|
437
437
|
extras={}
|
|
438
438
|
)
|
|
439
439
|
|
|
@@ -724,7 +724,7 @@ class AgentIndexer:
|
|
|
724
724
|
"mcpPrompts": reg_file.get('mcpPrompts', []),
|
|
725
725
|
"mcpResources": reg_file.get('mcpResources', []),
|
|
726
726
|
"active": reg_file.get('active', True),
|
|
727
|
-
"x402support": reg_file.get('x402support', False),
|
|
727
|
+
"x402support": reg_file.get('x402Support', reg_file.get('x402support', False)),
|
|
728
728
|
"totalFeedback": agent_data.get('totalFeedback', 0),
|
|
729
729
|
"lastActivity": agent_data.get('lastActivity'),
|
|
730
730
|
"updatedAt": agent_data.get('updatedAt'),
|
|
@@ -871,7 +871,7 @@ class AgentIndexer:
|
|
|
871
871
|
"mcpPrompts": reg_file.get('mcpPrompts', []),
|
|
872
872
|
"mcpResources": reg_file.get('mcpResources', []),
|
|
873
873
|
"active": reg_file.get('active', True),
|
|
874
|
-
"x402support": reg_file.get('x402support', False),
|
|
874
|
+
"x402support": reg_file.get('x402Support', reg_file.get('x402support', False)),
|
|
875
875
|
"totalFeedback": agent.get('totalFeedback', 0),
|
|
876
876
|
"lastActivity": agent.get('lastActivity'),
|
|
877
877
|
"updatedAt": agent.get('updatedAt'),
|
|
@@ -1106,7 +1106,7 @@ class AgentIndexer:
|
|
|
1106
1106
|
|
|
1107
1107
|
def search_feedback(
|
|
1108
1108
|
self,
|
|
1109
|
-
agentId: AgentId,
|
|
1109
|
+
agentId: Optional[AgentId] = None,
|
|
1110
1110
|
clientAddresses: Optional[List[Address]] = None,
|
|
1111
1111
|
tags: Optional[List[str]] = None,
|
|
1112
1112
|
capabilities: Optional[List[str]] = None,
|
|
@@ -1118,29 +1118,77 @@ class AgentIndexer:
|
|
|
1118
1118
|
include_revoked: bool = False,
|
|
1119
1119
|
first: int = 100,
|
|
1120
1120
|
skip: int = 0,
|
|
1121
|
+
agents: Optional[List[AgentId]] = None,
|
|
1121
1122
|
) -> List[Feedback]:
|
|
1122
|
-
"""Search feedback
|
|
1123
|
-
|
|
1124
|
-
|
|
1123
|
+
"""Search feedback via subgraph.
|
|
1124
|
+
|
|
1125
|
+
Backwards compatible:
|
|
1126
|
+
- Previously required `agentId`; it is now optional.
|
|
1127
|
+
|
|
1128
|
+
New:
|
|
1129
|
+
- `agents` supports searching across multiple agents.
|
|
1130
|
+
- If neither `agentId` nor `agents` is provided, subgraph search can still run using
|
|
1131
|
+
other filters (e.g., reviewers / tags).
|
|
1132
|
+
"""
|
|
1133
|
+
|
|
1134
|
+
merged_agents: Optional[List[AgentId]] = None
|
|
1135
|
+
if agents:
|
|
1136
|
+
merged_agents = list(agents)
|
|
1137
|
+
if agentId:
|
|
1138
|
+
merged_agents = (merged_agents or []) + [agentId]
|
|
1139
|
+
|
|
1140
|
+
# Determine chain/subgraph client based on first specified agent (if any)
|
|
1141
|
+
chain_id = None
|
|
1142
|
+
if merged_agents and len(merged_agents) > 0:
|
|
1143
|
+
first_agent = merged_agents[0]
|
|
1144
|
+
chain_id, token_id = self._parse_agent_id(first_agent)
|
|
1125
1145
|
|
|
1126
1146
|
# Get subgraph client for the chain
|
|
1127
1147
|
subgraph_client = None
|
|
1128
|
-
|
|
1129
|
-
|
|
1148
|
+
|
|
1130
1149
|
if chain_id is not None:
|
|
1131
1150
|
subgraph_client = self._get_subgraph_client_for_chain(chain_id)
|
|
1132
1151
|
else:
|
|
1133
|
-
#
|
|
1134
|
-
# Construct full agentId format for subgraph query
|
|
1135
|
-
default_chain_id = self.web3_client.chain_id
|
|
1136
|
-
full_agent_id = f"{default_chain_id}:{token_id}"
|
|
1152
|
+
# If no explicit chainId, use SDK's default subgraph client (if configured).
|
|
1137
1153
|
subgraph_client = self.subgraph_client
|
|
1154
|
+
|
|
1155
|
+
# If we have agent ids but they weren't chain-prefixed, prefix them with default chain id for the subgraph.
|
|
1156
|
+
if merged_agents and chain_id is None:
|
|
1157
|
+
default_chain_id = self.web3_client.chain_id
|
|
1158
|
+
normalized: List[AgentId] = []
|
|
1159
|
+
for aid in merged_agents:
|
|
1160
|
+
if isinstance(aid, str) and ":" in aid:
|
|
1161
|
+
normalized.append(aid)
|
|
1162
|
+
else:
|
|
1163
|
+
normalized.append(f"{default_chain_id}:{int(aid)}")
|
|
1164
|
+
merged_agents = normalized
|
|
1165
|
+
elif merged_agents and chain_id is not None:
|
|
1166
|
+
# Ensure all agent ids are chain-prefixed for the chosen chain
|
|
1167
|
+
normalized = []
|
|
1168
|
+
for aid in merged_agents:
|
|
1169
|
+
if isinstance(aid, str) and ":" in aid:
|
|
1170
|
+
normalized.append(aid)
|
|
1171
|
+
else:
|
|
1172
|
+
normalized.append(f"{chain_id}:{int(aid)}")
|
|
1173
|
+
merged_agents = normalized
|
|
1138
1174
|
|
|
1139
1175
|
# Use subgraph if available (preferred)
|
|
1140
1176
|
if subgraph_client:
|
|
1141
1177
|
return self._search_feedback_subgraph(
|
|
1142
|
-
|
|
1143
|
-
|
|
1178
|
+
agentId=None,
|
|
1179
|
+
agents=merged_agents,
|
|
1180
|
+
clientAddresses=clientAddresses,
|
|
1181
|
+
tags=tags,
|
|
1182
|
+
capabilities=capabilities,
|
|
1183
|
+
skills=skills,
|
|
1184
|
+
tasks=tasks,
|
|
1185
|
+
names=names,
|
|
1186
|
+
minValue=minValue,
|
|
1187
|
+
maxValue=maxValue,
|
|
1188
|
+
include_revoked=include_revoked,
|
|
1189
|
+
first=first,
|
|
1190
|
+
skip=skip,
|
|
1191
|
+
subgraph_client=subgraph_client,
|
|
1144
1192
|
)
|
|
1145
1193
|
|
|
1146
1194
|
# Fallback not implemented (would require blockchain queries)
|
|
@@ -1149,7 +1197,8 @@ class AgentIndexer:
|
|
|
1149
1197
|
|
|
1150
1198
|
def _search_feedback_subgraph(
|
|
1151
1199
|
self,
|
|
1152
|
-
agentId: AgentId,
|
|
1200
|
+
agentId: Optional[AgentId],
|
|
1201
|
+
agents: Optional[List[AgentId]],
|
|
1153
1202
|
clientAddresses: Optional[List[Address]],
|
|
1154
1203
|
tags: Optional[List[str]],
|
|
1155
1204
|
capabilities: Optional[List[str]],
|
|
@@ -1169,9 +1218,15 @@ class AgentIndexer:
|
|
|
1169
1218
|
if not client:
|
|
1170
1219
|
return []
|
|
1171
1220
|
|
|
1221
|
+
merged_agents: Optional[List[AgentId]] = None
|
|
1222
|
+
if agents:
|
|
1223
|
+
merged_agents = list(agents)
|
|
1224
|
+
if agentId:
|
|
1225
|
+
merged_agents = (merged_agents or []) + [agentId]
|
|
1226
|
+
|
|
1172
1227
|
# Create SearchFeedbackParams
|
|
1173
1228
|
params = SearchFeedbackParams(
|
|
1174
|
-
agents=
|
|
1229
|
+
agents=merged_agents,
|
|
1175
1230
|
reviewers=clientAddresses,
|
|
1176
1231
|
tags=tags,
|
|
1177
1232
|
capabilities=capabilities,
|
|
@@ -1305,7 +1360,7 @@ class AgentIndexer:
|
|
|
1305
1360
|
token_id
|
|
1306
1361
|
)
|
|
1307
1362
|
|
|
1308
|
-
# Get
|
|
1363
|
+
# Get on-chain verified wallet (IdentityRegistry.getAgentWallet)
|
|
1309
1364
|
wallet_address = None
|
|
1310
1365
|
try:
|
|
1311
1366
|
wallet_address = self.web3_client.call_contract(
|
|
@@ -1316,7 +1371,6 @@ class AgentIndexer:
|
|
|
1316
1371
|
if wallet_address == "0x0000000000000000000000000000000000000000":
|
|
1317
1372
|
wallet_address = None
|
|
1318
1373
|
except Exception:
|
|
1319
|
-
# Fallback to registration file if getAgentWallet not available
|
|
1320
1374
|
pass
|
|
1321
1375
|
|
|
1322
1376
|
# Create agent ID
|
agent0_sdk/core/models.py
CHANGED
|
@@ -89,7 +89,7 @@ class RegistrationFile:
|
|
|
89
89
|
endpoints.append(endpoint_dict)
|
|
90
90
|
|
|
91
91
|
# Note: agentWallet is no longer included in endpoints array.
|
|
92
|
-
# It's now a reserved on-chain metadata key managed via
|
|
92
|
+
# It's now a reserved on-chain metadata key managed via Agent.setWallet().
|
|
93
93
|
|
|
94
94
|
# Build registrations array
|
|
95
95
|
registrations = []
|
|
@@ -106,7 +106,7 @@ class RegistrationFile:
|
|
|
106
106
|
"name": self.name,
|
|
107
107
|
"description": self.description,
|
|
108
108
|
"image": self.image,
|
|
109
|
-
"
|
|
109
|
+
"services": endpoints,
|
|
110
110
|
"registrations": registrations,
|
|
111
111
|
"supportedTrust": [tm.value if isinstance(tm, TrustModel) else tm for tm in self.trustModels],
|
|
112
112
|
"active": self.active,
|
|
@@ -118,7 +118,8 @@ class RegistrationFile:
|
|
|
118
118
|
def from_dict(cls, data: Dict[str, Any]) -> RegistrationFile:
|
|
119
119
|
"""Create from dictionary."""
|
|
120
120
|
endpoints = []
|
|
121
|
-
|
|
121
|
+
raw_services = data.get("services", data.get("endpoints", []))
|
|
122
|
+
for ep_data in raw_services:
|
|
122
123
|
name = ep_data["name"]
|
|
123
124
|
# Special handling for agentWallet - it's not a standard endpoint type
|
|
124
125
|
if name == "agentWallet":
|
agent0_sdk/core/sdk.py
CHANGED
|
@@ -27,6 +27,7 @@ from .agent import Agent
|
|
|
27
27
|
from .indexer import AgentIndexer
|
|
28
28
|
from .ipfs_client import IPFSClient
|
|
29
29
|
from .feedback_manager import FeedbackManager
|
|
30
|
+
from .transaction_handle import TransactionHandle
|
|
30
31
|
from .subgraph_client import SubgraphClient
|
|
31
32
|
|
|
32
33
|
|
|
@@ -273,6 +274,8 @@ class SDK:
|
|
|
273
274
|
name=name,
|
|
274
275
|
description=description,
|
|
275
276
|
image=image,
|
|
277
|
+
# Default trust model: reputation (if caller doesn't set one explicitly).
|
|
278
|
+
trustModels=[TrustModel.REPUTATION],
|
|
276
279
|
updatedAt=int(time.time())
|
|
277
280
|
)
|
|
278
281
|
return Agent(sdk=self, registration_file=registration_file)
|
|
@@ -590,7 +593,7 @@ class SDK:
|
|
|
590
593
|
mcpPrompts=reg_file.get('mcpPrompts', []),
|
|
591
594
|
mcpResources=reg_file.get('mcpResources', []),
|
|
592
595
|
active=reg_file.get('active', True),
|
|
593
|
-
x402support=reg_file.get('x402support', False),
|
|
596
|
+
x402support=reg_file.get('x402Support', reg_file.get('x402support', False)),
|
|
594
597
|
extras={'averageValue': agent_data.get('averageValue')}
|
|
595
598
|
)
|
|
596
599
|
results.append(agent_summary)
|
|
@@ -747,7 +750,7 @@ class SDK:
|
|
|
747
750
|
mcpPrompts=reg_file.get('mcpPrompts', []),
|
|
748
751
|
mcpResources=reg_file.get('mcpResources', []),
|
|
749
752
|
active=reg_file.get('active', True),
|
|
750
|
-
x402support=reg_file.get('x402support', False),
|
|
753
|
+
x402support=reg_file.get('x402Support', reg_file.get('x402support', False)),
|
|
751
754
|
extras={'averageValue': agent_data.get('averageValue')}
|
|
752
755
|
)
|
|
753
756
|
results.append(agent_summary)
|
|
@@ -797,7 +800,7 @@ class SDK:
|
|
|
797
800
|
tag2: Optional[str] = None,
|
|
798
801
|
endpoint: Optional[str] = None,
|
|
799
802
|
feedbackFile: Optional[Dict[str, Any]] = None,
|
|
800
|
-
) -> "Feedback":
|
|
803
|
+
) -> "TransactionHandle[Feedback]":
|
|
801
804
|
"""Give feedback (on-chain first; optional off-chain file upload).
|
|
802
805
|
|
|
803
806
|
- If feedbackFile is None: submit on-chain only (no upload even if IPFS is configured).
|
|
@@ -825,7 +828,7 @@ class SDK:
|
|
|
825
828
|
|
|
826
829
|
def searchFeedback(
|
|
827
830
|
self,
|
|
828
|
-
agentId: "AgentId",
|
|
831
|
+
agentId: Optional["AgentId"] = None,
|
|
829
832
|
reviewers: Optional[List["Address"]] = None,
|
|
830
833
|
tags: Optional[List[str]] = None,
|
|
831
834
|
capabilities: Optional[List[str]] = None,
|
|
@@ -837,10 +840,38 @@ class SDK:
|
|
|
837
840
|
include_revoked: bool = False,
|
|
838
841
|
first: int = 100,
|
|
839
842
|
skip: int = 0,
|
|
843
|
+
agents: Optional[List["AgentId"]] = None,
|
|
840
844
|
) -> List["Feedback"]:
|
|
841
|
-
"""Search feedback
|
|
845
|
+
"""Search feedback.
|
|
846
|
+
|
|
847
|
+
Backwards compatible:
|
|
848
|
+
- Previously required `agentId`; it is now optional.
|
|
849
|
+
|
|
850
|
+
New:
|
|
851
|
+
- `agents` can be used to search feedback across multiple agents in one call.
|
|
852
|
+
- `reviewers` can now be used without specifying any agent, enabling "all feedback given by a wallet".
|
|
853
|
+
"""
|
|
854
|
+
has_any_filter = any([
|
|
855
|
+
bool(agentId),
|
|
856
|
+
bool(agents),
|
|
857
|
+
bool(reviewers),
|
|
858
|
+
bool(tags),
|
|
859
|
+
bool(capabilities),
|
|
860
|
+
bool(skills),
|
|
861
|
+
bool(tasks),
|
|
862
|
+
bool(names),
|
|
863
|
+
minValue is not None,
|
|
864
|
+
maxValue is not None,
|
|
865
|
+
])
|
|
866
|
+
if not has_any_filter:
|
|
867
|
+
raise ValueError(
|
|
868
|
+
"searchFeedback requires at least one filter "
|
|
869
|
+
"(agentId/agents/reviewers/tags/capabilities/skills/tasks/names/minValue/maxValue)."
|
|
870
|
+
)
|
|
871
|
+
|
|
842
872
|
return self.feedback_manager.searchFeedback(
|
|
843
873
|
agentId=agentId,
|
|
874
|
+
agents=agents,
|
|
844
875
|
clientAddresses=reviewers,
|
|
845
876
|
tags=tags,
|
|
846
877
|
capabilities=capabilities,
|
|
@@ -857,13 +888,10 @@ class SDK:
|
|
|
857
888
|
def revokeFeedback(
|
|
858
889
|
self,
|
|
859
890
|
agentId: "AgentId",
|
|
860
|
-
clientAddress: "Address",
|
|
861
891
|
feedbackIndex: int,
|
|
862
|
-
) -> "Feedback":
|
|
863
|
-
"""Revoke feedback."""
|
|
864
|
-
return self.feedback_manager.revokeFeedback(
|
|
865
|
-
agentId, clientAddress, feedbackIndex
|
|
866
|
-
)
|
|
892
|
+
) -> "TransactionHandle[Feedback]":
|
|
893
|
+
"""Revoke feedback (submitted-by-default)."""
|
|
894
|
+
return self.feedback_manager.revokeFeedback(agentId, feedbackIndex)
|
|
867
895
|
|
|
868
896
|
def appendResponse(
|
|
869
897
|
self,
|
|
@@ -871,8 +899,8 @@ class SDK:
|
|
|
871
899
|
clientAddress: "Address",
|
|
872
900
|
feedbackIndex: int,
|
|
873
901
|
response: Dict[str, Any],
|
|
874
|
-
) -> "Feedback":
|
|
875
|
-
"""Append a response/follow-up to existing feedback."""
|
|
902
|
+
) -> "TransactionHandle[Feedback]":
|
|
903
|
+
"""Append a response/follow-up to existing feedback (submitted-by-default)."""
|
|
876
904
|
return self.feedback_manager.appendResponse(
|
|
877
905
|
agentId, clientAddress, feedbackIndex, response
|
|
878
906
|
)
|
|
@@ -890,7 +918,7 @@ class SDK:
|
|
|
890
918
|
self,
|
|
891
919
|
agentId: "AgentId",
|
|
892
920
|
newOwnerAddress: str,
|
|
893
|
-
) -> Dict[str, Any]:
|
|
921
|
+
) -> "TransactionHandle[Dict[str, Any]]":
|
|
894
922
|
"""Transfer agent ownership to a new address.
|
|
895
923
|
|
|
896
924
|
Convenience method that loads the agent and calls transfer().
|