rusticai-forge 0.2.2__tar.gz → 0.2.4__tar.gz

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.
Files changed (23) hide show
  1. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/PKG-INFO +2 -2
  2. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/pyproject.toml +2 -2
  3. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/agent_runner.py +12 -4
  4. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/messaging/backend.py +40 -14
  5. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rusticai_forge.egg-info/PKG-INFO +2 -2
  6. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rusticai_forge.egg-info/requires.txt +1 -1
  7. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/README.md +0 -0
  8. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/setup.cfg +0 -0
  9. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/agent_wrapper.py +0 -0
  10. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/agents/system/guild_manager_agent.py +0 -0
  11. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/agents/system/guild_manager_agent_props.py +0 -0
  12. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/execution_engine.py +0 -0
  13. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/messaging/__init__.py +0 -0
  14. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/messaging/supervisor_backend.py +0 -0
  15. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/metastore/manager_client.py +0 -0
  16. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/testutils/file_manager_agent.py +0 -0
  17. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rustic_ai/forge/testutils/mock_llm_agent.py +0 -0
  18. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rusticai_forge.egg-info/SOURCES.txt +0 -0
  19. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rusticai_forge.egg-info/dependency_links.txt +0 -0
  20. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/src/rusticai_forge.egg-info/top_level.txt +0 -0
  21. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/tests/test_execution_engine.py +0 -0
  22. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/tests/test_forge_api_contract.py +0 -0
  23. {rusticai_forge-0.2.2 → rusticai_forge-0.2.4}/tests/test_forge_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rusticai-forge
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Python agent wrapper and execution engine for Forge
5
5
  Requires-Python: <3.14,>=3.13
6
6
  Description-Content-Type: text/markdown
@@ -8,7 +8,7 @@ Requires-Dist: pydantic<3.0.0,>=2.12.5
8
8
  Requires-Dist: redis<7.0.0,>=6.4.0
9
9
  Requires-Dist: nats-py<3.0.0,>=2.9.0
10
10
  Requires-Dist: pyzmq<27.0.0,>=26.0.0
11
- Requires-Dist: rusticai-core<2.0.0,>=1.1.0
11
+ Requires-Dist: rusticai-core<2.0.0,>=1.2.0
12
12
  Requires-Dist: rusticai-redis<2.0.0,>=1.1.0
13
13
  Requires-Dist: psycopg[binary]<4.0.0,>=3.3.3
14
14
  Requires-Dist: httpx<1.0.0,>=0.28.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rusticai-forge"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "Python agent wrapper and execution engine for Forge"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13,<3.14"
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "nats-py>=2.9.0,<3.0.0",
11
11
  "pyzmq>=26.0.0,<27.0.0",
12
12
  # DO NOT CHANGE THESE TO LOCAL FILE PATHS. Always use package references.
13
- "rusticai-core>=1.1.0,<2.0.0",
13
+ "rusticai-core>=1.2.0,<2.0.0",
14
14
  "rusticai-redis>=1.1.0,<2.0.0",
15
15
  "psycopg[binary]>=3.3.3,<4.0.0",
16
16
  "httpx>=0.28.1,<1.0.0",
@@ -204,10 +204,14 @@ def _load_backend_config(client_props: dict, client_type_str: str) -> dict:
204
204
  raw_backend_config = client_props["backend_config"]
205
205
  else:
206
206
  raw_backend_config = {
207
- key: value for key, value in client_props.items() if key != "organization_id"
207
+ key: value
208
+ for key, value in client_props.items()
209
+ if key != "organization_id"
208
210
  }
209
211
  if not isinstance(raw_backend_config, dict):
210
- raise ValueError("FORGE_CLIENT_PROPERTIES_JSON backend_config must be a JSON object.")
212
+ raise ValueError(
213
+ "FORGE_CLIENT_PROPERTIES_JSON backend_config must be a JSON object."
214
+ )
211
215
 
212
216
  backend_config = dict(raw_backend_config)
213
217
 
@@ -216,7 +220,9 @@ def _load_backend_config(client_props: dict, client_type_str: str) -> dict:
216
220
  if raw_supervisor_config:
217
221
  supervisor_config = json.loads(raw_supervisor_config)
218
222
  if not isinstance(supervisor_config, dict):
