agentstr 0.0.9__py3-none-any.whl → 0.0.10__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- agentstr/marketplace.py +163 -0
- agentstr/nostr.py +141 -0
- {agentstr-0.0.9.dist-info → agentstr-0.0.10.dist-info}/METADATA +44 -26
- agentstr-0.0.10.dist-info/RECORD +8 -0
- agentstr/core.py +0 -42
- agentstr-0.0.9.dist-info/RECORD +0 -7
- {agentstr-0.0.9.dist-info → agentstr-0.0.10.dist-info}/LICENSE +0 -0
- {agentstr-0.0.9.dist-info → agentstr-0.0.10.dist-info}/WHEEL +0 -0
- {agentstr-0.0.9.dist-info → agentstr-0.0.10.dist-info}/top_level.txt +0 -0
agentstr/marketplace.py
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import Optional
|
3
|
+
from . import nostr
|
4
|
+
|
5
|
+
try:
|
6
|
+
from phi.tools import Toolkit
|
7
|
+
except ImportError:
|
8
|
+
raise ImportError("`phidata` not installed. Please install using `pip install phidata`")
|
9
|
+
|
10
|
+
try:
|
11
|
+
import asyncio
|
12
|
+
except ImportError:
|
13
|
+
raise ImportError("`asyncio` not installed. Please install using `pip install asyncio`")
|
14
|
+
|
15
|
+
class MerchantProfile():
|
16
|
+
|
17
|
+
logger = logging.getLogger("MerchantProfile")
|
18
|
+
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
name: str,
|
22
|
+
about: str,
|
23
|
+
picture: str,
|
24
|
+
nsec: Optional[str] = None
|
25
|
+
):
|
26
|
+
"""Initialize the Merchant profile.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
name: Name for the merchant
|
30
|
+
about: brief description about the merchant
|
31
|
+
picture: url to a png file with a picture for the merchant
|
32
|
+
nsec: private key to be used by this Merchant
|
33
|
+
"""
|
34
|
+
|
35
|
+
# Set log handling for MerchantProfile
|
36
|
+
if not MerchantProfile.logger.hasHandlers():
|
37
|
+
console_handler = logging.StreamHandler()
|
38
|
+
console_handler.setLevel(logging.INFO)
|
39
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
40
|
+
console_handler.setFormatter(formatter)
|
41
|
+
MerchantProfile.logger.addHandler(console_handler)
|
42
|
+
|
43
|
+
self.name = name
|
44
|
+
self.about = about
|
45
|
+
self.picture = picture
|
46
|
+
|
47
|
+
if nsec:
|
48
|
+
self.private_key = nsec
|
49
|
+
keys = nostr.Keys.parse(self.private_key)
|
50
|
+
self.public_key = keys.public_key().to_bech32()
|
51
|
+
MerchantProfile.logger.info(f"Pre-defined private key reused for {self.name}: {self.private_key}")
|
52
|
+
MerchantProfile.logger.info(f"Pre-defined public key reused for {self.name}: {self.public_key}")
|
53
|
+
else:
|
54
|
+
keys = nostr.Keys.generate()
|
55
|
+
self.private_key = keys.secret_key().to_bech32()
|
56
|
+
self.public_key = keys.public_key().to_bech32()
|
57
|
+
MerchantProfile.logger.info(f"New private key created for {self.name}: {self.private_key}")
|
58
|
+
MerchantProfile.logger.info(f"New public key created for {self.name}: {self.public_key}")
|
59
|
+
|
60
|
+
def merchant_profile_to_str(self) -> str:
|
61
|
+
return (
|
62
|
+
f"Merchant name: {self.name}. "
|
63
|
+
f"Merchant description: {self.about}. "
|
64
|
+
f"Merchant picture URL: {self.picture}. "
|
65
|
+
f"Private key: {self.private_key}. "
|
66
|
+
f"Public key: {self.public_key}."
|
67
|
+
)
|
68
|
+
|
69
|
+
def get_public_key(self) -> str:
|
70
|
+
return self.public_key
|
71
|
+
|
72
|
+
def get_private_key(self) -> str:
|
73
|
+
return self.private_key
|
74
|
+
|
75
|
+
def get_name(self) -> str:
|
76
|
+
return self.name
|
77
|
+
|
78
|
+
def get_about(self) -> str:
|
79
|
+
return self.about
|
80
|
+
|
81
|
+
def get_picture(self) -> str:
|
82
|
+
return self.picture
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
class Merchant(Toolkit):
|
87
|
+
|
88
|
+
WEB_URL: str = "http://njump.me/"
|
89
|
+
|
90
|
+
def __init__(
|
91
|
+
self,
|
92
|
+
merchant_profile: MerchantProfile,
|
93
|
+
relay: str,
|
94
|
+
):
|
95
|
+
"""Initialize the Merchant toolkit.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
merchant_profile: profile of the merchant using this agent
|
99
|
+
relay: Nostr relay to use for communications
|
100
|
+
"""
|
101
|
+
super().__init__(name="merchant")
|
102
|
+
self.relay = relay
|
103
|
+
self.merchant_profile = merchant_profile
|
104
|
+
|
105
|
+
# Register all methods
|
106
|
+
self.register(self.publish_merchant_profile)
|
107
|
+
self.register(self.get_merchant_url)
|
108
|
+
|
109
|
+
def publish_merchant_profile(
|
110
|
+
self
|
111
|
+
) -> str:
|
112
|
+
"""
|
113
|
+
Publishes the merchant profile on Nostr
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
str: with event id and other details if successful or "error" string if unsuccesful
|
117
|
+
"""
|
118
|
+
# Run the async pubilshing function synchronously
|
119
|
+
return asyncio.run(self._async_publish_merchant_profile())
|
120
|
+
|
121
|
+
async def _async_publish_merchant_profile(
|
122
|
+
self
|
123
|
+
) -> str:
|
124
|
+
"""
|
125
|
+
Asynchronous method to publish the merchant profile on Nostr
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
str: with event id and other details if successful or "error" string if unsuccesful
|
129
|
+
"""
|
130
|
+
|
131
|
+
nostr_client = nostr.NostrClient(self.relay, self.merchant_profile.get_private_key())
|
132
|
+
|
133
|
+
# Connect to the relay
|
134
|
+
outcome = await nostr_client.connect()
|
135
|
+
|
136
|
+
# Check if the operation resulted in an error
|
137
|
+
if outcome == nostr.NostrClient.ERROR:
|
138
|
+
return nostr.NostrClient.ERROR
|
139
|
+
else:
|
140
|
+
eventid = await nostr_client.publish_profile(
|
141
|
+
self.merchant_profile.get_name(),
|
142
|
+
self.merchant_profile.get_about(),
|
143
|
+
self.merchant_profile.get_picture()
|
144
|
+
)
|
145
|
+
|
146
|
+
# Check if the operation resulted in an error
|
147
|
+
if eventid == nostr.NostrClient.ERROR:
|
148
|
+
return nostr.NostrClient.ERROR
|
149
|
+
|
150
|
+
# Return the event ID and merchant profile details
|
151
|
+
return eventid + self.merchant_profile.merchant_profile_to_str()
|
152
|
+
|
153
|
+
def get_merchant_url(
|
154
|
+
self
|
155
|
+
) -> str:
|
156
|
+
"""
|
157
|
+
Returns URL with merchant profile
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
str: valid URL with merchant profile
|
161
|
+
"""
|
162
|
+
|
163
|
+
return self.WEB_URL + self.merchant_profile.get_public_key()
|
agentstr/nostr.py
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from os import getenv
|
3
|
+
import logging
|
4
|
+
|
5
|
+
try:
|
6
|
+
import asyncio
|
7
|
+
except ImportError:
|
8
|
+
raise ImportError("`asyncio` not installed. Please install using `pip install asyncio`")
|
9
|
+
|
10
|
+
try:
|
11
|
+
from nostr_sdk import Keys, Client, EventBuilder, NostrSigner, SendEventOutput, Event, Metadata
|
12
|
+
except ImportError:
|
13
|
+
raise ImportError("`nostr_sdk` not installed. Please install using `pip install nostr_sdk`")
|
14
|
+
|
15
|
+
class NostrClient():
|
16
|
+
|
17
|
+
logger = logging.getLogger("NostrClient")
|
18
|
+
ERROR: str = "ERROR"
|
19
|
+
SUCCESS: str = "SUCCESS"
|
20
|
+
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
relay: str = None,
|
24
|
+
nsec: str = None,
|
25
|
+
):
|
26
|
+
"""Initialize the Nostr client.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
relay: Nostr relay that the client will connect to
|
30
|
+
nsec: Nostr private key in bech32 format
|
31
|
+
"""
|
32
|
+
# Set log handling
|
33
|
+
if not NostrClient.logger.hasHandlers():
|
34
|
+
console_handler = logging.StreamHandler()
|
35
|
+
console_handler.setLevel(logging.INFO)
|
36
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
37
|
+
console_handler.setFormatter(formatter)
|
38
|
+
NostrClient.logger.addHandler(console_handler)
|
39
|
+
|
40
|
+
self.relay = relay
|
41
|
+
self.keys = Keys.parse(nsec)
|
42
|
+
self.nostr_signer = NostrSigner.keys(self.keys)
|
43
|
+
self.client = Client(self.nostr_signer)
|
44
|
+
|
45
|
+
|
46
|
+
async def connect(
|
47
|
+
self
|
48
|
+
) -> str:
|
49
|
+
|
50
|
+
"""Add relay to the NostrClient instance and connect to it.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
str: NostrClient.SUCCESS or NostrClient.ERROR
|
54
|
+
"""
|
55
|
+
try:
|
56
|
+
await self.client.add_relay(self.relay)
|
57
|
+
NostrClient.logger.info(f"Relay {self.relay} succesfully added.")
|
58
|
+
await self.client.connect()
|
59
|
+
NostrClient.logger.info("Connected to relay.")
|
60
|
+
return NostrClient.SUCCESS
|
61
|
+
except Exception as e:
|
62
|
+
NostrClient.logger.error(f"Unable to connect to relay {self.relay}. Exception: {e}.")
|
63
|
+
return NostrClient.ERROR
|
64
|
+
|
65
|
+
async def publish_text_note(
|
66
|
+
self,
|
67
|
+
text: str
|
68
|
+
) -> str:
|
69
|
+
|
70
|
+
"""Publish kind 1 event (text note) to the relay
|
71
|
+
|
72
|
+
Args:
|
73
|
+
text: text to be published as kind 1 event
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
str: event id if successful and "error" string if unsuccesful
|
77
|
+
"""
|
78
|
+
builder = EventBuilder.text_note(text)
|
79
|
+
|
80
|
+
try:
|
81
|
+
output = await self.client.send_event_builder(builder)
|
82
|
+
NostrClient.logger.info(f"Text note published with event id: {output.id.to_bech32()}")
|
83
|
+
return output.id.to_bech32()
|
84
|
+
except Exception as e:
|
85
|
+
NostrClient.logger.error(f"Unable to publish text note to relay {self.relay}. Exception: {e}.")
|
86
|
+
return NostrClient.ERROR
|
87
|
+
|
88
|
+
async def publish_event(
|
89
|
+
self,
|
90
|
+
builder: EventBuilder
|
91
|
+
) -> str:
|
92
|
+
|
93
|
+
"""Publish generic Nostr event to the relay
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
str: event id if successful or "error" string if unsuccesful
|
97
|
+
"""
|
98
|
+
try:
|
99
|
+
output = await self.client.send_event_builder(builder)
|
100
|
+
NostrClient.logger.info(f"Event published with event id: {output.id.to_bech32()}")
|
101
|
+
return output.id.to_bech32()
|
102
|
+
except Exception as e:
|
103
|
+
NostrClient.logger.error(f"Unable to publish event to relay {self.relay}. Exception: {e}.")
|
104
|
+
return NostrClient.ERROR
|
105
|
+
|
106
|
+
async def publish_profile(self, name: str, about: str, picture: str) -> str:
|
107
|
+
"""Publish a Nostr profile.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
name: name of the Nostr profile
|
111
|
+
about: brief description about the profile
|
112
|
+
picture: url to a png file with a picture for the profile
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
str: event id if successful or "error" string if unsuccesful
|
116
|
+
"""
|
117
|
+
metadata_content = Metadata().set_name(name)
|
118
|
+
metadata_content = metadata_content.set_about(about)
|
119
|
+
metadata_content = metadata_content.set_picture(picture)
|
120
|
+
|
121
|
+
builder = EventBuilder.metadata(metadata_content)
|
122
|
+
try:
|
123
|
+
output = await self.client.send_event_builder(builder)
|
124
|
+
NostrClient.logger.info(f"Profile note published with event id: {output.id.to_bech32()}")
|
125
|
+
return output.id.to_bech32()
|
126
|
+
except Exception as e:
|
127
|
+
NostrClient.logger.error(f"Unable to publish profile to relay {self.relay}. Exception: {e}.")
|
128
|
+
return NostrClient.ERROR
|
129
|
+
|
130
|
+
@classmethod
|
131
|
+
def set_logging_level(cls, logging_level: int):
|
132
|
+
"""
|
133
|
+
Set the logging level for the NostrClient logger.
|
134
|
+
|
135
|
+
Args:
|
136
|
+
logging_level (int): The logging level (e.g., logging.DEBUG, logging.INFO).
|
137
|
+
"""
|
138
|
+
cls.logger.setLevel(logging_level)
|
139
|
+
for handler in cls.logger.handlers:
|
140
|
+
handler.setLevel(logging_level)
|
141
|
+
cls.logger.info(f"Logging level set to {logging.getLevelName(logging_level)}")
|
@@ -1,9 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: agentstr
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.10
|
4
4
|
Summary: A library for collaborative AI agents
|
5
|
-
Home-page: https://github.com/synvya/agentstr
|
6
|
-
Author: Alejandro Gil
|
7
5
|
Author-email: Alejandro Gil <info@synvya.com>
|
8
6
|
License: MIT
|
9
7
|
Project-URL: Homepage, https://github.com/synvya/agentstr
|
@@ -13,14 +11,13 @@ Keywords: AI,agents,collaboration,library
|
|
13
11
|
Classifier: Programming Language :: Python :: 3
|
14
12
|
Classifier: License :: OSI Approved :: MIT License
|
15
13
|
Classifier: Operating System :: OS Independent
|
16
|
-
Requires-Python:
|
14
|
+
Requires-Python: <3.13,>=3.9
|
17
15
|
Description-Content-Type: text/markdown
|
18
16
|
License-File: LICENSE
|
19
17
|
Requires-Dist: phidata>=2.7.0
|
20
18
|
Requires-Dist: openai>=1.50.0
|
21
|
-
|
22
|
-
|
23
|
-
Dynamic: requires-python
|
19
|
+
Requires-Dist: packaging>=24.0
|
20
|
+
Requires-Dist: nostr-sdk>=0.38.0
|
24
21
|
|
25
22
|
AgentStr
|
26
23
|
========
|
@@ -28,6 +25,10 @@ AgentStr is an extension of [Phidata](https://www.phidata.com) AI agents that al
|
|
28
25
|
|
29
26
|
The goal is for Agent A operated by Company A to be able to work with Agent B operated by Company B to achieve a common goal. For example: Company A wants to buy a product sold by Company B so Agent A and Agent B can coordinate and execute the transaction.
|
30
27
|
|
28
|
+
The basic communication tools are implemented in `agentstr/nostr.py`.
|
29
|
+
|
30
|
+
As a first example, AgentStr provides the tools to create and operate a marketplace using the [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) Nostr Marketplace as its foundation. The file `agentstr/marketplace.py` includes NIP-15 `merchant` and `customer` profiles implemented each as a Phidata Toolkit.
|
31
|
+
|
31
32
|
# License
|
32
33
|
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
33
34
|
|
@@ -36,16 +37,13 @@ The library is in its infancy.
|
|
36
37
|
|
37
38
|
Done:
|
38
39
|
- Workflow to package and distribute the library
|
39
|
-
-
|
40
|
-
|
40
|
+
- Users can create a Merchant profile and create an agent with the `merchant` toolkit that acts on behalf of the Merchant profile
|
41
|
+
|
41
42
|
|
42
43
|
To be done:
|
43
|
-
-
|
44
|
-
-
|
45
|
-
-
|
46
|
-
- Expose capabilities via Nostr
|
47
|
-
- Agent B retrieves capabilities exposed by Agent A
|
48
|
-
- Agent B coordinates transaction with Agent A
|
44
|
+
- Create a `marketplace` with `stalls`
|
45
|
+
- Merchants to define `products`
|
46
|
+
- Create a `customer` Toolkit
|
49
47
|
|
50
48
|
# Installation
|
51
49
|
AgentStr is offered as a python library available at https://pypi.org/project/agentstr/.
|
@@ -56,10 +54,11 @@ Here is an example on how to use the library:
|
|
56
54
|
```
|
57
55
|
cd ~/
|
58
56
|
python3 -m venv ~/.venvs/aienv
|
59
|
-
source ~/.venvs/aienv/bin/
|
57
|
+
source ~/.venvs/aienv/bin/activate
|
60
58
|
```
|
61
59
|
2. Install the agentstr library
|
62
60
|
```
|
61
|
+
pip install --upgrade pip
|
63
62
|
pip install agentstr
|
64
63
|
mkdir ~/mysampleapp
|
65
64
|
cd ~/mysampleapp
|
@@ -70,24 +69,43 @@ Here is an example on how to use the library:
|
|
70
69
|
```
|
71
70
|
4. Copy paste this code to the main.py file
|
72
71
|
```
|
73
|
-
from
|
74
|
-
|
75
|
-
agent
|
72
|
+
from dotenv import load_dotenv
|
73
|
+
from os import getenv
|
74
|
+
from phi.agent import Agent
|
75
|
+
from phi.model.openai import OpenAIChat
|
76
|
+
from agentstr.marketplace import MerchantProfile, Merchant
|
76
77
|
|
77
|
-
# Test AgentStr new capabilities
|
78
|
-
print(f"Public key: {agent.get_public_key()}\nPrivate key: {agent.get_private_key()}")
|
79
|
-
print(f"Company: {agent.get_company()}\nRole: {agent.get_role()}")
|
80
78
|
|
81
|
-
|
82
|
-
|
79
|
+
profile = MerchantProfile(
|
80
|
+
"Synvya",
|
81
|
+
"Testing stuff",
|
82
|
+
"https://i.nostr.build/ocjZ5GlAKwrvgRhx.png",
|
83
|
+
getenv("NSEC_KEY")
|
84
|
+
)
|
85
|
+
|
86
|
+
agent = Agent(
|
87
|
+
name="Merchant Assistant",
|
88
|
+
model=OpenAIChat(id="gpt-4o"),
|
89
|
+
tools=[Merchant(merchant_profile=profile, relay="wss://relay.damus.io")],
|
90
|
+
show_tool_calls=True,
|
91
|
+
markdown=True,
|
92
|
+
debug_mode=True
|
93
|
+
)
|
94
|
+
|
95
|
+
agent.print_response("Publish the merchant information and tell me the event id used")
|
83
96
|
```
|
84
|
-
5.
|
97
|
+
5. Export your OpenAI key and optionally a Nostr private key before running the code
|
85
98
|
```
|
99
|
+
export OPENAI_API_KEY="sk-***"
|
100
|
+
export NSEC_KEY="nsec***"
|
86
101
|
python main.py
|
87
102
|
```
|
88
103
|
|
104
|
+
This example will attempt to load a Nostr private key defined as NSEC_KEY in bech32 format. If a private key is not provided, the `MerchantProfile` class initializer will assign it a new one.
|
105
|
+
|
89
106
|
# Contributing
|
90
107
|
Refer to [CONTRIBUTING.md](CONTRIBUTING.md) for specific instructions on installation instructions for developers and how to contribute.
|
91
108
|
|
92
109
|
# Acknowledgments
|
93
|
-
- [Phidata](https://www.phidata.com
|
110
|
+
- [Phidata](https://www.phidata.com) - For building robust AI agents.
|
111
|
+
- [Rust-Nostr](https://rust-nostr.org/index.html) - For providing a python based Nostr SDK.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
agentstr/__init__.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
|
2
|
+
agentstr/marketplace.py,sha256=XYF2ZrF6MpmxgCEOz3uN436cj7F4VHyUATFk8gmr7Zg,5245
|
3
|
+
agentstr/nostr.py,sha256=C5zMWKBbXLkarZxBoTydJCZVzqGoCogBd_9v8Gll0VU,5012
|
4
|
+
agentstr-0.0.10.dist-info/LICENSE,sha256=xF8akIKB07gOtkhjENT0xVbWGdFp4-srDKpZKjD03Js,1063
|
5
|
+
agentstr-0.0.10.dist-info/METADATA,sha256=GuVKTLwjr6Skj4HH387GQP7YYMnTKulqgh8OQuuJGvs,4082
|
6
|
+
agentstr-0.0.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
7
|
+
agentstr-0.0.10.dist-info/top_level.txt,sha256=KZObFRHppZvKUGYB_m9w5HhLwps7jj7w6Xrw73dH2ss,9
|
8
|
+
agentstr-0.0.10.dist-info/RECORD,,
|
agentstr/core.py
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
from phi.agent import Agent
|
2
|
-
from phi.model.openai import OpenAIChat
|
3
|
-
from pydantic import Field
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
|
7
|
-
class AgentStr(Agent):
|
8
|
-
|
9
|
-
# -*- Agent settings
|
10
|
-
# Company operating the agent.
|
11
|
-
# Used as seed for public / private key identifier together with the agent role
|
12
|
-
company: str = None
|
13
|
-
|
14
|
-
# -*- Agent public / private key identifiers
|
15
|
-
# The public / private key should be deterministic for a given 'company' and 'role' combination
|
16
|
-
# Public key for the agent
|
17
|
-
npub: str = None
|
18
|
-
# Private key for the agent
|
19
|
-
nsec: str = None
|
20
|
-
|
21
|
-
# Call the parent class (Agent) constructor
|
22
|
-
def __init__(self, company: str, role: str):
|
23
|
-
super().__init__(role = role, model=OpenAIChat(id="gpt-4o"))
|
24
|
-
self.company = company
|
25
|
-
self.npub = f"npub - {self.company} - {self.role}"
|
26
|
-
self.nsec = f"nsec - {self.company} - {self.role}"
|
27
|
-
|
28
|
-
def get_public_key(self) -> str:
|
29
|
-
return self.npub
|
30
|
-
|
31
|
-
def get_private_key(self) -> str:
|
32
|
-
return self.nsec
|
33
|
-
|
34
|
-
def get_company(self) -> str:
|
35
|
-
return self.company
|
36
|
-
|
37
|
-
def get_role(self) -> str:
|
38
|
-
return self.role
|
39
|
-
|
40
|
-
def add(a, b):
|
41
|
-
"""Add two numbers."""
|
42
|
-
return a + b
|
agentstr-0.0.9.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
agentstr/__init__.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
|
2
|
-
agentstr/core.py,sha256=xS5q8ltl81DqLjKgiVtjUQ5r-jbEPXXjTlJ0pWcV5p8,1214
|
3
|
-
agentstr-0.0.9.dist-info/LICENSE,sha256=xF8akIKB07gOtkhjENT0xVbWGdFp4-srDKpZKjD03Js,1063
|
4
|
-
agentstr-0.0.9.dist-info/METADATA,sha256=0H9Gophcg8p8Hw3vCZhQanTZTb9EGkCNvMWXsA_aOo0,3194
|
5
|
-
agentstr-0.0.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
6
|
-
agentstr-0.0.9.dist-info/top_level.txt,sha256=KZObFRHppZvKUGYB_m9w5HhLwps7jj7w6Xrw73dH2ss,9
|
7
|
-
agentstr-0.0.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|