soliplex 0.78__tar.gz → 0.78.1__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 (95) hide show
  1. {soliplex-0.78/src/soliplex.egg-info → soliplex-0.78.1}/PKG-INFO +1 -1
  2. {soliplex-0.78 → soliplex-0.78.1}/pyproject.toml +1 -1
  3. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/audit.py +75 -41
  4. {soliplex-0.78 → soliplex-0.78.1/src/soliplex.egg-info}/PKG-INFO +1 -1
  5. {soliplex-0.78 → soliplex-0.78.1}/LICENSE +0 -0
  6. {soliplex-0.78 → soliplex-0.78.1}/MANIFEST.in +0 -0
  7. {soliplex-0.78 → soliplex-0.78.1}/README.md +0 -0
  8. {soliplex-0.78 → soliplex-0.78.1}/example/skills/bare-bones/SKILL.md +0 -0
  9. {soliplex-0.78 → soliplex-0.78.1}/example/skills/stanzas/SKILL.md +0 -0
  10. {soliplex-0.78 → soliplex-0.78.1}/setup.cfg +0 -0
  11. {soliplex-0.78 → soliplex-0.78.1}/skills/soliplex-docs/SKILL.md +0 -0
  12. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agents.py +0 -0
  13. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agui/__init__.py +0 -0
  14. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agui/parser.py +0 -0
  15. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agui/persistence.py +0 -0
  16. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agui/schema.py +0 -0
  17. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/agui/util.py +0 -0
  18. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/authn.py +0 -0
  19. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/authz/__init__.py +0 -0
  20. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/authz/persistence.py +0 -0
  21. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/authz/schema.py +0 -0
  22. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/capabilities/filesystem.py +0 -0
  23. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/capabilities/rag_audit.py +0 -0
  24. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/admin_users.py +0 -0
  25. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/ask.py +0 -0
  26. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/cli_util.py +0 -0
  27. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/main.py +0 -0
  28. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/ollama.py +0 -0
  29. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/room_authz.py +0 -0
  30. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/serve.py +0 -0
  31. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/cli/types.py +0 -0
  32. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/completions.py +0 -0
  33. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/__init__.py +0 -0
  34. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/_utils.py +0 -0
  35. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/agents.py +0 -0
  36. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/agui.py +0 -0
  37. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/authsystem.py +0 -0
  38. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/completions.py +0 -0
  39. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/exceptions.py +0 -0
  40. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/installation.py +0 -0
  41. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/logfire.py +0 -0
  42. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/meta.py +0 -0
  43. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/middleware.py +0 -0
  44. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/quizzes.py +0 -0
  45. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/rag.py +0 -0
  46. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/rooms.py +0 -0
  47. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/routing.py +0 -0
  48. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/secrets.py +0 -0
  49. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/skills.py +0 -0
  50. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/config/tools.py +0 -0
  51. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/examples.py +0 -0
  52. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/installation.py +0 -0
  53. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/log_ingest.py +0 -0
  54. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/loggers.py +0 -0
  55. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/main.py +0 -0
  56. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/mcp_auth.py +0 -0
  57. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/mcp_client.py +0 -0
  58. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/mcp_server.py +0 -0
  59. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/models.py +0 -0
  60. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/ollama.py +0 -0
  61. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/quizzes.py +0 -0
  62. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/rag_audit.py +0 -0
  63. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/sandbox_audit.py +0 -0
  64. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/secrets.py +0 -0
  65. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/skills/bwrap_sandbox/SKILL.md +0 -0
  66. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/skills/bwrap_sandbox/__init__.py +0 -0
  67. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/titles.py +0 -0
  68. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tools/__init__.py +0 -0
  69. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tools/agui_run_feedback.py +0 -0
  70. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tools/file_uploads.py +0 -0
  71. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tools/rag.py +0 -0
  72. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tui/cli.py +0 -0
  73. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tui/main.py +0 -0
  74. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tui/rest_api.py +0 -0
  75. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/tui/serve.py +0 -0
  76. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/util.py +0 -0
  77. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/__init__.py +0 -0
  78. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/agui.py +0 -0
  79. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/authn.py +0 -0
  80. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/authz.py +0 -0
  81. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/completions.py +0 -0
  82. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/installation.py +0 -0
  83. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/log_ingest.py +0 -0
  84. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/quizzes.py +0 -0
  85. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/room_file_uploads.py +0 -0
  86. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/rooms.py +0 -0
  87. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/sandbox_workdirs.py +0 -0
  88. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/stats.py +0 -0
  89. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/streaming.py +0 -0
  90. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex/views/thread_file_uploads.py +0 -0
  91. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex.egg-info/SOURCES.txt +0 -0
  92. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex.egg-info/dependency_links.txt +0 -0
  93. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex.egg-info/entry_points.txt +0 -0
  94. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex.egg-info/requires.txt +0 -0
  95. {soliplex-0.78 → soliplex-0.78.1}/src/soliplex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soliplex
3
- Version: 0.78
3
+ Version: 0.78.1
4
4
  Summary: An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface.
5
5
  Author-email: Enfold <info@enfoldsystems.net>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "soliplex"
7
- version = "0.78"
7
+ version = "0.78.1"
8
8
  description = "An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface."
9
9
  authors = [{ name = "Enfold", email = "info@enfoldsystems.net" }]
10
10
  readme = "README.md"
@@ -568,22 +568,39 @@ async def _list_admin_discriminators(dburi):
568
568
  return await policy.list_admin_user_discriminators()
569
569
 
570
570
 
571
- def _room_authz_groups(the_installation):
572
- """Bucket configured rooms by authorization state; collect stale rows."""
573
- configured = sorted(the_installation._config.room_configs)
571
+ def _room_policies(the_installation) -> tuple[list, str | None]:
572
+ """Return ``(policies, error)`` for the stored room policies.
573
+
574
+ ``policies`` holds the unchecked policy models read via
575
+ 'RoomAuthorizationPolicy.list_room_policies' and ``error`` is ``None``
576
+ on success. A RAM-based authz DB can hold no persisted rows, so it
577
+ short-circuits to ``([], None)`` without touching the database.
578
+
579
+ When the database itself cannot be reached -- e.g. its DBURI names a
580
+ Postgres server that isn't listening -- ``policies`` is empty and
581
+ ``error`` carries the exception message, so the audit can report the
582
+ unreachable DB instead of dying on the traceback.
583
+ """
574
584
  dburi = the_installation.authorization_dburi_async
575
585
 
576
586
  if dburi in cli_util._RAM_DBURIS:
577
- return {
578
- "default": list(configured),
579
- "public": [],
580
- "private": [],
581
- "stale": [],
582
- }
587
+ return [], None
588
+
589
+ try:
590
+ return list(asyncio.run(_list_room_policies(dburi))), None
591
+ except Exception as exc:
592
+ return [], f"{type(exc).__name__}: {exc}"
593
+
594
+
595
+ def _room_authz_groups(the_installation, room_policies):
596
+ """Bucket configured rooms by authorization state; collect stale rows.
597
+
598
+ ``room_policies`` is the policy list from '_room_policies'.
599
+ """
600
+ configured = sorted(the_installation._config.room_configs)
583
601
 
584
602
  policies = {
585
- policy.room_id: policy.default_allow_deny
586
- for policy in asyncio.run(_list_room_policies(dburi))
603
+ policy.room_id: policy.default_allow_deny for policy in room_policies
587
604
  }
588
605
 
589
606
  configured_set = set(configured)
@@ -606,26 +623,21 @@ def _room_authz_groups(the_installation):
606
623
  }
607
624
 
608
625
 
609
- def _invalid_acl_json_paths(the_installation) -> dict:
626
+ def _invalid_acl_json_paths(room_policies) -> dict:
610
627
  """Collect ACL entries whose stored 'json_path' fails to validate.
611
628
 
612
- Reads every room policy via 'RoomAuthorizationPolicy.list_room_policies'
613
- -- which returns the unchecked models, tolerating entries that would
614
- fail 'policy.as_model' -- and re-validates each surfaced 'json_path'
615
- against the currently-loaded JSONPath environment. Typically an
616
- entry lands here when it was authored under a meta-config that
617
- registered filter functions which are no longer present.
629
+ ``room_policies`` is the policy list from '_room_policies' -- the
630
+ unchecked models, which tolerate entries that would fail
631
+ 'policy.as_model'. Each surfaced 'json_path' is re-validated against
632
+ the currently-loaded JSONPath environment. Typically an entry lands
633
+ here when it was authored under a meta-config that registered filter
634
+ functions which are no longer present.
618
635
 
619
636
  Returns a dict mapping 'room_id' to a list of '(json_path, error)'
620
- pairs. A RAM-based authz DB has no persisted rows and returns '{}'.
637
+ pairs.
621
638
  """
622
- dburi = the_installation.authorization_dburi_async
623
-
624
- if dburi in cli_util._RAM_DBURIS:
625
- return {}
626
-
627
639
  invalid: dict = {}
628
- for policy in asyncio.run(_list_room_policies(dburi)):
640
+ for policy in room_policies:
629
641
  for entry in policy.acl_entries:
630
642
  if entry.json_path is None:
631
643
  continue
@@ -651,7 +663,13 @@ def _audit_room_authz_section(
651
663
  tc_rule("Configured rooms by authorization state")
652
664
  tc_line()
653
665
 
654
- groups = _room_authz_groups(the_installation)
666
+ room_policies, db_error = _room_policies(the_installation)
667
+ if db_error is not None:
668
+ tc_print(f"ERROR: authorization database unreachable: {db_error}")
669
+ tc_line()
670
+ return {"room_authz": {"unreachable": db_error}}
671
+
672
+ groups = _room_authz_groups(the_installation, room_policies)
655
673
 
656
674
  for label, room_ids in (
657
675
  (
@@ -677,7 +695,7 @@ def _audit_room_authz_section(
677
695
  tc_print(" (none)")
678
696
  tc_line()
679
697
 
680
- invalid_acls = _invalid_acl_json_paths(the_installation)
698
+ invalid_acls = _invalid_acl_json_paths(room_policies)
681
699
  tc_print("ACL entries with invalid JSONPath:")
682
700
  if invalid_acls:
683
701
  for room_id in sorted(invalid_acls):
@@ -699,36 +717,47 @@ def _audit_room_authz_section(
699
717
  return errors
700
718
 
701
719
 
702
- def _admin_user_json_paths(the_installation) -> list[str]:
703
- """Return every stored 'AdminUser.json_path', in insertion order.
704
-
705
- Reads them via
706
- 'AdminUserPolicy.list_admin_user_discriminators'. Returns an
707
- empty list when the authz DB is RAM-based (no persisted rows can
708
- exist).
720
+ def _admin_user_json_paths(
721
+ the_installation,
722
+ ) -> tuple[list[str], str | None]:
723
+ """Return ``(json_paths, error)`` for the stored admin rows.
724
+
725
+ ``json_paths`` holds every stored 'AdminUser.json_path', in insertion
726
+ order, read via 'AdminUserPolicy.list_admin_user_discriminators';
727
+ ``error`` is ``None`` on success. A RAM-based authz DB can hold no
728
+ persisted rows, so it short-circuits to ``([], None)`` without
729
+ touching the database.
730
+
731
+ When the database itself cannot be reached -- e.g. its DBURI names a
732
+ Postgres server that isn't listening -- ``json_paths`` is empty and
733
+ ``error`` carries the exception message, so the audit can report the
734
+ unreachable DB instead of dying on the traceback.
709
735
  """
710
736
  dburi = the_installation.authorization_dburi_async
711
737
 
712
738
  if dburi in cli_util._RAM_DBURIS:
713
- return []
739
+ return [], None
714
740
 
715
- return asyncio.run(_list_admin_discriminators(dburi))
741
+ try:
742
+ return list(asyncio.run(_list_admin_discriminators(dburi))), None
743
+ except Exception as exc:
744
+ return [], f"{type(exc).__name__}: {exc}"
716
745
 
717
746
 
718
747
  def _invalid_admin_user_json_paths(
719
- the_installation,
748
+ json_paths,
720
749
  ) -> list[tuple[str, str]]:
721
750
  """Collect admin entries whose 'json_path' fails to validate.
722
751
 
723
752
  Same intent as '_invalid_acl_json_paths' but for the 'AdminUser'
724
753
  table: a row typically lands here when it was authored under a
725
754
  meta-config that registered filter functions which are no longer
726
- present.
755
+ present. ``json_paths`` is the list from '_admin_user_json_paths'.
727
756
 
728
757
  Returns a list of '(json_path, error)' pairs.
729
758
  """
730
759
  invalid: list[tuple[str, str]] = []
731
- for json_path in _admin_user_json_paths(the_installation):
760
+ for json_path in json_paths:
732
761
  try:
733
762
  authz.validate_json_path(json_path)
734
763
  except authz.InvalidJSONPath as exc:
@@ -749,7 +778,12 @@ def _audit_admin_users_section(
749
778
  tc_rule("Configured admin users")
750
779
  tc_line()
751
780
 
752
- json_paths = _admin_user_json_paths(the_installation)
781
+ json_paths, db_error = _admin_user_json_paths(the_installation)
782
+ if db_error is not None:
783
+ tc_print(f"ERROR: authorization database unreachable: {db_error}")
784
+ tc_line()
785
+ return {"admin_users": {"unreachable": db_error}}
786
+
753
787
  tc_print(f"Admin users ({len(json_paths)}):")
754
788
  if json_paths:
755
789
  for json_path in json_paths:
@@ -763,7 +797,7 @@ def _audit_admin_users_section(
763
797
  tc_print(" (none)")
764
798
  tc_line()
765
799
 
766
- invalid = _invalid_admin_user_json_paths(the_installation)
800
+ invalid = _invalid_admin_user_json_paths(json_paths)
767
801
  tc_print("Admin users with invalid JSONPath:")
768
802
  if invalid:
769
803
  for json_path, error in invalid:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soliplex
3
- Version: 0.78
3
+ Version: 0.78.1
4
4
  Summary: An AI-powered Retrieval-Augmented Generation (RAG) system with a modern web interface.
5
5
  Author-email: Enfold <info@enfoldsystems.net>
6
6
  Classifier: Programming Language :: Python :: 3
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes