diff --git a/02-samples/16-ai-ads-generation-agent-with-crypto-payments/.env.example b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/.env.example new file mode 100644 index 00000000..a3235647 --- /dev/null +++ b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/.env.example @@ -0,0 +1,11 @@ +CDP_API_KEY_ID="" +CDP_API_KEY_SECRET="" +CDP_WALLET_SECRET="" +ADDRESS="" +OPENWEATHER_API_KEY="" +# If not working in an already configured AWS environment, provide values for the following +# AWS_BEARER_TOKEN_BEDROCK="" +# OR +# AWS_ACCESS_KEY_ID="" +# AWS_SECRET_ACCESS_KEY="" +# AWS_REGION="" diff --git a/02-samples/16-ai-ads-generation-agent-with-crypto-payments/README.md b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/README.md new file mode 100644 index 00000000..d8bfbdd9 --- /dev/null +++ b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/README.md @@ -0,0 +1,132 @@ +# Autonomous AI Advertising Agent with Crypto Payments + +An AI agent that creates complete advertising campaigns while autonomously paying for premium services using cryptocurrency via the X402 payment protocol. + +## Overview + +### Sample Details + +| Information | Details | +|------------------------|------------------------------------------------------------| +| **Agent Architecture** | Single-agent | +| **Native Tools** | image_reader | +| **Custom Tools** | list_available_services, get_service_schema, create_ad_html | +| **MCP Servers** | None | +| **Use Case Vertical** | Marketing & Advertising | +| **Complexity** | Advanced | +| **Model Provider** | Amazon Bedrock (Claude Sonnet 4) | +| **SDK Used** | Strands Agents SDK + Coinbase AgentKit | + +### Architecture + +The sample demonstrates integration between multiple systems: +- **Strands AI Framework** → Agent reasoning and tool orchestration +- **Coinbase AgentKit** → Blockchain wallet and transaction management +- **X402 Protocol** → HTTP-based micropayment standard for API access +- **External APIs** → Payment-gated image generation and weather services + +### Key Features + +- **Economic Agency**: AI agent manages its own budget and purchases services autonomously +- **Crypto-Native Payments**: Uses USDC on Base Sepolia testnet for service payments +- **Multi-Service Integration**: Combines weather data and AI image generation for enhanced campaigns +- **Complete Campaign Generation**: Produces ready-to-deploy HTML advertising assets + +## Prerequisites + +- Python **3.10+** +- [uv](https://docs.astral.sh/uv/getting-started/installation/) for dependency management +- [AWS CLI configured with appropriate credentials](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html) +- [Model access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access-modify.html) enabled for Claude Sonnet 4 +- [Coinbase Developer Platform account](https://docs.cdp.coinbase.com/get-started/quickstart) (testnet) +- [OpenWeather API key](https://openweathermap.org/guide) +- **⚠️ TESTNET ONLY**: Base Sepolia testnet wallet with test USDC + +## Setup + +1. **Configure environment variables:** + ```bash + cp .env.example .env + # Edit .env with your configuration: + # - CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET (Coinbase testnet) + # - ADDRESS (Base Sepolia testnet receiving address) + # - OPENWEATHER_API_KEY + ``` + +2. **Install dependencies:** + ```bash + uv pip install requirements.txt + ``` + +3. **Start the payment server:** + ```bash + uv run paid_server.py + ``` + +## Usage + +**Run the advertising agent:** + +**Execute the `agentkit-x402-strands` notebook:** +1. Open the notebook and run cells sequentially +2. The agent will automatically: + - Discover available services + - Make cryptocurrency payments for premium APIs + - Generate weather-responsive ad campaigns + - Create visual assets using AI image generation + - Output complete HTML advertising campaigns + +**Example interaction:** +```python +response = advertising_agent("""Generate an ad for: + product="ice cream shop promotion", + city="Miami,US", + platform="social-media" +""") +``` + +## Example Output + +The agent produces: +- Weather-responsive ad copy based on real-time conditions +- AI-generated tropical imagery for campaigns +- Complete HTML files with embedded visuals +- Multi-platform advertising assets (social media, display, email) + +## Troubleshooting + +| Symptom | Likely Cause | Fix | +|---------|-------------|-----| +| Payment failures | Insufficient testnet USDC | Fund wallet via Base Sepolia faucet | +| API key errors | Missing environment variables | Verify all required keys in `.env` | +| Image generation fails | Payment server not running | Start `paid_server.py` first | + +## Safety Notice + +**⚠️ TESTNET ONLY - DO NOT USE REAL FUNDS** +- This sample uses Base Sepolia testnet exclusively +- Only use test credentials and testnet tokens +- Never run with production wallets or mainnet addresses +- Educational demonstration purposes only + +## Cleanup + +Stop the payment server: +```bash +# Press Ctrl+C to stop paid_server.py +``` + +No additional infrastructure cleanup required. + +--- + +## Disclaimer + +This sample is provided for educational and demonstration purposes only. It is not intended for production use without further development, testing, and hardening. + +For production deployments, consider: +- Implementing appropriate content filtering and safety measures +- Following security best practices for cryptocurrency handling +- Conducting thorough testing on testnets before any mainnet deployment +- Reviewing and adjusting payment amounts and security configurations +- Implementing proper wallet management and key security practices diff --git a/02-samples/16-ai-ads-generation-agent-with-crypto-payments/agentkit-x402-strands.ipynb b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/agentkit-x402-strands.ipynb new file mode 100644 index 00000000..4647b253 --- /dev/null +++ b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/agentkit-x402-strands.ipynb @@ -0,0 +1,853 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "71dea1ea-719b-4411-9d01-ee3b3e9c29fd", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "!pip install -r requirements.txt" + ] + }, + { + "cell_type": "markdown", + "id": "5d884b1d", + "metadata": {}, + "source": [ + "Tested successfully on Amazon Sagemaker AI studio JupyterLab `ml.m5.xlarge` using the `sagemaker-distribution-image`" + ] + }, + { + "cell_type": "markdown", + "id": "9158de98-10c2-4cb4-a815-ca70998aa86e", + "metadata": {}, + "source": [ + "# Autonomous AI Advertising Agent with Crypto Payments\n", + "\n", + "## ⚠️ **SAFETY WARNINGS - READ BEFORE PROCEEDING**\n", + "\n", + "### 🚨 **TESTNET ONLY - DO NOT USE REAL FUNDS**\n", + "- **This notebook uses BASE SEPOLIA TESTNET** - never use mainnet\n", + "- **Use only TEST TOKENS** - do not fund with real cryptocurrency\n", + "- **Wallet credentials are for development only** - never use production keys\n", + "- **Educational demonstration** - not intended for production use\n", + "\n", + "### 🔒 **Security Best Practices**\n", + "- ✅ Use separate test credentials and API keys\n", + "- ✅ Verify you're on Base Sepolia testnet (not mainnet)\n", + "- ✅ Only use testnet USDC tokens (no real value)\n", + "- ❌ Never expose real wallet private keys\n", + "- ❌ Never run this code with production credentials\n", + "- ❌ Never use mainnet addresses or real cryptocurrency\n", + "\n", + "---\n", + "## Overview\n", + "\n", + "This notebook demonstrates how to build an **autonomous AI advertising agent** that can create complete marketing campaigns while automatically paying for premium services using cryptocurrency. By combining cutting-edge AI agent frameworks with blockchain technology, we create a system that operates independently in the digital economy.\n", + "\n", + "## What This Notebook Demonstrates\n", + "\n", + "### 🤖 **Autonomous Agent Architecture**\n", + "- Built using the **Strands AI framework** with Claude Sonnet 4\n", + "- Integrated with **Coinbase AgentKit** for blockchain functionality\n", + "- Capable of making independent decisions and executing complex workflows\n", + "\n", + "### 💳 **Crypto-Native Payments**\n", + "- **X402 Payment Protocol**: Automatic micropayments for API services\n", + "- **Base Sepolia Network**: EVM-compatible blockchain transactions\n", + "- **USDC Payments**: Stable currency for predictable service costs\n", + "- **Autonomous Wallet Management**: No human intervention required\n", + "\n", + "### 🎨 **Premium Service Integration**\n", + "- **AI Image Generation**: Creates custom visuals for ad campaigns\n", + "- **Weather Data APIs**: Enables location and season-based targeting\n", + "- **Payment-Gated Access**: Demonstrates real economic interactions\n", + "\n", + "### 📊 **Complete Campaign Creation**\n", + "- **Multi-Platform Ads**: Social media, display, email, and print formats\n", + "- **Dynamic Content**: Adapts messaging based on real-time data\n", + "- **Visual Integration**: Embeds generated images into campaign materials\n", + "- **HTML Output**: Produces ready-to-deploy advertising assets\n", + "\n", + "## Key Innovation: Economic Agency\n", + "\n", + "This agent represents a new paradigm where AI systems can:\n", + "- 🏦 **Manage their own budgets** for operational expenses\n", + "- 🛒 **Purchase services** needed to complete tasks\n", + "- 🔄 **Optimize spending** based on campaign requirements\n", + "- 📈 **Scale operations** without human financial oversight\n", + "\n", + "## Real-World Applications\n", + "\n", + "- **Marketing Agencies**: Automated campaign generation and optimization\n", + "- **E-commerce**: Dynamic product advertising with seasonal adaptations\n", + "- **Local Businesses**: Location-based campaigns with weather integration\n", + "- **Content Creators**: Automated visual and copy generation workflows\n", + "\n", + "## Technical Architecture\n", + "\n", + "The notebook showcases integration between:\n", + "- **Strands AI Framework** → Agent reasoning and tool orchestration\n", + "- **Coinbase AgentKit** → Blockchain wallet and transaction management\n", + "- **X402 Protocol** → HTTP-based micropayment standard\n", + "- **External APIs** → Premium image generation and weather services\n", + "\n", + "---\n", + "\n", + "**Run through this notebook to see how autonomous agents can operate as independent economic actors in the digital advertising ecosystem!**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18f201c8-3862-46d3-9fbf-e52ce16b4deb", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:02:32.851048Z", + "iopub.status.busy": "2025-10-07T04:02:32.850701Z", + "iopub.status.idle": "2025-10-07T04:02:35.230054Z", + "shell.execute_reply": "2025-10-07T04:02:35.229149Z", + "shell.execute_reply.started": "2025-10-07T04:02:32.851026Z" + } + }, + "outputs": [], + "source": [ + "import json\n", + "import sys\n", + "import time\n", + "import os\n", + "import botocore.exceptions\n", + "from coinbase_agentkit import (\n", + " AgentKit,\n", + " AgentKitConfig,\n", + " CdpEvmWalletProvider,\n", + " CdpEvmWalletProviderConfig,\n", + " cdp_api_action_provider,\n", + " wallet_action_provider,\n", + " x402_action_provider\n", + ")\n", + "\n", + "from typing import Dict, Any, Optional, List\n", + "from strands import Agent, tool\n", + "from strands.models import BedrockModel\n", + "from strands_tools import image_reader\n", + "import base64\n", + "from pathlib import Path\n", + "from coinbase_agentkit_strands_agents import get_strands_tools\n", + "from strands.tools import normalize_tool_spec\n", + "from dotenv import load_dotenv" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffdb6025", + "metadata": {}, + "outputs": [], + "source": [ + "# Load environment variables\n", + "load_dotenv()" + ] + }, + { + "cell_type": "markdown", + "id": "797214cd-9d15-4730-895b-308aa66a2211", + "metadata": {}, + "source": [ + "# Wallet Provider and AgentKit Setup\n", + "\n", + "This cell initializes the core blockchain functionality for our advertising agent:\n", + "\n", + "## Wallet Provider Configuration\n", + "- **CdpEvmWalletProvider**: Creates an EVM-compatible wallet for blockchain transactions\n", + "- **Credentials**: Loaded securely from environment variables (CDP API keys and wallet secret)\n", + "- **Network**: Defaults to Base Sepolia testnet for development\n", + "\n", + "## AgentKit Initialization\n", + "The AgentKit combines multiple action providers:\n", + "- **CDP API Provider**: Direct blockchain API interactions\n", + "- **Wallet Provider**: Transaction signing and wallet operations \n", + "- **X402 Provider**: HTTP payment protocol for accessing paid APIs\n", + "\n", + "This setup enables our agent to:\n", + "- 💰 Make cryptocurrency payments for premium services\n", + "- 🔗 Interact with blockchain networks\n", + "- 🌐 Access payment-gated APIs using the X402 protocol\n", + "- 📝 Manage wallet transactions autonomously" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f9d3cf93-f028-407a-b06c-189d6fa88656", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:02:45.945718Z", + "iopub.status.busy": "2025-10-07T04:02:45.945180Z", + "iopub.status.idle": "2025-10-07T04:02:46.158084Z", + "shell.execute_reply": "2025-10-07T04:02:46.157213Z", + "shell.execute_reply.started": "2025-10-07T04:02:45.945688Z" + } + }, + "outputs": [], + "source": [ + "# Initialize the wallet provider with the config\n", + "wallet_provider = CdpEvmWalletProvider(\n", + " CdpEvmWalletProviderConfig(\n", + " api_key_id=os.getenv(\"CDP_API_KEY_ID\"), # CDP API Key ID\n", + " api_key_secret=os.getenv(\"CDP_API_KEY_SECRET\"), # CDP API Key Secret\n", + " wallet_secret=os.getenv(\"CDP_WALLET_SECRET\"), # CDP Wallet Secret\n", + " # network_id=config.network_id, # Network ID - Optional, will default to 'base-sepolia'\n", + " # address=config.address, # Wallet Address - Optional, will trigger idempotency flow if not provided\n", + " # idempotency_key=config.idempotency_key, # Idempotency Key - Optional, seeds generation of a new wallet\n", + " )\n", + " )\n", + "\n", + "\n", + "# Create AgentKit instance with wallet and action providers\n", + "agentkit = AgentKit(\n", + " AgentKitConfig(\n", + " wallet_provider=wallet_provider,\n", + " action_providers=[\n", + " cdp_api_action_provider(),\n", + " wallet_action_provider(),\n", + " x402_action_provider()\n", + " ],\n", + " )\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "3edf6235-3782-4c7c-bdac-8575c9c217ea", + "metadata": {}, + "source": [ + "# Service Discovery System and Custom Tools\n", + "\n", + "This cell creates a service catalog and custom tools for external API integration:\n", + "\n", + "## Service Catalog\n", + "Defines available external services, that matches the paid service endpoints, with complete schemas:\n", + "\n", + "### 🎨 Media Creation Service\n", + "- **Purpose**: AI image generation for ad visuals\n", + "- **Cost**: Payment required via X402 protocol\n", + "- **Input**: Text prompts describing desired images\n", + "- **Output**: Generated image URLs/paths\n", + "\n", + "### 🌤️ Weather Service \n", + "- **Purpose**: Real-time weather data for location-based campaigns\n", + "- **Cost**: Payment required via X402 protocol\n", + "- **Input**: City name and unit preferences\n", + "- **Output**: Current weather conditions and forecasts\n", + "\n", + "## Custom Agent Tools\n", + "\n", + "### `@tool list_available_services()`\n", + "- Lists all available external services\n", + "- Helps agent discover capabilities dynamically\n", + "\n", + "### `@tool get_service_schema(service_name)`\n", + "- Returns detailed API schema for specific services\n", + "- Enables proper request formatting\n", + "\n", + "### `@tool create_ad_html(ad_html_content, file_name, output_path)`\n", + "- Generates HTML files containing complete ad campaigns\n", + "- Embeds images and formats content for web display\n", + "- Creates organized file structure for campaign assets\n", + "\n", + "These tools enable intelligent service discovery and seamless integration with payment-gated APIs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa9d62d9-b696-4644-bc04-64d2d41247aa", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:02:47.404726Z", + "iopub.status.busy": "2025-10-07T04:02:47.404433Z", + "iopub.status.idle": "2025-10-07T04:02:47.424913Z", + "shell.execute_reply": "2025-10-07T04:02:47.424041Z", + "shell.execute_reply.started": "2025-10-07T04:02:47.404703Z" + } + }, + "outputs": [], + "source": [ + "# Configuration\n", + "HOST = os.getenv(\"HOST\", \"127.0.0.1\")\n", + "PORT = int(os.getenv(\"PORT\", 4021))\n", + "BASE_URL = os.getenv(\"BASE_URL\", f\"http://{HOST}:{PORT}\")\n", + "\n", + "# Service Discovery Functions\n", + "def external_service_catalog(service_name: str) -> Optional[Dict[str, Any]]:\n", + " \"\"\"\n", + " Returns service endpoint information including schemas and URLs.\n", + "\n", + " Args:\n", + " service_name: Name of the service to query\n", + "\n", + " Returns:\n", + " Dictionary containing service metadata, schemas, and endpoint URL\n", + " \"\"\"\n", + " catalog = {\n", + " \"media-creation\": {\n", + " \"name\": \"Image Generator\",\n", + " \"description\": \"Generate images based on text prompts using AI. Perfect for creating ad visuals, product shots, and marketing materials.\",\n", + " \"url\": f\"{BASE_URL}/image_generator\",\n", + " \"method\": \"POST\",\n", + " \"payment_required\": True,\n", + " \"input_schema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"query\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The prompt describing what images to generate\",\n", + " \"example\": \"Generate 3 images of a friendly dragon reading a book\",\n", + " \"minLength\": 1,\n", + " \"maxLength\": 500\n", + " }\n", + " },\n", + " \"required\": [\"query\"]\n", + " }\n", + " },\n", + "\n", + " \"weather\": {\n", + " \"name\": \"Weather Information\",\n", + " \"description\": \"Get current weather information for any city. Useful for location-based or seasonal ad campaigns.\",\n", + " \"url\": f\"{BASE_URL}/weather\",\n", + " \"method\": \"POST\",\n", + " \"payment_required\": True,\n", + " \"input_schema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"City name (e.g., 'London' or 'London,UK')\",\n", + " \"example\": \"London,UK\"\n", + " },\n", + " \"units\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"Units: 'metric', 'imperial', or 'standard'\",\n", + " \"default\": \"metric\"\n", + " }\n", + " },\n", + " \"required\": [\"city\"]\n", + " }\n", + " }\n", + " }\n", + "\n", + " return catalog.get(service_name)\n", + "\n", + "\n", + "# Custom Tools for the Agent\n", + "@tool\n", + "def list_available_services() -> str:\n", + " \"\"\"\n", + " List all available external services that can be used for ad creation.\n", + " Returns information about available endpoints including weather data and image generation.\n", + " Use this when you need to know what external services are available for your ad campaign.\n", + " \"\"\"\n", + " services = {\n", + " \"media-creation\": external_service_catalog(\"media-creation\"),\n", + " \"weather\": external_service_catalog(\"weather\")\n", + " }\n", + "\n", + " result = \"Available Services for Content Creation:\\n\\n\"\n", + "\n", + " for service_name, service_info in services.items():\n", + " if service_info:\n", + " result += f\"Service: {service_info['name']}\\n\"\n", + " result += f\" Description: {service_info['description']}\\n\"\n", + " return result\n", + "\n", + "\n", + "@tool\n", + "def get_service_schema(service_name: str) -> str:\n", + " \"\"\"\n", + " Get detailed schema information and URL endpoint for a specific service.\n", + "\n", + " Args:\n", + " service_name: Name of the service ('media-creation' or 'weather')\n", + "\n", + " Returns:\n", + " Detailed schema information including input requirements\n", + " \"\"\"\n", + " service = external_service_catalog(service_name)\n", + "\n", + " if not service:\n", + " return f\"Service '{service_name}' not found. Available services: 'media-creation', 'weather'\"\n", + "\n", + " result = f\"Service: {service['name']}\\n\"\n", + " result += f\"Description: {service['description']}\\n\\n\"\n", + " result += f\"Endpoint: {service['method']} {service['url']}\\n\\n\"\n", + " result += f\"Input Schema:\\n{json.dumps(service['input_schema'], indent=2)}\\n\"\n", + " \n", + " return result\n", + "\n", + "\n", + "@tool\n", + "def create_ad_html(\n", + " ad_html_content: str,\n", + " file_name: str,\n", + " output_path: str = \"ad_campaign\",\n", + ") -> str:\n", + " \"\"\"\n", + " Create an HTML file displaying the ad campaign.\n", + "\n", + " Args:\n", + " ad_html_content: Html data containing ad content including generated images (if used) with html syntax used in creating the html file\n", + " file_name: name of the html file including the .html extension\n", + " output_path: Path where HTML file will be saved\n", + "\n", + " Returns:\n", + " Path to the created HTML file\n", + " \"\"\"\n", + " # Write to file\n", + " output_file = Path(f\"{output_path}/{file_name}\")\n", + " output_file.parent.mkdir(parents=True, exist_ok=True)\n", + "\n", + " with open(output_file, 'w', encoding='utf-8') as f:\n", + " f.write(ad_html_content)\n", + "\n", + " return f\"HTML file saved to {str(output_file.absolute())}\"\n" + ] + }, + { + "cell_type": "markdown", + "id": "1f08f288-72ce-4711-9040-f28a4d8a03d7", + "metadata": {}, + "source": [ + "# Tool Schema Modification for X402 Payment Protocol\n", + "\n", + "This cell modifies tool schemas to ensure compatibility with HTTP payment protocols:\n", + "\n", + "## Schema Modification Function\n", + "The `modify_tool_schema()` function updates tool parameter types:\n", + "- **Target Field**: Changes 'headers' parameter from 'string' to 'object' type\n", + "- **Normalization**: Ensures schemas comply with Strands tool specifications\n", + "\n", + "## Tools Modified\n", + "- `x402ActionProvider_retry_with_x402`\n", + "- `x402ActionProvider_make_http_request` \n", + "- `x402ActionProvider_make_http_request_with_x402`\n", + "\n", + "## Why This Matters\n", + "X402 payment protocol requires properly formatted HTTP headers as objects rather than strings. This modification ensures our agent can:\n", + "- ✅ Successfully make payment-gated API requests\n", + "- ✅ Pass authentication headers correctly\n", + "- ✅ Handle retry logic for payment failures\n", + "- ✅ Integrate seamlessly with paid external services\n", + "\n", + "Without this modification, payment requests would fail due to schema mismatches." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e1fd71cd-f193-4ed5-8ee1-cde02080f9c9", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:02:49.579109Z", + "iopub.status.busy": "2025-10-07T04:02:49.578325Z", + "iopub.status.idle": "2025-10-07T04:02:49.602255Z", + "shell.execute_reply": "2025-10-07T04:02:49.601551Z", + "shell.execute_reply.started": "2025-10-07T04:02:49.579075Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Modifying schema of x402ActionProvider_make_http_request\n", + "Modifying schema of x402ActionProvider_make_http_request_with_x402\n", + "Modifying schema of x402ActionProvider_retry_with_x402\n" + ] + } + ], + "source": [ + "def modify_tool_schema(tool_spec, field_name, new_field_type, new_description=None):\n", + " \"\"\"Modify a specific field type in a tool's schema\"\"\"\n", + " modified_spec = tool_spec.copy()\n", + " \n", + " # Navigate to the field in inputSchema\n", + " if \"inputSchema\" in modified_spec and \"json\" in modified_spec[\"inputSchema\"]:\n", + " schema = modified_spec[\"inputSchema\"][\"json\"]\n", + " if \"properties\" in schema and field_name in schema[\"properties\"]:\n", + " # Modify the field type\n", + " schema[\"properties\"][field_name][\"type\"] = new_field_type\n", + " \n", + " # Optionally modify description\n", + " if new_description:\n", + " schema[\"properties\"][field_name][\"description\"] = new_description\n", + " \n", + " # Normalize the modified schema\n", + " return normalize_tool_spec(modified_spec)\n", + "\n", + "# Load AgentKit actions as Strands tools\n", + "tool_list = get_strands_tools(agentkit)\n", + "\n", + "# List of tools to modify their schema to match the expected action schema\n", + "tool_to_modify = [\"x402ActionProvider_retry_with_x402\", \"x402ActionProvider_make_http_request\", \"x402ActionProvider_make_http_request_with_x402\"]\n", + "\n", + "modified_tools = []\n", + "for tool in tool_list:\n", + " tool_spec = tool.tool_spec\n", + " \n", + " # Modify specific field - change 'config' from 'string' to 'object'\n", + " if tool.tool_name in tool_to_modify:\n", + " print(f\"Modifying schema of {tool.tool_name}\")\n", + " modified_spec = modify_tool_schema(\n", + " tool_spec, \n", + " field_name=\"headers\",\n", + " new_field_type=\"object\",\n", + " )\n", + " # Update the tool's spec\n", + " tool._tool_spec = modified_spec\n", + " \n", + " modified_tools.append(tool)" + ] + }, + { + "cell_type": "markdown", + "id": "137bd9ab-7077-4b1f-b564-13f51da8da00", + "metadata": {}, + "source": [ + "# Advertising Agent Configuration\n", + "\n", + "This cell sets up our specialized advertising agent with comprehensive capabilities:\n", + "\n", + "## Model Configuration (Optional)\n", + "The commented BedrockModel shows advanced configuration options:\n", + "- **Claude Sonnet 4**: Latest high-performance reasoning model\n", + "- **Thinking Budget**: 2048 tokens for internal reasoning\n", + "- **Cache Settings**: Optimized for prompt and tool caching\n", + "\n", + "## Tool Integration\n", + "Combines multiple tool categories:\n", + "- **Custom Tools**: Service discovery and HTML generation\n", + "- **Strands Tools**: Image reading and processing\n", + "- **AgentKit Tools**: Blockchain and payment capabilities\n", + "- **Modified X402 Tools**: Payment-gated API access\n", + "\n", + "## System Prompt Design\n", + "The comprehensive system prompt defines the agent as an expert in:\n", + "\n", + "### 🎯 Core Capabilities\n", + "- Digital marketing and copywriting\n", + "- Multi-platform ad creation (social, display, email, print)\n", + "- Visual content generation and integration\n", + "- Campaign strategy and optimization\n", + "\n", + "### 🛠️ Technical Workflow\n", + "1. **Discovery**: Use service catalog to find relevant APIs\n", + "2. **Enhancement**: Generate visuals and gather contextual data\n", + "3. **Creation**: Craft compelling copy with clear CTAs\n", + "4. **Integration**: Combine all elements into cohesive campaigns\n", + "5. **Output**: Generate complete HTML files with embedded media\n", + "\n", + "### ✅ Quality Standards\n", + "- Mobile-first design approach\n", + "- A/B testing recommendations\n", + "- Proper image embedding in HTML\n", + "- Brand consistency guidelines\n", + "- Performance optimization\n", + "\n", + "This agent is designed to create production-ready advertising campaigns autonomously." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12cfb3e8-1d4f-4e1b-af16-0d05b7221b3c", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:02:51.016986Z", + "iopub.status.busy": "2025-10-07T04:02:51.016701Z", + "iopub.status.idle": "2025-10-07T04:02:51.121138Z", + "shell.execute_reply": "2025-10-07T04:02:51.120488Z", + "shell.execute_reply.started": "2025-10-07T04:02:51.016962Z" + } + }, + "outputs": [], + "source": [ + "# Initialize the Bedrock Model\n", + "\n", + "# bedrock_model = BedrockModel(\n", + "# cache_prompt=\"default\",\n", + "# cache_tools=\"default\",\n", + "# model_id=\"us.anthropic.claude-sonnet-4-20250514-v1:0\",\n", + "# max_tokens=4000,\n", + "# additional_request_fields={\n", + "# \"thinking\": {\n", + "# \"type\": \"enabled\",\n", + "# \"budget_tokens\": 2048 # Minimum of 1,024\n", + "# }\n", + "# }\n", + "# )\n", + "\n", + "# Create the Ads Creative Agent\n", + "advertising_agent = Agent(\n", + " # model=bedrock_model, # defaults to Sonnet 4\n", + " tools=[\n", + " list_available_services,\n", + " get_service_schema,\n", + " image_reader,\n", + " create_ad_html,\n", + " ] + modified_tools, # Custom tools plus Coinbase Agentkit tools\n", + " system_prompt=\"\"\"You are an expert advertising and marketing content creator with extensive experience in digital marketing, copywriting, and creative direction.\n", + "\n", + "Your capabilities:\n", + "1. Create compelling ad copy for various platforms (social media, display, email, print)\n", + "2. Discover and use external services for ad enhancement:\n", + " - Generate professional visuals using the image generation service\n", + " - Get real-time weather data for location-based and seasonal campaigns\n", + "3. Design complete ad campaigns with copy, visuals, and targeting strategy\n", + "4. Interacting with on chain actions for making and necessary payments\n", + "5. Tool for creating a html file of the generated ads\n", + "\n", + "When creating ads:\n", + "- First start with and outline of the ads to be created\n", + "- Use list_available_services() to discover external services that can help in creating ads\n", + "- Consider the target audience, platform, and campaign goals\n", + "- If location-specific or weather-dependent, use the appropiate external service to get weather info\n", + "- Always generate relevant visuals using image endpoint service\n", + "- Use persuasive copywriting techniques (AIDA, PAS, FAB)\n", + "- Include clear call-to-action (CTA)\n", + "- Optimize for the specific ad format and platform\n", + "- Save the ads content as a html file. When creating the html content, make sure images are rendered properly. Take this part very seriously\n", + "\n", + "Ad Formats You Can Create:\n", + "- Social Media Ads (Facebook, Instagram, LinkedIn, Twitter)\n", + "- Display Banner Ads\n", + "- Email Marketing\n", + "- Print Advertisements\n", + "- Video Ad Scripts\n", + "- Search Ads (Google, Bing)\n", + "\n", + "Response Structure:\n", + "1. Campaign Overview (objective, audience, platform)\n", + "2. Headline(s) - attention-grabbing and benefit-focused\n", + "3. Body Copy - persuasive and engaging\n", + "4. Call-to-Action - clear and action-oriented\n", + "5. Visual Description/Generated Images\n", + "6. Targeting Recommendations (demographics, interests, behaviors)\n", + "7. Budget & Timing Suggestions (if applicable)\n", + "8. **HTML File Creation Checklist:**\n", + " - [ ] All images generated and URLs obtained\n", + " - [ ] Images embedded in HTML with tags using relative paths\n", + " - [ ] HTML file saved with rendered images\n", + "\n", + "Best Practices:\n", + "- Keep it concise and scannable\n", + "- Focus on benefits, not just features\n", + "- Use emotional triggers and power words\n", + "- Create urgency when appropriate\n", + "- Ensure brand consistency\n", + "- Mobile-first approach\n", + "- A/B testing recommendations\n", + "- Include images in teh generated html file\n", + "\n", + "CRITICAL REQUIREMENT - HTML FILE GENERATION:\n", + "When saving ads as HTML files, you MUST:\n", + "✓ Include ALL generated images embedded in the HTML\n", + "✓ Use proper tags with src attributes pointing to the image URLs\n", + "✓ Ensure images are visible when the HTML file is opened\n", + "✓ Test that image URLs are accessible and properly formatted\n", + "✓ Never create HTML files with missing or broken image references\n", + "**NEVER use absolute file system paths:**\n", + "❌ ``\n", + "\n", + "**ALWAYS use relative paths based on the HTML file location:**\n", + "✅ ``\n", + "\n", + "\n", + "BEFORE saving the HTML file, verify:\n", + "1. Each ad section has its corresponding image embedded\n", + "2. Image URLs are complete and valid\n", + "3. Images have appropriate alt text\n", + "4. The HTML renders images correctly\n", + "\n", + "Be creative, data-driven, and results-oriented!\"\"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cfbd34f6-e47b-4791-9014-45dc47124ed8", + "metadata": { + "execution": { + "iopub.execute_input": "2025-10-07T04:08:45.956627Z", + "iopub.status.busy": "2025-10-07T04:08:45.955530Z", + "iopub.status.idle": "2025-10-07T04:10:42.649928Z", + "shell.execute_reply": "2025-10-07T04:10:42.649353Z", + "shell.execute_reply.started": "2025-10-07T04:08:45.956596Z" + }, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I'll create a compelling social media ad for your ice cream shop promotion in Miami! Let me start by outlining the campaign and then gathering the resources I need.\n", + "\n", + "## Campaign Overview\n", + "- **Objective**: Drive foot traffic to ice cream shop in Miami\n", + "- **Audience**: Local Miami residents, tourists, families, young adults\n", + "- **Platform**: Social Media (Facebook, Instagram)\n", + "- **Strategy**: Weather-responsive promotion leveraging Miami's warm climate\n", + "\n", + "Let me first check what external services are available to enhance this ad:\n", + "Tool #1: list_available_services\n", + "Perfect! Let me get the current weather in Miami to create a weather-responsive ad, and then I'll generate compelling visuals.\n", + "Tool #2: get_service_schema\n", + "\n", + "Tool #3: x402ActionProvider_make_http_request\n", + "I need to make a payment to access the weather service. Let me check my wallet balance and proceed with the payment:\n", + "Tool #4: WalletActionProvider_get_wallet_details\n", + "Let me request some test funds to cover the payment:\n", + "Tool #5: CdpApiActionProvider_request_faucet_funds\n", + "Great! Now let me retry the weather request with payment:\n", + "Tool #6: x402ActionProvider_retry_with_x402\n", + "Excellent! Miami is at a perfect 80°F with few clouds - ideal ice cream weather! Now let me get the image generation service details to create compelling visuals:\n", + "Tool #7: get_service_schema\n", + "Now I'll generate compelling visuals for the ice cream shop ad. Let me create a vibrant, Miami-themed ice cream image:\n", + "Tool #8: x402ActionProvider_make_http_request_with_x402\n", + "Perfect! I've generated 5 tropical Miami ice cream images. Now let me create the complete social media ad campaign:\n", + "\n", + "# 🍦 MIAMI ICE CREAM SHOP SOCIAL MEDIA AD CAMPAIGN\n", + "\n", + "## Campaign Overview\n", + "- **Objective**: Drive foot traffic and increase sales during prime ice cream weather\n", + "- **Current Miami Weather**: 80°F, Few Clouds - Perfect ice cream conditions!\n", + "- **Target Audience**: Miami locals, tourists, families, young adults (18-45)\n", + "- **Platform**: Facebook & Instagram\n", + "- **Campaign Type**: Weather-responsive promotion\n", + "\n", + "## Headlines (A/B Test Options)\n", + "1. **\"80°F in Miami = Perfect Ice Cream Weather! 🌴\"**\n", + "2. **\"Beat the Miami Heat with Our Tropical Flavors!\"**\n", + "3. **\"Cool Down Miami Style - Tropical Scoops Await! 🍦\"**\n", + "\n", + "## Body Copy\n", + "**Primary Version:**\n", + "\"Miami's hitting a sweet 80°F today with beautiful skies! ☀️ There's no better time to treat yourself to our tropical ice cream flavors. From coconut mango to key lime pie, we've got the perfect scoop to cool you down! \n", + "\n", + "🌴 Fresh tropical flavors daily\n", + "🍦 Handcrafted with premium ingredients \n", + "📍 Located in the heart of Miami\n", + "💨 Fast service, no long waits!\n", + "\n", + "The weather's perfect, the vibes are right - come get your Miami ice cream fix!\"\n", + "\n", + "## Call-to-Action Options\n", + "- **Primary**: \"Visit Us Today!\" \n", + "- **Secondary**: \"See Menu & Location\"\n", + "- **Urgency**: \"Cool Down Now!\"\n", + "\n", + "## Visual Elements Generated\n", + "✅ Multiple tropical ice cream scenes with Miami vibes\n", + "✅ Colorful scoops with palm tree backgrounds\n", + "✅ Professional food photography style\n", + "✅ Bright, summer-ready aesthetic\n", + "\n", + "Now let me create the HTML file with all the content and generated images:\n", + "Tool #9: create_ad_html\n", + "# 🍦 MIAMI ICE CREAM SHOP AD CAMPAIGN - COMPLETE! \n", + "\n", + "## ✅ **HTML File Creation Checklist - VERIFIED:**\n", + "- [x] All 5 generated images embedded in HTML with proper paths\n", + "- [x] Images use relative paths (`../output/image.png`)\n", + "- [x] HTML file saved with rendered images\n", + "- [x] Weather-responsive content integrated\n", + "- [x] Multiple CTA options included\n", + "- [x] Mobile-responsive design implemented\n", + "\n", + "## 🎯 **Campaign Summary**\n", + "\n", + "**Perfect Timing Alert!** 🌡️ Miami is currently at an ideal **80°F with few clouds** - perfect ice cream weather conditions!\n", + "\n", + "### **Headline Options (A/B Test Ready)**\n", + "1. **Primary**: \"80°F in Miami = Perfect Ice Cream Weather! 🌴\"\n", + "2. **Alternative**: \"Beat the Miami Heat with Our Tropical Flavors!\"\n", + "3. **Urgency**: \"Cool Down Miami Style - Tropical Scoops Await!\"\n", + "\n", + "### **Key Messaging Strategy**\n", + "- **Weather-Responsive**: Leverages real-time 80°F temperature\n", + "- **Local Appeal**: Miami-specific tropical themes\n", + "- **Urgency**: Perfect weather conditions create natural urgency\n", + "- **Benefits-Focused**: Fresh flavors, fast service, premium quality\n", + "\n", + "### **Visual Assets Generated** 🎨\n", + "✅ **5 Professional Images Created:**\n", + "- Hand holding triple scoop in Miami setting\n", + "- Vibrant colorful ice cream display\n", + "- Close-up tropical flavor shots\n", + "- Overhead view of multiple flavors \n", + "- Wide-angle Miami ice cream shop scene\n", + "\n", + "### **Target Audience Strategy**\n", + "- **Primary**: Miami locals & tourists (18-45)\n", + "- **Secondary**: Families with children\n", + "- **Platform**: Facebook & Instagram (Feed + Stories)\n", + "- **Peak Times**: 12PM-6PM weekends, 3PM-8PM weekdays\n", + "\n", + "### **Expected Performance** 📈\n", + "- **+40% engagement boost** due to perfect weather conditions\n", + "- **High conversion potential** with weather-responsive messaging\n", + "- **Recommended budget**: $200-500/day during peak weather\n", + "\n", + "### **Call-to-Action Options**\n", + "- **Primary**: \"Visit Us Today! 🍦\"\n", + "- **Location**: \"See Menu & Location 📍\" \n", + "- **Urgency**: \"Cool Down Now! ❄️\"\n", + "\n", + "The complete campaign is now ready for deployment with weather-optimized messaging, professional tropical visuals, and mobile-responsive design. The HTML file contains all generated images and can be used immediately for social media advertising!" + ] + } + ], + "source": [ + "response = advertising_agent(\"\"\" Generate an ad for the following:\n", + " product=\"ice cream shop promotion\",\n", + " city=\"Miami,US\",\n", + " platform=\"social-media\"\n", + "\"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "431a509d-cb2d-49b6-a5dd-630c69bcc87e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/02-samples/16-ai-ads-generation-agent-with-crypto-payments/paid_server.py b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/paid_server.py new file mode 100644 index 00000000..4bea91ee --- /dev/null +++ b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/paid_server.py @@ -0,0 +1,315 @@ +import os +from typing import Any, Dict, Optional + +from dotenv import load_dotenv +from fastapi import FastAPI +from pydantic import BaseModel, ConfigDict, Field, field_validator +from x402.fastapi.middleware import require_payment +from x402.types import EIP712Domain, TokenAmount, TokenAsset +from strands import Agent +from strands_tools import generate_image as generate_image_tool +import requests +import uvicorn + +# Load environment variables +load_dotenv() + +# Get configuration from environment - properly use environment variable +ADDRESS = os.getenv("ADDRESS") # Receiving Payment address +OPENWEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY") # OpenWeather API key +# Use environment variable or default to localhost for security +HOST = os.getenv("HOST", "127.0.0.1") # Defaults to localhost +PORT = int(os.getenv("PORT", 4021)) + +if not ADDRESS: + raise ValueError("Missing required environment variable: ADDRESS") + + +# Define Pydantic models for request/response validation + +class ContentRequest(BaseModel): + query: str = Field( + ..., + min_length=1, + max_length=1000, + description="The prompt describing what images to generate" + ) + + @field_validator('query') + @classmethod + def validate_query(cls, v): + if not v.strip(): + raise ValueError('Query cannot be empty or whitespace only') + return v.strip() + + model_config = ConfigDict( + json_schema_extra={ + "example": { + "query": "Generate 3 images of a sunset over mountains" + } + } + ) + + +class WeatherRequest(BaseModel): + city: str = Field( + ..., + min_length=1, + max_length=100, + description="City name (e.g., 'London' or 'London,UK')" + ) + units: Optional[str] = Field( + default="metric", + description="Units of measurement: 'metric', 'imperial', or 'standard'" + ) + + @field_validator('city') + @classmethod + def validate_city(cls, v): + if not v.strip(): + raise ValueError('City cannot be empty or whitespace only') + return v.strip() + + @field_validator('units') + @classmethod + def validate_units(cls, v): + if v not in ['metric', 'imperial', 'standard']: + raise ValueError('Units must be metric, imperial, or standard') + return v + + model_config = ConfigDict( + json_schema_extra={ + "example": { + "city": "London,UK", + "units": "metric" + } + } + ) + + +# image genration function +def create_images_with_agent(query: str) -> str: + """ + Generate images using the artist agent. + + Args: + query: The prompt describing what images to generate + + Returns: + Comma-separated list of file paths to generated images + """ + # Artist agent that generates images based on prompts + artist = Agent( + tools=[generate_image_tool], + system_prompt=( + "You will be instructed to generate a number of images of a given subject. " + "Vary the prompt for each generated image to create a variety of options. " + "Your final output must contain ONLY a comma-separated list of the file system " + "paths of generated images with a preamble telling the user the files are saved" + ) + ) + + result = artist(query) + return result + + +# weather generation function using OpenWeather +def get_weather_data(city: str, units: str = "metric") -> Dict[str, Any]: + """ + Fetch weather data from OpenWeather API. + + Args: + city: City name + units: Units of measurement (metric, imperial, or standard) + + Returns: + Weather data from OpenWeather API + + Raises: + HTTPException: If the API request fails + """ + base_url = "https://api.openweathermap.org/data/2.5/weather" + params = { + "q": city, + "appid": OPENWEATHER_API_KEY, + "units": units + } + + try: + response = requests.get(base_url, params=params, timeout=(30, 30)) + response.raise_for_status() # Raise an exception for HTTP errors (4xx or 5xx) + weather_data = response.json() + return weather_data + except requests.exceptions.Timeout: + print(f"Timeout error fetching weather data for {city}") + return f"Timeout error fetching weather data for {city}" + except requests.exceptions.RequestException as e: + print(f"Error fetching weather data: {e}") + return f"Error fetching weather data: {e}" + + +# Initialize FastAPI app +app = FastAPI( + title="Payment-Gated API", + description="API with payment requirements for different endpoints", + version="1.0.0" +) + + +# Apply payment middleware to image generator endpoint +app.middleware("http")( + require_payment( + path="/image_generator", + price=TokenAmount( + amount="100", + asset=TokenAsset( + address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", + decimals=6, + eip712=EIP712Domain(name="USDC", version="2"), + ), + ), + pay_to_address=ADDRESS, + network="base-sepolia", + description="Image generation service", + input_schema={ + "body_type": "json", + "body_fields": { + "query": { + "type": "string", + "description": "The prompt describing what images to generate (e.g., 'Generate 3 images of a sunset over mountains')", + "required": True + } + } + }, + output_schema={ + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the image generation was successful" + }, + "content": { + "type": "string", + "description": "Comma-separated list of file paths to generated images" + }, + "error": { + "type": "string", + "description": "Error message if success is false" + } + } + } + ) +) + + +# Apply payment middleware to weather endpoint +app.middleware("http")( + require_payment( + path="/weather", + price="$0.001", + pay_to_address=ADDRESS, + network="base-sepolia", + description="weather generation service", + input_schema={ + "body_type": "json", + "body_fields": { + "query": { + "type": "string", + "description": "The prompt describing what images to generate", + "example": "Generate 3 images of a sunset over mountains", + "required": True, + "minLength": 1, + "maxLength": 500 + } + } + } + ) +) + + +@app.get("/") +async def root() -> Dict[str, str]: + """Root endpoint with API information.""" + return { + "message": "Payment-Gated API", + "endpoints": { + "image_generator": "POST /image_generator - 100 USDC", + "weather": "POST /weather - 0.001 USDC" + } + } + + +@app.post("/image_generator") +async def generate_images(request: ContentRequest) -> Dict[str, Any]: + """ + Generate images based on the provided query. + Requires payment of 100 USDC. + + Args: + request: ContentRequest with query field + + Returns: + Dictionary containing the generated image paths + """ + try: + result = create_images_with_agent(request.query) + return { + "success": True, + "content": result.message, + } + except Exception as e: + return { + "success": False, + "error": str(e), + } + + +@app.post("/weather") +async def get_weather(request: WeatherRequest) -> Dict[str, Any]: + """ + Get current weather information for a specified city. + Requires payment of $0.001. + + Args: + request: WeatherRequest with city and optional units + + Returns: + WeatherResponse containing current weather data or error + """ + print(f"Weather request for city: {request.city}, units: {request.units}") + + try: + weather_data = get_weather_data(request.city, request.units) + + # Parse the OpenWeather API response + weather_response = { + "temperature": weather_data["main"]["temp"], + "feels_like": weather_data["main"]["feels_like"], + "temp_min": weather_data["main"]["temp_min"], + "temp_max": weather_data["main"]["temp_max"], + "pressure": weather_data["main"]["pressure"], + "humidity": weather_data["main"]["humidity"], + "description": weather_data["weather"][0]["description"], + "wind_speed": weather_data["wind"]["speed"], + "clouds": weather_data["clouds"]["all"], + "city": weather_data["name"], + "country": weather_data["sys"]["country"] + } + + print(f"Weather data retrieved successfully for {request.city}") + return weather_response + + except Exception as e: + return { + "error": str(e), + } + + +if __name__ == "__main__": + + uvicorn.run( + app, + host=HOST, + port=PORT, + log_level="info" + ) \ No newline at end of file diff --git a/02-samples/16-ai-ads-generation-agent-with-crypto-payments/requirements.txt b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/requirements.txt new file mode 100644 index 00000000..355f9d26 --- /dev/null +++ b/02-samples/16-ai-ads-generation-agent-with-crypto-payments/requirements.txt @@ -0,0 +1,8 @@ +strands-agents +strands-agents-tools +strands-agents-builder +coinbase-agentkit +coinbase-agentkit-strands-agents +x402 +fastapi +boto3