|
| 1 | +import threading |
| 2 | + |
1 | 3 | from typing import Tuple |
2 | 4 | from game_sdk.game.agent import Agent, WorkerConfig |
3 | 5 | from game_sdk.game.custom_types import Argument, Function, FunctionResultStatus |
@@ -53,32 +55,81 @@ def on_evaluate(job: ACPJob): |
53 | 55 | # }, |
54 | 56 | # } |
55 | 57 |
|
56 | | -def buyer(): |
57 | | - # upon phase change, the buyer agent will respond to the transaction |
| 58 | +def buyer(use_thread_lock: bool = True): |
| 59 | + if env.WHITELISTED_WALLET_PRIVATE_KEY is None: |
| 60 | + return |
| 61 | + |
| 62 | + if env.BUYER_ENTITY_ID is None: |
| 63 | + return |
| 64 | + |
| 65 | + # Thread-safe job queue setup |
| 66 | + job_queue = [] |
| 67 | + job_queue_lock = threading.Lock() |
| 68 | + job_event = threading.Event() |
| 69 | + |
| 70 | + # Thread-safe append with optional lock |
| 71 | + def safe_append_job(job): |
| 72 | + if use_thread_lock: |
| 73 | + print(f"[safe_append_job] Acquiring lock to append job {job.id}") |
| 74 | + with job_queue_lock: |
| 75 | + print(f"[safe_append_job] Lock acquired, appending job {job.id} to queue") |
| 76 | + job_queue.append(job) |
| 77 | + else: |
| 78 | + job_queue.append(job) |
| 79 | + |
| 80 | + # Thread-safe pop with optional lock |
| 81 | + def safe_pop_job(): |
| 82 | + if use_thread_lock: |
| 83 | + print(f"[safe_pop_job] Acquiring lock to pop job") |
| 84 | + with job_queue_lock: |
| 85 | + if job_queue: |
| 86 | + job = job_queue.pop(0) |
| 87 | + print(f"[safe_pop_job] Lock acquired, popped job {job.id}") |
| 88 | + return job |
| 89 | + else: |
| 90 | + print("[safe_pop_job] Queue is empty after acquiring lock") |
| 91 | + else: |
| 92 | + if job_queue: |
| 93 | + job = job_queue.pop(0) |
| 94 | + print(f"[safe_pop_job] Popped job {job.id} without lock") |
| 95 | + return job |
| 96 | + else: |
| 97 | + print("[safe_pop_job] Queue is empty (no lock)") |
| 98 | + return None |
| 99 | + |
| 100 | + # Background thread worker: process jobs one by one |
| 101 | + def job_worker(): |
| 102 | + while True: |
| 103 | + job_event.wait() # Wait for job |
| 104 | + |
| 105 | + job = safe_pop_job() |
| 106 | + while job: |
| 107 | + process_job(job) |
| 108 | + job = safe_pop_job() |
| 109 | + |
| 110 | + job_event.clear() # Go back to wait |
| 111 | + |
| 112 | + # Event-triggered job task receiver |
58 | 113 | def on_new_task(job: ACPJob): |
| 114 | + print(f"[on_new_task] Received job {job.id} (phase: {job.phase})") |
| 115 | + safe_append_job(job) |
| 116 | + job_event.set() |
| 117 | + |
| 118 | + def process_job(job: ACPJob): |
59 | 119 | out = "" |
60 | 120 | print(job.phase, "job.phase") |
61 | 121 | if job.phase == ACPJobPhase.NEGOTIATION: |
62 | 122 | for memo in job.memos: |
63 | 123 | print(memo.next_phase, "memo.next_phase") |
64 | 124 | if memo.next_phase == ACPJobPhase.TRANSACTION: |
65 | 125 | out += f"Buyer agent is reacting to job:\n{job}\n\n" |
66 | | - |
67 | 126 | buyer_agent.get_worker("acp_worker").run( |
68 | 127 | f"Respond to the following transaction: {job}", |
69 | 128 | ) |
70 | | - |
71 | 129 | out += "Buyer agent has responded to the job\n" |
| 130 | + |
72 | 131 | print(Panel(out, title="🔁 Reaction", box=box.ROUNDED, title_align="left", border_style="red")) |
73 | 132 |
|
74 | | - |
75 | | - if env.WHITELISTED_WALLET_PRIVATE_KEY is None: |
76 | | - return |
77 | | - |
78 | | - if env.BUYER_ENTITY_ID is None: |
79 | | - return |
80 | | - |
81 | | - |
82 | 133 | acp_plugin = AcpPlugin( |
83 | 134 | options=AcpPluginOptions( |
84 | 135 | api_key=env.GAME_API_KEY, |
@@ -185,15 +236,24 @@ def post_tweet(content: str, reasoning: str) -> Tuple[FunctionResultStatus, str, |
185 | 236 | buyer_agent.compile() |
186 | 237 | agent.compile() |
187 | 238 |
|
| 239 | + # Start background job thread |
| 240 | + threading.Thread(target=job_worker, daemon=True).start() |
| 241 | + |
188 | 242 | while True: |
189 | 243 | print("🟢"*40) |
190 | 244 | init_state = AcpState.model_validate(agent.agent_state) |
191 | 245 | print(Panel(f"{init_state}", title="Agent State", box=box.ROUNDED, title_align="left")) |
192 | | - agent.step() |
| 246 | + |
| 247 | + print("[agent.step] Attempting to acquire lock for agent.step()") |
| 248 | + with job_queue_lock: |
| 249 | + print("[agent.step] Lock acquired, executing agent.step()") |
| 250 | + agent.step() |
| 251 | + print("[agent.step] Released lock after agent.step()") |
| 252 | + |
193 | 253 | end_state = AcpState.model_validate(agent.agent_state) |
194 | 254 | print(Panel(f"{end_state}", title="End Agent State", box=box.ROUNDED, title_align="left")) |
195 | 255 | print("🔴"*40) |
196 | 256 | input("\nPress any key to continue...\n") |
197 | 257 |
|
198 | 258 | if __name__ == "__main__": |
199 | | - buyer() |
| 259 | + buyer(use_thread_lock=True) |
0 commit comments