agent0-sdk 0.31__tar.gz → 1.0.1__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.
Files changed (39) hide show
  1. agent0_sdk-1.0.1/MANIFEST.in +10 -0
  2. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/PKG-INFO +22 -14
  3. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/README.md +20 -12
  4. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/__init__.py +1 -1
  5. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/agent.py +172 -30
  6. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/contracts.py +93 -58
  7. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/feedback_manager.py +90 -161
  8. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/indexer.py +54 -26
  9. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/models.py +6 -19
  10. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/oasf_validator.py +1 -1
  11. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/sdk.py +31 -16
  12. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/subgraph_client.py +34 -15
  13. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/web3_client.py +184 -17
  14. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/PKG-INFO +22 -14
  15. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/SOURCES.txt +2 -15
  16. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/pyproject.toml +2 -2
  17. agent0_sdk-0.31/tests/__init__.py +0 -1
  18. agent0_sdk-0.31/tests/config.py +0 -46
  19. agent0_sdk-0.31/tests/conftest.py +0 -22
  20. agent0_sdk-0.31/tests/discover_test_data.py +0 -445
  21. agent0_sdk-0.31/tests/test_feedback.py +0 -417
  22. agent0_sdk-0.31/tests/test_models.py +0 -224
  23. agent0_sdk-0.31/tests/test_multi_chain.py +0 -588
  24. agent0_sdk-0.31/tests/test_oasf_management.py +0 -404
  25. agent0_sdk-0.31/tests/test_real_public_servers.py +0 -103
  26. agent0_sdk-0.31/tests/test_registration.py +0 -267
  27. agent0_sdk-0.31/tests/test_registrationIpfs.py +0 -227
  28. agent0_sdk-0.31/tests/test_sdk.py +0 -240
  29. agent0_sdk-0.31/tests/test_search.py +0 -415
  30. agent0_sdk-0.31/tests/test_transfer.py +0 -255
  31. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/LICENSE +0 -0
  32. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/endpoint_crawler.py +0 -0
  33. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/core/ipfs_client.py +0 -0
  34. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/taxonomies/all_domains.json +0 -0
  35. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk/taxonomies/all_skills.json +0 -0
  36. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/dependency_links.txt +0 -0
  37. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/requires.txt +0 -0
  38. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/agent0_sdk.egg-info/top_level.txt +0 -0
  39. {agent0_sdk-0.31 → agent0_sdk-1.0.1}/setup.cfg +0 -0
@@ -0,0 +1,10 @@
1
+ exclude .env
2
+ global-exclude *.env
3
+ global-exclude *.env.*
4
+
5
+ # local artifacts
6
+ prune venv
7
+ exclude agent_registration_*.json
8
+
9
+ # don't ship tests in sdist by default
10
+ prune tests
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent0-sdk
3
- Version: 0.31
3
+ Version: 1.0.1
4
4
  Summary: Python SDK for agent portability, discovery and trust based on ERC-8004
