Unfucked gemini's mess

This commit is contained in:
2025-12-07 03:27:45 +01:00
parent 5b71233fb0
commit a923a760ef
24 changed files with 1885 additions and 1282 deletions
+19 -14
View File
@@ -51,15 +51,16 @@ class DeepSeekClient:
logger.info(f"DeepSeek client initialized with model: {self.model}")
def complete(self, messages: list[dict[str, Any]]) -> str:
def complete(self, messages: list[dict[str, Any]], tools: list[dict[str, Any]] | None = None) -> dict[str, Any]:
"""
Generate a completion from the LLM.
Args:
messages: List of message dicts with 'role' and 'content' keys
tools: Optional list of tool specifications (OpenAI format)
Returns:
Generated text response
OpenAI-compatible message dict with 'role', 'content', and optionally 'tool_calls'
Raises:
LLMAPIError: If API request fails
@@ -72,12 +73,14 @@ class DeepSeekClient:
for msg in messages:
if not isinstance(msg, dict):
raise ValueError(f"Each message must be a dict, got {type(msg)}")
if "role" not in msg or "content" not in msg:
raise ValueError(
f"Each message must have 'role' and 'content' keys, got {msg.keys()}"
)
if msg["role"] not in ("system", "user", "assistant"):
if "role" not in msg:
raise ValueError(f"Message must have 'role' key, got {msg.keys()}")
# Allow system, user, assistant, and tool roles
if msg["role"] not in ("system", "user", "assistant", "tool"):
raise ValueError(f"Invalid role: {msg['role']}")
# Content is optional for tool messages (they may have tool_call_id instead)
if msg["role"] != "tool" and "content" not in msg:
raise ValueError(f"Non-tool message must have 'content' key, got {msg.keys()}")
url = f"{self.base_url}/v1/chat/completions"
headers = {
@@ -89,9 +92,13 @@ class DeepSeekClient:
"messages": messages,
"temperature": settings.temperature,
}
# Add tools if provided
if tools:
payload["tools"] = tools
try:
logger.debug(f"Sending request to {url} with {len(messages)} messages")
logger.debug(f"Sending request to {url} with {len(messages)} messages and {len(tools) if tools else 0} tools")
response = requests.post(
url, headers=headers, json=payload, timeout=self.timeout
)
@@ -105,13 +112,11 @@ class DeepSeekClient:
if "message" not in data["choices"][0]:
raise LLMAPIError("Invalid API response: missing 'message' in choice")
if "content" not in data["choices"][0]["message"]:
raise LLMAPIError("Invalid API response: missing 'content' in message")
# Return the full message dict (OpenAI format)
message = data["choices"][0]["message"]
logger.debug(f"Received response: {message.get('content', '')[:100]}...")
content = data["choices"][0]["message"]["content"]
logger.debug(f"Received response with {len(content)} characters")
return content
return message
except Timeout as e:
logger.error(f"Request timeout after {self.timeout}s: {e}")
+19 -14
View File
@@ -66,15 +66,16 @@ class OllamaClient:
logger.info(f"Ollama client initialized with model: {self.model}")
def complete(self, messages: list[dict[str, Any]]) -> str:
def complete(self, messages: list[dict[str, Any]], tools: list[dict[str, Any]] | None = None) -> dict[str, Any]:
"""
Generate a completion from the LLM.
Args:
messages: List of message dicts with 'role' and 'content' keys
tools: Optional list of tool specifications (OpenAI format)
Returns:
Generated text response
OpenAI-compatible message dict with 'role', 'content', and optionally 'tool_calls'
Raises:
LLMAPIError: If API request fails
@@ -87,12 +88,14 @@ class OllamaClient:
for msg in messages:
if not isinstance(msg, dict):
raise ValueError(f"Each message must be a dict, got {type(msg)}")
if "role" not in msg or "content" not in msg:
raise ValueError(
f"Each message must have 'role' and 'content' keys, got {msg.keys()}"
)
if msg["role"] not in ("system", "user", "assistant"):
if "role" not in msg:
raise ValueError(f"Message must have 'role' key, got {msg.keys()}")
# Allow system, user, assistant, and tool roles
if msg["role"] not in ("system", "user", "assistant", "tool"):
raise ValueError(f"Invalid role: {msg['role']}")
# Content is optional for tool messages (they may have tool_call_id instead)
if msg["role"] != "tool" and "content" not in msg:
raise ValueError(f"Non-tool message must have 'content' key, got {msg.keys()}")
url = f"{self.base_url}/api/chat"
payload = {
@@ -103,9 +106,13 @@ class OllamaClient:
"temperature": self.temperature,
},
}
# Add tools if provided
if tools:
payload["tools"] = tools
try:
logger.debug(f"Sending request to {url} with {len(messages)} messages")
logger.debug(f"Sending request to {url} with {len(messages)} messages and {len(tools) if tools else 0} tools")
response = requests.post(url, json=payload, timeout=self.timeout)
response.raise_for_status()
data = response.json()
@@ -114,13 +121,11 @@ class OllamaClient:
if "message" not in data:
raise LLMAPIError("Invalid API response: missing 'message'")
if "content" not in data["message"]:
raise LLMAPIError("Invalid API response: missing 'content' in message")
# Return the full message dict (OpenAI format)
message = data["message"]
logger.debug(f"Received response: {message.get('content', '')[:100]}...")
content = data["message"]["content"]
logger.debug(f"Received response with {len(content)} characters")
return content
return message
except Timeout as e:
logger.error(f"Request timeout after {self.timeout}s: {e}")