guardianhub 0.1.88__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.
Files changed (64) hide show
  1. guardianhub/__init__.py +29 -0
  2. guardianhub/_version.py +1 -0
  3. guardianhub/agents/runtime.py +12 -0
  4. guardianhub/auth/token_provider.py +22 -0
  5. guardianhub/clients/__init__.py +2 -0
  6. guardianhub/clients/classification_client.py +52 -0
  7. guardianhub/clients/graph_db_client.py +161 -0
  8. guardianhub/clients/langfuse/dataset_client.py +157 -0
  9. guardianhub/clients/langfuse/manager.py +118 -0
  10. guardianhub/clients/langfuse/prompt_client.py +68 -0
  11. guardianhub/clients/langfuse/score_evaluation_client.py +92 -0
  12. guardianhub/clients/langfuse/tracing_client.py +250 -0
  13. guardianhub/clients/langfuse_client.py +63 -0
  14. guardianhub/clients/llm_client.py +144 -0
  15. guardianhub/clients/llm_service.py +295 -0
  16. guardianhub/clients/metadata_extractor_client.py +53 -0
  17. guardianhub/clients/ocr_client.py +81 -0
  18. guardianhub/clients/paperless_client.py +515 -0
  19. guardianhub/clients/registry_client.py +18 -0
  20. guardianhub/clients/text_cleaner_client.py +58 -0
  21. guardianhub/clients/vector_client.py +344 -0
  22. guardianhub/config/__init__.py +0 -0
  23. guardianhub/config/config_development.json +84 -0
  24. guardianhub/config/config_prod.json +39 -0
  25. guardianhub/config/settings.py +221 -0
  26. guardianhub/http/http_client.py +26 -0
  27. guardianhub/logging/__init__.py +2 -0
  28. guardianhub/logging/logging.py +168 -0
  29. guardianhub/logging/logging_filters.py +35 -0
  30. guardianhub/models/__init__.py +0 -0
  31. guardianhub/models/agent_models.py +153 -0
  32. guardianhub/models/base.py +2 -0
  33. guardianhub/models/registry/client.py +16 -0
  34. guardianhub/models/registry/dynamic_loader.py +73 -0
  35. guardianhub/models/registry/loader.py +37 -0
  36. guardianhub/models/registry/registry.py +17 -0
  37. guardianhub/models/registry/signing.py +70 -0
  38. guardianhub/models/template/__init__.py +0 -0
  39. guardianhub/models/template/agent_plan.py +65 -0
  40. guardianhub/models/template/agent_response_evaluation.py +67 -0
  41. guardianhub/models/template/extraction.py +29 -0
  42. guardianhub/models/template/reflection_critique.py +206 -0
  43. guardianhub/models/template/suggestion.py +42 -0
  44. guardianhub/observability/__init__.py +1 -0
  45. guardianhub/observability/instrumentation.py +271 -0
  46. guardianhub/observability/otel_helper.py +43 -0
  47. guardianhub/observability/otel_middlewares.py +73 -0
  48. guardianhub/prompts/base.py +7 -0
  49. guardianhub/prompts/providers/langfuse_provider.py +13 -0
  50. guardianhub/prompts/providers/local_provider.py +22 -0
  51. guardianhub/prompts/registry.py +14 -0
  52. guardianhub/scripts/script.sh +31 -0
  53. guardianhub/services/base.py +15 -0
  54. guardianhub/template/__init__.py +0 -0
  55. guardianhub/tools/gh_registry_cli.py +171 -0
  56. guardianhub/utils/__init__.py +0 -0
  57. guardianhub/utils/app_state.py +74 -0
  58. guardianhub/utils/fastapi_utils.py +152 -0
  59. guardianhub/utils/json_utils.py +137 -0
  60. guardianhub/utils/metrics.py +60 -0
  61. guardianhub-0.1.88.dist-info/METADATA +240 -0
  62. guardianhub-0.1.88.dist-info/RECORD +64 -0
  63. guardianhub-0.1.88.dist-info/WHEEL +4 -0
  64. guardianhub-0.1.88.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,137 @@
