agent0-sdk 1.4.2__tar.gz → 1.5.1b1__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 (28) hide show
  1. {agent0_sdk-1.4.2/agent0_sdk.egg-info → agent0_sdk-1.5.1b1}/PKG-INFO +163 -9
  2. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/README.md +162 -8
  3. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/__init__.py +7 -3
  4. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/contracts.py +1 -0
  5. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/feedback_manager.py +75 -78
  6. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/indexer.py +645 -635
  7. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/models.py +91 -12
  8. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/sdk.py +26 -314
  9. agent0_sdk-1.5.1b1/agent0_sdk/core/semantic_search_client.py +70 -0
  10. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/subgraph_client.py +182 -239
  11. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1/agent0_sdk.egg-info}/PKG-INFO +163 -9
  12. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk.egg-info/SOURCES.txt +1 -0
  13. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk.egg-info/top_level.txt +0 -1
  14. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/pyproject.toml +1 -1
  15. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/LICENSE +0 -0
  16. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/MANIFEST.in +0 -0
  17. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/agent.py +0 -0
  18. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/endpoint_crawler.py +0 -0
  19. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/ipfs_client.py +0 -0
  20. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/oasf_validator.py +0 -0
  21. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/transaction_handle.py +0 -0
  22. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/value_encoding.py +0 -0
  23. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/core/web3_client.py +0 -0
  24. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/taxonomies/all_domains.json +0 -0
  25. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk/taxonomies/all_skills.json +0 -0
  26. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk.egg-info/dependency_links.txt +0 -0
  27. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/agent0_sdk.egg-info/requires.txt +0 -0
  28. {agent0_sdk-1.4.2 → agent0_sdk-1.5.1b1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent0-sdk
3
- Version: 1.4.2
3
+ Version: 1.5.1b1
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
@@ -104,6 +104,12 @@ Agent0 SDK enables you to:
104
104
  pip install agent0-sdk
105
105
  ```
106
106
 
107
+ To install the **1.5.1 pre-release** explicitly:
108
+
109
+ ```bash
110
+ pip install --pre agent0-sdk==1.5.1b1
111
+ ```
112
+
107
113
  ### Install from Source
108
114
 
109
115
  ```bash
@@ -198,14 +204,18 @@ print(f"Updated: {update.agentURI}")
198
204
  ```python
199
205
  # Search by name, capabilities, or attributes
200
206
  results = sdk.searchAgents(
201
- name="AI", # Substring search
202
- mcpTools=["code_generation"], # Specific MCP tools
203
- a2aSkills=["python"], # Specific A2A skills
204
- active=True, # Only active agents
205
- x402support=True # Payment support
207
+ filters={
208
+ "name": "AI", # substring
209
+ "mcpTools": ["code_generation"],
210
+ "a2aSkills": ["python"],
211
+ "active": True,
212
+ "x402support": True,
213
+ "feedback": {"minValue": 80, "tag": "enterprise", "includeRevoked": False},
214
+ },
215
+ options={"sort": ["updatedAt:desc"]},
206
216
  )
207
217
 
208
- for agent in results['items']:
218
+ for agent in results:
209
219
  print(f"{agent.name}: {agent.description}")
210
220
  print(f" Tools: {agent.mcpTools}")
211
221
  print(f" Skills: {agent.a2aSkills}")
@@ -355,6 +365,151 @@ The SDK includes complete OASF v0.8.0 taxonomy files:
355
365
 
356
366
  Browse these files to find appropriate skill and domain slugs. For more information, see the [OASF specification](https://github.com/agntcy/oasf) and [Release Notes v0.31](RELEASE_NOTES_0.31.md).
357
367
 
368
+ ## Unified Search Reference (Exhaustive)
369
+
370
+ The unified search API is:
371
+
372
+ ```python
373
+ results = sdk.searchAgents(filters: dict | SearchFilters | None = None, options: dict | SearchOptions | None = None)
374
+ # results: list[AgentSummary]
375
+ ```
376
+
377
+ ### `FeedbackFilters` (used as `filters["feedback"]`)
378
+
379
+ ```python
380
+ @dataclass
381
+ class FeedbackFilters:
382
+ hasFeedback: Optional[bool] = None
383
+ hasNoFeedback: Optional[bool] = None
384
+ includeRevoked: Optional[bool] = None
385
+ minValue: Optional[float] = None
386
+ maxValue: Optional[float] = None
387
+ minCount: Optional[int] = None
388
+ maxCount: Optional[int] = None
389
+ fromReviewers: Optional[List[Address]] = None
390
+ endpoint: Optional[str] = None # substring match
391
+ hasResponse: Optional[bool] = None
392
+ tag1: Optional[str] = None
393
+ tag2: Optional[str] = None
394
+ tag: Optional[str] = None # matches tag1 OR tag2
395
+ ```
396
+
397
+ | Field | Semantics |
398
+ | --- | --- |
399
+ | `hasFeedback` / `hasNoFeedback` | Filter by whether the agent has any feedback |
400
+ | `includeRevoked` | Include revoked feedback entries in the pool used for filtering |
401
+ | `minValue` / `maxValue` | Threshold on **average value** over feedback matching the other feedback constraints (inclusive) |
402
+ | `minCount` / `maxCount` | Threshold on **count** over feedback matching the other feedback constraints (inclusive) |
403
+ | `fromReviewers` | Only consider feedback from these reviewer wallets |
404
+ | `endpoint` | Only consider feedback whose `endpoint` contains this substring |
405
+ | `hasResponse` | Only consider feedback that has at least one response (if supported) |
406
+ | `tag1` / `tag2` | Only consider feedback matching tag1/tag2 |
407
+ | `tag` | Shorthand: match either tag1 OR tag2 |
408
+
409
+ ### `SearchFilters`
410
+
411
+ ```python
412
+ DateLike = Union[datetime, str, int]
413
+
414
+ @dataclass
415
+ class SearchFilters:
416
+ chains: Optional[Union[List[ChainId], Literal["all"]]] = None
417
+ agentIds: Optional[List[AgentId]] = None
418
+
419
+ name: Optional[str] = None
420
+ description: Optional[str] = None
421
+
422
+ owners: Optional[List[Address]] = None
423
+ operators: Optional[List[Address]] = None
424
+
425
+ hasRegistrationFile: Optional[bool] = None
426
+ hasWeb: Optional[bool] = None
427
+ hasMCP: Optional[bool] = None
428
+ hasA2A: Optional[bool] = None
429
+ hasOASF: Optional[bool] = None
430
+ hasEndpoints: Optional[bool] = None
431
+
432
+ webContains: Optional[str] = None
433
+ mcpContains: Optional[str] = None
434
+ a2aContains: Optional[str] = None
435
+ ensContains: Optional[str] = None
436
+ didContains: Optional[str] = None
437
+
438
+ walletAddress: Optional[Address] = None
439
+
440
+ supportedTrust: Optional[List[str]] = None
441
+ a2aSkills: Optional[List[str]] = None
442
+ mcpTools: Optional[List[str]] = None
443
+ mcpPrompts: Optional[List[str]] = None
444
+ mcpResources: Optional[List[str]] = None
445
+ oasfSkills: Optional[List[str]] = None
446
+ oasfDomains: Optional[List[str]] = None
447
+
448
+ active: Optional[bool] = None
449
+ x402support: Optional[bool] = None
450
+
451
+ registeredAtFrom: Optional[DateLike] = None
452
+ registeredAtTo: Optional[DateLike] = None
453
+ updatedAtFrom: Optional[DateLike] = None
454
+ updatedAtTo: Optional[DateLike] = None
455
+
456
+ hasMetadataKey: Optional[str] = None
457
+ metadataValue: Optional[Dict[str, str]] = None # { key, value }
458
+
459
+ keyword: Optional[str] = None
460
+ feedback: Optional[FeedbackFilters] = None
461
+ ```
462
+
463
+ ### `SearchOptions`
464
+
465
+ ```python
466
+ @dataclass
467
+ class SearchOptions:
468
+ sort: Optional[List[str]] = None
469
+ semanticMinScore: Optional[float] = None
470
+ semanticTopK: Optional[int] = None
471
+ ```
472
+
473
+ ### `AgentSummary` (returned items)
474
+
475
+ ```python
476
+ @dataclass
477
+ class AgentSummary:
478
+ chainId: ChainId
479
+ agentId: AgentId
480
+ name: str
481
+ image: Optional[URI]
482
+ description: str
483
+ owners: List[Address]
484
+ operators: List[Address]
485
+ # Endpoint strings (present when advertised; not booleans)
486
+ mcp: Optional[str] = None
487
+ a2a: Optional[str] = None
488
+ web: Optional[str] = None
489
+ email: Optional[str] = None
490
+ ens: Optional[str] = None
491
+ did: Optional[str] = None
492
+ walletAddress: Optional[Address] = None
493
+ supportedTrusts: List[str] = field(default_factory=list)
494
+ a2aSkills: List[str] = field(default_factory=list)
495
+ mcpTools: List[str] = field(default_factory=list)
496
+ mcpPrompts: List[str] = field(default_factory=list)
497
+ mcpResources: List[str] = field(default_factory=list)
498
+ oasfSkills: List[str] = field(default_factory=list)
499
+ oasfDomains: List[str] = field(default_factory=list)
500
+ active: bool = False
501
+ x402support: bool = False
502
+ createdAt: Optional[int] = None
503
+ updatedAt: Optional[int] = None
504
+ lastActivity: Optional[int] = None
505
+ agentURI: Optional[str] = None
506
+ agentURIType: Optional[str] = None
507
+ feedbackCount: Optional[int] = None
508
+ averageValue: Optional[float] = None
509
+ semanticScore: Optional[float] = None
510
+ extras: Dict[str, Any] = field(default_factory=dict)
511
+ ```
512
+
358
513
  ## Use Cases
359
514
 
360
515
  - **Building agent marketplaces** - Create platforms where developers can discover, evaluate, and integrate agents based on their capabilities and reputation
@@ -364,10 +519,9 @@ Browse these files to find appropriate skill and domain slugs. For more informat
364
519
 
365
520
  ## 🚀 Coming Soon
366
521
 
367
- - More chains (currently Ethereum Sepolia + Ethereum Mainnet)
522
+ - More chains (currently Ethereum Mainnet + Ethereum Sepolia + Polygon Mainnet)
368
523
  - Support for validations
369
524
  - Enhanced x402 payments
370
- - Semantic/Vectorial search
371
525
  - Advanced reputation aggregation
372
526
  - Import/Export to centralized catalogues
373
527
 
@@ -34,6 +34,12 @@ Agent0 SDK enables you to:
34
34
  pip install agent0-sdk
35
35
  ```
36
36
 
37
+ To install the **1.5.1 pre-release** explicitly:
38
+
39
+ ```bash
40
+ pip install --pre agent0-sdk==1.5.1b1
41
+ ```
42
+
37
43
  ### Install from Source
38
44
 
39
45
  ```bash
@@ -128,14 +134,18 @@ print(f"Updated: {update.agentURI}")
128
134
  ```python
129
135
  # Search by name, capabilities, or attributes
130
136
  results = sdk.searchAgents(
131
- name="AI", # Substring search
132
- mcpTools=["code_generation"], # Specific MCP tools
133
- a2aSkills=["python"], # Specific A2A skills
134
- active=True, # Only active agents
135
- x402support=True # Payment support
137
+ filters={
138
+ "name": "AI", # substring
139
+ "mcpTools": ["code_generation"],
140
+ "a2aSkills": ["python"],
141
+ "active": True,
142
+ "x402support": True,
143
+ "feedback": {"minValue": 80, "tag": "enterprise", "includeRevoked": False},
144
+ },
145
+ options={"sort": ["updatedAt:desc"]},
136
146
  )
137
147
 
138
- for agent in results['items']:
148
+ for agent in results:
139
149
  print(f"{agent.name}: {agent.description}")
140
150
  print(f" Tools: {agent.mcpTools}")
141
151
  print(f" Skills: {agent.a2aSkills}")
@@ -285,6 +295,151 @@ The SDK includes complete OASF v0.8.0 taxonomy files:
285
295
 
286
296
  Browse these files to find appropriate skill and domain slugs. For more information, see the [OASF specification](https://github.com/agntcy/oasf) and [Release Notes v0.31](RELEASE_NOTES_0.31.md).
287
297
 
298
+ ## Unified Search Reference (Exhaustive)
299
+
300
+ The unified search API is:
301
+
302
+ ```python
303
+ results = sdk.searchAgents(filters: dict | SearchFilters | None = None, options: dict | SearchOptions | None = None)
304
+ # results: list[AgentSummary]
305
+ ```
306
+
307
+ ### `FeedbackFilters` (used as `filters["feedback"]`)
308
+
309
+ ```python
310
+ @dataclass
311
+ class FeedbackFilters:
312
+ hasFeedback: Optional[bool] = None
313
+ hasNoFeedback: Optional[bool] = None
314
+ includeRevoked: Optional[bool] = None
315
+ minValue: Optional[float] = None
316
+ maxValue: Optional[float] = None
317
+ minCount: Optional[int] = None
318
+ maxCount: Optional[int] = None
319
+ fromReviewers: Optional[List[Address]] = None
320
+ endpoint: Optional[str] = None # substring match
321
+ hasResponse: Optional[bool] = None
322
+ tag1: Optional[str] = None
323
+ tag2: Optional[str] = None
324
+ tag: Optional[str] = None # matches tag1 OR tag2
325
+ ```
326
+
327
+ | Field | Semantics |
328
+ | --- | --- |
329
+ | `hasFeedback` / `hasNoFeedback` | Filter by whether the agent has any feedback |
330
+ | `includeRevoked` | Include revoked feedback entries in the pool used for filtering |
331
+ | `minValue` / `maxValue` | Threshold on **average value** over feedback matching the other feedback constraints (inclusive) |
332
+ | `minCount` / `maxCount` | Threshold on **count** over feedback matching the other feedback constraints (inclusive) |
333
+ | `fromReviewers` | Only consider feedback from these reviewer wallets |
334
+ | `endpoint` | Only consider feedback whose `endpoint` contains this substring |
335
+ | `hasResponse` | Only consider feedback that has at least one response (if supported) |
336
+ | `tag1` / `tag2` | Only consider feedback matching tag1/tag2 |
337
+ | `tag` | Shorthand: match either tag1 OR tag2 |
338
+
339
+ ### `SearchFilters`
340
+
341
+ ```python
342
+ DateLike = Union[datetime, str, int]
343
+
344
+ @dataclass
345
+ class SearchFilters:
346
+ chains: Optional[Union[List[ChainId], Literal["all"]]] = None
347
+ agentIds: Optional[List[AgentId]] = None
348
+
349
+ name: Optional[str] = None
350
+ description: Optional[str] = None
351
+
352
+ owners: Optional[List[Address]] = None
353
+ operators: Optional[List[Address]] = None
354
+
355
+ hasRegistrationFile: Optional[bool] = None
356
+ hasWeb: Optional[bool] = None
357
+ hasMCP: Optional[bool] = None
358
+ hasA2A: Optional[bool] = None
359
+ hasOASF: Optional[bool] = None
360
+ hasEndpoints: Optional[bool] = None
361
+
362
+ webContains: Optional[str] = None
363
+ mcpContains: Optional[str] = None
364
+ a2aContains: Optional[str] = None
365
+ ensContains: Optional[str] = None
366
+ didContains: Optional[str] = None
367
+
368
+ walletAddress: Optional[Address] = None
369
+
370
+ supportedTrust: Optional[List[str]] = None
371
+ a2aSkills: Optional[List[str]] = None
372
+ mcpTools: Optional[List[str]] = None
373
+ mcpPrompts: Optional[List[str]] = None
374
+ mcpResources: Optional[List[str]] = None
375
+ oasfSkills: Optional[List[str]] = None
376
+ oasfDomains: Optional[List[str]] = None
377
+
378
+ active: Optional[bool] = None
379
+ x402support: Optional[bool] = None
380
+
381
+ registeredAtFrom: Optional[DateLike] = None
382
+ registeredAtTo: Optional[DateLike] = None
383
+ updatedAtFrom: Optional[DateLike] = None
384
+ updatedAtTo: Optional[DateLike] = None
385
+
386
+ hasMetadataKey: Optional[str] = None
387
+ metadataValue: Optional[Dict[str, str]] = None # { key, value }
388
+
389
+ keyword: Optional[str] = None
390
+ feedback: Optional[FeedbackFilters] = None
391
+ ```
392
+
393
+ ### `SearchOptions`
394
+
395
+ ```python
396
+ @dataclass
397
+ class SearchOptions:
398
+ sort: Optional[List[str]] = None
399
+ semanticMinScore: Optional[float] = None
400
+ semanticTopK: Optional[int] = None
401
+ ```
402
+
403
+ ### `AgentSummary` (returned items)
404
+
405
+ ```python
406
+ @dataclass
407
+ class AgentSummary:
408
+ chainId: ChainId
409
+ agentId: AgentId
410
+ name: str
411
+ image: Optional[URI]
412
+ description: str
413
+ owners: List[Address]
414
+ operators: List[Address]
415
+ # Endpoint strings (present when advertised; not booleans)
416
+ mcp: Optional[str] = None
417
+ a2a: Optional[str] = None
418
+ web: Optional[str] = None
419
+ email: Optional[str] = None
420
+ ens: Optional[str] = None
421
+ did: Optional[str] = None
422
+ walletAddress: Optional[Address] = None
423
+ supportedTrusts: List[str] = field(default_factory=list)
424
+ a2aSkills: List[str] = field(default_factory=list)
425
+ mcpTools: List[str] = field(default_factory=list)
426
+ mcpPrompts: List[str] = field(default_factory=list)
427
+ mcpResources: List[str] = field(default_factory=list)
428
+ oasfSkills: List[str] = field(default_factory=list)
429
+ oasfDomains: List[str] = field(default_factory=list)
430
+ active: bool = False
431
+ x402support: bool = False
432
+ createdAt: Optional[int] = None
433
+ updatedAt: Optional[int] = None
434
+ lastActivity: Optional[int] = None
435
+ agentURI: Optional[str] = None
436
+ agentURIType: Optional[str] = None
437
+ feedbackCount: Optional[int] = None
438
+ averageValue: Optional[float] = None
439
+ semanticScore: Optional[float] = None
440
+ extras: Dict[str, Any] = field(default_factory=dict)
441
+ ```
442
+
288
443
  ## Use Cases
289
444
 
290
445
  - **Building agent marketplaces** - Create platforms where developers can discover, evaluate, and integrate agents based on their capabilities and reputation
@@ -294,10 +449,9 @@ Browse these files to find appropriate skill and domain slugs. For more informat
294
449
 
295
450
  ## 🚀 Coming Soon
296
451
 
297
- - More chains (currently Ethereum Sepolia + Ethereum Mainnet)
452
+ - More chains (currently Ethereum Mainnet + Ethereum Sepolia + Polygon Mainnet)
298
453
  - Support for validations
299
454
  - Enhanced x402 payments
300
- - Semantic/Vectorial search
301
455
  - Advanced reputation aggregation
302
456
  - Import/Export to centralized catalogues
303
457
 
@@ -16,7 +16,9 @@ from .core.models import (
16
16
  RegistrationFile,
17
17
  AgentSummary,
18
18
  Feedback,
19
- SearchParams,
19
+ SearchFilters,
20
+ SearchOptions,
21
+ FeedbackFilters,
20
22
  SearchFeedbackParams,
21
23
  )
22
24
 
@@ -33,7 +35,7 @@ except ImportError:
33
35
  TransactionMined = None
34
36
  _sdk_available = False
35
37
 
36
- __version__ = "1.4.2"
38
+ __version__ = "1.5.1b1"
37
39
  __all__ = [
38
40
  "SDK",
39
41
  "Agent",
@@ -52,6 +54,8 @@ __all__ = [
52
54
  "RegistrationFile",
53
55
  "AgentSummary",
54
56
  "Feedback",
55
- "SearchParams",
57
+ "SearchFilters",
58
+ "SearchOptions",
59
+ "FeedbackFilters",
56
60
  "SearchFeedbackParams",
57
61
  ]
@@ -547,6 +547,7 @@ DEFAULT_REGISTRIES: Dict[int, Dict[str, str]] = {
547
547
  DEFAULT_SUBGRAPH_URLS: Dict[int, str] = {
548
548
  1: "https://gateway.thegraph.com/api/7fd2e7d89ce3ef24cd0d4590298f0b2c/subgraphs/id/FV6RR6y13rsnCxBAicKuQEwDp8ioEGiNaWaZUmvr1F8k", # Ethereum Mainnet
549
549
  11155111: "https://gateway.thegraph.com/api/00a452ad3cd1900273ea62c1bf283f93/subgraphs/id/6wQRC7geo9XYAhckfmfo8kbMRLeWU8KQd3XsJqFKmZLT", # Ethereum Sepolia
550
+ 137: "https://gateway.thegraph.com/api/782d61ed390e625b8867995389699b4c/subgraphs/id/9q16PZv1JudvtnCAf44cBoxg82yK9SSsFvrjCY9xnneF", # Polygon Mainnet
550
551
  # Other chains temporarily disabled - subgraphs to be updated
551
552
  # 84532: "https://gateway.thegraph.com/api/...", # Base Sepolia - To be updated
552
553
  # 80002: "https://gateway.thegraph.com/api/...", # Polygon Amoy - To be updated
@@ -422,8 +422,6 @@ class FeedbackManager:
422
422
  minValue: Optional[float] = None,
423
423
  maxValue: Optional[float] = None,
424
424
  include_revoked: bool = False,
425
- first: int = 100,
426
- skip: int = 0,
427
425
  agents: Optional[List[AgentId]] = None,
428
426
  ) -> List[Feedback]:
429
427
  """Search feedback.
@@ -451,8 +449,6 @@ class FeedbackManager:
451
449
  minValue,
452
450
  maxValue,
453
451
  include_revoked,
454
- first,
455
- skip,
456
452
  agents=agents,
457
453
  )
458
454
 
@@ -469,8 +465,6 @@ class FeedbackManager:
469
465
  minValue,
470
466
  maxValue,
471
467
  include_revoked,
472
- first,
473
- skip,
474
468
  agents=agents,
475
469
  )
476
470
 
@@ -558,8 +552,6 @@ class FeedbackManager:
558
552
  minValue: Optional[float],
559
553
  maxValue: Optional[float],
560
554
  include_revoked: bool,
561
- first: int,
562
- skip: int,
563
555
  agents: Optional[List[AgentId]] = None,
564
556
  ) -> List[Feedback]:
565
557
  """Search feedback using subgraph."""
@@ -583,79 +575,84 @@ class FeedbackManager:
583
575
  includeRevoked=include_revoked
584
576
  )
585
577
 
586
- # Query subgraph
587
- feedbacks_data = self.subgraph_client.search_feedback(
588
- params=params,
589
- first=first,
590
- skip=skip,
591
- order_by="createdAt",
592
- order_direction="desc"
593
- )
594
-
595
- # Map to Feedback objects
596
578
  feedbacks = []
597
- for fb_data in feedbacks_data:
598
- feedback_file = fb_data.get('feedbackFile') or {}
599
- if not isinstance(feedback_file, dict):
600
- feedback_file = {}
601
-
602
- # Map responses
603
- responses_data = fb_data.get('responses', [])
604
- answers = []
605
- for resp in responses_data:
606
- answers.append({
607
- 'responder': resp.get('responder'),
608
- 'responseUri': resp.get('responseUri'),
609
- 'responseHash': resp.get('responseHash'),
610
- 'createdAt': resp.get('createdAt')
611
- })
612
-
613
- # Map tags: rely on whatever the subgraph returns (may be legacy bytes/hash-like values)
614
- tags_list: List[str] = []
615
- tag1 = fb_data.get('tag1') or feedback_file.get('tag1')
616
- tag2 = fb_data.get('tag2') or feedback_file.get('tag2')
617
- if isinstance(tag1, str) and tag1:
579
+ batch = 1000
580
+ skip = 0
581
+ while True:
582
+ feedbacks_data = self.subgraph_client.search_feedback(
583
+ params=params,
584
+ first=batch,
585
+ skip=skip,
586
+ order_by="createdAt",
587
+ order_direction="desc",
588
+ )
589
+
590
+ for fb_data in feedbacks_data:
591
+ feedback_file = fb_data.get('feedbackFile') or {}
592
+ if not isinstance(feedback_file, dict):
593
+ feedback_file = {}
594
+
595
+ # Map responses
596
+ responses_data = fb_data.get('responses', [])
597
+ answers = []
598
+ for resp in responses_data:
599
+ answers.append({
600
+ 'responder': resp.get('responder'),
601
+ 'responseUri': resp.get('responseUri'),
602
+ 'responseHash': resp.get('responseHash'),
603
+ 'createdAt': resp.get('createdAt')
604
+ })
605
+
606
+ # Map tags: rely on whatever the subgraph returns (may be legacy bytes/hash-like values)
607
+ tags_list: List[str] = []
608
+ tag1 = fb_data.get('tag1') or feedback_file.get('tag1')
609
+ tag2 = fb_data.get('tag2') or feedback_file.get('tag2')
610
+ if isinstance(tag1, str) and tag1:
618
611
  tags_list.append(tag1)
619
- if isinstance(tag2, str) and tag2:
612
+ if isinstance(tag2, str) and tag2:
620
613
  tags_list.append(tag2)
621
-
622
- # Parse agentId from feedback ID
623
- feedback_id = fb_data['id']
624
- parts = feedback_id.split(':')
625
- if len(parts) >= 2:
626
- agent_id_str = f"{parts[0]}:{parts[1]}"
627
- client_addr = parts[2] if len(parts) > 2 else ""
628
- feedback_idx = int(parts[3]) if len(parts) > 3 else 1
629
- else:
630
- agent_id_str = feedback_id
631
- client_addr = ""
632
- feedback_idx = 1
633
-
634
- feedback = Feedback(
635
- id=Feedback.create_id(agent_id_str, client_addr, feedback_idx),
636
- agentId=agent_id_str,
637
- reviewer=client_addr,
638
- value=float(fb_data.get("value")) if fb_data.get("value") is not None else None,
639
- tags=tags_list,
640
- text=feedback_file.get('text'),
641
- capability=feedback_file.get('capability'),
642
- context=feedback_file.get('context'),
643
- proofOfPayment={
644
- 'fromAddress': feedback_file.get('proofOfPaymentFromAddress'),
645
- 'toAddress': feedback_file.get('proofOfPaymentToAddress'),
646
- 'chainId': feedback_file.get('proofOfPaymentChainId'),
647
- 'txHash': feedback_file.get('proofOfPaymentTxHash'),
648
- } if feedback_file.get('proofOfPaymentFromAddress') else None,
649
- fileURI=fb_data.get('feedbackURI') or fb_data.get('feedbackUri'), # Handle both old and new field names
650
- endpoint=fb_data.get('endpoint'),
651
- createdAt=fb_data.get('createdAt', int(time.time())),
652
- answers=answers,
653
- isRevoked=fb_data.get('isRevoked', False),
654
- name=feedback_file.get('name'),
655
- skill=feedback_file.get('skill'),
656
- task=feedback_file.get('task'),
657
- )
658
- feedbacks.append(feedback)
614
+
615
+ # Parse agentId from feedback ID
616
+ feedback_id = fb_data['id']
617
+ parts = feedback_id.split(':')
618
+ if len(parts) >= 2:
619
+ agent_id_str = f"{parts[0]}:{parts[1]}"
620
+ client_addr = parts[2] if len(parts) > 2 else ""
621
+ feedback_idx = int(parts[3]) if len(parts) > 3 else 1
622
+ else:
623
+ agent_id_str = feedback_id
624
+ client_addr = ""
625
+ feedback_idx = 1
626
+
627
+ feedback = Feedback(
628
+ id=Feedback.create_id(agent_id_str, client_addr, feedback_idx),
629
+ agentId=agent_id_str,
630
+ reviewer=client_addr,
631
+ value=float(fb_data.get("value")) if fb_data.get("value") is not None else None,
632
+ tags=tags_list,
633
+ text=feedback_file.get('text'),
634
+ capability=feedback_file.get('capability'),
635
+ context=feedback_file.get('context'),
636
+ proofOfPayment={
637
+ 'fromAddress': feedback_file.get('proofOfPaymentFromAddress'),
638
+ 'toAddress': feedback_file.get('proofOfPaymentToAddress'),
639
+ 'chainId': feedback_file.get('proofOfPaymentChainId'),
640
+ 'txHash': feedback_file.get('proofOfPaymentTxHash'),
641
+ } if feedback_file.get('proofOfPaymentFromAddress') else None,
642
+ fileURI=fb_data.get('feedbackURI') or fb_data.get('feedbackUri'), # Handle both old and new field names
643
+ endpoint=fb_data.get('endpoint'),
644
+ createdAt=fb_data.get('createdAt', int(time.time())),
645
+ answers=answers,
646
+ isRevoked=fb_data.get('isRevoked', False),
647
+ name=feedback_file.get('name'),
648
+ skill=feedback_file.get('skill'),
649
+ task=feedback_file.get('task'),
650
+ )
651
+ feedbacks.append(feedback)
652
+
653
+ if len(feedbacks_data) < batch:
654
+ break
655
+ skip += batch
659
656
 
660
657
  return feedbacks
661
658