219
- raise ValueError(f"{SUPERVISOR_ZMQ_CONFIG_ENV} must decode to a JSON object.")
223
+ raise ValueError(
224
+ f"{SUPERVISOR_ZMQ_CONFIG_ENV} must decode to a JSON object."
225
+ )
220
226
  backend_config = supervisor_config | backend_config
221
227
 
222
228
  endpoint = os.getenv(SUPERVISOR_ZMQ_ENDPOINT_ENV, "")
@@ -248,7 +254,9 @@ def main():
248
254
  client_module_str = os.getenv("FORGE_CLIENT_MODULE", "")
249
255
  client_props = json.loads(os.getenv("FORGE_CLIENT_PROPERTIES_JSON", "{}"))
250
256
  if not isinstance(client_props, dict):
251
- raise ValueError("FORGE_CLIENT_PROPERTIES_JSON must decode to a JSON object.")
257
+ raise ValueError(
258
+ "FORGE_CLIENT_PROPERTIES_JSON must decode to a JSON object."
259
+ )
252
260
 
253
261
  backend_config = _load_backend_config(client_props, client_type_str)
254
262
 
@@ -93,14 +93,18 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
93
93
  response = self._send_request("get_messages", {"topic": topic})
94
94
  return [_normalize_message(msg) for msg in response.get("messages", [])]
95
95
 
96
- def get_messages_for_topic_since(self, topic: str, msg_id_since: int) -> List[Message]:
96
+ def get_messages_for_topic_since(
97
+ self, topic: str, msg_id_since: int
98
+ ) -> List[Message]:
97
99
  response = self._send_request(
98
100
  "get_since",
99
101
  {"topic": topic, "since_id": msg_id_since},
100
102
  )
101
103
  return [_normalize_message(msg) for msg in response.get("messages", [])]
102
104
 
103
- def get_next_message_for_topic_since(self, topic: str, last_message_id: int) -> Optional[Message]:
105
+ def get_next_message_for_topic_since(
106
+ self, topic: str, last_message_id: int
107
+ ) -> Optional[Message]:
104
108
  response = self._send_request(
105
109
  "get_next",
106
110
  {"topic": topic, "since_id": last_message_id},
@@ -142,7 +146,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
142
146
  timeout_ms=min(self.request_timeout_ms, 2_000),
143
147
  )
144
148
  except Exception:
145
- logger.debug("Supervisor cleanup request failed during shutdown", exc_info=True)
149
+ logger.debug(
150
+ "Supervisor cleanup request failed during shutdown", exc_info=True
151
+ )
146
152
 
147
153
  self._shutdown_event.set()
148
154
  self._reconnect_event.set()
@@ -200,7 +206,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
200
206
 
201
207
  def _heartbeat_loop(self) -> None:
202
208
  interval = self.heartbeat_interval_ms / 1000.0
203
- timeout_ms = max(1_000, min(self.request_timeout_ms, self.heartbeat_interval_ms))
209
+ timeout_ms = max(
210
+ 1_000, min(self.request_timeout_ms, self.heartbeat_interval_ms)
211
+ )
204
212
 
205
213
  while not self._shutdown_event.wait(interval):
206
214
  try:
@@ -231,8 +239,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
231
239
  self._drain_outbound(socket)
232
240
 
233
241
  if self._reconnect_event.is_set():
