Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this repository are documented in this file.
## [Unreleased]

### Added
- `pharmacy-locator-agent/`: Beginner-friendly uAgent combining ASI:One location extraction with the free OpenStreetMap Overpass API
- `Browser-based-agents/playwright/job-application-agent/`: Playwright + ASI:One + Stripe job application agent. Orchestrates a Chromium session to auto-fill Greenhouse application forms using a stored user profile, with LLM-drafted free-text answers via ASI:One, Stripe-gated premium features, and resume ingestion.
- GSSoC '26 label system: [.github/labels/gssoc-labels.json](.github/labels/gssoc-labels.json) definitions, [.github/scripts/create-gssoc-labels.sh](.github/scripts/create-gssoc-labels.sh) bootstrap script, `gssoc-label-bootstrap` workflow (auto-create/update labels), `gssoc-label-sync` workflow (copy `gssoc26`/`level1-3` labels from linked issues to PRs for dashboard tracking), and [docs/GSSOC.md](docs/GSSOC.md) guide
- `langchain-agents/deep-agents/hackflow-agent/`: LangChain Deep Agents hackathon intelligence agent for ASI:One. Three-subagent research pipeline (event_finder, sponsor_researcher, winner_researcher), Stripe-gated full analysis, ASI:One primary LLM with fallbacks, Tavily web search, and persisted cross-turn follow-up memory.
Expand All @@ -16,23 +17,20 @@ All notable changes to this repository are documented in this file.
- CI gates: `contributor-path-check`, `changelog-check`, and `review-required` (no merge without approval when branch protection is enabled)
- Issue templates: contributor good-first tasks and real-time agent challenge
- `.github/BRANCH_PROTECTION.md` maintainer setup for required reviews and status checks

### Changed
- `community_agent/` moved to `contributors/community_agent/` — all new community agents must use `contributors/<agent-name>/`
- `CONTRIBUTING.md`, `README.md`, `ISSUES_GUIDE.md`, and PR template updated for contributor folder workflow
- `security-scanner-agent/`: LLM-powered code security analysis agent that scans code snippets via ASI:One and returns structured vulnerability reports (type, severity, line number, description, suggested fix). Built on a multi-agent Bureau using the standard Agent Chat Protocol; ASI:One-compatible and discoverable on Agentverse.
- `ticketlens-agent/`: Live real-time travel discovery AI agent powered by TicketLens MCP. High-precision reasoning utilizing the ASI1 LLM, persistent `uAgents` storage, and directly actionable booking deep links.
- `openclaw/`: OpenClaw examples — `fetchai-openclaw-orchestrator` (connector + orchestrator, repo health analyzer) and `agentverse-caller` (OpenClaw skill to search and message Agentverse agents)
- `stripe-payment-agents/youtube-growth-analyzer-agent`: Multi-agent YouTube channel analyzer with free preview and Stripe-gated premium report flow, built for Agentverse/ASI:One chat + payment protocols
- `openai-agent-sdk/Appliance Auto Whisperer`: Multi-agent right-to-repair system — Gemini Vision (via OpenAI SDK) identifies broken parts from photos, Bright Data scrapes prices from 6+ retailers, YouTube Data API finds repair tutorials. Orchestrator coordinates workers via REST fan-out with Docker Compose support.

### Changed
- `openai-agent-sdk/Appliance Auto Whisperer`: Multi-agent right-to-repair assistant for ASI:One with orchestrator + parts/tutorial workers, streamlined bureau-first architecture, and updated README demo screenshots

- `google-adk/google-trends-agent`: Fetch.ai uAgent that answers natural-language Google Trends questions with per-query Stripe payment gating, using ASI:One LLM for BigQuery SQL generation and result interpretation

- `stripe-payment-agents/conversational-property-finder`: ASI1 conversational property search agent (Repliers MLS, optional Stripe details paywall, OpenAI/regex parsing)
- `ag2-agents/` — Two AG2 (formerly AutoGen) multi-agent examples: a payment approval workflow and a research synthesis team, both integrated with uAgents via the A2A protocol
- `community_agent/` — AI Community Growth Agent for planning events, conferences, and hackathons
- `community_agent/` moved to `contributors/community_agent/` — all new community agents must use `contributors/<agent-name>/`
- `CONTRIBUTING.md`, `README.md`, `ISSUES_GUIDE.md`, and PR template updated for contributor folder workflow
- `security-scanner-agent/`: LLM-powered code security analysis agent that scans code snippets via ASI:One and returns structured vulnerability reports (type, severity, line number, description, suggested fix). Built on a multi-agent Bureau using the standard Agent Chat Protocol; ASI:One-compatible and discoverable on Agentverse.
- `CONTRIBUTING.md` with agent-focused contribution workflow and merge policy
- Pull request CI workflow with checks for `stargazer-gate`, `lint`, `format`, `typecheck`, `validate-architecture`, and `test`
- `.github/CODEOWNERS` for required reviewer routing
Expand All @@ -48,9 +46,5 @@ All notable changes to this repository are documented in this file.
- Missing `requirements.txt` for `community_agent`, `av-script-example`, `asi1-llm-example`, `advance-agent-examples/{search,policy,basic}_agent`
- Missing `.env.example` for `community_agent`, `duffel-agent`, `deploy-agent-on-av`, `asi-cloud-agent`, `pdf-summariser-example`, `flight-tracker-openai-workflow-agent`, `google-genai-parallel-processing/brand-management-agent`, `Rag-agent/ango`, `asi1-llm-example`
- Missing `README.md` for `duffel-agent`, `deploy-agent-on-av`


### Changed

- `README.md` rewritten with project overview, quickstart guide, categorized examples index table, folder structure, Docker instructions, and resource links
- `CONTRIBUTING.md` expanded with setup script reference, tagging/categorization guidance, Docker support section, and issue flow references
3 changes: 3 additions & 0 deletions pharmacy-locator-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API Key for the ASI:One LLM
# Get your key from: https://asi1.ai/
ASI_ONE_API_KEY=your_asi1_api_key_here
64 changes: 64 additions & 0 deletions pharmacy-locator-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Pharmacy Locator Agent

- **Category:** `Getting Started`, `Integration`
- **Difficulty:** Beginner

A beginner-friendly uAgent that helps users find nearby pharmacies. It uses the [ASI:One LLM](https://asi1.ai/) to parse natural language location queries and connects to the free [OpenStreetMap Overpass API](https://overpass-api.de/) to fetch real-world data.

## Prerequisites

- Python 3.10+
- An API key for [ASI:One](https://asi1.ai/) (to parse user intent/locations).

> **Note:** The OpenStreetMap Overpass API is completely free and public, requiring no API key.

## Installation

Navigate to the agent directory and install dependencies:

```bash
cd pharmacy-locator-agent
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
```

Set up your environment variables:

```bash
cp .env.example .env
```

Edit the `.env` file and add your `ASI_ONE_API_KEY`.

## Running the Agent

Start the agent:

```bash
python agent.py
```

The agent will print its address in the console.

## Expected Output

You can interact with the agent via the Agentverse chat interface or a local chat script.

**User:** `Find me a pharmacy near London`

**Agent:**
```
Searching for pharmacies in **London**... 🔍

Here are 5 pharmacies I found in London:

1. **Boots**
📍 Address: Oxford Street London
📞 Phone: +44 20 1234 5678
🕒 Hours: Mo-Su 08:00-22:00

...

*Data provided by OpenStreetMap (Overpass API)*
```
228 changes: 228 additions & 0 deletions pharmacy-locator-agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
"""
Pharmacy Locator Agent

A uAgent that helps users find nearby pharmacies using the ASI:One LLM
to parse location queries and the free OpenStreetMap Overpass API to fetch data.
"""

from __future__ import annotations

import os
import asyncio
from datetime import datetime, timezone
from uuid import uuid4

# Python 3.13 compatibility: Create an event loop if one doesn't exist
try:
asyncio.get_running_loop()
except RuntimeError:
asyncio.set_event_loop(asyncio.new_event_loop())

import httpx
from dotenv import load_dotenv
from uagents import Agent, Context, Protocol


load_dotenv()

from uagents_core.contrib.protocols.chat import (
ChatAcknowledgement,
ChatMessage,
TextContent,
chat_protocol_spec,
)

ASI_ONE_API_KEY = (os.getenv("ASI_ONE_API_KEY") or "").strip()


def _call_asi1_extract_location(user_text: str) -> str:
"""Use ASI:One to extract just the city/neighborhood name from the user query."""
if not ASI_ONE_API_KEY:
raise RuntimeError(
"ASI_ONE_API_KEY is not set. Please add it to your .env file."
)

system_prompt = (
"You are a helpful geographic assistant. "
"Extract ONLY the city or neighborhood name from the user's request. "
"Do not include any extra words, punctuation, or explanations. "
"If no location is found, output exactly: UNKNOWN"
)

payload = {
"model": "asi1",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_text},
],
"temperature": 0.1,
"max_tokens": 50,
}

headers = {
"Authorization": f"Bearer {ASI_ONE_API_KEY}",
"Content-Type": "application/json",
}

resp = httpx.post(
"https://api.asi1.ai/v1/chat/completions",
json=payload,
headers=headers,
timeout=30.0,
)
resp.raise_for_status()

