Silence annoying OpenAI client shutdown error (#4157)
This commit is contained in:
committed by
GitHub
parent
7100b7e004
commit
4ac82ec25b
@@ -9,6 +9,7 @@ from openai import AsyncAzureOpenAI, AsyncOpenAI
|
|||||||
from skyvern.config import Settings
|
from skyvern.config import Settings
|
||||||
from skyvern.forge.agent import ForgeAgent
|
from skyvern.forge.agent import ForgeAgent
|
||||||
from skyvern.forge.agent_functions import AgentFunction
|
from skyvern.forge.agent_functions import AgentFunction
|
||||||
|
from skyvern.forge.forge_openai_client import ForgeAsyncHttpxClientWrapper
|
||||||
from skyvern.forge.sdk.api.azure import AzureClientFactory
|
from skyvern.forge.sdk.api.azure import AzureClientFactory
|
||||||
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
||||||
from skyvern.forge.sdk.api.llm.models import LLMAPIHandler
|
from skyvern.forge.sdk.api.llm.models import LLMAPIHandler
|
||||||
@@ -95,7 +96,10 @@ def create_forge_app() -> ForgeApp:
|
|||||||
app.EXPERIMENTATION_PROVIDER = NoOpExperimentationProvider()
|
app.EXPERIMENTATION_PROVIDER = NoOpExperimentationProvider()
|
||||||
|
|
||||||
app.LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(settings.LLM_KEY)
|
app.LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(settings.LLM_KEY)
|
||||||
app.OPENAI_CLIENT = AsyncOpenAI(api_key=settings.OPENAI_API_KEY or "")
|
app.OPENAI_CLIENT = AsyncOpenAI(
|
||||||
|
api_key=settings.OPENAI_API_KEY or "",
|
||||||
|
http_client=ForgeAsyncHttpxClientWrapper(),
|
||||||
|
)
|
||||||
if settings.ENABLE_AZURE_CUA:
|
if settings.ENABLE_AZURE_CUA:
|
||||||
app.OPENAI_CLIENT = AsyncAzureOpenAI(
|
app.OPENAI_CLIENT = AsyncAzureOpenAI(
|
||||||
api_key=settings.AZURE_CUA_API_KEY,
|
api_key=settings.AZURE_CUA_API_KEY,
|
||||||
@@ -113,6 +117,7 @@ def create_forge_app() -> ForgeApp:
|
|||||||
app.UI_TARS_CLIENT = AsyncOpenAI(
|
app.UI_TARS_CLIENT = AsyncOpenAI(
|
||||||
api_key=settings.VOLCENGINE_API_KEY,
|
api_key=settings.VOLCENGINE_API_KEY,
|
||||||
base_url=settings.VOLCENGINE_API_BASE,
|
base_url=settings.VOLCENGINE_API_BASE,
|
||||||
|
http_client=ForgeAsyncHttpxClientWrapper(),
|
||||||
)
|
)
|
||||||
|
|
||||||
app.SECONDARY_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
|
app.SECONDARY_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
|
||||||
|
|||||||
24
skyvern/forge/forge_openai_client.py
Normal file
24
skyvern/forge/forge_openai_client.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from openai import DefaultAsyncHttpxClient
|
||||||
|
|
||||||
|
|
||||||
|
class ForgeAsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
|
||||||
|
"""
|
||||||
|
Wrapper around OpenAI's AsyncHttpxClientWrapper to mask teardown races.
|
||||||
|
|
||||||
|
The upstream `__del__` checks `self.is_closed`, but during interpreter
|
||||||
|
shutdown httpx internals may already be None, which raises:
|
||||||
|
|
||||||
|
AttributeError: 'NoneType' object has no attribute 'CLOSED'
|
||||||
|
|
||||||
|
We defensively swallow that destructor error so shutdown logs stay clean.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __del__(self) -> None:
|
||||||
|
try:
|
||||||
|
if self.is_closed:
|
||||||
|
return
|
||||||
|
asyncio.get_running_loop().create_task(self.aclose())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
@@ -18,6 +18,7 @@ from pydantic import BaseModel
|
|||||||
from skyvern.config import settings
|
from skyvern.config import settings
|
||||||
from skyvern.exceptions import SkyvernContextWindowExceededError
|
from skyvern.exceptions import SkyvernContextWindowExceededError
|
||||||
from skyvern.forge import app
|
from skyvern.forge import app
|
||||||
|
from skyvern.forge.forge_openai_client import ForgeAsyncHttpxClientWrapper
|
||||||
from skyvern.forge.sdk.api.llm.config_registry import LLMConfigRegistry
|
from skyvern.forge.sdk.api.llm.config_registry import LLMConfigRegistry
|
||||||
from skyvern.forge.sdk.api.llm.exceptions import (
|
from skyvern.forge.sdk.api.llm.exceptions import (
|
||||||
DuplicateCustomLLMProviderError,
|
DuplicateCustomLLMProviderError,
|
||||||
@@ -1100,7 +1101,11 @@ class LLMCaller:
|
|||||||
self.openai_client = None
|
self.openai_client = None
|
||||||
if self.llm_key.startswith("openrouter/"):
|
if self.llm_key.startswith("openrouter/"):
|
||||||
self.llm_key = self.llm_key.replace("openrouter/", "")
|
self.llm_key = self.llm_key.replace("openrouter/", "")
|
||||||
self.openai_client = AsyncOpenAI(api_key=settings.OPENROUTER_API_KEY, base_url=settings.OPENROUTER_API_BASE)
|
self.openai_client = AsyncOpenAI(
|
||||||
|
api_key=settings.OPENROUTER_API_KEY,
|
||||||
|
base_url=settings.OPENROUTER_API_BASE,
|
||||||
|
http_client=ForgeAsyncHttpxClientWrapper(),
|
||||||
|
)
|
||||||
|
|
||||||
def add_tool_result(self, tool_result: dict[str, Any]) -> None:
|
def add_tool_result(self, tool_result: dict[str, Any]) -> None:
|
||||||
self.current_tool_results.append(tool_result)
|
self.current_tool_results.append(tool_result)
|
||||||
@@ -1513,7 +1518,8 @@ class LLMCaller:
|
|||||||
if isinstance(response, UITarsResponse):
|
if isinstance(response, UITarsResponse):
|
||||||
ui_tars_usage = response.usage
|
ui_tars_usage = response.usage
|
||||||
return LLMCallStats(
|
return LLMCallStats(
|
||||||
llm_cost=0, # TODO: calculate the cost according to the price: https://www.volcengine.com/docs/82379/1544106
|
llm_cost=0,
|
||||||
|
# TODO: calculate the cost according to the price: https://www.volcengine.com/docs/82379/1544106
|
||||||
input_tokens=ui_tars_usage.get("prompt_tokens", 0),
|
input_tokens=ui_tars_usage.get("prompt_tokens", 0),
|
||||||
output_tokens=ui_tars_usage.get("completion_tokens", 0),
|
output_tokens=ui_tars_usage.get("completion_tokens", 0),
|
||||||
cached_tokens=0, # only part of model support cached tokens
|
cached_tokens=0, # only part of model support cached tokens
|
||||||
|
|||||||
Reference in New Issue
Block a user