chore: initial public snapshot for github upload
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Policy endpoints package.
|
||||
|
||||
Re-exports everything from endpoints module so existing imports
|
||||
like `from litellm.proxy.management_endpoints.policy_endpoints import router`
|
||||
continue to work. Patch targets also resolve correctly since names
|
||||
are imported directly into this namespace.
|
||||
"""
|
||||
|
||||
from litellm.proxy.management_endpoints.policy_endpoints.endpoints import * # noqa: F401, F403
|
||||
from litellm.proxy.management_endpoints.policy_endpoints.endpoints import ( # noqa: F401
|
||||
_build_all_names_per_competitor,
|
||||
_build_comparison_blocked_words,
|
||||
_build_competitor_guardrail_definitions,
|
||||
_build_name_blocked_words,
|
||||
_build_recommendation_blocked_words,
|
||||
_build_refinement_prompt,
|
||||
_clean_competitor_line,
|
||||
_parse_variations_response,
|
||||
)
|
||||
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
AI Policy Suggester - uses LLM tool calling to suggest policy templates
|
||||
based on user-provided attack examples and descriptions.
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import List, Optional
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.constants import DEFAULT_COMPETITOR_DISCOVERY_MODEL
|
||||
|
||||
SUGGEST_TOOL = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "select_policy_templates",
|
||||
"description": "Select one or more policy templates that best match the user's security requirements",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"selected_templates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template_id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the selected template",
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"description": "Brief reason why this template matches",
|
||||
},
|
||||
},
|
||||
"required": ["template_id", "reason"],
|
||||
},
|
||||
"description": "List of templates that match the user's requirements",
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string",
|
||||
"description": "Overall explanation of why these templates were suggested",
|
||||
},
|
||||
},
|
||||
"required": ["selected_templates", "explanation"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class AiPolicySuggester:
|
||||
"""Suggests policy templates using LLM tool calling."""
|
||||
|
||||
async def suggest(
|
||||
self,
|
||||
templates: list,
|
||||
attack_examples: List[str],
|
||||
description: str,
|
||||
model: Optional[str] = None,
|
||||
) -> dict:
|
||||
system_prompt = self._build_system_prompt(templates)
|
||||
user_prompt = self._build_user_prompt(attack_examples, description)
|
||||
model = model or DEFAULT_COMPETITOR_DISCOVERY_MODEL
|
||||
|
||||
try:
|
||||
response = await litellm.acompletion(
|
||||
model=model,
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt},
|
||||
],
|
||||
tools=[SUGGEST_TOOL],
|
||||
tool_choice={
|
||||
"type": "function",
|
||||
"function": {"name": "select_policy_templates"},
|
||||
},
|
||||
temperature=0.2,
|
||||
)
|
||||
|
||||
tool_calls = response.choices[0].message.tool_calls # type: ignore
|
||||
if not tool_calls:
|
||||
return {
|
||||
"selected_templates": [],
|
||||
"explanation": "No templates could be matched to your requirements.",
|
||||
}
|
||||
|
||||
result = json.loads(tool_calls[0].function.arguments)
|
||||
|
||||
valid_ids = {t["id"] for t in templates}
|
||||
result["selected_templates"] = [
|
||||
s
|
||||
for s in result.get("selected_templates", [])
|
||||
if s.get("template_id") in valid_ids
|
||||
]
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error("AI policy suggestion failed: %s", e)
|
||||
raise
|
||||
|
||||
def _build_system_prompt(self, templates: list) -> str:
|
||||
template_descriptions = []
|
||||
for t in templates:
|
||||
examples = t.get("example_sentences", [])
|
||||
examples_str = ", ".join(f'"{e}"' for e in examples) if examples else "none"
|
||||
entry = (
|
||||
f"- ID: {t['id']}\n"
|
||||
f" Title: {t['title']}\n"
|
||||
f" Description: {t['description']}\n"
|
||||
f" Example attacks it protects against: {examples_str}"
|
||||
)
|
||||
template_descriptions.append(entry)
|
||||
|
||||
return (
|
||||
"You are a security policy advisor. The user will describe attacks or content "
|
||||
"they want to block. Your job is to select the most relevant policy templates "
|
||||
"from the available set. Use the select_policy_templates tool to return your "
|
||||
"selections. Only select templates that are clearly relevant to what the user "
|
||||
"wants to block.\n\n"
|
||||
"Available templates:\n\n" + "\n\n".join(template_descriptions)
|
||||
)
|
||||
|
||||
def _build_user_prompt(self, attack_examples: List[str], description: str) -> str:
|
||||
parts = []
|
||||
filtered_examples = [e for e in attack_examples if e.strip()]
|
||||
if filtered_examples:
|
||||
parts.append("Example attack prompts I want to block:")
|
||||
for i, ex in enumerate(filtered_examples, 1):
|
||||
parts.append(f" {i}. {ex}")
|
||||
if description.strip():
|
||||
parts.append(f"\nDescription of what I want to block: {description}")
|
||||
return "\n".join(parts)
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user