loreguard-cli 0.12.0__tar.gz → 0.12.2__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 (59) hide show
  1. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/PKG-INFO +1 -1
  2. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/pyproject.toml +1 -1
  3. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/main.py +26 -2
  4. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/running.py +19 -0
  5. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/npc_chat.py +12 -4
  6. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/wizard.py +1 -1
  7. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/uv.lock +1 -1
  8. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/.claude/skills/llama-cpp-troubleshooting/SKILL.md +0 -0
  9. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/.env.example +0 -0
  10. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/.github/workflows/release.yml +0 -0
  11. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/.gitignore +0 -0
  12. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/LICENSE +0 -0
  13. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/README.md +0 -0
  14. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/THIRD_PARTY_NOTICES.md +0 -0
  15. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/scripts/build.py +0 -0
  16. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/sdk/csharp/LoreguardSDK.cs +0 -0
  17. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/sdk/gdscript/LoreguardSDK.gd +0 -0
  18. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/sdk/javascript/loreguard-sdk.js +0 -0
  19. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/sdk/python/loreguard_sdk.py +0 -0
  20. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/__init__.py +0 -0
  21. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/__main__.py +0 -0
  22. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/chunk_detector.py +0 -0
  23. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/cli.py +0 -0
  24. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/config.py +0 -0
  25. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/dialogue_act_classifier.py +0 -0
  26. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/hf_discovery.py +0 -0
  27. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/http_server.py +0 -0
  28. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/intent_classifier.py +0 -0
  29. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/llama_server.py +0 -0
  30. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/llm.py +0 -0
  31. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/main.py +0 -0
  32. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/models_registry.py +0 -0
  33. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/nli.py +0 -0
  34. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/npc_chat.py +0 -0
  35. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/runtime.py +0 -0
  36. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/steam.py +0 -0
  37. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/term_ui.py +0 -0
  38. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/__init__.py +0 -0
  39. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/app.py +0 -0
  40. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/modals/__init__.py +0 -0
  41. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/modals/auth_menu.py +0 -0
  42. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/modals/npc_chat.py +0 -0
  43. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/modals/token_input.py +0 -0
  44. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/modals/unified_palette.py +0 -0
  45. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/__init__.py +0 -0
  46. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/auth.py +0 -0
  47. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/model_select.py +0 -0
  48. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/screens/nli_setup.py +0 -0
  49. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/styles.py +0 -0
  50. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/__init__.py +0 -0
  51. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/banner.py +0 -0
  52. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/footer.py +0 -0
  53. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/hardware_info.py +0 -0
  54. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/server_monitor.py +0 -0
  55. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tui/widgets/status_panel.py +0 -0
  56. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/src/tunnel.py +0 -0
  57. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/templates/llama31-no-tools.jinja +0 -0
  58. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/tests/test_nli_hhem.py +0 -0
  59. {loreguard_cli-0.12.0 → loreguard_cli-0.12.2}/tests/test_websocket_timeout.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: loreguard-cli
3
- Version: 0.12.0
3
+ Version: 0.12.2
4
4
  Summary: Local inference client for Loreguard NPCs
5
5
  Project-URL: Homepage, https://loreguard.com
6
6
  Project-URL: Documentation, https://github.com/beyond-logic-labs/loreguard-cli#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "loreguard-cli"
7
- version = "0.12.0"
7
+ version = "0.12.2"
8
8
  description = "Local inference client for Loreguard NPCs"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -580,6 +580,28 @@ class MainScreen(Screen):
580
580
  self._log(f"Dialogue act classifier error: {e}", "error")
581
581
  dialogue_act_classifier = None
582
582
 
583
+ # Initialize chunk detector (ADR-0023) - shares DeBERTa model with intent classifier
584
+ chunk_detector = None
585
+ try:
586
+ from ...chunk_detector import ChunkDetector
587
+
588
+ chunk_detector = ChunkDetector()
589
+ if intent_classifier is not None and intent_classifier._classifier is not None:
590
+ chunk_detector.set_classifier(intent_classifier._classifier)
591
+ self._log("Chunk detector ready (shared model)", "success")
592
+ else:
593
+ loop = asyncio.get_event_loop()
594
+ with concurrent.futures.ThreadPoolExecutor() as pool:
595
+ with suppress_external_output():
596
+ if await loop.run_in_executor(pool, chunk_detector.load_model):
597
+ self._log(f"Chunk detector ready ({chunk_detector.device})", "success")
598
+ else:
599
+ self._log("Chunk detector failed to load", "warning")
600
+ chunk_detector = None
601
+ except Exception as e:
602
+ self._log(f"Chunk detector error: {e}", "error")
603
+ chunk_detector = None
604
+
583
605
  self._update_status("Connecting to backend...", log=False)
584
606
  self._log("Connecting to Loreguard backend...")
585
607
 
@@ -628,6 +650,7 @@ class MainScreen(Screen):
628
650
  nli_service=nli_service,
629
651
  intent_classifier=intent_classifier,
630
652
  dialogue_act_classifier=dialogue_act_classifier,
653
+ chunk_detector=chunk_detector,
631
654
  log_callback=log_callback,
632
655
  max_retries=0, # Single try, no retries
633
656
  )
@@ -641,11 +664,12 @@ class MainScreen(Screen):
641
664
 
642
665
  # Wire up pass update callback to chat widget (for verbose mode)
643
666
  def on_pass_update(payload: dict) -> None:
667
+ log.debug(f"tunnel on_pass_update callback fired, payload keys: {list(payload.keys()) if payload else 'None'}")
644
668
  try:
645
669
  chat = self.query_one(NPCChat)
646
670
  chat.on_pass_update(payload)
647
- except Exception:
648
- pass
671
+ except Exception as e:
672
+ log.debug(f"tunnel on_pass_update callback error: {e}")
649
673
 
650
674
  app._tunnel.on_pass_update = on_pass_update
651
675
 
@@ -284,6 +284,24 @@ class RunningScreen(Screen):
284
284
  self._log(f"Dialogue act classifier error: {e}", "error")
285
285
  dialogue_act_classifier = None
286
286
 
287
+ # Initialize chunk detector (ADR-0023) - shares DeBERTa model with intent classifier
288
+ chunk_detector = None
289
+ try:
290
+ from ...chunk_detector import ChunkDetector
291
+
292
+ chunk_detector = ChunkDetector()
293
+ if intent_classifier is not None and intent_classifier._classifier is not None:
294
+ chunk_detector.set_classifier(intent_classifier._classifier)
295
+ self._log("Chunk detector ready (shared model)", "success")
296
+ else:
297
+ if await asyncio.to_thread(chunk_detector.load_model):
298
+ self._log(f"Chunk detector ready ({chunk_detector.device})", "success")
299
+ else:
300
+ chunk_detector = None
301
+ except Exception as e:
302
+ self._log(f"Chunk detector error: {e}", "error")
303
+ chunk_detector = None
304
+
287
305
  # Get model ID for backend
288
306
  model_id = app.model_path.stem
289
307
 
@@ -296,6 +314,7 @@ class RunningScreen(Screen):
296
314
  nli_service=nli_service,
297
315
  intent_classifier=intent_classifier,
298
316
  dialogue_act_classifier=dialogue_act_classifier,
317
+ chunk_detector=chunk_detector,
299
318
  log_callback=self._log,
300
319
  )
301
320
  self._tunnel.on_request_complete = self._on_request_complete
@@ -5,9 +5,12 @@ Uses the local proxy for NPC conversations with token streaming:
5
5
  """
6
6
 
7
7
  import json
8
+ import logging
8
9
  from typing import TYPE_CHECKING
9
10
 
10
11
  import httpx
12
+
13
+ logger = logging.getLogger(__name__)
11
14
  from textual.app import ComposeResult
12
15
  from textual.containers import Vertical, Horizontal, VerticalScroll
13
16
  from textual.widgets import Static, Input
@@ -799,11 +802,11 @@ class NPCChat(Vertical):
799
802
  if self._verbose:
800
803
  payload["verbose"] = True
801
804
 
805
+ local_url = get_local_proxy_url()
802
806
  try:
803
807
  await self._do_generate_streaming(payload, status, container)
804
808
  return
805
809
  except httpx.ConnectError as e:
806
- local_url = get_local_proxy_url()
807
810
  if self._verbose:
808
811
  if local_url:
809
812
  status.update(Text(f"Local proxy failed ({local_url}): {e}", style=FG_DIM))
@@ -812,7 +815,6 @@ class NPCChat(Vertical):
812
815
  else:
813
816
  status.update(Text("Local proxy unavailable, using cloud...", style=FG_DIM))
814
817
  except Exception as e:
815
- local_url = get_local_proxy_url()
816
818
  if self._verbose:
817
819
  status.update(Text(f"Local proxy error ({local_url}): {type(e).__name__}: {e}", style="#FF5555"))
818
820
  else:
@@ -895,6 +897,9 @@ class NPCChat(Vertical):
895
897
  container.scroll_end(animate=False)
896
898
  status.update(Text(f"Streaming... ({tokens_received} tokens)", style=CYAN))
897
899
 
900
+ elif event_type == "pass_update":
901
+ self.on_pass_update(data)
902
+
898
903
  elif event_type == "done":
899
904
  final_data = data
900
905
  speech = data.get("speech", speech)
@@ -987,15 +992,18 @@ class NPCChat(Vertical):
987
992
 
988
993
  Called by the tunnel when it receives pass updates via WebSocket.
989
994
  """
995
+ logger.debug(f"on_pass_update called: verbose={self._verbose}, visible={self._visible}, payload_keys={list(payload.keys()) if payload else 'None'}")
990
996
  if not self._verbose or not self._visible:
997
+ logger.debug(f"on_pass_update skipped: verbose={self._verbose}, visible={self._visible}")
991
998
  return
992
999
 
993
1000
  # Add pass to debug panel instead of chat
994
1001
  try:
995
1002
  debug_panel = self.query_one(DebugPanel)
996
1003
  debug_panel.add_pass(payload)
997
- except Exception:
998
- pass
1004
+ logger.debug(f"on_pass_update: added pass to debug panel")
1005
+ except Exception as e:
1006
+ logger.debug(f"on_pass_update exception: {e}")
999
1007
 
1000
1008
  def action_close_chat(self) -> None:
1001
1009
  """Close the chat widget."""
@@ -1596,7 +1596,7 @@ async def step_start(
1596
1596
  status.stop()
1597
1597
  from .npc_chat import run_npc_chat
1598
1598
  try:
1599
- await run_npc_chat(api_token=token, tunnel=tunnel)
1599
+ await run_npc_chat(api_token=token, tunnel=tunnel, verbose=_verbose)
1600
1600
  except KeyboardInterrupt:
1601
1601
  pass
1602
1602
  status.start()
@@ -600,7 +600,7 @@ wheels = [
600
600
 
601
601
  [[package]]
602
602
  name = "loreguard-cli"
603
- version = "0.11.2"
603
+ version = "0.12.2"
604
604
  source = { editable = "." }
605
605
  dependencies = [
606
606
  { name = "aiofiles" },
File without changes
File without changes