Skip to content

doc: add design spec for azd ai agent routine commands#8200

Open
huimiu wants to merge 5 commits into
mainfrom
huimiu/hui-ai-routine-design-spec
Open

doc: add design spec for azd ai agent routine commands#8200
huimiu wants to merge 5 commits into
mainfrom
huimiu/hui-ai-routine-design-spec

Conversation

@huimiu
Copy link
Copy Markdown
Member

@huimiu huimiu commented May 15, 2026

Summary

Adds the design spec for the new routine command subtree (cli/azd/docs/design/ai-routine-design-spec.md). A routine pairs one trigger (when) with one action (what) on a Foundry project, for example "every weekday at 8 AM UTC, invoke the daily report agent", without standing up Logic Apps, Functions, or cron infra.

Related issues:

Key points

  • Placement: lives in the existing azure.ai.agents extension. Today the commands surface as azd ai agent routine …; they become azd ai routine … after the planned extension split (registration only). No azure.yaml or registry.json impact, no new persistent state.
  • v1 surface: create, update, show, list, delete, enable, disable, dispatch, and run list. run show and run delete are deferred until the data plane lands them.
  • Endpoint resolution: reuses the standard 5 level cascade and works standalone outside an azd project, matching connection, toolbox, and skill. The Routines=V1Preview opt in header is sent on every call.
  • Create vs. update: the data plane is a single idempotent PUT; the CLI splits it for usability. create fails on existing (or upserts with --force). update is GET then PUT preserving untouched fields, with type switching of --trigger / --action rejected client side.
  • enable / disable / dispatch: dedicated idempotent verbs hide the wire format. dispatch is sync by default and streams the agent response; --async switches to the async route.
  • Wire mapping: kebab case CLI aliases (recurring, agent-response, agent-invoke) read naturally and absorb upstream API renames via a single mapping table.
  • Telemetry and tests: one event per command (no PII), plus unit coverage for flag to wire mapping, update merge semantics, and dispatch route selection, with an E2E smoke covering the create through delete loop.

@huimiu huimiu marked this pull request as ready for review May 15, 2026 07:02
Copilot AI review requested due to automatic review settings May 15, 2026 07:02
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

📋 Prioritization Note

Thanks for the contribution! The linked issue isn't in the current milestone yet.
Review may take a bit longer — reach out to @rajeshkamal5050 or @kristenwomack if you'd like to discuss prioritization.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a design specification for the proposed azd ai agent routine command subtree in the azure.ai.agents extension, covering command behavior, endpoint resolution, wire mappings, telemetry, and tests.

Changes:

  • Adds the routine command design spec and v1 command surface.
  • Documents endpoint resolution, API routes, output shapes, telemetry, and test plan.
  • Adds a cspell override for terminology in the new design doc.

Reviewed changes

Copilot reviewed 1 out of 1 changed files in this pull request and generated 8 comments.

File Description
cli/azd/docs/design/ai-routine-design-spec.md New design spec for routine commands.
cli/azd/.vscode/cspell.yaml Adds a file-specific spelling override for the new doc.

Comment thread cli/azd/docs/design/ai-routine-design-spec.md Outdated
Comment thread cli/azd/docs/design/ai-routine-design-spec.md Outdated
Comment thread cli/azd/docs/design/ai-routine-design-spec.md
Comment thread cli/azd/docs/design/ai-routine-design-spec.md
Comment thread cli/azd/docs/design/ai-routine-design-spec.md
Comment thread cli/azd/docs/design/ai-routine-design-spec.md Outdated
Comment thread cli/azd/docs/design/ai-routine-design-spec.md Outdated
Comment thread cli/azd/docs/design/ai-routine-design-spec.md Outdated
- Multi-trigger routines via the CLI — deferred ([§7 OQ-2](#7-open-questions)).
- Changing `--trigger` or `--action` *type* on an existing routine — delete and
recreate, mirroring the `connection` auth-type rule ([§4.2](#42-create-vs-update)).
- Creating routines from a file (`--file`) — tracked as [#8187](https://github.com/Azure/azure-dev/issues/8187).
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.

Add this back to the scope. We need to be able to create from a file so routines can live in the repo as source controlled items.

Comment thread cli/azd/docs/design/ai-routine-design-spec.md

### Out of scope

- Declarative routines (`routine.yaml`, `azd provision` integration, `azd up`) —
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.

sorry my naive question - is azd provision and azd up needed? thought azd ai routine create would cover the JTBD

Comment thread cli/azd/docs/design/ai-routine-design-spec.md
| --------------- | ---------------- | -------------------------------------------------------------------- | ------ |
| `recurring` | `schedule` | `--cron "<expr>"`, `--time-zone <tz>` | v1 |
| `timer` | `timer` | `--at "<ISO 8601>"`, `--time-zone <tz>` | v1 |
| `github-issue` | `github_issue` | `--connection <id>`, `--owner <o>`, `--repository <r>`, `--event-action <a>` (repeatable) | Deferred — pending workspace connection model |
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.

it seems typespec is making this only specific to github, checking with the team

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.

there is only github-issue strong typed trigger, we plan to add a few other strong typed trigger and a generic event based trigger, coming soon next week. Would this risking azd plan?

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.

we will update the typespec next monday with the generic and a few more strong typed ones

| Flag | Notes |
| --------------------- | -------------------------------------------------------------------- |
| `--async` | Switches to `:dispatchAsync`. Returns `dispatch_id` immediately. |
| `--input "<text>"` | User-message payload wrapped into `RoutineDispatchPayload`. |
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.

this --input ''" can accept json format if customer provides?

Copy link
Copy Markdown
Contributor

@lindazqli lindazqli left a comment

Choose a reason for hiding this comment

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

Reviewed against TypeSpec PR #43186 (adding routines, now merged into feature/foundry-release). Six issues found — four are blockers before shipping v1:

  1. [Line 56] TypeSpec PR reference is stale (#42779 → should be #43186).
  2. [Line 165] enable/disable should call the dedicated :enable / :disable routes that already exist in the TypeSpec, not GET-then-PUT.
  3. [Line 173] No sync :dispatch route exists in TypeSpec — only POST :dispatch_async. The "sync by default" contract has no API backing.
  4. [Line 249] --agent-id / agent_id should be --agent-name / agent_name to match the TypeSpec field name.
  5. [Line 201] --orderby has no orderBy query param in ListRoutineRunsParameters.
  6. [Line 239] GitHub trigger: --owner serializes to owner but TypeSpec field is assignee; --event-action has no TypeSpec counterpart.

### In scope

- The commands listed in [§1](#1-summary).
- Mapping from CLI flags onto the wire format in [TypeSpec PR #42779](https://github.com/Azure/azure-rest-api-specs/pull/42779).
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.

Stale TypeSpec PR reference. This spec cites PR #42779 throughout (§1, §4.8, §7 OQ-3). The routines TypeSpec landed in PR #43186 (now merged into feature/foundry-release). Please update all references to #43186 so readers can cross-check the wire format accurately.


Dedicated verbs that hide the wire format. Today: GET-then-PUT toggling
`enabled: true | false`. If the service later adds `:enable` / `:disable` action
routes, the CLI flips silently — the verb contract does not change.
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.

enable/disable routes already exist in TypeSpec. The spec says these use "GET-then-PUT toggling enabled: true | false" and speculates "If the service later adds :enable / :disable action routes, the CLI flips silently." However, TypeSpec PR #43186 already defines these as dedicated operations:

POST /routines/{routine_name}:enable  → enableRoutine
POST /routines/{routine_name}:disable → disableRoutine

The CLI should call these directly rather than doing a GET-then-PUT. The GET-then-PUT fallback is unnecessary and creates a TOCTOU race.


### 4.6 `routine dispatch <name>`

Sync by default → `POST /routines/{name}:dispatch`.
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.

No sync dispatch route exists in TypeSpec. This line proposes POST /routines/{name}:dispatch as the sync path, but TypeSpec PR #43186 only defines one dispatch operation:

POST /routines/{routine_name}:dispatch_async  → dispatchRoutineAsync

There is no synchronous :dispatch route. The "Sync by default" contract described here has no backing API. Either:

  • Clarify that dispatch always maps to :dispatch_async (both sync and --async modes), or
  • Track getting a sync :dispatch route added to the TypeSpec before shipping this verb.

Also note the route uses an underscore (dispatch_async), not camel case — the routes table in §5.3 should reflect that.


| CLI `--action` | TypeSpec `type` | Required CLI flags | Optional CLI flags |
| ----------------------- | -------------------------------- | ----------------------------------------------- | --------------------- |
| `agent-response` (def.) | `invoke_agent_responses_api` | one of `--agent-id` / `--agent-endpoint-id` | `--conversation-id` |
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.

--agent-id maps to the wrong TypeSpec field. The TypeSpec field for the project-scoped agent name is agent_name, not agent_id:

@doc("The project-scoped agent name for responses API dispatch.")
@maxLength(256)
agent_name?: string;

The flag should be --agent-name (or the wire key should be documented as agent_name). Using agent_id / --agent-id implies an ID (UUID/numeric), whereas this is a human-readable name used for project-scoped lookup. This also affects the telemetry property name in §6 (agent_idagent_name or agentName).

| CLI flag | Query param |
| ------------- | ------------------ |
| `--top N` | `maxResults` per page; CLI stops auto-paging once `N` items have been returned |
| `--orderby` | `orderBy` (repeatable) |
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.

--orderby has no backing TypeSpec query parameter. ListRoutineRunsParameters in TypeSpec PR #43186 only spreads CommonPageQueryParameters (which covers pagination) plus the filter query param. There is no orderBy parameter defined. Either remove --orderby from v1 scope or get orderBy added to the TypeSpec before shipping run list.

| --------------- | ---------------- | -------------------------------------------------------------------- | ------ |
| `recurring` | `schedule` | `--cron "<expr>"`, `--time-zone <tz>` | v1 |
| `timer` | `timer` | `--at "<ISO 8601>"`, `--time-zone <tz>` | v1 |
| `github-issue` | `github_issue` | `--connection <id>`, `--owner <o>`, `--repository <r>`, `--event-action <a>` (repeatable) | Deferred — pending workspace connection model |
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.

Field name mismatch on the GitHub issue trigger. The spec maps --owner → GitHub assignee/org filter, but the TypeSpec field is assignee, not owner:

@doc("The GitHub assignee or organization filter that scopes which issues can fire the trigger.")
@maxLength(128)
assignee: string;

--owner would serialize to owner on the wire, which the service won't recognize. The flag should be --assignee to match the TypeSpec (or the spec should explicitly document the CLI-to-wire mapping for this field).

Additionally, --event-action has no corresponding field in GitHubIssueOpenedRoutineTrigger — it only has connection_id, assignee, and repository. Since this trigger type is deferred anyway, please remove --event-action from the table or track it as a separate TypeSpec gap.

Copy link
Copy Markdown
Contributor

@lindazqli lindazqli left a comment

Choose a reason for hiding this comment

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

Correction: the previous review was submitted as REQUEST_CHANGES by mistake — please treat all inline comments as informational notes for discussion, not as blockers. The comments remain valid observations to align the spec with TypeSpec PR #43186.

Copy link
Copy Markdown
Member

@jongio jongio left a comment

Choose a reason for hiding this comment

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

Spec follows the extension's existing patterns well for endpoint resolution, flag naming, and prompt/no-prompt behavior. The TypeSpec alignment feedback from existing reviews is the main thing to address before implementation.

One gap: error behavior isn't defined for any of the 9 commands. See inline comment.

**Not registered in v1.** The data-plane endpoints are not in
[TypeSpec PR #42779](https://github.com/Azure/azure-rest-api-specs/pull/42779).
These will be added as a strictly additive change when the APIs land, with no
churn on already-shipped verbs.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Missing from the spec: what does the user see on errors? Some cases the implementer will need to decide on:

  • create without --force on an existing name: 409 conflict? Structured error with a 'delete and recreate' hint?
  • show/delete/dispatch on a non-existent routine: how does the service 404 surface?
  • update's GET succeeds, then the routine gets deleted before the PUT lands: 404 on the PUT with no context?

The existing design specs in this repo don't have explicit error sections, so this isn't blocking. But since azd routes errors through error_suggestions.yaml and ErrorWithSuggestion, a one-liner like 'errors follow the connection command pattern' would prevent the implementer from having to reverse-engineer the expected error handling approach. The test plan would also benefit from negative cases covering service-side failures (404, 409, auth).

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

Labels

None yet

Projects

None yet

5 participants