acp-plugin-gamesdk 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ import requests
5
5
  from acp_plugin_gamesdk.interface import AcpAgent, AcpJobPhases, AcpOffering, AcpState
6
6
  from acp_plugin_gamesdk.acp_token import AcpToken, MemoType
7
7
  import time
8
+ import traceback
8
9
 
9
10
 
10
11
  class AcpClient:
@@ -40,7 +41,12 @@ class AcpClient:
40
41
  response = requests.get(url)
41
42
 
42
43
  if response.status_code != 200:
43
- raise Exception(f"Failed to browse agents: {response.text}")
44
+ raise Exception(
45
+ f"Error occured in browse_agents function. Failed to browse agents.\n"
46
+ f"Response status code: {response.status_code}\n"
47
+ f"Response description: {response.text}\n"
48
+ )
49
+
44
50
 
45
51
  response_json = response.json()
46
52
 
@@ -98,7 +104,8 @@ class AcpClient:
98
104
  break
99
105
 
100
106
  except Exception as e:
101
- print(f"Error creating job: {e}")
107
+ print(f"Error in create_job function: {e}")
108
+ print(traceback.format_exc())
102
109
  if attempt < retry_count - 1:
103
110
  time.sleep(retry_delay)
104
111
  else:
@@ -166,7 +173,15 @@ class AcpClient:
166
173
  time.sleep(5)
167
174
  self.acp_token.approve_allowance(amount_wei)
168
175
  time.sleep(5)
169
- return self.acp_token.sign_memo(memo_id, True, reason)
176
+ self.acp_token.sign_memo(memo_id, True, reason)
177
+ time.sleep(5)
178
+ return self.acp_token.create_memo(
179
+ job_id=job_id,
180
+ content=f"Payment of {amount} made {reason}",
181
+ memo_type=MemoType.MESSAGE,
182
+ is_secured=False,
183
+ next_phase=AcpJobPhases.EVALUATION
184
+ )
170
185
 
171
186
  def deliver_job(self, job_id: int, deliverable: str):
172
187
  return self.acp_token.create_memo(
@@ -194,7 +209,11 @@ class AcpClient:
194
209
  )
195
210
 
196
211
  if response.status_code != 200 and response.status_code != 201:
197
- raise Exception(f"Failed to add tweet: {response.status_code} {response.text}")
212
+ raise Exception(
213
+ f"Error occured in add_tweet function. Failed to add tweet.\n"
214
+ f"Response status code: {response.status_code}\n"
215
+ f"Response description: {response.text}\n"
216
+ )
198
217
 
199
218
 
200
219
  return response.json()
@@ -206,4 +225,22 @@ class AcpClient:
206
225
  )
207
226
 
208
227
  if response.status_code not in [200, 204]:
228
+ raise Exception(
229
+ f"Error occured in reset_state function. Failed to reset state\n"
230
+ f"Response status code: {response.status_code}\n"
231
+ f"Response description: {response.text}\n"
232
+ )
209
233
  raise Exception(f"Failed to reset state: {response.status_code} {response.text}")
234
+
235
+ def delete_completed_job(self, job_id: int) -> None:
236
+ response = requests.delete(
237
+ f"{self.base_url}/{job_id}/wallet/{self.agent_wallet_address}",
238
+ headers={"x-api-key": self.api_key}
239
+ )
240
+
241
+ if response.status_code not in [200, 204]:
242
+ raise Exception(
243
+ f"Error occurred in delete_completed_job function. Failed to delete job.\n"
244
+ f"Response status code: {response.status_code}\n"
245
+ f"Response description: {response.text}\n"
246
+ )
@@ -15,7 +15,7 @@ from twitter_plugin_gamesdk.twitter_plugin import TwitterPlugin
15
15
  from twitter_plugin_gamesdk.game_twitter_plugin import GameTwitterPlugin
16
16
  from acp_plugin_gamesdk.acp_client import AcpClient
17
17
  from acp_plugin_gamesdk.acp_token import AcpToken
18
- from acp_plugin_gamesdk.interface import AcpJobPhasesDesc, IDeliverable, IInventory
18
+ from acp_plugin_gamesdk.interface import AcpJobPhasesDesc, IDeliverable, IInventory, AcpJob
19
19
 
20
20
  @dataclass
21
21
  class AcpPluginOptions:
@@ -25,12 +25,15 @@ class AcpPluginOptions:
25
25
  cluster: Optional[str] = None
26
26
  evaluator_cluster: Optional[str] = None
27
27
  on_evaluate: Optional[Callable[[IDeliverable], Tuple[bool, str]]] = None
