feat(agents): provision Foundry memory stores during deploy#8852
Conversation
Add support for declaring Foundry memory stores in the agent service config and provisioning them (create-if-not-exists) during `azd deploy`, mirroring the reference provision_memory_store.py sample. - New FoundryMemoryStoreClient (Create/Get/Ensure) targeting the memory_stores data-plane API (api-version 2025-11-15-preview). - New `memoryStores` section in the agent service-target config and JSON schema. - provisionMemoryStores wired into the agent Deploy flow before agent creation. Fixes #8742 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📋 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 Foundry memory support to the azure.ai.agents extension by allowing users to declare memoryStores in azure.yaml, and provisioning those stores (create-if-not-exists) as part of the hosted-agent deploy flow.
Changes:
- Adds
memoryStoresto the agent service-target config and JSON schema, including optional retention/extraction options. - Introduces a new Foundry data-plane client to
GET/POSTmemory store resources and an idempotentEnsureMemoryStore. - Wires provisioning into
Deployand adds unit tests + a changelog entry.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/extensions/azure.ai.agents/schemas/azure.ai.agent.json | Adds memoryStores schema and MemoryStore definition for azure.yaml validation. |
| cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go | Calls memory-store provisioning during deploy; adds mapping helper for options. |
| cli/azd/extensions/azure.ai.agents/internal/project/memory_store_provision_test.go | Adds tests for provisioning no-op, validation, and options mapping. |
| cli/azd/extensions/azure.ai.agents/internal/project/config.go | Extends service target config structs with MemoryStore and MemoryStoreOptions. |
| cli/azd/extensions/azure.ai.agents/internal/project/config_test.go | Adds marshal/unmarshal round-trip coverage for MemoryStores. |
| cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_memory_store_client.go | Introduces the Foundry Memory Store data-plane client (create/get/ensure). |
| cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_memory_store_client_test.go | Adds request-shape, escaping, and ensure(create-if-missing) tests for the client. |
| cli/azd/extensions/azure.ai.agents/internal/exterrors/codes.go | Adds error code and op name for memory store provisioning. |
| cli/azd/extensions/azure.ai.agents/CHANGELOG.md | Documents the new memoryStores deploy-time provisioning behavior. |
jongio
left a comment
There was a problem hiding this comment.
One error code inconsistency to fix. The rest of the implementation follows existing patterns cleanly (client structure mirrors the toolsets client, idempotent ensure pattern is solid, tests cover the key branches).
The Copilot bot flagged IncludeBody: true as a concern, but that's the existing convention in oundry_toolsets_client.go, so it's fine here.
… options, neutral provision op name Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
Incremental review after 1f1975d: the error code is now aligned with the existing CodeMissingAiProjectEndpoint convention, the mapMemoryStoreOptions nil-or-empty guard prevents sending an empty options object to the service, and the op name OpProvisionMemoryStore better reflects the GET-then-POST semantics of EnsureMemoryStore. All fields in memoryStoreOptionsEmpty match the MemoryStoreOptions struct, and the new test case validates the empty-struct path. No remaining concerns.
…-memory-support # Conflicts: # cli/azd/extensions/azure.ai.agents/CHANGELOG.md
|
@copilot resolve the merge conflicts in this pull request |
…-memory-support # Conflicts: # cli/azd/extensions/azure.ai.agents/CHANGELOG.md Co-authored-by: huimiu <107838226+huimiu@users.noreply.github.com>
Done. Merged |
RickWinter
left a comment
There was a problem hiding this comment.
This adds a data-plane client for Foundry memory stores and wires idempotent create-if-missing provisioning into the hosted-agent deploy, gated on declared memoryStores in azure.yaml. The shape is right: it mirrors the existing Foundry client pattern, keys off FOUNDRY_PROJECT_ENDPOINT like the rest of the file, only creates on a real 404, and propagates auth/5xx/network errors instead of masking them. Client and provisioning-validation test coverage is solid. The one thing worth resolving before merge is drift: once a store exists, editing its chatModel, embeddingModel, or options in azure.yaml has no effect and no warning, and the gray "leaving as-is" line lands exactly where a user expects their change to apply. Documenting that as intended and, ideally, warning when the declared definition diverges from the live store would prevent a confusing silent no-op. The rest are optional: validating all stores before the first network call avoids half-provisioning on a typo, and routing the created/exists lines through the progress reporter keeps deploy output consistent. Nothing here blocks; the idempotent design is sound and safe to re-run.
jongio
left a comment
There was a problem hiding this comment.
All prior feedback addressed. The implementation follows existing patterns cleanly, test coverage is solid, and the merge conflicts from main were resolved without issues.
|
/check-enforcer override |
… route status through progress - Detect and warn when a declared memory store definition diverges from an existing live store, so azure.yaml changes are not silently ignored (azd does not update existing stores). - Validate all declared stores before any network call to avoid half-provisioning on a typo. - Route created/already-exists status through the progress reporter for consistent deploy output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….com/Azure/azure-dev into glharper/8742-foundry-memory-support # Conflicts: # cli/azd/extensions/azure.ai.agents/CHANGELOG.md
There was a problem hiding this comment.
Incremental review of 119db86: drift detection, upfront validation, and progress routing all look correct.
- validateMemoryStores extraction ensures fail-fast before any network call
- memoryStoreDefinitionDrift only flags fields the user explicitly declared (no false positives from service defaults)
- boolPtrDiffers nil-handling is correct: nil declared = no drift, nil live with set declared = drift
- Test coverage is thorough (drift scenarios, bool pointer edge cases, upfront validation ordering)
- writeMemoryStoreDriftWarning on stderr with actionable remediation text is the right output channel for a warning
No remaining concerns.
RickWinter
left a comment
There was a problem hiding this comment.
This adds Foundry memory store provisioning to the hosted-agent deploy path: a new data-plane client (FoundryMemoryStoreClient), a memoryStores config/schema block, and provisionMemoryStores wired into Deploy before the agent is created. The shape is right. The client faithfully mirrors the existing FoundryToolboxClient (same pipeline, same https://ai.azure.com/.default scope), validation runs up front before any network call, errors are classified through exterrors, and provisioning is idempotent with a clear warning when a declared definition diverges from a store that already exists.
One thing worth resolving before merge: the drift detection in memoryStoreDefinitionDrift assumes the GET on an existing store returns the full definition. If the preview API does not echo it, the warning fires on every redeploy of a correctly configured store. That is a UX regression rather than a correctness bug, so it does not block, but I would confirm the service contract before this ships. See the inline note.
One non-blocking edge case to keep in mind: because Deploy runs per service in parallel, two services declaring the same store name could both GET 404 and then race on create, and the second POST would surface as an error. Fine to leave for now given this is preview and an unusual config, but worth a follow-up if it comes up.
Nothing here blocks. Address the drift-on-GET question (or confirm the contract), and the rest is good to merge.
| func memoryStoreDefinitionDrift(declared, live azure.MemoryStoreDefinition) []string { | ||
| var drift []string | ||
|
|
||
| if declared.ChatModel != live.ChatModel { |
There was a problem hiding this comment.
This comparison assumes the GET on an existing store returns the full definition (chat_model, embedding_model, and any options) that we send on create. If the 2025-11-15-preview service omits or only partially populates definition on GET, then live.ChatModel comes back empty and this reports drift on every redeploy of a correctly configured store, so the user sees the "changes were NOT applied" warning even when nothing changed. Have we confirmed against the live service that GET echoes the definition? If it does not, I would gate the warning on the live definition actually being populated rather than comparing declared values against zero values.
Summary
Adds support for Foundry memory in the azure.ai.agents extension by provisioning Foundry memory stores as part of the hosted-agent deploy flow, mirroring the reference
provision_memory_store.pysample.Users declare one or more memory stores under the agent service config in
azure.yaml, and azd creates them (idempotent create-if-not-exists) in the Foundry project before deploying the agent. Memory stores back the agent'smemory_searchtool, letting agents retain context across sessions.Fixes #8742
What changed
FoundryMemoryStoreClient(internal/pkg/azure/foundry_memory_store_client.go): new data-plane client withCreateMemoryStore,GetMemoryStore, and an idempotentEnsureMemoryStore(create-if-missing, leave existing stores unchanged). TargetsPOST/GET {projectEndpoint}/memory_storeswith API version2025-11-15-preview, matching the official REST contract. Follows the existingFoundryToolboxClientpattern.internal/project/config.go): newmemoryStoressection on the agent service-target config (name,description,chatModel,embeddingModel, and optional extraction/retentionoptions).internal/project/service_target_agent.go):provisionMemoryStoresis invoked fromDeployafter config/env load and before the agent is created. Validates required fields and reports per-store progress and created/already-exists status.schemas/azure.ai.agent.json):memoryStoresarray +MemoryStoredefinition.internal/exterrors/codes.go):CodeInvalidMemoryStore,OpCreateMemoryStore.Example
azure.yamlconfigDesign notes / assumptions
chatModel/embeddingModelreference model deployment names that must already exist in the Foundry project (consistent with the sample and REST docs).main; this PR targetsmainusing the existing service-target config, consistent with howtoolboxes/connections/deploymentsare declared.Testing
go build ./...go test ./...(full extension suite passes)gofmt -s,golangci-lint run(0 issues),cspell(0 issues) on changed files