Skip to content

{aimanager} Improve az aimanager list/show table output - #10322

Open
Liqian Luo (circy9) wants to merge 16 commits into
Azure:mainfrom
circy9:aimanager-list-table-format
Open

{aimanager} Improve az aimanager list/show table output#10322
Liqian Luo (circy9) wants to merge 16 commits into
Azure:mainfrom
circy9:aimanager-list-table-format

Conversation

@circy9

@circy9 Liqian Luo (circy9) commented Sep 10, 2026

Copy link
Copy Markdown

🤖 PR Validation — ️✔️ All clear

Breaking Changes
️✔️ None

Related command

az aimanager list/show, az aimanager namespace list/show, az aimanager namespace modeldeployment list/show

Description

Improves the -o table output across the az aimanager command surface. Previously the default table projection surfaced the internal ETag column while omitting useful status fields. This PR adds dedicated table transformers (azext_aimanager/_format.py) for each resource.

az aimanager list / show

Name    ProvisioningState    ResourceGroup    Location
------  -------------------  ---------------  ---------
aimbyo  Succeeded            yiralirg         westus2

az aimanager namespace list / show

Name    ProvisioningState    Age    Labels
------  -------------------  -----  ----------------------
ns1     Succeeded            45d    env=prod,team=payments

az aimanager namespace modeldeployment list / show

Namespace  Name  ProvisioningState  Replicas  Age  ModelId                Endpoint
---------  ----  -----------------  --------  ---  ---------------------  -----------------------
ns1        md1   Succeeded          1/3       45d  meta-llama/Llama-3-8B  https://md1.example.com

Notes

  • ResourceGroup, Namespace and parent info are parsed from the resource id via parse_resource_id, so a callable transformer is used rather than a JMESPath string.
  • Age is derived from systemData.createdAt and rendered kubectl-style (e.g. 45d, 3h12m); blank when the timestamp is missing or unparseable.
  • Labels (namespace) renders the Kubernetes namespace labels (properties.labels) as sorted, comma-joined key=value pairs, similar to kubectl get ns --show-labels.
  • ModelId is the human-readable model identifier (e.g. meta-llama/Llama-3-8B). The custom modeldeployment list/show functions best-effort resolve each deployment's modelResourceId to the AIModel's properties.modelId; AIModel lookups are memoized by (location, ai_model_name) so a namespace with many deployments referencing the same model incurs one GET per distinct model. When resolution fails the column is left blank (the raw AIModel resource name is not human-readable, so it is not used as a fallback).
  • Replicas is rendered current/desired, using - for counts not yet reported.
  • All formatters guard against properties/status being present but null.

Changes

  • Add azext_aimanager/_format.py with table formatters for aimanager, namespace and modeldeployment.
  • Wire the transformers into the respective list/show commands in commands.py.
  • Resolve human-readable ModelId in custom.py (_annotate_model_ids) with memoized AIModel lookups.
  • Add unit tests (test_aimanager_format.py).
  • Bump extension version to 1.5.3b1 and update HISTORY.rst.

General Guidelines

  • My extension version conforms to the Extension version schema.

About Extension Publish

Only setup.py and HISTORY.rst version info were updated; src/index.json is untouched.

Drop the `ETag` column and add `ProvisioningState` and `Subscription`
columns to the `-o table` output for `az aimanager list` and
`az aimanager show`, matching the information shown by peer commands
such as `az aks list`.

Fixes AB#39624822

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 10, 2026 16:09
@azure-client-tools-bot-prd

Copy link
Copy Markdown

Hi Liqian Luo (@circy9),
Please write the description of changes which can be perceived by customers into HISTORY.rst.
If you want to release a new extension version, please update the version in pyproject.toml (or setup.py, if the extension has not migrated yet) as well.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new table formatter can raise at runtime when properties is present but null, which would break -o table output for certain API responses.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR improves the default -o table output for az aimanager list and az aimanager show by replacing the implicit table projection (which exposed ETag) with explicit table transformers that surface more user-relevant fields like provisioning state and subscription.

Changes:

  • Added azext_aimanager/_format.py with table transformer functions for single and list AI Manager results.
  • Wired the new table transformers into aimanager show and aimanager list command registrations.
  • Added unit tests for the new table formatting and bumped the extension version + release notes.