28
+ on_phase_change: Optional[Callable[[AcpJob], None]] = None
29
+
28
30
 
29
31
  SocketEvents = {
30
32
  "JOIN_EVALUATOR_ROOM": "joinEvaluatorRoom",
31
33
  "LEAVE_EVALUATOR_ROOM": "leaveEvaluatorRoom",
32
34
  "ON_EVALUATE": "onEvaluate",
33
- "ROOM_JOINED" : "roomJoined"
35
+ "ROOM_JOINED" : "roomJoined",
36
+ "ON_PHASE_CHANGE": "onPhaseChange"
34
37
  }
35
38
 
36
39
  class AcpPlugin:
@@ -57,22 +60,29 @@ class AcpPlugin:
57
60
  """
58
61
  self.cluster = options.cluster
59
62
  self.evaluator_cluster = options.evaluator_cluster
60
- self.twitter_plugin = options.twitter_plugin
63
+ self.twitter_plugin = None
64
+ if (options.twitter_plugin is not None):
65
+ self.twitter_plugin = options.twitter_plugin
66
+
61
67
  self.produced_inventory: List[IInventory] = []
62
68
  self.acp_base_url = self.acp_token_client.acp_base_url if self.acp_token_client.acp_base_url is None else "https://acpx-staging.virtuals.io/api"
63
- if (options.on_evaluate is not None):
69
+ if options.on_evaluate is not None or options.on_phase_change is not None:
64
70
  print("Initializing socket")
65
- self.on_evaluate = options.on_evaluate
66
71
  self.socket = None
72
+ if options.on_evaluate is not None:
73
+ self.on_evaluate = options.on_evaluate
74
+ if options.on_phase_change is not None:
75
+ self.on_phase_change = options.on_phase_change
67
76
  self.initializeSocket()
68
77
 
78
+
79
+
69
80
  def initializeSocket(self) -> Tuple[bool, str]:
70
81
  """
71
82
  Initialize socket connection for real-time communication.
72
83
  Returns a tuple of (success, message).
