gaard-api 0.1.2__tar.gz → 0.1.3__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 (55) hide show
  1. {gaard_api-0.1.2/src/gaard_api.egg-info → gaard_api-0.1.3}/PKG-INFO +1 -1
  2. {gaard_api-0.1.2 → gaard_api-0.1.3}/pyproject.toml +1 -1
  3. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/services.py +98 -0
  4. gaard_api-0.1.3/src/gaard_api/admin-web/assets/main.js +2215 -0
  5. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin-web/assets/styles.css +62 -2
  6. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin-web/src/main.ts +351 -36
  7. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/v1/admin.py +144 -1
  8. gaard_api-0.1.3/src/gaard_api/api_registry.py +266 -0
  9. gaard_api-0.1.3/src/gaard_api/extension_services.py +82 -0
  10. gaard_api-0.1.3/src/gaard_api/extensions.py +50 -0
  11. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/main.py +3 -0
  12. {gaard_api-0.1.2 → gaard_api-0.1.3/src/gaard_api.egg-info}/PKG-INFO +1 -1
  13. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api.egg-info/SOURCES.txt +3 -0
  14. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_admin_api.py +226 -0
  15. gaard_api-0.1.3/tests/test_api_registry.py +101 -0
  16. gaard_api-0.1.2/src/gaard_api/admin-web/assets/main.js +0 -2111
  17. gaard_api-0.1.2/src/gaard_api/extensions.py +0 -18
  18. {gaard_api-0.1.2 → gaard_api-0.1.3}/MANIFEST.in +0 -0
  19. {gaard_api-0.1.2 → gaard_api-0.1.3}/README.md +0 -0
  20. {gaard_api-0.1.2 → gaard_api-0.1.3}/setup.cfg +0 -0
  21. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/__init__.py +0 -0
  22. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/__init__.py +0 -0
  23. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/database.py +0 -0
  24. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/defaults.py +0 -0
  25. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/models.py +0 -0
  26. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/prompt_runtime.py +0 -0
  27. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin/security.py +0 -0
  28. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin-web/index.html +0 -0
  29. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/admin-web/package.json +0 -0
  30. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/__init__.py +0 -0
  31. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/v1/__init__.py +0 -0
  32. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/v1/prompts.py +0 -0
  33. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/v1/query.py +0 -0
  34. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/api/v1/schema.py +0 -0
  35. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/cli.py +0 -0
  36. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/cli_commands.py +0 -0
  37. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/core/__init__.py +0 -0
  38. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/core/error_handlers.py +0 -0
  39. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/core/schema_cache.py +0 -0
  40. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/core/settings.py +0 -0
  41. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/example_data/__init__.py +0 -0
  42. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/example_data/medical_poc/__init__.py +0 -0
  43. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/example_data/medical_poc/schema.sql +0 -0
  44. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/example_data/medical_poc/seed.sql +0 -0
  45. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/example_database.py +0 -0
  46. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api/server_cli.py +0 -0
  47. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api.egg-info/dependency_links.txt +0 -0
  48. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api.egg-info/entry_points.txt +0 -0
  49. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api.egg-info/requires.txt +0 -0
  50. {gaard_api-0.1.2 → gaard_api-0.1.3}/src/gaard_api.egg-info/top_level.txt +0 -0
  51. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_error_handlers.py +0 -0
  52. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_investigation_error_messages.py +0 -0
  53. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_prompt_runtime.py +0 -0
  54. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_server_cli.py +0 -0
  55. {gaard_api-0.1.2 → gaard_api-0.1.3}/tests/test_settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gaard-api
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: GAARD backend web services providing admin interface
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gaard-api"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "GAARD backend web services providing admin interface"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -818,6 +818,104 @@ def set_llm_runtime_config(
818
818
  return get_llm_runtime_config(session)
819
819
 
820
820
 
821
+ def build_llm_runtime_config(
822
+ session: Session,
823
+ *,
824
+ provider: str,
825
+ base_url: str,
826
+ api_key: str | None,
827
+ clear_api_key: bool,
828
+ model: str,
829
+ timeout_seconds: int | None,
830
+ extra_body: dict[str, Any],
831
+ ) -> LlmRuntimeConfig:
832
+ if provider != "openai-compatible":
833
+ raise ValueError("Only openai-compatible LLM provider is supported.")
834
+
835
+ current_config = get_llm_runtime_config(session)
836
+ normalized_base_url = str(base_url or "").strip()
837
+ normalized_model = str(model or "").strip()
838
+ if not normalized_base_url:
839
+ raise ValueError("LLM Base URL is required.")
840
+ if not normalized_model:
841
+ raise ValueError("LLM model is required.")
842
+ if timeout_seconds is not None and timeout_seconds < 1:
843
+ raise ValueError("LLM timeout seconds must be greater than 0.")
844
+ if not isinstance(extra_body, dict):
845
+ raise ValueError("LLM Extra body JSON must be an object.")
846
+
847
+ next_api_key = current_config.api_key
848
+ if clear_api_key:
849
+ next_api_key = "change-me"
850
+ elif api_key is not None and api_key.strip():
851
+ next_api_key = api_key.strip()
852
+
853
+ return LlmRuntimeConfig(
854
+ provider=provider,
855
+ base_url=normalized_base_url,
856
+ api_key=next_api_key,
857
+ model=normalized_model,
858
+ timeout_seconds=timeout_seconds or current_config.timeout_seconds,
859
+ extra_body=extra_body,
860
+ )
861
+
862
+
863
+ def test_llm_runtime_config(
864
+ session: Session,
865
+ *,
866
+ provider: str,
867
+ base_url: str,
868
+ api_key: str | None,
869
+ clear_api_key: bool,
870
+ model: str,
871
+ timeout_seconds: int | None,
872
+ extra_body: dict[str, Any],
873
+ ) -> dict[str, Any]:
874
+ config = build_llm_runtime_config(
875
+ session,
876
+ provider=provider,
877
+ base_url=base_url,
878
+ api_key=api_key,
879
+ clear_api_key=clear_api_key,
880
+ model=model,
881
+ timeout_seconds=timeout_seconds,
882
+ extra_body=extra_body,
883
+ )
884
+ if not config.api_key or config.api_key == "change-me":
885
+ raise ValueError("LLM API key is required for the connection test.")
886
+
887
+ client = OpenAICompatibleClient(
888
+ base_url=config.base_url,
889
+ api_key=config.api_key,
890
+ timeout_seconds=config.timeout_seconds,
891
+ )
892
+
893
+ try:
894
+ response = client.create_chat_completion(
895
+ ChatCompletionRequest(
896
+ model=config.model,
897
+ messages=[
898
+ ChatMessage(
899
+ role="user",
900
+ content="GAARD LLM connection test. Reply with OK.",
901
+ )
902
+ ],
903
+ temperature=0,
904
+ extra_body=config.extra_body,
905
+ )
906
+ )
907
+ except LlmProviderError as exc:
908
+ raise ValueError(str(exc)) from exc
909
+
910
+ if not response.content.strip():
911
+ raise ValueError("LLM provider returned an empty response.")
912
+
913
+ return {
914
+ "ok": True,
915
+ "model": response.model or config.model,
916
+ }
917
+
918
+
821
919
  def get_data_query_audit_retention_days(session: Session) -> int:
822
920
  value = get_setting(
823
921
  session,