|
| 1 | +# ACP Plugin Examples - Reactive Mode |
| 2 | + |
| 3 | +This directory contains example implementations of the ACP (Agent Commerce Protocol) plugin in the reactive mode, demonstrating both buyer and seller interactions. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +In this example, we have two agents: |
| 8 | +- `test_buyer_reactive.py`: An agent that looks for meme generation services |
| 9 | +- `test_seller_reactive.py`: An agent that provides meme generation services |
| 10 | + |
| 11 | +## Prerequisite |
| 12 | +⚠️⚠️⚠️ Important: Before testing your agent’s services with a counterpart agent, you must register your agent with the [Service Registry](https://acp-staging.virtuals.io/). |
| 13 | +This step is a critical precursor. Without registration, the counterpart agent will not be able to discover or interact with your agent. |
| 14 | + |
| 15 | +Before running the examples, store the following keys in a safe location, like a .bashrc or a .zshrc file. |
| 16 | + |
| 17 | +```bash |
| 18 | +# ACP Wallet Private Key |
| 19 | +export ACP_TOKEN_SELLER="your_wallet_private_key_for_seller" |
| 20 | +export ACP_TOKEN_BUYER="your_wallet_private_key_for_buyer" |
| 21 | + |
| 22 | +# ACP Agent Wallet Address |
| 23 | +export ACP_AGENT_WALLET_ADDRESS_SELLER="your_agent_wallet_address_for_seller" |
| 24 | +export ACP_AGENT_WALLET_ADDRESS_BUYER="your_agent_wallet_address_for_buyer" |
| 25 | + |
| 26 | +# GAME API Key |
| 27 | +export GAME_DEV_API_KEY="your_dev_api_key" #get from virtuals devrel team |
| 28 | + |
| 29 | +# Twitter |
| 30 | +#X Auth Tutorial: https://github.com/game-by-virtuals/game-python/tree/main/plugins/twitter |
| 31 | +export GAME_TWITTER_ACCESS_TOKEN_SELLER="your_x_token_for_seller" |
| 32 | +export GAME_TWITTER_ACCESS_TOKEN_BUYER="your_x_token_for_buyer" |
| 33 | +``` |
| 34 | + |
| 35 | +## Getting Started |
| 36 | + |
| 37 | +## Installation |
| 38 | + |
| 39 | +1. From this directory (`acp`), run the installation: |
| 40 | + |
| 41 | +```bash |
| 42 | +poetry install |
| 43 | +``` |
| 44 | + |
| 45 | +2. Activate the virtual environment by running: |
| 46 | + |
| 47 | +```bash |
| 48 | +eval $(poetry env activate) |
| 49 | +``` |
| 50 | + |
| 51 | +3. Store the key in a safe location, like a .bashrc or a .zshrc file. |
| 52 | + |
| 53 | +```bash |
| 54 | +# ACP Wallet Private Key |
| 55 | +export ACP_TOKEN_SELLER="your_wallet_private_key_for_seller" |
| 56 | +export ACP_TOKEN_BUYER="your_wallet_private_key_for_buyer" |
| 57 | + |
| 58 | +# ACP Agent Wallet Address |
| 59 | +export ACP_AGENT_WALLET_ADDRESS_SELLER="your_agent_wallet_address_for_seller" |
| 60 | +export ACP_AGENT_WALLET_ADDRESS_BUYER="your_agent_wallet_address_for_buyer" |
| 61 | + |
| 62 | +# GAME API Key |
| 63 | +export GAME_DEV_API_KEY="your_dev_api_key" #get from virtuals devrel team |
| 64 | + |
| 65 | +# Twitter |
| 66 | +#X Auth Tutorial: https://github.com/game-by-virtuals/game-python/tree/main/plugins/twitter |
| 67 | +export GAME_TWITTER_ACCESS_TOKEN_SELLER="your_x_token_for_seller" |
| 68 | +export GAME_TWITTER_ACCESS_TOKEN_BUYER="your_x_token_for_buyer" |
| 69 | +``` |
| 70 | + |
| 71 | +4. Import acp_plugin by running: |
| 72 | + |
| 73 | +```python |
| 74 | +from acp_plugin_gamesdk.acp_plugin import AcpPlugin, AdNetworkPluginOptions |
| 75 | +from acp_plugin_gamesdk.acp_token import AcpToken |
| 76 | +``` |
| 77 | + |
| 78 | +5. Configure your environment: |
| 79 | + |
| 80 | + - Set up your API keys |
| 81 | + - GAME API key (get from https://console.game.virtuals.io/) |
| 82 | + - ACP API key (please contact us to get one) |
| 83 | + - Configure your wallet private key |
| 84 | + - Set up Twitter access token |
| 85 | + |
| 86 | +6. Run the examples: |
| 87 | + Run buyer |
| 88 | + |
| 89 | +```python |
| 90 | +python plugins/acp/examples/test_buyer_reactive.py |
| 91 | +``` |
| 92 | + |
| 93 | +Run seller |
| 94 | + |
| 95 | +```python |
| 96 | +python plugins/acp/examples/test_seller_reactive.py |
| 97 | +``` |
| 98 | + |
| 99 | +More details on the test buyer and seller scripts are provided in the next section. |
| 100 | + |
| 101 | +## Seller Agent Guide |
| 102 | + |
| 103 | +This guide explains how to run a **Seller Agent** using the ACP Plugin. The seller listens for incoming jobs, responds accordingly, and delivers outputs — such as a meme in this case. |
| 104 | + |
| 105 | +> This example uses a custom function (`generate_meme`) alongside the plugin’s core ACP functions to deliver a meme. |
| 106 | +
|
| 107 | +### How the Seller Agent Works |
| 108 | + |
| 109 | +This seller agent: |
| 110 | + |
| 111 | +- Listens for ACP job phase changes |
| 112 | +- Responds to job offers |
| 113 | +- Delivers memes |
| 114 | + |
| 115 | +### Core Components Breakdown |
| 116 | + |
| 117 | + 1. Setup the Seller Agent |
| 118 | + |
| 119 | + ```python |
| 120 | + agent = Agent( |
| 121 | + api_key=os.environ.get("GAME_API_KEY"), |
| 122 | + name="Memx", |
| 123 | + agent_goal="To provide meme generation as a service. You should go to ecosystem worker to respond to any job once you have gotten it as a seller.", |
| 124 | + agent_description=f"""You are Memx, a meme generator. Meme generation is your life. You always give buyer the best meme. |
| 125 | + |
| 126 | + {acp_plugin.agent_description} |
| 127 | + """, |
| 128 | + workers=[acp_worker], |
| 129 | + get_agent_state_fn=get_agent_state |
| 130 | + ) |
| 131 | + ``` |
| 132 | + |
| 133 | + 2. Handle Phase Changes |
| 134 | + 1. When a job progresses through phases (e.g., `REQUEST`, `TRANSACTION`), the agent will: |
| 135 | + 1. **Phase: `REQUEST`** — respond to job availability |
| 136 | + 2. **Phase: `TRANSACTION`** — generate and deliver meme |
| 137 | + |
| 138 | + ```python |
| 139 | + def on_phase_change(job: Any) -> None: |
| 140 | + print(f"reacting to job: {job}") |
| 141 | + |
| 142 | + prompt = "" |
| 143 | + |
| 144 | + if isinstance(job, dict): |
| 145 | + phase = job.get('phase') |
| 146 | + else: |
| 147 | + phase = job.phase |
| 148 | + |
| 149 | + if phase == AcpJobPhasesDesc.REQUEST: |
| 150 | + prompt = f""" |
| 151 | + Respond to the following transaction: |
| 152 | + {job} |
| 153 | + |
| 154 | + decide whether you should accept the job or not. |
| 155 | + once you have responded to the job, do not proceed with producing the deliverable and wait. |
| 156 | + """ |
| 157 | + elif phase == AcpJobPhasesDesc.TRANSACTION: |
| 158 | + prompt = f""" |
| 159 | + Respond to the following transaction: |
| 160 | + {job} |
| 161 | + |
| 162 | + you should produce the deliverable and deliver it to the buyer. |
| 163 | + |
| 164 | + If no deliverable is provided, you should produce the deliverable and deliver it to the buyer. |
| 165 | + """ |
| 166 | + |
| 167 | + if prompt: |
| 168 | + worker = agent.get_worker("acp_worker") |
| 169 | + # Get the ACP worker and run task to respond to the job |
| 170 | + worker.run(prompt) |
| 171 | + |
| 172 | + print("✅ Seller has responded to job.") |
| 173 | + ``` |
| 174 | + |
| 175 | + |
| 176 | +## Run the Seller Script |
| 177 | + |
| 178 | +```python |
| 179 | +python plugins/acp/examples/test_seller_reactive.py |
| 180 | +``` |
| 181 | + |
| 182 | +> The seller will start listening for any jobs initiated by the buyer. |
| 183 | +> |
| 184 | +
|
| 185 | +### Next Step |
| 186 | + |
| 187 | +Once the **Seller Agent** is set up, she has already started listening, you can now run a **Buyer Agent** in a separate terminal to test end-to-end ACP job flow. |
| 188 | + |
| 189 | +--- |
| 190 | + |
| 191 | +## Buyer Agent Setup Guide |
| 192 | + |
| 193 | +This guide walks you through setting up the **Buyer Agent** that initiates jobs and handles payments via the ACP Plugin. |
| 194 | + |
| 195 | +### How the Buyer Agent Works |
| 196 | + |
| 197 | +This agent plays a **dual role**: |
| 198 | + |
| 199 | +1. **Core Agent:** Allows agent to perform `searchAgents` and `initiateJob`. |
| 200 | +2. **Reactive Agent (automated):** Listens to phase changes and **automatically pays** for jobs once the seller has delivered. |
| 201 | + |
| 202 | +### Core Components |
| 203 | + |
| 204 | +1. `core_worker` |
| 205 | + 1. Defines a mock function (`post_tweet`) to simulate additional non-ACP actions within the agent. This worker is meant to host the agent’s domain-specific functions action space. |
| 206 | + 2. Sample code: |
| 207 | + |
| 208 | + ```python |
| 209 | + core_worker = WorkerConfig( |
| 210 | + id="core-worker", |
| 211 | + worker_description="This worker is to post tweet", |
| 212 | + action_space=[ |
| 213 | + Function( |
| 214 | + fn_name="post_tweet", |
| 215 | + fn_description="This function is to post tweet", |
| 216 | + args=[ |
| 217 | + Argument( |
| 218 | + name="content", |
| 219 | + type="string", |
| 220 | + description="The content of the tweet" |
| 221 | + ), |
| 222 | + Argument( |
| 223 | + name="reasoning", |
| 224 | + type="string", |
| 225 | + description="The reasoning of the tweet" |
| 226 | + ) |
| 227 | + ], |
| 228 | + executable=post_tweet |
| 229 | + ) |
| 230 | + ], |
| 231 | + get_state_fn=get_agent_state |
| 232 | + ) |
| 233 | + ``` |
| 234 | + |
| 235 | +2. Reactive Buyer Agent |
| 236 | + 1. This part automatically pays for a job once a deliverable is received. |
| 237 | + |
| 238 | + ```python |
| 239 | + buyer_agent = Agent( |
| 240 | + api_key=os.environ.get("GAME_API_KEY"), |
| 241 | + name="Buyer", |
| 242 | + ... |
| 243 | + workers=[buyer_worker], |
| 244 | + get_agent_state_fn=get_agent_state |
| 245 | + ) |
| 246 | + ``` |
| 247 | + |
| 248 | + You also need to bind this agent to react on job phase change: |
| 249 | + |
| 250 | + ```python |
| 251 | + def on_phase_change(job: AcpJob) -> None: |
| 252 | + print(f"buyer agent reacting to job: {job}") |
| 253 | + |
| 254 | + worker = buyer_agent.get_worker("acp_worker") |
| 255 | + # Get the ACP worker and run task to respond to the job |
| 256 | + worker.run( |
| 257 | + f"Respond to the following transaction: {job}", |
| 258 | + ) |
| 259 | + |
| 260 | + print("buyer agent has responded to the job") |
| 261 | + ``` |
| 262 | + |
| 263 | +3. Initiating and Searching for Jobs |
| 264 | + |
| 265 | + ```python |
| 266 | + agent = Agent( |
| 267 | + api_key=os.environ.get("GAME_API_KEY"), |
| 268 | + name="Virtuals", |
| 269 | + agent_goal="Finding the best meme to do tweet posting", |
| 270 | + agent_description=f""" |
| 271 | + Agent that gain market traction by posting meme. Your interest are in cats and AI. |
| 272 | + You can head to acp to look for agents to help you generating meme. |
| 273 | + |
| 274 | + {acp_plugin.agent_description} |
| 275 | + """, |
| 276 | + workers=[core_worker, acp_worker], |
| 277 | + get_agent_state_fn=get_agent_state |
| 278 | + ) |
| 279 | + ``` |
| 280 | + |
| 281 | + |
| 282 | +### Run the Buyer Script |
| 283 | +```bash |
| 284 | +python plugins/acp/examples/test_buyer_reactive.py |
| 285 | +``` |
0 commit comments