mirror of
https://github.com/SHOGGOTH-SECTOR/sica-fondt.git
synced 2026-08-01 08:30:20 +00:00
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
217 lines
8.5 KiB
Python
217 lines
8.5 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.
|
|
#
|
|
|
|
from dapr_agents.types.llm import DaprInferenceClientConfig
|
|
from dapr_agents.llm.base import LLMClientBase
|
|
from dapr.clients import DaprClient
|
|
from dapr.clients.grpc import conversation as dapr_conversation
|
|
from typing import Dict, Any, List, Optional
|
|
from pydantic import model_validator
|
|
from google.protobuf import json_format
|
|
from google.protobuf.struct_pb2 import Struct as GrpcStruct
|
|
|
|
import json
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DaprInferenceClient:
|
|
def __init__(self):
|
|
pass # No persistent client - use per-call context manager
|
|
|
|
def get_metadata(self):
|
|
"""Fetch Dapr sidecar metadata using a fresh per-call client."""
|
|
with DaprClient() as client:
|
|
return client.get_metadata()
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────
|
|
# Alpha2 (Tool Calling) support
|
|
# ──────────────────────────────────────────────────────────────────────────
|
|
def _convert_openai_tools_to_conversation_tools(
|
|
self, tools: Optional[List[Dict[str, Any]]]
|
|
) -> Optional[List[dapr_conversation.ConversationTools]]:
|
|
"""
|
|
Convert OpenAI-style tools (type=function, function={name, description, parameters})
|
|
into Dapr ConversationTools objects for Alpha2.
|
|
"""
|
|
if not tools:
|
|
return None
|
|
converted: List[dapr_conversation.ConversationTools] = []
|
|
for tool in tools:
|
|
fn = tool.get("function", {}) if isinstance(tool, dict) else {}
|
|
name = fn.get("name")
|
|
description = fn.get("description")
|
|
parameters = fn.get("parameters")
|
|
function_spec = dapr_conversation.ConversationToolsFunction(
|
|
name=name or "",
|
|
description=description or "",
|
|
parameters=parameters or {},
|
|
)
|
|
conv_tool = dapr_conversation.ConversationTools(function=function_spec)
|
|
converted.append(conv_tool)
|
|
return converted
|
|
|
|
def chat_completion_alpha2(
|
|
self,
|
|
*,
|
|
llm: str,
|
|
inputs: List[dapr_conversation.ConversationInputAlpha2],
|
|
scrub_pii: Optional[bool] = None,
|
|
temperature: Optional[float] = None,
|
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
tool_choice: Optional[str] = None,
|
|
context_id: Optional[str] = None,
|
|
parameters: Optional[Dict[str, Any]] = None,
|
|
response_format: Optional[Dict[str, Any]] = None,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Invoke Dapr Conversation API Alpha2 with optional tool-calling support and
|
|
convert the response into a simplified OpenAI-like JSON envelope.
|
|
"""
|
|
conv_tools = self._convert_openai_tools_to_conversation_tools(tools)
|
|
|
|
# TODO: Remove when langchaningo is updated in contrib to latest version with a fix for openai-like temperature
|
|
if temperature is None:
|
|
temperature = 1
|
|
|
|
with DaprClient() as client:
|
|
kwargs: Dict[str, Any] = dict(
|
|
name=llm,
|
|
inputs=inputs,
|
|
context_id=context_id,
|
|
parameters=parameters,
|
|
scrub_pii=scrub_pii,
|
|
temperature=temperature,
|
|
tools=conv_tools,
|
|
tool_choice=tool_choice,
|
|
)
|
|
if response_format is not None:
|
|
kwargs["response_format"] = json_format.ParseDict(
|
|
response_format, GrpcStruct()
|
|
)
|
|
|
|
response_alpha2 = client.converse_alpha2(**kwargs)
|
|
|
|
outputs: List[Dict[str, Any]] = []
|
|
for output in getattr(response_alpha2, "outputs", []) or []:
|
|
choices_list: List[Dict[str, Any]] = []
|
|
for choice in getattr(output, "choices", []) or []:
|
|
msg = getattr(choice, "message", None)
|
|
content = getattr(msg, "content", None) if msg else None
|
|
|
|
# Convert tool calls if present
|
|
tool_calls_json: Optional[List[Dict[str, Any]]] = None
|
|
if msg and getattr(msg, "tool_calls", None):
|
|
tool_calls_json = []
|
|
for tc in msg.tool_calls:
|
|
fn = getattr(tc, "function", None)
|
|
arguments = getattr(fn, "arguments", None) if fn else None
|
|
if isinstance(arguments, (dict, list)):
|
|
try:
|
|
arguments = json.dumps(arguments)
|
|
except Exception:
|
|
arguments = str(arguments)
|
|
elif arguments is None:
|
|
arguments = ""
|
|
|
|
tool_calls_json.append(
|
|
{
|
|
"id": getattr(tc, "id", ""),
|
|
"type": "function",
|
|
"function": {
|
|
"name": getattr(fn, "name", "") if fn else "",
|
|
"arguments": arguments,
|
|
},
|
|
}
|
|
)
|
|
|
|
choices_list.append(
|
|
{
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": content,
|
|
**(
|
|
{"tool_calls": tool_calls_json}
|
|
if tool_calls_json
|
|
else {}
|
|
),
|
|
},
|
|
"finish_reason": getattr(choice, "finish_reason", "stop"),
|
|
}
|
|
)
|
|
outputs.append({"choices": choices_list})
|
|
|
|
return {
|
|
"context_id": getattr(response_alpha2, "context_id", None),
|
|
"outputs": outputs,
|
|
}
|
|
|
|
|
|
class DaprInferenceClientBase(LLMClientBase):
|
|
"""
|
|
Base class for managing Dapr Inference API clients.
|
|
Handles client initialization, configuration, and shared logic.
|
|
"""
|
|
|
|
@model_validator(mode="before")
|
|
def validate_and_initialize(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
|
return values
|
|
|
|
def model_post_init(self, __context: Any) -> None:
|
|
"""
|
|
Initializes private attributes after validation.
|
|
"""
|
|
self._provider = "dapr"
|
|
|
|
# Set up the private config and client attributes
|
|
self._config = self.get_config()
|
|
self._client = self.get_client()
|
|
return super().model_post_init(__context)
|
|
|
|
def get_config(self) -> DaprInferenceClientConfig:
|
|
"""
|
|
Returns the appropriate configuration for the Dapr Conversation API.
|
|
"""
|
|
return DaprInferenceClientConfig()
|
|
|
|
def get_client(self) -> DaprInferenceClient:
|
|
"""
|
|
Initializes and returns the Dapr Inference client.
|
|
"""
|
|
return DaprInferenceClient()
|
|
|
|
@classmethod
|
|
def from_config(
|
|
cls, client_options: DaprInferenceClientConfig, timeout: float = 1500
|
|
):
|
|
"""
|
|
Initializes the DaprInferenceClientBase using DaprInferenceClientConfig.
|
|
|
|
Args:
|
|
client_options: The configuration options for the client.
|
|
timeout: Timeout for requests (default is 1500 seconds).
|
|
|
|
Returns:
|
|
DaprInferenceClientBase: The initialized client instance.
|
|
"""
|
|
return cls()
|
|
|
|
@property
|
|
def config(self) -> Dict[str, Any]:
|
|
return self._config
|
|
|
|
@property
|
|
def client(self) -> DaprInferenceClient:
|
|
return self._client
|