234
- reconnect_cause = self._consume_transport_error() or RuntimeError(
235
- "supervisor ZeroMQ reconnect requested"
242
+ reconnect_cause = (
243
+ self._consume_transport_error()
244
+ or RuntimeError("supervisor ZeroMQ reconnect requested")
236
245
  )
237
246
  socket, poller = self._reset_socket(socket, poller)
238
247
  self._reconnect_event.clear()
@@ -257,7 +266,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
257
266
  finally:
258
267
  self._close_socket(socket, poller)
259
268
 
260
- def _connect_with_retry(self, initial_cause: Exception) -> tuple[Optional[zmq.Socket], Optional[zmq.Poller]]:
269
+ def _connect_with_retry(
270
+ self, initial_cause: Exception
271
+ ) -> tuple[Optional[zmq.Socket], Optional[zmq.Poller]]:
261
272
  attempt = 0
262
273
  delay = self.retry_initial_delay
263
274
  start_time = time.monotonic()
@@ -340,9 +351,14 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
340
351
  continue
341
352
 
342
353
  incoming = socket.recv_json()
343
- if incoming.get("kind") == "response" and incoming.get("request_id") == request_id:
354
+ if (
355
+ incoming.get("kind") == "response"
356
+ and incoming.get("request_id") == request_id
357
+ ):
344
358
  if not incoming.get("ok", False):
345
- raise RuntimeError(incoming.get("error", f"Supervisor {op} request failed"))
359
+ raise RuntimeError(
360
+ incoming.get("error", f"Supervisor {op} request failed")
361
+ )
346
362
  return incoming
347
363
 
348
364
  self._handle_envelope(incoming)
@@ -390,7 +406,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
390
406
  try:
391
407
  handler(message)
392
408
  except Exception:
393
- logger.exception("Supervisor ZeroMQ delivery handler failed for topic %s", topic)
409
+ logger.exception(
410
+ "Supervisor ZeroMQ delivery handler failed for topic %s", topic
411
+ )
394
412
 
395
413
  def _send_request(
396
414
  self,
@@ -409,14 +427,20 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
409
427
  with self._pending_lock:
410
428
  self._pending[request_id] = queue
411
429
 
412
- self._outbound.put({"kind": "request", "op": op, "request_id": request_id} | payload)
430
+ self._outbound.put(
431
+ {"kind": "request", "op": op, "request_id": request_id} | payload
432
+ )
413
433
 
414
434
  try:
415
- response = queue.get(timeout=(timeout_ms or self.request_timeout_ms) / 1000.0)
435
+ response = queue.get(
436
+ timeout=(timeout_ms or self.request_timeout_ms) / 1000.0
437
+ )
416
438
  except Empty as exc:
417
439
  if allow_reconnect:
418
440
  self._mark_transport_unhealthy(exc)
419
- raise TimeoutError(f"Timed out waiting for supervisor response to {op}") from exc
441
+ raise TimeoutError(
442
+ f"Timed out waiting for supervisor response to {op}"
443
+ ) from exc
420
444
  finally:
421
445
  with self._pending_lock:
422
446
  self._pending.pop(request_id, None)
@@ -451,7 +475,9 @@ class SupervisorZmqMessagingBackend(MessagingBackend):
451
475
  self._close_socket(socket, poller)
452
476
  return None, None
453
477
 
454
- def _close_socket(self, socket: Optional[zmq.Socket], poller: Optional[zmq.Poller]) -> None:
478
+ def _close_socket(
479
+ self, socket: Optional[zmq.Socket], poller: Optional[zmq.Poller]
480
+ ) -> None:
455
481
  if socket is None:
456
482
  return
457
483
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rusticai-forge
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Python agent wrapper and execution engine for Forge
5
5
  Requires-Python: <3.14,>=3.13
6
6
  Description-Content-Type: text/markdown
@@ -8,7 +8,7 @@ Requires-Dist: pydantic<3.0.0,>=2.12.5
8
8
  Requires-Dist: redis<7.0.0,>=6.4.0
9
9
  Requires-Dist: nats-py<3.0.0,>=2.9.0
10
10
  Requires-Dist: pyzmq<27.0.0,>=26.0.0
11
- Requires-Dist: rusticai-core<2.0.0,>=1.1.0
11
+ Requires-Dist: rusticai-core<2.0.0,>=1.2.0
12
12
  Requires-Dist: rusticai-redis<2.0.0,>=1.1.0
13
13
  Requires-Dist: psycopg[binary]<4.0.0,>=3.3.3
14
14
  Requires-Dist: httpx<1.0.0,>=0.28.1
@@ -2,7 +2,7 @@ pydantic<3.0.0,>=2.12.5
2
2
  redis<7.0.0,>=6.4.0
3
3
  nats-py<3.0.0,>=2.9.0
4
4
  pyzmq<27.0.0,>=26.0.0
5
- rusticai-core<2.0.0,>=1.1.0
5
+ rusticai-core<2.0.0,>=1.2.0
6
6
  rusticai-redis<2.0.0,>=1.1.0
7
7
  psycopg[binary]<4.0.0,>=3.3.3
8
8
  httpx<1.0.0,>=0.28.1
File without changes
File without changes