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

209 lines
7.8 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 logging
from datetime import date, datetime
from typing import Any, Dict, Iterable, List, Literal, Optional, Type, Union
from pydantic import BaseModel, ValidationError
from dapr_agents.llm.utils.structure import StructureHandler
from dapr_agents.prompt.prompty import Prompty, PromptyHelper
from dapr_agents.tool.base import AgentTool
from dapr_agents.tool.utils.tool import ToolHelper
from dapr_agents.types.message import BaseMessage
logger = logging.getLogger(__name__)
def _make_json_serializable(obj: Any) -> Any:
"""Recursively convert datetime/date to ISO strings for JSON serialization."""
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, date):
return obj.isoformat()
if isinstance(obj, dict):
return {k: _make_json_serializable(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_make_json_serializable(v) for v in obj]
return obj
class RequestHandler:
"""
Handles the preparation of requests for language models.
"""
@staticmethod
def process_prompty_messages(
prompty: Prompty, inputs: Dict[str, Any] = {}
) -> List[Dict[str, Any]]:
"""
Process and format messages based on Prompty template and provided inputs.
Args:
prompty (Prompty): The Prompty instance containing the template and settings.
inputs (Dict[str, Any]): Input variables for the Prompty template (default is an empty dictionary).
Returns:
List[Dict[str, Any]]: Processed and prepared messages.
"""
# Prepare inputs and generate messages from Prompty content
api_type = prompty.model.api
prepared_inputs = PromptyHelper.prepare_inputs(
inputs, prompty.inputs, prompty.sample
)
messages = PromptyHelper.to_prompt(
prompty.content, prepared_inputs, api_type=api_type
)
return messages
@staticmethod
def normalize_chat_messages(
messages: Union[
str,
Dict[str, Any],
BaseMessage,
Iterable[Union[Dict[str, Any], BaseMessage]],
],
) -> List[Dict[str, Any]]:
"""
Normalize and validate the input messages into a list of dictionaries.
Args:
messages (Union[str, Dict[str, Any], BaseMessage, Iterable[Union[Dict[str, Any], BaseMessage]]]):
Input messages in various formats (string, dict, BaseMessage, or an iterable).
Returns:
List[Dict[str, Any]]: A list of normalized message dictionaries with keys 'role' and 'content'.
Raises:
ValueError: If the input format is unsupported or if required fields are missing in a dictionary.
"""
# Initialize an empty list to store the normalized messages
normalized_messages = []
# Use a queue to process messages iteratively and handle nested structures
queue = [messages]
while queue:
msg = queue.pop(0)
if isinstance(msg, str):
normalized_messages.append({"role": "user", "content": msg})
elif isinstance(msg, BaseMessage):
normalized_messages.append(msg.model_dump())
elif isinstance(msg, dict):
role = msg.get("role")
if role not in {"user", "assistant", "tool", "system"}:
raise ValueError(
f"Unrecognized role '{role}'. Supported roles are 'user', 'assistant', 'tool', or 'system'."
)
normalized_messages.append(msg)
elif isinstance(msg, Iterable) and not isinstance(msg, (str, dict)):
queue.extend(msg)
else:
raise ValueError(f"Unsupported message format: {type(msg)}")
return normalized_messages
@staticmethod
def process_params(
params: Dict[str, Any],
llm_provider: str,
tools: Optional[List[Union[AgentTool, Dict[str, Any]]]] = None,
response_format: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
structured_mode: Literal["json", "function_call"] = "json",
) -> Dict[str, Any]:
"""
Prepare request parameters for the language model.
Args:
params: Raw request params (messages/inputs, model, etc.).
llm_provider: Provider key, e.g. "openai", "dapr".
tools: Tools to expose to the model (AgentTool or already-shaped dicts).
response_format:
- If structured_mode == "json": a JSON Schema dict or a Pydantic model
(we'll convert) to request raw JSON output.
- If structured_mode == "function_call": a Pydantic model describing
the function/tool signature for model-side function calling.
structured_mode: "json" for raw JSON structured output,
"function_call" for tool/function calling.
Returns:
A params dict ready for the target provider.
"""
# Tools
if tools:
logger.info("Tools are available in the request.")
params["tools"] = [
ToolHelper.format_tool(t, tool_format=llm_provider) for t in tools
]
# Structured output
if response_format:
logger.info(f"Structured Mode Activated! mode={structured_mode}")
# If we're on Dapr, we cannot rely on OpenAI-style `response_format`.
# Add a small system nudge to enforce JSON-only output so we can parse reliably.
if llm_provider == "dapr":
params = StructureHandler.ensure_json_only_system_prompt(params)
# Generate provider-specific request params
params = StructureHandler.generate_request(
response_format=response_format,
llm_provider=llm_provider,
structured_mode=structured_mode,
**params,
)
return params
@staticmethod
def make_params_json_serializable(params: Dict[str, Any]) -> Dict[str, Any]:
"""
Return a copy of params with datetime/date values converted to ISO strings
so the dict is safe for JSON serialization (e.g. OpenAI API request body).
"""
return _make_json_serializable(params)
@staticmethod
def validate_request(
request: Union[BaseModel, Dict[str, Any]], request_class: Type[BaseModel]
) -> BaseModel:
"""
Validate and transform a dictionary into a Pydantic object.
Args:
request (Union[BaseModel, Dict[str, Any]]): The request data as a dictionary or a Pydantic object.
request_class (Type[BaseModel]): The Pydantic model class for validation.
Returns:
BaseModel: A validated Pydantic object.
Raises:
ValueError: If validation fails.
"""
if isinstance(request, dict):
try:
request = request_class(**request)
except ValidationError as e:
raise ValueError(f"Validation error: {e}")
try:
validated_request = request_class.model_validate(request)
except ValidationError as e:
raise ValueError(f"Validation error: {e}")
return validated_request