Skip to content

Commit 39950f9

Browse files
author
Mateusz
committed
Chore(unification): WIP
1 parent 54636fa commit 39950f9

14 files changed

Lines changed: 337 additions & 684 deletions

src/connectors/_openai_codex_connector.py

Lines changed: 7 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,132 +1902,15 @@ async def _prepare_payload(
19021902
)
19031903
return payload
19041904

1905-
def _normalize_chat_completions_request(
1906-
self, *args: Any, **kwargs: Any
1907-
) -> ConnectorChatCompletionsRequest:
1908-
"""Normalize canonical and legacy invocation shapes into one request contract."""
1909-
if len(args) == 1 and isinstance(args[0], ConnectorChatCompletionsRequest):
1910-
if kwargs:
1911-
unexpected = ", ".join(sorted(kwargs))
1912-
raise TypeError(
1913-
"OpenAICodexConnector.chat_completions received unexpected keyword "
1914-
f"arguments with canonical request: {unexpected}"
1915-
)
1916-
return args[0]
1917-
1918-
if len(args) > 1 and isinstance(args[0], ConnectorChatCompletionsRequest):
1919-
raise TypeError(
1920-
"OpenAICodexConnector.chat_completions received too many positional "
1921-
"arguments with canonical request invocation."
1922-
)
1923-
1924-
if (
1925-
"request" in kwargs
1926-
and isinstance(kwargs["request"], ConnectorChatCompletionsRequest)
1927-
and not args
1928-
):
1929-
canonical_request = cast(
1930-
ConnectorChatCompletionsRequest, kwargs.pop("request")
1931-
)
1932-
if kwargs:
1933-
unexpected = ", ".join(sorted(kwargs))
1934-
raise TypeError(
1935-
"OpenAICodexConnector.chat_completions received unexpected keyword "
1936-
f"arguments with canonical request: {unexpected}"
1937-
)
1938-
return canonical_request
1939-
1940-
legacy_fields = (
1941-
"request_data",
1942-
"processed_messages",
1943-
"effective_model",
1944-
"identity",
1945-
"cancellation_token",
1946-
"cancellation_coordinator",
1947-
"context",
1948-
)
1949-
if len(args) > len(legacy_fields):
1950-
raise TypeError(
1951-
"OpenAICodexConnector.chat_completions expected at most "
1952-
f"{len(legacy_fields)} positional arguments for legacy invocation, "
1953-
f"got {len(args)}."
1954-
)
1955-
1956-
legacy_values: dict[str, Any] = {}
1957-
for index, value in enumerate(args):
1958-
field_name = legacy_fields[index]
1959-
if field_name in kwargs:
1960-
raise TypeError(
1961-
"OpenAICodexConnector.chat_completions got multiple values for "
1962-
f"argument '{field_name}'."
1963-
)
1964-
legacy_values[field_name] = value
1965-
1966-
for field_name in legacy_fields:
1967-
if field_name in kwargs:
1968-
legacy_values[field_name] = kwargs.pop(field_name)
1969-
1970-
if "request" in kwargs and "request_data" not in legacy_values:
1971-
legacy_values["request_data"] = kwargs.pop("request")
1972-
1973-
options_value = kwargs.pop("options", None)
1974-
1975-
missing = object()
1976-
request_data = legacy_values.get("request_data", missing)
1977-
if request_data is missing:
1978-
raise TypeError(
1979-
"OpenAICodexConnector.chat_completions missing required argument "
1980-
"'request_data' (or canonical 'request')."
1981-
)
1982-
1983-
processed_messages = legacy_values.get("processed_messages", missing)
1984-
if processed_messages is missing or processed_messages is None:
1985-
request_messages = getattr(request_data, "messages", None)
1986-
if isinstance(request_messages, list | tuple):
1987-
processed_messages = list(request_messages)
1988-
else:
1989-
processed_messages = []
1990-
1991-
effective_model_value = legacy_values.get("effective_model", missing)
1992-
if isinstance(effective_model_value, str) and effective_model_value:
1993-
effective_model = effective_model_value
1994-
else:
1995-
model_hint = getattr(request_data, "model", None)
1996-
if isinstance(model_hint, str) and model_hint:
1997-
effective_model = model_hint
1998-
elif effective_model_value is missing:
1999-
raise TypeError(
2000-
"OpenAICodexConnector.chat_completions missing required argument "
2001-
"'effective_model'."
2002-
)
2003-
else:
2004-
effective_model = str(effective_model_value)
2005-
2006-
normalized_options: dict[str, Any] = {}
2007-
if isinstance(options_value, dict):
2008-
normalized_options.update(options_value)
2009-
elif options_value is not None:
2010-
normalized_options["options"] = options_value
2011-
if kwargs:
2012-
normalized_options.update(kwargs)
2013-
2014-
return ConnectorChatCompletionsRequest(
2015-
request=request_data,
2016-
processed_messages=processed_messages,
2017-
effective_model=effective_model,
2018-
identity=legacy_values.get("identity"),
2019-
cancellation_token=legacy_values.get("cancellation_token"),
2020-
cancellation_coordinator=legacy_values.get("cancellation_coordinator"),
2021-
context=legacy_values.get("context"),
2022-
options=normalized_options,
2023-
)
2024-
2025-
async def chat_completions( # type: ignore[override]
1905+
async def chat_completions(
20261906
self,
2027-
*args: Any,
2028-
**kwargs: Any,
1907+
request: ConnectorChatCompletionsRequest,
20291908
) -> ResponseEnvelope | StreamingResponseEnvelope:
2030-
request = self._normalize_chat_completions_request(*args, **kwargs)
1909+
if not isinstance(request, ConnectorChatCompletionsRequest):
1910+
raise TypeError(
1911+
"OpenAICodexConnector.chat_completions() requires a "
1912+
"ConnectorChatCompletionsRequest instance."
1913+
)
20311914

20321915
# Structural enforcement: check cancellation immediately if coordinator and token provided
20331916
if (

src/connectors/base.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,9 @@ async def chat_completions(
256256
Forwards a chat completion request to the LLM backend.
257257
258258
Args:
259-
request_data: The request payload as a domain `ChatRequest`.
260-
processed_messages: The list of messages after command processing.
261-
effective_model: The model name to be used after considering any overrides.
262-
identity: Application identity configuration for authentication.
263-
cancellation_token: Optional session key for cancellation scoping.
264-
If provided, enables cancellation gating and work registration.
265-
cancellation_coordinator: Optional cancellation coordinator for structural enforcement.
266-
If provided along with cancellation_token, enables connector-level cancellation checks
267-
immediately before HTTP request transmission.
268-
**kwargs: Additional keyword arguments for the backend.
259+
request: Canonical connector request containing the domain chat payload,
260+
processed messages, effective model, optional identity and cancellation
261+
fields, connector-facing context, and JSON-safe provider options.
269262
270263
Returns:
271264
Either a ResponseEnvelope for non-streaming requests or

src/connectors/contracts/__init__.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ class ConnectorRequestContext(InternalDTO):
5454
class ConnectorChatCompletionsRequest(InternalDTO):
5555
"""Canonical connector-facing request contract.
5656
57-
Bundles all inputs needed for connector invocation in a single typed contract.
58-
This replaces the permissive dict[str, Any] and **kwargs patterns used
59-
in the legacy connector API.
57+
Bundles all inputs needed for connector invocation in a single typed contract
58+
at the connector entry boundary.
6059
6160
Attributes:
6261
request: Canonical chat request payload
@@ -85,10 +84,7 @@ class ICanonicalChatCompletionsBackend(Protocol):
8584
Connectors implementing this protocol receive typed contracts and
8685
return typed response envelopes, eliminating dict/Any leakage at the boundary.
8786
88-
This protocol defines the canonical connector API that should be used
89-
for all new connector implementations. Legacy connectors continue to
90-
use LLMBackend.chat_completions() with permissive signatures, but
91-
core orchestration will prefer this canonical API when available.
87+
Core orchestration invokes backends through this contract.
9288
9389
The protocol is transport-agnostic and does not depend on FastAPI/Starlette types.
9490
"""

src/connectors/gemini_base/connector.py

Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,53 +1611,16 @@ async def _ensure_healthy(self) -> None:
16111611
self._health_checked = True
16121612
logger.info("Backend health check completed - ready for use")
16131613

1614-
async def chat_completions( # type: ignore[override]
1614+
async def chat_completions(
16151615
self,
1616-
request: ConnectorChatCompletionsRequest | Any = None,
1617-
*args: Any,
1618-
**kwargs: Any,
1616+
request: ConnectorChatCompletionsRequest,
16191617
) -> ResponseEnvelope | StreamingResponseEnvelope:
1620-
if isinstance(request, ConnectorChatCompletionsRequest):
1621-
return await self._chat_completions_canonical(request)
1622-
1623-
legacy_request_data = kwargs.pop("request_data", request)
1624-
legacy_processed_messages = kwargs.pop(
1625-
"processed_messages", args[0] if args else []
1626-
)
1627-
legacy_effective_model = kwargs.pop(
1628-
"effective_model", args[1] if len(args) > 1 else "unknown"
1629-
)
1630-
legacy_context = kwargs.pop("context", None)
1631-
normalized_effective_model = self._resolve_internal_effective_model(
1632-
legacy_effective_model
1633-
)
1634-
1635-
stream = getattr(legacy_request_data, "stream", False) or kwargs.get(
1636-
"stream", False
1637-
)
1638-
if stream:
1639-
return await self._chat_completions_code_assist_streaming(
1640-
request_data=legacy_request_data,
1641-
processed_messages=(
1642-
list(legacy_processed_messages)
1643-
if not isinstance(legacy_processed_messages, list)
1644-
else legacy_processed_messages
1645-
),
1646-
effective_model=normalized_effective_model,
1647-
context=legacy_context,
1648-
**kwargs,
1618+
if not isinstance(request, ConnectorChatCompletionsRequest):
1619+
raise TypeError(
1620+
"GeminiOAuthBaseConnector.chat_completions() requires a "
1621+
"ConnectorChatCompletionsRequest instance."
16491622
)
1650-
return await self._chat_completions_code_assist(
1651-
request_data=legacy_request_data,
1652-
processed_messages=(
1653-
list(legacy_processed_messages)
1654-
if not isinstance(legacy_processed_messages, list)
1655-
else legacy_processed_messages
1656-
),
1657-
effective_model=normalized_effective_model,
1658-
context=legacy_context,
1659-
**kwargs,
1660-
)
1623+
return await self._chat_completions_canonical(request)
16611624

16621625
def _resolve_internal_effective_model(self, effective_model: str) -> str:
16631626
model_name = effective_model

src/connectors/gemini_cloud_project.py

Lines changed: 10 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
import uuid
5454
from collections.abc import AsyncGenerator, Callable, Sequence
5555
from pathlib import Path
56-
from typing import TYPE_CHECKING, Any, cast
56+
from typing import TYPE_CHECKING, Any
5757

5858
import google.auth
5959
import google.auth.transport.requests
@@ -1292,125 +1292,17 @@ async def _ensure_healthy(self) -> None:
12921292
if logger.isEnabledFor(logging.INFO):
12931293
logger.info("Health check passed - backend is ready for use")
12941294

1295-
_LEGACY_CHAT_COMPLETIONS_PARAM_ORDER: tuple[str, ...] = (
1296-
"request_data",
1297-
"processed_messages",
1298-
"effective_model",
1299-
"identity",
1300-
"cancellation_token",
1301-
"cancellation_coordinator",
1302-
"context",
1303-
"options",
1304-
)
1305-
1306-
def _normalize_chat_completions_request(
1307-
self,
1308-
request: ConnectorChatCompletionsRequest | None,
1309-
args: tuple[Any, ...],
1310-
kwargs: dict[str, Any],
1311-
) -> ConnectorChatCompletionsRequest:
1312-
"""Normalize canonical and legacy invocation shapes into one request object."""
1313-
if isinstance(request, ConnectorChatCompletionsRequest):
1314-
if args or kwargs:
1315-
raise TypeError(
1316-
"GeminiCloudProjectConnector.chat_completions() canonical invocation accepts only "
1317-
"the `request` argument."
1318-
)
1319-
return request
1320-
1321-
legacy_values: dict[str, Any] = {}
1322-
legacy_kwargs = dict(kwargs)
1323-
1324-
positional_values: list[Any] = []
1325-
if request is not None:
1326-
positional_values.append(request)
1327-
positional_values.extend(args)
1328-
1329-
max_positional = len(self._LEGACY_CHAT_COMPLETIONS_PARAM_ORDER)
1330-
if len(positional_values) > max_positional:
1331-
raise TypeError(
1332-
"GeminiCloudProjectConnector.chat_completions() takes at most "
1333-
f"{max_positional} legacy positional arguments "
1334-
f"({len(positional_values)} given)."
1335-
)
1336-
1337-
for index, value in enumerate(positional_values):
1338-
param_name = self._LEGACY_CHAT_COMPLETIONS_PARAM_ORDER[index]
1339-
if param_name in legacy_kwargs:
1340-
raise TypeError(
1341-
"GeminiCloudProjectConnector.chat_completions() got multiple values for "
1342-
f"argument '{param_name}'."
1343-
)
1344-
legacy_values[param_name] = value
1345-
1346-
for param_name in self._LEGACY_CHAT_COMPLETIONS_PARAM_ORDER:
1347-
if param_name in legacy_kwargs:
1348-
legacy_values[param_name] = legacy_kwargs.pop(param_name)
1349-
1350-
required_legacy = self._LEGACY_CHAT_COMPLETIONS_PARAM_ORDER[:3]
1351-
missing_required = [
1352-
name for name in required_legacy if name not in legacy_values
1353-
]
1354-
if missing_required:
1355-
raise TypeError(
1356-
"GeminiCloudProjectConnector.chat_completions() missing required arguments: "
1357-
f"{', '.join(missing_required)}. "
1358-
"Provide canonical `request` or legacy "
1359-
"`request_data`, `processed_messages`, and `effective_model`."
1360-
)
1361-
1362-
processed_messages_raw = legacy_values["processed_messages"]
1363-
if processed_messages_raw is None:
1364-
processed_messages_seq: Sequence[ChatMessage] = ()
1365-
elif isinstance(processed_messages_raw, Sequence):
1366-
processed_messages_seq = cast(Sequence[ChatMessage], processed_messages_raw)
1367-
else:
1368-
raise TypeError(
1369-
"GeminiCloudProjectConnector.chat_completions() legacy `processed_messages` "
1370-
"must be a sequence."
1371-
)
1372-
1373-
effective_model = legacy_values["effective_model"]
1374-
if not isinstance(effective_model, str):
1375-
raise TypeError(
1376-
"GeminiCloudProjectConnector.chat_completions() legacy `effective_model` "
1377-
"must be a string."
1378-
)
1379-
1380-
options_from_legacy = legacy_values.get("options")
1381-
if options_from_legacy is None:
1382-
options: dict[str, Any] = {}
1383-
elif isinstance(options_from_legacy, dict):
1384-
options = dict(options_from_legacy)
1385-
else:
1386-
raise TypeError(
1387-
"GeminiCloudProjectConnector.chat_completions() legacy `options` must be a dict."
1388-
)
1389-
options.update(legacy_kwargs)
1390-
1391-
return ConnectorChatCompletionsRequest(
1392-
request=legacy_values["request_data"],
1393-
processed_messages=processed_messages_seq,
1394-
effective_model=effective_model,
1395-
identity=legacy_values.get("identity"),
1396-
cancellation_token=legacy_values.get("cancellation_token"),
1397-
cancellation_coordinator=legacy_values.get("cancellation_coordinator"),
1398-
context=legacy_values.get("context"),
1399-
options=options,
1400-
)
1401-
1402-
async def chat_completions( # type: ignore[override]
1295+
async def chat_completions(
14031296
self,
1404-
request: ConnectorChatCompletionsRequest | None = None,
1405-
*args: Any,
1406-
**kwargs: Any,
1297+
request: ConnectorChatCompletionsRequest,
14071298
) -> ResponseEnvelope | StreamingResponseEnvelope:
14081299
"""Handle chat completions using Google Code Assist API with user's GCP project."""
1409-
connector_request = self._normalize_chat_completions_request(
1410-
request=request,
1411-
args=args,
1412-
kwargs=kwargs,
1413-
)
1300+
if not isinstance(request, ConnectorChatCompletionsRequest):
1301+
raise TypeError(
1302+
"GeminiCloudProjectConnector.chat_completions() requires a "
1303+
"ConnectorChatCompletionsRequest instance."
1304+
)
1305+
connector_request = request
14141306
# Structural enforcement: check cancellation immediately if coordinator and token provided
14151307
if (
14161308
connector_request.cancellation_coordinator is not None
@@ -1424,8 +1316,7 @@ async def chat_completions( # type: ignore[override]
14241316
processed_messages = connector_request.processed_messages
14251317
effective_model = connector_request.effective_model
14261318

1427-
# Options not specifically used here but available in request.options if needed
1428-
# kwargs was previously passed down to _chat_completions_streaming / _chat_completions_standard
1319+
# Provider-specific options flow through ``ConnectorChatCompletionsRequest.options``.
14291320
kwargs = dict(connector_request.options) if connector_request.options else {}
14301321

14311322
# Runtime validation with descriptive errors

0 commit comments

Comments
 (0)