Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

240 lines
8.3 KiB
Python

#
# Copyright 2026 The Dapr Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
from typing import Dict, Optional, Any, Union
import logging
import requests
from pydantic import BaseModel, Field, PrivateAttr
from dapr_agents.types import ToolError
from urllib.parse import urlparse
try:
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
OPENTELEMETRY_AVAILABLE = True
except ImportError:
# OpenTelemetry is not available - tracing will be disabled
# To enable observability features, install: pip install dapr-agents[observability]
RequestsInstrumentor = None
trace = None
set_logger_provider = None
OPENTELEMETRY_AVAILABLE = False
logger = logging.getLogger(__name__)
def _parse_bool_env(value: str) -> bool:
"""
Parse a string to boolean, similar to distutils.util.strtobool.
Args:
value: String value to parse (e.g., 'true', 'yes', '1', 'false', 'no', '0')
Returns:
Boolean value
Raises:
ValueError: If the value cannot be parsed as a boolean
"""
if value.lower() in ("y", "yes", "t", "true", "on", "1"):
return True
elif value.lower() in ("n", "no", "f", "false", "off", "0"):
return False
else:
raise ValueError(f"Cannot parse '{value}' as boolean")
class DaprHTTPClient(BaseModel):
"""
Client for sending HTTP requests to Dapr endpoints.
"""
dapr_app_id: Optional[str] = Field(
default="", description="Optional name of the Dapr App ID to invoke."
)
dapr_http_endpoint: Optional[str] = Field(
default="",
description="Optional name of the HTTPEndpoint to call for invocation",
)
http_endpoint: Optional[str] = Field(
default="", description="Optional FQDN URL to request to."
)
path: Optional[str] = Field(
default="", description="Optional name of the path to invoke."
)
headers: Optional[Dict[str, str]] = Field(
default={},
description="Default headers to include in all requests.",
)
_base_url: str = PrivateAttr(default="http://localhost:3500/v1.0/invoke")
def model_post_init(self, __context: Any) -> None:
"""Initialize the client after the model is created."""
try:
otel_enabled: bool = _parse_bool_env(
os.getenv("DAPR_AGENTS_OTEL_ENABLED", "True")
)
except ValueError:
otel_enabled = False
if otel_enabled:
from dapr_agents.agents.telemetry.otel import DaprAgentsOtel
otel_client = DaprAgentsOtel(
service_name=os.getenv("OTEL_SERVICE_NAME", "dapr-http-client"),
otlp_endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", ""),
)
tracer = otel_client.create_and_instrument_tracer_provider()
trace.set_tracer_provider(tracer)
otel_logger = otel_client.create_and_instrument_logging_provider(
logger=logger,
)
set_logger_provider(otel_logger)
RequestsInstrumentor().instrument()
logger.debug("Initializing DaprHTTPClient client")
super().model_post_init(__context)
def do_http_request(
self,
payload: dict[str, str],
endpoint: str = "",
path: str = "",
verb: str = "GET",
) -> Union[tuple[int, str] | ToolError]:
"""
Send a POST request to the specified endpoint with the given input.
Args:
endpoint_url (str): The host of the URI to send the request to.
payload (dict[str, str]): The payload to include in the request.
path (str): The path of the URI to invoke including any query strings appended.
verb (str): The HTTP verb. Either GET or POST.
Returns:
A tuple with the http status code and respose or a ToolError.
"""
try:
url = self._validate_endpoint_type(
endpoint=endpoint, path=self.path if path == "" else path
)
except ToolError as e:
logger.error(f"Error validating endpoint: {e}")
raise e
logger.debug(
f"[HTTP] Sending POST request to '{url}' with input '{payload}' and headers '{self.headers}"
)
match verb.upper():
case "GET":
response = requests.get(url=str(url), headers=self.headers)
case "POST":
response = requests.post(
url=str(url), headers=self.headers, json=payload
)
case _:
raise ValueError(
f"Value for 'verb' not in expected format ['GET'|'POST']: {verb}"
)
logger.debug(
f"Request returned status code '{response.status_code}' and '{response.text}'"
)
if not response.ok:
raise ToolError(
f"Error occured sending the request. Received '{response.status_code}' - '{response.text}'"
)
return (response.status_code, response.text)
def _validate_endpoint_type(
self, endpoint: str, path: Optional[str | None]
) -> Union[str | ToolError]:
if path == "":
raise ToolError("No path provided. Please provide a valid path.")
if isinstance(path, str) and path.startswith("/"):
# Remove leading slash
path = path[1:]
try:
if self.dapr_app_id != "":
# Prefered option
if isinstance(self.dapr_app_id, str) and self.dapr_app_id.endswith("/"):
# Remove trailing slash
self.dapr_app_id = self.dapr_app_id[:-1]
url = f"{self._base_url}/{self.dapr_app_id}/method/{self.path if path == '' else path}"
elif self.dapr_http_endpoint != "":
# Dapr HTTPEndpoint
if isinstance(
self.dapr_http_endpoint, str
) and self.dapr_http_endpoint.endswith("/"):
# Remove trailing slash
self.dapr_http_endpoint = self.dapr_http_endpoint[:-1]
url = f"{self._base_url}/{self.dapr_http_endpoint}/method/{self.path if path == '' else path}"
elif self.http_endpoint != "":
# FQDN URL
if isinstance(self.http_endpoint, str) and self.http_endpoint.endswith(
"/"
):
# Remove trailing slash
self.http_endpoint = self.http_endpoint[:-1]
url = f"{self._base_url}/{self.http_endpoint}/method/{self.path if path == '' else path}"
elif endpoint != "":
# Fallback to default
if isinstance(endpoint, str) and endpoint.endswith("/"):
# Remove trailing slash
endpoint = endpoint[:-1]
url = f"{self._base_url}/{endpoint}/method/{self.path if path == '' else path}"
else:
raise ToolError(
"No endpoint provided. Please provide a valid dapr-app-id, HTTPEndpoint or endpoint."
)
except Exception as e:
logger.error(f"Error validating endpoint: {e}")
raise ToolError(
"Error occured while validating the endpoint. Please check the provided values."
)
if not self._validate_url(url):
raise ToolError(f"'{url}' is not a valid URL.")
return url
def _validate_url(self, url) -> bool:
"""
Valides URL for HTTP requests
"""
logger.debug(f"[HTTP] Url to be validated: {url}")
try:
parsed_url = urlparse(url=url)
return all([parsed_url.scheme, parsed_url.netloc])
except AttributeError:
return False