Skip to content

Commit 6aae761

Browse files
mmontanclaude
andcommitted
feat: Add --base-url and --api-version options for Vertex AI endpoint overrides
Allow users to override the Vertex AI base URL and API version on all commands, useful for testing against staging environments, private endpoints, or different API versions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 84bc6d4 commit 6aae761

6 files changed

Lines changed: 181 additions & 16 deletions

File tree

src/agent_engine_cli/chat.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ async def run_chat(
119119
agent_id: str,
120120
user_id: str = "cli-user",
121121
debug: bool = False,
122+
base_url: str | None = None,
123+
api_version: str | None = None,
122124
) -> None:
123125
"""
124126
Run an interactive chat session with an Agent Engine instance.
@@ -129,6 +131,8 @@ async def run_chat(
129131
agent_id: Agent ID or full resource name.
130132
user_id: User ID for the chat session.
131133
debug: Enable verbose HTTP debug logging.
134+
base_url: Optional override for the Vertex AI base URL.
135+
api_version: Optional API version override.
132136
"""
133137
# Suppress vertexai experimental warnings
134138
try:
@@ -149,7 +153,12 @@ async def run_chat(
149153
import vertexai
150154

151155
# Get agent instance
152-
client = vertexai.Client(project=project, location=location)
156+
http_options: dict[str, str] = {}
157+
if api_version:
158+
http_options["api_version"] = api_version
159+
if base_url:
160+
http_options["base_url"] = base_url
161+
client = vertexai.Client(project=project, location=location, http_options=http_options or None)
153162
resource_name = (
154163
f"projects/{project}/locations/{location}/reasoningEngines/{agent_id}"
155164
)

src/agent_engine_cli/client.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ class AgentResource(Protocol):
2424
class AgentEngineClient:
2525
"""Client for interacting with Vertex AI Agent Engine."""
2626

27-
def __init__(self, project: str, location: str):
27+
def __init__(self, project: str, location: str, *, base_url: str | None = None, api_version: str | None = None):
2828
"""Initialize the client with project and location.
2929
3030
Args:
3131
project: Google Cloud project ID
3232
location: Google Cloud region
33+
base_url: Optional override for the Vertex AI base URL
34+
api_version: Optional API version override
3335
"""
3436
self.project = project
3537
self.location = location
@@ -38,10 +40,16 @@ def __init__(self, project: str, location: str):
3840

3941
vertexai.init(project=project, location=location)
4042

43+
http_options: dict[str, str] = {}
44+
if api_version:
45+
http_options["api_version"] = api_version
46+
if base_url:
47+
http_options["base_url"] = base_url
48+
4149
self._client = vertexai.Client(
4250
project=project,
4351
location=location,
44-
http_options={"api_version": "v1beta1"},
52+
http_options=http_options or None,
4553
)
4654

4755
def _resolve_resource_name(self, agent_id: str) -> str:

src/agent_engine_cli/dependencies.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
from agent_engine_cli.client import AgentEngineClient
44

55

6-
def get_client(project: str, location: str) -> AgentEngineClient:
6+
def get_client(
7+
project: str,
8+
location: str,
9+
*,
10+
base_url: str | None = None,
11+
api_version: str | None = None,
12+
) -> AgentEngineClient:
713
"""Create a new AgentEngineClient instance.
814
915
This function serves as a dependency injection point for the CLI.
@@ -12,8 +18,10 @@ def get_client(project: str, location: str) -> AgentEngineClient:
1218
Args:
1319
project: Google Cloud project ID
1420
location: Google Cloud region
21+
base_url: Optional override for the Vertex AI base URL
22+
api_version: Optional API version override
1523
1624
Returns:
1725
An instance of AgentEngineClient
1826
"""
19-
return AgentEngineClient(project=project, location=location)
27+
return AgentEngineClient(project=project, location=location, base_url=base_url, api_version=api_version)

src/agent_engine_cli/main.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ def version():
3333
def list_agents(
3434
location: Annotated[str, typer.Option("--location", "-l", help="Google Cloud region")],
3535
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
36+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
37+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
3638
) -> None:
3739
"""List all agents in the project."""
3840
try:
@@ -42,7 +44,7 @@ def list_agents(
4244
raise typer.Exit(code=1)
4345

4446
try:
45-
client = get_client(project=project, location=location)
47+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
4648
agents = list(client.list_agents())
4749

4850
if not agents:
@@ -99,6 +101,8 @@ def get_agent(
99101
location: Annotated[str, typer.Option("--location", "-l", help="Google Cloud region")],
100102
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
101103
full: Annotated[bool, typer.Option("--full", "-f", help="Show full JSON output")] = False,
104+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
105+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
102106
) -> None:
103107
"""Get details for a specific agent."""
104108
try:
@@ -108,7 +112,7 @@ def get_agent(
108112
raise typer.Exit(code=1)
109113

110114
try:
111-
client = get_client(project=project, location=location)
115+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
112116
agent = client.get_agent(agent_id)
113117

114118
# v1beta1 api_resource uses 'name' instead of 'resource_name'
@@ -239,6 +243,8 @@ def create_agent(
239243
str | None,
240244
typer.Option("--service-account", "-s", help="Service account email (only used with --identity service_account)"),
241245
] = None,
246+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
247+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
242248
) -> None:
243249
"""Create a new agent (without deploying code)."""
244250
try:
@@ -248,7 +254,7 @@ def create_agent(
248254
raise typer.Exit(code=1)
249255

250256
try:
251-
client = get_client(project=project, location=location)
257+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
252258
console.print(f"Creating agent '{escape(display_name)}'...")
253259

254260
agent = client.create_agent(
@@ -274,6 +280,8 @@ def delete_agent(
274280
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
275281
force: Annotated[bool, typer.Option("--force", "-f", help="Force deletion of agents with sessions/memory")] = False,
276282
yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompt")] = False,
283+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
284+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
277285
) -> None:
278286
"""Delete an agent."""
279287
try:
@@ -289,7 +297,7 @@ def delete_agent(
289297
raise typer.Exit()
290298

291299
try:
292-
client = get_client(project=project, location=location)
300+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
293301
client.delete_agent(agent_id, force=force)
294302
console.print(f"[red]Agent '{escape(agent_id)}' deleted.[/red]")
295303
except Exception as e:
@@ -307,6 +315,8 @@ def list_sessions(
307315
agent_id: Annotated[str, typer.Argument(help="Agent ID or full resource name")],
308316
location: Annotated[str, typer.Option("--location", "-l", help="Google Cloud region")],
309317
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
318+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
319+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
310320
) -> None:
311321
"""List all sessions for an agent."""
312322
try:
@@ -316,7 +326,7 @@ def list_sessions(
316326
raise typer.Exit(code=1)
317327

318328
try:
319-
client = get_client(project=project, location=location)
329+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
320330
sessions = list(client.list_sessions(agent_id))
321331

322332
if not sessions:
@@ -375,6 +385,8 @@ def list_sandboxes(
375385
agent_id: Annotated[str, typer.Argument(help="Agent ID or full resource name")],
376386
location: Annotated[str, typer.Option("--location", "-l", help="Google Cloud region")],
377387
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
388+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
389+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
378390
) -> None:
379391
"""List all sandboxes for an agent."""
380392
try:
@@ -384,7 +396,7 @@ def list_sandboxes(
384396
raise typer.Exit(code=1)
385397

386398
try:
387-
client = get_client(project=project, location=location)
399+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
388400
sandboxes = list(client.list_sandboxes(agent_id))
389401

390402
if not sandboxes:
@@ -449,6 +461,8 @@ def list_memories(
449461
agent_id: Annotated[str, typer.Argument(help="Agent ID or full resource name")],
450462
location: Annotated[str, typer.Option("--location", "-l", help="Google Cloud region")],
451463
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
464+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
465+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
452466
) -> None:
453467
"""List all memories for an agent."""
454468
try:
@@ -458,7 +472,7 @@ def list_memories(
458472
raise typer.Exit(code=1)
459473

460474
try:
461-
client = get_client(project=project, location=location)
475+
client = get_client(project=project, location=location, base_url=base_url, api_version=api_version)
462476
memories = list(client.list_memories(agent_id))
463477

464478
table = Table(title="Memories")
@@ -525,6 +539,8 @@ def chat(
525539
project: Annotated[str | None, typer.Option("--project", "-p", help="Google Cloud project ID (defaults to ADC project)")] = None,
526540
user: Annotated[str, typer.Option("--user", "-u", help="User ID for the chat session")] = "cli-user",
527541
debug: Annotated[bool, typer.Option("--debug", "-d", help="Enable verbose HTTP debug logging")] = False,
542+
base_url: Annotated[str | None, typer.Option("--base-url", help="Override the Vertex AI base URL")] = None,
543+
api_version: Annotated[str | None, typer.Option("--api-version", help="Override the API version")] = None,
528544
) -> None:
529545
"""Start an interactive chat session with an agent."""
530546
try:
@@ -540,6 +556,8 @@ def chat(
540556
agent_id=agent_id,
541557
user_id=user,
542558
debug=debug,
559+
base_url=base_url,
560+
api_version=api_version,
543561
))
544562
except KeyboardInterrupt:
545563
console.print("\n[yellow]Chat session ended.[/yellow]")

tests/test_client.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,60 @@ def test_init_custom_location(self, mock_vertexai, mock_agent_engines, mock_type
5050

5151
assert client.location == "europe-west1"
5252

53+
def test_init_default_http_options(self, mock_vertexai, mock_agent_engines, mock_types):
54+
"""Test that default init passes no http_options."""
55+
AgentEngineClient(project="test-project", location="us-central1")
56+
57+
mock_vertexai.Client.assert_called_once_with(
58+
project="test-project",
59+
location="us-central1",
60+
http_options=None,
61+
)
62+
63+
def test_init_custom_api_version(self, mock_vertexai, mock_agent_engines, mock_types):
64+
"""Test that custom api_version is passed through in http_options."""
65+
AgentEngineClient(project="test-project", location="us-central1", api_version="v1beta1")
66+
67+
mock_vertexai.Client.assert_called_once_with(
68+
project="test-project",
69+
location="us-central1",
70+
http_options={"api_version": "v1beta1"},
71+
)
72+
73+
def test_init_custom_base_url(self, mock_vertexai, mock_agent_engines, mock_types):
74+
"""Test that custom base_url is passed through in http_options."""
75+
AgentEngineClient(
76+
project="test-project",
77+
location="us-central1",
78+
base_url="https://custom-endpoint.example.com",
79+
)
80+
81+
mock_vertexai.Client.assert_called_once_with(
82+
project="test-project",
83+
location="us-central1",
84+
http_options={
85+
"base_url": "https://custom-endpoint.example.com",
86+
},
87+
)
88+
89+
def test_init_custom_base_url_and_api_version(self, mock_vertexai, mock_agent_engines, mock_types):
90+
"""Test that both base_url and api_version are passed through together."""
91+
AgentEngineClient(
92+
project="test-project",
93+
location="us-central1",
94+
base_url="https://staging.example.com",
95+
api_version="v1",
96+
)
97+
98+
mock_vertexai.Client.assert_called_once_with(
99+
project="test-project",
100+
location="us-central1",
101+
http_options={
102+
"api_version": "v1",
103+
"base_url": "https://staging.example.com",
104+
},
105+
)
106+
53107
def test_list_agents(self, mock_vertexai, mock_agent_engines, mock_types):
54108
"""Test listing agents."""
55109
mock_api_resource1 = MagicMock()

0 commit comments

Comments
 (0)