73
84
  """
74
85
  try:
75
- print("Initializing socket after")
76
86
  self.socket = socketio.Client()
77
87
 
78
88
  # Set up authentication before connecting
@@ -97,15 +107,23 @@ class AcpPlugin:
97
107
  is_approved, reasoning = self.on_evaluate(deliverable)
98
108
 
99
109
  self.acp_token_client.sign_memo(memo_id, is_approved, reasoning)
110
+
111
+ # Set up event handler for phase changes
112
+ @self.socket.on(SocketEvents["ON_PHASE_CHANGE"])
113
+ def on_phase_change(data):
114
+ if hasattr(self, 'on_phase_change') and self.on_phase_change:
115
+ print(f"on_phase_change: {data}")
116
+ self.on_phase_change(data)
100
117
 
101
118
  # Set up cleanup function for graceful shutdown
102
119
  def cleanup():
103
120
  if self.socket:
104
121
  print("Disconnecting socket")
105
-
106
122
  import time
107
123
  time.sleep(1)
108
124
  self.socket.disconnect()
125
+
126
+
109
127
 
110
128
  def signal_handler(sig, frame):
111
129
  cleanup()
@@ -120,6 +138,8 @@ class AcpPlugin:
120
138
  return False, f"Failed to initialize socket: {str(e)}"
121
139
 
122
140
 
141
+ def set_on_phase_change(self, on_phase_change: Callable[[AcpJob], None]) -> None:
142
+ self.on_phase_change = on_phase_change
123
143
 
124
144
  def add_produce_item(self, item: IInventory) -> None:
125
145
  self.produced_inventory.append(item)
@@ -127,6 +147,9 @@ class AcpPlugin:
127
147
  def reset_state(self) -> None:
128
148
  self.acp_client.reset_state()
129
149
 
150
+ def delete_completed_job(self, job_id: int) -> None:
151
+ self.acp_client.delete_completed_job(job_id)
152
+
130
153
  def get_acp_state(self) -> Dict:
131
154
  server_state = self.acp_client.get_state()
132
155
  server_state["inventory"]["produced"] = self.produced_inventory
@@ -252,7 +275,7 @@ class AcpPlugin:
252
275
 
253
276
  args = [seller_wallet_address_arg, price_arg, reasoning_arg, service_requirements_arg, require_evaluation_arg, evaluator_keyword_arg]
254
277
 
255
- if self.twitter_plugin is not None:
278
+ if hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None:
256
279
  tweet_content_arg = Argument(
257
280
  name="tweetContent",
258
281
  type="string",
@@ -304,7 +327,7 @@ class AcpPlugin:
304
327
  evaluatorAddress
305
328
  )
306
329
 
307
- if (self.twitter_plugin is not None and tweetContent is not None):
330
+ if (hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None and tweetContent is not None):
308
331
  post_tweet_fn = self.twitter_plugin.get_function('post_tweet')
309
332
  tweet_id = post_tweet_fn(tweetContent, None).get('data', {}).get('id')
310
333
  if (tweet_id is not None):
@@ -343,7 +366,7 @@ class AcpPlugin:
343
366
 
344
367
  args = [job_id_arg, decision_arg, reasoning_arg]
345
368
 
346
- if self.twitter_plugin is not None:
369
+ if hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None:
347
370
  tweet_content_arg = Argument(
348
371
  name="tweetContent",
349
372
  type="string",
@@ -389,7 +412,7 @@ class AcpPlugin:
389
412
  reasoning
390
413
  )
391
414
 
392
- if (self.twitter_plugin is not None and tweetContent is not None):
415
+ if (hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None and tweetContent is not None):
393
416
  tweet_history = job.get("tweetHistory", [])
394
417
  tweet_id = tweet_history[-1].get("tweetId") if tweet_history else None
395
418
  if (tweet_id is not None):
@@ -429,7 +452,7 @@ class AcpPlugin:
429
452
 
430
453
  args = [job_id_arg, amount_arg, reasoning_arg]
431
454
 
432
- if self.twitter_plugin is not None:
455
+ if hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None:
433
456
  tweet_content_arg = Argument(
434
457
  name="tweetContent",
435
458
  type="string",
@@ -476,7 +499,7 @@ class AcpPlugin:
476
499
  reasoning
477
500
  )
478
501
 
479
- if (self.twitter_plugin is not None and tweetContent is not None):
502
+ if (hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None and tweetContent is not None):
480
503
  tweet_history = job.get("tweetHistory", [])
481
504
  tweet_id = tweet_history[-1].get("tweetId") if tweet_history else None
482
505
  if (tweet_id is not None):
@@ -522,7 +545,7 @@ class AcpPlugin:
522
545
 
523
546
  args = [job_id_arg, deliverable_type_arg, deliverable_arg, reasoning_arg]
524
547
 
525
- if self.twitter_plugin is not None:
548
+ if hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None:
526
549
  tweet_content_arg = Argument(
527
550
  name="tweetContent",
528
551
  type="string",
@@ -579,7 +602,8 @@ class AcpPlugin:
579
602
  json.dumps(deliverable),
580
603
  )
581
604
 
582
- if (self.twitter_plugin is not None and tweetContent is not None):
605
+ if (hasattr(self, 'twitter_plugin') and self.twitter_plugin is not None and tweetContent is not None):
606
+
583
607
  tweet_history = job.get("tweetHistory", [])
584
608
  tweet_id = tweet_history[-1].get("tweetId") if tweet_history else None
585
609
  if (tweet_id is not None):
@@ -107,6 +107,7 @@ class AcpToken:
107
107
  ) -> dict:
108
108
  try:
109
109
  provider_address = Web3.to_checksum_address(provider_address)
110
+ evaluator_address = Web3.to_checksum_address(evaluator_address)
110
111
  expire_timestamp = int(expire_at.timestamp())
111
112
 
112
113
  # Sign the transaction
@@ -34,7 +34,13 @@ class AcpJobPhasesDesc(str, Enum):
34
34
  class AcpRequestMemo:
35
35
  id: int
36
36
  created_at: int
37
-
37
+
38
+ @dataclass
39
+ class ITweet:
40
+ type: Literal["buyer", "seller"]
41
+ tweet_id: str
42
+ content: str
43
+ created_at: int
38
44
  @dataclass
39
45
  class AcpJob:
40
46
  job_id: int
@@ -42,6 +48,7 @@ class AcpJob:
42
48
  price: str
43
49
  phase: AcpJobPhasesDesc
44
50
  memo: List[AcpRequestMemo]
51
+ tweet_history : ITweet
45
52
  last_updated: int
46
53
 
47
54
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: acp-plugin-gamesdk
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: ACP Plugin for Python SDK for GAME by Virtuals
5
5
  Author: Steven Lee Soon Fatt
6
6
  Author-email: steven@virtuals.io
@@ -134,7 +134,7 @@ acp_plugin = AcpPlugin(
134
134
  > - This is where you can get your session entity key ID:
135
135
  > ![Session Entity ID](../../docs/imgs/session-entity-id-location.png)
136
136
 
137
- 4. (optional) If you want to use GAME's twitter client with the ACP plugin, you can initialize it by running:
137
+ 4. (Optional) If you want to use GAME's twitter client with the ACP plugin, you can initialize it by running:
138
138
 
139
139
  ```python
140
140
  twitter_client_options = {
@@ -200,7 +200,7 @@ agent = Agent(
200
200
  )
201
201
  ```
202
202
 
203
- 1. Buyer-specific configurations
203
+ 7. Buyer-specific configurations
204
204
 
205
205
  - <i>[Setting buyer agent goal]</i> Define what item needs to be "bought" and which worker to go to look for the item, e.g.
206
206
 
@@ -208,7 +208,7 @@ agent = Agent(
208
208
  agent_goal = "You are an agent that gains market traction by posting memes. Your interest are in cats and AI. You can head to acp to look for agents to help you generate memes."
209
209
  ```
210
210
 
211
- 2. Seller-specific configurations
211
+ 8. Seller-specific configurations
212
212
 
213
213
  - <i>[Setting seller agent goal]</i> Define what item needs to be "sold" and which worker to go to respond to jobs, e.g.
214
214
 
@@ -288,4 +288,5 @@ To register your agent, please head over to the [agent registry](https://acp-sta
288
288
  1. [Agent Commerce Protocol (ACP) research page](https://app.virtuals.io/research/agent-commerce-protocol)
289
289
  - This webpage introduces the Agent Commerce Protocol - A Standard for Permissionless AI Agent Commerce, a piece of research done by the Virtuals Protocol team
290
290
  - It includes the links to the multi-agent demo dashboard and paper.
291
+ 2. [ACP Plugin FAQs](https://virtualsprotocol.notion.site/ACP-Plugin-FAQs-Troubleshooting-Tips-1d62d2a429e980eb9e61de851b6a7d60?pvs=4)
291
292
 
@@ -0,0 +1,8 @@
1
+ acp_plugin_gamesdk/acp_client.py,sha256=JRrlfaRDgP2uZpbX8Vea-uHO6yicn488bmi_IXGVvt8,8896
2
+ acp_plugin_gamesdk/acp_plugin.py,sha256=M4pZ6UyTk60CEA_R2tvKVRezd4CZQOFna94jzrM6_ss,26778
3
+ acp_plugin_gamesdk/acp_token.py,sha256=Wx87e2Wd-5QUKoMWX_wf3IBEP-cl1pSyA9IZr1yYIDE,11796
4
+ acp_plugin_gamesdk/acp_token_abi.py,sha256=nllh9xOuDXxFFdhLklTTdtZxWZd2LcUTBoOP2d9xDTA,22319
5
+ acp_plugin_gamesdk/interface.py,sha256=mWZ41SycGrNQbnC_IfBq8K6TgpguCvvbVTqFg8Uxy58,1549
6
+ acp_plugin_gamesdk-0.1.6.dist-info/METADATA,sha256=w_mr3J8GkBN5AY6IU-CVfKpZG-lv4pu4cMSLOHxN7zw,11545
7
+ acp_plugin_gamesdk-0.1.6.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
8
+ acp_plugin_gamesdk-0.1.6.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- acp_plugin_gamesdk/acp_client.py,sha256=8wHyGL6VIWVTOkmXcYwDd1v_Tp4SqbWHpxXHc4fSl4c,7382
2
- acp_plugin_gamesdk/acp_plugin.py,sha256=UZlC5SqVZw1F7Cg-oez9d7xwYfWJmcnMLDp6SA-QbMs,25459
3
- acp_plugin_gamesdk/acp_token.py,sha256=CL-0Ww1i0tzDNj0sAuY3DvlWIKrEGoMcb0Z69e5X9og,11720
4
- acp_plugin_gamesdk/acp_token_abi.py,sha256=nllh9xOuDXxFFdhLklTTdtZxWZd2LcUTBoOP2d9xDTA,22319
5
- acp_plugin_gamesdk/interface.py,sha256=5jStptqzT_dTlO-d51Xp4PaOVYeFV6uss70GvpLfCEM,1401
6
- acp_plugin_gamesdk-0.1.4.dist-info/METADATA,sha256=iICvWAXJEdNAlbVW06cLm4En1zqUYKq5t0LGQ-K2SAc,11410
7
- acp_plugin_gamesdk-0.1.4.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
8
- acp_plugin_gamesdk-0.1.4.dist-info/RECORD,,