jvserve 2.1.6__py3-none-any.whl → 2.1.8__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.

Potentially problematic release.


This version of jvserve might be problematic. Click here for more details.

jvserve/cli.py CHANGED
@@ -21,6 +21,8 @@ from fastapi.middleware.cors import CORSMiddleware
21
21
  from fastapi.responses import FileResponse, StreamingResponse
22
22
  from jac_cloud.core.context import JaseciContext
23
23
  from jac_cloud.jaseci.main import FastAPI as JaseciFastAPI # type: ignore
24
+ from jac_cloud.jaseci.utils import logger
25
+ from jac_cloud.jaseci.utils.logger import Level
24
26
  from jac_cloud.plugin.jaseci import NodeAnchor
25
27
  from jaclang import JacMachine as Jac
26
28
  from jaclang.cli.cmdreg import cmd_registry
@@ -35,20 +37,18 @@ from jvserve.lib.file_interface import (
35
37
  )
36
38
  from jvserve.lib.jvlogger import JVLogger
37
39
 
38
- # quiet the jac_cloud logger down to errors only
39
- # jac cloud dumps payload details to console which makes it hard to debug in JIVAS
40
- os.environ["LOGGER_LEVEL"] = "ERROR"
41
40
  load_dotenv(".env")
42
- # Set up logging
41
+ # quiet the jac_cloud logger down to errors only
42
+ logger.setLevel(Level.ERROR.value)
43
+ # Set up logging for JIVAS
43
44
  JVLogger.setup_logging(level="INFO")
44
- logger = logging.getLogger(__name__)
45
+ jvlogger = logging.getLogger(__name__)
45
46
 
46
47
  # Global for MongoDB collection with thread-safe initialization
47
48
  url_proxy_collection = None
48
49
  collection_init_lock = asyncio.Lock()
49
50
 
50
51
  # Global state for watcher control
51
- WATCHER_STATE_FILE = ".jvserve_watcher_state"
52
52
  watcher_enabled = True
53
53
 
54
54
 
@@ -113,21 +113,21 @@ def start_file_watcher(
113
113
  """File watcher loop that runs in a separate thread"""
114
114
  global watcher_enabled
115
115
 
116
- logger.info(f"Starting file watcher for directory: {watchdir}")
116
+ jvlogger.info(f"Starting file watcher for directory: {watchdir}")
117
117
 
118
118
  try:
119
119
  for changes in watch(watchdir):
120
120
  if watcher_enabled:
121
121
  log_reload(changes)
122
122
  # Kill the current server process and restart
123
- reload_server()
123
+ reload_jivas()
124
124
  else:
125
- logger.info("Watcher disabled, ignoring changes")
125
+ jvlogger.info("Watcher disabled, ignoring changes")
126
126
  time.sleep(1) # Prevent busy loop when disabled
127
127
  except KeyboardInterrupt:
128
- logger.info("File watcher stopped")
128
+ jvlogger.info("File watcher stopped")
129
129
  except Exception as e:
130
- logger.error(f"File watcher error: {e}")
130
+ jvlogger.error(f"File watcher error: {e}")
131
131
 
132
132
  # Start watcher in daemon thread so it doesn't prevent program exit
133
133
  watcher_thread = threading.Thread(target=watcher_loop, daemon=True)
@@ -169,28 +169,28 @@ def run_jivas(filename: str, host: str = "localhost", port: int = 8000) -> None:
169
169
  async with aiohttp.ClientSession() as session:
170
170
  async with session.get(health_url, timeout=1) as response:
171
171
  if response.status == 200:
172
- logger.info("Server is ready, initializing agents...")
172
+ jvlogger.info("Server is ready, initializing agents...")
173
173
  await agent_interface.init_agents()
174
174
  return
175
175
  except (aiohttp.ClientConnectorError, asyncio.TimeoutError) as e:
176
- logger.warning(
176
+ jvlogger.warning(
177
177
  f"Server not ready yet (attempt {attempt + 1} / {max_retries}): {e}"
178
178
  )
179
179
  await asyncio.sleep(retry_delay)
180
180
  retry_delay *= 1.5 # Exponential backoff
181
181
 
182
- logger.error(
182
+ jvlogger.error(
183
183
  "Server did not become ready in time. Agent initialization skipped."
184
184
  )
185
185
 
186
186
  # set up lifespan events
187
187
  async def on_startup() -> None:
188
- logger.info("JIVAS is starting up...")
188
+ jvlogger.info("JIVAS is starting up...")
189
189
  # Start initialization in background without blocking
190
190
  asyncio.create_task(post_startup())
191
191
 
192
192
  async def on_shutdown() -> None:
193
- logger.info("JIVAS is shutting down...")
193
+ jvlogger.info("JIVAS is shutting down...")
194
194
 
195
195
  app = JaseciFastAPI.get()
196
196
  app_lifespan = app.router.lifespan_context
@@ -254,7 +254,7 @@ def run_jivas(filename: str, host: str = "localhost", port: int = 8000) -> None:
254
254
 
255
255
  raise HTTPException(status_code=404, detail="File not found")
256
256
  except Exception as e:
257
- logger.error(f"Proxy error: {str(e)}")
257
+ jvlogger.error(f"Proxy error: {str(e)}")
258
258
  raise HTTPException(status_code=500, detail="Internal server error")
259
259
 
260
260
  ctx.close()
@@ -265,8 +265,7 @@ def run_jivas(filename: str, host: str = "localhost", port: int = 8000) -> None:
265
265
  watchdir = os.path.join(
266
266
  os.path.abspath(os.path.dirname(filename)), "actions", ""
267
267
  )
268
- logger.info("Development mode: Starting file watcher")
269
- enable_watcher()
268
+ jvlogger.info("Development mode: Starting file watcher")
270
269
  start_file_watcher(watchdir, filename, host, port)
271
270
 
272
271
  # Run the app
@@ -277,34 +276,19 @@ def log_reload(changes: set[tuple[Change, str]]) -> None:
277
276
  """Log changes and check watcher state."""
278
277
  global watcher_enabled
279
278
 
280
- logger.warning(f"Watcher is: {watcher_enabled}")
279
+ jvlogger.warning(f"Watcher is: {watcher_enabled}")
281
280
 
282
281
  # Check if watcher is disabled
283
282
  if not watcher_enabled:
284
- logger.warning("Watcher is disabled. Ignoring changes.")
285
283
  return
286
284
 
287
285
  num_of_changes = len(changes)
288
- logger.warning(
286
+ jvlogger.warning(
289
287
  f'Detected {num_of_changes} change{"s" if num_of_changes > 1 else ""}'
290
288
  )
291
289
  for change in changes:
292
- logger.warning(f"{change[1]} ({change[0].name})")
293
- logger.warning("Reloading ...")
294
-
295
-
296
- class JacCmd:
297
- """Jac CLI."""
298
-
299
- @staticmethod
300
- @hookimpl
301
- def create_cmd() -> None:
302
- """Create Jac CLI cmds."""
303
-
304
- @cmd_registry.register
305
- def jvserve(filename: str, host: str = "localhost", port: int = 8000) -> None:
306
- """Launch unified JIVAS server with file services"""
307
- run_jivas(filename, host, port)
290
+ jvlogger.warning(f"{change[1]} ({change[0].name})")
291
+ jvlogger.warning("Reloading ...")
308
292
 
309
293
 
310
294
  def disable_watcher() -> dict:
@@ -312,8 +296,6 @@ def disable_watcher() -> dict:
312
296
  if os.environ.get("JIVAS_ENVIRONMENT") == "development":
313
297
  global watcher_enabled
314
298
  watcher_enabled = False
315
- with open(WATCHER_STATE_FILE, "w") as f:
316
- f.write("disabled")
317
299
  return {"message": "Watcher disabled"}
318
300
  else:
319
301
  return {"message": "Watcher already disabled"}
@@ -324,40 +306,52 @@ def enable_watcher() -> dict:
324
306
  if os.environ.get("JIVAS_ENVIRONMENT") == "development":
325
307
  global watcher_enabled
326
308
  watcher_enabled = True
327
- with open(WATCHER_STATE_FILE, "w") as f:
328
- f.write("enabled")
329
309
  return {"message": "Watcher enabled"}
330
310
  else:
331
311
  return {"message": "Watcher already enabled"}
332
312
 
333
313
 
334
- def reload_server() -> None:
335
- """Reload the server using the exact command that started it."""
314
+ def reload_jivas() -> None:
315
+ """Reload the server, handling virtual environments robustly."""
336
316
  try:
337
- # Get the command used to start the sever
317
+ # Use sys.executable to ensure correct Python interpreter (handles venv)
338
318
  current_process = psutil.Process(os.getpid())
339
319
  cmdline = current_process.cmdline()
340
-
341
- logger.info(f"Restarting with command: {' '.join(cmdline)}")
342
-
343
- # Replace current process with the same command
344
- os.execvp(cmdline[0], cmdline)
345
-
320
+ if cmdline:
321
+ # Replace executable with sys.executable if different (for venv safety)
322
+ exec_path = sys.executable
323
+ if os.path.exists(exec_path):
324
+ cmdline[0] = exec_path
325
+ jvlogger.info(f"Restarting with command: {' '.join(cmdline)}")
326
+ os.execvp(exec_path, cmdline)
327
+ else:
328
+ raise RuntimeError("sys.executable does not exist")
329
+ else:
330
+ raise RuntimeError("Invalid cmdline from psutil")
346
331
  except Exception as e:
347
- logger.error(f"Failed to get process command line: {e}")
348
- # Fallback to sys.argv
349
- reload_server_from_argv()
350
- finally:
351
- is_development = os.environ.get("JIVAS_ENVIRONMENT") == "development"
352
-
353
- if is_development:
354
- enable_watcher()
332
+ jvlogger.error(f"Failed to reload using psutil cmdline: {e}")
333
+ # Fallback to sys.argv if psutil fails or cmdline is not usable
334
+ reload_jivas_from_argv()
355
335
 
356
336
 
357
- def reload_server_from_argv() -> None:
337
+ def reload_jivas_from_argv() -> None:
358
338
  """Reload using sys.argv (the original command line arguments)."""
359
- logger.info("Reloading server using sys.argv...")
360
- logger.info(f"Original command: {' '.join(sys.argv)}")
339
+ jvlogger.info("Reloading server using sys.argv...")
340
+ jvlogger.info(f"Original command: {' '.join(sys.argv)}")
361
341
 
362
342
  # sys.argv[0] is the script name, rest are arguments
363
343
  os.execvp(sys.executable, [sys.executable] + sys.argv)
344
+
345
+
346
+ class JacCmd:
347
+ """Jac CLI."""
348
+
349
+ @staticmethod
350
+ @hookimpl
351
+ def create_cmd() -> None:
352
+ """Create Jac CLI cmds."""
353
+
354
+ @cmd_registry.register
355
+ def jvserve(filename: str, host: str = "localhost", port: int = 8000) -> None:
356
+ """Launch unified JIVAS server with file services"""
357
+ run_jivas(filename, host, port)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jvserve
3
- Version: 2.1.6
3
+ Version: 2.1.8
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.
@@ -1,13 +1,13 @@
1
1
  jvserve/__init__.py,sha256=Jd0pamSDn2wGTZkNk8I9qNYTFBHp7rasdYO0_Dvad_k,245
2
- jvserve/cli.py,sha256=BThAXt_0csFd7Z6Hytr8usQ7gh-zfnqmh9kLWvVVKZc,12861
2
+ jvserve/cli.py,sha256=uQdHWJxI_Xl-hFGEanDRQWrkNJ3p3HXqt019I6e9Igk,12884
3
3
  jvserve/lib/__init__.py,sha256=cnzfSHLoTWG9Ygut2nOpDys5aPlQz-m0BSkB-nd7OMs,31
4
4
  jvserve/lib/agent_interface.py,sha256=Igv5Jb7i9Aq_7IbLDZ6jnldGKssAWKeb6iXoolX8u4k,3478
5
5
  jvserve/lib/file_interface.py,sha256=VO9RBCtJwaBxu5eZjc57-uRbsVXXZt86wVRVq9R3KXY,6079
6
6
  jvserve/lib/jac_interface.py,sha256=ydhXfYTsrhdvMXBTAd_vnAXJSSVBydQ3qavPU1-oodU,7973
7
7
  jvserve/lib/jvlogger.py,sha256=RNiB9PHuBzTvNIQWhxoDgrDlNYA0PYm1SVpvzlqu8mE,4180
8
- jvserve-2.1.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
- jvserve-2.1.6.dist-info/METADATA,sha256=IdC359dfxjBhEyqAaWLCDrpwgFl_ohjQUNggqooqbo4,4820
10
- jvserve-2.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- jvserve-2.1.6.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
12
- jvserve-2.1.6.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
13
- jvserve-2.1.6.dist-info/RECORD,,
8
+ jvserve-2.1.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
+ jvserve-2.1.8.dist-info/METADATA,sha256=-pjSBZHf1eF4HnEQyvCxosEMI2mxa74voz9e6YkyRuU,4820
10
+ jvserve-2.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ jvserve-2.1.8.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
12
+ jvserve-2.1.8.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
13
+ jvserve-2.1.8.dist-info/RECORD,,