Private
Public Access
Revert "merge: tier2/phase2_4_5_call_site_completion_20260621 (parent + follow-up + Phase 6e analysis)"
This reverts commitf914b2bcd4, reversing changes made to7fef95cc87.
This commit is contained in:
+46
-78
@@ -1,59 +1,42 @@
|
||||
"""OpenAI-compatible API client for the Manual Slop ai_client layer.
|
||||
|
||||
Provides `send_openai_compatible(client, request, *, capabilities)` which
|
||||
calls any OpenAI-compatible chat completion endpoint and returns a
|
||||
`NormalizedResponse` (re-exported from src.openai_schemas).
|
||||
|
||||
CONVENTION: 1-space indentation. NO COMMENTS.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
from openai import (
|
||||
APIConnectionError,
|
||||
APIStatusError,
|
||||
AuthenticationError,
|
||||
BadRequestError,
|
||||
OpenAIError,
|
||||
PermissionDeniedError,
|
||||
RateLimitError,
|
||||
)
|
||||
from openai import OpenAIError, RateLimitError, AuthenticationError, PermissionDeniedError, APIConnectionError, APIStatusError, BadRequestError
|
||||
|
||||
from src.openai_schemas import (
|
||||
ChatMessage,
|
||||
NormalizedResponse,
|
||||
OpenAICompatibleRequest,
|
||||
ToolCall,
|
||||
ToolCallFunction,
|
||||
UsageStats,
|
||||
)
|
||||
from src.result_types import ErrorInfo, ErrorKind, Result
|
||||
|
||||
__all__ = [
|
||||
"ChatMessage",
|
||||
"NormalizedResponse",
|
||||
"OpenAICompatibleRequest",
|
||||
"ToolCall",
|
||||
"ToolCallFunction",
|
||||
"UsageStats",
|
||||
]
|
||||
|
||||
|
||||
def _to_typed_tool_call(tc: Any) -> ToolCall:
|
||||
return ToolCall(
|
||||
id=getattr(tc, "id", "") or "",
|
||||
type=getattr(tc, "type", "function"),
|
||||
function=ToolCallFunction(
|
||||
name=getattr(tc.function, "name", "") or "",
|
||||
arguments=getattr(tc.function, "arguments", "{}") or "{}",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _to_dict_tool_call(tc: ToolCall) -> dict[str, Any]:
|
||||
return tc.to_dict()
|
||||
@dataclass(frozen=True)
|
||||
class NormalizedResponse:
|
||||
text: str
|
||||
tool_calls: list[dict[str, Any]]
|
||||
usage_input_tokens: int
|
||||
usage_output_tokens: int
|
||||
usage_cache_read_tokens: int
|
||||
usage_cache_creation_tokens: int
|
||||
raw_response: Any
|
||||
|
||||
@dataclass
|
||||
class OpenAICompatibleRequest:
|
||||
messages: list[dict[str, Any]]
|
||||
model: str
|
||||
temperature: float = 0.0
|
||||
top_p: float = 1.0
|
||||
max_tokens: int = 8192
|
||||
tools: Optional[list[dict[str, Any]]] = None
|
||||
tool_choice: str = "auto"
|
||||
stream: bool = False
|
||||
stream_callback: Optional[Callable[[str], None]] = None
|
||||
extra_body: Optional[dict[str, Any]] = None
|
||||
def _to_dict_tool_call(tc: Any) -> dict[str, Any]:
|
||||
return {
|
||||
"id": getattr(tc, "id", None),
|
||||
"type": getattr(tc, "type", "function"),
|
||||
"function": {
|
||||
"name": getattr(tc.function, "name", None),
|
||||
"arguments": getattr(tc.function, "arguments", "{}"),
|
||||
},
|
||||
}
|
||||
|
||||
def _classify_openai_compatible_error(exc: Exception, source: str = "openai_compatible") -> ErrorInfo:
|
||||
if isinstance(exc, RateLimitError):
|
||||
@@ -76,17 +59,15 @@ def _classify_openai_compatible_error(exc: Exception, source: str = "openai_comp
|
||||
return ErrorInfo(kind=ErrorKind.QUOTA, message=str(exc), source=source, original=exc)
|
||||
return ErrorInfo(kind=ErrorKind.UNKNOWN, message=str(exc), source=source, original=exc)
|
||||
|
||||
|
||||
def send_openai_compatible(
|
||||
client: Any,
|
||||
request: OpenAICompatibleRequest,
|
||||
*,
|
||||
capabilities: Any,
|
||||
) -> Result[NormalizedResponse]:
|
||||
messages_dicts = [m.to_dict() if hasattr(m, "to_dict") else m for m in request.messages]
|
||||
kwargs: dict[str, Any] = {
|
||||
"model": request.model,
|
||||
"messages": messages_dicts,
|
||||
"messages": request.messages,
|
||||
"temperature": request.temperature,
|
||||
"top_p": request.top_p,
|
||||
"max_tokens": request.max_tokens,
|
||||
@@ -104,32 +85,27 @@ def send_openai_compatible(
|
||||
response = _send_blocking(client, kwargs)
|
||||
return Result(data=response)
|
||||
except OpenAIError as exc:
|
||||
empty_resp = NormalizedResponse(
|
||||
text="",
|
||||
tool_calls=(),
|
||||
usage=UsageStats(input_tokens=0, output_tokens=0),
|
||||
raw_response=None,
|
||||
)
|
||||
empty_resp = NormalizedResponse(text="", tool_calls=[], usage_input_tokens=0, usage_output_tokens=0, usage_cache_read_tokens=0, usage_cache_creation_tokens=0, raw_response=None)
|
||||
return Result(data=empty_resp, errors=[_classify_openai_compatible_error(exc, source="openai_compatible")])
|
||||
|
||||
|
||||
def _send_blocking(client: Any, kwargs: dict[str, Any]) -> NormalizedResponse:
|
||||
resp = client.chat.completions.create(**kwargs)
|
||||
msg = resp.choices[0].message
|
||||
tool_calls_raw = msg.tool_calls or []
|
||||
tool_calls: tuple[ToolCall, ...] = tuple(_to_typed_tool_call(tc) for tc in tool_calls_raw)
|
||||
tool_calls: list[dict[str, Any]] = []
|
||||
for tc in tool_calls_raw:
|
||||
tool_calls.append(_to_dict_tool_call(tc))
|
||||
usage = getattr(resp, "usage", None)
|
||||
return NormalizedResponse(
|
||||
text=msg.content or "",
|
||||
tool_calls=tool_calls,
|
||||
usage=UsageStats(
|
||||
input_tokens=int(getattr(usage, "prompt_tokens", 0) or 0),
|
||||
output_tokens=int(getattr(usage, "completion_tokens", 0) or 0),
|
||||
),
|
||||
usage_input_tokens=int(getattr(usage, "prompt_tokens", 0) or 0),
|
||||
usage_output_tokens=int(getattr(usage, "completion_tokens", 0) or 0),
|
||||
usage_cache_read_tokens=0,
|
||||
usage_cache_creation_tokens=0,
|
||||
raw_response=resp,
|
||||
)
|
||||
|
||||
|
||||
def _send_streaming(client: Any, kwargs: dict[str, Any], callback: Optional[Callable[[str], None]]) -> NormalizedResponse:
|
||||
kwargs_stream = dict(kwargs)
|
||||
kwargs_stream["stream"] = True
|
||||
@@ -163,20 +139,12 @@ def _send_streaming(client: Any, kwargs: dict[str, Any], callback: Optional[Call
|
||||
if chunk_usage is not None:
|
||||
usage_input = int(getattr(chunk_usage, "prompt_tokens", 0) or 0)
|
||||
usage_output = int(getattr(chunk_usage, "completion_tokens", 0) or 0)
|
||||
tool_calls_typed: tuple[ToolCall, ...] = tuple(
|
||||
ToolCall(
|
||||
id=acc["id"] or "",
|
||||
type=acc["type"],
|
||||
function=ToolCallFunction(
|
||||
name=acc["function"]["name"] or "",
|
||||
arguments=acc["function"]["arguments"] or "{}",
|
||||
),
|
||||
)
|
||||
for acc in (tool_calls_acc[k] for k in sorted(tool_calls_acc.keys()))
|
||||
)
|
||||
return NormalizedResponse(
|
||||
text="".join(text_parts),
|
||||
tool_calls=tool_calls_typed,
|
||||
usage=UsageStats(input_tokens=usage_input, output_tokens=usage_output),
|
||||
tool_calls=[tool_calls_acc[k] for k in sorted(tool_calls_acc.keys())],
|
||||
usage_input_tokens=usage_input,
|
||||
usage_output_tokens=usage_output,
|
||||
usage_cache_read_tokens=0,
|
||||
usage_cache_creation_tokens=0,
|
||||
raw_response=None,
|
||||
)
|
||||
Reference in New Issue
Block a user