> ## Documentation Index
> Fetch the complete documentation index at: https://hobbyist-e43fa225.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create hosted agent workflows in the Microsoft Foundry Toolkit for Visual Studio Code extension

> Create, test, and deploy hosted agent workflows in Foundry Agent Service by using the Microsoft Foundry Toolkit for Visual Studio Code extension.

export const ZonePivot = ({group, options = [], defaultValue, label = "Choose an experience"}) => {
  const values = options.map(option => option.id);
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  const publishPivotChange = value => {
    if (typeof window === "undefined") return;
    window.dispatchEvent(new CustomEvent("foundry-zone-pivot-change", {
      detail: {
        group,
        value
      }
    }));
  };
  const syncTableOfContents = () => {
    if (typeof window === "undefined") return;
    window.requestAnimationFrame(() => {
      const toc = document.getElementById("table-of-contents-content");
      if (!toc) return;
      const links = Array.from(toc.querySelectorAll('a[href^="#"]'));
      for (const link of links) {
        const item = link.closest("li");
        const rawId = link.getAttribute("href")?.slice(1);
        if (!item || !rawId) continue;
        let id = rawId;
        try {
          id = decodeURIComponent(rawId);
        } catch {}
        item.style.display = document.getElementById(id) ? "" : "none";
      }
    });
  };
  useEffect(() => {
    const resolvedPivot = resolvePivot();
    setActivePivot(resolvedPivot);
    publishPivotChange(resolvedPivot);
    window.setTimeout(syncTableOfContents, 0);
  }, [group, defaultValue, values.join("|"), optionKey]);
  const selectPivot = value => {
    setActivePivot(value);
    if (typeof window !== "undefined") {
      try {
        window.localStorage.setItem(`foundry-zone-pivot:${group}`, value);
      } catch {}
      const url = new URL(window.location.href);
      const current = url.searchParams.get("pivots");
      const preserved = current ? current.split(",").map(id => id.trim()).filter(id => id && !values.includes(id)) : [];
      url.searchParams.set("pivots", [...preserved, value].join(","));
      window.history.replaceState(null, "", `${url.pathname}${url.search}${url.hash}`);
    }
    publishPivotChange(value);
    window.setTimeout(syncTableOfContents, 0);
  };
  if (options.length < 2) return null;
  return <div className="not-prose my-6 border-b border-slate-200 pb-3 dark:border-slate-800">
      <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
        {label}
      </div>
      <div className="flex flex-wrap gap-2" role="tablist" aria-label={label}>
        {options.map(option => {
    const selected = option.id === activePivot;
    return <button key={option.id} type="button" role="tab" aria-selected={selected} onClick={() => selectPivot(option.id)} className={`rounded-md border px-3 py-1.5 text-sm font-medium transition ${selected ? "border-slate-900 bg-slate-900 text-white shadow-sm dark:border-slate-100 dark:bg-slate-100 dark:text-slate-950" : "border-slate-200 bg-white text-slate-700 hover:border-slate-400 hover:text-slate-950 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-200 dark:hover:border-slate-500"}`}>
              {option.title}
            </button>;
  })}
      </div>
    </div>;
};

export const ZoneContent = ({group, value, options = [], values = [], defaultValue, children}) => {
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  useEffect(() => {
    setActivePivot(resolvePivot());
  }, [group, defaultValue, values.join("|"), optionKey]);
  useEffect(() => {
    const onPivotChange = event => {
      if (event.detail?.group === group && values.includes(event.detail.value)) {
        setActivePivot(event.detail.value);
      }
    };
    window.addEventListener("foundry-zone-pivot-change", onPivotChange);
    return () => window.removeEventListener("foundry-zone-pivot-change", onPivotChange);
  }, [group, values.join("|")]);
  if (activePivot !== value) return null;
  return <>{children}</>;
};

Create, test, and deploy [hosted Foundry Agent workflows](/agents/hosted-agents) by using the [Microsoft Foundry Toolkit for Visual Studio Code extension](https://aka.ms/foundrytk). The toolkit supports agent creation from templates, local testing and debugging with the Agent Inspector for visualization and trace support, and direct deployment to Foundry Agent Service from VS Code. Hosted workflows let multiple agents collaborate in sequence, each with its own model, tools, and instructions.

Before you start, [build an agent in Foundry Agent Service](https://learn.microsoft.com/azure/ai-foundry/how-to/develop/vs-code-agents) by using the extension. You can then add hosted workflows to that agent.

This article covers creating a workflow project, running it locally, visualizing the execution, and deploying it to your Foundry workspace.

## Prerequisites

* A Foundry project with a deployed model, or an Azure OpenAI resource.
* The [Microsoft Foundry Toolkit for Visual Studio Code extension](https://aka.ms/foundrytk) installed.
* The project's managed identity with the [Foundry User](https://aka.ms/foundry-ext-project-role) and [AcrPull](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles/containers#acrpull) roles assigned. Also assign the `acrPull` role to the managed identity of the Foundry project where you plan to deploy the Hosted agent.

<Info />

> The Foundry RBAC roles were recently renamed. **Foundry User**, **Foundry Owner**, **Foundry Account Owner**, and **Foundry Project Manager** were previously named Azure AI User, Azure AI Owner, Azure AI Account Owner, and Azure AI Project Manager. You might still see the previous names in some places while the rename rolls out. The role IDs and core permissions are unchanged by the rename.

* A [supported region](/agents/hosted-agents#region-availability) for Hosted agents.

<ZonePivot group="csharp__python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} defaultValue="python" />

<ZoneContent group="csharp__python" value="python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  * Python 3.13 or higher.
</ZoneContent>

<ZoneContent group="csharp__python" value="csharp" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  * [.NET 10 SDK](https://dotnet.microsoft.com/download) or later.
</ZoneContent>

## Create a hosted agent workflow

You can use the Microsoft Foundry Toolkit for Visual Studio Code extension to create Hosted agent workflows. A Hosted agent workflow is a sequence of agents that work together to accomplish a task. Each agent in the workflow can have its own model, tools, and instructions.

1. Open the command palette (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>).

2. Run this command: `>Foundry Toolkit: Create a New Hosted Agent`.

3. Select a programming language

4. Choose a framework, either Copilot SDK, Microsoft Agent Framework, or Bring your own.

5. Choose a protocol, either Responses API or Invocations API.

6. Choose a template from the list.

7. Select the "Next" button.

8. Select a folder where you want to save your new Hosted Agent.

9. For Environment Setup, selecting "Skip for now" will skip Foundry project and model setup, which requires you to manually configure them in the code later. Selecting "Configure with Microsoft Foundry" will auto-populate your project and model information with the existing Foundry Project.

The files for your Hosted agent project are generated in your selected folder based on the framework, template and language you selected to get you started. You can remove or modify that code as needed.

### Install dependencies

Install the required dependencies for your Hosted agent project. The dependencies vary based on the programming language that you selected when you created the project.

<ZoneContent group="csharp__python" value="python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  1. Create virtual environment.

     ```bash theme={null}
      python -m venv .venv
     ```

  2. Activate the virtual environment.

     ```bash theme={null}
     # PowerShell
     ./.venv/Scripts/Activate.ps1

     # Windows cmd
     .venv\Scripts\activate.bat

     # Unix/MacOS
     source .venv/bin/activate
     ```

  3. Install the required packages:

     ```bash theme={null}
     pip install -r requirements.txt
     ```
</ZoneContent>

<ZoneContent group="csharp__python" value="csharp" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  1. Go to your project directory and run this command to get the necessary NuGet packages:

     ```bash theme={null}
     dotnet restore
     ```
</ZoneContent>

## Run your hosted workflow locally

<ZoneContent group="csharp__python" value="python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  The sample workflow project creates an .env file with the necessary environment variables. Create or update the .env file with your Foundry credentials:

  ```
  FOUNDRY_PROJECT_ENDPOINT=https://<your-resource-name>.services.ai.azure.com/api/projects/<your-project-name>

  FOUNDRY_MODEL_NAME=<your-model-deployment-name>
  ```

  <Info>
    Never commit the `.env` file to version control. Add it to your `.gitignore` file.
  </Info>

  ### Authenticate your hosted agent

  The Hosted agent sample authenticates using [DefaultAzureCredential](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential). Configure your development environment to provide credentials via one of the supported sources, for example:

  * Azure CLI (`az login`)
  * Visual Studio Code account sign-in
  * Visual Studio account sign-in
  * Environment variables for a service principal (AZURE\_TENANT\_ID, AZURE\_CLIENT\_ID, AZURE\_CLIENT\_SECRET)

  Confirm authentication locally by running either the Azure CLI `az account show` or `az account get-access-token` commands before running the sample.

  You can run the Hosted agent in interactive mode or container mode.

  ### Run your hosted agent in the Agent Inspector

  Press **F5** to start the local HTTP server with debugging enabled. The Foundry Toolkit Agent Inspector opens for interactive testing, and you can set breakpoints in your code.

  To run the server without debugging:

  ```bash theme={null}
  python main.py
  ```

  The agent listens on `http://localhost:8088/`. Send a test prompt with curl (or any HTTP client):

  ```bash theme={null}
  curl -sS -H "Content-Type: application/json" -X POST http://localhost:8088/responses \
      -d '{"input": "Write a haiku about deploying cloud applications.", "stream": false}'
  ```
</ZoneContent>

<ZoneContent group="csharp__python" value="csharp" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  The sample workflow project creates an .env file with the necessary environment variables. Create or update the .env file with your Foundry credentials:

  1. Set up your environment variables based on your operating system:

     #### [Windows (PowerShell)](#tab/windows-powershell)

     ```powershell theme={null}
     $env:FOUNDRY_PROJECT_ENDPOINT="https://<your-resource-name>.services.ai.azure.com/api/projects/<your-project-name>"
     $env:FOUNDRY_MODEL_NAME="your-deployment-name"
     ```

     #### [Windows (command prompt)](#tab/windows-command-prompt)

     ```dos theme={null}
     set FOUNDRY_PROJECT_ENDPOINT=https://your-resource-name.openai.azure.com/
     set FOUNDRY_MODEL_NAME=your-deployment-name
     ```

     #### [macOS/Linux (Bash)](#tab/macos-linux-bash)

     ```bash theme={null}
     export FOUNDRY_PROJECT_ENDPOINT="https://your-resource-name.openai.azure.com/"
     export FOUNDRY_MODEL_NAME="your-deployment-name"
     ```

     ***

  ### Authenticate your hosted agent

  The Hosted agent sample authenticates using [DefaultAzureCredential](https://learn.microsoft.com/dotnet/azure/sdk/authentication/credential-chains). Configure your development environment to provide credentials via one of the supported sources, for example:

  * Azure CLI (`az login`)
  * Visual Studio Code account sign-in
  * Visual Studio account sign-in
  * Environment variables for a service principal (AZURE\_TENANT\_ID, AZURE\_CLIENT\_ID, AZURE\_CLIENT\_SECRET)

  Confirm authentication locally by running either the Azure CLI `az account show` or `az account get-access-token` commands before running the sample.

  You can run the Hosted agent in interactive mode or container mode.

  ### Run your hosted agent in interactive mode

  Run the Hosted agent directly for development and testing:

  ```bash theme={null}
  dotnet restore
  dotnet build
  dotnet run
  ```

  ### Run your hosted agent in container mode

  <Tip>
    Open the local playground before starting the container agent to ensure the visualization functions correctly.
  </Tip>

  To run the agent in container mode:

  1. Open the Visual Studio Code Command Palette and execute the `Foundry Toolkit: Open Container Agent Playground Locally` command.
  2. Use the following command to initialize the containerized Hosted agent.
     ```bash theme={null}
     dotnet restore
     dotnet build
     dotnet run
     ```
  3. Submit a request to the agent through the playground interface. For example, enter a prompt such as: "Create a slogan for a new electric SUV that's affordable and fun to drive."
  4. Review the agent's response in the playground interface.

  ## Visualize hosted agent workflow execution

  The Microsoft Foundry Toolkit for Visual Studio Code extension provides a real-time execution graph that shows how agents in your workflow interact and collaborate. Enable observability in your project to use this visualization.

  Add the following reference to your csproj file:

  ```xml theme={null}
  <ItemGroup>
      <PackageReference Include="OpenTelemetry" Version="1.12.0" />
      <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
      <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
      <PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.10" />
  </ItemGroup>
  ```

  Update your program to include the following code snippet:

  ```CSharp theme={null}
  using System.Diagnostics;
  using OpenTelemetry;
  using OpenTelemetry.Logs;
  using OpenTelemetry.Metrics;
  using OpenTelemetry.Resources;
  using OpenTelemetry.Trace;

  var otlpEndpoint =
      Environment.GetEnvironmentVariable("OTLP_ENDPOINT") ?? "http://localhost:4319";

  var resourceBuilder = OpenTelemetry
      .Resources.ResourceBuilder.CreateDefault()
      .AddService("WorkflowSample");

  var s_tracerProvider = OpenTelemetry
      .Sdk.CreateTracerProviderBuilder()
      .SetResourceBuilder(resourceBuilder)
      .AddSource("Microsoft.Agents.AI.*") // All agent framework sources
      .SetSampler(new AlwaysOnSampler()) // Ensure all traces are sampled
      .AddOtlpExporter(options =>
      {
          options.Endpoint = new Uri(otlpEndpoint);
          options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
      })
      .Build();
  ```

  ### Monitor and visualize your hosted agent workflow

  To monitor and visualize your Hosted agent workflow execution in real time:

  1. Open the command palette (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>).

  2. Run this command: `>Foundry Toolkit: Open Visualizer for Hosted Agents`.

  A new tab opens in VS Code to display the execution graph. The visualization updates itself automatically as your workflow progresses, to show the flow between agents and their interactions.

  #### Port conflicts

  For port conflicts, you can change the visualization port by setting it in the Microsoft Foundry Toolkit for Visual Studio Code extension settings. To do that, follow these steps:

  1. In the left sidebar of VS Code, select the gear icon to open the settings menu.
  2. Select `Extensions` > `Microsoft Foundry Configuration`.
  3. Locate the `Hosted Agent Visualization Port` setting and change it to an available port number.
  4. Restart VS Code to apply the changes.

  #### Change port in code

  For any port conflicts, change the visualization port by setting the `FOUNDRY_OTLP_PORT` environment variable. Update the OTLP endpoint in your program accordingly.

  For example, to change the port to 4318, use this command:

  ```powershell theme={null}
    $env:FOUNDRY_OTLP_PORT="4318"
  ```

  In your program, update the OTLP endpoint to use the new port number:

  ```CSharp theme={null}
  var otlpEndpoint =
      Environment.GetEnvironmentVariable("OTLP_ENDPOINT") ?? "http://localhost:4318";
  ```
</ZoneContent>

## Deploy the hosted agent

After testing your Hosted agent locally, deploy it to your Foundry workspace so other team members and applications can use it.

<Info>
  Make sure you give the necessary permissions to deploy Hosted agents in your Foundry workspace, as stated in the [Prerequisites](#prerequisites). You might need to work with your Azure administrator to get the required role assignments.
</Info>

<ZoneContent group="csharp__python" value="python" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  1. Open the Command Palette and select **Foundry Toolkit: Deploy Hosted Agent**. A deployment webview will open.
  2. For "Deployment Method", select **Code** or **Container**.
  3. If deploying with "Code", for "Package Mode", select **Remote** or **Local**.
  4. If deploying with "Container", select either **Default ACR**, **Custom ACR**, or **Customer ACR Image**.
  5. The "Agent Name" should auto-populate.
  6. Select the "Next" button.
  7. This "Review and Deploy" page should all auto-populate.
  8. Select the "Deploy" button.
  9. Open the Visual Studio Code Command Palette and run the `Foundry Toolkit: Deploy Hosted Agent` command.
</ZoneContent>

<ZoneContent group="csharp__python" value="csharp" options={[{"id": "python", "title": "Python"}, {"id": "csharp", "title": "C#"}]} values={["python", "csharp"]} defaultValue="python">
  1. Open the Visual Studio Code Command Palette and run the `Foundry Toolkit: Deploy Hosted Agent` command.
  2. For "Deployment Method", select **Code** or **Container**.
  3. If deploying with "Code", for "Package Mode", select **Remote** or **Local**.
  4. If deploying with "Container", select either **Default ACR**, **Custom ACR**, or **Customer ACR Image**.
  5. The "Agent Name" should auto-populate.
  6. Select the "Next" button.
  7. This "Review and Deploy" page should all auto-populate.
  8. Select the "Deploy" button.
</ZoneContent>

## Related content

* [Hosted agent concepts](/agents/hosted-agents)
* [Build an agent in Foundry Agent Service](https://learn.microsoft.com/azure/ai-foundry/how-to/develop/vs-code-agents)
* [Agent applications in Microsoft Foundry](/agents/agent-applications)