data = resp.json()
choices = data.get("choices", [])
if not choices:
raise RuntimeError("No response from ASI:One")

location = choices[0]["message"]["content"].strip()
return location


def _fetch_pharmacies_from_overpass(location: str) -> list[dict]:
"""Fetch pharmacies using the OpenStreetMap Overpass API."""
overpass_url = "http://overpass-api.de/api/interpreter"

# Overpass QL to find pharmacies in a specific named area
query = f"""
[out:json];
area[name="{location}"]->.searchArea;
node["amenity"="pharmacy"](area.searchArea);
out 5;
"""

headers = {"User-Agent": "PharmacyLocatorAgent/1.0 (Fetch.ai)", "Accept": "*/*"}
resp = httpx.post(overpass_url, data={"data": query}, headers=headers, timeout=30.0)
resp.raise_for_status()

data = resp.json()
elements = data.get("elements", [])

results = []
for el in elements:
tags = el.get("tags", {})
name = tags.get("name", "Unnamed Pharmacy")
address = tags.get("addr:street", "") + " " + tags.get("addr:city", "")
phone = tags.get("phone", "No phone listed")
opening_hours = tags.get("opening_hours", "Hours not specified")

results.append(
{
"name": name,
"address": address.strip() or "Address not specified",
"phone": phone,
"opening_hours": opening_hours,
}
)

return results


chat_proto = Protocol(spec=chat_protocol_spec)


@chat_proto.on_message(ChatMessage)
async def on_chat(ctx: Context, sender: str, msg: ChatMessage):
# Acknowledge the message immediately
await ctx.send(
sender,
ChatAcknowledgement(
timestamp=datetime.now(timezone.utc),
acknowledged_msg_id=msg.msg_id,
),
)

# Extract user text
parts = [
item.text for item in msg.content if isinstance(item, TextContent) and item.text
]
user_text = "\n".join(parts).strip()

if not user_text:
welcome = (
"Hi! I'm the Pharmacy Locator Agent 🏥\n\n"
"Tell me where you are, and I'll find nearby pharmacies for you.\n"
"Example: 'Find a pharmacy in London' or 'Need meds near Brooklyn'"
)
await _send_reply(ctx, sender, welcome)
return

try:
# Step 1: Use LLM to extract the location from natural language
location = _call_asi1_extract_location(user_text)
ctx.logger.info(f"Extracted location: {location}")

if location == "UNKNOWN":
await _send_reply(
ctx,
sender,
"I couldn't figure out the location from your message. Please specify a city or neighborhood!",
)
return

await _send_reply(
ctx, sender, f"Searching for pharmacies in **{location}**... 🔍"
)

# Step 2: Query the Overpass API
pharmacies = _fetch_pharmacies_from_overpass(location)

if not pharmacies:
await _send_reply(
ctx,
sender,
f"Sorry, I couldn't find any pharmacies listed in OpenStreetMap for {location}.",
)
return

# Step 3: Format the response
response_text = (
f"Here are {len(pharmacies)} pharmacies I found in {location}:\n\n"
)
for i, p in enumerate(pharmacies, 1):
response_text += f"{i}. **{p['name']}**\n"
response_text += f" 📍 Address: {p['address']}\n"
response_text += f" 📞 Phone: {p['phone']}\n"
response_text += f" 🕒 Hours: {p['opening_hours']}\n\n"

response_text += "\n*Data provided by OpenStreetMap (Overpass API)*"

await _send_reply(ctx, sender, response_text.strip())

except Exception as e:
ctx.logger.exception("Agent encountered an error")
await _send_reply(ctx, sender, f"Sorry, I encountered an error: {str(e)[:200]}")


async def _send_reply(ctx: Context, sender: str, text: str):
await ctx.send(
sender,
ChatMessage(
timestamp=datetime.now(timezone.utc),
msg_id=uuid4(),
content=[TextContent(type="text", text=text)],
),
)


@chat_proto.on_message(ChatAcknowledgement)
async def on_ack(ctx: Context, sender: str, msg: ChatAcknowledgement):
ctx.logger.info(f"ACK received from {sender}")


agent = Agent(
name="pharmacy-locator-agent", seed="random_seed_for_pharmacy_locator_agent_123"
)
agent.include(chat_proto, publish_manifest=True)


@agent.on_event("startup")
async def on_startup(ctx: Context):
ctx.logger.info(f"Pharmacy Locator Agent started -> {agent.address}")
ctx.logger.info(f"ASI:One API key present: {bool(ASI_ONE_API_KEY)}")


if __name__ == "__main__":
agent.run()
4 changes: 4 additions & 0 deletions pharmacy-locator-agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
httpx>=0.27.0
uagents>=0.24.0
python-dotenv>=1.0.0

Loading
Loading