diff --git a/.workshop_instance/.workshop-state.json b/.workshop_instance/.workshop-state.json index 557d016..3f5e43d 100644 --- a/.workshop_instance/.workshop-state.json +++ b/.workshop_instance/.workshop-state.json @@ -1 +1,4 @@ -{"current_step": 0, "schema_version": 1} +{ + "current_step": 0, + "schema_version": 1 +} diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/.azdignore b/.workshop_instance/workshop_backups/reset-20260818184435/.azdignore new file mode 100644 index 0000000..4a74eab --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/.azdignore @@ -0,0 +1,3 @@ +agent.manifest.yaml +agent.yaml +.env.example diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/.dockerignore b/.workshop_instance/workshop_backups/reset-20260818184435/.dockerignore new file mode 100644 index 0000000..31ed562 --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/.dockerignore @@ -0,0 +1,7 @@ +.venv +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +.env diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/.gitkeep b/.workshop_instance/workshop_backups/reset-20260818184435/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/Dockerfile b/.workshop_instance/workshop_backups/reset-20260818184435/Dockerfile new file mode 100644 index 0000000..d2e7aa5 --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY . user_agent/ +WORKDIR /app/user_agent + +RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; else echo "No requirements.txt found"; fi + +EXPOSE 8088 + +CMD ["python", "main.py"] diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/STEP_README.md b/.workshop_instance/workshop_backups/reset-20260818184435/STEP_README.md new file mode 100644 index 0000000..c0e856b --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/STEP_README.md @@ -0,0 +1 @@ +You're now on step 01. The TravelBuddy agent files are present: `agent.yaml` and `agent.manifest.yaml` are ready to use, and you complete one small edit — write TravelBuddy's instructions in `main.py`. The `Dockerfile`, `.dockerignore`, and `.azdignore` that package and deploy the agent are also included (read-only) and explained in the Step 1 doc. The model you deployed in Step 0 is used at runtime via `AZURE_AI_MODEL_DEPLOYMENT_NAME`, so there's no model to provision here. Follow Step 1 in the root `README.md`. diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/agent.manifest.yaml b/.workshop_instance/workshop_backups/reset-20260818184435/agent.manifest.yaml new file mode 100644 index 0000000..ee3a9f8 --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/agent.manifest.yaml @@ -0,0 +1,42 @@ +# travel_assistant/agent.manifest.yaml — AgentManifest: a parameterized template +# that deployment tooling (azd ai agent init / Foundry Toolkit) reads to scaffold +# your hosted agent. It has top-level metadata (name, description, tags), a +# `template` block (the hosted-agent definition), and a `resources` list. +# This file is provided ready to use — skim it so you know what it declares. +# Reference (each field explained): +# https://learn.microsoft.com/azure/foundry/agents/concepts/agent-yaml-reference +# NOTE: `name` (and `template.name` below) must be a hardcoded literal here — do +# NOT use ${VAR} or {{VAR}}. `azd ai agent init` reads and validates the agent +# name as-is, BEFORE any substitution: it never expands ${VAR} (those resolve later +# at deploy/run from .env / Bicep outputs) and only substitutes {{VAR}} for values +# declared under a `parameters:` block, which happens AFTER the name is validated. +# The validator rejects `$`, `{`, and `}`, so a placeholder here fails with +# "invalid agent name". The runtime-configurable prefix still lives in agent.yaml's +# `name` and in the WORKSHOP_RESOURCE_PREFIX environment variable below. +name: travel-buddy +description: > + A basic Agent Framework travel assistant hosted by Foundry. +metadata: + tags: + - Agent Framework + - AI Agent Hosting + - Azure AI AgentServer + - Responses Protocol + - Travel Assistant +template: + name: travel-buddy + kind: hosted + protocols: + - protocol: responses + version: 2.0.0 + environment_variables: + - name: AZURE_AI_PROJECT_ENDPOINT + value: ${AZURE_AI_PROJECT_ENDPOINT} + - name: AZURE_AI_MODEL_DEPLOYMENT_NAME + value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME} + - name: WORKSHOP_RESOURCE_PREFIX + value: ${WORKSHOP_RESOURCE_PREFIX} +# No provisioned resources: you already deployed a model in setup (Step 0), and the +# agent selects it at runtime through the AZURE_AI_MODEL_DEPLOYMENT_NAME env var +# above — so we don't declare a `kind: model` resource for azd to create. +resources: [] diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/agent.yaml b/.workshop_instance/workshop_backups/reset-20260818184435/agent.yaml new file mode 100644 index 0000000..be6fccd --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/agent.yaml @@ -0,0 +1,25 @@ +# travel_assistant/agent.yaml — AgentDefinition (kind: hosted): the concrete +# runtime definition for your agent. It names the hosted agent, declares the +# `responses` protocol, sets a small CPU/memory shape, and lists the environment +# variables the container needs. This file is ready to run as-is — skim it so you +# understand each block. Reference: +# https://learn.microsoft.com/azure/foundry/agents/concepts/agent-yaml-reference +# yaml-language-server: $schema=https://raw.githubusercontent.com/microsoft/AgentSchema/refs/heads/main/schemas/v1.0/ContainerAgent.yaml +kind: hosted +name: ${WORKSHOP_RESOURCE_PREFIX}-travel-buddy +protocols: + - protocol: responses + version: 2.0.0 +resources: + cpu: "0.25" + memory: "0.5Gi" +environment_variables: + # These values come from your .env at run/deploy time — keep the ${...} refs as-is. + - name: AZURE_AI_PROJECT_ENDPOINT + value: ${AZURE_AI_PROJECT_ENDPOINT} + - name: AZURE_AI_MODEL_DEPLOYMENT_NAME + value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME} + # WORKSHOP_RESOURCE_PREFIX keeps your agent's name unique so it doesn't collide + # with other attendees deploying into a shared project. + - name: WORKSHOP_RESOURCE_PREFIX + value: ${WORKSHOP_RESOURCE_PREFIX} diff --git a/.workshop_instance/workshop_backups/reset-20260818184435/main.py b/.workshop_instance/workshop_backups/reset-20260818184435/main.py new file mode 100644 index 0000000..fbd6b85 --- /dev/null +++ b/.workshop_instance/workshop_backups/reset-20260818184435/main.py @@ -0,0 +1,38 @@ +# travel_assistant/main.py — Python entry point that hosts TravelBuddy: it creates +# the Foundry model client, defines the agent, and starts the Responses server. +# Complete the one TODO inside main() below. +import os + +from agent_framework import Agent +from agent_framework.foundry import FoundryChatClient +from agent_framework_foundry_hosting import ResponsesHostServer +from azure.identity import DefaultAzureCredential +from dotenv import load_dotenv + +load_dotenv(override=True) + + +def main() -> None: + # Foundry model client, built from your .env settings. + client = FoundryChatClient( + project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], + model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=DefaultAzureCredential(), + ) + + # TODO: write TravelBuddy's system instructions. Describe a friendly travel + # assistant that gives practical, concise trip-planning advice — local context, + # budget awareness, and safety-minded tips. + agent = Agent( + client=client, + name="travel-buddy", + instructions="TODO: write TravelBuddy's system instructions here.", + # History is managed by the hosting infrastructure, so don't store it server-side. + default_options={"store": False}, + ) + + ResponsesHostServer(agent).run() + + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index eb82ae4..e5fb36b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,33 @@ # Foundry hosted agents with Agent Framework — Travel Assistant Workshop +Built on the upstream [foundry-samples](https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents/agent-framework/responses). + +> **Progress:** Step `00` of `9` — **Setup** +> ▱▱▱▱▱▱▱▱▱▱ + -This repository is the **template source** for the workshop. It is not a live Step 00 instance. +
+Workshop map + +- **Step 00 — Setup** +- Step 01 — Basic hosted agent +- Step 02 — Function tools +- Step 03 — MCP integration +- Step 04 — Foundry Toolbox +- Step 05 — RAG (Azure AI Search) +- Step 06 — Skills +- Step 07 — Multi-agent +- Step 08 — Workflow (experimental) +- Step 09 — Memory (experimental) +- Step 99 — Cleanup + +
-After you create your own copy from this template, initialization runs automatically and your copy rewrites `README.md` to the real Step 00 content with progress/status and step navigation. +If something looks broken see [Troubleshooting](.workshop/docs/steps/00-intro.md#troubleshooting). + + +> **Welcome — start here.** Step 0 has no agent code. It introduces the workshop, walks you through creating your own copy of the repository, and gets your local toolchain ready so Step 1 can jump straight into building the first agent. ## What this workshop is about @@ -23,14 +46,219 @@ This is a **GitHub template repository**. You must create your own copy before d > 💡 **Already in your own copy?** If the green button at the top reads "Open" rather than "Use this template", you're already in a workshop instance. Continue below. +## Open your repo + +Pick one of the two paths — the rest of the workshop works the same either way. + +### Option A — GitHub Codespaces (recommended) + +In your new repo, click **Code → Codespaces → Create codespace on `main`**. The first build takes ~2 minutes; after that the included devcontainer has everything pre-installed: + +- Python 3.12, `az` CLI (with Bicep), `azd` CLI, `uv`, `git`, `gh`, Node.js, GitHub Copilot CLI (`copilot`) +- VS Code extensions: **Python**, **Pylance**, **Python Debugger**, **Foundry Toolkit**, **Bicep**, **Azure MCP Server (Azure Skills)**, **YAML**, **GitHub Pull Requests** +- The **Azure Skills** plugin for the GitHub Copilot CLI is installed (its Azure MCP + Foundry MCP tools require `az login` at use time) +- The post-create step has already created `.venv/` and installed workshop dependencies from `travel_assistant/requirements.txt` (or `.workshop/step_files/00/requirements.txt`) plus `.workshop/scripts/requirements.txt` + +> ⚠️ **Wait for "Initialize workshop" to finish first.** If you create the Codespace before that Action has applied step 0, the container falls back to `.workshop/step_files/00/requirements.txt` for workshop deps. After the Action turns green, rebuild the Codespace (Command Palette → **Codespaces: Rebuild Container**) so it picks up `travel_assistant/requirements.txt`. + +If you go this route, **skip the "Install the tools you'll need" section** below and jump straight to **"Set up your local environment (one-time)"**. +👉 Direct link: [Set up your local environment (one-time)](#set-up-your-local-environment-one-time) + +### Option B — Clone locally + +```bash +git clone https://github.com//.git +cd +``` + +Then continue with **"Install the tools you'll need"** below to install Python, `az`, `azd`, and (optionally) `uv` on your machine. + +## Install the tools you'll need + +> 💡 **In a Codespace?** Skip this section — the devcontainer already installed all of these. Jump to **"Set up your local environment (one-time)"**. + +**Prerequisites at a glance:** + +- **Azure subscription** with access to a Foundry project and a deployed model such as `gpt-4o-mini` or `gpt-4.1-mini`. See [Create a Foundry project](https://learn.microsoft.com/azure/ai-foundry/how-to/create-projects). +- **A role that lets you *use* the project** — **`Foundry User`** (formerly *Azure AI User*) on the Foundry project. This is the least-privilege role for *using* a project — prefer it over broader roles like Owner or Contributor. If you created the project you already have at least this. Some steps assign extra roles as needed (Step 5 adds Azure AI Search roles; Step 6 reuses `Foundry User` for the Skills API and grants it to the deployed agent's identity). +- **Python 3.10 or newer** (the devcontainer ships 3.12). +- **Azure CLI (`az`)** — used by `DefaultAzureCredential` for local auth. +- **Azure Developer CLI (`azd`)** with the [`microsoft.foundry` extension](https://learn.microsoft.com/azure/foundry/agents/how-to/install-cli-foundry-extensions) — used to scaffold, provision, run, and deploy hosted agents. +- **VS Code + [Foundry Toolkit](https://marketplace.visualstudio.com/items?itemName=ms-windows-ai-studio.windows-ai-studio)** *(optional, recommended)* — UI alternative to `azd` for running, debugging, and deploying hosted agents. +- **[GitHub Copilot CLI](https://github.com/github/copilot-cli) (`copilot`)** *(optional, recommended)* — AI-powered CLI assistant. Install with `npm install -g @github/copilot` (the devcontainer installs it automatically via the `copilot-cli` feature). +- **[Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/install)** *(optional, recommended)* — infrastructure-as-code language for the `azd`-generated `infra/`. Install the CLI with `az bicep install` and the [Bicep VS Code extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep) for language support. +- **[Azure Skills](https://github.com/microsoft/azure-skills)** *(optional, recommended)* — Azure skills and MCP server configurations for AI coding assistants. In VS Code install the [Azure MCP extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azure-mcp-server); for the GitHub Copilot CLI run `/plugin marketplace add microsoft/azure-skills` then `/plugin install azure@azure-skills`. Requires **Node.js 18+** (the MCP servers run via `npx`) and an authenticated `az login` for the Azure tools. +- **[`uv`](https://docs.astral.sh/uv/)** *(optional)* — a faster drop-in for `pip`/`venv`. Anywhere this workshop says `pip` or `python -m venv` you can use `uv pip` or `uv venv` instead. + +### Python 3.10+ + +- **Windows:** + ```powershell + winget install --id Python.Python.3.12 -e + ``` +- **macOS:** install from [python.org](https://www.python.org/downloads/) or `brew install python@3.12`. +- **Linux (Ubuntu/Debian):** + ```bash + sudo apt update && sudo apt install -y python3 python3-venv python3-pip + ``` + +Verify: + +```bash +python --version # or `python3 --version` +``` + +### Azure CLI (`az`) + +Full instructions: [Install the Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli). + +- **Windows:** + ```powershell + winget install --id Microsoft.AzureCLI -e + ``` +- **macOS:** + ```bash + brew update && brew install azure-cli + ``` +- **Linux (Ubuntu/Debian):** + ```bash + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + ``` + +Verify: + +```bash +az --version +``` + +### Azure Developer CLI (`azd`) + +Full instructions: [Install the Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd). + +- **Windows:** + ```powershell + winget install --id Microsoft.Azd -e + ``` +- **macOS:** + ```bash + brew tap azure/azd && brew install azd + ``` +- **Linux:** + ```bash + curl -fsSL https://aka.ms/install-azd.sh | bash + ``` + +Verify: + +```bash +azd version +``` + +### Optional: `uv` (faster Python package manager) + +Full instructions: [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/). + +- **Windows:** + ```powershell + winget install --id=astral-sh.uv -e + ``` +- **macOS / Linux:** + ```bash + curl -LsSf https://astral.sh/uv/install.sh | sh + ``` + +## Set up your local environment (one-time) + +> 💡 **In a Codespace?** The devcontainer already handled the venv and the `pip install` (substeps 3 and 5 below) — but you still need to do **substeps 1, 2, 4, and 6** (`az login`, `azd auth login` + ext install, copy `.env`, run preflight). Authentication and your `.env` can't be baked into the container. + +1. **Sign in to Azure**: + ```bash + az login + ``` + If needed, select a subscription: + ```bash + az account set -s + ``` +2. **Sign in to azd and install the Foundry extension** (one-time): + ```bash + azd auth login + azd ext install microsoft.foundry + ``` + This adds the `azd ai agent ...` subcommands used from Step 1 onward to scaffold `azure.yaml`/`infra/`, provision Foundry resources, run the agent locally, deploy, and invoke. `microsoft.foundry` is a meta-package that installs all the Foundry `azd ai` extensions — see [Install the Azure Developer CLI Foundry extensions](https://learn.microsoft.com/azure/foundry/agents/how-to/install-cli-foundry-extensions) for details. If you'd rather drive everything from VS Code, the **Foundry Toolkit** extension exposes the same operations as palette commands and a sidebar. If you have a Python virtual environment active (next substep), the Foundry Toolkit picks it up automatically when you press **F5** to debug. +3. **Create and activate a Python virtual environment.** + + Pick one of the two options below. Option A uses the Python stdlib `venv` module and matches the rest of the workshop; Option B uses [`uv`](https://docs.astral.sh/uv/), which is significantly faster but requires installing `uv` first (see above). Both options create the environment at `.venv/`, so the activation commands are the same. + + **Option A — `python -m venv` (default)** + ```bash + python -m venv .venv + ``` + + **Option B — `uv venv`** + ```bash + uv venv .venv + ``` + + Then activate it: + + - macOS / Linux: + ```bash + source .venv/bin/activate + ``` + - Windows (PowerShell): + ```powershell + .\.venv\Scripts\Activate.ps1 + ``` + + > 💡 **`uv` users:** activation is optional. `uv pip install`, `uv run`, and `uv` itself auto-discover `.venv/` in the current directory. If you skip activation, prefix later Python commands with `uv run` (e.g. `uv run python .workshop/scripts/preflight.py`) so they use the venv's interpreter. +4. **Configure environment**: setup and every later step read their configuration from a repo-root `.env` file, so create it **before** running preflight — copy the template, then fill it in: + + ```bash + # bash / zsh + cp .env.example .env + ``` + + ```powershell + # PowerShell + Copy-Item .env.example .env + ``` + + Then edit `.env`: + - `AZURE_AI_PROJECT_ENDPOINT` — from your Foundry project's overview page. + - `AZURE_AI_MODEL_DEPLOYMENT_NAME` — your deployment name, for example `gpt-4o-mini`. + - `WORKSHOP_RESOURCE_PREFIX` — this prefixes **every** Azure/Foundry resource the workshop creates (and is how `.workshop/scripts/cleanup.py` finds them later). If you're working solo in your own subscription, leave the default `foundry-workshop`. But if you **share the Foundry project or subscription** with other people running this workshop, change it to a value unique to you (for example `foundry-workshop-`) so your resource names don't **collide** with a teammate's — otherwise provisioning can fail on name conflicts, and cleanup could delete each other's resources. + - Leave step-specific variables empty for now; the README will tell you when to fill them. +5. **Install dependencies** (use the option that matches your venv choice above): + + **Option A — `pip`** + ```bash + pip install -r travel_assistant/requirements.txt + pip install -r .workshop/scripts/requirements.txt + ``` + + **Option B — `uv pip`** + ```bash + uv pip install -r travel_assistant/requirements.txt + uv pip install -r .workshop/scripts/requirements.txt + ``` +6. **Run preflight**: + ```bash + # If you activated .venv + python .workshop/scripts/preflight.py + + # If you're using uv without activation + uv run python .workshop/scripts/preflight.py + ``` + Fix any ❌. ⚠️ items are usually safe to ignore until later steps. + ## How the workshop works This workshop has one important contract: **`README.md` is the current step**. Each time you advance, the repository rewrites `README.md` so the next set of instructions appears in place. -- **Leaving Setup (Step 0):** click the **▶ Start the workshop** button at the bottom of that step. It opens the workshop's GitHub Action — click **Run workflow** to move to Step 1. -- **Every step after that:** there is no button. When you finish a step, **commit your work and push it to `main`**. The push triggers the **Advance workshop on push to main** Action, which loads the next step (each landed push advances one step). +- **Leaving Setup (this step):** click the **▶ Start the workshop** button at the bottom. It opens the workshop's GitHub Action — click **Run workflow**, and it moves you from Setup to Step 1. +- **Every step after that:** there is no button. When you finish a step, **commit the files you created and push them to `main`**. The push triggers the **Advance workshop on push to main** Action, which loads the next step. Each landed push advances by exactly **one** step, so push once — when the step is done. - After the Action finishes, run **`git pull`** locally. If you are reading in the GitHub UI, refresh the page to see the new `README.md`. -- Advancing lays the next step's canonical starter files **on top of** your `travel_assistant/` directory. Your previous edits are saved to `.workshop_instance/workshop_backups/step-/` in the same commit. +- Advancing lays the next step's canonical files **on top of** your `travel_assistant/` directory. Files from earlier steps that the next step doesn't touch are kept as-is — nothing is deleted. Files the next step ships are refreshed to that step's version, and your current edits are first saved to `.workshop_instance/workshop_backups/step-/` in the same commit so you can recover your own wording. ## What you'll build @@ -46,13 +274,11 @@ This workshop has one important contract: **`README.md` is the current step**. E ## When you're ready -Initialization is automatic in your own copy. +Make sure `python .workshop/scripts/preflight.py` is green (or `uv run python .workshop/scripts/preflight.py` if you're using `uv` without activation), then click the button below to open the workflow — and click **Run workflow** in the dialog that appears: -- **Using GitHub Actions:** create your repo from this template and push once. The **Initialize workshop** workflow runs automatically. -- **If it didn't run:** open **Actions → Initialize workshop → Run workflow** manually. -- **Working fully locally (no Actions):** run `python .workshop/scripts/advance_step.py --init` from the repository root. +[![▶ Start the workshop](https://img.shields.io/badge/%E2%96%B6_Start_the_workshop-Step_01-2ea44f?style=for-the-badge)](https://github.com/frostbyte74/foundry-hosted-agents-workshop/actions/workflows/start-workshop.yml) -After initialization completes, refresh/pull. The README switches to Step 00 with the **Start the workshop** button; from Step 1 on you advance by pushing to `main`. +Click **Run workflow** to move from Setup to Step 1. Pull after the action completes. From Step 1 onward you advance by committing your work and pushing to `main` — there is no button. With setup already done, Step 1 jumps straight into authoring `agent.yaml`, `agent.manifest.yaml`, and `main.py` for your first hosted TravelBuddy agent. ## Working fully locally (no GitHub Actions) @@ -76,18 +302,40 @@ python .workshop/scripts/advance_step.py --reset --auto-commit Your previous `travel_assistant/` is preserved under `.workshop_instance/workshop_backups/reset-/`. +**Pull the latest workshop machinery (without advancing):** + +```bash +python .workshop/scripts/sync_template.py --auto-commit # add --push to push too +``` + +Occasionally the upstream template ships fixes to the workshop machinery (the authoring material under `.workshop/` and the GitHub configuration under `.github/`). This pulls those into your instance **without moving to the next step** and without touching your `travel_assistant/`, your `.workshop_instance/` state, `README.md`, or `.env`. The commit carries a `[skip-advance]` marker, so pushing it never advances you. A local run also refreshes `.github/workflows/`; the automated CI sync deliberately skips workflow files so it stays tokenless (no Personal Access Token required). + +**Reset the current step (re-lay its clean starter files):** + +```bash +python .workshop/scripts/advance_step.py --reset-current --auto-commit +``` + +Re-lays the **current** step's clean starter files and re-renders its `README.md`, staying on the current step — unlike `--reset`, which returns you to step 0. Your previous `travel_assistant/` is backed up under `.workshop_instance/workshop_backups/reset-current--/` first. Pair it with a sync when you want the current step's delivery refreshed too: **sync first, then reset the current step**. (If you sync just before advancing, you don't need this — advancing already lays down fresh files.) + **Re-run preflight:** ```bash +# If you activated .venv python .workshop/scripts/preflight.py + +# If you're using uv without activation +uv run python .workshop/scripts/preflight.py ``` -**Shortcuts (optional):** the repo ships a `Makefile` with three aliases: +**Shortcuts (optional):** the repo ships a `Makefile` with these aliases: ```bash -make advance # advance to the next step (auto-commits workshop paths) -make reset # reset to step 0 (auto-commits workshop paths) -make preflight # run environment checks +make advance # advance to the next step (auto-commits workshop paths) +make reset # reset to step 0 (auto-commits workshop paths) +make reset-current # re-lay the current step's clean files (auto-commits) +make preflight # run environment checks +make sync-template # pull latest .workshop/ + .github/ from the template ``` When `make` is not available (e.g. on a clean Windows install), just run the equivalent `python .workshop/scripts/...` commands above. @@ -121,7 +369,7 @@ This workshop does not use marketplace actions for advancing steps; it uses the ### "My push didn't advance the step" -Auto-advance only runs for pushes to `main` in your own (non-template) repo, and it skips pushes that only changed workshop bookkeeping such as `.workshop_instance/.workshop-state.json`. Check the **Actions** tab for the **Advance workshop on push to main** run. If it was skipped, make sure you pushed a real change to `main` and that the previous advance already finished. If several quick pushes collapsed into a single advance, that's expected — each *landed* push advances one step. +Auto-advance only runs for pushes to `main` in your own (non-template) repo, and it skips a few kinds of push that aren't step progress: pushes that only changed workshop bookkeeping such as `.workshop_instance/.workshop-state.json`, pushes whose commit carries a `[skip-advance]` marker (what a template sync adds), and pushes that changed **only** workshop machinery or platform files (`.github/`, `.workshop/`, `Makefile`, `.devcontainer/`, `README.md`, …) and never your delivery (`travel_assistant/` or its sibling folders like `travel_toolbox/`). That last case means you can pull the latest machinery from upstream and push it — even manually, without the `[skip-advance]` marker — without being bumped to the next step. Check the **Actions** tab for the **Advance workshop on push to main** run. If it was skipped, make sure your push touched a delivery file and that the previous advance already finished. If several quick pushes collapsed into a single advance, that's expected — each *landed* push advances one step. ### "Codespace can't reach my Foundry project" @@ -139,12 +387,28 @@ They were backed up to `.workshop_instance/workshop_backups/step-/` in When you finish, or if you want to abandon the workshop, step 99 runs `python .workshop/scripts/cleanup.py --apply` to delete all workshop-created Azure resources. The script only touches resources whose names start with `WORKSHOP_RESOURCE_PREFIX`. If you used `azd` to provision hosted-agent resources, you can alternatively run `azd down` to tear down the resources `azd` created. +## Solution + +This step has no code to write — it's intro and setup of your repo from the template. + + --- -**Initialization is automatic:** in your own copy, push once and let **Initialize workshop** run. + + + +[![▶ Start the workshop](https://img.shields.io/badge/%E2%96%B6_Start_the_workshop-Step_01-2ea44f?style=for-the-badge)](https://github.com/frostbyte74/foundry-hosted-agents-workshop/actions/workflows/start-workshop.yml) + +**Next:** Step 01 — Basic hosted agent + +Click the badge to open **Start the workshop**, then click **Run workflow**. It moves you from Setup to Step 01. Pull after the action completes. + +Or open **Actions → Start the workshop → Run workflow** manually. + +From Step 01 onward you don't click a button to advance — you just **commit your work and push to `main`**, and the next step loads automatically. -**If needed:** run **Actions → Initialize workshop** manually. +> 💡 **Button returns 404?** Your repo's one-time **Initialize workshop** Action hasn't run yet. Open the **Actions** tab, run **Initialize workshop → Run workflow**, then refresh this page. -**Prefer local only?** Run `python .workshop/scripts/advance_step.py --init`. +> **Prefer to stay local?** Run `python .workshop/scripts/advance_step.py --expected-current-step 0 --auto-commit` (or `make advance`) instead of clicking the button. See [Working fully locally](.workshop/docs/steps/00-intro.md#5-working-fully-locally-no-github-actions) for the full local flow. -Then refresh/pull: your README will be rewritten to Step 00 and from there you can advance normally. +Made a mistake? Use the [Reset workshop](https://github.com/frostbyte74/foundry-hosted-agents-workshop/actions/workflows/reset-workshop.yml) workflow, or run `python .workshop/scripts/advance_step.py --reset --auto-commit` locally. diff --git a/travel_assistant/STEP_README.md b/travel_assistant/STEP_README.md new file mode 100644 index 0000000..e94bd97 --- /dev/null +++ b/travel_assistant/STEP_README.md @@ -0,0 +1,3 @@ +You're now on step 00. This minimal snapshot sets up the workshop requirements; advance to step 01 to complete the TravelBuddy scaffold. + +The devcontainer for this workshop also provisions the recommended tooling: the **GitHub Copilot CLI** (`copilot`), the **Bicep** CLI + VS Code extension, and the **Azure Skills** plugin / **Azure MCP Server** VS Code extension. See `.workshop/docs/steps/00-intro.md` for how to install them locally. diff --git a/travel_assistant/requirements.txt b/travel_assistant/requirements.txt new file mode 100644 index 0000000..85a926b --- /dev/null +++ b/travel_assistant/requirements.txt @@ -0,0 +1,15 @@ +# ---- Agent Framework with Microsoft Foundry ---- +agent-framework-foundry +agent-framework-foundry-hosting>=1.0.0a260630 + +# ---- Step 7: Multi-agent orchestration (HandoffBuilder) ---- +agent-framework-orchestrations + +# ---- Local Debugging in Foundry Toolkit ---- +debugpy + +# ---- RAG (Azure AI Search) ---- +agent-framework-azure-ai-search + +# ---- Step 6: Skills ---- +azure-ai-projects \ No newline at end of file