agentstr 0.0.9__tar.gz → 0.1.7__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: agentstr
3
- Version: 0.0.9
3
+ Version: 0.1.7
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: >=3.6
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
- Dynamic: author
22
- Dynamic: home-page
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
- - Create AgentStr as an extension of Phidata Agent
40
- - Test the addition of new properties and capabilities for the AgentStr class
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
- - Incorporate Nostr capabilities
44
- - Create unique public / private key identifiers for agent instances
45
- - Send and retreive messages via Nostr
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/acticate
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 agentstr.core import AgentStr
74
- # Create the agent
75
- agent = AgentStr("Synvya Inc", "Seller")
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
- # Test phidata inherited capabilities
82
- agent.print_response("Write two sentence poem for the love between the sun and the moon.")
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 full URL where I can find it")
83
96
  ```
84
- 5. Run the code
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/.com/) - For building robust AI agents.
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,90 @@
1
+ AgentStr
2
+ ========
3
+ AgentStr is an extension of [Phidata](https://www.phidata.com) AI agents that allows for agents to communicate with other agents in separate computers using the Nostr communication protocol.
4
+
5
+ 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.
6
+
7
+ The basic communication tools are implemented in `agentstr/nostr.py`.
8
+
9
+ 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.
10
+
11
+ # License
12
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
13
+
14
+ # Current status
15
+ The library is in its infancy.
16
+
17
+ Done:
18
+ - Workflow to package and distribute the library
19
+ - Users can create a Merchant profile and create an agent with the `merchant` toolkit that acts on behalf of the Merchant profile
20
+
21
+
22
+ To be done:
23
+ - Create a `marketplace` with `stalls`
24
+ - Merchants to define `products`
25
+ - Create a `customer` Toolkit
26
+
27
+ # Installation
28
+ AgentStr is offered as a python library available at https://pypi.org/project/agentstr/.
29
+
30
+ Here is an example on how to use the library:
31
+
32
+ 1. Create a new python environment for your app
33
+ ```
34
+ cd ~/
35
+ python3 -m venv ~/.venvs/aienv
36
+ source ~/.venvs/aienv/bin/activate
37
+ ```
38
+ 2. Install the agentstr library
39
+ ```
40
+ pip install --upgrade pip
41
+ pip install agentstr
42
+ mkdir ~/mysampleapp
43
+ cd ~/mysampleapp
44
+ ```
45
+ 3. Create a new python file
46
+ ```
47
+ touch main.py
48
+ ```
49
+ 4. Copy paste this code to the main.py file
50
+ ```
51
+ from dotenv import load_dotenv
52
+ from os import getenv
53
+ from phi.agent import Agent
54
+ from phi.model.openai import OpenAIChat
55
+ from agentstr.marketplace import MerchantProfile, Merchant
56
+
57
+
58
+ profile = MerchantProfile(
59
+ "Synvya",
60
+ "Testing stuff",
61
+ "https://i.nostr.build/ocjZ5GlAKwrvgRhx.png",
62
+ getenv("NSEC_KEY")
63
+ )
64
+
65
+ agent = Agent(
66
+ name="Merchant Assistant",
67
+ model=OpenAIChat(id="gpt-4o"),
68
+ tools=[Merchant(merchant_profile=profile, relay="wss://relay.damus.io")],
69
+ show_tool_calls=True,
70
+ markdown=True,
71
+ debug_mode=True
72
+ )
73
+
74
+ agent.print_response("Publish the merchant information and tell me full URL where I can find it")
75
+ ```
76
+ 5. Export your OpenAI key and optionally a Nostr private key before running the code
77
+ ```
78
+ export OPENAI_API_KEY="sk-***"
79
+ export NSEC_KEY="nsec***"
80
+ python main.py
81
+ ```
82
+
83
+ 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.
84
+
85
+ # Contributing
86
+ Refer to [CONTRIBUTING.md](CONTRIBUTING.md) for specific instructions on installation instructions for developers and how to contribute.
87
+
88
+ # Acknowledgments
89
+ - [Phidata](https://www.phidata.com) - For building robust AI agents.
90
+ - [Rust-Nostr](https://rust-nostr.org/index.html) - For providing a python based Nostr SDK.
@@ -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()
@@ -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.9
3
+ Version: 0.1.7
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: >=3.6
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
- Dynamic: author
22
- Dynamic: home-page
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
- - Create AgentStr as an extension of Phidata Agent
40
- - Test the addition of new properties and capabilities for the AgentStr class
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
- - Incorporate Nostr capabilities
44
- - Create unique public / private key identifiers for agent instances
45
- - Send and retreive messages via Nostr
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/acticate
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 agentstr.core import AgentStr
74
- # Create the agent
75
- agent = AgentStr("Synvya Inc", "Seller")
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
- # Test phidata inherited capabilities
82
- agent.print_response("Write two sentence poem for the love between the sun and the moon.")
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 full URL where I can find it")
83
96
  ```
84
- 5. Run the code
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/.com/) - For building robust AI agents.
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.
@@ -1,9 +1,9 @@
1
1
  LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
- setup.py
5
4
  agentstr/__init__.py
6
- agentstr/core.py
5
+ agentstr/marketplace.py
6
+ agentstr/nostr.py
7
7
  agentstr.egg-info/PKG-INFO
8
8
  agentstr.egg-info/SOURCES.txt
9
9
  agentstr.egg-info/dependency_links.txt
@@ -0,0 +1,4 @@
1
+ phidata>=2.7.0
2
+ openai>=1.50.0
3
+ packaging>=24.0
4
+ nostr-sdk>=0.38.0
@@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta" # Backend used for the build process
4
4
 
5
5
  [project]
6
6
  name = "agentstr"
7
- version = "0.0.9"
7
+ version = "0.1.7"
8
8
  description = "A library for collaborative AI agents"
9
- requires-python = ">=3.6"
9
+ requires-python = ">=3.9, <3.13"
10
10
  readme = "README.md"
11
11
  license = { text = "MIT" }
12
12
  authors = [
@@ -19,7 +19,7 @@ classifiers = [
19
19
  "Operating System :: OS Independent"
20
20
  ]
21
21
  dependencies = [
22
- "phidata>=2.7.0", "openai>=1.50.0"
22
+ "phidata>=2.7.0", "openai>=1.50.0", "packaging>=24.0", "nostr-sdk>=0.38.0"
23
23
  ]
24
24
 
25
25
  [project.urls]
@@ -0,0 +1,79 @@
1
+ import pytest, pytest_asyncio, asyncio
2
+ import logging
3
+ from dotenv import load_dotenv
4
+ from os import getenv
5
+
6
+ from phi.model.openai import OpenAIChat
7
+ from nostr_sdk import Keys, Client, SendEventOutput
8
+
9
+ from agentstr.nostr import NostrClient
10
+ from agentstr.marketplace import MerchantProfile, Merchant
11
+
12
+
13
+ # Clear existing handlers and set up logging again
14
+ for handler in logging.root.handlers[:]:
15
+ logging.root.removeHandler(handler)
16
+
17
+ logging.basicConfig(
18
+ level=logging.INFO, # Adjust to the desired level (e.g., INFO, DEBUG)
19
+ format="%(asctime)s - %(levelname)s - %(message)s", # Log format
20
+ )
21
+
22
+ load_dotenv()
23
+
24
+ def test_create_merchant_profile():
25
+ nsec = getenv("NSEC_KEY")
26
+
27
+ if nsec:
28
+ merchant_profile = MerchantProfile("Synvya Inc",
29
+ "Agentic communications",
30
+ "https://i.nostr.build/ocjZ5GlAKwrvgRhx.png",
31
+ nsec)
32
+ merchant_profile.merchant_profile_to_str()
33
+ assert isinstance(merchant_profile, MerchantProfile)
34
+ del merchant_profile
35
+ else:
36
+ logging.error("NSEC_KEY environment variable not set")
37
+ assert False
38
+ del merchant_profile
39
+
40
+ def test_publish_merchant_profile():
41
+ nsec = getenv("NSEC_KEY")
42
+
43
+ if nsec:
44
+ merchant_profile = MerchantProfile(
45
+ "Synvya Inc",
46
+ "Agentic communications",
47
+ "https://i.nostr.build/ocjZ5GlAKwrvgRhx.png",
48
+ nsec
49
+ )
50
+ merchant = Merchant(merchant_profile, "wss://relay.damus.io")
51
+ eventid = merchant.publish_merchant_profile()
52
+ assert isinstance(eventid, str)
53
+ logging.info(f"Merchant profile published with event id: " + eventid)
54
+ del merchant_profile
55
+ else:
56
+ logging.error("NSEC_KEY environment variable not set")
57
+ assert False
58
+ del merchant_profile
59
+
60
+ @pytest.mark.asyncio
61
+ async def test_async_publish_merchant_profile():
62
+ nsec = getenv("NSEC_KEY")
63
+
64
+ if nsec:
65
+ merchant_profile = MerchantProfile(
66
+ "Synvya Inc",
67
+ "Agentic communications",
68
+ "https://i.nostr.build/ocjZ5GlAKwrvgRhx.png",
69
+ nsec
70
+ )
71
+ merchant = Merchant(merchant_profile, "wss://relay.damus.io")
72
+ eventid = await merchant._async_publish_merchant_profile()
73
+ assert isinstance(eventid, str)
74
+ logging.info(f"Merchant profile published with event id: " + eventid)
75
+ del merchant_profile
76
+ else:
77
+ logging.error("NSEC_KEY environment variable not set")
78
+ assert False
79
+ del merchant_profile
agentstr-0.0.9/README.md DELETED
@@ -1,69 +0,0 @@
1
- AgentStr
2
- ========
3
- AgentStr is an extension of [Phidata](https://www.phidata.com) AI agents that allows for agents to communicate with other agents in separate computers using the Nostr communication protocol.
4
-
5
- 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.
6
-
7
- # License
8
- This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
9
-
10
- # Current status
11
- The library is in its infancy.
12
-
13
- Done:
14
- - Workflow to package and distribute the library
15
- - Create AgentStr as an extension of Phidata Agent
16
- - Test the addition of new properties and capabilities for the AgentStr class
17
-
18
- To be done:
19
- - Incorporate Nostr capabilities
20
- - Create unique public / private key identifiers for agent instances
21
- - Send and retreive messages via Nostr
22
- - Expose capabilities via Nostr
23
- - Agent B retrieves capabilities exposed by Agent A
24
- - Agent B coordinates transaction with Agent A
25
-
26
- # Installation
27
- AgentStr is offered as a python library available at https://pypi.org/project/agentstr/.
28
-
29
- Here is an example on how to use the library:
30
-
31
- 1. Create a new python environment for your app
32
- ```
33
- cd ~/
34
- python3 -m venv ~/.venvs/aienv
35
- source ~/.venvs/aienv/bin/acticate
36
- ```
37
- 2. Install the agentstr library
38
- ```
39
- pip install agentstr
40
- mkdir ~/mysampleapp
41
- cd ~/mysampleapp
42
- ```
43
- 3. Create a new python file
44
- ```
45
- touch main.py
46
- ```
47
- 4. Copy paste this code to the main.py file
48
- ```
49
- from agentstr.core import AgentStr
50
- # Create the agent
51
- agent = AgentStr("Synvya Inc", "Seller")
52
-
53
- # Test AgentStr new capabilities
54
- print(f"Public key: {agent.get_public_key()}\nPrivate key: {agent.get_private_key()}")
55
- print(f"Company: {agent.get_company()}\nRole: {agent.get_role()}")
56
-
57
- # Test phidata inherited capabilities
58
- agent.print_response("Write two sentence poem for the love between the sun and the moon.")
59
- ```
60
- 5. Run the code
61
- ```
62
- python main.py
63
- ```
64
-
65
- # Contributing
66
- Refer to [CONTRIBUTING.md](CONTRIBUTING.md) for specific instructions on installation instructions for developers and how to contribute.
67
-
68
- # Acknowledgments
69
- - [Phidata](https://www.phidata.com/.com/) - For building robust AI agents.
@@ -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
@@ -1,2 +0,0 @@
1
- phidata>=2.7.0
2
- openai>=1.50.0
agentstr-0.0.9/setup.py DELETED
@@ -1,21 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name="agentstr",
5
- version="0.0.9",
6
- author="Alejandro Gil",
7
- description="A library for collaborative AI agents",
8
- long_description=open("README.md").read(),
9
- long_description_content_type="text/markdown",
10
- url="https://github.com/synvya/agentstr",
11
- packages=find_packages(where="."),
12
- install_requires=[
13
- "phidata>=2.7.0", "openai>=1.50.0"
14
- ],
15
- classifiers=[
16
- "Programming Language :: Python :: 3",
17
- "License :: OSI Approved :: MIT License",
18
- "Operating System :: OS Independent",
19
- ],
20
- python_requires=">=3.6",
21
- )
@@ -1,17 +0,0 @@
1
- import unittest
2
- import agentstr
3
-
4
- from agentstr.core import add, AgentStr
5
- from phi.model.openai import OpenAIChat
6
- from dotenv import load_dotenv
7
-
8
- load_dotenv()
9
-
10
- def test_get_public_key():
11
- agent = AgentStr(company="Synvya AI", role="Seller")
12
- public_key = agent.get_public_key()
13
- assert public_key == "npub - Synvya AI - Seller"
14
-
15
- def test_add():
16
- assert add(2, 3) == 5
17
-
File without changes
File without changes
File without changes