Skip to content

Commit d202187

Browse files
committed
Added commands using the v1 foundry project client library
1 parent 98d6fed commit d202187

File tree

5 files changed

+160
-19
lines changed

5 files changed

+160
-19
lines changed

src/azure-cli/azure/cli/command_modules/cognitiveservices/_client_factory.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,46 @@ def cf_models(cli_ctx, *_):
4040

4141
def cf_usages(cli_ctx, *_):
4242
return get_cognitiveservices_management_client(cli_ctx).usages
43+
44+
45+
def cf_ai_projects(cli_ctx, command_args):
46+
"""
47+
Create AI Projects client for data plane operations.
48+
Similar to keyvault's data plane client factory pattern.
49+
"""
50+
from azure.ai.projects import AIProjectClient
51+
from azure.cli.core.commands.client_factory import prepare_client_kwargs_track2
52+
from azure.cli.core._profile import Profile
53+
54+
# Get credentials using Azure CLI login
55+
profile = Profile(cli_ctx=cli_ctx)
56+
credential, _, _ = profile.get_login_credentials(
57+
subscription_id=cli_ctx.data.get('subscription_id')
58+
)
59+
60+
# Get endpoint from command arguments (similar to keyvault's vault_url)
61+
account_name = command_args.get('account_name', None)
62+
endpoint = command_args.get('endpoint', None)
63+
project = command_args.get('project_name', None)
64+
65+
# If no explicit endpoint provided, construct from account name
66+
if not endpoint and account_name:
67+
# Construct endpoint URL from account name
68+
# Format: https://{account_name}.cognitiveservices.azure.com
69+
endpoint = f"https://{account_name}.services.ai.azure.com/api/projects/{project}"
70+
71+
if not endpoint:
72+
from azure.cli.core.azclierror import RequiredArgumentMissingError
73+
raise RequiredArgumentMissingError(
74+
'Please specify --account-name or --endpoint'
75+
)
76+
77+
# Prepare client kwargs with proper logging and telemetry
78+
client_kwargs = prepare_client_kwargs_track2(cli_ctx)
79+
80+
# Create and return the AI Projects client
81+
return AIProjectClient(
82+
endpoint=endpoint,
83+
credential=credential,
84+
**client_kwargs
85+
)

src/azure-cli/azure/cli/command_modules/cognitiveservices/_params.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,26 @@ def _validate_subnet(cmd, namespace):
121121
child_name_1=subnet)
122122

123123

124+
def validate_agent_endpoint_or_account_name(namespace):
125+
"""
126+
Validate that either account_name or endpoint is provided, but not both.
127+
"""
128+
from azure.cli.core.azclierror import MutuallyExclusiveArgumentError, RequiredArgumentMissingError
129+
130+
account_name = getattr(namespace, 'account_name', None)
131+
endpoint = getattr(namespace, 'endpoint', None)
132+
133+
if account_name and endpoint:
134+
raise MutuallyExclusiveArgumentError(
135+
'Cannot specify both --name and --endpoint. Please provide only one.'
136+
)
137+
138+
if not account_name and not endpoint:
139+
raise RequiredArgumentMissingError(
140+
'Must specify either --name or --endpoint.'
141+
)
142+
143+
124144
@Completer
125145
def sku_name_completer(cmd, prefix, namespace, **kwargs): # pylint: disable=unused-argument
126146
names = {x.name for x in _sku_filter(cmd, namespace)}
@@ -216,13 +236,29 @@ def load_arguments(self, _):
216236
c.argument('next_tier', help='Cognitive Services account commitment plan next commitment period tier.')
217237

218238
with self.argument_context('cognitiveservices agent') as c:
239+
c.argument('account_name', arg_type=name_arg_type,
240+
help='cognitive service account name. Mutually exclusive with --endpoint.',
241+
completer=get_resource_name_completion_list('Microsoft.CognitiveServices/accounts'),
242+
required=False)
243+
c.argument('project_name', help='AI Project name')
219244
c.argument('agent_name', help='Cognitive Services hosted agent name')
220245
c.argument('agent_version', help='Cognitive Services hosted agent version')
246+
c.argument('endpoint', help='AI Projects endpoint URL. Mutually exclusive with --name.')
221247

222248
with self.argument_context('cognitiveservices agent update') as c:
223-
c.argument('min_replica', help='Minimum number of replicas for horizontal scaling')
224-
c.argument('max_replica', help='Maximum number of replicas for horizontal scaling')
249+
c.argument('min_replica', options_list=['--min-replica'], help='Minimum number of replicas for horizontal scaling')
250+
c.argument('max_replica', options_list=['--max-replica'], help='Maximum number of replicas for horizontal scaling')
225251
c.argument('description', help='Description of the agent')
226252

227253
with self.argument_context('cognitiveservices agent delete') as c:
228254
c.argument('agent_version', help='Cognitive Services hosted agent version. If not provided, deletes all versions.', required=False)
255+
256+
with self.argument_context('cognitiveservices agent versions') as c:
257+
c.argument('account_name', arg_type=name_arg_type,
258+
help='cognitive service account name. Mutually exclusive with --endpoint.',
259+
completer=get_resource_name_completion_list('Microsoft.CognitiveServices/accounts'),
260+
required=False,
261+
validator=validate_agent_endpoint_or_account_name)
262+
c.argument('project_name', help='AI Project name')
263+
c.argument('agent_name', help='Cognitive Services hosted agent name')
264+
c.argument('endpoint', help='AI Projects endpoint URL. Mutually exclusive with --name.')

src/azure-cli/azure/cli/command_modules/cognitiveservices/commands.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
from azure.cli.core.commands import CliCommandType
77
from azure.cli.command_modules.cognitiveservices._client_factory import cf_accounts, cf_resource_skus, \
8-
cf_deleted_accounts, cf_deployments, cf_commitment_plans, cf_commitment_tiers, cf_models, cf_usages
8+
cf_deleted_accounts, cf_deployments, cf_commitment_plans, cf_commitment_tiers, cf_models, cf_usages, \
9+
cf_ai_projects
910

1011

1112
def load_command_table(self, _):
@@ -104,10 +105,12 @@ def load_command_table(self, _):
104105
with self.command_group('cognitiveservices usage', usages_type) as g:
105106
g.command('list', 'list')
106107

107-
with self.command_group('cognitiveservices agent', client_factory=cf_accounts) as g:
108+
with self.command_group('cognitiveservices agent', client_factory=cf_ai_projects) as g:
108109
g.custom_command('update', 'agent_update')
109110
g.custom_command('stop', 'agent_stop')
110111
g.custom_command('start', 'agent_start')
111112
g.custom_command('delete-deployment', 'agent_delete_deployment')
112113
g.custom_command('delete', 'agent_delete')
113114
g.custom_command('list', 'agent_list')
115+
g.custom_command('list-versions', 'agent_versions_list')
116+
g.custom_command('show', 'agent_show')

src/azure-cli/azure/cli/command_modules/cognitiveservices/custom.py

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
# --------------------------------------------------------------------------------------------
55

66
import json
7+
import urllib.parse
78

89
from knack.util import CLIError
910
from knack.log import get_logger
1011

