Skip to content

Add AI Crypto Price Alert Agent#22

Open
ChiragTankan wants to merge 1 commit into
fetchai:mainfrom
ChiragTankan:main
Open

Add AI Crypto Price Alert Agent#22
ChiragTankan wants to merge 1 commit into
fetchai:mainfrom
ChiragTankan:main

Conversation

@ChiragTankan
Copy link
Copy Markdown

Summary

Describe what this PR changes.

Type of Change

  • New agent example
  • Bug fix
  • Documentation update
  • Refactor / cleanup
  • Other

Checklist

  • I have starred this repository.
  • I ran ruff check ..
  • I ran ruff format ..
  • I added/updated README.md for changed example(s).
  • I added .env.example if environment variables are required.
  • I added demo image/GIF (if applicable).
  • I added agent profile link (if applicable).
  • I updated CHANGELOG.md (required for non-doc changes).
  • I verified paths/commands used in docs.

Related Issue

Link issue number(s), if any:

Notes for Reviewers

This agent is a great entry-level example for users learning how to integrate external APIs (CoinGecko) with the uAgents framework. It focuses on the on_interval decorator and basic logging.


def get_price(coin_id):
url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
response = requests.get(url)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The asynchronous check_price function uses a blocking requests.get() call without a timeout, which will freeze the agent and make it unresponsive during the API request.
Severity: CRITICAL

Suggested Fix

Replace the synchronous requests.get() call with an asynchronous HTTP client library like aiohttp. Alternatively, if requests must be used, wrap the blocking call in asyncio.to_thread() to run it in a separate thread without blocking the main event loop. In either case, a reasonable timeout should be added to all network requests to prevent indefinite hangs.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: Crypto-Price-Alert-Agent/agent.py#L14

Potential issue: The `check_price` function is an asynchronous interval handler that
uses the synchronous `requests.get()` library to make an HTTP call. This is a blocking
I/O operation that will freeze the agent's entire asyncio event loop while it waits for
the network response. During this time, the agent will be unable to process any other
tasks, such as incoming messages or other scheduled intervals. Furthermore, the
`requests.get()` call does not have a `timeout` parameter, creating a risk that the
agent could hang indefinitely if the external API is slow or unresponsive, causing it to
miss subsequent checks.

Did we get this right? 👍 / 👎 to inform future reviews.

@gautammanak1 gautammanak1 self-requested a review May 4, 2026 11:41
@gautammanak1
Copy link
Copy Markdown
Collaborator

Review: Add AI Crypto Price Alert Agent

Summary

This PR adds a new example agent that monitors cryptocurrency prices via the CoinGecko API and logs alerts when Bitcoin drops below a configurable threshold. The agent uses the @agent.on_interval decorator to poll every 60 seconds. This is a clean, beginner-friendly example that demonstrates external API integration with uAgents.

Overall risk: Low — This is an example agent with no external dependencies beyond requests, and it doesn't handle sensitive data or perform on-chain operations.


What I liked

  • Clear, well-commented code structure with numbered sections explaining the setup
  • Good use of the @agent.on_interval decorator for a simple polling pattern
  • Proper error handling with a try/except block around the external API call
  • The example is genuinely useful for learning — it shows how to bridge external APIs with uAgents without overcomplicating things

Security

Hardcoded seed phrase (blocking for production, acceptable for example)

Crypto-Price-Alert-Agent/agent.py:7 — The agent seed is hardcoded as a literal string:

crypto_agent = Agent(name="crypto_watcher", seed="Cripto_Watcher_24")

Why this matters: The seed deterministically generates the agent's address and its on-chain wallet. Anyone with the seed can impersonate the agent and drain any FET associated with that address.

For an example: This is acceptable as-is, but I'd recommend adding a comment explaining this should come from an environment variable in production:

# Replace "your_seed_phrase" with any random text
# In production, load from os.environ["AGENT_SEED_PHRASE"]
crypto_agent = Agent(name="crypto_watcher", seed="Cripto_Watcher_24")

Correctness & logic

Missing HTTP error handling

Crypto-Price-Alert-Agent/agent.py:15 — The get_price function doesn't check the HTTP response status before parsing JSON:

def get_price(coin_id):
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
    response = requests.get(url)
    data = response.json()  # Will raise if status != 200
    return data[coin_id]['usd']

