doc: design spec for azd ai agent toolbox direct commands#8160
Conversation
📋 Prioritization NoteThanks for the contribution! The linked issue isn't in the current milestone yet. |
There was a problem hiding this comment.
Pull request overview
Adds a new design specification document describing the proposed azd ai agent toolbox direct-command surface in the azure.ai.agents extension (design review only; no implementation).
Changes:
- Documents the planned toolbox CRUD command surface (
create|update|delete|show|list) plusconnectionandtagsubgroups. - Specifies data-plane API endpoints, request/response shapes, and CLI behaviors (including a local pending-toolbox record model).
- Outlines endpoint resolution, config storage shape, telemetry events, error codes, and a test plan.
Comments suppressed due to low confidence (1)
cli/azd/docs/design/azure-ai-toolbox-direct-commands.md:166
- The spec’s computed MCP consumption URL omits the toolbox version (
{projectEndpoint}/toolboxes/{name}/mcp?...). In the existing extension code, the MCP endpoint is version-scoped:/toolboxes/{name}/versions/{version}/mcp?api-version=v1(seeextensions/azure.ai.agents/internal/cmd/listen.go). If the service contract is versioned, this spec should reflect that soshowreturns a runnable URL.
1. `GET /toolboxes/{name}` for `default_version`.
2. `GET /toolboxes/{name}/versions/{version}` (or `default_version` when `--version` is absent) for the body.
3. Compute the toolbox's MCP consumption URL as `{projectEndpoint}/toolboxes/{name}/mcp?api-version=v1`.
4. Output:
| - The eleven verbs listed in § 1. | ||
| - Cross-cutting flags (`--output table|json`, `--no-prompt`, `--debug`, `--project-endpoint`) on every new command. | ||
| - A self-contained data-plane client at `internal/pkg/toolbox/`. | ||
|
|
There was a problem hiding this comment.
@hund030 Reuse the existing one if you can for now.
| - The eleven verbs listed in § 1. | ||
| - Cross-cutting flags (`--output table|json`, `--no-prompt`, `--debug`, `--project-endpoint`) on every new command. | ||
| - A self-contained data-plane client at `internal/pkg/toolbox/`. | ||
|
|
There was a problem hiding this comment.
@hund030 Reuse the existing one if you can for now.
|
|
||
| ## 13. Open Questions | ||
|
|
||
| 1. Should `create` also accept an optional `--connection <name>` flag to publish v1 immediately, skipping the pending-record step? Current proposal: no — the pending-record model keeps `create` free of toolbox-write calls (it only reads `GET /toolboxes/{name}` to decide between the registered / existing one-liner) and matches the "one command, one action" principle from the umbrella spec. |
| ## 13. Open Questions | ||
|
|
||
| 1. Should `create` also accept an optional `--connection <name>` flag to publish v1 immediately, skipping the pending-record step? Current proposal: no — the pending-record model keeps `create` free of toolbox-write calls (it only reads `GET /toolboxes/{name}` to decide between the registered / existing one-liner) and matches the "one command, one action" principle from the umbrella spec. | ||
| 2. Should `toolbox list` surface every version's tool count, or just the default-version's count? Current proposal: just the default — matches what `show` displays by default and keeps the list call to a single GET per toolbox. |
|
|
||
| 1. Should `create` also accept an optional `--connection <name>` flag to publish v1 immediately, skipping the pending-record step? Current proposal: no — the pending-record model keeps `create` free of toolbox-write calls (it only reads `GET /toolboxes/{name}` to decide between the registered / existing one-liner) and matches the "one command, one action" principle from the umbrella spec. | ||
| 2. Should `toolbox list` surface every version's tool count, or just the default-version's count? Current proposal: just the default — matches what `show` displays by default and keeps the list call to a single GET per toolbox. | ||
| 3. Should `connection add` accept `--as <alias>` to decouple the tool entry's `name` from the connection name? Current proposal: no — defer until users ask. |
jongio
left a comment
There was a problem hiding this comment.
Solid spec with clear API mapping, good test plan, and well-structured command surface. A few design gaps that'll bite during implementation:
Error code overloading: CodeInvalidToolbox is used for 6+ distinct failure modes (duplicate connection, unsupported category, empty tools, missing --index, missing connection, invalid version target). This makes telemetry useless for distinguishing root causes. Consider at least: CodeDuplicateConnection, CodeUnsupportedConnectionCategory, CodeEmptyToolsArray, CodeMissingIndex.
TOCTOU in shared write flow: Steps 2-5 (fetch default version, mutate, POST, PATCH) have a race window. Two concurrent connection add calls both fetch the same version, both POST, and the second creates a version missing the first's tool. Worth acknowledging as a known limitation or describing retry/conflict detection (e.g., conditional on the fetched version number).
Stale pending-record accumulation: Records are cleared by connection add or delete, but if a user runs create and never follows up (or the endpoint changes), pending records accumulate forever. Consider a TTL (e.g., 30 days) or a toolbox list --cleanup-stale hint.
Built-in tool interaction with last-tool guard: connection remove rejects when tools[] would be empty. But if removing the last connection-backed tool leaves only built-ins (which are "carried through unchanged"), is the result considered empty? The guard should clarify whether empty means zero total entries or zero connection-backed entries.
show on pending toolbox: create records locally, but show does GET /toolboxes/{name} which will 404 for a pending-only toolbox. Should show fall back to displaying the pending record metadata, or explicitly error with "toolbox is pending, run connection add first"?
Summary
This PR adds the design spec for the
azd ai agent toolboxdirect commands. This is for design review only and contains no implementation code.What's in this spec
Five top-level verbs for managing versioned toolboxes against a Foundry project:
toolbox create <name>: register a toolbox (pending tools until firstconnection add).toolbox update <name> --default-version <n>: retarget the active version.toolbox delete <name>: delete the whole toolbox or a single version via--version.toolbox show <name>: display metadata, version body, and the toolbox's MCP endpoint URL for runtime consumption.toolbox list: list toolboxes plus any local pending records for the resolved endpoint.Connection subgroup (
connection add | remove | list) that wraps the toolbox versions API. Every tool mutation is a full-tools[]POST to/toolboxes/{name}/versionsfollowed by aPATCH default_version; tool-entry shape is inferred from the project connection's ARMcategory(RemoteTool→mcp,CognitiveSearch→azure_ai_search).Tag subgroup (
tag set | remove | list) shipped as a Compatibility stub: toolboxes are not yet exposed as ARM resources, so the standard ARM resource-tag surface is unavailable. The CLI surface is final and activates without surface changes once the underlying API exists.Pending-toolbox config store:
createcannot POST because the service requires a non-emptytools[], so it records a local entry underextensions.ai-agents.pending-toolboxes.<endpointHash>.items.<name>. The firstconnection addpromotes the record to a real v1.Live-verified API surface (§ 4): every endpoint the spec relies on was probed against a live Foundry project, including the per-version delete guard, the MCP runtime endpoint, and the ARM connection lookup used by
connection add.Key design decisions for review
azure.ai.agentsextension atazd ai agent toolbox …. Files are isolated underinternal/cmd/toolbox*.goandinternal/pkg/toolbox/so a future move to a standaloneazure.ai.toolboxextension is a registration-only change.createdoes not POST (§ 5.1, Open Question 1): the service requires a non-emptytools[]. Two options were considered — auto-seed with a sentinel built-in, or defer the first POST until the firstconnection add. Current proposal: defer (pending-record model). Keepscreatenon-network and matches the "one command, one action" principle.updateis--default-versiononly (§ 5.2): the service only acceptsdefault_versionon PATCH. Description and tool edits must go throughconnection add/connection remove, which publish a new version.default_versionwhen sibling versions exist (400). When the default is the only remaining version the service deletes it and cascades to remove the parent toolbox; the CLI rejects this without--forceto avoid surprise destruction.code_interpreter,web_search,file_search,mcp, andazure_ai_searchside-by-side. Per issue Feature: Add ai.toolbox commands for CRUD on Toolboxes in Foundry Project #8143, built-ins are wired on the agent rather than via toolboxes; the CLI does not author built-ins but carries them through unchanged during fetch-merge-POST.-pshort form (§ 5.1):-pis already taken onagent run/agent invoke. The canonical name is--project-endpoint, matching the project-context spec.Related
Feature: Add ai.toolbox commands for CRUD on Toolboxes in Foundry Projectdocs: design spec for azd ai connection direct commandsdoc: design spec for azd ai project context commands and endpoint resolution— the 5-level endpoint resolution cascade referenced in § 6 is owned by this spec.azd aiDirect Commands (CLI Surface for Foundry)