Skip to content

Commit b2df404

Browse files
committed
fix(BA-5528): format BackendAPIError in deployment chat/chat-config
Mirror the _run_async wrapper used by deployment access-token commands so manager errors (e.g. 404 NotFound when the deployment_id does not exist) print a one-line 'Error (status): title' message instead of exposing the raw aiohttp BackendAPIError traceback to stderr.
1 parent 6e207d3 commit b2df404

2 files changed

Lines changed: 69 additions & 36 deletions

File tree

src/ai/backend/client/cli/v2/deployment/chat.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
import asyncio
66
import sys
7+
from collections.abc import Awaitable, Callable
78
from datetime import UTC, datetime
8-
from typing import TYPE_CHECKING, NoReturn
9+
from typing import TYPE_CHECKING, Any, NoReturn
910
from uuid import UUID
1011

1112
import click
@@ -28,6 +29,21 @@ def _abort(message: str) -> NoReturn:
2829
sys.exit(1)
2930

3031

32+
def _run_async(coro_fn: Callable[[], Awaitable[None]]) -> None:
33+
from ai.backend.client.exceptions import BackendAPIError
34+
35+
try:
36+
asyncio.run(coro_fn())
37+
except BackendAPIError as e:
38+
data: Any = e.args[2] if len(e.args) > 2 else {}
39+
title = data.get("title", "") if isinstance(data, dict) else ""
40+
msg = data.get("msg", "") if isinstance(data, dict) else ""
41+
status = e.args[0] if e.args else "?"
42+
detail = title or msg or str(e)
43+
click.echo(f"Error ({status}): {detail}", err=True)
44+
sys.exit(1)
45+
46+
3147
async def _resolve_endpoint_url(registry: V2ClientRegistry, deployment_id: UUID) -> str:
3248
deployment = await registry.deployment.get(deployment_id)
3349
endpoint_url = deployment.network_access.endpoint_url
@@ -147,7 +163,7 @@ async def _run() -> None:
147163
_abort(f"Inference endpoint error ({e.status} {e.reason}): {e.data}")
148164
print_result(response)
149165

150-
asyncio.run(_run())
166+
_run_async(_run)
151167

152168

153169
__all__ = ("chat", "CHAT_CACHE_FILE")

src/ai/backend/client/cli/v2/deployment/chat_config.py

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
import asyncio
66
import sys
7+
from collections.abc import Awaitable, Callable
78
from datetime import UTC, datetime
8-
from typing import NoReturn
9+
from typing import Any, NoReturn
910
from uuid import UUID
1011

1112
import click
@@ -25,6 +26,21 @@ def _abort(message: str) -> NoReturn:
2526
sys.exit(1)
2627

2728

29+
def _run_async(coro_fn: Callable[[], Awaitable[None]]) -> None:
30+
from ai.backend.client.exceptions import BackendAPIError
31+
32+
try:
33+
asyncio.run(coro_fn())
34+
except BackendAPIError as e:
35+
data: Any = e.args[2] if len(e.args) > 2 else {}
36+
title = data.get("title", "") if isinstance(data, dict) else ""
37+
msg = data.get("msg", "") if isinstance(data, dict) else ""
38+
status = e.args[0] if e.args else "?"
39+
detail = title or msg or str(e)
40+
click.echo(f"Error ({status}): {detail}", err=True)
41+
sys.exit(1)
42+
43+
2844
@click.group(name="chat-config")
2945
def chat_config() -> None:
3046
"""Manage local chat cache for deployment chat (vLLM API keys, endpoints)."""
@@ -66,41 +82,42 @@ def set_(
6682

6783
existing = cache.get(deployment_id)
6884

69-
async def _resolve() -> str:
85+
async def _run() -> None:
7086
if endpoint_url:
71-
return endpoint_url
72-
if existing is not None and existing.endpoint_url:
73-
return existing.endpoint_url
74-
registry = await create_v2_registry(config)
75-
try:
76-
deployment = await registry.deployment.get(deployment_id)
77-
finally:
78-
await registry.close()
79-
resolved = deployment.network_access.endpoint_url
80-
if not resolved:
81-
raise click.ClickException(
82-
f"Deployment {deployment_id} has no endpoint_url yet "
83-
"(it may still be provisioning). Provide --endpoint-url explicitly."
84-
)
85-
return resolved
86-
87-
final_endpoint = asyncio.run(_resolve())
88-
89-
cache.upsert(
90-
deployment_id,
91-
DeploymentChatCacheEntry(
92-
endpoint_url=final_endpoint,
93-
vllm_api_key=vllm_api_key,
94-
default_model=(
95-
default_model
96-
if default_model is not None
97-
else (existing.default_model if existing is not None else None)
87+
final_endpoint = endpoint_url
88+
elif existing is not None and existing.endpoint_url:
89+
final_endpoint = existing.endpoint_url
90+
else:
91+
registry = await create_v2_registry(config)
92+
try:
93+
deployment = await registry.deployment.get(deployment_id)
94+
finally:
95+
await registry.close()
96+
resolved = deployment.network_access.endpoint_url
97+
if not resolved:
98+
raise click.ClickException(
99+
f"Deployment {deployment_id} has no endpoint_url yet "
100+
"(it may still be provisioning). Provide --endpoint-url explicitly."
101+
)
102+
final_endpoint = resolved
103+
104+
cache.upsert(
105+
deployment_id,
106+
DeploymentChatCacheEntry(
107+
endpoint_url=final_endpoint,
108+
vllm_api_key=vllm_api_key,
109+
default_model=(
110+
default_model
111+
if default_model is not None
112+
else (existing.default_model if existing is not None else None)
113+
),
114+
last_synced_at=datetime.now(UTC),
98115
),
99-
last_synced_at=datetime.now(UTC),
100-
),
101-
)
102-
save_chat_cache(cache)
103-
click.echo(f"Updated chat cache entry for deployment {deployment_id}.")
116+
)
117+
save_chat_cache(cache)
118+
click.echo(f"Updated chat cache entry for deployment {deployment_id}.")
119+
120+
_run_async(_run)
104121

105122

106123
@chat_config.command(name="show")

0 commit comments

Comments
 (0)