agentstr 0.1.12__tar.gz → 0.1.14__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {agentstr-0.1.12/src/agentstr.egg-info → agentstr-0.1.14}/PKG-INFO +10 -7
- {agentstr-0.1.12 → agentstr-0.1.14}/pyproject.toml +11 -7
- agentstr-0.1.14/src/agentstr/__init__.py +49 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/buyer.py +37 -23
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/buyer.pyi +1 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/merchant.py +68 -59
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/merchant.pyi +1 -1
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/models.py +8 -9
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/models.pyi +1 -1
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/nostr.py +75 -78
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/nostr.pyi +15 -1
- {agentstr-0.1.12 → agentstr-0.1.14/src/agentstr.egg-info}/PKG-INFO +10 -7
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr.egg-info/requires.txt +7 -3
- {agentstr-0.1.12 → agentstr-0.1.14}/tests/test_buyer.py +24 -5
- {agentstr-0.1.12 → agentstr-0.1.14}/tests/test_merchant.py +22 -6
- {agentstr-0.1.12 → agentstr-0.1.14}/tests/test_nostr_integration.py +6 -2
- {agentstr-0.1.12 → agentstr-0.1.14}/tests/test_nostr_mocked.py +32 -26
- agentstr-0.1.12/src/agentstr/__init__.py +0 -37
- {agentstr-0.1.12 → agentstr-0.1.14}/LICENSE +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/MANIFEST.in +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/README.md +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/setup.cfg +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr/py.typed +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr.egg-info/SOURCES.txt +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr.egg-info/dependency_links.txt +0 -0
- {agentstr-0.1.12 → agentstr-0.1.14}/src/agentstr.egg-info/top_level.txt +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: agentstr
|
3
|
-
Version: 0.1.
|
4
|
-
Summary:
|
5
|
-
Author-email: Synvya <
|
3
|
+
Version: 0.1.14
|
4
|
+
Summary: Tools for a Nostr agentic ecosystem
|
5
|
+
Author-email: Synvya <synvya@synvya.com>
|
6
6
|
License: MIT
|
7
7
|
Project-URL: Homepage, https://www.synvya.com
|
8
8
|
Project-URL: Repository, https://github.com/synvya/agentstr
|
@@ -13,18 +13,21 @@ Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
14
14
|
Requires-Dist: agno>=1.1.1
|
15
15
|
Requires-Dist: openai>=1.50.0
|
16
|
-
Requires-Dist: packaging>=24.0
|
17
16
|
Requires-Dist: nostr_sdk>=0.39.0
|
18
17
|
Requires-Dist: pydantic>=2.0.0
|
19
|
-
Requires-Dist: cassandra-driver>=3.29.2
|
20
|
-
Requires-Dist: cassio>=0.1.10
|
21
18
|
Provides-Extra: dev
|
22
19
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
23
20
|
Requires-Dist: pytest-asyncio>=0.23.5; extra == "dev"
|
24
21
|
Requires-Dist: black>=23.0; extra == "dev"
|
25
22
|
Requires-Dist: isort>=5.0; extra == "dev"
|
26
23
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
27
|
-
Requires-Dist:
|
24
|
+
Requires-Dist: pylint>=3.0; extra == "dev"
|
25
|
+
Provides-Extra: examples
|
26
|
+
Requires-Dist: python-dotenv>=1.0; extra == "examples"
|
27
|
+
Requires-Dist: cassandra-driver>=3.29.2; extra == "examples"
|
28
|
+
Requires-Dist: cassio>=0.1.10; extra == "examples"
|
29
|
+
Requires-Dist: fastapi>=0.110.0; extra == "examples"
|
30
|
+
Requires-Dist: uvicorn>=0.30.0; extra == "examples"
|
28
31
|
|
29
32
|
# AgentStr
|
30
33
|
|
@@ -4,22 +4,19 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "agentstr"
|
7
|
-
version = "0.1.
|
8
|
-
description = "
|
7
|
+
version = "0.1.14"
|
8
|
+
description = "Tools for a Nostr agentic ecosystem"
|
9
9
|
readme = "README.md"
|
10
10
|
requires-python = ">=3.9, <3.13"
|
11
11
|
license = { text = "MIT" }
|
12
12
|
authors = [
|
13
|
-
{name = "Synvya", email = "
|
13
|
+
{name = "Synvya", email = "synvya@synvya.com"}
|
14
14
|
]
|
15
15
|
dependencies = [
|
16
16
|
"agno>=1.1.1",
|
17
17
|
"openai>=1.50.0",
|
18
|
-
"packaging>=24.0",
|
19
18
|
"nostr_sdk>=0.39.0",
|
20
|
-
"pydantic>=2.0.0",
|
21
|
-
"cassandra-driver>=3.29.2",
|
22
|
-
"cassio>=0.1.10",
|
19
|
+
"pydantic>=2.0.0",
|
23
20
|
]
|
24
21
|
|
25
22
|
[project.optional-dependencies]
|
@@ -29,7 +26,14 @@ dev = [
|
|
29
26
|
"black>=23.0",
|
30
27
|
"isort>=5.0",
|
31
28
|
"mypy>=1.0",
|
29
|
+
"pylint>=3.0",
|
30
|
+
]
|
31
|
+
examples = [
|
32
32
|
"python-dotenv>=1.0",
|
33
|
+
"cassandra-driver>=3.29.2",
|
34
|
+
"cassio>=0.1.10",
|
35
|
+
"fastapi>=0.110.0",
|
36
|
+
"uvicorn>=0.30.0",
|
33
37
|
]
|
34
38
|
|
35
39
|
[project.urls]
|
@@ -0,0 +1,49 @@
|
|
1
|
+
"""
|
2
|
+
AgentStr: Nostr extension for Agno AI agents
|
3
|
+
"""
|
4
|
+
|
5
|
+
import importlib.metadata
|
6
|
+
import logging
|
7
|
+
|
8
|
+
from nostr_sdk import ShippingCost, ShippingMethod, Timestamp # type: ignore
|
9
|
+
|
10
|
+
from agentstr.nostr import EventId, Keys, Kind, NostrClient, generate_and_save_keys
|
11
|
+
|
12
|
+
from .buyer import BuyerTools
|
13
|
+
from .merchant import MerchantTools
|
14
|
+
|
15
|
+
# Import main classes to make them available at package level
|
16
|
+
from .models import AgentProfile, MerchantProduct, MerchantStall, NostrProfile
|
17
|
+
|
18
|
+
# Import version from pyproject.toml at runtime
|
19
|
+
try:
|
20
|
+
__version__ = importlib.metadata.version("agentstr")
|
21
|
+
except importlib.metadata.PackageNotFoundError:
|
22
|
+
logging.warning("Package 'agentstr' not found. Falling back to 'unknown'.")
|
23
|
+
__version__ = "unknown"
|
24
|
+
except ImportError:
|
25
|
+
logging.warning("importlib.metadata is not available. Falling back to 'unknown'.")
|
26
|
+
__version__ = "unknown"
|
27
|
+
|
28
|
+
# Define What is Exposed at the Package Level
|
29
|
+
__all__ = [
|
30
|
+
# Merchant Tools
|
31
|
+
"MerchantTools",
|
32
|
+
"MerchantProduct",
|
33
|
+
"MerchantStall",
|
34
|
+
# Buyer Tools
|
35
|
+
"BuyerTools",
|
36
|
+
# Shipping
|
37
|
+
"ShippingCost",
|
38
|
+
"ShippingMethod",
|
39
|
+
# Nostr-related utils
|
40
|
+
"EventId",
|
41
|
+
"Keys",
|
42
|
+
"Kind",
|
43
|
+
"NostrClient",
|
44
|
+
"generate_and_save_keys",
|
45
|
+
"Timestamp",
|
46
|
+
# Models
|
47
|
+
"AgentProfile",
|
48
|
+
"NostrProfile",
|
49
|
+
]
|
@@ -1,17 +1,24 @@
|
|
1
|
+
"""
|
2
|
+
Module implementing the BuyerTools Toolkit for Agno agents.
|
3
|
+
"""
|
4
|
+
|
1
5
|
import json
|
2
6
|
import logging
|
3
7
|
from uuid import uuid4
|
4
8
|
|
5
|
-
from
|
6
|
-
from agno.document.base import Document
|
9
|
+
from pydantic import ConfigDict
|
7
10
|
|
8
11
|
from agentstr.models import AgentProfile, NostrProfile
|
9
12
|
from agentstr.nostr import NostrClient, PublicKey
|
10
13
|
|
11
14
|
try:
|
15
|
+
from agno.agent import AgentKnowledge # type: ignore
|
16
|
+
from agno.document.base import Document
|
12
17
|
from agno.tools import Toolkit
|
13
|
-
except ImportError:
|
14
|
-
raise ImportError(
|
18
|
+
except ImportError as exc:
|
19
|
+
raise ImportError(
|
20
|
+
"`agno` not installed. Please install using `pip install agno`"
|
21
|
+
) from exc
|
15
22
|
|
16
23
|
|
17
24
|
def _map_location_to_geohash(location: str) -> str:
|
@@ -21,20 +28,22 @@ def _map_location_to_geohash(location: str) -> str:
|
|
21
28
|
TBD: Implement this function. Returning a fixed geohash for now.
|
22
29
|
|
23
30
|
Args:
|
24
|
-
location: location to map to a geohash. Can be a zip code, city,
|
31
|
+
location: location to map to a geohash. Can be a zip code, city,
|
32
|
+
state, country, or latitude and longitude.
|
25
33
|
|
26
34
|
Returns:
|
27
35
|
str: geohash of the location or empty string if location is not found
|
28
36
|
"""
|
29
37
|
if "snoqualmie" in location.lower():
|
30
38
|
return "C23Q7U36W"
|
31
|
-
|
32
|
-
|
39
|
+
|
40
|
+
return ""
|
33
41
|
|
34
42
|
|
35
43
|
class BuyerTools(Toolkit):
|
36
44
|
"""
|
37
|
-
BuyerTools is a toolkit that allows an agent to find sellers and
|
45
|
+
BuyerTools is a toolkit that allows an agent to find sellers and
|
46
|
+
transact with them over Nostr.
|
38
47
|
|
39
48
|
Sellers are downloaded from the Nostr relay and cached.
|
40
49
|
Sellers can be found by name or public key.
|
@@ -44,8 +53,6 @@ class BuyerTools(Toolkit):
|
|
44
53
|
TBD: populate the sellers locations with info from stalls.
|
45
54
|
"""
|
46
55
|
|
47
|
-
from pydantic import ConfigDict
|
48
|
-
|
49
56
|
model_config = ConfigDict(
|
50
57
|
arbitrary_types_allowed=True, extra="allow", validate_assignment=True
|
51
58
|
)
|
@@ -92,8 +99,13 @@ class BuyerTools(Toolkit):
|
|
92
99
|
|
93
100
|
Args:
|
94
101
|
product: JSON string with product to purchase
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
str: JSON string with status and message
|
95
105
|
"""
|
96
|
-
return json.dumps(
|
106
|
+
return json.dumps(
|
107
|
+
{"status": "success", "message": f"Product {product} purchased"}
|
108
|
+
)
|
97
109
|
|
98
110
|
def find_seller_by_name(self, name: str) -> str:
|
99
111
|
"""Find a seller by name.
|
@@ -151,9 +163,6 @@ class BuyerTools(Toolkit):
|
|
151
163
|
# Find sellers in the same geohash
|
152
164
|
for seller in self.sellers:
|
153
165
|
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
166
|
sellers.add(seller)
|
158
167
|
|
159
168
|
if not sellers:
|
@@ -165,9 +174,17 @@ class BuyerTools(Toolkit):
|
|
165
174
|
response = json.dumps([seller.to_dict() for seller in sellers])
|
166
175
|
# print("find_sellers_by_location: storing response in knowledge base")
|
167
176
|
self._store_response_in_knowledge_base(response)
|
168
|
-
|
177
|
+
self.logger.info("Found %d sellers", len(sellers))
|
169
178
|
return response
|
170
179
|
|
180
|
+
def get_nostr_client(self) -> NostrClient:
|
181
|
+
"""Get the Nostr client.
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
NostrClient: Nostr client
|
185
|
+
"""
|
186
|
+
return self._nostr_client
|
187
|
+
|
171
188
|
def get_profile(self) -> str:
|
172
189
|
"""Get the Nostr profile of the buyer agent.
|
173
190
|
|
@@ -204,7 +221,7 @@ class BuyerTools(Toolkit):
|
|
204
221
|
response = json.dumps([stall.as_json() for stall in stalls])
|
205
222
|
self._store_response_in_knowledge_base(response)
|
206
223
|
return response
|
207
|
-
except
|
224
|
+
except RuntimeError as e:
|
208
225
|
response = json.dumps({"status": "error", "message": str(e)})
|
209
226
|
return response
|
210
227
|
|
@@ -234,7 +251,7 @@ class BuyerTools(Toolkit):
|
|
234
251
|
response = json.dumps([product.to_dict() for product in products])
|
235
252
|
self._store_response_in_knowledge_base(response)
|
236
253
|
return response
|
237
|
-
except
|
254
|
+
except RuntimeError as e:
|
238
255
|
response = json.dumps({"status": "error", "message": str(e)})
|
239
256
|
return response
|
240
257
|
|
@@ -265,7 +282,8 @@ class BuyerTools(Toolkit):
|
|
265
282
|
def _refresh_sellers(self) -> None:
|
266
283
|
"""
|
267
284
|
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
|
285
|
+
The old list is discarded and the new list only contains unique sellers
|
286
|
+
currently stored at the relay.
|
269
287
|
|
270
288
|
Returns:
|
271
289
|
List[NostrProfile]: List of Nostr profiles of all sellers.
|
@@ -274,11 +292,7 @@ class BuyerTools(Toolkit):
|
|
274
292
|
if len(sellers) == 0:
|
275
293
|
self.logger.info("No sellers found")
|
276
294
|
else:
|
277
|
-
self.logger.info(
|
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()}")
|
295
|
+
self.logger.info("Found %d sellers", len(sellers))
|
282
296
|
|
283
297
|
self.sellers = sellers
|
284
298
|
|
@@ -19,6 +19,7 @@ class BuyerTools(Toolkit):
|
|
19
19
|
def find_seller_by_name(self, name: str) -> str: ...
|
20
20
|
def find_seller_by_public_key(self, public_key: str) -> str: ...
|
21
21
|
def find_sellers_by_location(self, location: str) -> str: ...
|
22
|
+
def get_nostr_client(self) -> NostrClient: ...
|
22
23
|
def get_profile(self) -> str: ...
|
23
24
|
def get_relay(self) -> str: ...
|
24
25
|
def get_seller_stalls(self, public_key: str) -> str: ...
|
@@ -1,30 +1,36 @@
|
|
1
|
+
"""
|
2
|
+
Module implementing the MerchantTools Toolkit for Agno agents.
|
3
|
+
"""
|
4
|
+
|
1
5
|
import json
|
2
6
|
import logging
|
3
7
|
import time
|
4
8
|
from typing import Any, List, Optional, Tuple, Union
|
5
9
|
|
10
|
+
from pydantic import ConfigDict
|
11
|
+
|
6
12
|
from agentstr.models import AgentProfile, MerchantProduct, MerchantStall
|
7
13
|
from agentstr.nostr import EventId, NostrClient
|
8
14
|
|
9
15
|
try:
|
10
16
|
from agno.tools import Toolkit
|
11
|
-
except ImportError:
|
12
|
-
raise ImportError(
|
13
|
-
|
14
|
-
from
|
17
|
+
except ImportError as exc:
|
18
|
+
raise ImportError(
|
19
|
+
"`agno` not installed. Please install using `pip install agno`"
|
20
|
+
) from exc
|
15
21
|
|
16
22
|
|
17
23
|
class MerchantTools(Toolkit):
|
18
24
|
"""
|
19
|
-
MerchantTools is a toolkit that allows a merchant to publish
|
25
|
+
MerchantTools is a toolkit that allows a merchant to publish
|
26
|
+
products and stalls to Nostr.
|
20
27
|
|
21
28
|
TBD:
|
22
|
-
- Better differentiation between products and stalls in the database
|
29
|
+
- Better differentiation between products and stalls in the database
|
30
|
+
and products and stalls published.
|
23
31
|
|
24
32
|
"""
|
25
33
|
|
26
|
-
from pydantic import ConfigDict
|
27
|
-
|
28
34
|
model_config = ConfigDict(
|
29
35
|
arbitrary_types_allowed=True, extra="allow", validate_assignment=True
|
30
36
|
)
|
@@ -77,6 +83,12 @@ class MerchantTools(Toolkit):
|
|
77
83
|
self.register(self.remove_product_by_name)
|
78
84
|
self.register(self.remove_stall_by_name)
|
79
85
|
|
86
|
+
def get_nostr_client(self) -> NostrClient:
|
87
|
+
"""
|
88
|
+
Get the NostrClient instance
|
89
|
+
"""
|
90
|
+
return self._nostr_client
|
91
|
+
|
80
92
|
def get_profile(self) -> str:
|
81
93
|
"""
|
82
94
|
Get the merchant profile in JSON format
|
@@ -147,8 +159,8 @@ class MerchantTools(Toolkit):
|
|
147
159
|
)
|
148
160
|
# Pause for 0.5 seconds to avoid rate limiting
|
149
161
|
time.sleep(0.5)
|
150
|
-
except
|
151
|
-
logging.error(
|
162
|
+
except RuntimeError as e:
|
163
|
+
logging.error("Unable to publish product %s. Error %s", product, e)
|
152
164
|
results.append(
|
153
165
|
{"status": "error", "message": str(e), "product_name": product.name}
|
154
166
|
)
|
@@ -159,7 +171,8 @@ class MerchantTools(Toolkit):
|
|
159
171
|
self,
|
160
172
|
) -> str:
|
161
173
|
"""
|
162
|
-
Publishes or updates to Nostr all stalls managed by the merchant and adds
|
174
|
+
Publishes or updates to Nostr all stalls managed by the merchant and adds
|
175
|
+
the corresponding EventId to the Stall DB
|
163
176
|
|
164
177
|
Returns:
|
165
178
|
str: JSON array with status of all stall publishing operations
|
@@ -186,8 +199,8 @@ class MerchantTools(Toolkit):
|
|
186
199
|
)
|
187
200
|
# Pause for 0.5 seconds to avoid rate limiting
|
188
201
|
time.sleep(0.5)
|
189
|
-
except
|
190
|
-
logging.error(
|
202
|
+
except RuntimeError as e:
|
203
|
+
logging.error("Unable to publish stall %s. Error %s", stall, e)
|
191
204
|
results.append(
|
192
205
|
{"status": "error", "message": str(e), "stall_name": stall.name}
|
193
206
|
)
|
@@ -196,7 +209,8 @@ class MerchantTools(Toolkit):
|
|
196
209
|
|
197
210
|
def publish_new_product(self, product: MerchantProduct) -> str:
|
198
211
|
"""
|
199
|
-
Publishes to Nostra new product that is not currently in the Merchant's
|
212
|
+
Publishes to Nostra new product that is not currently in the Merchant's
|
213
|
+
Product DB and adds it to the Product DB
|
200
214
|
|
201
215
|
Args:
|
202
216
|
product: MerchantProduct to be published
|
@@ -224,7 +238,7 @@ class MerchantTools(Toolkit):
|
|
224
238
|
"product_name": product.name,
|
225
239
|
}
|
226
240
|
)
|
227
|
-
except
|
241
|
+
except RuntimeError as e:
|
228
242
|
return json.dumps(
|
229
243
|
{"status": "error", "message": str(e), "product_name": product.name}
|
230
244
|
)
|
@@ -233,7 +247,8 @@ class MerchantTools(Toolkit):
|
|
233
247
|
"""
|
234
248
|
Publishes or updates to Nostra given product from the Merchant's Product DB
|
235
249
|
Args:
|
236
|
-
arguments: JSON string that may contain
|
250
|
+
arguments: JSON string that may contain
|
251
|
+
{"name": "product_name"} or just "product_name"
|
237
252
|
|
238
253
|
Returns:
|
239
254
|
str: JSON string with status of the operation
|
@@ -267,6 +282,8 @@ class MerchantTools(Toolkit):
|
|
267
282
|
event_id = self._nostr_client.publish_product(product)
|
268
283
|
# Update the product_db with the new event_id
|
269
284
|
self.product_db[i] = (product, event_id)
|
285
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
286
|
+
time.sleep(0.5)
|
270
287
|
return json.dumps(
|
271
288
|
{
|
272
289
|
"status": "success",
|
@@ -274,9 +291,7 @@ class MerchantTools(Toolkit):
|
|
274
291
|
"product_name": product.name,
|
275
292
|
}
|
276
293
|
)
|
277
|
-
|
278
|
-
time.sleep(0.5)
|
279
|
-
except Exception as e:
|
294
|
+
except RuntimeError as e:
|
280
295
|
return json.dumps(
|
281
296
|
{
|
282
297
|
"status": "error",
|
@@ -376,7 +391,7 @@ class MerchantTools(Toolkit):
|
|
376
391
|
)
|
377
392
|
# Pause for 0.5 seconds to avoid rate limiting
|
378
393
|
time.sleep(0.5)
|
379
|
-
except
|
394
|
+
except RuntimeError as e:
|
380
395
|
results.append(
|
381
396
|
{
|
382
397
|
"status": "error",
|
@@ -399,7 +414,7 @@ class MerchantTools(Toolkit):
|
|
399
414
|
|
400
415
|
return json.dumps(results)
|
401
416
|
|
402
|
-
except
|
417
|
+
except RuntimeError as e:
|
403
418
|
return json.dumps(
|
404
419
|
[{"status": "error", "message": str(e), "arguments": str(arguments)}]
|
405
420
|
)
|
@@ -424,12 +439,13 @@ class MerchantTools(Toolkit):
|
|
424
439
|
self.merchant_profile.get_picture(),
|
425
440
|
)
|
426
441
|
return json.dumps(event_id.__dict__)
|
427
|
-
except
|
428
|
-
raise RuntimeError(f"Unable to publish the profile: {e}")
|
442
|
+
except RuntimeError as e:
|
443
|
+
raise RuntimeError(f"Unable to publish the profile: {e}") from e
|
429
444
|
|
430
445
|
def publish_new_stall(self, stall: MerchantStall) -> str:
|
431
446
|
"""
|
432
|
-
Publishes to Nostr a new stall that is not currently in the Merchant's
|
447
|
+
Publishes to Nostr a new stall that is not currently in the Merchant's
|
448
|
+
Stall DB and adds it to the Stall DB
|
433
449
|
|
434
450
|
Args:
|
435
451
|
stall: MerchantStall to be published
|
@@ -444,7 +460,8 @@ class MerchantTools(Toolkit):
|
|
444
460
|
raise ValueError("NostrClient not initialized")
|
445
461
|
|
446
462
|
try:
|
447
|
-
# We don't ned to convert to StallData.
|
463
|
+
# We don't ned to convert to StallData.
|
464
|
+
# nostr_client.publish_stall() accepts a MerchantStall
|
448
465
|
# stall_data = stall.to_stall_data()
|
449
466
|
# Publish using the synchronous method
|
450
467
|
event_id = self._nostr_client.publish_stall(stall)
|
@@ -457,7 +474,7 @@ class MerchantTools(Toolkit):
|
|
457
474
|
"stall_name": stall.name,
|
458
475
|
}
|
459
476
|
)
|
460
|
-
except
|
477
|
+
except RuntimeError as e:
|
461
478
|
return json.dumps(
|
462
479
|
{"status": "error", "message": str(e), "stall_name": stall.name}
|
463
480
|
)
|
@@ -514,10 +531,10 @@ class MerchantTools(Toolkit):
|
|
514
531
|
for i, (stall, _) in enumerate(self.stall_db):
|
515
532
|
if stall.name == stall_name:
|
516
533
|
try:
|
517
|
-
# We are not passing StallData to nostr_client.publish_stall() anymore
|
518
|
-
# stall_data = stall.to_stall_data()
|
519
534
|
event_id = self._nostr_client.publish_stall(stall)
|
520
535
|
self.stall_db[i] = (stall, event_id)
|
536
|
+
# Pause for 0.5 seconds to avoid rate limiting
|
537
|
+
time.sleep(0.5)
|
521
538
|
return json.dumps(
|
522
539
|
{
|
523
540
|
"status": "success",
|
@@ -525,9 +542,8 @@ class MerchantTools(Toolkit):
|
|
525
542
|
"stall_name": stall.name,
|
526
543
|
}
|
527
544
|
)
|
528
|
-
|
529
|
-
|
530
|
-
except Exception as e:
|
545
|
+
|
546
|
+
except RuntimeError as e:
|
531
547
|
return json.dumps(
|
532
548
|
[
|
533
549
|
{
|
@@ -549,7 +565,7 @@ class MerchantTools(Toolkit):
|
|
549
565
|
]
|
550
566
|
)
|
551
567
|
|
552
|
-
except
|
568
|
+
except RuntimeError as e:
|
553
569
|
return json.dumps(
|
554
570
|
[{"status": "error", "message": str(e), "stall_name": "unknown"}]
|
555
571
|
)
|
@@ -574,7 +590,9 @@ class MerchantTools(Toolkit):
|
|
574
590
|
results.append(
|
575
591
|
{
|
576
592
|
"status": "skipped",
|
577
|
-
"message":
|
593
|
+
"message": (
|
594
|
+
f"Product '{product.name}' has not been published yet"
|
595
|
+
),
|
578
596
|
"product_name": product.name,
|
579
597
|
}
|
580
598
|
)
|
@@ -597,7 +615,7 @@ class MerchantTools(Toolkit):
|
|
597
615
|
)
|
598
616
|
# Pause for 0.5 seconds to avoid rate limiting
|
599
617
|
time.sleep(0.5)
|
600
|
-
except
|
618
|
+
except RuntimeError as e:
|
601
619
|
results.append(
|
602
620
|
{"status": "error", "message": str(e), "product_name": product.name}
|
603
621
|
)
|
@@ -606,7 +624,8 @@ class MerchantTools(Toolkit):
|
|
606
624
|
|
607
625
|
def remove_all_stalls(self) -> str:
|
608
626
|
"""
|
609
|
-
Removes from Nostr all stalls from the merchant and their
|
627
|
+
Removes from Nostr all stalls from the merchant and their
|
628
|
+
corresponding products
|
610
629
|
|
611
630
|
Returns:
|
612
631
|
str: JSON array with status of all removal operations
|
@@ -631,7 +650,7 @@ class MerchantTools(Toolkit):
|
|
631
650
|
results.append(
|
632
651
|
{
|
633
652
|
"status": "skipped",
|
634
|
-
"message":
|
653
|
+
"message": "Unpublished product",
|
635
654
|
"product_name": product.name,
|
636
655
|
"stall_name": stall_name,
|
637
656
|
}
|
@@ -653,7 +672,7 @@ class MerchantTools(Toolkit):
|
|
653
672
|
"event_id": str(event_id),
|
654
673
|
}
|
655
674
|
)
|
656
|
-
except
|
675
|
+
except RuntimeError as e:
|
657
676
|
results.append(
|
658
677
|
{
|
659
678
|
"status": "error",
|
@@ -669,7 +688,7 @@ class MerchantTools(Toolkit):
|
|
669
688
|
results.append(
|
670
689
|
{
|
671
690
|
"status": "skipped",
|
672
|
-
"message": f"Stall '{stall_name}' has not been published yet",
|
691
|
+
"message": (f"Stall '{stall_name}' has not been published yet"),
|
673
692
|
"stall_name": stall_name,
|
674
693
|
}
|
675
694
|
)
|
@@ -689,7 +708,7 @@ class MerchantTools(Toolkit):
|
|
689
708
|
)
|
690
709
|
# Pause for 0.5 seconds to avoid rate limiting
|
691
710
|
time.sleep(0.5)
|
692
|
-
except
|
711
|
+
except RuntimeError as e:
|
693
712
|
results.append(
|
694
713
|
{"status": "error", "message": str(e), "stall_name": stall_name}
|
695
714
|
)
|
@@ -701,7 +720,8 @@ class MerchantTools(Toolkit):
|
|
701
720
|
Removes from Nostr a product with the given name
|
702
721
|
|
703
722
|
Args:
|
704
|
-
arguments: JSON string that may contain {"name": "product_name"}
|
723
|
+
arguments: JSON string that may contain {"name": "product_name"}
|
724
|
+
or just "product_name"
|
705
725
|
|
706
726
|
Returns:
|
707
727
|
str: JSON string with status of the operation
|
@@ -754,7 +774,7 @@ class MerchantTools(Toolkit):
|
|
754
774
|
"event_id": str(event_id),
|
755
775
|
}
|
756
776
|
)
|
757
|
-
except
|
777
|
+
except RuntimeError as e:
|
758
778
|
return json.dumps(
|
759
779
|
{"status": "error", "message": str(e), "product_name": name}
|
760
780
|
)
|
@@ -843,7 +863,7 @@ class MerchantTools(Toolkit):
|
|
843
863
|
results.append(
|
844
864
|
{
|
845
865
|
"status": "skipped",
|
846
|
-
"message":
|
866
|
+
"message": "Unpublished product",
|
847
867
|
"product_name": product.name,
|
848
868
|
"stall_name": stall_name,
|
849
869
|
}
|
@@ -866,7 +886,7 @@ class MerchantTools(Toolkit):
|
|
866
886
|
)
|
867
887
|
# Pause for 0.5 seconds to avoid rate limiting
|
868
888
|
time.sleep(0.5)
|
869
|
-
except
|
889
|
+
except RuntimeError as e:
|
870
890
|
results.append(
|
871
891
|
{
|
872
892
|
"status": "error",
|
@@ -883,7 +903,9 @@ class MerchantTools(Toolkit):
|
|
883
903
|
results.append(
|
884
904
|
{
|
885
905
|
"status": "skipped",
|
886
|
-
"message":
|
906
|
+
"message": (
|
907
|
+
f"Stall '{stall_name}' has not been published yet"
|
908
|
+
),
|
887
909
|
"stall_name": stall_name,
|
888
910
|
}
|
889
911
|
)
|
@@ -904,7 +926,7 @@ class MerchantTools(Toolkit):
|
|
904
926
|
"event_id": str(stall_event_id),
|
905
927
|
}
|
906
928
|
)
|
907
|
-
except
|
929
|
+
except RuntimeError as e:
|
908
930
|
results.append(
|
909
931
|
{
|
910
932
|
"status": "error",
|
@@ -915,20 +937,7 @@ class MerchantTools(Toolkit):
|
|
915
937
|
|
916
938
|
return json.dumps(results)
|
917
939
|
|
918
|
-
except
|
940
|
+
except RuntimeError as e:
|
919
941
|
return json.dumps(
|
920
942
|
[{"status": "error", "message": str(e), "stall_name": "unknown"}]
|
921
943
|
)
|
922
|
-
|
923
|
-
# def get_event_id(self, response: Any) -> str:
|
924
|
-
# """Convert any response to a string event ID.
|
925
|
-
|
926
|
-
# Args:
|
927
|
-
# response: Response that might contain an event ID
|
928
|
-
|
929
|
-
# Returns:
|
930
|
-
# str: String representation of event ID or empty string if None
|
931
|
-
# """
|
932
|
-
# if response is None:
|
933
|
-
# return ""
|
934
|
-
# return str(response)
|
@@ -18,6 +18,7 @@ class MerchantTools(Toolkit):
|
|
18
18
|
stalls: List[MerchantStall],
|
19
19
|
products: List[MerchantProduct],
|
20
20
|
) -> None: ...
|
21
|
+
def get_nostr_client(self) -> NostrClient: ...
|
21
22
|
def get_profile(self) -> str: ...
|
22
23
|
def get_relay(self) -> str: ...
|
23
24
|
def get_products(self) -> str: ...
|
@@ -34,4 +35,3 @@ class MerchantTools(Toolkit):
|
|
34
35
|
def remove_all_stalls(self) -> str: ...
|
35
36
|
def remove_product_by_name(self, product_name: str) -> str: ...
|
36
37
|
def remove_stall_by_name(self, stall_name: str) -> str: ...
|
37
|
-
def get_event_id(self, response: Any) -> str: ...
|