File summaries
File Description
src/aimanager/setup.py Bumps extension version to 1.5.3b1.
src/aimanager/HISTORY.rst Documents the table output change in release notes.
src/aimanager/azext_aimanager/_format.py Introduces explicit table formatters for AI Manager list/show.
src/aimanager/azext_aimanager/commands.py Hooks the new formatters into the CLI commands.
src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py Adds unit tests validating column selection and basic parsing.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/aimanager/azext_aimanager/_format.py Outdated
Comment thread src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py
Liqian Luo (circy9) and others added 10 commits September 10, 2026 09:59
Order as Name, ProvisioningState, ResourceGroup, Subscription, Location.

Co-Authored-By: Claude <noreply@anthropic.com>
Guard against `properties` being present but null (Optional in the
vendored model) so `-o table` does not raise AttributeError. Add a
regression test for the null-properties case.

Co-Authored-By: Claude <noreply@anthropic.com>
Subscription is constant within a single list call, so remove it.
Table columns are now Name, ProvisioningState, ResourceGroup, Location.

Co-Authored-By: Claude <noreply@anthropic.com>
Format `az aimanager namespace list` and `show` `-o table` output with
Name, ProvisioningState, AIManager (parent, parsed from id) and
ResourceGroup columns. Add unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Format `az aimanager namespace modeldeployment list` and `show`
`-o table` output with Name, ProvisioningState, ModelId, Replicas
(current/desired), Endpoint, Namespace, AIManager and ResourceGroup.

ModelId is the human-readable model identifier: the custom list/show
functions best-effort resolve the deployment's modelResourceId to the
AIModel's properties.modelId; the formatter falls back to the AIModel
resource name when resolution is unavailable.

Co-Authored-By: Claude <noreply@anthropic.com>
Build the AIModel client once per list/show and cache lookups by
(location, ai_model_name), so a namespace with many deployments that
reference the same model incurs one GET per distinct model instead of
one per deployment.

Co-Authored-By: Claude <noreply@anthropic.com>
Namespace table: keep only Name and ProvisioningState.
Modeldeployment table: drop AIManager and ResourceGroup, keeping Name,
ProvisioningState, ModelId, Replicas, Endpoint and Namespace.

Co-Authored-By: Claude <noreply@anthropic.com>
Render the Kubernetes namespace labels (properties.labels) as
comma-joined key=value pairs, sorted for stable output, similar to
kubectl get ns --show-labels.

Co-Authored-By: Claude <noreply@anthropic.com>
Derive Age from systemData.createdAt and render it kubectl-style
(e.g. 45d, 3h12m), placed just before Labels. Best-effort: blank when
the timestamp is missing or unparseable.

Co-Authored-By: Claude <noreply@anthropic.com>
Columns are now Namespace, Name, ProvisioningState, Replicas, Age,
ModelId, Endpoint. Age is derived from systemData.createdAt.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py Outdated
Comment thread src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py Outdated
Comment thread src/aimanager/azext_aimanager/tests/latest/test_aimanager_format.py Outdated
Liqian Luo (circy9) and others added 2 commits September 10, 2026 10:45
Remove the unused eTag sample field and the redundant assertNotIn("ETag")
assertions; the exact key-list assertions already prove ETag is absent.

Co-Authored-By: Claude <noreply@anthropic.com>
Do not fall back to the raw AIModel resource name (not human-readable);
leave the ModelId column blank when the human-readable id is unavailable.

Co-Authored-By: Claude <noreply@anthropic.com>
@xmzhao0822

Copy link
Copy Markdown
Contributor

Reviewed the PR and did some testing. This PR change doesn't break the existing functionality such as creating aimanager, namespace and model deployment. The only missing part is the "ModelId" doesn't show up.

Testing result:

(env) root [ ~ ]# az aimanager show -g clixmtesteuap-rg -n clixmaimeuap -otable
Command group 'aimanager' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name          ProvisioningState    ResourceGroup     Location
------------  -------------------  ----------------  -----------
clixmaimeuap  Succeeded            clixmtesteuap-rg  eastus2euap
(env) root [ ~ ]# az aimanager list -g clixmtesteuap-rg -otable
Command group 'aimanager' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name          ProvisioningState    ResourceGroup     Location
------------  -------------------  ----------------  -----------
clixmaimeuap  Succeeded            clixmtesteuap-rg  eastus2euap
(env) root [ ~ ]# az aimanager namespace show -g clixmtesteuap-rg -m clixmaimeuap -n ns1 -otable
Command group 'aimanager namespace' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name    ProvisioningState    Age    Labels
------  -------------------  -----  ---------
ns1     Succeeded            6m     team=beta

