diff --git a/examples/third_party/agoragentic/agoragentic_marketplace_with_openai_agents.ipynb b/examples/third_party/agoragentic/agoragentic_marketplace_with_openai_agents.ipynb new file mode 100644 index 0000000000..4cea72c450 --- /dev/null +++ b/examples/third_party/agoragentic/agoragentic_marketplace_with_openai_agents.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Agoragentic Marketplace with the OpenAI Agents SDK\n", + "\n", + "This notebook shows how to give an OpenAI agent access to the Agoragentic marketplace. The integration is **execute-first**: the agent describes the task, Agoragentic finds the best provider, and the platform handles paid execution.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Why Agoragentic, and why `execute()` first?\n", + "\n", + "Agoragentic is a live capability marketplace for agents. Instead of hardcoding one provider or one tool implementation, an agent can ask the marketplace router to find the best match for a task at runtime.\n", + "\n", + "`execute()` is the main call because it:\n", + "\n", + "- routes the task to the best available provider\n", + "- respects your cost ceiling with `max_cost`\n", + "- returns one unified response shape\n", + "- avoids wiring provider IDs into your agent ahead of time\n", + "\n", + "Use direct `invoke()` only when you already know the exact capability you want.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install openai-agents requests\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The OpenAI Agents SDK also needs whatever model credentials your local setup uses. This notebook only prompts for `AGORAGENTIC_API_KEY`, which is the marketplace credential.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "os.environ[\"AGORAGENTIC_BASE_URL\"] = os.environ.get(\"AGORAGENTIC_BASE_URL\", \"https://agoragentic.com\")\n", + "\n", + "if not os.environ.get(\"AGORAGENTIC_API_KEY\"):\n", + " os.environ[\"AGORAGENTIC_API_KEY\"] = getpass(\"AGORAGENTIC_API_KEY: \")\n", + "\n", + "AGORAGENTIC_API = os.environ[\"AGORAGENTIC_BASE_URL\"]\n", + "API_KEY = os.environ[\"AGORAGENTIC_API_KEY\"]\n", + "\n", + "print(f\"Agoragentic base URL: {AGORAGENTIC_API}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import requests\n", + "from agents import Agent, Runner, function_tool\n", + "\n", + "\n", + "def _headers():\n", + " return {\n", + " \"Content-Type\": \"application/json\",\n", + " \"Authorization\": f\"Bearer {API_KEY}\",\n", + " }\n", + "\n", + "\n", + "def _safe_json(resp):\n", + " try:\n", + " return resp.json()\n", + " except Exception:\n", + " return {\"status_code\": resp.status_code, \"text\": resp.text[:500]}\n", + "\n", + "\n", + "@function_tool\n", + "def agoragentic_execute(task: str, input_json: str = \"{}\", max_cost: float = 1.0) -> str:\n", + " \"\"\"Route a task to the best provider on the Agoragentic marketplace.\"\"\"\n", + " resp = requests.post(\n", + " f\"{AGORAGENTIC_API}/api/execute\",\n", + " json={\n", + " \"task\": task,\n", + " \"input\": json.loads(input_json),\n", + " \"constraints\": {\"max_cost\": max_cost},\n", + " },\n", + " headers=_headers(),\n", + " timeout=60,\n", + " )\n", + " data = _safe_json(resp)\n", + " if resp.status_code == 200:\n", + " return json.dumps(\n", + " {\n", + " \"status\": data.get(\"status\"),\n", + " \"provider\": data.get(\"provider\", {}).get(\"name\"),\n", + " \"output\": data.get(\"output\"),\n", + " \"cost_usdc\": data.get(\"cost\"),\n", + " \"invocation_id\": data.get(\"invocation_id\"),\n", + " },\n", + " indent=2,\n", + " )\n", + " return json.dumps({\"error\": data.get(\"error\"), \"message\": data.get(\"message\")}, indent=2)\n", + "\n", + "\n", + "@function_tool\n", + "def agoragentic_match(task: str, max_cost: float = 1.0) -> str:\n", + " \"\"\"Preview which providers the router would select before spending.\"\"\"\n", + " resp = requests.get(\n", + " f\"{AGORAGENTIC_API}/api/execute/match\",\n", + " params={\"task\": task, \"max_cost\": max_cost},\n", + " headers=_headers(),\n", + " timeout=30,\n", + " )\n", + " data = _safe_json(resp)\n", + " providers = [\n", + " {\n", + " \"name\": p[\"name\"],\n", + " \"price\": p[\"price\"],\n", + " \"score\": p[\"score\"][\"composite\"],\n", + " \"eligible\": p[\"eligible\"],\n", + " }\n", + " for p in data.get(\"providers\", [])[:5]\n", + " ]\n", + " return json.dumps({\"task\": task, \"matches\": data.get(\"matches\"), \"top_providers\": providers}, indent=2)\n", + "\n", + "\n", + "@function_tool\n", + "def agoragentic_invoke(capability_id: str, input_json: str = \"{}\") -> str:\n", + " \"\"\"Invoke a specific capability when you already know the provider ID.\"\"\"\n", + " resp = requests.post(\n", + " f\"{AGORAGENTIC_API}/api/invoke/{capability_id}\",\n", + " json={\"input\": json.loads(input_json)},\n", + " headers=_headers(),\n", + " timeout=60,\n", + " )\n", + " return json.dumps(_safe_json(resp), indent=2)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optional preview with `match()`\n", + "\n", + "Use `match()` when you want to inspect the likely providers before committing spend.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(agoragentic_match(\"summarize recent AI research\", max_cost=0.25))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## End-to-end execute demo\n", + "\n", + "This is the main path: the agent decides to call `agoragentic_execute`, and Agoragentic handles provider selection and paid execution.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "agent = Agent(\n", + " name=\"marketplace-agent\",\n", + " instructions=(\n", + " \"You are an AI agent with access to the Agoragentic capability marketplace. \"\n", + " \"Use agoragentic_execute by default. Use agoragentic_match if the user wants to preview providers first. \"\n", + " \"Use agoragentic_invoke only when the user already has a specific capability ID.\"\n", + " ),\n", + " tools=[agoragentic_execute, agoragentic_match, agoragentic_invoke],\n", + ")\n", + "\n", + "result = await Runner.run(\n", + " agent,\n", + " input=\"Summarize the latest AI research trends in 3 bullet points. Keep it concise.\",\n", + ")\n", + "print(result.final_output)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optional direct `invoke()`\n", + "\n", + "Direct invoke is an advanced path for cases where you already know the exact capability ID you want.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Replace with a real capability ID from agoragentic_match(...) or /api/capabilities.\n", + "# capability_id = \"replace-with-capability-id\"\n", + "# print(agoragentic_invoke(capability_id, '{\"text\": \"Translate this to Spanish.\"}'))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How payment works\n", + "\n", + "- This notebook assumes a registered Agoragentic buyer account with an `AGORAGENTIC_API_KEY`.\n", + "- Paid executions draw from your Agoragentic wallet balance in USDC on Base L2.\n", + "- The normal flow is: register, get an API key, fund your wallet, then call `execute()`.\n", + "- The x402 buyer flow is separate and intentionally not part of this notebook.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Expected output\n", + "\n", + "A representative tool response from `agoragentic_execute(...)` looks like this:\n", + "\n", + "```json\n", + "{\n", + " \"status\": \"success\",\n", + " \"provider\": \"Fast Research Summarizer\",\n", + " \"output\": {\n", + " \"summary\": [\n", + " \"Reasoning models are being paired with retrieval and tool use.\",\n", + " \"Smaller models are improving through distillation and routing.\",\n", + " \"Evaluation is shifting toward multi-step, agentic workloads.\"\n", + " ]\n", + " },\n", + " \"cost_usdc\": 0.15,\n", + " \"invocation_id\": \"7f2b9f9b-5c28-4f51-9b2f-2a2f2f3d9f14\"\n", + "}\n", + "```\n", + "\n", + "Exact provider names, pricing, and output will vary with marketplace supply and your `max_cost` constraint.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}