agentstr 0.1.11__tar.gz → 0.1.12__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. {agentstr-0.1.11/src/agentstr.egg-info → agentstr-0.1.12}/PKG-INFO +36 -53
  2. {agentstr-0.1.11 → agentstr-0.1.12}/README.md +29 -49
  3. {agentstr-0.1.11 → agentstr-0.1.12}/pyproject.toml +19 -5
  4. agentstr-0.1.12/src/agentstr/__init__.py +37 -0
  5. agentstr-0.1.12/src/agentstr/buyer.py +291 -0
  6. agentstr-0.1.12/src/agentstr/buyer.pyi +31 -0
  7. agentstr-0.1.11/src/agentstr/marketplace.py → agentstr-0.1.12/src/agentstr/merchant.py +126 -323
  8. agentstr-0.1.12/src/agentstr/merchant.pyi +37 -0
  9. agentstr-0.1.12/src/agentstr/models.py +381 -0
  10. agentstr-0.1.12/src/agentstr/models.pyi +103 -0
  11. agentstr-0.1.12/src/agentstr/nostr.py +663 -0
  12. agentstr-0.1.12/src/agentstr/nostr.pyi +82 -0
  13. agentstr-0.1.12/src/agentstr/py.typed +0 -0
  14. {agentstr-0.1.11 → agentstr-0.1.12/src/agentstr.egg-info}/PKG-INFO +36 -53
  15. {agentstr-0.1.11 → agentstr-0.1.12}/src/agentstr.egg-info/SOURCES.txt +11 -2
  16. {agentstr-0.1.11 → agentstr-0.1.12}/src/agentstr.egg-info/requires.txt +5 -2
  17. agentstr-0.1.12/tests/test_buyer.py +91 -0
  18. agentstr-0.1.12/tests/test_merchant.py +138 -0
  19. agentstr-0.1.12/tests/test_nostr_integration.py +94 -0
  20. agentstr-0.1.12/tests/test_nostr_mocked.py +101 -0
  21. agentstr-0.1.11/src/agentstr/__init__.py +0 -30
  22. agentstr-0.1.11/src/agentstr/nostr.py +0 -327
  23. agentstr-0.1.11/tests/test_merchant.py +0 -371
  24. agentstr-0.1.11/tests/test_nostr.py +0 -164
  25. {agentstr-0.1.11 → agentstr-0.1.12}/LICENSE +0 -0
  26. {agentstr-0.1.11 → agentstr-0.1.12}/MANIFEST.in +0 -0
  27. {agentstr-0.1.11 → agentstr-0.1.12}/setup.cfg +0 -0
  28. {agentstr-0.1.11 → agentstr-0.1.12}/src/agentstr.egg-info/dependency_links.txt +0 -0
  29. {agentstr-0.1.11 → agentstr-0.1.12}/src/agentstr.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: agentstr
3
- Version: 0.1.11
4
- Summary: Nostr extension for Phidata AI agents
3
+ Version: 0.1.12
4
+ Summary: Nostr extension for Agno AI agents
5
5
  Author-email: Synvya <info@synvya.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://www.synvya.com
@@ -11,13 +11,16 @@ Project-URL: BugTracker, https://github.com/synvya/agentstr/issues
11
11
  Requires-Python: <3.13,>=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: phidata>=2.7.0
14
+ Requires-Dist: agno>=1.1.1
15
15
  Requires-Dist: openai>=1.50.0
16
16
  Requires-Dist: packaging>=24.0
17
- Requires-Dist: nostr-sdk>=0.38.0
17
+ Requires-Dist: nostr_sdk>=0.39.0
18
18
  Requires-Dist: pydantic>=2.0.0
19
+ Requires-Dist: cassandra-driver>=3.29.2
20
+ Requires-Dist: cassio>=0.1.10
19
21
  Provides-Extra: dev
20
22
  Requires-Dist: pytest>=7.0; extra == "dev"
23
+ Requires-Dist: pytest-asyncio>=0.23.5; extra == "dev"
21
24
  Requires-Dist: black>=23.0; extra == "dev"
22
25
  Requires-Dist: isort>=5.0; extra == "dev"
23
26
  Requires-Dist: mypy>=1.0; extra == "dev"
@@ -25,7 +28,7 @@ Requires-Dist: python-dotenv>=1.0; extra == "dev"
25
28
 
26
29
  # AgentStr
27
30
 
28
- AgentStr is an extension of [Phidata](https://www.phidata.com) AI agents that enables peer-to-peer agent communication using the Nostr protocol.
31
+ AgentStr is an extension of [Agno](https://www.agno.ai) AI agents that enables peer-to-peer agent communication using the Nostr protocol.
29
32
 
30
33
  ## Overview
31
34
 
@@ -41,8 +44,15 @@ agentstr/
41
44
  ├── src/ # Source code
42
45
  │ └── agentstr/
43
46
  │ ├── __init__.py
44
- │ ├── marketplace.py
45
- └── nostr.py
47
+ │ ├── buyer.py
48
+ ├── buyer.pyi
49
+ │ ├── merchant.py
50
+ │ ├── merchant.pyi
51
+ │ ├── models.py
52
+ │ ├── models.pyi
53
+ │ ├── nostr.py
54
+ │ ├── nostr.pyi
55
+ │ └── py.typed
46
56
  ├── tests/ # Test files
47
57
  ├── docs/ # Documentation
48
58
  ├── examples/ # Example implementations
@@ -52,17 +62,19 @@ agentstr/
52
62
  ## Features
53
63
 
54
64
  ### Current Features
55
- - Create Merchant agents with Nostr identities
56
- - Publish and manage merchant products using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
57
- - Create merchant stalls to organize products
58
- - Handle shipping zones and costs
59
- - Secure communication using Nostr keys
65
+ - Create Merchant agents with Nostr identities:
66
+ - Publish and manage merchant products using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
67
+ - Create merchant stalls to organize products
68
+ - Handle shipping zones and costs
69
+ - Secure communication using Nostr keys
70
+ - Create Buyer agents:
71
+ - Retrieve a list of sellers from the relay using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
72
+ - Find an specific seller by name or public key
73
+ - Refresh the list of sellers from the relay
60
74
 
61
75
  ### Roadmap
62
76
  - [ ] Create marketplace with stalls
63
- - [ ] Create Buyer agents
64
- - [ ] Enable merchants to define products
65
- - [ ] Add customer toolkit for buyers
77
+ - [ ] Expand buyer agent to include more features
66
78
  - [ ] Support additional Nostr NIPs
67
79
  - [ ] Add more agent interaction patterns
68
80
 
@@ -82,46 +94,13 @@ pip install agentstr
82
94
 
83
95
  You can find example code in the [examples](https://github.com/Synvya/agentstr/tree/main/examples/) directory.
84
96
 
85
- ### Instaling the examples
86
- 1. **Clone the repository**
87
- ```bash
88
- git clone https://github.com/Synvya/agentstr.git
89
- ```
90
-
91
- ### Basic CLI Example
92
- A simple command-line interface demonstrating agentstr's merchant capabilities:
93
-
94
-
95
- - [Basic CLI Agent](https://github.com/Synvya/agentstr/tree/main/src/agentstr/examples/basic_cli/main.py) - A complete example showing:
96
- - Setting up merchant profiles
97
- - Creating stalls with shipping methods
98
- - Defining products with shipping costs
99
- - Configuring the agent with the merchant toolkit
100
- - Running an interactive CLI application
101
-
102
- 1. ** Create a virtual environment**
103
- ```bash
104
- cd agentstr/examples/basic_cli
105
- python3 -m venv venv
106
- source venv/bin/activate
107
- ```
97
+ To install the examples clone the repository and navigate to the examples directory:
108
98
 
109
- 2. ** Install dependencies**
110
99
  ```bash
111
- pip install -r requirements.txt
112
- ```
113
-
114
- 3. ** Configure your environment**
115
- ```bash
116
- cp .env.example .env
117
- ```
118
- **Edit the .env file with your own API keys and Nostr credentials**
119
-
120
- 4. ** Run the example**
121
- ```bash
122
- python main.py
100
+ git clone https://github.com/Synvya/agentstr.git
101
+ cd agentstr/examples/
123
102
  ```
124
-
103
+ Each example has its own README with instructions on how to run it.
125
104
 
126
105
  ## Documentation
127
106
 
@@ -140,7 +119,11 @@ This project is licensed under the MIT License - see the [LICENSE](https://githu
140
119
 
141
120
  ## Acknowledgments
142
121
 
143
- - [Phidata](https://www.phidata.com) - For their AI agent framework
122
+ - [Agno](https://www.agno.ai) - For their AI agent framework
144
123
  - [Rust-Nostr](https://rust-nostr.org) - For their Python Nostr SDK
145
124
  - [Nostr Protocol](https://github.com/nostr-protocol/nips) - For the protocol specification
146
125
 
126
+ This software includes the following software licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0):
127
+ - [DataStax Python Driver for Apache Cassandra](https://github.com/datastax/python-driver)
128
+ - [cassIO](https://github.com/CassioML/cassio). This library is not maintained anymore. We will need to replace it with a new library.
129
+
@@ -1,6 +1,6 @@
1
1
  # AgentStr
2
2
 
3
- AgentStr is an extension of [Phidata](https://www.phidata.com) AI agents that enables peer-to-peer agent communication using the Nostr protocol.
3
+ AgentStr is an extension of [Agno](https://www.agno.ai) AI agents that enables peer-to-peer agent communication using the Nostr protocol.
4
4
 
5
5
  ## Overview
6
6
 
@@ -16,8 +16,15 @@ agentstr/
16
16
  ├── src/ # Source code
17
17
  │ └── agentstr/
18
18
  │ ├── __init__.py
19
- │ ├── marketplace.py
20
- └── nostr.py
19
+ │ ├── buyer.py
20
+ ├── buyer.pyi
21
+ │ ├── merchant.py
22
+ │ ├── merchant.pyi
23
+ │ ├── models.py
24
+ │ ├── models.pyi
25
+ │ ├── nostr.py
26
+ │ ├── nostr.pyi
27
+ │ └── py.typed
21
28
  ├── tests/ # Test files
22
29
  ├── docs/ # Documentation
23
30
  ├── examples/ # Example implementations
@@ -27,17 +34,19 @@ agentstr/
27
34
  ## Features
28
35
 
29
36
  ### Current Features
30
- - Create Merchant agents with Nostr identities
31
- - Publish and manage merchant products using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
32
- - Create merchant stalls to organize products
33
- - Handle shipping zones and costs
34
- - Secure communication using Nostr keys
37
+ - Create Merchant agents with Nostr identities:
38
+ - Publish and manage merchant products using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
39
+ - Create merchant stalls to organize products
40
+ - Handle shipping zones and costs
41
+ - Secure communication using Nostr keys
42
+ - Create Buyer agents:
43
+ - Retrieve a list of sellers from the relay using [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) marketplace protocol
44
+ - Find an specific seller by name or public key
45
+ - Refresh the list of sellers from the relay
35
46
 
36
47
  ### Roadmap
37
48
  - [ ] Create marketplace with stalls
38
- - [ ] Create Buyer agents
39
- - [ ] Enable merchants to define products
40
- - [ ] Add customer toolkit for buyers
49
+ - [ ] Expand buyer agent to include more features
41
50
  - [ ] Support additional Nostr NIPs
42
51
  - [ ] Add more agent interaction patterns
43
52
 
@@ -57,46 +66,13 @@ pip install agentstr
57
66
 
58
67
  You can find example code in the [examples](https://github.com/Synvya/agentstr/tree/main/examples/) directory.
59
68
 
60
- ### Instaling the examples
61
- 1. **Clone the repository**
62
- ```bash
63
- git clone https://github.com/Synvya/agentstr.git
64
- ```
65
-
66
- ### Basic CLI Example
67
- A simple command-line interface demonstrating agentstr's merchant capabilities:
68
-
69
-
70
- - [Basic CLI Agent](https://github.com/Synvya/agentstr/tree/main/src/agentstr/examples/basic_cli/main.py) - A complete example showing:
71
- - Setting up merchant profiles
72
- - Creating stalls with shipping methods
73
- - Defining products with shipping costs
74
- - Configuring the agent with the merchant toolkit
75
- - Running an interactive CLI application
76
-
77
- 1. ** Create a virtual environment**
78
- ```bash
79
- cd agentstr/examples/basic_cli
80
- python3 -m venv venv
81
- source venv/bin/activate
82
- ```
69
+ To install the examples clone the repository and navigate to the examples directory:
83
70
 
84
- 2. ** Install dependencies**
85
71
  ```bash
86
- pip install -r requirements.txt
87
- ```
88
-
89
- 3. ** Configure your environment**
90
- ```bash
91
- cp .env.example .env
92
- ```
93
- **Edit the .env file with your own API keys and Nostr credentials**
94
-
95
- 4. ** Run the example**
96
- ```bash
97
- python main.py
72
+ git clone https://github.com/Synvya/agentstr.git
73
+ cd agentstr/examples/
98
74
  ```
99
-
75
+ Each example has its own README with instructions on how to run it.
100
76
 
101
77
  ## Documentation
102
78
 
@@ -115,7 +91,11 @@ This project is licensed under the MIT License - see the [LICENSE](https://githu
115
91
 
116
92
  ## Acknowledgments
117
93
 
118
- - [Phidata](https://www.phidata.com) - For their AI agent framework
94
+ - [Agno](https://www.agno.ai) - For their AI agent framework
119
95
  - [Rust-Nostr](https://rust-nostr.org) - For their Python Nostr SDK
120
96
  - [Nostr Protocol](https://github.com/nostr-protocol/nips) - For the protocol specification
121
97
 
98
+ This software includes the following software licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0):
99
+ - [DataStax Python Driver for Apache Cassandra](https://github.com/datastax/python-driver)
100
+ - [cassIO](https://github.com/CassioML/cassio). This library is not maintained anymore. We will need to replace it with a new library.
101
+
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentstr"
7
- version = "0.1.11"
8
- description = "Nostr extension for Phidata AI agents"
7
+ version = "0.1.12"
8
+ description = "Nostr extension for Agno AI agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9, <3.13"
11
11
  license = { text = "MIT" }
@@ -13,16 +13,19 @@ authors = [
13
13
  {name = "Synvya", email = "info@synvya.com"}
14
14
  ]
15
15
  dependencies = [
16
- "phidata>=2.7.0",
16
+ "agno>=1.1.1",
17
17
  "openai>=1.50.0",
18
18
  "packaging>=24.0",
19
- "nostr-sdk>=0.38.0",
19
+ "nostr_sdk>=0.39.0",
20
20
  "pydantic>=2.0.0",
21
+ "cassandra-driver>=3.29.2",
22
+ "cassio>=0.1.10",
21
23
  ]
22
24
 
23
25
  [project.optional-dependencies]
24
26
  dev = [
25
27
  "pytest>=7.0",
28
+ "pytest-asyncio>=0.23.5",
26
29
  "black>=23.0",
27
30
  "isort>=5.0",
28
31
  "mypy>=1.0",
@@ -55,7 +58,18 @@ python_version = "3.9"
55
58
  warn_return_any = true
56
59
  warn_unused_configs = true
57
60
  mypy_path = "src"
61
+ check_untyped_defs = true
62
+ disallow_untyped_defs = true
58
63
 
59
64
  [[tool.mypy.overrides]]
60
65
  module = ["nostr_sdk.*"]
61
- ignore_missing_imports = true
66
+ ignore_missing_imports = true
67
+
68
+ [tool.setuptools.package-data]
69
+ agentstr = ["py.typed"]
70
+
71
+ [tool.pytest.ini_options]
72
+ asyncio_mode = "auto"
73
+ markers = [
74
+ "asyncio: mark test as async",
75
+ ]
@@ -0,0 +1,37 @@
1
+ """
2
+ AgentStr: Nostr extension for Agno AI agents
3
+ """
4
+
5
+ from nostr_sdk import ShippingCost, ShippingMethod # type: ignore
6
+
7
+ from .merchant import MerchantTools
8
+
9
+ # Import main classes to make them available at package level
10
+ from .models import AgentProfile, MerchantProduct, MerchantStall, NostrProfile
11
+
12
+ # Import version from pyproject.toml at runtime
13
+ try:
14
+ from importlib.metadata import version
15
+
16
+ __version__ = version("agentstr")
17
+ except Exception:
18
+ __version__ = "unknown"
19
+
20
+ __all__ = [
21
+ "MerchantTools",
22
+ "MerchantProduct",
23
+ "MerchantStall",
24
+ "ShippingCost",
25
+ "ShippingMethod",
26
+ ]
27
+
28
+ from agentstr.nostr import EventId, Keys, NostrClient, ProductData, StallData
29
+
30
+ __all__ = [
31
+ "EventId",
32
+ "Keys",
33
+ "NostrClient",
34
+ "ProductData",
35
+ "StallData",
36
+ "AgentProfile",
37
+ ]
@@ -0,0 +1,291 @@
1
+ import json
2
+ import logging
3
+ from uuid import uuid4
4
+
5
+ from agno.agent import AgentKnowledge # type: ignore
6
+ from agno.document.base import Document
7
+
8
+ from agentstr.models import AgentProfile, NostrProfile
9
+ from agentstr.nostr import NostrClient, PublicKey
10
+
11
+ try:
12
+ from agno.tools import Toolkit
13
+ except ImportError:
14
+ raise ImportError("`agno` not installed. Please install using `pip install agno`")
15
+
16
+
17
+ def _map_location_to_geohash(location: str) -> str:
18
+ """
19
+ Map a location to a geohash.
20
+
21
+ TBD: Implement this function. Returning a fixed geohash for now.
22
+
23
+ Args:
24
+ location: location to map to a geohash. Can be a zip code, city, state, country, or latitude and longitude.
25
+
26
+ Returns:
27
+ str: geohash of the location or empty string if location is not found
28
+ """
29
+ if "snoqualmie" in location.lower():
30
+ return "C23Q7U36W"
31
+ else:
32
+ return ""
33
+
34
+
35
+ class BuyerTools(Toolkit):
36
+ """
37
+ BuyerTools is a toolkit that allows an agent to find sellers and transact with them over Nostr.
38
+
39
+ Sellers are downloaded from the Nostr relay and cached.
40
+ Sellers can be found by name or public key.
41
+ Sellers cache can be refreshed from the Nostr relay.
42
+ Sellers can be retrieved as a list of Nostr profiles.
43
+
44
+ TBD: populate the sellers locations with info from stalls.
45
+ """
46
+
47
+ from pydantic import ConfigDict
48
+
49
+ model_config = ConfigDict(
50
+ arbitrary_types_allowed=True, extra="allow", validate_assignment=True
51
+ )
52
+
53
+ logger = logging.getLogger("Buyer")
54
+ sellers: set[NostrProfile] = set()
55
+
56
+ def __init__(
57
+ self,
58
+ knowledge_base: AgentKnowledge,
59
+ buyer_profile: AgentProfile,
60
+ relay: str,
61
+ ) -> None:
62
+ """Initialize the Buyer toolkit.
63
+
64
+ Args:
65
+ knowledge_base: knowledge base of the buyer agent
66
+ buyer_profile: profile of the buyer using this agent
67
+ relay: Nostr relay to use for communications
68
+ """
69
+ super().__init__(name="Buyer")
70
+
71
+ self.relay = relay
72
+ self.buyer_profile = buyer_profile
73
+ self.knowledge_base = knowledge_base
74
+ # Initialize fields
75
+ self._nostr_client = NostrClient(relay, buyer_profile.get_private_key())
76
+
77
+ # Register methods
78
+ self.register(self.find_seller_by_name)
79
+ self.register(self.find_seller_by_public_key)
80
+ self.register(self.find_sellers_by_location)
81
+ self.register(self.get_profile)
82
+ self.register(self.get_relay)
83
+ self.register(self.get_seller_stalls)
84
+ self.register(self.get_seller_products)
85
+ self.register(self.get_seller_count)
86
+ self.register(self.get_sellers)
87
+ self.register(self.refresh_sellers)
88
+ self.register(self.purchase_product)
89
+
90
+ def purchase_product(self, product: str) -> str:
91
+ """Purchase a product.
92
+
93
+ Args:
94
+ product: JSON string with product to purchase
95
+ """
96
+ return json.dumps({"status": "success", "message": "Product purchased"})
97
+
98
+ def find_seller_by_name(self, name: str) -> str:
99
+ """Find a seller by name.
100
+
101
+ Args:
102
+ name: name of the seller to find
103
+
104
+ Returns:
105
+ str: JSON string with seller profile or error message
106
+ """
107
+ for seller in self.sellers:
108
+ if seller.get_name() == name:
109
+ response = seller.to_json()
110
+ # self._store_response_in_knowledge_base(response)
111
+ return response
112
+ response = json.dumps({"status": "error", "message": "Seller not found"})
113
+ self._store_response_in_knowledge_base(response)
114
+ return response
115
+
116
+ def find_seller_by_public_key(self, public_key: str) -> str:
117
+ """Find a seller by public key.
118
+
119
+ Args:
120
+ public_key: bech32 encoded public key of the seller to find
121
+
122
+ Returns:
123
+ str: seller profile json string or error message
124
+ """
125
+ for seller in self.sellers:
126
+ if seller.get_public_key() == public_key:
127
+ response = seller.to_json()
128
+ # self._store_response_in_knowledge_base(response)
129
+ return response
130
+ response = json.dumps({"status": "error", "message": "Seller not found"})
131
+ self._store_response_in_knowledge_base(response)
132
+ return response
133
+
134
+ def find_sellers_by_location(self, location: str) -> str:
135
+ """Find sellers by location.
136
+
137
+ Args:
138
+ location: location of the seller to find (e.g. "San Francisco, CA")
139
+
140
+ Returns:
141
+ str: list of seller profile json strings or error message
142
+ """
143
+ sellers: set[NostrProfile] = set()
144
+ geohash = _map_location_to_geohash(location)
145
+ # print(f"find_sellers_by_location: geohash: {geohash}")
146
+
147
+ if not geohash:
148
+ response = json.dumps({"status": "error", "message": "Invalid location"})
149
+ return response
150
+
151
+ # Find sellers in the same geohash
152
+ for seller in self.sellers:
153
+ if geohash in seller.get_locations():
154
+ # print(
155
+ # f"geohash {geohash} found in seller {seller.get_name()} with locations {seller.get_locations()}"
156
+ # )
157
+ sellers.add(seller)
158
+
159
+ if not sellers:
160
+ response = json.dumps(
161
+ {"status": "error", "message": f"No sellers found near {location}"}
162
+ )
163
+ return response
164
+
165
+ response = json.dumps([seller.to_dict() for seller in sellers])
166
+ # print("find_sellers_by_location: storing response in knowledge base")
167
+ self._store_response_in_knowledge_base(response)
168
+ # print(f"Found {len(sellers)} sellers near {location}")
169
+ return response
170
+
171
+ def get_profile(self) -> str:
172
+ """Get the Nostr profile of the buyer agent.
173
+
174
+ Returns:
175
+ str: buyer profile json string
176
+ """
177
+ response = self.buyer_profile.to_json()
178
+ self._store_response_in_knowledge_base(response)
179
+ return response
180
+
181
+ def get_relay(self) -> str:
182
+ """Get the Nostr relay that the buyer agent is using.
183
+
184
+ Returns:
185
+ str: Nostr relay
186
+ """
187
+ response = self.relay
188
+ # self._store_response_in_knowledge_base(response)
189
+ return response
190
+
191
+ def get_seller_stalls(self, public_key: str) -> str:
192
+ """Get the stalls from a seller.
193
+
194
+ Args:
195
+ public_key: public key of the seller
196
+
197
+ Returns:
198
+ str: JSON string with seller collections
199
+ """
200
+ try:
201
+ stalls = self._nostr_client.retrieve_stalls_from_seller(
202
+ PublicKey.parse(public_key)
203
+ )
204
+ response = json.dumps([stall.as_json() for stall in stalls])
205
+ self._store_response_in_knowledge_base(response)
206
+ return response
207
+ except Exception as e:
208
+ response = json.dumps({"status": "error", "message": str(e)})
209
+ return response
210
+
211
+ def get_seller_count(self) -> str:
212
+ """Get the number of sellers.
213
+
214
+ Returns:
215
+ str: JSON string with status and count of sellers
216
+ """
217
+ response = json.dumps({"status": "success", "count": len(self.sellers)})
218
+ return response
219
+
220
+ def get_seller_products(self, public_key: str) -> str:
221
+ """Get the products from a seller
222
+
223
+ Args:
224
+ public_key: public key of the seller
225
+
226
+ Returns:
227
+ str: JSON string with seller products
228
+ """
229
+ try:
230
+ products = self._nostr_client.retrieve_products_from_seller(
231
+ PublicKey.parse(public_key)
232
+ )
233
+
234
+ response = json.dumps([product.to_dict() for product in products])
235
+ self._store_response_in_knowledge_base(response)
236
+ return response
237
+ except Exception as e:
238
+ response = json.dumps({"status": "error", "message": str(e)})
239
+ return response
240
+
241
+ def get_sellers(self) -> str:
242
+ """Get the list of sellers.
243
+ If no sellers are cached, the list is refreshed from the Nostr relay.
244
+ If sellers are cached, the list is returned from the cache.
245
+ To get a fresh list of sellers, call refresh_sellers() sellers first.
246
+
247
+ Returns:
248
+ str: list of sellers json strings
249
+ """
250
+ if not self.sellers:
251
+ self._refresh_sellers()
252
+ response = json.dumps([seller.to_json() for seller in self.sellers])
253
+ return response
254
+
255
+ def refresh_sellers(self) -> str:
256
+ """Refresh the list of sellers.
257
+
258
+ Returns:
259
+ str: JSON string with status and count of sellers refreshed
260
+ """
261
+ self._refresh_sellers()
262
+ response = json.dumps({"status": "success", "count": len(self.sellers)})
263
+ return response
264
+
265
+ def _refresh_sellers(self) -> None:
266
+ """
267
+ Internal fucntion to retrieve a new list of sellers from the Nostr relay.
268
+ The old list is discarded and the new list only contains unique sellers currently stored at the relay.
269
+
270
+ Returns:
271
+ List[NostrProfile]: List of Nostr profiles of all sellers.
272
+ """
273
+ sellers = self._nostr_client.retrieve_sellers()
274
+ if len(sellers) == 0:
275
+ self.logger.info("No sellers found")
276
+ else:
277
+ self.logger.info(f"Found {len(sellers)} sellers")
278
+
279
+ # Print the locations of the sellers
280
+ # for seller in sellers:
281
+ # print(f"Seller {seller.get_name()} has locations {seller.get_locations()}")
282
+
283
+ self.sellers = sellers
284
+
285
+ def _store_response_in_knowledge_base(self, response: str) -> None:
286
+ doc = Document(
287
+ id=str(uuid4()),
288
+ content=response,
289
+ )
290
+ # print(f"Document length: {len(doc.content.split())} words")
291
+ self.knowledge_base.load_documents([doc]) # Store response in Cassandra
@@ -0,0 +1,31 @@
1
+ from logging import Logger
2
+ from typing import ClassVar
3
+
4
+ from agno.agent import AgentKnowledge
5
+ from agno.tools import Toolkit
6
+
7
+ from agentstr.models import AgentProfile, NostrProfile
8
+ from agentstr.nostr import NostrClient
9
+
10
+ class BuyerTools(Toolkit):
11
+ logger: ClassVar[Logger]
12
+ sellers: set[NostrProfile]
13
+ relay: str
14
+ _nostr_client: NostrClient
15
+
16
+ def __init__(
17
+ self, knowledge_base: AgentKnowledge, buyer_profile: AgentProfile, relay: str
18
+ ) -> None: ...
19
+ def find_seller_by_name(self, name: str) -> str: ...
20
+ def find_seller_by_public_key(self, public_key: str) -> str: ...
21
+ def find_sellers_by_location(self, location: str) -> str: ...
22
+ def get_profile(self) -> str: ...
23
+ def get_relay(self) -> str: ...
24
+ def get_seller_stalls(self, public_key: str) -> str: ...
25
+ def get_seller_count(self) -> str: ...
26
+ def get_seller_products(self, public_key: str) -> str: ...
27
+ def get_sellers(self) -> str: ...
28
+ def purchase_product(self, product: str) -> str: ...
29
+ def refresh_sellers(self) -> str: ...
30
+ def _refresh_sellers(self) -> None: ...
31
+ def _store_response_in_knowledge_base(self, response: str) -> None: ...