Wrap Loop's REST API as @function_tool decorators and drop them into any gpt-4o or o3 agent. The SDK auto-generates JSON schemas from your type hints and docstrings — no manual tool definitions needed.
pip install openai-agents requests. Set OPENAI_API_KEY in your env. No Loop key required in the free tier (30 reads/min).Define all four Loop operations as @function_tool functions, pass them to Agent(tools=[...]), and let the model decide when to call each one.
import asyncio import requests from agents import Agent, Runner, function_tool BASE = "https://api.stayinloop.dev/v1" @function_tool def search_loop(query: str, location: str = "Kreuzberg, Berlin") -> list: """Search for local businesses using Loop. Args: query: Natural language description, e.g. "vegan outdoor seating". location: Area hint, default is Kreuzberg, Berlin. """ return requests.get( f"{BASE}/search", params={"q": query, "location": location}, ).json()["results"] @function_tool def get_loop_details(result_id: str) -> dict: """Get full details and a result_token for a Loop result. Args: result_id: The result_id from a search() result. """ return requests.get(f"{BASE}/details/{result_id}").json() @function_tool def verify_loop(result_id: str, claim: str) -> dict: """Verify a specific claim about a business live. Args: result_id: The result_id from a search() result. claim: What to check, e.g. "open tonight" or "has outdoor seating". """ return requests.get( f"{BASE}/verify/{result_id}", params={"claim": claim}, ).json() @function_tool def report_loop(result_token: str, outcome: str) -> dict: """Report what happened after acting on a result. Mutates the record's confidence. Args: result_token: The token returned by get_loop_details(). outcome: One of: correct, wrong, booked, closed, other. """ return requests.post( f"{BASE}/report", json={"result_token": result_token, "outcome": outcome}, ).json() agent = Agent( name="Loop agent", instructions=( "You help users find local businesses in Kreuzberg, Berlin. " "Always call search_loop first, then get_loop_details for the chosen result. " "Call verify_loop before making a definitive claim. " "Call report_loop with the outcome when the task is done." ), tools=[search_loop, get_loop_details, verify_loop, report_loop], ) async def main(): result = await Runner.run( agent, "Find a quiet vegan restaurant with outdoor seating for tonight.", ) print(result.final_output) asyncio.run(main())
Async @function_tool functions work natively with the SDK. Use asyncio.gather to fan out get_details and verify in one round-trip.
import asyncio import httpx from agents import Agent, Runner, function_tool BASE = "https://api.stayinloop.dev/v1" @function_tool async def search_loop_async(query: str, location: str = "Kreuzberg, Berlin") -> list: """Search for local businesses. Async version for high-throughput agents. Args: query: Natural language search query. location: Area hint. """ async with httpx.AsyncClient() as client: r = await client.get( f"{BASE}/search", params={"q": query, "location": location}, ) return r.json()["results"] @function_tool async def get_and_verify(result_id: str, claim: str) -> dict: """Get details and verify a claim in parallel. Args: result_id: The result_id from a search result. claim: What to verify, e.g. "open now". """ async with httpx.AsyncClient() as client: details, obs = await asyncio.gather( client.get(f"{BASE}/details/{result_id}"), client.get(f"{BASE}/verify/{result_id}", params={"claim": claim}), ) return {**details.json(), "observation": obs.json()} agent = Agent( name="Loop async agent", instructions="Find businesses and verify claims using Loop. Always call get_and_verify.", tools=[search_loop_async, get_and_verify], ) async def main(): result = await Runner.run(agent, "Is Burgermeister in Kreuzberg open right now?") print(result.final_output) asyncio.run(main())
@function_tool approach is the recommended path. ChatGPT guide →