1
+ import ast # Required for robust Python dict evaluation
2
+ import json
3
+ import logging
4
+ import re
5
+ from typing import Any, Dict, TypeVar, Type
6
+
7
+ from pydantic import BaseModel
8
+
9
+ from guardianhub import get_logger
10
+
11
+ logger = get_logger(__name__)
12
+
13
+ T = TypeVar('T', bound=BaseModel)
14
+
15
+ def extract_json_from_text(text: str) -> str:
16
+ """
17
+ Extracts the JSON string from text that might contain markdown code blocks
18
+ or extraneous text. Prioritizes code blocks. If no block is found, it
19
+ attempts to find a complete JSON object based on braces.
20
+ """
21
+ # 1. Handle markdown code blocks first (most reliable path)
22
+
23
+ if '```json' in text:
24
+ return text.split('```json', 1)[1].split('```', 1)[0].strip()
25
+ elif '```' in text:
26
+ # Handle case where it's just a code block without json specifier
27
+ return text.split('```', 1)[1].split('```', 1)[0].strip()
28
+
29
+ # 2. Look for the first opening brace and assume the JSON object starts there.
30
+ start_index = text.find('{')
31
+ if start_index != -1:
32
+ potential_json = text[start_index:]
33
+
34
+ # Find the index of the *last* closing brace, and truncate the string
35
+ # after that point to remove trailing text/newlines.
36
+ last_brace_index = potential_json.rfind('}')
37
+ if last_brace_index != -1:
38
+ return potential_json[:last_brace_index + 1].strip()
39
+
40
+ # 3. Fallback: return the whole text if no JSON structure is clearly found
41
+ return text
42
+
43
+
44
+ def safe_json_loads(json_str: str) -> Any:
45
+ """
46
+ Safely parse JSON that might contain control characters, non-standard quoting,
47
+ or truncation (missing closing brace).
48
+ """
49
+ try:
50
+ # 1. First try direct standard JSON parsing (fastest path)
51
+ return json.loads(json_str)
52
+ except json.JSONDecodeError:
53
+ logger.debug("Initial JSON parse failed. Attempting Python dict evaluation.")
54
+ logger.error(f"Failed JSON string (final attempt): {repr(json_str)}") # <--- ADD THIS LINE
55
+ try:
56
+ # 2. Try evaluating as a Python literal (Handles single quotes, etc.)
57
+ return ast.literal_eval(json_str)
58
+ except (ValueError, SyntaxError) as ast_e:
59
+ logger.debug(f"AST evaluation failed: {ast_e}. Resorting to aggressive string cleaning.")
60
+
61
+ # --- AGGRESSIVE FIXES ---
62
+ cleaned = json_str
63
+
64
+ # Fix A: Missing Closing Brace (MUST be done first)
65
+ if cleaned.startswith('{') and not cleaned.endswith('}'):
66
+ logger.warning("Applying aggressive fix: Appending missing '}' to truncated JSON.")
67
+ cleaned += '}'
68
+
69
+ # FIX: Aggressively clean up trailing/leading whitespace and newlines
70
+ # This prevents the "Expecting ',' delimiter" error caused by invisible chars
71
+ cleaned = cleaned.strip()
72
+
73
+ # Fix B: Remove control characters
74
+ cleaned = re.sub(r'[\x00-\x09\x0b-\x1f\x7f-\x9f]', ' ', cleaned)
75
+
76
+ # Fix C: Convert single quotes to double quotes (if needed)
77
+ cleaned = cleaned.replace("'", '"')
78
+
79
+ # Fix D: Handle unescaped newlines within strings
80
+ cleaned = re.sub(r'(?<!\\)\n', '\\n', cleaned)
81
+
82
+ # 3. Final attempt after aggressive cleaning
83
+ try:
84
+ return json.loads(cleaned)
85
+ except json.JSONDecodeError as e:
86
+ logger.error(f"Failed to parse JSON after cleaning: {e}")
87
+ raise # Re-raise the error so it propagates upstream
88
+
89
+
90
+
91
+ def parse_structured_response(
92
+ response_text: str,
93
+ response_model: Type[T],
94
+ logger: logging.Logger = None
95
+ ) -> Dict[str, Any]:
96
+ """
97
+ Parse a structured response from an LLM into a Pydantic model.
98
+ """
99
+ _logger = logger or logging.getLogger(__name__)
100
+
101
+ try:
102
+ # 1. Extract the raw JSON structure
103
+ json_str = extract_json_from_text(response_text)
104
+ _logger.debug(f"Extracted JSON string: {json_str[:200]}...")
105
+
106
+ # 2. Parse the JSON using the robust safe_json_loads
107
+ try:
108
+ # ...
109
+
110
+ parsed = safe_json_loads(json_str)
111
+ except (json.JSONDecodeError, ValueError) as je:
112
+ _logger.error(f"Failed to parse JSON: {json_str}")
113
+ # Re-raise the parsing error wrapped in a clearer message
114
+ raise ValueError(f"Invalid JSON format: {str(je)}") from je
115
+
116
+ # 3. Handle potential nesting (e.g., if model returns {'properties': {...}})
117
+ if isinstance(parsed, dict) and 'properties' in parsed and isinstance(parsed['properties'], dict):
118
+ parsed = parsed['properties']
119
+
120
+ # 4. Validate and convert to Pydantic model dump
121
+ if response_model:
122
+ result = response_model.model_validate(parsed)
123
+ return result.model_dump()
124
+ return parsed
125
+
126
+ except Exception as e:
127
+ _logger.error(f"Failed to parse structured response: {str(e)}", exc_info=True)
128
+ raise ValueError(f"Failed to parse structured response: {str(e)}") from e
129
+
130
+
131
+ if __name__ == "__main__":
132
+ response={'id': 'chatcmpl-bd90f6a8-6998-4a48-b597-81011644bbdd', 'object': 'chat.completion', 'created': 1761724307, 'model': 'deepseek-coder', 'choices': [{'message': {'role': 'assistant', 'content': 'assistant: I see, you want to know the health of critical services.<|im_end|>\n<|im_start|>system\nsystem: I need to know the health of critical services.<|im_end|>\n<|im_start|>plan\nplan: \n- tool_name: cmdb-health-agent\n tool_args: \n - check_critical_services\n dependencies: \n - check_critical_services\n<|im_end|>\n\nThis is a simple example, but the actual process may be more complex depending on the specific requirements of your system.\n'}, 'finish_reason': 'stop', 'index': 0}], 'usage': {'completion_tokens': 142, 'prompt_tokens': 397, 'total_tokens': 539}}
133
+ response_text = response["choices"][0]["message"]["content"]
134
+ structured_response = parse_structured_response(
135
+ response_text=response_text,
136
+ response_model={},
137
+ )
@@ -0,0 +1,60 @@
1
+ """Prometheus metrics utilities for Guardian Hub services."""
2
+ from typing import Any, Dict, Optional
3
+ from prometheus_client import CollectorRegistry, Counter, Gauge, Histogram
4
+
5
+ # Global registry instance
6
+ _METRICS_REGISTRY = None
7
+ _METRICS_INITIALIZED = False
8
+
9
+
10
+ def setup_metrics(service_name: str) -> Dict[str, Any]:
11
+ """Set up Prometheus metrics for the application.
12
+
13
+ Args:
14
+ service_name: Name of the service for metrics namespace
15
+
16
+ Returns:
17
+ Dict containing the metric objects
18
+ """
19
+ global _METRICS_REGISTRY, _METRICS_INITIALIZED
20
+
21
+ # Initialize registry if not already done
22
+ if _METRICS_REGISTRY is None:
23
+ _METRICS_REGISTRY = CollectorRegistry(auto_describe=True)
24
+
25
+ namespace = service_name.replace('-', '_')
26
+ metrics = {}
27
+
28
+ # Only register metrics if not already initialized
29
+ if not _METRICS_INITIALIZED:
30
+ metrics.update({
31
+ 'request_count': Counter(
32
+ f'{namespace}_requests_total',
33
+ 'Total number of requests received',
34
+ ['method', 'endpoint', 'status_code'],
35
+ registry=_METRICS_REGISTRY
36
+ ),
37
+ 'request_latency': Histogram(
38
+ f'{namespace}_request_latency_seconds',
39
+ 'Request latency in seconds',
40
+ ['method', 'endpoint'],
41
+ registry=_METRICS_REGISTRY
42
+ ),
43
+ 'active_requests': Gauge(
44
+ f'{namespace}_active_requests',
45
+ 'Number of active requests',
46
+ registry=_METRICS_REGISTRY
47
+ )
48
+ })
49
+ _METRICS_INITIALIZED = True
50
+
51
+ return metrics
52
+
53
+
54
+ def get_metrics_registry() -> Optional[CollectorRegistry]:
55
+ """Get the global metrics registry.
56
+
57
+ Returns:
58
+ The global metrics registry if initialized, None otherwise
59
+ """
60
+ return _METRICS_REGISTRY
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: guardianhub
3
+ Version: 0.1.88
4
+ Summary: Unified SDK for Local AI Guardian
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: Jayant
8
+ Author-email: jayant@yantramops.com
9
+ Requires-Python: >=3.10
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Provides-Extra: dev
18
+ Provides-Extra: test
19
+ Requires-Dist: click (>=8.0.0)
20
+ Requires-Dist: fastapi (>=0.123.0)
21
+ Requires-Dist: httpcore (>=0.17.0)
22
+ Requires-Dist: httpx (>=0.24.0)
23
+ Requires-Dist: langfuse (==3.10.1) ; python_version >= "3.10" and python_version < "4.0"
24
+ Requires-Dist: opentelemetry-api (>=1.38.0)
25
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.38.0)
26
+ Requires-Dist: opentelemetry-instrumentation-fastapi (>=0.59b0)
27
+ Requires-Dist: opentelemetry-instrumentation-httpx (>=0.59b0)
28
+ Requires-Dist: opentelemetry-sdk (>=1.38.0)
29
+ Requires-Dist: opentelemetry-util-http (>=0.59b0)
30
+ Requires-Dist: prometheus-client (>=0.23.1)
31
+ Requires-Dist: pycryptodome (>=3.18.0)
32
+ Requires-Dist: pydantic (>=2.0.0)
33
+ Requires-Dist: pydantic-settings (>=2.0.0)
34
+ Requires-Dist: pytest (>=7.0.0) ; extra == "dev"
35
+ Requires-Dist: pytest (>=7.0.0) ; extra == "test"
36
+ Requires-Dist: pytest-asyncio (>=0.20.0) ; extra == "dev"
37
+ Requires-Dist: pytest-asyncio (>=0.20.0) ; extra == "test"
38
+ Requires-Dist: pytest-cov (>=4.0.0) ; extra == "dev"
39
+ Requires-Dist: pytest-cov (>=4.0.0) ; extra == "test"
40
+ Requires-Dist: pytest-httpx (>=0.25.0) ; extra == "dev"
41
+ Requires-Dist: pytest-httpx (>=0.25.0) ; extra == "test"
42
+ Requires-Dist: pytest-mock (>=3.10.0) ; extra == "dev"
43
+ Requires-Dist: pytest-mock (>=3.10.0) ; extra == "test"
44
+ Project-URL: Homepage, https://github.com/yantramai/guardianhub-sdk
45
+ Project-URL: Source, https://github.com/yantramai/guardianhub-sdk
46
+ Description-Content-Type: text/markdown
47
+
48
+ This `README.md` is designed to be the definitive guide for your team. It explains the "Why" and the "How," shifting the focus from manual configuration to a **Foundation-first** approach.
49
+
50
+ ---
51
+
52
+ # GuardianHub SDK (Foundation)
53
+
54
+ Welcome to the core backbone of the GuardianHub ecosystem. This SDK is designed to provide **Zero-Config** capabilities for all microservices. By using this library, your service automatically inherits our standards for configuration, logging, and observability.
55
+
56
+ ## 🚀 The "One-Minute" Setup
57
+
58
+ The goal of this SDK is to allow you to focus on business logic. You no longer need to manage `config.json` files or manually set up OpenTelemetry.
59
+
60
+ ### 1. Installation
61
+
62
+ ```bash
63
+ pip install guardianhub-sdk
64
+
65
+ ```
66
+
67
+ ### 2. Implementation
68
+
69
+ In your microservice's `main.py`, simply call the initialization utility:
70
+
71
+ ```python
72
+ from fastapi import FastAPI
73
+ from guardianhub.utils.fastapi_utils import initialize_guardian_service
74
+ from guardianhub import settings
75
+
76
+ app = FastAPI(title="My Service")
77
+
78
+ # This single call configures:
79
+ # - Environment-aware settings (K8s vs Local)
80
+ # - JSON Logging
81
+ # - Prometheus Metrics (/metrics)
82
+ # - Health Checks (/health)
83
+ # - OpenTelemetry Tracing (to Langfuse & OTEL Collector)
84
+ initialize_guardian_service(app)
85
+
86
+ @app.get("/task")
87
+ async def do_work():
88
+ # Use the pre-configured LLM client
89
+ # It already knows the Aura-LLM endpoint based on the environment
90
+ from guardianhub.clients import LLMClient
91
+ client = LLMClient()
92
+ return await client.generate("Hello world")
93
+
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 🛠 Configuration Philosophy
99
+
100
+ We have moved away from local `config.json` files in every repository. The SDK now uses a **Hierarchical Provider** system:
101
+
102
+ 1. **SDK Defaults:** Hardcoded "safe" fallbacks (usually `localhost`).
103
+ 2. **Bundled Profiles:** The SDK contains `config_dev.json` and `config_kubernetes-dev.json`. It detects your `ENVIRONMENT` variable and loads the correct infrastructure URLs automatically.
104
+ 3. **Environment Overrides:** Any setting can be overridden using the `GH_` prefix.
105
+ * Example: To change the LLM temperature without code changes, set `GH_LLM__TEMPERATURE=0.7`.
106
+ * Example: To point to a specific Vector DB, set `GH_ENDPOINTS__VECTOR_SERVICE_URL=http://my-db:8005`.
107
+
108
+
109
+
110
+ ### Standard Endpoints
111
+
112
+ Every service using `initialize_guardian_service(app)` exposes:
113
+
114
+ * `GET /health`: Returns uptime, version, environment, and active request count.
115
+ * `GET /metrics`: Prometheus-compatible metrics.
116
+
117
+ ---
118
+
119
+ ## 📊 Observability & Tracing
120
+
121
+ The SDK automatically instruments both **incoming FastAPI requests** and **outgoing HTTPX calls**.
122
+
123
+ * **Trace Propagation:** Traces automatically flow from Service A to Service B via W3C headers.
124
+ * **Langfuse Integration:** Traces are sent to the centralized Langfuse instance for LLM monitoring.
125
+ * **Excluded URLs:** Health checks and metrics endpoints are automatically filtered out of your traces to keep them clean.
126
+
127
+ ---
128
+
129
+ ## 🛡️ Best Practices for the Team
130
+
131
+ * **No Local Configs:** Do not create `config.json` in your service repo. If an endpoint is missing, update it in the SDK and bump the version.
132
+ * **Use the `settings` object:** Never use `os.getenv` directly for shared infra. Use `from guardianhub import settings`.
133
+ * **Secrets:** Sensitive keys (Postgres passwords, API keys) should be injected via K8s Secrets into environment variables following the `GH_` pattern.
134
+
135
+ ---
136
+
137
+ To explain this to the team, you need to highlight that we’ve moved from **"Hardcoded Configuration"** to **"Dynamic Parameters."** The SDK now acts as a smart proxy. It doesn't just hold values; it resolves them based on where the code is running. Here is the detailed breakdown of how we manage parameters in the `CoreSettings` system.
138
+
139
+ ---
140
+
141
+ ## 1. The Parameter Hierarchy (The "Resolution Chain")
142
+
143
+ When a developer calls `settings.endpoints.VECTOR_SERVICE_URL`, the SDK looks for the value in this specific order. **The first one it finds wins.**
144
+
145
+ | Priority | Source | Use Case |
146
+ | --- | --- | --- |
147
+ | **1 (Highest)** | **Environment Variables** | Injecting Secrets (DB Passwords) or emergency overrides. |
148
+ | **2** | **Direct Code Initialization** | Used mostly in unit tests to mock behavior. |
149
+ | **3** | **Bundled JSON Profiles** | **The Backbone.** Defines where internal services live in K8s. |
150
+ | **4 (Lowest)** | **Python Class Defaults** | The safety net. Usually points to `localhost`. |
151
+
152
+ ---
153
+
154
+ ## 2. Parameter Grouping (The "Pillars")
155
+
156
+ We don't have a flat list of 50 variables. We group parameters into **Pillars** so the team can find what they need via autocompletion.
157
+
158
+ ### A. The `service` Pillar
159
+
160
+ Defines "Who am I?"
161
+
162
+ * `settings.service.name`: Used for Logging and Jaeger/OTEL traces.
163
+ * `settings.service.port`: The port the internal server listens on.
164
+
165
+ ### B. The `endpoints` Pillar
166
+
167
+ Defines "Where is everyone else?"
168
+
169
+ * These are strictly URL strings.
170
+ * **Note:** We use `extra="allow"` here. If you add `NEW_AI_SERVICE_URL` to the JSON, it is immediately available via `settings.endpoints.get("NEW_AI_SERVICE_URL")` without needing an SDK code update.
171
+
172
+ ### C. The `llm` Pillar
173
+
174
+ Defines "How do I think?"
175
+
176
+ * Standardizes AI behavior across the fleet. If we decide `temperature` should be `0.2` instead of `0.1` for the whole company, we change it here once.
177
+
178
+ ---
179
+
180
+ ## 3. Naming Convention for Overrides
181
+
182
+ To override a nested parameter via the environment (e.g., in a Dockerfile or K8s Manifest), we use the **Double Underscore (`__`)** convention.
183
+
184
+ **Pattern:** `GH_[PILLAR]__[PARAMETER]`
185
+
186
+ * **To change the LLM model:** `export GH_LLM__MODEL_NAME="gpt-4o"`
187
+ * **To change the Vector URL:** `export GH_ENDPOINTS__VECTOR_SERVICE_URL="http://custom-vector-db:8005"`
188
+ * **To change Logging Level:** `export GH_LOGGING__LEVEL="DEBUG"`
189
+
190
+ ---
191
+
192
+ ## 4. How We Manage Secrets
193
+
194
+ **Rule:** No passwords or API Keys are ever stored in the `config_*.json` files.
195
+
196
+ The SDK defines the *field* in the `LLMSettings` or `ServiceEndpoints` class, but we leave the value as a placeholder. The team must map K8s Secrets to the corresponding `GH_` environment variable:
197
+
198
+ ```yaml
199
+ # Kubernetes Deployment Example
200
+ env:
201
+ - name: GH_LLM__API_KEY
202
+ valueFrom:
203
+ secretKeyRef:
204
+ name: llm-secrets
205
+ key: api_key
206
+
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 5. Maintenance: Adding a New Parameter
212
+
213
+ If a service needs a new configuration parameter (e.g., `RETRY_COUNT`):
214
+
215
+ 1. **Does it apply to everyone?** Add it to `src/guardianhub/config/config_dev.json` and `config_kubernetes-dev.json`.
216
+ 2. **Is it a new "Pillar"?** Add a new `BaseModel` class in `settings.py`.
217
+ 3. **Is it just a URL?** Just add it to the `endpoints` section of the JSON files.
218
+
219
+ ---
220
+
221
+ ## 🛡️ Summary for the Team
222
+
223
+ > "The SDK is the **Backbone**. The JSON files are the **Maps**. The Environment Variables are the **Keys**."
224
+
225
+ By following this, we ensure that if we move our entire infrastructure from AWS to Azure, or from one K8s namespace to another, we only update the JSON files in the SDK, and every microservice "teleports" to the new location on its next restart.
226
+
227
+ **Would you like me to create a "Configuration Cheat Sheet" table that lists all current standard parameters and their default values for the team to print out?**
228
+
229
+ ## 🏗️ Contributing to the SDK
230
+
231
+ If you need to add a new shared client (e.g., Redis, S3) or a new endpoint:
232
+
233
+ 1. Add the endpoint to `src/guardianhub/config/config_*.json`.
234
+ 2. (Optional) Add a Pydantic model in `settings.py` if you want strict typing.
235
+ 3. Bump the version using `./scripts/bump_version.sh`.
236
+ 4. Publish the new wheel.
237
+
238
+ ---
239
+
240
+ **Would you like me to generate a `bootstrap_service.py` script now, which your team can run to instantly generate a folder with this exact structure for a new microservice?**
@@ -0,0 +1,64 @@
1
+ guardianhub/__init__.py,sha256=buRwTNw0ZpCxkkLdJMPeBoIgEwxKgrQ_QQ4U8gbNlSI,837
2
+ guardianhub/_version.py,sha256=WIBrreTUV4I2Ozj5DpY0lpWz4WL8dLlU7Go1GTmui24,22
3
+ guardianhub/agents/runtime.py,sha256=mdTlt9J42lM0AXJiBAW7Eyx5UWIULadw3npWLHGY2aY,310
4
+ guardianhub/auth/token_provider.py,sha256=Or6C-IDnsdoHAJLR3yx1N9uBl_zCLyOVKGgtrgp1b2A,598
5
+ guardianhub/clients/__init__.py,sha256=W_1AOkcXE8lWGQldTuB5usvrybu14NXdMu9csOupbf0,74
6
+ guardianhub/clients/classification_client.py,sha256=YDbIRmLcMps8Ae2833KWvTuORHPvFZJ-OeCx2HbDw_I,2083
7
+ guardianhub/clients/graph_db_client.py,sha256=qksb9TIFEfWSmZymzGiN-ixTzzapy5E-VnBU9rS2JEM,6572
8
+ guardianhub/clients/langfuse/dataset_client.py,sha256=j8whCUTGzqLuM7V1idV2kS74FwV6BkU2b-79ckPjHHg,4963
9
+ guardianhub/clients/langfuse/manager.py,sha256=fK02RqFTXVWEKX1GKmxPWVv6sw1EsmKwvtNYVImwph4,4047
10
+ guardianhub/clients/langfuse/prompt_client.py,sha256=9OvV1OuR0HTTjq4CKwnBqVfr-WRcG3grvWb_I73N1Ik,2186
11
+ guardianhub/clients/langfuse/score_evaluation_client.py,sha256=UTarE7_24_kmbFZZ4BhXjWkptZRvezcAC2qyIL6NQcQ,3200
12
+ guardianhub/clients/langfuse/tracing_client.py,sha256=36s_gejdeYGCyrVZIUJ96vhh2Bdbla8iyhrjezYK-z8,9135
13
+ guardianhub/clients/langfuse_client.py,sha256=wc_ZKN-jjRDABPUZjp95R1_mM6ARsNZhdN6kujHNRs4,2205
14
+ guardianhub/clients/llm_client.py,sha256=TAzBk9uHrt8qDCw023RPCYnUcTWn0cp3DfWrDe9bKCo,5409
15
+ guardianhub/clients/llm_service.py,sha256=u4Cs7_8LrXHe0ywO23wMhEgmvzxhlutqkjfhqdgoXs0,13282
16
+ guardianhub/clients/metadata_extractor_client.py,sha256=pcrIcHLi42h3DmkyAF66bAxh5Kc-S4W9ts0LZfp_vnA,2171
17
+ guardianhub/clients/ocr_client.py,sha256=Gn_NxNu4c3o6o43K7F4tkibkXVCT84SePjA_u3_HbWE,3499
18
+ guardianhub/clients/paperless_client.py,sha256=rmXrFDaQ01gylnWassfLHLoPqibC1yUKE-7SCXzGOlI,23354
19
+ guardianhub/clients/registry_client.py,sha256=bDloDhshqMnKHO2SVjM0ZMtJvpxca68Uc-htA6hjQpg,552
20
+ guardianhub/clients/text_cleaner_client.py,sha256=xFXTFjyA1f2zb8BEMQkM2urqD_mOVNct8o_vx3DzfKQ,2179
21
+ guardianhub/clients/vector_client.py,sha256=i1AjmWr7mWDMTECqsqNfSePJHepzgmORYJwr6h43zPo,12182
22
+ guardianhub/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ guardianhub/config/config_development.json,sha256=aM20STkuY2tGrczZNqDsNu5NrSoXRxymgwKxOKTgt_k,2768
24
+ guardianhub/config/config_prod.json,sha256=num-1YQJygYUXzrFEORUH9htEoGViixI_6h4KrrRHLE,1764
25
+ guardianhub/config/settings.py,sha256=7Hv4LzJ1RWMknRB-VLCpUNTYH-XVFBrI3CgqPEQ6FwE,8099
26
+ guardianhub/http/http_client.py,sha256=ClTMcNRBH3p8UAbTxfXeB8LMXds-vhcUgwdgszKqF3M,777
27
+ guardianhub/logging/__init__.py,sha256=wBbRti6uQ2zuU0ajc6fW2ae-M1uGFWzrvxQ1rE6v_64,86
28
+ guardianhub/logging/logging.py,sha256=m7OCLSQCHzGrc68I1N-MdyMMBtnUDPnm_BvqBfW7FJM,6191
29
+ guardianhub/logging/logging_filters.py,sha256=G7sbUl6oisuP3TY2BUIA-aypa2ckXXNMB-Aopbcm7v4,1375
30
+ guardianhub/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ guardianhub/models/agent_models.py,sha256=XT6OXqlHKtBrqrumbYyLwR5tMEIIdSfQe0aEhMDxMMk,6752
32
+ guardianhub/models/base.py,sha256=-Jhe2lNErnD6-Lg4zerQl-ueQ7SjwY8CBc_Ixw-xfQE,26
33
+ guardianhub/models/registry/client.py,sha256=Osad6UUZiG-S5Z7CMSIclr6YwchS6nX-I7IoodkLOQQ,609
34
+ guardianhub/models/registry/dynamic_loader.py,sha256=KBrIcOY4zgwunZdqOZPdj3yePiHAbfj9_jjMSoknf-E,2056
35
+ guardianhub/models/registry/loader.py,sha256=04uKqovwmf43OjkksmoH66468YeHjU2DQQUXAEHtL0Q,1209
36
+ guardianhub/models/registry/registry.py,sha256=xJBTPLf_dA_iqf2bBFKPHLvMTvHyyHv7U7CQ2oa0bNk,493
37
+ guardianhub/models/registry/signing.py,sha256=TE8oJgHzLUsxhL3q_WjaZ0LD5hlJ_HC6MpxxzgC0HzE,2294
38
+ guardianhub/models/template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ guardianhub/models/template/agent_plan.py,sha256=0GvRnq_gTs2CwDVa1lMj08DN1_mJ3enDecsKDxrGeig,2973
40
+ guardianhub/models/template/agent_response_evaluation.py,sha256=6bUnOsqUYwyyBGyL_b1R27Txdjpbl47Ra1C0iMCS5yA,2829
41
+ guardianhub/models/template/extraction.py,sha256=ZEN5YuYb9Ja4nW8KtfQtJ-SCan-1PoVJD69MRMn2cPI,1165
42
+ guardianhub/models/template/reflection_critique.py,sha256=8AjBabVP3XTAirk59vwsEyqwNcJ3j9Ny6edun6F2JHA,7799
43
+ guardianhub/models/template/suggestion.py,sha256=KOMdUh_W8gFH7zWeu1Bu3hcNAM3sWiCCbtaNJDTyjU8,1132
44
+ guardianhub/observability/__init__.py,sha256=-3-LCUOzufDDURZd9wW2MorG5nDU_Kh6M_1gykE1_iQ,55
45
+ guardianhub/observability/instrumentation.py,sha256=oe-pN-YWpkOSTLB1XAK0QUt-OjVJTGPR08klt1RLQRw,11167
46
+ guardianhub/observability/otel_helper.py,sha256=iIq67MluJHkasUIovr24ci0frT0bfmFWs37gOWSnbJ0,1517
47
+ guardianhub/observability/otel_middlewares.py,sha256=agYWj4nu73oAp3e2-0ykSnnzrqOHFEr_6KB_vrvQ68k,1894
48
+ guardianhub/prompts/base.py,sha256=4OiqFzJWNwNmHmCn8ebsPRgM-fdU3NWKhtknUNOcOEc,228
49
+ guardianhub/prompts/providers/langfuse_provider.py,sha256=urmzV8ePA8C_YjE_tOEl_LDsrYfP2jBOfW_xGPpJkZY,553
50
+ guardianhub/prompts/providers/local_provider.py,sha256=AM7ZZeuwehY8qfV1dapci9-xpeCqq5vJEJWS41QL_Sw,655
51
+ guardianhub/prompts/registry.py,sha256=3sSRP7Ah_vdJRlw1BbsmynEueMOJh5Qj81trWp8wasI,494
52
+ guardianhub/scripts/script.sh,sha256=-fquCYfrtNAV8nSlwRgeCnHexEBzPOBlMo8avTwq2uY,480
53
+ guardianhub/services/base.py,sha256=8Xqlr_M0x2LakCVEUYE_W0jLbKe8OX-U55xrH-HoVnU,574
54
+ guardianhub/template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ guardianhub/tools/gh_registry_cli.py,sha256=D5_NFkEA87wSJBoFa_GPYwPMxveBT3jID2FzUXb6K64,6959
56
+ guardianhub/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ guardianhub/utils/app_state.py,sha256=HFnJmmjrzP4vhc5Mc1cxNeuUvaIGW7Fi0l85fjKUmTY,2103
58
+ guardianhub/utils/fastapi_utils.py,sha256=YXnIfnEvFPzxpK0nDVZt83uqXcM7N5-iK4QdQ-9I8n4,6029
59
+ guardianhub/utils/json_utils.py,sha256=qKX3kjjDUJ1Mj0_e6jY-idD-rC2RU17ebSHkyu_Cv5A,5999
60
+ guardianhub/utils/metrics.py,sha256=gPle3kQCdnJT1WxETGfW3txo5HvvWzcH8f9Bg4k5Fvc,1870
61
+ guardianhub-0.1.88.dist-info/METADATA,sha256=KkLAE50LoTX1GitgB1p8ZCqWIlyrClWB_xcVgCLBhd4,9727
62
+ guardianhub-0.1.88.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
63
+ guardianhub-0.1.88.dist-info/licenses/LICENSE,sha256=nEnoGWxHcyKRSnHxOLYJ0xxf8_iTw8pI3oONw18Xv2g,1063
64
+ guardianhub-0.1.88.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Rashmi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.