If CoinGecko returns a 429 (rate limit), 500, or other error, response.json() may fail or return an error envelope. This will be caught by the outer try/except, but the error message won't distinguish between network issues and API errors.

Suggested fix:

def get_price(coin_id):
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
    response = requests.get(url)
    response.raise_for_status()  # Raise HTTPError for bad responses
    data = response.json()
    return data[coin_id]['usd']

Potential KeyError on malformed response

Crypto-Price-Alert-Agent/agent.py:17 — If the API response doesn't contain the expected structure (e.g., data[coin_id] is missing or usd key is absent), this will raise a KeyError. The outer try/except catches it, but the error message is generic.

Suggested fix:

def get_price(coin_id):
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
    response = requests.get(url)
    response.raise_for_status()
    data = response.json()
    
    if coin_id not in data or 'usd' not in data[coin_id]:
        raise ValueError(f"Unexpected API response structure: {data}")
    
    return data[coin_id]['usd']

Performance

Blocking HTTP call in async handler

Crypto-Price-Alert-Agent/agent.py:20 — The get_price function uses synchronous requests.get() inside an async handler. This blocks the entire event loop while waiting for the CoinGecko API response.

Why this matters: For a simple example with one agent and one interval, this is fine. But if this pattern were scaled (multiple agents, concurrent message handling), blocking calls would stall all other work.

Suggested fix (for production patterns):

import aiohttp

async def get_price(coin_id):
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            response.raise_for_status()
            data = await response.json()
            if coin_id not in data or 'usd' not in data[coin_id]:
                raise ValueError(f"Unexpected API response structure: {data}")
            return data[coin_id]['usd']

For this example, the synchronous approach is acceptable — but a comment explaining the tradeoff would be helpful for learners.


Code quality

Missing .env.example

The PR checklist indicates .env.example was not added. Even though this example doesn't currently use environment variables, adding one would:

  1. Document the expected configuration pattern
  2. Make it easy for users to migrate the seed to an env variable
  3. Follow the repo's conventions

Suggested .env.example:

# Agent seed phrase (generate your own random string)
# AGENT_SEED_PHRASE="your_random_seed_here"

# CoinGecko API configuration
# CRYPTO_ID=bitcoin
# THRESHOLD_PRICE=60000

Typo in seed comment

Crypto-Price-Alert-Agent/agent.py:6 — The comment says "Replace your_seed_phrase" but the actual seed is Cripto_Watcher_24. Minor, but could confuse beginners copying the pattern.


Tests

No tests were added. For an example agent, this is acceptable, but a simple test would demonstrate:

  • Mocking the CoinGecko API response
  • Verifying the alert logic triggers at the threshold
  • Testing error handling paths

If you'd like to add tests, a test_agent.py file mirroring the repo's test layout would be great.


Suggested fixes (priority order)

  1. Add HTTP error handling in get_price — use response.raise_for_status()
  2. Add a comment explaining the seed should come from an environment variable in production
  3. Consider adding .env.example to document configuration options
  4. Optional: Add a note about async HTTP for production patterns

Questions for the author

  • Was the decision to use synchronous requests intentional to keep the example simple, or would you like me to show an async version?
  • Are you planning to add a README.md for this example? The checklist mentions it was added, but I don't see it in the diff.

Conclusion

This is a solid, well-structured example that achieves its goal of teaching external API integration with uAgents. The code is clean and readable. The main improvements would be around HTTP error handling and documenting production best practices (env variables, async I/O). Nothing blocking for an example — ship it, but consider the suggested enhancements.

# 1. Define your Agent
# Replace "your_seed_phrase" with any random text
crypto_agent = Agent(name="crypto_watcher", seed="Cripto_Watcher_24")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Replace "your_seed_phrase" with any random text
# In production, load from os.environ["AGENT_SEED_PHRASE"]
crypto_agent = Agent(name="crypto_watcher", seed="Cripto_Watcher_24")

def get_price(coin_id):
url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
response = requests.get(url)
data = response.json()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data = response.json()
def get_price(coin_id):
url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
response = requests.get(url)
response.raise_for_status() # Raise HTTPError for bad responses
data = response.json()
return data[coin_id]['usd']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants