Remove client.chat resource (#105)
This was always temporary, but we are finally removing the chat resource from the ``Arcade`` and ``AsyncArcade`` clients.
This commit is contained in:
parent
6b716d6dde
commit
ff092ac303
6 changed files with 30 additions and 38 deletions
|
|
@ -8,7 +8,7 @@ from typing import Any, Optional
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
from openai import OpenAIError
|
from openai import OpenAI, OpenAIError
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.markup import escape
|
from rich.markup import escape
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
@ -256,7 +256,10 @@ def chat(
|
||||||
history.append({"role": "user", "content": user_input})
|
history.append({"role": "user", "content": user_input})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
chat_result = handle_chat_interaction(client, model, history, user_email, stream)
|
openai_client = OpenAI(api_key=config.api.key, base_url=config.engine_url)
|
||||||
|
chat_result = handle_chat_interaction(
|
||||||
|
openai_client, model, history, user_email, stream
|
||||||
|
)
|
||||||
except OpenAIError as e:
|
except OpenAIError as e:
|
||||||
console.print(f"❌ Arcade Chat failed with error: {e!s}", style="bold red")
|
console.print(f"❌ Arcade Chat failed with error: {e!s}", style="bold red")
|
||||||
continue
|
continue
|
||||||
|
|
@ -273,7 +276,7 @@ def chat(
|
||||||
try:
|
try:
|
||||||
history.pop()
|
history.pop()
|
||||||
chat_result = handle_chat_interaction(
|
chat_result = handle_chat_interaction(
|
||||||
client, model, history, user_email, stream
|
openai_client, model, history, user_email, stream
|
||||||
)
|
)
|
||||||
except OpenAIError as e:
|
except OpenAIError as e:
|
||||||
console.print(f"❌ Arcade Chat failed with error: {e!s}", style="bold red")
|
console.print(f"❌ Arcade Chat failed with error: {e!s}", style="bold red")
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
||||||
from typing import Callable, Union
|
from typing import Callable, Union
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
from openai import OpenAI
|
||||||
from openai.resources.chat.completions import ChatCompletionChunk, Stream
|
from openai.resources.chat.completions import ChatCompletionChunk, Stream
|
||||||
from openai.types.chat.chat_completion import Choice as ChatCompletionChoice
|
from openai.types.chat.chat_completion import Choice as ChatCompletionChoice
|
||||||
from openai.types.chat.chat_completion_chunk import Choice as ChatCompletionChunkChoice
|
from openai.types.chat.chat_completion_chunk import Choice as ChatCompletionChunkChoice
|
||||||
|
|
@ -247,7 +248,7 @@ class ChatInteractionResult:
|
||||||
|
|
||||||
|
|
||||||
def handle_chat_interaction(
|
def handle_chat_interaction(
|
||||||
client: Arcade, model: str, history: list[dict], user_email: str | None, stream: bool = False
|
client: OpenAI, model: str, history: list[dict], user_email: str | None, stream: bool = False
|
||||||
) -> ChatInteractionResult:
|
) -> ChatInteractionResult:
|
||||||
"""
|
"""
|
||||||
Handle a single chat-request/chat-response interaction for both streamed and non-streamed responses.
|
Handle a single chat-request/chat-response interaction for both streamed and non-streamed responses.
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ from arcade.client.errors import (
|
||||||
RateLimitError,
|
RateLimitError,
|
||||||
UnauthorizedError,
|
UnauthorizedError,
|
||||||
)
|
)
|
||||||
from arcade.client.schema import OPENAI_API_VERSION
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
ResponseT = TypeVar("ResponseT")
|
ResponseT = TypeVar("ResponseT")
|
||||||
|
|
@ -22,11 +21,15 @@ ResponseT = TypeVar("ResponseT")
|
||||||
class BaseResource(Generic[T]):
|
class BaseResource(Generic[T]):
|
||||||
"""Base class for all resources."""
|
"""Base class for all resources."""
|
||||||
|
|
||||||
_path: str
|
_path: str = ""
|
||||||
|
_version: str = "v1"
|
||||||
|
|
||||||
def __init__(self, client: T) -> None:
|
def __init__(self, client: T) -> None:
|
||||||
self._client = client
|
self._client = client
|
||||||
self._resource_path = self._client._base_url + self._path # type: ignore[attr-defined]
|
self._resource_path = urljoin(
|
||||||
|
self._client._base_url, # type: ignore[attr-defined]
|
||||||
|
f"{self._version}/{self._path}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseArcadeClient:
|
class BaseArcadeClient:
|
||||||
|
|
@ -37,8 +40,8 @@ class BaseArcadeClient:
|
||||||
base_url: str | None = None,
|
base_url: str | None = None,
|
||||||
api_key: str | None = None,
|
api_key: str | None = None,
|
||||||
headers: dict[str, str] | None = None,
|
headers: dict[str, str] | None = None,
|
||||||
timeout: float | Timeout = 10.0,
|
timeout: float | Timeout = 30.0,
|
||||||
retries: int = 3,
|
retries: int = 1,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Initialize the BaseArcadeClient.
|
Initialize the BaseArcadeClient.
|
||||||
|
|
@ -70,12 +73,6 @@ class BaseArcadeClient:
|
||||||
"""
|
"""
|
||||||
return urljoin(self._base_url, path)
|
return urljoin(self._base_url, path)
|
||||||
|
|
||||||
def _chat_url(self, base_url: str) -> str:
|
|
||||||
chat_url = str(base_url)
|
|
||||||
if not base_url.endswith(OPENAI_API_VERSION):
|
|
||||||
chat_url = f"{base_url}/{OPENAI_API_VERSION}"
|
|
||||||
return chat_url
|
|
||||||
|
|
||||||
def _handle_http_error(self, e: httpx.HTTPStatusError) -> None:
|
def _handle_http_error(self, e: httpx.HTTPStatusError) -> None:
|
||||||
error_map = {
|
error_map = {
|
||||||
400: BadRequestError,
|
400: BadRequestError,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
import json
|
||||||
from typing import Any, TypeVar, Union
|
from typing import Any, TypeVar, Union
|
||||||
|
|
||||||
from httpx import Timeout
|
from httpx import Timeout
|
||||||
from openai import AsyncOpenAI, OpenAI
|
|
||||||
from openai.resources.chat import AsyncChat, Chat
|
|
||||||
|
|
||||||
from arcade.client.base import (
|
from arcade.client.base import (
|
||||||
AsyncArcadeClient,
|
AsyncArcadeClient,
|
||||||
|
|
@ -120,7 +119,7 @@ class ToolResource(BaseResource[ClientT]):
|
||||||
tool_name: str,
|
tool_name: str,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
tool_version: str | None = None,
|
tool_version: str | None = None,
|
||||||
inputs: dict[str, Any] | None = None,
|
inputs: dict[str, Any] | str | None = None,
|
||||||
) -> ExecuteToolResponse:
|
) -> ExecuteToolResponse:
|
||||||
"""
|
"""
|
||||||
Send a request to execute a tool and return the response.
|
Send a request to execute a tool and return the response.
|
||||||
|
|
@ -131,6 +130,12 @@ class ToolResource(BaseResource[ClientT]):
|
||||||
tool_version: The version of the tool to execute (if not provided, the latest version will be used).
|
tool_version: The version of the tool to execute (if not provided, the latest version will be used).
|
||||||
inputs: The inputs for the tool.
|
inputs: The inputs for the tool.
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(inputs, str):
|
||||||
|
try:
|
||||||
|
inputs = json.dumps(inputs)
|
||||||
|
except Exception:
|
||||||
|
raise ValueError("Inputs must be a valid JSON object or serializable dictionary")
|
||||||
|
|
||||||
request_data = {
|
request_data = {
|
||||||
"tool_name": tool_name,
|
"tool_name": tool_name,
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
|
|
@ -399,12 +404,6 @@ class Arcade(SyncArcadeClient):
|
||||||
self.auth: AuthResource = AuthResource(self)
|
self.auth: AuthResource = AuthResource(self)
|
||||||
self.tools: ToolResource = ToolResource(self)
|
self.tools: ToolResource = ToolResource(self)
|
||||||
self.health: HealthResource = HealthResource(self)
|
self.health: HealthResource = HealthResource(self)
|
||||||
chat_url = self._chat_url(self._base_url)
|
|
||||||
self._openai_client = OpenAI(base_url=chat_url, api_key=self._api_key)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat(self) -> Chat:
|
|
||||||
return self._openai_client.chat
|
|
||||||
|
|
||||||
def _execute_request(self, method: str, url: str, **kwargs: Any) -> Any:
|
def _execute_request(self, method: str, url: str, **kwargs: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
|
|
@ -422,12 +421,6 @@ class AsyncArcade(AsyncArcadeClient):
|
||||||
self.auth: AsyncAuthResource = AsyncAuthResource(self)
|
self.auth: AsyncAuthResource = AsyncAuthResource(self)
|
||||||
self.tools: AsyncToolResource = AsyncToolResource(self)
|
self.tools: AsyncToolResource = AsyncToolResource(self)
|
||||||
self.health: AsyncHealthResource = AsyncHealthResource(self)
|
self.health: AsyncHealthResource = AsyncHealthResource(self)
|
||||||
chat_url = self._chat_url(self._base_url)
|
|
||||||
self._openai_client = AsyncOpenAI(base_url=chat_url, api_key=self._api_key)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def chat(self) -> AsyncChat:
|
|
||||||
return self._openai_client.chat
|
|
||||||
|
|
||||||
async def _execute_request(self, method: str, url: str, **kwargs: Any) -> Any:
|
async def _execute_request(self, method: str, url: str, **kwargs: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
import os
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from arcade.core.schema import ToolAuthorizationContext, ToolCallOutput
|
from arcade.core.schema import ToolAuthorizationContext, ToolCallOutput
|
||||||
|
|
||||||
OPENAI_API_VERSION = os.getenv("OPENAI_API_VERSION", "v1")
|
|
||||||
|
|
||||||
|
|
||||||
class AuthProvider(str, Enum):
|
class AuthProvider(str, Enum):
|
||||||
google = "google"
|
google = "google"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ except ImportError:
|
||||||
"Use `pip install arcade-ai[evals]` to install the required dependencies for evaluation."
|
"Use `pip install arcade-ai[evals]` to install the required dependencies for evaluation."
|
||||||
)
|
)
|
||||||
|
|
||||||
from arcade.client.client import AsyncArcade
|
from openai import AsyncOpenAI
|
||||||
|
|
||||||
from arcade.sdk.error import WeightError
|
from arcade.sdk.error import WeightError
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -520,12 +521,12 @@ class EvalSuite:
|
||||||
)
|
)
|
||||||
self.cases.append(new_case)
|
self.cases.append(new_case)
|
||||||
|
|
||||||
async def run(self, client: AsyncArcade, model: str) -> dict[str, Any]:
|
async def run(self, client: AsyncOpenAI, model: str) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Run the evaluation suite.
|
Run the evaluation suite.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
client: The AsyncArcade client instance.
|
client: The AsyncOpenAI client instance.
|
||||||
model: The model to evaluate.
|
model: The model to evaluate.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -651,11 +652,11 @@ def tool_eval() -> Callable[[Callable], Callable]:
|
||||||
raise TypeError("Eval function must return an EvalSuite")
|
raise TypeError("Eval function must return an EvalSuite")
|
||||||
suite.max_concurrent = max_concurrency
|
suite.max_concurrent = max_concurrency
|
||||||
results = []
|
results = []
|
||||||
async with AsyncArcade(
|
async with AsyncOpenAI(
|
||||||
api_key=config.api.key,
|
api_key=config.api.key,
|
||||||
base_url=config.engine_url,
|
base_url=config.engine_url,
|
||||||
) as client:
|
) as client:
|
||||||
result = await suite.run(client, model) # type: ignore[arg-type]
|
result = await suite.run(client, model)
|
||||||
results.append(result)
|
results.append(result)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue