agent0-sdk 1.0.2__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {agent0_sdk-1.0.2/agent0_sdk.egg-info → agent0_sdk-1.2.0}/PKG-INFO +6 -6
  2. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/README.md +5 -5
  3. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/__init__.py +1 -1
  4. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/contracts.py +21 -7
  5. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/feedback_manager.py +43 -41
  6. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/indexer.py +14 -14
  7. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/models.py +5 -3
  8. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/sdk.py +16 -16
  9. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/subgraph_client.py +22 -27
  10. agent0_sdk-1.2.0/agent0_sdk/core/value_encoding.py +91 -0
  11. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0/agent0_sdk.egg-info}/PKG-INFO +6 -6
  12. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk.egg-info/SOURCES.txt +1 -0
  13. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/pyproject.toml +1 -1
  14. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/LICENSE +0 -0
  15. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/MANIFEST.in +0 -0
  16. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/agent.py +0 -0
  17. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/endpoint_crawler.py +0 -0
  18. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/ipfs_client.py +0 -0
  19. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/oasf_validator.py +0 -0
  20. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/core/web3_client.py +0 -0
  21. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/taxonomies/all_domains.json +0 -0
  22. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk/taxonomies/all_skills.json +0 -0
  23. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk.egg-info/dependency_links.txt +0 -0
  24. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk.egg-info/requires.txt +0 -0
  25. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/agent0_sdk.egg-info/top_level.txt +0 -0
  26. {agent0_sdk-1.0.2 → agent0_sdk-1.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent0-sdk
3
- Version: 1.0.2
3
+ Version: 1.2.0
4
4
  Summary: Python SDK for agent portability, discovery and trust based on ERC-8004
5
5
  Author-email: Agent0 Team <team@ag0.xyz>
6
6
  License: MIT License
@@ -216,7 +216,7 @@ agent_summary = sdk.getAgent("11155111:123")
216
216
  # On-chain-only feedback (no off-chain upload, even if IPFS is configured)
217
217
  feedback = sdk.giveFeedback(
218
218
  agentId="11155111:123",
219
- score=85, # 0-100 (mandatory)
219
+ value=85, # number|string
220
220
  tag1="data_analyst", # Optional: tags are strings
221
221
  tag2="finance",
222
222
  endpoint="https://example.com/endpoint", # Optional: saved on-chain
@@ -232,7 +232,7 @@ feedback_file = sdk.prepareFeedbackFile({
232
232
 
233
233
  feedback = sdk.giveFeedback(
234
234
  agentId="11155111:123",
235
- score=85,
235
+ value=85,
236
236
  tag1="data_analyst",
237
237
  tag2="finance",
238
238
  endpoint="https://example.com/endpoint",
@@ -243,13 +243,13 @@ feedback = sdk.giveFeedback(
243
243
  results = sdk.searchFeedback(
244
244
  agentId="11155111:123",
245
245
  capabilities=["tools"],
246
- minScore=80,
247
- maxScore=100
246
+ minValue=80,
247
+ maxValue=100
248
248
  )
249
249
 
250
250
  # Get reputation summary
251
251
  summary = sdk.getReputationSummary("11155111:123")
252
- print(f"Average score: {summary['averageScore']}")
252
+ print(f"Average value: {summary['averageValue']}")
253
253
  ```
254
254
 
255
255
  ## IPFS Configuration Options
@@ -146,7 +146,7 @@ agent_summary = sdk.getAgent("11155111:123")
146
146
  # On-chain-only feedback (no off-chain upload, even if IPFS is configured)
147
147
  feedback = sdk.giveFeedback(
148
148
  agentId="11155111:123",
149
- score=85, # 0-100 (mandatory)
149
+ value=85, # number|string
150
150
  tag1="data_analyst", # Optional: tags are strings
151
151
  tag2="finance",
152
152
  endpoint="https://example.com/endpoint", # Optional: saved on-chain
@@ -162,7 +162,7 @@ feedback_file = sdk.prepareFeedbackFile({
162
162
 
163
163
  feedback = sdk.giveFeedback(
164
164
  agentId="11155111:123",
165
- score=85,
165
+ value=85,
166
166
  tag1="data_analyst",
167
167
  tag2="finance",
168
168
  endpoint="https://example.com/endpoint",
@@ -173,13 +173,13 @@ feedback = sdk.giveFeedback(
173
173
  results = sdk.searchFeedback(
174
174
  agentId="11155111:123",
175
175
  capabilities=["tools"],
176
- minScore=80,
177
- maxScore=100
176
+ minValue=80,
177
+ maxValue=100
178
178
  )
179
179
 
180
180
  # Get reputation summary
181
181
  summary = sdk.getReputationSummary("11155111:123")
182
- print(f"Average score: {summary['averageScore']}")
182
+ print(f"Average value: {summary['averageValue']}")
183
183
  ```
184
184
 
185
185
  ## IPFS Configuration Options
@@ -30,7 +30,7 @@ except ImportError:
30
30
  Agent = None
31
31
  _sdk_available = False
32
32
 
33
- __version__ = "1.0.2"
33
+ __version__ = "1.2.0"
34
34
  __all__ = [
35
35
  "SDK",
36
36
  "Agent",
@@ -159,7 +159,7 @@ IDENTITY_REGISTRY_ABI = [
159
159
  {"internalType": "uint256", "name": "agentId", "type": "uint256"}
160
160
  ],
161
161
  "name": "getAgentWallet",
162
- "outputs": [{"internalType": "address", "name": "", "type": "address"}],
162
+ "outputs": [{"internalType": "bytes", "name": "", "type": "bytes"}],
163
163
  "stateMutability": "view",
164
164
  "type": "function"
165
165
  },
@@ -175,6 +175,15 @@ IDENTITY_REGISTRY_ABI = [
175
175
  "stateMutability": "nonpayable",
176
176
  "type": "function"
177
177
  },
178
+ {
179
+ "inputs": [
180
+ {"internalType": "uint256", "name": "agentId", "type": "uint256"}
181
+ ],
182
+ "name": "unsetAgentWallet",
183
+ "outputs": [],
184
+ "stateMutability": "nonpayable",
185
+ "type": "function"
186
+ },
178
187
 
179
188
  # Events
180
189
  {
@@ -222,7 +231,8 @@ REPUTATION_REGISTRY_ABI = [
222
231
  {
223
232
  "inputs": [
224
233
  {"internalType": "uint256", "name": "agentId", "type": "uint256"},
225
- {"internalType": "uint8", "name": "score", "type": "uint8"},
234
+ {"internalType": "int256", "name": "value", "type": "int256"},
235
+ {"internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
226
236
  {"internalType": "string", "name": "tag1", "type": "string"},
227
237
  {"internalType": "string", "name": "tag2", "type": "string"},
228
238
  {"internalType": "string", "name": "endpoint", "type": "string"},
@@ -275,7 +285,8 @@ REPUTATION_REGISTRY_ABI = [
275
285
  ],
276
286
  "name": "readFeedback",
277
287
  "outputs": [
278
- {"internalType": "uint8", "name": "score", "type": "uint8"},
288
+ {"internalType": "int256", "name": "value", "type": "int256"},
289
+ {"internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
279
290
  {"internalType": "string", "name": "tag1", "type": "string"},
280
291
  {"internalType": "string", "name": "tag2", "type": "string"},
281
292
  {"internalType": "bool", "name": "isRevoked", "type": "bool"}
@@ -293,7 +304,8 @@ REPUTATION_REGISTRY_ABI = [
293
304
  "name": "getSummary",
294
305
  "outputs": [
295
306
  {"internalType": "uint64", "name": "count", "type": "uint64"},
296
- {"internalType": "uint8", "name": "averageScore", "type": "uint8"}
307
+ {"internalType": "int256", "name": "summaryValue", "type": "int256"},
308
+ {"internalType": "uint8", "name": "summaryValueDecimals", "type": "uint8"}
297
309
  ],
298
310
  "stateMutability": "view",
299
311
  "type": "function"
@@ -308,9 +320,10 @@ REPUTATION_REGISTRY_ABI = [
308
320
  ],
309
321
  "name": "readAllFeedback",
310
322
  "outputs": [
311
- {"internalType": "address[]", "name": "clientAddresses", "type": "address[]"},
323
+ {"internalType": "address[]", "name": "clients", "type": "address[]"},
312
324
  {"internalType": "uint64[]", "name": "feedbackIndexes", "type": "uint64[]"},
313
- {"internalType": "uint8[]", "name": "scores", "type": "uint8[]"},
325
+ {"internalType": "int256[]", "name": "values", "type": "int256[]"},
326
+ {"internalType": "uint8[]", "name": "valueDecimals", "type": "uint8[]"},
314
327
  {"internalType": "string[]", "name": "tag1s", "type": "string[]"},
315
328
  {"internalType": "string[]", "name": "tag2s", "type": "string[]"},
316
329
  {"internalType": "bool[]", "name": "revokedStatuses", "type": "bool[]"}
@@ -345,7 +358,8 @@ REPUTATION_REGISTRY_ABI = [
345
358
  {"indexed": True, "internalType": "uint256", "name": "agentId", "type": "uint256"},
346
359
  {"indexed": True, "internalType": "address", "name": "clientAddress", "type": "address"},
347
360
  {"indexed": False, "internalType": "uint64", "name": "feedbackIndex", "type": "uint64"},
348
- {"indexed": False, "internalType": "uint8", "name": "score", "type": "uint8"},
361
+ {"indexed": False, "internalType": "int256", "name": "value", "type": "int256"},
362
+ {"indexed": False, "internalType": "uint8", "name": "valueDecimals", "type": "uint8"},
349
363
  {"indexed": True, "internalType": "string", "name": "indexedTag1", "type": "string"},
350
364
  {"indexed": False, "internalType": "string", "name": "tag1", "type": "string"},
351
365
  {"indexed": False, "internalType": "string", "name": "tag2", "type": "string"},
@@ -16,6 +16,7 @@ from .models import (
16
16
  )
17
17
  from .web3_client import Web3Client
18
18
  from .ipfs_client import IPFSClient
19
+ from .value_encoding import encode_feedback_value, decode_feedback_value
19
20
 
20
21
  logger = logging.getLogger(__name__)
21
22
 
@@ -44,7 +45,7 @@ class FeedbackManager:
44
45
  """Prepare an off-chain feedback file payload (no on-chain fields).
45
46
 
46
47
  This intentionally does NOT attempt to represent on-chain fields like:
47
- score/tag1/tag2/endpoint (on-chain value), or registry-derived fields.
48
+ value/tag1/tag2/endpoint (on-chain value), or registry-derived fields.
48
49
 
49
50
  It may validate/normalize and remove None values.
50
51
  """
@@ -67,7 +68,7 @@ class FeedbackManager:
67
68
  def giveFeedback(
68
69
  self,
69
70
  agentId: AgentId,
70
- score: int,
71
+ value: Union[int, float, str],
71
72
  tag1: Optional[str] = None,
72
73
  tag2: Optional[str] = None,
73
74
  endpoint: Optional[str] = None,
@@ -117,11 +118,7 @@ class FeedbackManager:
117
118
  except Exception as e:
118
119
  raise ValueError(f"Failed to get feedback index: {e}")
119
120
 
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)
121
+ value_raw, value_decimals, _normalized = encode_feedback_value(value)
125
122
 
126
123
  tag1 = tag1 or ""
127
124
  tag2 = tag2 or ""
@@ -173,7 +170,8 @@ class FeedbackManager:
173
170
  "agentId",
174
171
  "clientAddress",
175
172
  "createdAt",
176
- "score",
173
+ "value",
174
+ "valueDecimals",
177
175
  "tag1",
178
176
  "tag2",
179
177
  "endpoint",
@@ -186,7 +184,9 @@ class FeedbackManager:
186
184
  "agentId": tokenId,
187
185
  "clientAddress": f"eip155:{agent_chain_id}:{clientAddress}",
188
186
  "createdAt": created_at,
189
- "score": int(score),
187
+ # On-chain fields (store raw+decimals for precision)
188
+ "value": str(value_raw),
189
+ "valueDecimals": int(value_decimals),
190
190
 
191
191
  # OPTIONAL fields that mirror on-chain
192
192
  **({"tag1": tag1} if tag1 else {}),
@@ -206,13 +206,14 @@ class FeedbackManager:
206
206
  except Exception as e:
207
207
  raise ValueError(f"Failed to store feedback on IPFS: {e}")
208
208
 
209
- # Submit to blockchain with new signature: giveFeedback(agentId, score, tag1, tag2, endpoint, feedbackURI, feedbackHash)
209
+ # Submit to blockchain with new signature: giveFeedback(agentId, value, valueDecimals, tag1, tag2, endpoint, feedbackURI, feedbackHash)
210
210
  try:
211
211
  txHash = self.web3_client.transact_contract(
212
212
  self.reputation_registry,
213
213
  "giveFeedback",
214
214
  tokenId,
215
- score,
215
+ value_raw,
216
+ value_decimals,
216
217
  tag1,
217
218
  tag2,
218
219
  endpoint_onchain,
@@ -234,7 +235,7 @@ class FeedbackManager:
234
235
  id=feedbackId,
235
236
  agentId=agentId,
236
237
  reviewer=clientAddress, # create_id normalizes the ID; reviewer field can remain as-is
237
- score=int(score) if score and score > 0 else None,
238
+ value=decode_feedback_value(value_raw, value_decimals),
238
239
  tags=[tag1, tag2] if tag1 or tag2 else [],
239
240
  text=ff.get("text"),
240
241
  context=ff.get("context"),
@@ -329,7 +330,7 @@ class FeedbackManager:
329
330
  id=Feedback.create_id(agentId, clientAddress, feedbackIndex), # create_id now normalizes
330
331
  agentId=agentId,
331
332
  reviewer=self.web3_client.normalize_address(clientAddress), # Also normalize reviewer field
332
- score=feedback_data.get('score'),
333
+ value=float(feedback_data.get("value")) if feedback_data.get("value") is not None else None,
333
334
  tags=tags,
334
335
  text=feedback_file.get('text'),
335
336
  capability=feedback_file.get('capability'),
@@ -377,7 +378,7 @@ class FeedbackManager:
377
378
  feedbackIndex
378
379
  )
379
380
 
380
- score, tag1, tag2, is_revoked = result
381
+ value_raw, value_decimals, tag1, tag2, is_revoked = result
381
382
 
382
383
  # Create feedback object (normalize address for consistency)
383
384
  normalized_address = self.web3_client.normalize_address(clientAddress)
@@ -394,7 +395,7 @@ class FeedbackManager:
394
395
  id=feedbackId,
395
396
  agentId=agentId,
396
397
  reviewer=normalized_address,
397
- score=int(score) if score and score > 0 else None,
398
+ value=decode_feedback_value(int(value_raw), int(value_decimals)),
398
399
  tags=tags,
399
400
  text=None, # Not stored on-chain
400
401
  capability=None, # Not stored on-chain
@@ -418,8 +419,8 @@ class FeedbackManager:
418
419
  skills: Optional[List[str]] = None,
419
420
  tasks: Optional[List[str]] = None,
420
421
  names: Optional[List[str]] = None,
421
- minScore: Optional[int] = None,
422
- maxScore: Optional[int] = None,
422
+ minValue: Optional[float] = None,
423
+ maxValue: Optional[float] = None,
423
424
  include_revoked: bool = False,
424
425
  first: int = 100,
425
426
  skip: int = 0,
@@ -431,14 +432,14 @@ class FeedbackManager:
431
432
  # This enables future semantic search capabilities
432
433
  return self.indexer.search_feedback(
433
434
  agentId, clientAddresses, tags, capabilities, skills, tasks, names,
434
- minScore, maxScore, include_revoked, first, skip
435
+ minValue, maxValue, include_revoked, first, skip
435
436
  )
436
437
 
437
438
  # Fallback: direct subgraph access (if indexer not available)
438
439
  if self.subgraph_client:
439
440
  return self._search_feedback_subgraph(
440
441
  agentId, clientAddresses, tags, capabilities, skills, tasks, names,
441
- minScore, maxScore, include_revoked, first, skip
442
+ minValue, maxValue, include_revoked, first, skip
442
443
  )
443
444
 
444
445
  # Fallback to blockchain
@@ -454,7 +455,7 @@ class FeedbackManager:
454
455
  tag1_filter = tags[0] if tags else ""
455
456
  tag2_filter = tags[1] if tags and len(tags) > 1 else ""
456
457
 
457
- # Read from blockchain - new signature returns: (clientAddresses, feedbackIndexes, scores, tag1s, tag2s, revokedStatuses)
458
+ # Read from blockchain - signature returns: (clients, feedbackIndexes, values, valueDecimals, tag1s, tag2s, revokedStatuses)
458
459
  result = self.web3_client.call_contract(
459
460
  self.reputation_registry,
460
461
  "readAllFeedback",
@@ -465,7 +466,7 @@ class FeedbackManager:
465
466
  include_revoked
466
467
  )
467
468
 
468
- clients, feedback_indexes, scores, tag1s, tag2s, revoked_statuses = result
469
+ clients, feedback_indexes, values, value_decimals, tag1s, tag2s, revoked_statuses = result
469
470
 
470
471
  # Convert to Feedback objects
471
472
  feedbacks = []
@@ -484,7 +485,7 @@ class FeedbackManager:
484
485
  id=feedbackId,
485
486
  agentId=agentId,
486
487
  reviewer=clients[i],
487
- score=int(scores[i]) if scores[i] and scores[i] > 0 else None,
488
+ value=decode_feedback_value(int(values[i]), int(value_decimals[i])),
488
489
  tags=tags_list,
489
490
  text=None,
490
491
  capability=None,
@@ -511,8 +512,8 @@ class FeedbackManager:
511
512
  skills: Optional[List[str]],
512
513
  tasks: Optional[List[str]],
513
514
  names: Optional[List[str]],
514
- minScore: Optional[int],
515
- maxScore: Optional[int],
515
+ minValue: Optional[float],
516
+ maxValue: Optional[float],
516
517
  include_revoked: bool,
517
518
  first: int,
518
519
  skip: int,
@@ -527,8 +528,8 @@ class FeedbackManager:
527
528
  skills=skills,
528
529
  tasks=tasks,
529
530
  names=names,
530
- minScore=minScore,
531
- maxScore=maxScore,
531
+ minValue=minValue,
532
+ maxValue=maxValue,
532
533
  includeRevoked=include_revoked
533
534
  )
534
535
 
@@ -584,7 +585,7 @@ class FeedbackManager:
584
585
  id=Feedback.create_id(agent_id_str, client_addr, feedback_idx),
585
586
  agentId=agent_id_str,
586
587
  reviewer=client_addr,
587
- score=fb_data.get('score'),
588
+ value=float(fb_data.get("value")) if fb_data.get("value") is not None else None,
588
589
  tags=tags_list,
589
590
  text=feedback_file.get('text'),
590
591
  capability=feedback_file.get('capability'),
@@ -757,14 +758,15 @@ class FeedbackManager:
757
758
  tag2_str
758
759
  )
759
760
 
760
- count, average_score = result
761
+ count, summary_value, summary_value_decimals = result
762
+ average_value = decode_feedback_value(int(summary_value), int(summary_value_decimals))
761
763
 
762
764
  # If no grouping requested, return simple summary
763
765
  if not groupBy:
764
766
  return {
765
767
  "agentId": agentId,
766
768
  "count": count,
767
- "averageScore": float(average_score) / 100.0 if average_score > 0 else 0.0,
769
+ "averageValue": average_value,
768
770
  "filters": {
769
771
  "clientAddresses": clientAddresses,
770
772
  "tag1": tag1,
@@ -786,7 +788,7 @@ class FeedbackManager:
786
788
  return {
787
789
  "agentId": agentId,
788
790
  "totalCount": count,
789
- "totalAverageScore": float(average_score) / 100.0 if average_score > 0 else 0.0,
791
+ "totalAverageValue": average_value,
790
792
  "groupedData": grouped_data,
791
793
  "filters": {
792
794
  "clientAddresses": clientAddresses,
@@ -828,15 +830,15 @@ class FeedbackManager:
828
830
 
829
831
  # Calculate summary statistics
830
832
  count = len(all_feedback)
831
- scores = [fb.score for fb in all_feedback if fb.score is not None]
832
- average_score = sum(scores) / len(scores) if scores else 0.0
833
+ values = [fb.value for fb in all_feedback if fb.value is not None]
834
+ average_value = sum(values) / len(values) if values else 0.0
833
835
 
834
836
  # If no grouping requested, return simple summary
835
837
  if not groupBy:
836
838
  return {
837
839
  "agentId": agentId,
838
840
  "count": count,
839
- "averageScore": average_score,
841
+ "averageValue": average_value,
840
842
  "filters": {
841
843
  "clientAddresses": clientAddresses,
842
844
  "tag1": tag1,
@@ -850,7 +852,7 @@ class FeedbackManager:
850
852
  return {
851
853
  "agentId": agentId,
852
854
  "totalCount": count,
853
- "totalAverageScore": average_score,
855
+ "totalAverageValue": average_value,
854
856
  "groupedData": grouped_data,
855
857
  "filters": {
856
858
  "clientAddresses": clientAddresses,
@@ -871,23 +873,23 @@ class FeedbackManager:
871
873
  if group_key not in grouped:
872
874
  grouped[group_key] = {
873
875
  "count": 0,
874
- "totalScore": 0.0,
875
- "averageScore": 0.0,
876
- "scores": [],
876
+ "totalValue": 0.0,
877
+ "averageValue": 0.0,
878
+ "values": [],
877
879
  "feedback": []
878
880
  }
879
881
 
880
882
  # Add feedback to group
881
883
  grouped[group_key]["count"] += 1
882
- if feedback.score is not None:
883
- grouped[group_key]["totalScore"] += feedback.score
884
- grouped[group_key]["scores"].append(feedback.score)
884
+ if feedback.value is not None:
885
+ grouped[group_key]["totalValue"] += float(feedback.value)
886
+ grouped[group_key]["values"].append(float(feedback.value))
885
887
  grouped[group_key]["feedback"].append(feedback)
886
888
 
887
889
  # Calculate averages for each group
888
890
  for group_data in grouped.values():
889
891
  if group_data["count"] > 0:
890
- group_data["averageScore"] = group_data["totalScore"] / group_data["count"]
892
+ group_data["averageValue"] = group_data["totalValue"] / group_data["count"]
891
893
 
892
894
  return grouped
893
895
 
@@ -87,7 +87,7 @@ class AgentIndexer:
87
87
  def _create_default_embeddings(self):
88
88
  """Create default embeddings model."""
89
89
  try:
90
- from sentence_transformers import SentenceTransformer
90
+ from sentence_transformers import SentenceTransformer # type: ignore[import-not-found]
91
91
  return SentenceTransformer('all-MiniLM-L6-v2')
92
92
  except ImportError:
93
93
  # Return None if sentence-transformers is not available
@@ -260,7 +260,7 @@ class AgentIndexer:
260
260
  raise ValueError(f"Failed to get agent data: {e}")
261
261
 
262
262
  # Load registration file
263
- registration_data = await self._load_registration_data(token_uri)
263
+ registration_data = await self._load_registration_data(agent_uri)
264
264
 
265
265
  # Create agent summary
266
266
  summary = self._create_agent_summary(
@@ -1082,7 +1082,7 @@ class AgentIndexer:
1082
1082
  id=Feedback.create_id(agentId, clientAddress, feedbackIndex),
1083
1083
  agentId=agentId,
1084
1084
  reviewer=self.web3_client.normalize_address(clientAddress),
1085
- score=feedback_data.get('score'),
1085
+ value=float(feedback_data.get("value")) if feedback_data.get("value") is not None else None,
1086
1086
  tags=tags,
1087
1087
  text=feedback_file.get('text'),
1088
1088
  capability=feedback_file.get('capability'),
@@ -1113,8 +1113,8 @@ class AgentIndexer:
1113
1113
  skills: Optional[List[str]] = None,
1114
1114
  tasks: Optional[List[str]] = None,
1115
1115
  names: Optional[List[str]] = None,
1116
- minScore: Optional[int] = None,
1117
- maxScore: Optional[int] = None,
1116
+ minValue: Optional[float] = None,
1117
+ maxValue: Optional[float] = None,
1118
1118
  include_revoked: bool = False,
1119
1119
  first: int = 100,
1120
1120
  skip: int = 0,
@@ -1140,7 +1140,7 @@ class AgentIndexer:
1140
1140
  if subgraph_client:
1141
1141
  return self._search_feedback_subgraph(
1142
1142
  full_agent_id, clientAddresses, tags, capabilities, skills, tasks, names,
1143
- minScore, maxScore, include_revoked, first, skip, subgraph_client
1143
+ minValue, maxValue, include_revoked, first, skip, subgraph_client
1144
1144
  )
1145
1145
 
1146
1146
  # Fallback not implemented (would require blockchain queries)
@@ -1156,8 +1156,8 @@ class AgentIndexer:
1156
1156
  skills: Optional[List[str]],
1157
1157
  tasks: Optional[List[str]],
1158
1158
  names: Optional[List[str]],
1159
- minScore: Optional[int],
1160
- maxScore: Optional[int],
1159
+ minValue: Optional[float],
1160
+ maxValue: Optional[float],
1161
1161
  include_revoked: bool,
1162
1162
  first: int,
1163
1163
  skip: int,
@@ -1178,8 +1178,8 @@ class AgentIndexer:
1178
1178
  skills=skills,
1179
1179
  tasks=tasks,
1180
1180
  names=names,
1181
- minScore=minScore,
1182
- maxScore=maxScore,
1181
+ minValue=minValue,
1182
+ maxValue=maxValue,
1183
1183
  includeRevoked=include_revoked
1184
1184
  )
1185
1185
 
@@ -1665,7 +1665,7 @@ class AgentIndexer:
1665
1665
  - updatedAt (timestamp)
1666
1666
  - totalFeedback (count)
1667
1667
  - name (alphabetical)
1668
- - averageScore (reputation, if available)
1668
+ - averageValue (reputation, if available)
1669
1669
  """
1670
1670
  if not sort or len(sort) == 0:
1671
1671
  # Default: sort by createdAt descending (newest first)
@@ -1700,9 +1700,9 @@ class AgentIndexer:
1700
1700
  reg_file = agent.get('registrationFile', {})
1701
1701
  return reg_file.get('name', '').lower()
1702
1702
 
1703
- elif field == 'averageScore':
1704
- # If reputation search was done, averageScore may be available
1705
- return agent.get('averageScore', 0)
1703
+ elif field == 'averageValue':
1704
+ # If reputation search was done, averageValue may be available
1705
+ return agent.get('averageValue', 0)
1706
1706
 
1707
1707
  else:
1708
1708
  logger.warning(f"Unknown sort field: {field}, defaulting to createdAt")
@@ -185,7 +185,9 @@ class Feedback:
185
185
  id: tuple # (agentId, clientAddress, feedbackIndex) - tuple for efficiency
186
186
  agentId: AgentId
187
187
  reviewer: Address
188
- score: Optional[int] # 0-100
188
+ # ReputationRegistry Jan 2026: decimal value computed as (value:int256 / 10^valueDecimals).
189
+ # SDK exposes ONLY the computed value.
190
+ value: Optional[float]
189
191
  tags: List[str] = field(default_factory=list)
190
192
  text: Optional[str] = None
191
193
  context: Optional[Dict[str, Any]] = None
@@ -291,8 +293,8 @@ class SearchFeedbackParams:
291
293
  tasks: Optional[List[str]] = None
292
294
  names: Optional[List[str]] = None # MCP tool/resource/prompt names
293
295
  endpoint: Optional[str] = None # Filter by endpoint URI
294
- minScore: Optional[int] = None # 0-100
295
- maxScore: Optional[int] = None # 0-100
296
+ minValue: Optional[float] = None
297
+ maxValue: Optional[float] = None
296
298
  includeRevoked: bool = False
297
299
 
298
300
  def to_dict(self) -> Dict[str, Any]:
@@ -502,7 +502,7 @@ class SDK:
502
502
  skills: Optional[List[str]] = None,
503
503
  tasks: Optional[List[str]] = None,
504
504
  names: Optional[List[str]] = None,
505
- minAverageScore: Optional[int] = None, # 0-100
505
+ minAverageValue: Optional[float] = None,
506
506
  includeRevoked: bool = False,
507
507
  page_size: int = 50,
508
508
  cursor: Optional[str] = None,
@@ -522,7 +522,7 @@ class SDK:
522
522
  return asyncio.run(
523
523
  self._search_agents_by_reputation_across_chains(
524
524
  agents, tags, reviewers, capabilities, skills, tasks, names,
525
- minAverageScore, includeRevoked, page_size, cursor, sort, chains
525
+ minAverageValue, includeRevoked, page_size, cursor, sort, chains
526
526
  )
527
527
  )
528
528
 
@@ -556,7 +556,7 @@ class SDK:
556
556
  skills=skills,
557
557
  tasks=tasks,
558
558
  names=names,
559
- minAverageScore=minAverageScore,
559
+ minAverageValue=minAverageValue,
560
560
  includeRevoked=includeRevoked,
561
561
  first=page_size,
562
562
  skip=skip,
@@ -591,7 +591,7 @@ class SDK:
591
591
  mcpResources=reg_file.get('mcpResources', []),
592
592
  active=reg_file.get('active', True),
593
593
  x402support=reg_file.get('x402support', False),
594
- extras={'averageScore': agent_data.get('averageScore')}
594
+ extras={'averageValue': agent_data.get('averageValue')}
595
595
  )
596
596
  results.append(agent_summary)
597
597
 
@@ -610,7 +610,7 @@ class SDK:
610
610
  skills: Optional[List[str]],
611
611
  tasks: Optional[List[str]],
612
612
  names: Optional[List[str]],
613
- minAverageScore: Optional[int],
613
+ minAverageValue: Optional[float],
614
614
  includeRevoked: bool,
615
615
  page_size: int,
616
616
  cursor: Optional[str],
@@ -668,7 +668,7 @@ class SDK:
668
668
  skills=skills,
669
669
  tasks=tasks,
670
670
  names=names,
671
- minAverageScore=minAverageScore,
671
+ minAverageValue=minAverageValue,
672
672
  includeRevoked=includeRevoked,
673
673
  first=page_size * 3, # Fetch extra to allow for filtering/sorting
674
674
  skip=0, # We'll handle pagination after aggregation
@@ -748,14 +748,14 @@ class SDK:
748
748
  mcpResources=reg_file.get('mcpResources', []),
749
749
  active=reg_file.get('active', True),
750
750
  x402support=reg_file.get('x402support', False),
751
- extras={'averageScore': agent_data.get('averageScore')}
751
+ extras={'averageValue': agent_data.get('averageValue')}
752
752
  )
753
753
  results.append(agent_summary)
754
754
 
755
- # Sort by averageScore (descending) if available, otherwise by createdAt
755
+ # Sort by averageValue (descending) if available, otherwise by createdAt
756
756
  results.sort(
757
757
  key=lambda x: (
758
- x.extras.get('averageScore') if x.extras.get('averageScore') is not None else 0,
758
+ x.extras.get('averageValue') if x.extras.get('averageValue') is not None else 0,
759
759
  x.chainId,
760
760
  x.agentId
761
761
  ),
@@ -785,14 +785,14 @@ class SDK:
785
785
  """Prepare an off-chain feedback file payload.
786
786
 
787
787
  This is intentionally off-chain-only; it does not attempt to represent
788
- the on-chain fields (score/tag1/tag2/endpoint-on-chain).
788
+ the on-chain fields (value/tag1/tag2/endpoint-on-chain).
789
789
  """
790
790
  return self.feedback_manager.prepareFeedbackFile(input)
791
791
 
792
792
  def giveFeedback(
793
793
  self,
794
794
  agentId: "AgentId",
795
- score: int,
795
+ value: Union[int, float, str],
796
796
  tag1: Optional[str] = None,
797
797
  tag2: Optional[str] = None,
798
798
  endpoint: Optional[str] = None,
@@ -805,7 +805,7 @@ class SDK:
805
805
  """
806
806
  return self.feedback_manager.giveFeedback(
807
807
  agentId=agentId,
808
- score=score,
808
+ value=value,
809
809
  tag1=tag1,
810
810
  tag2=tag2,
811
811
  endpoint=endpoint,
@@ -832,8 +832,8 @@ class SDK:
832
832
  skills: Optional[List[str]] = None,
833
833
  tasks: Optional[List[str]] = None,
834
834
  names: Optional[List[str]] = None,
835
- minScore: Optional[int] = None,
836
- maxScore: Optional[int] = None,
835
+ minValue: Optional[float] = None,
836
+ maxValue: Optional[float] = None,
837
837
  include_revoked: bool = False,
838
838
  first: int = 100,
839
839
  skip: int = 0,
@@ -847,8 +847,8 @@ class SDK:
847
847
  skills=skills,
848
848
  tasks=tasks,
849
849
  names=names,
850
- minScore=minScore,
851
- maxScore=maxScore,
850
+ minValue=minValue,
851
+ maxValue=maxValue,
852
852
  include_revoked=include_revoked,
853
853
  first=first,
854
854
  skip=skip,
@@ -260,7 +260,7 @@ class SubgraphClient:
260
260
  orderDirection: desc
261
261
  ) {{
262
262
  id
263
- score
263
+ value
264
264
  feedbackIndex
265
265
  tag1
266
266
  tag2
@@ -326,8 +326,7 @@ class SubgraphClient:
326
326
  agentId
327
327
  }}
328
328
  totalFeedback
329
- averageScore
330
- scoreDistribution
329
+ averageFeedbackValue
331
330
  totalValidations
332
331
  completedValidations
333
332
  averageValidationScore
@@ -416,7 +415,7 @@ class SubgraphClient:
416
415
  agent { id agentId chainId }
417
416
  clientAddress
418
417
  feedbackIndex
419
- score
418
+ value
420
419
  tag1
421
420
  tag2
422
421
  endpoint
@@ -516,11 +515,11 @@ class SubgraphClient:
516
515
  # Join all tag alternatives (each already contains complete filter set)
517
516
  tag_filter_condition = ", ".join([f"{{ {item} }}" for item in tag_where_items])
518
517
 
519
- if params.minScore is not None:
520
- where_conditions.append(f'score_gte: {params.minScore}')
518
+ if params.minValue is not None:
519
+ where_conditions.append(f'value_gte: "{params.minValue}"')
521
520
 
522
- if params.maxScore is not None:
523
- where_conditions.append(f'score_lte: {params.maxScore}')
521
+ if params.maxValue is not None:
522
+ where_conditions.append(f'value_lte: "{params.maxValue}"')
524
523
 
525
524
  # Feedback file filters
526
525
  feedback_file_filters = []
@@ -566,7 +565,7 @@ class SubgraphClient:
566
565
  agent {{ id agentId chainId }}
567
566
  clientAddress
568
567
  feedbackIndex
569
- score
568
+ value
570
569
  tag1
571
570
  tag2
572
571
  endpoint
@@ -616,7 +615,7 @@ class SubgraphClient:
616
615
  skills: Optional[List[str]] = None,
617
616
  tasks: Optional[List[str]] = None,
618
617
  names: Optional[List[str]] = None,
619
- minAverageScore: Optional[int] = None, # 0-100
618
+ minAverageValue: Optional[float] = None,
620
619
  includeRevoked: bool = False,
621
620
  first: int = 100,
622
621
  skip: int = 0,
@@ -633,7 +632,7 @@ class SubgraphClient:
633
632
  capabilities: List of capabilities to filter feedback by
634
633
  skills: List of skills to filter feedback by
635
634
  tasks: List of tasks to filter feedback by
636
- minAverageScore: Minimum average score (0-100) for included agents
635
+ minAverageValue: Minimum average value for included agents
637
636
  includeRevoked: Whether to include revoked feedback in calculations
638
637
  first: Number of results to return
639
638
  skip: Number of results to skip
@@ -641,7 +640,7 @@ class SubgraphClient:
641
640
  order_direction: Sort direction (asc/desc)
642
641
 
643
642
  Returns:
644
- List of agents with averageScore field calculated from filtered feedback
643
+ List of agents with averageValue field calculated from filtered feedback
645
644
  """
646
645
  # Build feedback filter
647
646
  feedback_filters = []
@@ -790,7 +789,7 @@ class SubgraphClient:
790
789
  createdAt
791
790
  }}
792
791
  feedback(where: {feedback_where_for_agents}) {{
793
- score
792
+ value
794
793
  isRevoked
795
794
  feedbackFile {{
796
795
  capability
@@ -813,37 +812,33 @@ class SubgraphClient:
813
812
 
814
813
  agents_result = result.get('agents', [])
815
814
 
816
- # Calculate average scores
815
+ # Calculate average values
817
816
  for agent in agents_result:
818
817
  feedbacks = agent.get('feedback', [])
819
818
  if feedbacks:
820
- scores = [int(fb['score']) for fb in feedbacks if fb.get('score', 0) > 0]
821
- if scores:
822
- avg_score = sum(scores) / len(scores)
823
- agent['averageScore'] = avg_score
824
- else:
825
- agent['averageScore'] = None
819
+ values = [float(fb["value"]) for fb in feedbacks if fb.get("value") is not None]
820
+ agent["averageValue"] = (sum(values) / len(values)) if values else None
826
821
  else:
827
- agent['averageScore'] = None
822
+ agent["averageValue"] = None
828
823
 
829
- # Filter by minAverageScore
830
- if minAverageScore is not None:
824
+ # Filter by minAverageValue
825
+ if minAverageValue is not None:
831
826
  agents_result = [
832
827
  agent for agent in agents_result
833
- if agent.get('averageScore') is not None and agent['averageScore'] >= minAverageScore
828
+ if agent.get("averageValue") is not None and agent["averageValue"] >= minAverageValue
834
829
  ]
835
830
 
836
831
  # For reputation search, filter logic:
837
- # - If specific agents were requested, return them even if averageScore is None
832
+ # - If specific agents were requested, return them even if averageValue is None
838
833
  # (the user explicitly asked for these agents, so return them)
839
834
  # - If general search (no specific agents), only return agents with reputation data
840
835
  if agents is None or len(agents) == 0:
841
836
  # General search - only return agents with reputation
842
837
  agents_result = [
843
838
  agent for agent in agents_result
844
- if agent.get('averageScore') is not None
839
+ if agent.get("averageValue") is not None
845
840
  ]
846
- # else: specific agents requested - return all requested agents (even if averageScore is None)
841
+ # else: specific agents requested - return all requested agents (even if averageValue is None)
847
842
 
848
843
  return agents_result
849
844
 
@@ -0,0 +1,91 @@
1
+ """
2
+ Value encoding utilities for ReputationRegistry (Jan 2026).
3
+
4
+ On-chain representation: (value:int256, valueDecimals:uint8)
5
+ Human representation: value / 10^valueDecimals
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from decimal import Decimal, ROUND_HALF_UP, getcontext
12
+ from typing import Tuple, Union
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Plenty of headroom for scaling and clamping checks
17
+ getcontext().prec = 120
18
+
19
+ MAX_DECIMALS = 18
20
+ # Solidity constant (raw int256 magnitude)
21
+ MAX_ABS_VALUE_RAW = 10**50
22
+
23
+
24
+ def encode_feedback_value(input_value: Union[int, float, str, Decimal]) -> Tuple[int, int, str]:
25
+ """
26
+ Encode a user-facing value into the on-chain (value, valueDecimals) pair.
27
+
28
+ Rules:
29
+ - str: parsed using Decimal (no float casting). If >18 decimals, it is rounded half-up to 18 decimals.
30
+ - float: accepted and rounded half-up to 18 decimals (never rejected).
31
+ - int/Decimal: treated similarly; Decimal preserves precision.
32
+
33
+ Returns: (value_raw:int, value_decimals:int, normalized:str)
34
+ """
35
+ if isinstance(input_value, Decimal):
36
+ dec = input_value
37
+ normalized = format(dec, "f")
38
+ elif isinstance(input_value, int):
39
+ dec = Decimal(input_value)
40
+ normalized = str(input_value)
41
+ elif isinstance(input_value, float):
42
+ # Avoid binary float artifacts by going through Decimal(str(x)), then quantize to 18 places.
43
+ dec = Decimal(str(input_value)).quantize(Decimal("1e-18"), rounding=ROUND_HALF_UP)
44
+ normalized = format(dec, "f")
45
+ elif isinstance(input_value, str):
46
+ s = input_value.strip()
47
+ if s == "":
48
+ raise ValueError("value cannot be an empty string")
49
+ dec = Decimal(s)
50
+ # Expand to plain decimal string (no exponent) for determining decimals
51
+ normalized = format(dec, "f")
52
+ else:
53
+ raise TypeError(f"value must be int|float|str|Decimal, got {type(input_value)}")
54
+
55
+ # Determine decimals from the normalized representation.
56
+ # This preserves trailing zeros for string inputs like "1.2300".
57
+ if "." in normalized:
58
+ decimals = len(normalized.split(".", 1)[1])
59
+ else:
60
+ decimals = 0
61
+
62
+ if decimals > MAX_DECIMALS:
63
+ dec = dec.quantize(Decimal("1e-18"), rounding=ROUND_HALF_UP)
64
+ normalized = format(dec, "f") # keeps fixed 18 decimals
65
+ decimals = MAX_DECIMALS
66
+
67
+ scale = Decimal(10) ** decimals
68
+ raw_decimal = dec * scale
69
+ raw_int = int(raw_decimal.to_integral_value(rounding=ROUND_HALF_UP))
70
+
71
+ if abs(raw_int) > MAX_ABS_VALUE_RAW:
72
+ raw_int = MAX_ABS_VALUE_RAW if raw_int > 0 else -MAX_ABS_VALUE_RAW
73
+ clamped = Decimal(raw_int) / (Decimal(10) ** decimals)
74
+ normalized = format(clamped, "f")
75
+ logger.warning(
76
+ "Feedback value %r exceeds on-chain max magnitude; clamped to %s (decimals=%s)",
77
+ input_value,
78
+ normalized,
79
+ decimals,
80
+ )
81
+
82
+ return raw_int, decimals, normalized
83
+
84
+
85
+ def decode_feedback_value(value_raw: int, value_decimals: int) -> float:
86
+ """Decode (value, valueDecimals) into a Python float."""
87
+ if value_decimals < 0:
88
+ raise ValueError("valueDecimals cannot be negative")
89
+ return float(Decimal(value_raw) / (Decimal(10) ** int(value_decimals)))
90
+
91
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent0-sdk
3
- Version: 1.0.2
3
+ Version: 1.2.0
4
4
  Summary: Python SDK for agent portability, discovery and trust based on ERC-8004
5
5
  Author-email: Agent0 Team <team@ag0.xyz>
6
6
  License: MIT License
@@ -216,7 +216,7 @@ agent_summary = sdk.getAgent("11155111:123")
216
216
  # On-chain-only feedback (no off-chain upload, even if IPFS is configured)
217
217
  feedback = sdk.giveFeedback(
218
218
  agentId="11155111:123",
219
- score=85, # 0-100 (mandatory)
219
+ value=85, # number|string
220
220
  tag1="data_analyst", # Optional: tags are strings
221
221
  tag2="finance",
222
222
  endpoint="https://example.com/endpoint", # Optional: saved on-chain
@@ -232,7 +232,7 @@ feedback_file = sdk.prepareFeedbackFile({
232
232
 
233
233
  feedback = sdk.giveFeedback(
234
234
  agentId="11155111:123",
235
- score=85,
235
+ value=85,
236
236
  tag1="data_analyst",
237
237
  tag2="finance",
238
238
  endpoint="https://example.com/endpoint",
@@ -243,13 +243,13 @@ feedback = sdk.giveFeedback(
243
243
  results = sdk.searchFeedback(
244
244
  agentId="11155111:123",
245
245
  capabilities=["tools"],
246
- minScore=80,
247
- maxScore=100
246
+ minValue=80,
247
+ maxValue=100
248
248
  )
249
249
 
250
250
  # Get reputation summary
251
251
  summary = sdk.getReputationSummary("11155111:123")
252
- print(f"Average score: {summary['averageScore']}")
252
+ print(f"Average value: {summary['averageValue']}")
253
253
  ```
254
254
 
255
255
  ## IPFS Configuration Options
@@ -18,6 +18,7 @@ agent0_sdk/core/models.py
18
18
  agent0_sdk/core/oasf_validator.py
19
19
  agent0_sdk/core/sdk.py
20
20
  agent0_sdk/core/subgraph_client.py
21
+ agent0_sdk/core/value_encoding.py
21
22
  agent0_sdk/core/web3_client.py
22
23
  agent0_sdk/taxonomies/all_domains.json
23
24
  agent0_sdk/taxonomies/all_skills.json
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agent0-sdk"
7
- version = "1.0.2"
7
+ version = "1.2.0"
8
8
  description = "Python SDK for agent portability, discovery and trust based on ERC-8004"
9
9
  authors = [
10
10
  {name = "Agent0 Team", email = "team@ag0.xyz"}
File without changes
File without changes
File without changes