(env) root [ ~ ]# az aimanager namespace list -g clixmtesteuap-rg -m clixmaimeuap -otable
Command group 'aimanager namespace' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name    ProvisioningState    Age    Labels
------  -------------------  -----  ---------
ns1     Succeeded            6m     team=beta
(env) root [ ~ ]# az aimanager namespace modeldeployment show -g clixmtesteuap-rg --aimanager-name clixmaimeuap --namespace-name ns1
-n md1 -otable
Command group 'aimanager namespace modeldeployment' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Namespace    Name    ProvisioningState    Replicas    Age    ModelId    Endpoint
-----------  ------  -------------------  ----------  -----  ---------  -------------------------------------------------------------
ns1          md1     Succeeded            1/1         19m               https://ns1.6aa30ce7adb8d8000167d92c.eastus2euap.aksapp.io/v1

(env) root [ ~ ]# az aimanager namespace modeldeployment list -g clixmtesteuap-rg --aimanager-name clixmaimeuap --namespace-name ns1
-otable
Command group 'aimanager namespace modeldeployment' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Namespace    Name    ProvisioningState    Replicas    Age    ModelId    Endpoint
-----------  ------  -------------------  ----------  -----  ---------  -------------------------------------------------------------
ns1          md1     Succeeded            0/1         17m               https://ns1.6aa30ce7adb8d8000167d92c.eastus2euap.aksapp.io/v1

@PugDeveloper

PugDeveloper commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Reviewed the PR and did some testing. This PR change doesn't break the existing functionality such as creating aimanager, namespace and model deployment. The only missing part is the "ModelId" doesn't show up.

Testing result:

(env) root [ ~ ]# az aimanager show -g clixmtesteuap-rg -n clixmaimeuap -otable
Command group 'aimanager' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name          ProvisioningState    ResourceGroup     Location
------------  -------------------  ----------------  -----------
clixmaimeuap  Succeeded            clixmtesteuap-rg  eastus2euap
(env) root [ ~ ]# az aimanager list -g clixmtesteuap-rg -otable
Command group 'aimanager' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name          ProvisioningState    ResourceGroup     Location
------------  -------------------  ----------------  -----------
clixmaimeuap  Succeeded            clixmtesteuap-rg  eastus2euap
(env) root [ ~ ]# az aimanager namespace show -g clixmtesteuap-rg -m clixmaimeuap -n ns1 -otable
Command group 'aimanager namespace' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name    ProvisioningState    Age    Labels
------  -------------------  -----  ---------
ns1     Succeeded            6m     team=beta

(env) root [ ~ ]# az aimanager namespace list -g clixmtesteuap-rg -m clixmaimeuap -otable
Command group 'aimanager namespace' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Name    ProvisioningState    Age    Labels
------  -------------------  -----  ---------
ns1     Succeeded            6m     team=beta
(env) root [ ~ ]# az aimanager namespace modeldeployment show -g clixmtesteuap-rg --aimanager-name clixmaimeuap --namespace-name ns1
-n md1 -otable
Command group 'aimanager namespace modeldeployment' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Namespace    Name    ProvisioningState    Replicas    Age    ModelId    Endpoint
-----------  ------  -------------------  ----------  -----  ---------  -------------------------------------------------------------
ns1          md1     Succeeded            1/1         19m               https://ns1.6aa30ce7adb8d8000167d92c.eastus2euap.aksapp.io/v1

(env) root [ ~ ]# az aimanager namespace modeldeployment list -g clixmtesteuap-rg --aimanager-name clixmaimeuap --namespace-name ns1
-otable
Command group 'aimanager namespace modeldeployment' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Namespace    Name    ProvisioningState    Replicas    Age    ModelId    Endpoint
-----------  ------  -------------------  ----------  -----  ---------  -------------------------------------------------------------
ns1          md1     Succeeded            0/1         17m               https://ns1.6aa30ce7adb8d8000167d92c.eastus2euap.aksapp.io/v1

thats cause there is no modelid column in azure-cli 2.76 and up, it returns blank.

so custom.py:654 writes modelId onto the deployment object. That key isn't a declared field on ModelDeployment; it's declared on AIModel. The CLI converts the object to a dict before the transformer runs, and azure-cli changed that conversion in core 2.76.0 (commit 4254e5467, July 2025). New cores copy declared fields only, so the key is dropped and _format.py:104 reads nothing.

@PugDeveloper

Copy link
Copy Markdown
Contributor

would prob need to resolve the model or return a plain dicts from show/list instead

The resolved modelId was injected as an extra attribute on the
ModelDeployment SDK model, but azure-cli core 2.76+ copies only declared
fields when converting a model for output, silently dropping it — so the
ModelId column always rendered blank.

Return plain dicts from list/show_modeldeployment with modelId set, so
the value survives output conversion. Add regression tests covering the
plain-dict result, per-model memoization, and blank-on-failure.

Reported by @xmzhao0822; root cause diagnosed by @PugDeveloper.

Co-Authored-By: Claude <noreply@anthropic.com>
@circy9

Copy link
Copy Markdown
Author

Thanks Ximeng Zhao (@xmzhao0822) for testing and PugDeveloper for the precise root cause — that's exactly it.

modelId was being injected as an extra attribute on the ModelDeployment SDK model, but azure-cli core 2.76+ copies only declared fields when converting a model to output, so the injected key was silently dropped and the column rendered blank.

Fixed in 35dab0f0c by returning plain dicts from list/show_modeldeployment (with modelId set), which pass through output conversion untouched — per PugDeveloper's suggestion. The AIModel resolution + per-model memoization is unchanged; on resolution failure the column stays blank (the raw AIModel resource name isn't human-readable). Added regression tests for the plain-dict result, memoization, and the blank-on-failure path.

Could you re-test when you get a chance? The az aimanager namespace modeldeployment list/show -o table output should now show the human-readable ModelId (e.g. meta-llama/Llama-3-8B).

Comment thread src/aimanager/azext_aimanager/custom.py
Comment thread src/aimanager/azext_aimanager/custom.py Outdated
Comment thread src/aimanager/azext_aimanager/custom.py
Comment thread src/aimanager/azext_aimanager/custom.py
Comment thread src/aimanager/azext_aimanager/custom.py Outdated
Comment thread src/aimanager/azext_aimanager/custom.py Outdated
Adopt reviewer suggestion: convert deployments (and the resolved AIModel)
with azure.cli.core.util.todict instead of dict(). todict recurses into
nested objects, so properties/status become plain dicts too and the
camelCase JSON keys the formatter reads are preserved.

Co-Authored-By: Claude <noreply@anthropic.com>
@xmzhao0822

Copy link
Copy Markdown
Contributor

yes, I left comments how to fix it. After resolving the change, should be good

image

@xmzhao0822

Copy link
Copy Markdown
Contributor

Thanks Ximeng Zhao (Ximeng Zhao (@xmzhao0822)) for testing and PugDeveloper for the precise root cause — that's exactly it.

modelId was being injected as an extra attribute on the ModelDeployment SDK model, but azure-cli core 2.76+ copies only declared fields when converting a model to output, so the injected key was silently dropped and the column rendered blank.

Fixed in 35dab0f0c by returning plain dicts from list/show_modeldeployment (with modelId set), which pass through output conversion untouched — per PugDeveloper's suggestion. The AIModel resolution + per-model memoization is unchanged; on resolution failure the column stays blank (the raw AIModel resource name isn't human-readable). Added regression tests for the plain-dict result, memoization, and the blank-on-failure path.

Could you re-test when you get a chance? The az aimanager namespace modeldeployment list/show -o table output should now show the human-readable ModelId (e.g. meta-llama/Llama-3-8B).

reviewing

@xmzhao0822

Copy link
Copy Markdown
Contributor

Looks good to me. It can list/show the Model ID.

@xmzhao0822 Ximeng Zhao (xmzhao0822) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@xmzhao0822

Ximeng Zhao (xmzhao0822) commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Hi Julie Zhu (@yanzhudd), Ethan Yang (@necusjz), this PR only update the format for show/list. Verified and tested, please help to merge, thanks.

@necusjz

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@yonzhan

Copy link
Copy Markdown
Collaborator

Please fix CI issues first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants