Connector calls, semantic rules, and DuckDB memory keep long runs stable, and stream retry stops chats from stalling. Co-authored-by: Cursor <cursoragent@cursor.com>
145 lines
3.7 KiB
Python
145 lines
3.7 KiB
Python
"""Error taxonomy for native connector calls."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
|
|
class NativeConnectorError(Exception):
|
|
error_type = "connector_error"
|
|
http_sent = False
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
*,
|
|
function: Optional[str] = None,
|
|
details: Optional[Dict[str, Any]] = None,
|
|
) -> None:
|
|
super().__init__(message)
|
|
self.message = message
|
|
self.function = function
|
|
self.details = details or {}
|
|
|
|
def to_payload(self) -> Dict[str, Any]:
|
|
payload: Dict[str, Any] = {
|
|
"ok": False,
|
|
"error_type": self.error_type,
|
|
"message": self.message,
|
|
"http_sent": self.http_sent,
|
|
}
|
|
if self.function:
|
|
payload["function"] = self.function
|
|
payload.update(self.details)
|
|
return payload
|
|
|
|
|
|
class CatalogError(NativeConnectorError):
|
|
error_type = "catalog_error"
|
|
|
|
|
|
class ConnectorNotAttached(NativeConnectorError):
|
|
error_type = "connector_not_attached"
|
|
|
|
|
|
class ConnectorNotFound(NativeConnectorError):
|
|
error_type = "connector_not_found"
|
|
|
|
|
|
class ConnectorAmbiguous(NativeConnectorError):
|
|
error_type = "connector_ambiguous"
|
|
|
|
def __init__(self, names: List[str]) -> None:
|
|
listing = "\n".join(f"- {name}" for name in names)
|
|
super().__init__(
|
|
"Several native connectors are attached.\n\nSpecify connection:\n" + listing,
|
|
details={"connections": names},
|
|
)
|
|
|
|
|
|
class ProviderNotFound(NativeConnectorError):
|
|
error_type = "provider_not_found"
|
|
|
|
|
|
class FunctionNotFound(NativeConnectorError):
|
|
error_type = "unknown_function"
|
|
|
|
def __init__(self, function: str, provider_label: str, suggestions: List[str]) -> None:
|
|
super().__init__(
|
|
f"Function '{function}' does not exist for {provider_label}.",
|
|
function=function,
|
|
details={
|
|
"suggestions": suggestions,
|
|
"instruction": "Use only predefined function names.",
|
|
},
|
|
)
|
|
|
|
|
|
class FunctionDisabled(NativeConnectorError):
|
|
error_type = "function_disabled"
|
|
|
|
|
|
class OperationNotAllowed(NativeConnectorError):
|
|
error_type = "operation_not_allowed"
|
|
|
|
def __init__(self, function: str, effect: str) -> None:
|
|
super().__init__(
|
|
"This connector is read-only. No HTTP request was sent.",
|
|
function=function,
|
|
details={"effect": effect},
|
|
)
|
|
|
|
|
|
class ValidationFailed(NativeConnectorError):
|
|
error_type = "validation_error"
|
|
|
|
|
|
class AuthenticationFailed(NativeConnectorError):
|
|
"""Local credential failure. Remote 401 uses RemoteCallFailed."""
|
|
|
|
error_type = "authentication_error"
|
|
|
|
|
|
class RemoteCallFailed(NativeConnectorError):
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
*,
|
|
error_type: str,
|
|
function: Optional[str] = None,
|
|
details: Optional[Dict[str, Any]] = None,
|
|
) -> None:
|
|
super().__init__(message, function=function, details=details)
|
|
self.error_type = error_type
|
|
self.http_sent = True
|
|
|
|
|
|
class TransportFailed(NativeConnectorError):
|
|
error_type = "transport_error"
|
|
|
|
|
|
class CallTimeout(NativeConnectorError):
|
|
error_type = "timeout_error"
|
|
|
|
|
|
class ResponseTooLarge(NativeConnectorError):
|
|
error_type = "response_too_large"
|
|
http_sent = True
|
|
|
|
|
|
class InvalidJSONResponse(NativeConnectorError):
|
|
error_type = "invalid_json_response"
|
|
http_sent = True
|
|
|
|
|
|
class ResultMaterializationError(NativeConnectorError):
|
|
error_type = "result_materialization_error"
|
|
http_sent = True
|
|
|
|
|
|
class AccuracyGuard(NativeConnectorError):
|
|
"""An exact management figure cannot be verified. No substitute total is included."""
|
|
|
|
error_type = "accuracy_guard"
|
|
http_sent = True
|