5
- Author-email: Marco De Rossi <marco.derossi@consensys.net>
5
+ Author-email: Marco De Rossi <marco@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 v0.31 enables you to:
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
- ## ⚠️ Alpha Release
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: [@marcoderossi](https://t.me/marcoderossi) | Email: marco@ag0.xyz
94
90
 
95
91
  ## Installation
96
92
 
@@ -152,12 +148,10 @@ agent.setENS("myagent.eth")
152
148
 
153
149
  # Add OASF skills and domains (standardized taxonomies)
154
150
  agent.addSkill("data_engineering/data_transformation_pipeline", validate_oasf=True)
155
- agent.addSkill("natural_language_processing/summarization", validate_oasf=True)
151
+ agent.addSkill("natural_language_processing/natural_language_generation/summarization", validate_oasf=True)
156
152
  agent.addDomain("finance_and_business/investment_services", validate_oasf=True)
157
- agent.addDomain("technology/data_science", validate_oasf=True)
153
+ agent.addDomain("technology/data_science/data_science", validate_oasf=True)
158
154
 
159
- # Configure wallet and trust
160
- agent.setAgentWallet("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", chainId=11155111)
161
155
  agent.setTrust(reputation=True, cryptoEconomic=True)
162
156
 
163
157
  # Add metadata and set status
@@ -168,6 +162,16 @@ agent.setActive(True)
168
162
  agent.registerIPFS()
169
163
  print(f"Agent registered: {agent.agentId}") # e.g., "11155111:123"
170
164
  print(f"Agent URI: {agent.agentURI}") # e.g., "ipfs://Qm..."
165
+
166
+ # (Optional) Change the agent wallet after registration
167
+ # - On mint/registration, `agentWallet` defaults to the current owner address.
168
+ # - Call this only if you want a DIFFERENT wallet (or after a transfer, since the wallet resets to zero).
169
+ # - Transaction is sent by the SDK signer (agent owner), but the signature must be produced by the NEW wallet.
170
+ agent.setAgentWallet(
171
+ "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
172
+ chainId=11155111,
173
+ new_wallet_signer=os.getenv("NEW_WALLET_PRIVATE_KEY"),
174
+ )
171
175
  ```
172
176
 
173
177
  ### 3. Load and Edit Agent
@@ -213,7 +217,8 @@ agent_summary = sdk.getAgent("11155111:123")
213
217
  feedback_file = sdk.prepareFeedback(
214
218
  agentId="11155111:123",
215
219
  score=85, # 0-100 (mandatory)
216
- tags=["data_analyst", "finance"], # Optional
220
+ tags=["data_analyst", "finance"], # Optional: tags are now strings (not bytes32)
221
+ endpoint="https://example.com/endpoint", # Optional: endpoint URI associated with feedback
217
222
  capability="tools", # Optional: MCP capability
218
223
  name="code_generation", # Optional: MCP tool name
219
224
  skill="python" # Optional: A2A skill
@@ -307,7 +312,7 @@ OASF skills and domains appear in your agent's registration file:
307
312
  ],
308
313
  "domains": [
309
314
  "finance_and_business/investment_services",
310
- "technology/data_science"
315
+ "technology/data_science/data_science"
311
316
  ]
312
317
  }
313
318
  ]
@@ -347,6 +352,9 @@ Complete working examples are available in the `tests/` directory:
347
352
  - `test_feedback.py` - Complete feedback flow with IPFS storage
348
353
  - `test_search.py` - Agent search and discovery
349
354
  - `test_transfer.py` - Agent ownership transfer
355
+ - `test_oasf_management.py` - OASF skills/domains management (unit tests)
356
+ - `test_real_public_servers.py` - Endpoint crawler against real public MCP/A2A servers
357
+ - `test_multi_chain.py` - Multi-chain read-only operations (subgraph-based)
350
358
 
351
359
  ## Documentation
352
360
 
@@ -6,7 +6,7 @@ Agent0 is the SDK for agentic economies. It enables agents to register, advertis
6
6
 
7
7
  ## What Does Agent0 SDK Do?
8
8
 
9
- Agent0 SDK v0.31 enables you to:
9
+ Agent0 SDK enables you to:
10
10
 
11
11
  - **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
12
12
  - **Advertise agent capabilities** - Publish MCP and A2A endpoints, with automated extraction of MCP tools and A2A skills from endpoints
@@ -16,11 +16,7 @@ Agent0 SDK v0.31 enables you to:
16
16
  - **Cross-chain registration** - One-line registration with IPFS nodes, Pinata, Filecoin, or HTTP URIs
17
17
  - **Public indexing** - Subgraph indexing both on-chain and IPFS data for fast search and retrieval
18
18
 
19
- ## ⚠️ Alpha Release
20
-
21
- Agent0 SDK v0.31 is in **alpha** with bugs and is not production ready. We're actively testing and improving it.
22
-
23
- **Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco.derossi@consensys.net
19
+ **Bug reports & feedback:** GitHub: [Report issues](https://github.com/agent0lab/agent0-py/issues) | Telegram: [@marcoderossi](https://t.me/marcoderossi) | Email: marco@ag0.xyz
24
20
 
25
21
  ## Installation
26
22
 
@@ -82,12 +78,10 @@ agent.setENS("myagent.eth")
82
78
 
83
79
  # Add OASF skills and domains (standardized taxonomies)
84
80
  agent.addSkill("data_engineering/data_transformation_pipeline", validate_oasf=True)
85
- agent.addSkill("natural_language_processing/summarization", validate_oasf=True)
81
+ agent.addSkill("natural_language_processing/natural_language_generation/summarization", validate_oasf=True)
86
82
  agent.addDomain("finance_and_business/investment_services", validate_oasf=True)
87
- agent.addDomain("technology/data_science", validate_oasf=True)
83
+ agent.addDomain("technology/data_science/data_science", validate_oasf=True)
88
84
 
89
- # Configure wallet and trust
90
- agent.setAgentWallet("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", chainId=11155111)
91
85
  agent.setTrust(reputation=True, cryptoEconomic=True)
92
86
 
93
87
  # Add metadata and set status
@@ -98,6 +92,16 @@ agent.setActive(True)
98
92
  agent.registerIPFS()
99
93
  print(f"Agent registered: {agent.agentId}") # e.g., "11155111:123"
100
94
  print(f"Agent URI: {agent.agentURI}") # e.g., "ipfs://Qm..."
95
+
96
+ # (Optional) Change the agent wallet after registration
97
+ # - On mint/registration, `agentWallet` defaults to the current owner address.
98
+ # - Call this only if you want a DIFFERENT wallet (or after a transfer, since the wallet resets to zero).
99
+ # - Transaction is sent by the SDK signer (agent owner), but the signature must be produced by the NEW wallet.
100
+ agent.setAgentWallet(
101
+ "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
102
+ chainId=11155111,
103
+ new_wallet_signer=os.getenv("NEW_WALLET_PRIVATE_KEY"),
104
+ )
101
105
  ```
102
106
 
103
107
  ### 3. Load and Edit Agent
@@ -143,7 +147,8 @@ agent_summary = sdk.getAgent("11155111:123")
143
147
  feedback_file = sdk.prepareFeedback(
144
148
  agentId="11155111:123",
145
149
  score=85, # 0-100 (mandatory)
146
- tags=["data_analyst", "finance"], # Optional
150
+ tags=["data_analyst", "finance"], # Optional: tags are now strings (not bytes32)
151
+ endpoint="https://example.com/endpoint", # Optional: endpoint URI associated with feedback
147
152
  capability="tools", # Optional: MCP capability
148
153
  name="code_generation", # Optional: MCP tool name
149
154
  skill="python" # Optional: A2A skill
@@ -237,7 +242,7 @@ OASF skills and domains appear in your agent's registration file:
237
242
  ],
238
243
  "domains": [
239
244
  "finance_and_business/investment_services",
240
- "technology/data_science"
245
+ "technology/data_science/data_science"
241
246
  ]
242
247
  }
