jvserve 2.1.15__py3-none-any.whl → 2.1.17__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.
jvserve/cli.py CHANGED
@@ -33,6 +33,7 @@ from typing_extensions import Any
33
33
  from watchfiles import Change, watch
34
34
 
35
35
  from jvserve.lib.agent_interface import AgentInterface
36
+ from jvserve.lib.agent_pulse import AgentPulse
36
37
  from jvserve.lib.file_interface import (
37
38
  DEFAULT_FILES_ROOT,
38
39
  FILE_INTERFACE,
@@ -220,6 +221,7 @@ def run_jivas(filename: str, host: str = "localhost", port: int = 8000) -> None:
220
221
 
221
222
  async def on_shutdown() -> None:
222
223
  jvlogger.info("JIVAS is shutting down...")
224
+ AgentPulse.stop()
223
225
 
224
226
  app = JaseciFastAPI.get()
225
227
  app_lifespan = app.router.lifespan_context
@@ -15,6 +15,7 @@ class AgentInterface:
15
15
 
16
16
  _instance = None
17
17
  logger = logging.getLogger(__name__)
18
+ timeout = int(os.environ.get("JIVAS_REQUEST_TIMEOUT", 30))
18
19
 
19
20
  def __init__(self, host: str = "localhost", port: int = 8000) -> None:
20
21
  """Initialize the AgentInterface with JacInterface."""
@@ -49,8 +50,10 @@ class AgentInterface:
49
50
  def api_pulse(self, action_label: str, agent_id: str) -> dict:
50
51
  """Synchronous pulse API call"""
51
52
  if not self._jac.is_valid():
52
- self.logger.warning("Invalid API state for pulse")
53
- return {}
53
+ self.logger.warning(
54
+ "Invalid API state for pulse, attempting to reinstate it..."
55
+ )
56
+ self._jac._authenticate()
54
57
 
55
58
  # Clean parameters
56
59
  action_label = action_label.replace("action_label=", "")
@@ -62,7 +65,7 @@ class AgentInterface:
62
65
 
63
66
  try:
64
67
  response = requests.post(
65
- endpoint, json=payload, headers=headers, timeout=10
68
+ endpoint, json=payload, headers=headers, timeout=self.timeout
66
69
  )
67
70
  if response.status_code == 200:
68
71
  return response.json().get("reports", {})
@@ -0,0 +1,63 @@
1
+ """Agent Pulse class for scheduling and running agent jobs."""
2
+
3
+ import logging
4
+ import threading
5
+ import time
6
+
7
+ import schedule
8
+
9
+
10
+ class AgentPulse:
11
+ """Agent Pulse class for scheduling and running agent jobs."""
12
+
13
+ EVENT = None
14
+ THREAD = None
15
+ LOGGER = logging.getLogger(__name__)
16
+
17
+ @staticmethod
18
+ def start(interval: int = 1) -> threading.Event:
19
+ """Starts the agent pulse in a separate thread that executes
20
+ pending jobs at each elapsed time interval.
21
+
22
+ This method ensures that only one thread is running at a time
23
+ to prevent duplication. If a thread is already running, it logs
24
+ a message and returns without starting a new thread.
25
+
26
+ @param interval: Time in seconds between each execution cycle of
27
+ scheduled jobs.
28
+ @return: threading.Event which can be set to stop the running
29
+ thread.
30
+
31
+ Note: It is intended behavior that run_continuously() does not
32
+ run missed jobs. For instance, a job scheduled to run every
33
+ minute with a run interval of one hour will only run once per
34
+ hour, not 60 times at once.
35
+ """
36
+
37
+ if AgentPulse.THREAD and AgentPulse.THREAD.is_alive():
38
+ AgentPulse.LOGGER.info("agent pulse is already running.")
39
+ return AgentPulse.EVENT
40
+
41
+ AgentPulse.EVENT = threading.Event()
42
+
43
+ class ScheduleThread(threading.Thread):
44
+ def run(self) -> None:
45
+ while AgentPulse.EVENT and not AgentPulse.EVENT.is_set():
46
+ schedule.run_pending()
47
+ time.sleep(interval)
48
+
49
+ AgentPulse.THREAD = ScheduleThread()
50
+ AgentPulse.THREAD.start()
51
+
52
+ AgentPulse.LOGGER.info("agent pulse started.")
53
+
54
+ return AgentPulse.EVENT
55
+
56
+ @staticmethod
57
+ def stop() -> None:
58
+ """Stops the agent pulse."""
59
+ if AgentPulse.EVENT and not AgentPulse.EVENT.is_set():
60
+ AgentPulse.LOGGER.info("agent pulse stopped.")
61
+ AgentPulse.EVENT.set()
62
+ if AgentPulse.THREAD:
63
+ AgentPulse.THREAD.join()
@@ -25,6 +25,8 @@ from jaclang.runtimelib.machine import JacMachine
25
25
  class JacInterface:
26
26
  """Thread-safe connection and context state provider for Jac Runtime with auto-authentication."""
27
27
 
28
+ timeout = int(os.environ.get("JIVAS_REQUEST_TIMEOUT", 30))
29
+
28
30
  def __init__(self, host: str = "localhost", port: int = 8000) -> None:
29
31
  """Initialize JacInterface with host and port."""
30
32
  self.host = host
@@ -155,7 +157,9 @@ class JacInterface:
155
157
  try:
156
158
  # Try login first
157
159
  response = requests.post(
158
- login_url, json={"email": user, "password": password}, timeout=15
160
+ login_url,
161
+ json={"email": user, "password": password},
162
+ timeout=self.timeout,
159
163
  )
160
164
  self.logger.info(f"Login response status: {response.status_code}")
161
165
  if response.status_code == 200:
@@ -164,7 +168,9 @@ class JacInterface:
164
168
 
165
169
  # Register if login fails
166
170
  reg_response = requests.post(
167
- register_url, json={"email": user, "password": password}, timeout=15
171
+ register_url,
172
+ json={"email": user, "password": password},
173
+ timeout=self.timeout,
168
174
  )
169
175
  self.logger.info(
170
176
  f"Register response status: {reg_response.status_code}"
@@ -174,7 +180,7 @@ class JacInterface:
174
180
  login_response = requests.post(
175
181
  login_url,
176
182
  json={"email": user, "password": password},
177
- timeout=15,
183
+ timeout=self.timeout,
178
184
  )
179
185
  self.logger.info(
180
186
  f"Retry login response status: {login_response.status_code}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jvserve
3
- Version: 2.1.15
3
+ Version: 2.1.17
4
4
  Summary: FastAPI webserver for loading and interaction with JIVAS agents.
5
5
  Home-page: https://github.com/TrueSelph/jvserve
6
6
  Author: TrueSelph Inc.
@@ -0,0 +1,14 @@
1
+ jvserve/__init__.py,sha256=Jd0pamSDn2wGTZkNk8I9qNYTFBHp7rasdYO0_Dvad_k,245
2
+ jvserve/cli.py,sha256=b1AHsiJUsMVHZ7ZOKhrOJSvISPh5O5O020aoDJQJ0Rk,13910
3
+ jvserve/lib/__init__.py,sha256=cnzfSHLoTWG9Ygut2nOpDys5aPlQz-m0BSkB-nd7OMs,31
4
+ jvserve/lib/agent_interface.py,sha256=p7Fofd5q6Fk-Q900qbvPu2gB4TemPJFkOPgSq1w-oyk,3628
5
+ jvserve/lib/agent_pulse.py,sha256=6hBF6KQYr6Z9Mi_yoWKGfdnW7gg84kK20Slu-bLR_m8,2067
6
+ jvserve/lib/file_interface.py,sha256=VO9RBCtJwaBxu5eZjc57-uRbsVXXZt86wVRVq9R3KXY,6079
7
+ jvserve/lib/jac_interface.py,sha256=7LuY_ddG9qANgRWk7i7Oum6cX_EzB_mYAH7YYRH7ytQ,8149
8
+ jvserve/lib/jvlogger.py,sha256=RNiB9PHuBzTvNIQWhxoDgrDlNYA0PYm1SVpvzlqu8mE,4180
9
+ jvserve-2.1.17.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
10
+ jvserve-2.1.17.dist-info/METADATA,sha256=03dypxwccncxgYacVU4cPQ53ncrkMd4Gc9g425UmTNs,4821
11
+ jvserve-2.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ jvserve-2.1.17.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
13
+ jvserve-2.1.17.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
14
+ jvserve-2.1.17.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- jvserve/__init__.py,sha256=Jd0pamSDn2wGTZkNk8I9qNYTFBHp7rasdYO0_Dvad_k,245
2
- jvserve/cli.py,sha256=LR6PbEWStL3eSErplA_K7U8ZY_5pDYGYJbZLV1oTlkw,13837
3
- jvserve/lib/__init__.py,sha256=cnzfSHLoTWG9Ygut2nOpDys5aPlQz-m0BSkB-nd7OMs,31
4
- jvserve/lib/agent_interface.py,sha256=Igv5Jb7i9Aq_7IbLDZ6jnldGKssAWKeb6iXoolX8u4k,3478
5
- jvserve/lib/file_interface.py,sha256=VO9RBCtJwaBxu5eZjc57-uRbsVXXZt86wVRVq9R3KXY,6079
6
- jvserve/lib/jac_interface.py,sha256=ydhXfYTsrhdvMXBTAd_vnAXJSSVBydQ3qavPU1-oodU,7973
7
- jvserve/lib/jvlogger.py,sha256=RNiB9PHuBzTvNIQWhxoDgrDlNYA0PYm1SVpvzlqu8mE,4180
8
- jvserve-2.1.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
- jvserve-2.1.15.dist-info/METADATA,sha256=IxIo1aY9pcqIiLIPd3UQbZZN58fNVTtyX1bHOZEiQAc,4821
10
- jvserve-2.1.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- jvserve-2.1.15.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
12
- jvserve-2.1.15.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
13
- jvserve-2.1.15.dist-info/RECORD,,