12+
import azure.core.rest
1113
from azure.mgmt.cognitiveservices.models import Account as CognitiveServicesAccount, Sku, \
1214
VirtualNetworkRule, IpRule, NetworkRuleSet, NetworkRuleAction, \
1315
AccountProperties as CognitiveServicesAccountProperties, ApiProperties as CognitiveServicesAccountApiProperties, \
@@ -327,52 +329,108 @@ def commitment_plan_create_or_update(
327329
return client.create_or_update(resource_group_name, account_name, commitment_plan_name, plan)
328330

329331

330-
def agent_update(client, account_name, agent_name, agent_version,
331-
min_replica=None, max_replica=None, description=None, tags=None):
332+
AGENT_API_VERSION_PARAMS = { 'api-version': '2025-11-15-preview' }
333+
334+
def agent_update(client, account_name, project_name, agent_name, agent_version,
335+
min_replica=None, max_replica=None, description=None, tags=None, endpoint=None):
332336
"""
333337
Update hosted agent deployment configuration.
334338
Updates horizontal scale configuration (min and max replica), agent meta-data such as description and tags.
335339
New version is not created for this update.
336340
"""
337-
raise NotImplementedError("agent_update command is not yet implemented")
338-
341+
request_body = {}
342+
if min_replica is not None:
343+
request_body['min_replica'] = min_replica
344+
if max_replica is not None:
345+
request_body['max_replica'] = max_replica
346+
request = azure.core.rest.HttpRequest('POST', f'/agents/{urllib.parse.quote(agent_name)}/containers/default:update', json = request_body, params=AGENT_API_VERSION_PARAMS)
347+
response = client.send_request(request)
348+
response.raise_for_status()
349+
return response.json()
339350

340-
def agent_stop(client, account_name, agent_name, agent_version):
351+
def agent_stop(client, account_name, project_name, agent_name, agent_version, endpoint=None):
341352
"""
342353
Stop hosted agent deployment.
343354
"""
344-
raise NotImplementedError("agent_stop command is not yet implemented")
355+
request = azure.core.rest.HttpRequest('POST', f'/agents/{urllib.parse.quote(agent_name)/containers/default:start}', params=AGENT_API_VERSION_PARAMS)
356+
response = client.send_request(request)
357+
response.raise_for_status()
358+
return response.json()
345359

346360

347-
def agent_start(client, account_name, agent_name, agent_version):
361+
def agent_start(client, account_name, project_name, agent_name, agent_version, endpoint=None):
348362
"""
349363
Start hosted agent deployment.
350364
"""
351-
raise NotImplementedError("agent_start command is not yet implemented")
365+
request = azure.core.rest.HttpRequest('POST', f'/agents/{urllib.parse.quote(agent_name)/containers/default:start}', params=AGENT_API_VERSION_PARAMS)
366+
response = client.send_request(request)
367+
response.raise_for_status()
368+
return response.json()
352369

353370

354-
def agent_delete_deployment(client, account_name, agent_name, agent_version):
371+
def agent_delete_deployment(client, account_name, project_name, agent_name, agent_version, endpoint=None):
355372
"""
356373
Delete hosted agent deployment.
357374
Deletes the agent deployment only, agent version associated with the deployment remains.
358375
"""
359376
raise NotImplementedError("agent_delete_deployment command is not yet implemented")
360377

361378

362-
def agent_delete(client, account_name, agent_name, agent_version=None):
379+
def agent_delete(client, account_name, project_name, agent_name, agent_version=None, endpoint=None):
363380
"""
364381
Delete hosted agent version or all versions.
365-
If agent_version is provided, deletes the agent instance and agent definition associated with that version.
382+
If agent_version is provided, deletes the agent instance and agent definition associated with `that version.
366383
If agent_version is not provided, deletes all agent instances and agent definitions associated with the agent name.
367384
"""
368-
raise NotImplementedError("agent_delete command is not yet implemented")
385+
request = azure.core.rest.HttpRequest('DELETE', f'/agents/{urllib.parse.quote(agent_name)}', params = AGENT_API_VERSION_PARAMS)
386+
response = client.send_request(request)
387+
response.raise_for_status()
388+
return response.json()
369389

370390

371-
def agent_list(client, account_name, agent_name, agent_version=None):
391+
def agent_list(client, account_name, project_name, endpoint=None):
372392
"""
373393
List hosted agent versions or deployments.
374394
If agent_version is not provided, lists all versions for an agent.
375395
If agent_version is provided, lists all deployments for that agent version.
376396
"""
377-
raise NotImplementedError("agent_list command is not yet implemented")
378-
397+
agents = []
398+
params = AGENT_API_VERSION_PARAMS.copy()
399+
while True:
400+
request = azure.core.rest.HttpRequest('GET', f'/agents', params=params)
401+
response = client.send_request(request)
402+
response.raise_for_status()
403+
body = response.json()
404+
agents.extend(body.get('data', []))
405+
if body.get('has_more'):
406+
params['after'] = body.get('last_id')
407+
else:
408+
return agents
409+
410+
411+
def agent_versions_list(client, account_name, project_name, agent_name, endpoint=None):
412+
"""
413+
List all versions of a hosted agent.
414+
"""
415+
versions = []
416+
params = AGENT_API_VERSION_PARAMS.copy()
417+
while True:
418+
request = azure.core.rest.HttpRequest('GET', f'/agents/{urllib.parse.quote(agent_name)}/versions', params=params)
419+
response = client.send_request(request)
420+
response.raise_for_status()
421+
body = response.json()
422+
versions.extend(body.get('data', []))
423+
if body.get('has_more'):
424+
params['after'] = body.get('last_id')
425+
else:
426+
return versions
427+
428+
429+
def agent_show(client, account_name, project_name, agent_name, endpoint=None):
430+
"""
431+
Show details of a hosted agent.
432+
"""
433+
request = azure.core.rest.HttpRequest('GET', f'/agents/{urllib.parse.quote(agent_name)}', params=AGENT_API_VERSION_PARAMS)
434+
response = client.send_request(request)
435+
response.raise_for_status()
436+
return response.json()

src/azure-cli/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
DEPENDENCIES = [
5454
"antlr4-python3-runtime~=4.13.1",
5555
'azure-appconfiguration~=1.7.1',
56+
'azure-ai-projects~=1.0.0',
5657
'azure-batch==15.0.0b1',
5758
'azure-cli-core=={}'.format(VERSION),
5859
'azure-cosmos~=3.0,>=3.0.2',

0 commit comments

Comments
 (0)