243
248
  ]
@@ -277,6 +282,9 @@ Complete working examples are available in the `tests/` directory:
277
282
  - `test_feedback.py` - Complete feedback flow with IPFS storage
278
283
  - `test_search.py` - Agent search and discovery
279
284
  - `test_transfer.py` - Agent ownership transfer
285
+ - `test_oasf_management.py` - OASF skills/domains management (unit tests)
286
+ - `test_real_public_servers.py` - Endpoint crawler against real public MCP/A2A servers
287
+ - `test_multi_chain.py` - Multi-chain read-only operations (subgraph-based)
280
288
 
281
289
  ## Documentation
282
290
 
@@ -30,7 +30,7 @@ except ImportError:
30
30
  Agent = None
31
31
  _sdk_available = False
32
32
 
33
- __version__ = "0.31"
33
+ __version__ = "1.0.1"
34
34
  __all__ = [
35
35
  "SDK",
36
36
  "Agent",
@@ -176,16 +176,14 @@ class Agent:
176
176
  return self.registration_file
177
177
 
178
178
  def _collectMetadataForRegistration(self) -> List[Dict[str, Any]]:
179
- """Collect all metadata entries for registration."""
179
+ """Collect all metadata entries for registration.
180
+
181
+ Note: agentWallet is now a reserved metadata key and cannot be set via setMetadata().
182
+ It must be set separately using setAgentWallet() with EIP-712 signature verification.
183
+ """
180
184
  metadata_entries = []
181
185
 
182
- # Add wallet address metadata
183
- if self.walletAddress:
184
- addr_bytes = bytes.fromhex(self.walletAddress[2:]) # Remove '0x' prefix
185
- metadata_entries.append({
186
- "key": "agentWallet",
187
- "value": addr_bytes
188
- })
186
+ # Note: agentWallet is no longer set via metadata - it's now reserved and managed via setAgentWallet()
189
187
 
190
188
  # Add ENS name metadata
191
189
  if self.ensEndpoint:
@@ -339,7 +337,7 @@ class Agent:
339
337
  Add a skill to the OASF endpoint.
340
338
 
341
339
  Args:
342
- slug: The skill slug to add (e.g., "natural_language_processing/summarization")
340
+ slug: The skill slug to add (e.g., "natural_language_processing/natural_language_generation/summarization")
343
341
  validate_oasf: If True, validate the slug against the OASF taxonomy (default: False)
344
342
 
345
343
  Returns:
@@ -492,20 +490,55 @@ class Agent:
492
490
  self.registration_file.updatedAt = int(time.time())
493
491
  return self
494
492
 
495
- def setAgentWallet(self, addr: Optional[Address], chainId: Optional[int] = None) -> 'Agent':
496
- """Set agent wallet address in registration file (will be saved on-chain during next register call)."""
497
- # Validate address format if provided
498
- if addr:
499
- if not addr.startswith("0x") or len(addr) != 42:
500
- raise ValueError(f"Invalid Ethereum address format: {addr}. Must be 42 characters starting with '0x'")
501
-
502
- # Validate hexadecimal characters
503
- try:
504
- int(addr[2:], 16)
505
- except ValueError:
506
- raise ValueError(f"Invalid hexadecimal characters in address: {addr}")
493
+ def setAgentWallet(
494
+ self,
495
+ new_wallet: Address,
496
+ chainId: Optional[int] = None,
497
+ *,
498
+ new_wallet_signer: Optional[Union[str, Any]] = None,
499
+ deadline: Optional[int] = None,
500
+ signature: Optional[bytes] = None,
501
+ ) -> 'Agent':
502
+ """Set agent wallet address on-chain (ERC-8004 agentWallet).
503
+
504
+ This method is **on-chain only**. The `agentWallet` is a verified attribute and must be set via
505
+ the IdentityRegistry `setAgentWallet` function.
506
+
507
+ EOAs: provide `new_wallet_signer` (private key string or eth-account account) OR ensure the SDK
508
+ signer address matches `new_wallet` so the SDK can auto-sign.\n
509
+ Contract wallets (ERC-1271): provide `signature` bytes produced by the wallet’s signing mechanism.
510
+ The SDK will build the correct EIP-712 typed data internally, but cannot produce the wallet signature.
511
+
512
+ Args:
513
+ new_wallet: New wallet address (must be controlled by the signer that produces the signature)
514
+ chainId: Optional local bookkeeping for registration file (walletChainId). Defaults to agent chain.
515
+ new_wallet_signer: EOA signer used to sign the EIP-712 message (private key string or eth-account account)
516
+ deadline: Signature deadline timestamp. Defaults to now+60s (must be <= now+5min per contract).
517
+ signature: Raw signature bytes (intended for ERC-1271 / external signing only)
518
+ """
519
+ # Breaking/clean: this API is only meaningful for already-registered agents.
520
+ if not self.agentId:
521
+ raise ValueError(
522
+ "Cannot set agent wallet before the agent is registered on-chain. "
523
+ "Call agent.register(...) / agent.registerIPFS() first to obtain agentId."
524
+ )
525
+
526
+ addr = new_wallet
527
+
528
+ if not addr:
529
+ raise ValueError("Wallet address cannot be empty. Use a non-zero address.")
507
530
 
508
- # Determine chain ID to use
531
+ # Validate address format
532
+ if not addr.startswith("0x") or len(addr) != 42:
533
+ raise ValueError(f"Invalid Ethereum address format: {addr}. Must be 42 characters starting with '0x'")
534
+
535
+ # Validate hexadecimal characters
536
+ try:
537
+ int(addr[2:], 16)
538
+ except ValueError:
539
+ raise ValueError(f"Invalid hexadecimal characters in address: {addr}")
540
+
541
+ # Determine chain ID to use (local bookkeeping)
509
542
  if chainId is None:
510
543
  # Extract chain ID from agentId if available, otherwise use SDK's chain ID
511
544
  if self.agentId and ":" in self.agentId:
@@ -516,14 +549,104 @@ class Agent:
516
549
  else:
517
550
  chainId = self.sdk.chainId # Use SDK's chain ID as fallback
518
551
 
519
- # Check if wallet changed
520
- if addr != self._last_registered_wallet:
521
- self._dirty_metadata.add("agentWallet")
552
+ # Parse agent ID
553
+ agent_id_int = int(self.agentId.split(":")[-1]) if ":" in self.agentId else int(self.agentId)
554
+
555
+ # Check if wallet is already set to this address (skip if same)
556
+ try:
557
+ current_wallet = self.sdk.web3_client.call_contract(
558
+ self.sdk.identity_registry,
559
+ "getAgentWallet",
560
+ agent_id_int
561
+ )
562
+ if current_wallet and current_wallet.lower() == addr.lower():
563
+ logger.debug(f"Agent wallet is already set to {addr}, skipping on-chain update")
564
+ # Still update local registration file
565
+ self.registration_file.walletAddress = addr
566
+ self.registration_file.walletChainId = chainId
567
+ self.registration_file.updatedAt = int(time.time())
568
+ return self
569
+ except Exception as e:
570
+ logger.debug(f"Could not check current agent wallet: {e}, proceeding with update")
571
+
572
+ # Set deadline (default to 60 seconds from now; contract max is now+5min)
573
+ if deadline is None:
574
+ deadline = int(time.time()) + 60
575
+
576
+ # Resolve typed data + signature
577
+ identity_registry_address = self.sdk.identity_registry.address
578
+ owner_address = self.sdk.web3_client.call_contract(self.sdk.identity_registry, "ownerOf", agent_id_int)
579
+
580
+ full_message = self.sdk.web3_client.build_agent_wallet_set_typed_data(
581
+ agent_id=agent_id_int,
582
+ new_wallet=addr,
583
+ owner=owner_address,
584
+ deadline=deadline,
585
+ verifying_contract=identity_registry_address,
586
+ chain_id=self.sdk.web3_client.chain_id,
587
+ )
588
+
589
+ if signature is None:
590
+ # EOA signing paths
591
+ if new_wallet_signer is not None:
592
+ # Validate signer address matches addr (fail fast)
593
+ try:
594
+ from eth_account import Account as _Account
595
+ if isinstance(new_wallet_signer, str):
596
+ signer_addr = _Account.from_key(new_wallet_signer).address
597
+ else:
598
+ signer_addr = getattr(new_wallet_signer, "address", None)
599
+ except Exception:
600
+ signer_addr = getattr(new_wallet_signer, "address", None)
601
+
602
+ if not signer_addr or signer_addr.lower() != addr.lower():
603
+ raise ValueError(
604
+ f"new_wallet_signer address ({signer_addr}) does not match new_wallet ({addr})."
605
+ )
606
+
607
+ signature = self.sdk.web3_client.sign_typed_data(full_message, new_wallet_signer) # type: ignore[arg-type]
608
+ else:
609
+ # Auto-sign only if SDK signer == new wallet
610
+ current_address = self.sdk.web3_client.account.address if self.sdk.web3_client.account else None
611
+ if current_address and current_address.lower() == addr.lower():
612
+ signature = self.sdk.web3_client.sign_typed_data(full_message, self.sdk.web3_client.account)
613
+ else:
614
+ raise ValueError(
615
+ f"New wallet must sign. Provide new_wallet_signer (EOA) or signature (ERC-1271/external). "
616
+ f"SDK signer is {current_address}, new_wallet is {addr}."
617
+ )
618
+
619
+ # Optional: verify recover matches addr for EOA signatures
620
+ recovered = self.sdk.web3_client.w3.eth.account.recover_message(
621
+ __import__("eth_account.messages").messages.encode_typed_data(full_message=full_message),
622
+ signature=signature,
623
+ )
624
+ if recovered.lower() != addr.lower():
625
+ raise ValueError(f"Signature verification failed: recovered {recovered} but expected {addr}")
626
+
627
+ # Call setAgentWallet on the contract
628
+ try:
629
+ txHash = self.sdk.web3_client.transact_contract(
630
+ self.sdk.identity_registry,
631
+ "setAgentWallet",
632
+ agent_id_int,
633
+ addr,
634
+ deadline,
635
+ signature
636
+ )
637
+
638
+ # Wait for transaction
639
+ receipt = self.sdk.web3_client.wait_for_transaction(txHash)
640
+ logger.debug(f"Agent wallet set on-chain: {txHash}")
641
+
642
+ except Exception as e:
643
+ raise ValueError(f"Failed to set agent wallet on-chain: {e}")
522
644
 
523
645
  # Update local registration file
524
646
  self.registration_file.walletAddress = addr
525
647
  self.registration_file.walletChainId = chainId
526
648
  self.registration_file.updatedAt = int(time.time())
649
+ self._last_registered_wallet = addr
527
650
 
528
651
  return self
529
652
 
@@ -636,7 +759,7 @@ class Agent:
636
759
  agentId = int(self.agentId.split(":")[-1])
637
760
  txHash = self.sdk.web3_client.transact_contract(
638
761
  self.sdk.identity_registry,
639
- "setAgentUri",
762
+ "setAgentURI",
640
763
  agentId,
641
764
  f"ipfs://{ipfsCid}"
642
765
  )
@@ -673,7 +796,7 @@ class Agent:
673
796
  agentId = int(self.agentId.split(":")[-1])
674
797
  txHash = self.sdk.web3_client.transact_contract(
675
798
  self.sdk.identity_registry,
676
- "setAgentUri",
799
+ "setAgentURI",
677
800
  agentId,
678
801
  f"ipfs://{ipfsCid}"
679
802
  )
@@ -715,7 +838,7 @@ class Agent:
715
838
  txHash = self.sdk.web3_client.transact_contract(
716
839
  self.sdk.identity_registry,
717
840
  "register",
718
- "", # Empty tokenUri for now
841
+ "", # Empty agentURI for now
719
842
  metadata_entries
720
843
  )
721
844
 
@@ -820,7 +943,7 @@ class Agent:
820
943
  agentId = int(self.registration_file.agentId.split(":")[-1])
821
944
  txHash = self.sdk.web3_client.transact_contract(
822
945
  self.sdk.identity_registry,
823
- "setAgentUri",
946
+ "setAgentURI",
824
947
  agentId,
825
948
  agentURI
826
949
  )
@@ -846,7 +969,12 @@ class Agent:
846
969
  approve_operator: bool = False,
847
970
  idem: Optional[IdemKey] = None,
848
971
  ) -> Dict[str, Any]:
849
- """Transfer agent ownership."""
972
+ """Transfer agent ownership.
973
+
974
+ Note: When an agent is transferred, the agentWallet is automatically reset
975
+ to the zero address on-chain. The new owner must call setAgentWallet() to
976
+ set a new wallet address with EIP-712 signature verification.
977
+ """
850
978
  if not self.registration_file.agentId:
851
979
  raise ValueError("Agent must be registered before transferring")
852
980
 
@@ -863,6 +991,11 @@ class Agent:
863
991
 
864
992
  receipt = self.sdk.web3_client.wait_for_transaction(txHash)
865
993
 
994
+ # Note: agentWallet will be reset to zero address by the contract
995
+ # Update local state to reflect this
996
+ self.registration_file.walletAddress = None
997
+ self._last_registered_wallet = None
998
+
866
999
  return {
867
1000
  "txHash": txHash,
868
1001
  "agentId": self.registration_file.agentId,
@@ -907,6 +1040,10 @@ class Agent:
907
1040
 
908
1041
  Only the current owner can transfer the agent.
909
1042
 
1043
+ Note: When an agent is transferred, the agentWallet is automatically reset
1044
+ to the zero address on-chain. The new owner must call setAgentWallet() to
1045
+ set a new wallet address with EIP-712 signature verification.
1046
+
910
1047
  Args:
911
1048
  newOwnerAddress: Ethereum address of the new owner
912
1049
 
@@ -964,6 +1101,11 @@ class Agent:
964
1101
 
965
1102
  logger.debug(f"Agent {self.registration_file.agentId} successfully transferred to {checksum_address}")
966
1103
 
1104
+ # Note: agentWallet will be reset to zero address by the contract
1105
+ # Update local state to reflect this
1106
+ self.registration_file.walletAddress = None
1107
+ self._last_registered_wallet = None
1108
+
967
1109
  return {"txHash": txHash, "from": currentOwner, "to": checksum_address, "agentId": self.registration_file.agentId}
968
1110
 
969
1111
  def activate(self, idem: Optional[IdemKey] = None) -> RegistrationFile: