Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions migration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ az role assignment create `

# Cross-project: read from one project, write to another
.\migrate-docker.ps1 --source-resource-id "<SOURCE_ID>" --resource-id "<TARGET_ID>"

# Migrate agent definitions ONLY, skip files/vector stores (advanced — see below)
.\migrate-docker.ps1 --resource-id "<ID>" --no-migrate-files
```

---
Expand All @@ -134,6 +137,62 @@ Real v2 agents are named (`agent.name = "MyAgent"`, `agent.version = "1"`) — `

---

## Files & vector stores

When an assistant uses **`file_search`** or **`code_interpreter`**, its uploaded files and vector stores live in the *source* project. Those IDs don't exist in the target project, so a naive copy would leave the migrated agent with broken references. The tool handles this for you.

### It's automatic — no flag required

File and vector-store migration is **on by default**. For every assistant it migrates, the tool:

1. Reads the tool resources on the v1 assistant.
2. **Downloads** each referenced file from the source project.
3. **Re-uploads** it to the target project's **Foundry endpoint** (`{resource}.services.ai.azure.com`).
4. **Recreates** each `file_search` vector store on the target and attaches the re-uploaded files.
5. **Rewrites** the file IDs and vector-store IDs in the new v2 agent definition so everything resolves.

You'll see it in the run output:

```text
📂 File migration: ENABLED (target Foundry endpoint: https://<resource>.services.ai.azure.com/api/projects/<project>)
📦 Migrating files for assistant asst_abc123
🔧 code_interpreter: 2 file(s) to migrate
📥 Downloaded sales.csv (10240B)
📤 Uploaded sales.csv -> assistant-file-...
🔍 file_search: 1 vector store(s) to migrate
🗄️ Created vector store vs_...
✅ Vector store vs_... ready (3 file(s) ingested)
```

### What gets migrated (and what doesn't)

| Tool on the v1 assistant | What's migrated | Read from |
| --- | --- | --- |
| `code_interpreter` | Each attached file | `tool_resources.code_interpreter.file_ids` |
| `file_search` | Every file inside each vector store, plus a freshly created vector store | `tool_resources.file_search.vector_store_ids` |
| Any other tool (bing, function, openapi, …) | Nothing — these carry no files | — |

- **Only files referenced by a tool are copied.** Stray files in the project that no assistant points at are left alone.
- **No file-type or size filtering by this tool.** Whatever the source returns is re-uploaded as-is; the target Files / `file_search` API enforces the actual limits — currently a 512 MB max file size, 5,000,000 max tokens per file, and [these supported file types](https://learn.microsoft.com/azure/foundry/agents/how-to/tools/file-search#supported-file-types) (`.c`, `.cpp`, `.cs`, `.doc`/`.docx`, `.html`, `.java`, `.json`, `.md`, `.pdf`, `.php`, `.pptx`, `.py`, `.rb`, `.tex`, `.txt`, `.css`, `.js`, `.sh`, `.ts` — text files must be UTF-8/UTF-16/ASCII). A vector store can also hold at most 10,000 files. If a file is too large or an unsupported type, the API rejects it (HTTP 400/415, or the vector-store file status ends up `failed`) — the tool does **not** retry these, and reports the file id + API-provided reason (e.g. `[invalid_file] ...`) in the terminal, the assistant's `failed_files` list, and `migration_failed_files.json`.
- **Files shared** between `code_interpreter` and a vector store are uploaded once and reused (deduplicated).

### Turning it OFF — `--no-migrate-files`

Pass `--no-migrate-files` to copy **agent definitions only**. The v2 agent keeps the *source* file / vector-store IDs, which do **not** exist on the target — so `file_search` and `code_interpreter` stay broken until you re-upload manually. Use this only when the target already has the files, or when you plan to fix references yourself.

```powershell
.\migrate-docker.ps1 --resource-id "<ID>" --no-migrate-files
```

### Requirements & caveats

- The tool needs a reachable **source endpoint** and a derivable **target Foundry endpoint** (derived automatically from `--resource-id`). If either is missing it prints `⚠️ Cannot migrate files: …` and continues with definitions only.
- **A wrong `--production-endpoint` is accepted, not rejected.** If you override the target with a raw `--production-endpoint` that points at a legacy OpenAI-compatible host (`*.openai.azure.com`) or a raw Cognitive Services host (`*.cognitiveservices.azure.com`) instead of a Foundry host (`*.services.ai.azure.com`), the migration **will still run and the file/vector-store upload calls will still succeed (HTTP 200)** — but the uploaded files land in a namespace the Foundry agent runtime can't see, so `file_search`/`code_interpreter` stay broken on the migrated agent. The tool cannot tell this happened from the API responses alone, so it proactively checks the endpoint's hostname and prints a `⚠️` warning up front and again in the final summary — it does **not** fail the migration, since you may not care about files at all (see `--no-migrate-files`). Re-run with a Foundry-format endpoint to actually get working files.
- **Vector-store ingestion is polled per file, not per store.** Each file is attached to the vector store and polled individually (default: 30 attempts × 2s = up to 60s per file; configurable via `MIGRATION_VS_FILE_POLL_ATTEMPTS` / `MIGRATION_VS_FILE_POLL_INTERVAL`) until it reaches `completed` or `failed`. This isolates one bad file from the rest — the vector store is still created and attached with whatever files succeeded, even if the poll window elapses on a slow file (it keeps indexing server-side) or a file permanently fails.
- You need write access (**Foundry User**) on the *target* resource — the same role required for the rest of the migration.

---

## Don't have Docker? Use migrate.ps1 instead

If you already have **Python 3.10+** and **Azure CLI** installed locally, you can skip Docker:
Expand Down
40 changes: 40 additions & 0 deletions migration/v1_to_v2_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,19 @@ def get_target_openai_endpoint(production_resource: Optional[str] = None, produc
return None


def _is_foundry_host(url: Optional[str]) -> bool:
"""
Return True if *url*'s hostname is a Foundry project endpoint
(``*.services.ai.azure.com``). Files/vector stores uploaded anywhere
else (legacy ``*.openai.azure.com`` / ``*.cognitiveservices.azure.com``)
are invisible to the Foundry agent runtime.
"""
if not url:
return False
host = (urlparse(url).hostname or "").lower()
return host == "services.ai.azure.com" or host.endswith(".services.ai.azure.com")


def get_target_foundry_endpoint(production_resource: Optional[str] = None, production_endpoint: Optional[str] = None) -> Optional[str]:
"""
Return the Foundry endpoint for file uploads and vector-store creation.
Expand Down Expand Up @@ -3689,6 +3702,30 @@ def _has_tools(assistant: Dict[str, Any]) -> bool:
production_endpoint=production_endpoint,
)

# Although a target endpoint using the legacy OpenAI-compatible host
# (*.openai.azure.com) or the raw Cognitive Services host
# (*.cognitiveservices.azure.com) WILL BE ACCEPTED for migration — those
# hosts return HTTP 200 for the file/vector-store upload calls, so nothing
# in the migration "fails" — it will NOT actually migrate files/vector
# stores: the uploads land in a namespace the Foundry agent runtime can't
# see, so file_search/code_interpreter stay broken on the migrated agent.
# This wrong-but-accepted endpoint case is called out as a warning during
# migration (printed up front and repeated in the final summary) rather
# than treated as fatal, since callers who passed --no-migrate-files don't
# care about this at all.
file_migration_endpoint_warning: Optional[str] = None
if migrate_files and target_v2_endpoint and not _is_foundry_host(target_v2_endpoint):
file_migration_endpoint_warning = (
f"--production-endpoint ({target_v2_endpoint}) is a legacy OpenAI-compatible "
"(*.openai.azure.com) or Cognitive Services (*.cognitiveservices.azure.com) host, "
"not a Foundry (*.services.ai.azure.com) host. This endpoint WILL BE ACCEPTED for "
"migration — the upload calls succeed — but it will NOT migrate files/vector stores; "
"they end up invisible to the Foundry agent runtime. Re-run with a Foundry-format "
"--production-endpoint (or --production-resource) to migrate files successfully, "
"or pass --no-migrate-files if you don't need files migrated."
)
print(f"\n⚠️ {file_migration_endpoint_warning}\n")

# In-place upgrade (source == target): when no explicit target was supplied
# but the source project is itself a Foundry endpoint, reuse it as the target
# so the duplicate-migration guard still runs. Without this, re-running the
Expand Down Expand Up @@ -4003,6 +4040,9 @@ def ensure_tools_array():
# Always using v2 API
print(f" Target: v2 API ({BASE_V2})")

if file_migration_endpoint_warning:
print(f"\n⚠️ File/vector-store migration warning: {file_migration_endpoint_warning}")


def _classify_v1_item(item: Dict[str, Any]) -> str:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
requiredVersions:
extensions:
azure.ai.agents: '>=1.0.0-beta.4'
name: browser-automation-csharp-maf-sample-foundry
name: bat-csharp-maf
services:
ai-project:
host: azure.ai.project
Expand Down Expand Up @@ -35,7 +35,7 @@ services:
browser_automation_preview:
connection:
project_connection_id: '${AZURE_AI_PROJECT_ID}/connections/browserautomation'
browser-automation-csharp-maf-sample-foundry:
bat-csharp-maf:
host: azure.ai.agent
metadata:
tags:
Expand All @@ -44,7 +44,7 @@ services:
- Azure AI AgentServer
- Responses Protocol
- Browser Automation
project: src/browser-automation-csharp-maf-sample-foundry
project: src/bat-csharp-maf
language: csharp
docker:
path: Dockerfile
Expand All @@ -53,7 +53,7 @@ services:
- browserautomation
- browser-automation-tools
kind: hosted
name: browser-automation-csharp-maf-sample-foundry
name: bat-csharp-maf
displayName: Browser Automation Agent (C#, MAF)
description: A Foundry-hosted browser automation agent (C#, MAF) for general browsing, web scraping, and form filling.
protocols:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
requiredVersions:
extensions:
azure.ai.agents: '>=1.0.0-beta.4'
name: browser-automation-csharp-byo-sample-foundry
name: bat-csharp-byo
services:
ai-project:
host: azure.ai.project
Expand Down Expand Up @@ -35,7 +35,7 @@ services:
browser_automation_preview:
connection:
project_connection_id: '${AZURE_AI_PROJECT_ID}/connections/browserautomation'
browser-automation-csharp-byo-sample-foundry:
bat-csharp-byo:
host: azure.ai.agent
metadata:
tags:
Expand All @@ -44,7 +44,7 @@ services:
- Bring Your Own
- Browser Automation
- .NET
project: src/browser-automation-csharp-byo-sample-foundry
project: src/bat-csharp-byo
language: csharp
docker:
path: Dockerfile
Expand All @@ -53,7 +53,7 @@ services:
- browserautomation
- browser-automation-tools
kind: hosted
name: browser-automation-csharp-byo-sample-foundry
name: bat-csharp-byo
displayName: Browser Automation Agent (C#, BYO Responses)
description: A Foundry-hosted browser automation agent (C#, BYO Responses) for general browsing, web scraping, and form filling.
protocols:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
requiredVersions:
extensions:
azure.ai.agents: '>=1.0.0-beta.4'
name: browser-automation-python-maf-sample-foundry
name: bat-python-maf
services:
ai-project:
host: azure.ai.project
Expand Down Expand Up @@ -35,7 +35,7 @@ services:
browser_automation_preview:
connection:
project_connection_id: '${AZURE_AI_PROJECT_ID}/connections/browserautomation'
browser-automation-python-maf-sample-foundry:
bat-python-maf:
host: azure.ai.agent
metadata:
tags:
Expand All @@ -44,7 +44,7 @@ services:
- Azure AI AgentServer
- Responses Protocol
- Browser Automation
project: src/browser-automation-python-maf-sample-foundry
project: src/bat-python-maf
language: python
docker:
path: Dockerfile
Expand All @@ -53,7 +53,7 @@ services:
- browserautomation
- browser-automation-tools
kind: hosted
name: browser-automation-python-maf-sample-foundry
name: bat-python-maf
description: A Foundry-hosted browser automation agent sample for general browsing, web scraping, and form filling.
protocols:
- protocol: responses
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
requiredVersions:
extensions:
azure.ai.agents: '>=1.0.0-beta.4'
name: browser-automation-python-byo-sample-foundry
name: bat-python-byo
services:
ai-project:
host: azure.ai.project
Expand Down Expand Up @@ -35,7 +35,7 @@ services:
browser_automation_preview:
connection:
project_connection_id: '${AZURE_AI_PROJECT_ID}/connections/browserautomation'
browser-automation-python-byo-sample-foundry:
bat-python-byo:
host: azure.ai.agent
metadata:
tags:
Expand All @@ -44,7 +44,7 @@ services:
- Azure AI AgentServer
- Responses Protocol
- Browser Automation
project: src/browser-automation-python-byo-sample-foundry
project: src/bat-python-byo
language: python
docker:
path: Dockerfile
Expand All @@ -53,7 +53,7 @@ services:
- browserautomation
- browser-automation-tools
kind: hosted
name: browser-automation-python-byo-sample-foundry
name: bat-python-byo
description: A Foundry-hosted browser automation agent sample for general browsing, web scraping, and form filling.
protocols:
- protocol: responses
Expand Down
Loading