Skip to content

Commit f8574f1

Browse files
committed
refactor(BA-5528): use existing JSONParamType for chat --params
Replace the local string-based --params parsing with the project's existing ai.backend.cli.params.JSONParamType. Click now handles JSON parsing and reports BadParameter consistently with other CLI commands. A dict-only check is kept in the handler so non-object JSON (arrays, scalars) still fails with a clear message. Drops the @path file shorthand; users can pass --params "$(cat file.json)" instead.
1 parent 078a69a commit f8574f1

1 file changed

Lines changed: 7 additions & 26 deletions

File tree

  • src/ai/backend/client/cli/v2/deployment

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

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import asyncio
66
from collections.abc import Awaitable, Callable
77
from datetime import UTC, datetime
8-
from pathlib import Path
98
from typing import Any
109
from uuid import UUID
1110

1211
import click
1312

13+
from ai.backend.cli.params import JSONParamType
1414
from ai.backend.client.cli.v2.deployment_chat_cache import (
1515
CHAT_CACHE_FILE,
1616
DeploymentChatCacheEntry,
@@ -35,26 +35,6 @@ def _run_async(coro_fn: Callable[[], Awaitable[None]]) -> None:
3535
raise click.ClickException(f"{status}: {detail}") from e
3636

3737

38-
def _parse_params(spec: str) -> dict[str, Any]:
39-
"""Parse the ``--params`` value as a JSON object (or ``@/path/to/file.json``)."""
40-
import json
41-
42-
if spec.startswith("@"):
43-
try:
44-
text = Path(spec[1:]).read_text(encoding="utf-8")
45-
except OSError as e:
46-
raise click.ClickException(f"--params file not readable: {e}") from e
47-
else:
48-
text = spec
49-
try:
50-
parsed = json.loads(text)
51-
except json.JSONDecodeError as e:
52-
raise click.ClickException(f"--params is not valid JSON: {e.msg}") from e
53-
if not isinstance(parsed, dict):
54-
raise click.ClickException("--params must be a JSON object.")
55-
return parsed
56-
57-
5838
@click.command(name="chat")
5939
@click.argument("deployment_id", type=click.UUID)
6040
@click.argument("content", type=str)
@@ -66,11 +46,10 @@ def _parse_params(spec: str) -> dict[str, Any]:
6646
)
6747
@click.option(
6848
"--params",
69-
"params_spec",
7049
default=None,
71-
type=str,
50+
type=JSONParamType(),
7251
help=(
73-
"Extra request-body fields as a JSON object, or '@PATH' to read from a file. "
52+
"Extra request-body fields as a JSON object. "
7453
"Forwarded to the inference endpoint as-is "
7554
'(e.g. \'{"temperature": 0.7, "max_tokens": 256}\'). '
7655
"The 'model' and 'messages' fields are always overridden by --model and CONTENT."
@@ -80,7 +59,7 @@ def chat(
8059
deployment_id: UUID,
8160
content: str,
8261
model: str | None,
83-
params_spec: str | None,
62+
params: Any,
8463
) -> None:
8564
"""Send a one-shot chat completion request to a deployed model.
8665
@@ -103,7 +82,9 @@ def chat(
10382
except IncompatibleChatCacheError as e:
10483
raise click.ClickException(str(e)) from e
10584

106-
extra_body = _parse_params(params_spec) if params_spec else {}
85+
if params is not None and not isinstance(params, dict):
86+
raise click.ClickException("--params must be a JSON object.")
87+
extra_body: dict[str, Any] = params or {}
10788
entry = cache.get(deployment_id)
10889

10990
async def _resolve_endpoint() -> DeploymentChatCacheEntry:

0 commit comments

Comments
 (0)