Skip to content

Commit 86de0e1

Browse files
Alejandro-MoralesAlejandro Morales
andauthored
feat: update agents (#79)
* feat: update agents deployment * feat: include new files --------- Co-authored-by: Alejandro Morales <alejandromorales@Alejandros-Mac-mini.local>
1 parent 004a5a6 commit 86de0e1

File tree

134 files changed

+26531
-929
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+26531
-929
lines changed

.github/workflows/deploy-agents.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches:
66
- main
77
paths:
8+
- "6-deployed-agents/chained/**"
89
- "6-deployed-agents/finance/**"
910
- "6-deployed-agents/geo/**"
1011
- "6-deployed-agents/knowledge-base/**"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[agent]
2+
address = "agent1qtwk0kzcnqym78rq5fgl6hxua2yessmlgunan27xezk0zr4th7ugkz32ndm"
3+
include = ""
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Asset Signal Agent
2+
3+
![domain:finance](https://img.shields.io/badge/finance-3D8BD3?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOCA2IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNCA0LjVDMS43ODEyNSA0LjUgMCAzLjUgMCAyLjI1QzAgMS4wMTU2MiAxLjc4MTI1IDAgNCAwQzYuMjAzMTIgMCA4IDEuMDE1NjIgOCAyLjI1QzggMy41IDYuMjAzMTIgNC41IDQgNC41Wk0xLjM0Mzc1IDIuODkwNjJDMS41MzEyNSAzLjA2MjUgMS43ODEyNSAzLjIwMzEyIDIuMDQ2ODggMy4yOTY4OEMyLjU2MjUgMy41MTU2MiAzLjI1IDMuNjI1IDQgMy42MjVDNC43MzQzOCAzLjYyNSA1LjQyMTg4IDMuNTE1NjIgNS45NTMxMiAzLjI5Njg4QzYuMjAzMTIgMy4yMDMxMiA2LjQ1MzEyIDMuMDYyNSA2LjY0MDYyIDIuODkwNjJDNi44MjgxMiAyLjcwMzEyIDcgMi40NTMxMiA3IDIuMTI1QzcgMS44MTI1IDYuODI4MTIgMS41NjI1IDYuNjQwNjIgMS4zNzVDNi40NTMxMiAxLjIwMzEyIDYuMjAzMTIgMS4wNjI1IDUuOTUzMTIgMC45NTMxMjVDNS40MjE4OCAwLjc1IDQuNzM0MzggMC42MjUgNCAwLjYyNUMzLjI1IDAuNjI1IDIuNTYyNSAwLjc1IDIuMDQ2ODggMC45NTMxMjVDMS43ODEyNSAxLjA2MjUgMS41MzEyNSAxLjIwMzEyIDEuMzQzNzUgMS4zNzVDMS4xNTYyNSAxLjU2MjUgMSAxLjgxMjUgMSAyLjEyNUMxIDIuNDUzMTIgMS4xNTYyNSAyLjcwMzEyIDEuMzQzNzUgMi44OTA2MlpNMS41IDIuMTI1QzEuNSAxLjU3ODEyIDIuNjA5MzggMS4xMjUgNCAxLjEyNUM1LjM3NSAxLjEyNSA2LjUgMS41NzgxMiA2LjUgMi4xMjVDNi41IDIuNjg3NSA1LjM3NSAzLjEyNSA0IDMuMTI1QzIuNjA5MzggMy4xMjUgMS41IDIuNjg3NSAxLjUgMi4xMjVaTTAgMy41NDY4OEMwLjIwMzEyNSAzLjc4MTI1IDAuNDUzMTI1IDQgMC43NSA0LjE3MTg4VjUuMTcxODhDMC4yNjU2MjUgNC44NDM3NSAwIDQuNDM3NSAwIDRWMy41NDY4OFpNMS4yNSA1LjQ1MzEyVjQuNDUzMTJDMS42ODc1IDQuNjU2MjUgMi4xODc1IDQuODEyNSAyLjc1IDQuOTA2MjVWNS45MDYyNUMyLjE3MTg4IDUuODEyNSAxLjY3MTg4IDUuNjU2MjUgMS4yNSA1LjQ1MzEyWk0zLjI1IDUuOTY4NzVWNC45Njg3NUMzLjQ4NDM4IDUgMy43MzQzOCA1LjAxNTYyIDQgNS4wMTU2MkM0LjI1IDUuMDE1NjIgNC41IDUgNC43NSA0Ljk2ODc1VjUuOTY4NzVDNC41IDYgNC4yNSA2IDQgNkMzLjczNDM4IDYgMy40ODQzOCA2IDMuMjUgNS45Njg3NVpNNS4yNSA1LjkwNjI1VjQuOTA2MjVDNS43OTY4OCA0LjgxMjUgNi4yOTY4OCA0LjY1NjI1IDYuNzUgNC40NTMxMlY1LjQ2ODc1QzYuMzEyNSA1LjY1NjI1IDUuODEyNSA1LjgxMjUgNS4yNSA1LjkwNjI1Wk03LjI1IDUuMTcxODhWNC4xNzE4OEM3LjUzMTI1IDQgNy43ODEyNSAzLjc4MTI1IDggMy41NDY4OFY0QzggNC40Mzc1IDcuNzE4NzUgNC44NDM3NSA3LjI1IDUuMTcxODhaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)
4+
![tech:tech-name](https://img.shields.io/badge/tech%20tag-E85D2E?style=flat&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iOCIgdmlld0JveD0iMCAwIDEwIDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI%2BCjxwYXRoIGQ9Ik00LjUgMUM0LjUgMS4yMTg3NSA0LjQyMTg4IDEuNDIxODggNC4zMTI1IDEuNTc4MTJMNC43NjU2MiAyLjU2MjVDNC45MjE4OCAyLjUzMTI1IDUuMDc4MTIgMi41IDUuMjUgMi41QzUuODEyNSAyLjUgNi4zMjgxMiAyLjcxODc1IDYuNzE4NzUgMy4wNjI1TDggMi4xMDkzOEM4IDIuMDc4MTIgOCAyLjA0Njg4IDggMkM4IDEuNDUzMTIgOC40Mzc1IDEgOSAxQzkuNTQ2ODggMSAxMCAxLjQ1MzEyIDEwIDJDMTAgMi41NjI1IDkuNTQ2ODggMyA5IDNDOC44NDM3NSAzIDguNzE4NzUgMi45ODQzOCA4LjU5Mzc1IDIuOTIxODhMNy4zMTI1IDMuODU5MzhDNy40MjE4OCA0LjE0MDYyIDcuNSA0LjQzNzUgNy41IDQuNzVDNy41IDUgNy40NTMxMiA1LjIzNDM4IDcuMzc1IDUuNDUzMTJMOC41IDYuMTI1QzguNjU2MjUgNi4wNDY4OCA4LjgxMjUgNiA5IDZDOS41NDY4OCA2IDEwIDYuNDUzMTIgMTAgN0MxMCA3LjU2MjUgOS41NDY4OCA4IDkgOEM4LjQzNzUgOCA4IDcuNTYyNSA4IDdWNi45ODQzOEw2Ljg1OTM4IDYuMzEyNUM2LjQ1MzEyIDYuNzM0MzggNS44NzUgNyA1LjI1IDdDNC4xNzE4OCA3IDMuMjgxMjUgNi4yNjU2MiAzLjA0Njg4IDUuMjVIMS44NTkzOEMxLjY4NzUgNS41NjI1IDEuMzU5MzggNS43NSAxIDUuNzVDMC40Mzc1IDUuNzUgMCA1LjMxMjUgMCA0Ljc1QzAgNC4yMDMxMiAwLjQzNzUgMy43NSAxIDMuNzVDMS4zNTkzOCAzLjc1IDEuNjg3NSAzLjk1MzEyIDEuODU5MzggNC4yNUgzLjA0Njg4QzMuMTcxODggMy43MzQzOCAzLjQ1MzEyIDMuMjk2ODggMy44NTkzOCAyLjk4NDM4TDMuNDA2MjUgMkMyLjg5MDYyIDEuOTUzMTIgMi41IDEuNTMxMjUgMi41IDFDMi41IDAuNDUzMTI1IDIuOTM3NSAwIDMuNSAwQzQuMDQ2ODggMCA0LjUgMC40NTMxMjUgNC41IDFaTTUuMjUgNS41QzUuNTE1NjIgNS41IDUuNzUgNS4zNTkzOCA1Ljg5MDYyIDUuMTI1QzYuMDMxMjUgNC45MDYyNSA2LjAzMTI1IDQuNjA5MzggNS44OTA2MiA0LjM3NUM1Ljc1IDQuMTU2MjUgNS41MTU2MiA0IDUuMjUgNEM0Ljk2ODc1IDQgNC43MzQzOCA0LjE1NjI1IDQuNTkzNzUgNC4zNzVDNC40NTMxMiA0LjYwOTM4IDQuNDUzMTIgNC45MDYyNSA0LjU5Mzc1IDUuMTI1QzQuNzM0MzggNS4zNTkzOCA0Ljk2ODc1IDUuNSA1LjI1IDUuNVoiIGZpbGw9IndoaXRlIi8%2BCjwvc3ZnPgo%3D)
5+
[![link to source code](https://img.shields.io/badge/Source%20Code-E8ECF1?style=flat&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSI4IiB2aWV3Qm94PSIwIDAgOCA4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNCAwLjA5ODk5OUMxLjc5IDAuMDk4OTk5IDAgMS44OSAwIDQuMDk5QzAgNS44NjY2NyAxLjE0NiA3LjM2NTY2IDIuNzM1IDcuODk0QzIuOTM1IDcuOTMxNjYgMy4wMDgzMyA3LjgwOCAzLjAwODMzIDcuNzAxNjZDMy4wMDgzMyA3LjYwNjY2IDMuMDA1IDcuMzU1IDMuMDAzMzMgNy4wMjE2N0MxLjg5MDY3IDcuMjYzIDEuNjU2IDYuNDg1IDEuNjU2IDYuNDg1QzEuNDc0IDYuMDIzMzMgMS4yMTEgNS45IDEuMjExIDUuOUMwLjg0ODY2NyA1LjY1MiAxLjIzOSA1LjY1NyAxLjIzOSA1LjY1N0MxLjY0MDY3IDUuNjg1IDEuODUxNjcgNi4wNjkgMS44NTE2NyA2LjA2OUMyLjIwODMzIDYuNjgwNjcgMi43ODggNi41MDQgMy4wMTY2NyA2LjQwMTY2QzMuMDUyNjcgNi4xNDMgMy4xNTU2NyA1Ljk2NjY3IDMuMjcgNS44NjY2N0MyLjM4MTY3IDUuNzY2NjcgMS40NDggNS40MjI2NyAxLjQ0OCAzLjg5QzEuNDQ4IDMuNDUzMzMgMS42MDMgMy4wOTY2NyAxLjg1OTY3IDIuODE2NjdDMS44MTQ2NyAyLjcxNTY3IDEuNjc5NjcgMi4zMDkgMS44OTQ2NyAxLjc1OEMxLjg5NDY3IDEuNzU4IDIuMjI5NjcgMS42NTA2NyAyLjk5NDY3IDIuMTY4QzMuMzE0NjcgMi4wNzkgMy42NTQ2NyAyLjAzNSAzLjk5NDY3IDIuMDMzQzQuMzM0NjcgMi4wMzUgNC42NzQ2NyAyLjA3OSA0Ljk5NDY3IDIuMTY4QzUuNzU0NjcgMS42NTA2NyA2LjA4OTY3IDEuNzU4IDYuMDg5NjcgMS43NThDNi4zMDQ2NyAyLjMwOSA2LjE2OTY3IDIuNzE1NjcgNi4xMjk2NyAyLjgxNjY3QzYuMzg0NjcgMy4wOTY2NyA2LjUzOTY3IDMuNDUzMzMgNi41Mzk2NyAzLjg5QzYuNTM5NjcgNS40MjY2NyA1LjYwNDY3IDUuNzY1IDQuNzE0NjcgNS44NjMzM0M0Ljg1NDY3IDUuOTgzMzMgNC45ODQ2NyA2LjIyODY2IDQuOTg0NjcgNi42MDMzM0M0Ljk4NDY3IDcuMTM4NjYgNC45Nzk2NyA3LjU2ODY3IDQuOTc5NjcgNy42OTg2N0M0Ljk3OTY3IDcuODAzNjcgNS4wNDk2NyA3LjkyODY3IDUuMjU0NjcgNy44ODg2N0M2Ljg1NSA3LjM2NCA4IDUuODY0IDggNC4wOTlDOCAxLjg5IDYuMjA5IDAuMDk4OTk5IDQgMC4wOTg5OTlaIiBmaWxsPSIjNTU2NTc4Ii8%2BCjwvc3ZnPgo%3D)](...)
6+
7+
**DISCLAIMER: THE RESULTS FROM THIS AGENT ARE NOT CONSIDERED FINANCIAL ADVICE.**
8+
9+
This agent will generate a context from information from other agents (as seen in the diagram below) to give you a general signal about a financial asset of a company.
10+
The return value contains a list of urls as sources that were factored into the final result.
11+
12+
## Diagram
13+
14+
```mermaid
15+
sequenceDiagram
16+
actor User
17+
participant A as Asset Signal Agent
18+
participant B as Company Ticker<br/>Resolver Agent
19+
participant C as Financial News<br/>Sentiment Agent
20+
participant D as Finbert Agent
21+
participant E as Stock Price Agent
22+
23+
activate User
24+
User->>A: Request Asset Signal
25+
activate A
26+
A->>B: Resolve Ticker from<br/>Company Name
27+
activate B
28+
B->>A: Return Company Ticker
29+
deactivate B
30+
A->>C: Get Financial News<br/>Sentiment from Ticker
31+
activate C
32+
C->>A: Return news overview
33+
deactivate C
34+
A->>D: Request Finbert model<br/> inference based on news
35+
activate D
36+
D->>A: Return Sentiment
37+
deactivate D
38+
A->>E: Get current stock price
39+
activate E
40+
E->>A: Return Price
41+
deactivate E
42+
A->>User: "Respond with signal<br/>and current price"
43+
deactivate A
44+
```
45+
46+
## Example input
47+
48+
```python
49+
AssetSignalRequest(
50+
company_name="Apple"
51+
)
52+
```
53+
54+
## Example output
55+
56+
```python
57+
AssetSignalResponse(
58+
signal="WAIT",
59+
price=230.28,
60+
sources={
61+
...
62+
},
63+
)
64+
```
65+
66+
## Usage Example
67+
68+
Copy and paste the following code into a new [Blank agent](https://agentverse.ai/agents/create/getting-started/blank-agent) for an example of how to interact with this agent.
69+
70+
```python
71+
from typing import Literal, Set
72+
73+
from uagents import Agent, Context, Model
74+
75+
76+
77+
class AssetSignalRequest(Model):
78+
company_name: str
79+
80+
81+
class AssetSignalResponse(Model):
82+
signal: Literal["BUY", "SELL", "WAIT"]
83+
price: float
84+
sources: Set[str]
85+
86+
87+
agent = Agent()
88+
89+
ASSET_SIGNAL_ADDRESS = "<deployed_agent_address>"
90+
91+
prompt = AssetSignalRequest(company_name="Apple")
92+
93+
94+
@agent.on_event("startup")
95+
async def handle_startup(ctx: Context):
96+
"""Send the prompt to the AI agent on startup."""
97+
await ctx.send(ASSET_SIGNAL_ADDRESS, prompt)
98+
ctx.logger.info(f"Sent prompt to AI agent: {prompt}")
99+
100+
101+
@agent.on_message(AssetSignalResponse)
102+
async def handle_response(ctx: Context, sender: str, msg: AssetSignalResponse):
103+
"""Do something with the response."""
104+
ctx.logger.info(f"Received response from: {sender}:\nSignal:{msg.signal} at price: {msg.price}")
105+
106+
107+
if __name__ == "__main__":
108+
agent.run()
109+
```
110+
111+
### Local Agent
112+
113+
1. Install the necessary packages:
114+
115+
```bash
116+
pip install uagents <and_whatever_else_is_needed>
117+
```
118+
119+
2. To interact with this agent from a local agent instead, replace `agent = Agent()` in the above with:
120+
121+
```python
122+
agent = Agent(
123+
name="user",
124+
endpoint="http://localhost:8000/submit",
125+
)
126+
```
127+
128+
3. Run the agent:
129+
```bash
130+
python agent.py
131+
```
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import os
2+
from enum import Enum
3+
4+
from models import (
5+
AssetSignalRequest,
6+
AssetSignalResponse,
7+
FinancialNewsSentimentRequest,
8+
FinancialNewsSentimentResponse,
9+
FinancialSentimentRequest,
10+
FinancialSentimentResponse,
11+
NewsSentiment,
12+
StockPriceRequest,
13+
StockPriceResponse,
14+
TickerRequest,
15+
TickerResponse,
16+
)
17+
from uagents import Agent, Context, Model
18+
from uagents.experimental.chat_agent import ChatAgent
19+
from uagents.experimental.quota import QuotaProtocol, RateLimit
20+
from uagents_core.models import ErrorMessage
21+
22+
COMPANY_TICKER_RESOLVER_AGENT = os.getenv("company-ticker-resolver-agent")
23+
FINANCIAL_NEWS_SENTIMENT_AGENT = os.getenv("financial-news-sentiment-agent")
24+
FINBERT_FINANCIAL_SENTIMENT_AGENT = os.getenv("finbert-financial-sentiment-agent")
25+
STOCK_PRICE_AGENT = os.getenv("stock-price-agent")
26+
27+
AGENT_SEED = os.getenv("AGENT_SEED", "<your-agent-seed>")
28+
AGENT_NAME = os.getenv("AGENT_NAME", "Asset Signal Agent")
29+
30+
31+
PORT = 8000
32+
agent = ChatAgent(
33+
name=AGENT_NAME,
34+
seed=AGENT_SEED,
35+
port=PORT,
36+
endpoint=f"http://localhost:{PORT}/submit",
37+
)
38+
39+
40+
proto = QuotaProtocol(
41+
storage_reference=agent.storage,
42+
name="Company-Asset-Signal",
43+
version="0.1.0",
44+
)
45+
46+
def generate_sentiment_overview(summary: list[NewsSentiment]) -> dict[str, int]:
47+
sentiments = [news.model_dump()["overall_sentiment_label"] for news in summary]
48+
count = len(sentiments)
49+
output = {
50+
"Bearish": 0,
51+
"Somewhat-Bearish": 0,
52+
"Neutral": 0,
53+
"Somewhat-Bullish": 0,
54+
"Bullish": 0,
55+
}
56+
for s in sentiments:
57+
output[s] += 1
58+
for key in output:
59+
output[key] = output[key] / count
60+
converted_output = {
61+
"positive": output["Somewhat-Bullish"] / 2 + output["Bullish"],
62+
"neutral": output["Neutral"]
63+
+ output["Somewhat-Bullish"] / 2
64+
+ output["Somewhat-Bearish"] / 2,
65+
"negative": output["Somewhat-Bearish"] / 2 + output["Bearish"],
66+
}
67+
return converted_output
68+
69+
70+
@proto.on_message(
71+
AssetSignalRequest,
72+
replies={AssetSignalResponse, ErrorMessage},
73+
rate_limit=RateLimit(window_size_minutes=60, max_requests=3),
74+
)
75+
async def handle_request(ctx: Context, sender: str, msg: AssetSignalRequest):
76+
if not COMPANY_TICKER_RESOLVER_AGENT:
77+
ctx.logger.info("COMPANY_TICKER_RESOLVER_AGENT is not set")
78+
return
79+
if not FINANCIAL_NEWS_SENTIMENT_AGENT:
80+
ctx.logger.info("FINANCIAL_NEWS_SENTIMENT_AGENT is not set")
81+
return
82+
if not FINBERT_FINANCIAL_SENTIMENT_AGENT:
83+
ctx.logger.info("FINBERT_FINANCIAL_SENTIMENT_AGENT is not set")
84+
return
85+
if not STOCK_PRICE_AGENT:
86+
ctx.logger.info("STOCK_PRICE_AGENT is not set")
87+
return
88+
89+
ticker_reply, ticker_status = await ctx.send_and_receive(
90+
COMPANY_TICKER_RESOLVER_AGENT,
91+
TickerRequest(company=msg.company_name),
92+
response_type=TickerResponse,
93+
)
94+
if not isinstance(ticker_reply, TickerResponse):
95+
await ctx.send(sender, ErrorMessage(error=f"Ticker resolver failed: {ticker_status}"))
96+
return
97+
ticker = ticker_reply.ticker
98+
99+
news_reply, news_status = await ctx.send_and_receive(
100+
FINANCIAL_NEWS_SENTIMENT_AGENT,
101+
FinancialNewsSentimentRequest(ticker=ticker),
102+
response_type=FinancialNewsSentimentResponse,
103+
)
104+
if not isinstance(news_reply, FinancialNewsSentimentResponse):
105+
await ctx.send(sender, ErrorMessage(error=f"News sentiment failed: {news_status}"))
106+
return
107+
if not news_reply.summary:
108+
await ctx.send(sender, ErrorMessage(error="News sentiment returned empty summary"))
109+
return
110+
111+
sentiment_summary = generate_sentiment_overview(news_reply.summary)
112+
113+
finbert_reply, finbert_status = await ctx.send_and_receive(
114+
FINBERT_FINANCIAL_SENTIMENT_AGENT,
115+
FinancialSentimentRequest(text="\n".join([a.title for a in news_reply.summary[:10]])),
116+
response_type=FinancialSentimentResponse,
117+
)
118+
if not isinstance(finbert_reply, FinancialSentimentResponse):
119+
await ctx.send(sender, ErrorMessage(error=f"FinBERT failed: {finbert_status}"))
120+
return
121+
122+
s2 = finbert_reply.model_dump()
123+
combined = {
124+
"BUY": sentiment_summary["positive"] + s2["positive"],
125+
"WAIT": sentiment_summary["neutral"] + s2["neutral"],
126+
"SELL": sentiment_summary["negative"] + s2["negative"],
127+
}
128+
129+
price_reply, price_status = await ctx.send_and_receive(
130+
STOCK_PRICE_AGENT,
131+
StockPriceRequest(ticker=ticker),
132+
response_type=StockPriceResponse,
133+
)
134+
if not isinstance(price_reply, StockPriceResponse):
135+
await ctx.send(sender, ErrorMessage(error=f"Stock price failed: {price_status}"))
136+
return
137+
138+
try:
139+
price = float(price_reply.text)
140+
except Exception:
141+
await ctx.send(sender, ErrorMessage(error=f"Invalid price payload: {getattr(price_reply, 'text', None)!r}"))
142+
return
143+
144+
signal = max(combined, key=combined.get)
145+
146+
sources = sorted({news.url for news in news_reply.summary if getattr(news, "url", None)})
147+
148+
await ctx.send(
149+
sender,
150+
AssetSignalResponse(
151+
signal=signal,
152+
price=price,
153+
sources=sources,
154+
),
155+
)
156+
157+
158+
agent.include(proto, publish_manifest=True)
159+
160+
161+
# Health Check code
162+
class HealthCheck(Model):
163+
pass
164+
165+
166+
class HealthStatus(str, Enum):
167+
HEALTHY = "healthy"
168+
UNHEALTHY = "unhealthy"
169+
170+
171+
class AgentHealth(Model):
172+
agent_name: str
173+
status: HealthStatus
174+
175+
176+
health_protocol = QuotaProtocol(
177+
storage_reference=agent.storage, name="HealthProtocol", version="0.1.0"
178+
)
179+
180+
181+
@health_protocol.on_message(HealthCheck, replies={AgentHealth})
182+
async def handle_health_check(ctx: Context, sender: str, msg: HealthCheck):
183+
await ctx.send(
184+
sender, AgentHealth(agent_name=AGENT_NAME, status=HealthStatus.HEALTHY)
185+
)
186+
187+
188+
agent.include(health_protocol, publish_manifest=True)
189+
190+
if __name__ == "__main__":
191+
agent.run()
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from typing import List, Literal, Set
2+
3+
from uagents import Model
4+
5+
6+
class AssetSignalRequest(Model):
7+
company_name: str
8+
9+
10+
class AssetSignalResponse(Model):
11+
signal: Literal["BUY", "SELL", "WAIT"]
12+
price: float
13+
sources: Set[str]
14+
15+
16+
# Ticker Resolver Agent
17+
class TickerRequest(Model):
18+
company: str
19+
20+
21+
class TickerResponse(Model):
22+
ticker: str
23+
24+
25+
# Financial News Sentiment Agent
26+
class FinancialNewsSentimentRequest(Model):
27+
ticker: str
28+
29+
30+
class NewsSentiment(Model):
31+
title: str
32+
url: str
33+
summary: str
34+
overall_sentiment_label: str
35+
36+
37+
class FinancialNewsSentimentResponse(Model):
38+
summary: List[NewsSentiment]
39+
40+
41+
# Finbert Financial Sentiment Agent
42+
class FinancialSentimentRequest(Model):
43+
text: str
44+
45+
46+
class FinancialSentimentResponse(Model):
47+
positive: float
48+
neutral: float
49+
negative: float
50+
51+
52+
# Stock Price Agent
53+
class StockPriceRequest(Model):
54+
ticker: str
55+
56+
57+
class StockPriceResponse(Model):
58+
text: str

0 commit comments

Comments
 (0)