{"owner":"microsoft","repo":"generative-ai-for-beginners","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":6595,"categories":["anthropic-skill","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":[".github/skills/azure-openai-to-responses/SKILL.md",".github/skills/azure-openai-to-responses/references/cheat-sheet.md","AGENTS.md"],"skills":{".github/skills/azure-openai-to-responses/SKILL.md":"---\nname: azure-openai-to-responses\ndescription: >-\n  Migrate Python apps from Azure OpenAI Chat Completions to the Responses API.\n  Covers AzureOpenAI/AsyncAzureOpenAI client migration to the v1 endpoint,\n  streaming, tools, structured output, multi-turn, EntraID auth, and model\n  compatibility checks. Python-focused, Azure OpenAI-specific.\n  USE FOR: migrate to responses API, switch from chat completions, openai responses,\n  upgrade openai SDK, responses API migration, move from completions to responses,\n  gpt-5 migration, azure openai python migration, chat completions to responses,\n  AzureOpenAI to OpenAI client, python azure openai upgrade.\n  DO NOT USE FOR: building new apps from scratch (start with responses directly),\n  Node/TypeScript/C#/Java/Go migrations (this skill is Python-only),\n  Azure infrastructure setup (use azure-prepare), deploying models (use microsoft-foundry).\nlicense: MIT\nsource: https://github.com/Azure-Samples/azure-openai-to-responses\n---\n\n# Migrate Python Apps from Azure OpenAI Chat Completions to Responses API\n\n> **AUTHORITATIVE GUIDANCE — FOLLOW EXACTLY**\n>\n> This skill migrates Python codebases using Azure OpenAI Chat Completions\n> to the unified Responses API. Follow these instructions precisely.\n> Do not improvise parameter mappings or invent API shapes.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Triggers\n\nActivate this skill when the user wants to:\n- Migrate a Python app from Azure OpenAI Chat Completions to Responses API\n- Upgrade Python OpenAI SDK usage to the latest API shape against Azure OpenAI\n- Prepare Python code for GPT-5 or newer models that require Responses on Azure\n- Switch from `AzureOpenAI`/`AsyncAzureOpenAI` to standard `OpenAI`/`AsyncOpenAI` client with the v1 endpoint\n- Fix deprecation warnings related to `AzureOpenAI` constructors or `api_version`\n\n## Why migrate\n\nGPT-5 and newer models require the Responses API. The new `/openai/v1/` endpoint\nuses the standard `OpenAI()` client instead of `AzureOpenAI()`, requires no\n`api_version` parameter, and works identically across OpenAI and Azure OpenAI.\n\n## What changes\n\n| Chat Completions (before) | Responses API (after) |\n| --- | --- |\n| `AzureOpenAI()` / `AsyncAzureOpenAI()` | `OpenAI(base_url=...)` / `AsyncOpenAI(base_url=...)` |\n| `azure_endpoint=...` | `base_url=f\"{endpoint.rstrip('/')}/openai/v1/\"` |\n| `api_version=\"2024-...\"` | Remove entirely — `/openai/v1/` is stable |\n| `azure_ad_token_provider=...` | `api_key=token_provider` |\n| `client.chat.completions.create(messages=...)` | `client.responses.create(input=...)` |\n| `resp.choices[0].message.content` | `resp.output_text` |\n| `max_tokens` | `max_output_tokens` (min 16 on Azure) |\n| `response_format` | `text={\"format\": {...}}` |\n| `seed` | **Remove** (not supported) |\n| tools nested `{\"type\":\"function\",\"function\":{...}}` | flat `{\"type\":\"function\",\"name\":...}` |\n| tool result `{\"role\":\"tool\",\"tool_call_id\":...}` | `{\"type\":\"function_call_output\",\"call_id\":...,\"output\":...}` |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` + `{\"url\": \"...\"}` | `content[].type: \"input_image\"` + flat `\"image_url\": \"...\"` |\n| streaming `chunk.choices[0].delta.content` | `event.type == \"response.output_text.delta\"` → `event.delta` |\n\n## Model compatibility — CHECK FIRST\n\nVerify the deployed model supports the Responses API before migrating. GPT-4o and\nGPT-4 support Responses for basic text/chat/streaming/tools but not all features.\nNewer models (gpt-4.1+, gpt-5.x) have full support. **GitHub Models\n(`models.github.ai`, `models.inference.ai.azure.com`) do NOT support the Responses\nAPI** — remove those code paths and switch to Azure OpenAI, OpenAI, or a compatible\nlocal endpoint.\n\nSmoke test:\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"ping\",\n    max_output_tokens=50,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Step 0: Client migration (prerequisite)\n\n`AzureOpenAI`/`AsyncAzureOpenAI` constructors are deprecated in `openai>=1.108.1`.\n\nBefore:\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\n```\n\nAfter:\n```python\nfrom openai import OpenAI\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\nCleanup: remove `api_version` args, remove `AZURE_OPENAI_API_VERSION` /\n`AZURE_OPENAI_VERSION` from `.env`/infra, rename `AZURE_OPENAI_CLIENT_ID` →\n`AZURE_CLIENT_ID`, ensure `openai>=1.108.1`.\n\n## Step 1: Detect legacy call sites\n\n```bash\nrg \"chat\\.completions\\.create\"        # legacy API calls\nrg \"ChatCompletion\\.create|Completion\\.create\"\nrg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"  # deprecated constructors\nrg \"choices\\[0\\]\\.message\\.content\"    # response access\nrg \"choices\\[0\\]\\.delta\\.content\"      # streaming access\nrg \"max_tokens\\b\"                      # rename to max_output_tokens\nrg \"['\\\"]seed['\\\"]\"                    # remove entirely\nrg \"response_format\"                   # → text.format\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"  # GitHub Models: remove\n```\n\n## Step 2: Apply migration\n\n- `client.chat.completions.create(messages=...)` → `client.responses.create(input=...)`\n- `resp.choices[0].message.content` → `resp.output_text`\n- `max_tokens` → `max_output_tokens` (min 16); remove `seed`\n- `response_format` → `text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`\n- Set `store=False` on every request (client-managed state)\n- Streaming: iterate events, handle `event.type == \"response.output_text.delta\"` (use `event.delta`) and `response.completed`\n- Tools: flat format, `tool_choice`, return results as `function_call_output` items; append `response.output` items for round-trips\n- Multi-turn: maintain conversation in an `input` array, or use `previous_response_id` (requires `store=True`)\n- Reasoning models (o-series, GPT-5): `max_completion_tokens` → `max_output_tokens` (4096+), `reasoning_effort` → `reasoning={\"effort\": ...}`, omit `temperature`/`top_p` (GPT-5 rejects `temperature` outright; to vary output use a non-reasoning model like `Llama-3.3-70B-Instruct` via Foundry Models)\n\n## Acceptance criteria (all must pass)\n\n- Zero matches for `chat.completions.create|ChatCompletion.create|Completion.create`\n- Zero matches for `AzureOpenAI(|AsyncAzureOpenAI(` — all use `OpenAI`/`AsyncOpenAI` + v1 endpoint\n- Zero matches for `models.github.ai|models.inference.ai.azure`\n- Zero matches for `choices[0]` — all access uses `resp.output_text` / Responses schema\n- No top-level `response_format`; structured output uses `text={\"format\": {...}}`\n- `openai>=1.108.1` in requirements; `store=False` on every call; no `api_version` in client construction\n- Tests updated (mocks use `kwargs.get(\"input\")`, snapshots use Responses shape); `pytest` passes\n\nSee [references/cheat-sheet.md](./references/cheat-sheet.md) for complete before/after code examples.\n\n## References\n\n- [Azure OpenAI Responses API docs](https://learn.microsoft.com/azure/ai-foundry/openai/how-to/responses)\n- [OpenAI Responses API reference](https://platform.openai.com/docs/api-reference/responses)\n- [Source skill: Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses)\n",".github/skills/azure-openai-to-responses/references/cheat-sheet.md":"# Responses API Cheat Sheet (Python + Azure OpenAI)\n\n> All snippets assume `deployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]` and `client` is already initialized.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Client setup — API key\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\n## Client setup — EntraID (recommended)\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nfrom openai import OpenAI\n\ntoken_provider = get_bearer_token_provider(\n    DefaultAzureCredential(),\n    \"https://cognitiveservices.azure.com/.default\",\n)\nclient = OpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,\n)\n```\n\n## Async client setup\n\n```python\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,   # or api_key=os.environ[\"AZURE_OPENAI_API_KEY\"]\n)\n```\n\n## Basic request\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Full sync migration — before/after\n\nBefore (Chat Completions):\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\nresp = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n    max_tokens=500,\n)\nprint(resp.choices[0].message.content)\n```\n\nAfter (Responses API):\n```python\nfrom openai import OpenAI\ndeployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Multi-turn conversation\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a helpful coding assistant.\"},\n    {\"role\": \"user\", \"content\": \"Write a Python function to calculate factorial\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nmessages.append({\"role\": \"assistant\", \"content\": response.output_text})\nmessages.append({\"role\": \"user\", \"content\": \"Now optimize it with memoization\"})\nresponse2 = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nprint(response2.output_text)\n```\n\n## Streaming (sync)\n\n```python\nstream = client.responses.create(\n    model=deployment,\n    input=\"Explain streaming in simple terms\",\n    max_output_tokens=1000,\n    stream=True,\n)\nfor event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Streaming (async)\n\n```python\nstream = await client.responses.create(\n    model=deployment, input=\"...\", max_output_tokens=1000, stream=True,\n)\nasync for event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Structured output — JSON Schema\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"What is the capital of France?\",\n    max_output_tokens=500,\n    text={\n        \"format\": {\n            \"type\": \"json_schema\",\n            \"name\": \"Output\",\n            \"strict\": True,\n            \"schema\": {\n                \"type\": \"object\",\n                \"properties\": {\"answer\": {\"type\": \"string\"}},\n                \"required\": [\"answer\"],\n                \"additionalProperties\": False,\n            },\n        }\n    },\n    store=False,\n)\nimport json\ndata = json.loads(resp.output_text)\n```\n\n## Tools (flat Responses format)\n\n```python\ntools = [\n    {\n        \"type\": \"function\",\n        \"name\": \"lookup_weather\",\n        \"description\": \"Lookup the weather for a given city name.\",\n        \"parameters\": {\n            \"type\": \"object\",\n            \"properties\": {\"city_name\": {\"type\": \"string\", \"description\": \"The city name\"}},\n            \"required\": [\"city_name\"],\n            \"additionalProperties\": False,\n        },\n    }\n]\nresponse = client.responses.create(\n    model=deployment,\n    input=[\n        {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n        {\"role\": \"user\", \"content\": \"What's the weather in Berkeley?\"},\n    ],\n    tools=tools,\n    tool_choice=\"auto\",\n    store=False,\n)\n```\n\nTool call round-trip:\n```python\nimport json\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n    {\"role\": \"user\", \"content\": \"Is it sunny in Berkeley?\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\ntool_calls = [item for item in response.output if item.type == \"function_call\"]\nif tool_calls:\n    messages.extend(response.output)   # append the model's function_call items\n    for tc in tool_calls:\n        result = execute_tool(tc.name, json.loads(tc.arguments))\n        messages.append({\n            \"type\": \"function_call_output\",\n            \"call_id\": tc.call_id,\n            \"output\": json.dumps(result),\n        })\n    response = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\n    print(response.output_text)\n```\n\n> `openai.pydantic_function_tool()` still generates the old nested format and is **not** compatible with `responses.create()`. Define tool schemas manually.\n\n## Image input\n\nBefore (Chat): `{\"type\": \"image_url\", \"image_url\": {\"url\": \"...\"}}`\nAfter (Responses): `{\"type\": \"input_image\", \"image_url\": \"...\"}` (flat string — HTTPS URL or `data:image/...;base64,...`). Also `{\"type\": \"text\"}` → `{\"type\": \"input_text\"}`.\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What's in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.jpg\"},\n            ],\n        }\n    ],\n    max_output_tokens=500,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Reasoning models (o1, o3, o3-mini, o4-mini, GPT-5 family)\n\n| Chat Completions | Responses API | Notes |\n|---|---|---|\n| `max_completion_tokens` | `max_output_tokens` | Set high (4096+) |\n| `reasoning_effort` | `reasoning={\"effort\": ...}` | keep low/medium/high |\n| `temperature` | remove | GPT-5 rejects it outright (o-series only accepts `1`). To vary output, use a non-reasoning model such as `Llama-3.3-70B-Instruct` via Foundry Models. |\n| `top_p` | remove | not supported |\n| `seed` | remove | not supported |\n","AGENTS.md":"# AGENTS.md\n\n## Project Overview\n\nThis repository contains a comprehensive 21-lesson curriculum teaching Generative AI fundamentals and application development. The course is designed for beginners and covers everything from basic concepts to building production-ready applications.\n\n**Key Technologies:**\n- Python 3.9+ with libraries: `openai`, `python-dotenv`, `tiktoken`, `azure-ai-inference`, `pandas`, `numpy`, `matplotlib`\n- TypeScript/JavaScript with Node.js and libraries: `openai` (Azure OpenAI via the v1 endpoint + Responses API), `@azure-rest/ai-inference` (Microsoft Foundry Models)\n- Azure OpenAI Service, OpenAI API, and Microsoft Foundry Models (GitHub Models is retiring end of July 2026)\n- Jupyter Notebooks for interactive learning\n- Dev Containers for consistent development environment\n\n**Repository Structure:**\n- 21 numbered lesson directories (00-21) containing READMEs, code examples, and assignments\n- Multiple implementations: Python, TypeScript, and sometimes .NET examples\n- Translations directory with 40+ language versions\n- Centralized configuration via `.env` file (use `.env.copy` as template)\n\n## Setup Commands\n\n### Initial Repository Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/microsoft/generative-ai-for-beginners.git\ncd generative-ai-for-beginners\n\n# Copy environment template\ncp .env.copy .env\n# Edit .env with your API keys and endpoints\n```\n\n### Python Environment Setup\n\n```bash\n# Create virtual environment\npython3 -m venv venv\n\n# Activate virtual environment\n# On macOS/Linux:\nsource venv/bin/activate\n# On Windows:\nvenv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Node.js/TypeScript Setup\n\n```bash\n# Install root-level dependencies (for documentation tooling)\nnpm install\n\n# For individual lesson TypeScript examples, navigate to the specific lesson:\ncd 06-text-generation-apps/typescript/recipe-app\nnpm install\n```\n\n### Dev Container Setup (Recommended)\n\nThe repository includes a `.devcontainer` configuration for GitHub Codespaces or VS Code Dev Containers:\n\n1. Open repository in GitHub Codespaces or VS Code with Dev Containers extension\n2. Dev Container will automatically:\n   - Install Python dependencies from `requirements.txt`\n   - Run post-create script (`.devcontainer/post-create.sh`)\n   - Set up Jupyter kernel\n\n## Development Workflow\n\n### Environment Variables\n\nAll lessons requiring API access use environment variables defined in `.env`:\n\n- `OPENAI_API_KEY` - For OpenAI API\n- `AZURE_OPENAI_API_KEY` - For Azure OpenAI in Microsoft Foundry (Azure OpenAI Service is now part of Microsoft Foundry: https://ai.azure.com)\n- `AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint URL (Foundry resource endpoint)\n- `AZURE_OPENAI_DEPLOYMENT` - Chat completion model deployment name (course default: `gpt-5-mini`)\n- `AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT` - Embeddings model deployment name (course default: `text-embedding-3-small`)\n- `AZURE_OPENAI_API_VERSION` - API version (default: `2024-10-21`)\n- `HUGGING_FACE_API_KEY` - For Hugging Face models\n- `AZURE_INFERENCE_ENDPOINT` - Microsoft Foundry Models endpoint (multi-provider model catalog)\n- `AZURE_INFERENCE_CREDENTIAL` - Microsoft Foundry Models API key (replaces the retiring `GITHUB_TOKEN`)\n- `AZURE_INFERENCE_CHAT_MODEL` - A non-reasoning model (e.g. `Llama-3.3-70B-Instruct`) used by the `temperature` examples, since reasoning models don't support sampling controls\n\n### Model conventions (important)\n\n- **Default chat model is `gpt-5-mini`** - a current, non-deprecated **reasoning** model. As of 2026 the older temperature-capable \"mini\" models (`gpt-4o-mini`, `gpt-4.1-mini`) are *deprecating*, so the curriculum standardizes on the GPT-5 family.\n- **Reasoning models reject `temperature` and `top_p`**, and use `max_output_tokens` (Responses API) / `max_completion_tokens` (chat completions) instead of `max_tokens`. Do **not** add `temperature`/`top_p`/`max_tokens` to samples that call `gpt-5-mini`.\n- **To demonstrate `temperature`**, samples use a **Llama** model (`Llama-3.3-70B-Instruct`) via the Microsoft Foundry Models endpoint (`AZURE_INFERENCE_CHAT_MODEL`). Steer reasoning models with prompt engineering + reasoning controls instead of sampling knobs.\n- **Fine-tuning (lesson 18)** keeps `gpt-4.1-mini`: GPT-5 only supports reinforcement fine-tuning (RFT), not the supervised fine-tuning (SFT) shown there.\n- Lessons 20 (Mistral) and 21 (Meta) keep `temperature`/`max_tokens` because they target Mistral/Llama models, which support them.\n\n### Running Python Examples\n\n```bash\n# Navigate to lesson directory\ncd 06-text-generation-apps/python\n\n# Run a Python script\npython aoai-app.py\n```\n\n### Running TypeScript Examples\n\n```bash\n# Navigate to TypeScript app directory\ncd 06-text-generation-apps/typescript/recipe-app\n\n# Build the TypeScript code\nnpm run build\n\n# Run the application\nnpm start\n```\n\n### Running Jupyter Notebooks\n\n```bash\n# Start Jupyter in the repository root\njupyter notebook\n\n# Or use VS Code with Jupyter extension\n```\n\n### Working with Different Lesson Types\n\n- **\"Learn\" lessons**: Focus on README.md documentation and concepts\n- **\"Build\" lessons**: Include working code examples in Python and TypeScript\n- Each lesson has a README.md with theory, code walkthroughs, and links to video content\n\n## Code Style Guidelines\n\n### Python\n\n- Use `python-dotenv` for environment variable management\n- Import `openai` library for API interactions\n- Use `pylint` for linting (some examples include `# pylint: disable=all` for simplicity)\n- Follow PEP 8 naming conventions\n- Store API credentials in `.env` file, never in code\n\n### TypeScript\n\n- Use `dotenv` package for environment variables\n- TypeScript configuration in `tsconfig.json` for each app\n- Use the `openai` package for Azure OpenAI (point the client at the `/openai/v1/` endpoint and call `client.responses.create`); use `@azure-rest/ai-inference` for Microsoft Foundry Models\n- Use `nodemon` for development with auto-reload\n- Build before running: `npm run build` then `npm start`\n\n### General Conventions\n\n- Keep code examples simple and educational\n- Include comments explaining key concepts\n- Each lesson's code should be self-contained and runnable\n- Use consistent naming: `aoai-` prefix for Azure OpenAI, `oai-` for OpenAI API, `githubmodels-` for Microsoft Foundry Models (legacy prefix retained from the GitHub Models era)\n\n## Documentation Guidelines\n\n### Markdown Style\n\n- All URLs must be wrapped in `[text](url)` format with no extra spaces\n- Relative links must start with `./` or `../`\n- All links to Microsoft domains must include tracking ID: `?WT.mc_id=academic-105485-koreyst`\n- No country-specific locales in URLs (avoid `/en-us/`)\n- Images stored in `./images` folder with descriptive names\n- Use English characters, numbers, and dashes in file names\n\n### Translation Support\n\n- Repository supports 40+ languages via automated GitHub Actions\n- Translations stored in `translations/` directory\n- Do not submit partial translations\n- Machine translations are not accepted\n- Translated images stored in `translated_images/` directory\n\n## Testing and Validation\n\n### Pre-submission Checks\n\nThis repository uses GitHub Actions for validation. Before submitting PRs:\n\n1. **Check Markdown Links**:\n   ```bash\n   # The validate-markdown.yml workflow checks:\n   # - Broken relative paths\n   # - Missing tracking IDs on paths\n   # - Missing tracking IDs on URLs\n   # - URLs with country locale\n   # - Broken external URLs\n   ```\n\n2. **Manual Testing**:\n   - Test Python examples: Activate venv and run scripts\n   - Test TypeScript examples: `npm install`, `npm run build`, `npm start`\n   - Verify environment variables are configured correctly\n   - Check that API keys work with the code examples\n\n3. **Code Examples**:\n   - Ensure all code runs without errors\n   - Test with both Azure OpenAI and OpenAI API when applicable\n   - Verify examples work with Microsoft Foundry Models where supported\n\n### No Automated Tests\n\nThis is an educational repository focused on tutorials and examples. There are no unit tests or integration tests to run. Validation is primarily:\n- Manual testing of code examples\n- GitHub Actions for Markdown validation\n- Community review of educational content\n\n## Pull Request Guidelines\n\n### Before Submitting\n\n1. Test code changes in both Python and TypeScript when applicable\n2. Run Markdown validation (triggered automatically on PR)\n3. Ensure tracking IDs are present on all Microsoft URLs\n4. Check that relative links are valid\n5. Verify images are properly referenced\n\n### PR Title Format\n\n- Use descriptive titles: `[Lesson 06] Fix Python example typo` or `Update README for lesson 08`\n- Reference issue numbers when applicable: `Fixes #123`\n\n### PR Description\n\n- Explain what was changed and why\n- Link to related issues\n- For code changes, specify which examples were tested\n- For translation PRs, include all files for a complete translation\n\n### Contribution Requirements\n\n- Sign Microsoft CLA (automatic on first PR)\n- Fork repository to your account before making changes\n- One PR per logical change (don't combine unrelated fixes)\n- Keep PRs focused and small when possible\n\n## Common Workflows\n\n### Adding a New Code Example\n\n1. Navigate to the appropriate lesson directory\n2. Create example in `python/` or `typescript/` subdirectory\n3. Follow naming convention: `{provider}-{example-name}.{py|ts|js}`\n4. Test with actual API credentials\n5. Document any new environment variables in lesson README\n\n### Updating Documentation\n\n1. Edit README.md in the lesson directory\n2. Follow Markdown guidelines (tracking IDs, relative links)\n3. Update translations are handled by GitHub Actions (don't edit manually)\n4. Test all links are valid\n\n### Working with Dev Containers\n\n1. Repository includes `.devcontainer/devcontainer.json`\n2. Post-create script installs Python dependencies automatically\n3. Extensions for Python and Jupyter are pre-configured\n4. Environment is based on `mcr.microsoft.com/devcontainers/universal:2.11.2`\n\n## Deployment and Publishing\n\nThis is a learning repository - there is no deployment process. The curriculum is consumed by:\n\n1. **GitHub Repository**: Direct access to code and documentation\n2. **GitHub Codespaces**: Instant dev environment with pre-configured setup\n3. **Microsoft Learn**: Content may be syndicated to official learning platform\n4. **docsify**: Documentation site built from Markdown (see `docsifytopdf.js` and `package.json`)\n\n### Building Documentation Site\n\n```bash\n# Generate PDF from documentation (if needed)\nnpm run convert\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Python Import Errors**:\n- Ensure virtual environment is activated\n- Run `pip install -r requirements.txt`\n- Check Python version is 3.9+\n\n**TypeScript Build Errors**:\n- Run `npm install` in the specific app directory\n- Check Node.js version is compatible\n- Clear `node_modules` and reinstall if needed\n\n**API Authentication Errors**:\n- Verify `.env` file exists and has correct values\n- Check API keys are valid and not expired\n- Ensure endpoint URLs are correct for your region\n\n**Missing Environment Variables**:\n- Copy `.env.copy` to `.env`\n- Fill in all required values for the lesson you're working on\n- Restart your application after updating `.env`\n\n## Additional Resources\n\n- [Course Setup Guide](./00-course-setup/README.md?WT.mc_id=academic-105485-koreyst)\n- [Contributing Guidelines](./CONTRIBUTING.md)\n- [Code of Conduct](./CODE_OF_CONDUCT.md)\n- [Security Policy](./SECURITY.md)\n- [Azure AI Discord](https://aka.ms/genai-discord?WT.mc_id=academic-105485-koreyst)\n- [Collection of Advanced Code Samples](https://aka.ms/genai-beg-code?WT.mc_id=academic-105485-koreyst)\n\n## Project-Specific Notes\n\n- This is an **educational repository** focused on learning, not production code\n- Examples are intentionally simple and focused on teaching concepts\n- Code quality is balanced with educational clarity\n- Each lesson is self-contained and can be completed independently\n- The repository supports multiple API providers: Azure OpenAI, OpenAI, Microsoft Foundry Models, and offline providers such as Foundry Local and Ollama\n- Content is multilingual with automated translation workflows\n- Active community on Discord for questions and support\n"},"files":{".github/skills/azure-openai-to-responses/SKILL.md":"---\nname: azure-openai-to-responses\ndescription: >-\n  Migrate Python apps from Azure OpenAI Chat Completions to the Responses API.\n  Covers AzureOpenAI/AsyncAzureOpenAI client migration to the v1 endpoint,\n  streaming, tools, structured output, multi-turn, EntraID auth, and model\n  compatibility checks. Python-focused, Azure OpenAI-specific.\n  USE FOR: migrate to responses API, switch from chat completions, openai responses,\n  upgrade openai SDK, responses API migration, move from completions to responses,\n  gpt-5 migration, azure openai python migration, chat completions to responses,\n  AzureOpenAI to OpenAI client, python azure openai upgrade.\n  DO NOT USE FOR: building new apps from scratch (start with responses directly),\n  Node/TypeScript/C#/Java/Go migrations (this skill is Python-only),\n  Azure infrastructure setup (use azure-prepare), deploying models (use microsoft-foundry).\nlicense: MIT\nsource: https://github.com/Azure-Samples/azure-openai-to-responses\n---\n\n# Migrate Python Apps from Azure OpenAI Chat Completions to Responses API\n\n> **AUTHORITATIVE GUIDANCE — FOLLOW EXACTLY**\n>\n> This skill migrates Python codebases using Azure OpenAI Chat Completions\n> to the unified Responses API. Follow these instructions precisely.\n> Do not improvise parameter mappings or invent API shapes.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Triggers\n\nActivate this skill when the user wants to:\n- Migrate a Python app from Azure OpenAI Chat Completions to Responses API\n- Upgrade Python OpenAI SDK usage to the latest API shape against Azure OpenAI\n- Prepare Python code for GPT-5 or newer models that require Responses on Azure\n- Switch from `AzureOpenAI`/`AsyncAzureOpenAI` to standard `OpenAI`/`AsyncOpenAI` client with the v1 endpoint\n- Fix deprecation warnings related to `AzureOpenAI` constructors or `api_version`\n\n## Why migrate\n\nGPT-5 and newer models require the Responses API. The new `/openai/v1/` endpoint\nuses the standard `OpenAI()` client instead of `AzureOpenAI()`, requires no\n`api_version` parameter, and works identically across OpenAI and Azure OpenAI.\n\n## What changes\n\n| Chat Completions (before) | Responses API (after) |\n| --- | --- |\n| `AzureOpenAI()` / `AsyncAzureOpenAI()` | `OpenAI(base_url=...)` / `AsyncOpenAI(base_url=...)` |\n| `azure_endpoint=...` | `base_url=f\"{endpoint.rstrip('/')}/openai/v1/\"` |\n| `api_version=\"2024-...\"` | Remove entirely — `/openai/v1/` is stable |\n| `azure_ad_token_provider=...` | `api_key=token_provider` |\n| `client.chat.completions.create(messages=...)` | `client.responses.create(input=...)` |\n| `resp.choices[0].message.content` | `resp.output_text` |\n| `max_tokens` | `max_output_tokens` (min 16 on Azure) |\n| `response_format` | `text={\"format\": {...}}` |\n| `seed` | **Remove** (not supported) |\n| tools nested `{\"type\":\"function\",\"function\":{...}}` | flat `{\"type\":\"function\",\"name\":...}` |\n| tool result `{\"role\":\"tool\",\"tool_call_id\":...}` | `{\"type\":\"function_call_output\",\"call_id\":...,\"output\":...}` |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` + `{\"url\": \"...\"}` | `content[].type: \"input_image\"` + flat `\"image_url\": \"...\"` |\n| streaming `chunk.choices[0].delta.content` | `event.type == \"response.output_text.delta\"` → `event.delta` |\n\n## Model compatibility — CHECK FIRST\n\nVerify the deployed model supports the Responses API before migrating. GPT-4o and\nGPT-4 support Responses for basic text/chat/streaming/tools but not all features.\nNewer models (gpt-4.1+, gpt-5.x) have full support. **GitHub Models\n(`models.github.ai`, `models.inference.ai.azure.com`) do NOT support the Responses\nAPI** — remove those code paths and switch to Azure OpenAI, OpenAI, or a compatible\nlocal endpoint.\n\nSmoke test:\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"ping\",\n    max_output_tokens=50,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Step 0: Client migration (prerequisite)\n\n`AzureOpenAI`/`AsyncAzureOpenAI` constructors are deprecated in `openai>=1.108.1`.\n\nBefore:\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\n```\n\nAfter:\n```python\nfrom openai import OpenAI\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\nCleanup: remove `api_version` args, remove `AZURE_OPENAI_API_VERSION` /\n`AZURE_OPENAI_VERSION` from `.env`/infra, rename `AZURE_OPENAI_CLIENT_ID` →\n`AZURE_CLIENT_ID`, ensure `openai>=1.108.1`.\n\n## Step 1: Detect legacy call sites\n\n```bash\nrg \"chat\\.completions\\.create\"        # legacy API calls\nrg \"ChatCompletion\\.create|Completion\\.create\"\nrg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"  # deprecated constructors\nrg \"choices\\[0\\]\\.message\\.content\"    # response access\nrg \"choices\\[0\\]\\.delta\\.content\"      # streaming access\nrg \"max_tokens\\b\"                      # rename to max_output_tokens\nrg \"['\\\"]seed['\\\"]\"                    # remove entirely\nrg \"response_format\"                   # → text.format\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"  # GitHub Models: remove\n```\n\n## Step 2: Apply migration\n\n- `client.chat.completions.create(messages=...)` → `client.responses.create(input=...)`\n- `resp.choices[0].message.content` → `resp.output_text`\n- `max_tokens` → `max_output_tokens` (min 16); remove `seed`\n- `response_format` → `text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`\n- Set `store=False` on every request (client-managed state)\n- Streaming: iterate events, handle `event.type == \"response.output_text.delta\"` (use `event.delta`) and `response.completed`\n- Tools: flat format, `tool_choice`, return results as `function_call_output` items; append `response.output` items for round-trips\n- Multi-turn: maintain conversation in an `input` array, or use `previous_response_id` (requires `store=True`)\n- Reasoning models (o-series, GPT-5): `max_completion_tokens` → `max_output_tokens` (4096+), `reasoning_effort` → `reasoning={\"effort\": ...}`, omit `temperature`/`top_p` (GPT-5 rejects `temperature` outright; to vary output use a non-reasoning model like `Llama-3.3-70B-Instruct` via Foundry Models)\n\n## Acceptance criteria (all must pass)\n\n- Zero matches for `chat.completions.create|ChatCompletion.create|Completion.create`\n- Zero matches for `AzureOpenAI(|AsyncAzureOpenAI(` — all use `OpenAI`/`AsyncOpenAI` + v1 endpoint\n- Zero matches for `models.github.ai|models.inference.ai.azure`\n- Zero matches for `choices[0]` — all access uses `resp.output_text` / Responses schema\n- No top-level `response_format`; structured output uses `text={\"format\": {...}}`\n- `openai>=1.108.1` in requirements; `store=False` on every call; no `api_version` in client construction\n- Tests updated (mocks use `kwargs.get(\"input\")`, snapshots use Responses shape); `pytest` passes\n\nSee [references/cheat-sheet.md](./references/cheat-sheet.md) for complete before/after code examples.\n\n## References\n\n- [Azure OpenAI Responses API docs](https://learn.microsoft.com/azure/ai-foundry/openai/how-to/responses)\n- [OpenAI Responses API reference](https://platform.openai.com/docs/api-reference/responses)\n- [Source skill: Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses)\n",".github/skills/azure-openai-to-responses/references/cheat-sheet.md":"# Responses API Cheat Sheet (Python + Azure OpenAI)\n\n> All snippets assume `deployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]` and `client` is already initialized.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Client setup — API key\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\n## Client setup — EntraID (recommended)\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nfrom openai import OpenAI\n\ntoken_provider = get_bearer_token_provider(\n    DefaultAzureCredential(),\n    \"https://cognitiveservices.azure.com/.default\",\n)\nclient = OpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,\n)\n```\n\n## Async client setup\n\n```python\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,   # or api_key=os.environ[\"AZURE_OPENAI_API_KEY\"]\n)\n```\n\n## Basic request\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Full sync migration — before/after\n\nBefore (Chat Completions):\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\nresp = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n    max_tokens=500,\n)\nprint(resp.choices[0].message.content)\n```\n\nAfter (Responses API):\n```python\nfrom openai import OpenAI\ndeployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Multi-turn conversation\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a helpful coding assistant.\"},\n    {\"role\": \"user\", \"content\": \"Write a Python function to calculate factorial\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nmessages.append({\"role\": \"assistant\", \"content\": response.output_text})\nmessages.append({\"role\": \"user\", \"content\": \"Now optimize it with memoization\"})\nresponse2 = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nprint(response2.output_text)\n```\n\n## Streaming (sync)\n\n```python\nstream = client.responses.create(\n    model=deployment,\n    input=\"Explain streaming in simple terms\",\n    max_output_tokens=1000,\n    stream=True,\n)\nfor event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Streaming (async)\n\n```python\nstream = await client.responses.create(\n    model=deployment, input=\"...\", max_output_tokens=1000, stream=True,\n)\nasync for event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Structured output — JSON Schema\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"What is the capital of France?\",\n    max_output_tokens=500,\n    text={\n        \"format\": {\n            \"type\": \"json_schema\",\n            \"name\": \"Output\",\n            \"strict\": True,\n            \"schema\": {\n                \"type\": \"object\",\n                \"properties\": {\"answer\": {\"type\": \"string\"}},\n                \"required\": [\"answer\"],\n                \"additionalProperties\": False,\n            },\n        }\n    },\n    store=False,\n)\nimport json\ndata = json.loads(resp.output_text)\n```\n\n## Tools (flat Responses format)\n\n```python\ntools = [\n    {\n        \"type\": \"function\",\n        \"name\": \"lookup_weather\",\n        \"description\": \"Lookup the weather for a given city name.\",\n        \"parameters\": {\n            \"type\": \"object\",\n            \"properties\": {\"city_name\": {\"type\": \"string\", \"description\": \"The city name\"}},\n            \"required\": [\"city_name\"],\n            \"additionalProperties\": False,\n        },\n    }\n]\nresponse = client.responses.create(\n    model=deployment,\n    input=[\n        {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n        {\"role\": \"user\", \"content\": \"What's the weather in Berkeley?\"},\n    ],\n    tools=tools,\n    tool_choice=\"auto\",\n    store=False,\n)\n```\n\nTool call round-trip:\n```python\nimport json\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n    {\"role\": \"user\", \"content\": \"Is it sunny in Berkeley?\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\ntool_calls = [item for item in response.output if item.type == \"function_call\"]\nif tool_calls:\n    messages.extend(response.output)   # append the model's function_call items\n    for tc in tool_calls:\n        result = execute_tool(tc.name, json.loads(tc.arguments))\n        messages.append({\n            \"type\": \"function_call_output\",\n            \"call_id\": tc.call_id,\n            \"output\": json.dumps(result),\n        })\n    response = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\n    print(response.output_text)\n```\n\n> `openai.pydantic_function_tool()` still generates the old nested format and is **not** compatible with `responses.create()`. Define tool schemas manually.\n\n## Image input\n\nBefore (Chat): `{\"type\": \"image_url\", \"image_url\": {\"url\": \"...\"}}`\nAfter (Responses): `{\"type\": \"input_image\", \"image_url\": \"...\"}` (flat string — HTTPS URL or `data:image/...;base64,...`). Also `{\"type\": \"text\"}` → `{\"type\": \"input_text\"}`.\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What's in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.jpg\"},\n            ],\n        }\n    ],\n    max_output_tokens=500,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Reasoning models (o1, o3, o3-mini, o4-mini, GPT-5 family)\n\n| Chat Completions | Responses API | Notes |\n|---|---|---|\n| `max_completion_tokens` | `max_output_tokens` | Set high (4096+) |\n| `reasoning_effort` | `reasoning={\"effort\": ...}` | keep low/medium/high |\n| `temperature` | remove | GPT-5 rejects it outright (o-series only accepts `1`). To vary output, use a non-reasoning model such as `Llama-3.3-70B-Instruct` via Foundry Models. |\n| `top_p` | remove | not supported |\n| `seed` | remove | not supported |\n","AGENTS.md":"# AGENTS.md\n\n## Project Overview\n\nThis repository contains a comprehensive 21-lesson curriculum teaching Generative AI fundamentals and application development. The course is designed for beginners and covers everything from basic concepts to building production-ready applications.\n\n**Key Technologies:**\n- Python 3.9+ with libraries: `openai`, `python-dotenv`, `tiktoken`, `azure-ai-inference`, `pandas`, `numpy`, `matplotlib`\n- TypeScript/JavaScript with Node.js and libraries: `openai` (Azure OpenAI via the v1 endpoint + Responses API), `@azure-rest/ai-inference` (Microsoft Foundry Models)\n- Azure OpenAI Service, OpenAI API, and Microsoft Foundry Models (GitHub Models is retiring end of July 2026)\n- Jupyter Notebooks for interactive learning\n- Dev Containers for consistent development environment\n\n**Repository Structure:**\n- 21 numbered lesson directories (00-21) containing READMEs, code examples, and assignments\n- Multiple implementations: Python, TypeScript, and sometimes .NET examples\n- Translations directory with 40+ language versions\n- Centralized configuration via `.env` file (use `.env.copy` as template)\n\n## Setup Commands\n\n### Initial Repository Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/microsoft/generative-ai-for-beginners.git\ncd generative-ai-for-beginners\n\n# Copy environment template\ncp .env.copy .env\n# Edit .env with your API keys and endpoints\n```\n\n### Python Environment Setup\n\n```bash\n# Create virtual environment\npython3 -m venv venv\n\n# Activate virtual environment\n# On macOS/Linux:\nsource venv/bin/activate\n# On Windows:\nvenv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Node.js/TypeScript Setup\n\n```bash\n# Install root-level dependencies (for documentation tooling)\nnpm install\n\n# For individual lesson TypeScript examples, navigate to the specific lesson:\ncd 06-text-generation-apps/typescript/recipe-app\nnpm install\n```\n\n### Dev Container Setup (Recommended)\n\nThe repository includes a `.devcontainer` configuration for GitHub Codespaces or VS Code Dev Containers:\n\n1. Open repository in GitHub Codespaces or VS Code with Dev Containers extension\n2. Dev Container will automatically:\n   - Install Python dependencies from `requirements.txt`\n   - Run post-create script (`.devcontainer/post-create.sh`)\n   - Set up Jupyter kernel\n\n## Development Workflow\n\n### Environment Variables\n\nAll lessons requiring API access use environment variables defined in `.env`:\n\n- `OPENAI_API_KEY` - For OpenAI API\n- `AZURE_OPENAI_API_KEY` - For Azure OpenAI in Microsoft Foundry (Azure OpenAI Service is now part of Microsoft Foundry: https://ai.azure.com)\n- `AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint URL (Foundry resource endpoint)\n- `AZURE_OPENAI_DEPLOYMENT` - Chat completion model deployment name (course default: `gpt-5-mini`)\n- `AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT` - Embeddings model deployment name (course default: `text-embedding-3-small`)\n- `AZURE_OPENAI_API_VERSION` - API version (default: `2024-10-21`)\n- `HUGGING_FACE_API_KEY` - For Hugging Face models\n- `AZURE_INFERENCE_ENDPOINT` - Microsoft Foundry Models endpoint (multi-provider model catalog)\n- `AZURE_INFERENCE_CREDENTIAL` - Microsoft Foundry Models API key (replaces the retiring `GITHUB_TOKEN`)\n- `AZURE_INFERENCE_CHAT_MODEL` - A non-reasoning model (e.g. `Llama-3.3-70B-Instruct`) used by the `temperature` examples, since reasoning models don't support sampling controls\n\n### Model conventions (important)\n\n- **Default chat model is `gpt-5-mini`** - a current, non-deprecated **reasoning** model. As of 2026 the older temperature-capable \"mini\" models (`gpt-4o-mini`, `gpt-4.1-mini`) are *deprecating*, so the curriculum standardizes on the GPT-5 family.\n- **Reasoning models reject `temperature` and `top_p`**, and use `max_output_tokens` (Responses API) / `max_completion_tokens` (chat completions) instead of `max_tokens`. Do **not** add `temperature`/`top_p`/`max_tokens` to samples that call `gpt-5-mini`.\n- **To demonstrate `temperature`**, samples use a **Llama** model (`Llama-3.3-70B-Instruct`) via the Microsoft Foundry Models endpoint (`AZURE_INFERENCE_CHAT_MODEL`). Steer reasoning models with prompt engineering + reasoning controls instead of sampling knobs.\n- **Fine-tuning (lesson 18)** keeps `gpt-4.1-mini`: GPT-5 only supports reinforcement fine-tuning (RFT), not the supervised fine-tuning (SFT) shown there.\n- Lessons 20 (Mistral) and 21 (Meta) keep `temperature`/`max_tokens` because they target Mistral/Llama models, which support them.\n\n### Running Python Examples\n\n```bash\n# Navigate to lesson directory\ncd 06-text-generation-apps/python\n\n# Run a Python script\npython aoai-app.py\n```\n\n### Running TypeScript Examples\n\n```bash\n# Navigate to TypeScript app directory\ncd 06-text-generation-apps/typescript/recipe-app\n\n# Build the TypeScript code\nnpm run build\n\n# Run the application\nnpm start\n```\n\n### Running Jupyter Notebooks\n\n```bash\n# Start Jupyter in the repository root\njupyter notebook\n\n# Or use VS Code with Jupyter extension\n```\n\n### Working with Different Lesson Types\n\n- **\"Learn\" lessons**: Focus on README.md documentation and concepts\n- **\"Build\" lessons**: Include working code examples in Python and TypeScript\n- Each lesson has a README.md with theory, code walkthroughs, and links to video content\n\n## Code Style Guidelines\n\n### Python\n\n- Use `python-dotenv` for environment variable management\n- Import `openai` library for API interactions\n- Use `pylint` for linting (some examples include `# pylint: disable=all` for simplicity)\n- Follow PEP 8 naming conventions\n- Store API credentials in `.env` file, never in code\n\n### TypeScript\n\n- Use `dotenv` package for environment variables\n- TypeScript configuration in `tsconfig.json` for each app\n- Use the `openai` package for Azure OpenAI (point the client at the `/openai/v1/` endpoint and call `client.responses.create`); use `@azure-rest/ai-inference` for Microsoft Foundry Models\n- Use `nodemon` for development with auto-reload\n- Build before running: `npm run build` then `npm start`\n\n### General Conventions\n\n- Keep code examples simple and educational\n- Include comments explaining key concepts\n- Each lesson's code should be self-contained and runnable\n- Use consistent naming: `aoai-` prefix for Azure OpenAI, `oai-` for OpenAI API, `githubmodels-` for Microsoft Foundry Models (legacy prefix retained from the GitHub Models era)\n\n## Documentation Guidelines\n\n### Markdown Style\n\n- All URLs must be wrapped in `[text](url)` format with no extra spaces\n- Relative links must start with `./` or `../`\n- All links to Microsoft domains must include tracking ID: `?WT.mc_id=academic-105485-koreyst`\n- No country-specific locales in URLs (avoid `/en-us/`)\n- Images stored in `./images` folder with descriptive names\n- Use English characters, numbers, and dashes in file names\n\n### Translation Support\n\n- Repository supports 40+ languages via automated GitHub Actions\n- Translations stored in `translations/` directory\n- Do not submit partial translations\n- Machine translations are not accepted\n- Translated images stored in `translated_images/` directory\n\n## Testing and Validation\n\n### Pre-submission Checks\n\nThis repository uses GitHub Actions for validation. Before submitting PRs:\n\n1. **Check Markdown Links**:\n   ```bash\n   # The validate-markdown.yml workflow checks:\n   # - Broken relative paths\n   # - Missing tracking IDs on paths\n   # - Missing tracking IDs on URLs\n   # - URLs with country locale\n   # - Broken external URLs\n   ```\n\n2. **Manual Testing**:\n   - Test Python examples: Activate venv and run scripts\n   - Test TypeScript examples: `npm install`, `npm run build`, `npm start`\n   - Verify environment variables are configured correctly\n   - Check that API keys work with the code examples\n\n3. **Code Examples**:\n   - Ensure all code runs without errors\n   - Test with both Azure OpenAI and OpenAI API when applicable\n   - Verify examples work with Microsoft Foundry Models where supported\n\n### No Automated Tests\n\nThis is an educational repository focused on tutorials and examples. There are no unit tests or integration tests to run. Validation is primarily:\n- Manual testing of code examples\n- GitHub Actions for Markdown validation\n- Community review of educational content\n\n## Pull Request Guidelines\n\n### Before Submitting\n\n1. Test code changes in both Python and TypeScript when applicable\n2. Run Markdown validation (triggered automatically on PR)\n3. Ensure tracking IDs are present on all Microsoft URLs\n4. Check that relative links are valid\n5. Verify images are properly referenced\n\n### PR Title Format\n\n- Use descriptive titles: `[Lesson 06] Fix Python example typo` or `Update README for lesson 08`\n- Reference issue numbers when applicable: `Fixes #123`\n\n### PR Description\n\n- Explain what was changed and why\n- Link to related issues\n- For code changes, specify which examples were tested\n- For translation PRs, include all files for a complete translation\n\n### Contribution Requirements\n\n- Sign Microsoft CLA (automatic on first PR)\n- Fork repository to your account before making changes\n- One PR per logical change (don't combine unrelated fixes)\n- Keep PRs focused and small when possible\n\n## Common Workflows\n\n### Adding a New Code Example\n\n1. Navigate to the appropriate lesson directory\n2. Create example in `python/` or `typescript/` subdirectory\n3. Follow naming convention: `{provider}-{example-name}.{py|ts|js}`\n4. Test with actual API credentials\n5. Document any new environment variables in lesson README\n\n### Updating Documentation\n\n1. Edit README.md in the lesson directory\n2. Follow Markdown guidelines (tracking IDs, relative links)\n3. Update translations are handled by GitHub Actions (don't edit manually)\n4. Test all links are valid\n\n### Working with Dev Containers\n\n1. Repository includes `.devcontainer/devcontainer.json`\n2. Post-create script installs Python dependencies automatically\n3. Extensions for Python and Jupyter are pre-configured\n4. Environment is based on `mcr.microsoft.com/devcontainers/universal:2.11.2`\n\n## Deployment and Publishing\n\nThis is a learning repository - there is no deployment process. The curriculum is consumed by:\n\n1. **GitHub Repository**: Direct access to code and documentation\n2. **GitHub Codespaces**: Instant dev environment with pre-configured setup\n3. **Microsoft Learn**: Content may be syndicated to official learning platform\n4. **docsify**: Documentation site built from Markdown (see `docsifytopdf.js` and `package.json`)\n\n### Building Documentation Site\n\n```bash\n# Generate PDF from documentation (if needed)\nnpm run convert\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Python Import Errors**:\n- Ensure virtual environment is activated\n- Run `pip install -r requirements.txt`\n- Check Python version is 3.9+\n\n**TypeScript Build Errors**:\n- Run `npm install` in the specific app directory\n- Check Node.js version is compatible\n- Clear `node_modules` and reinstall if needed\n\n**API Authentication Errors**:\n- Verify `.env` file exists and has correct values\n- Check API keys are valid and not expired\n- Ensure endpoint URLs are correct for your region\n\n**Missing Environment Variables**:\n- Copy `.env.copy` to `.env`\n- Fill in all required values for the lesson you're working on\n- Restart your application after updating `.env`\n\n## Additional Resources\n\n- [Course Setup Guide](./00-course-setup/README.md?WT.mc_id=academic-105485-koreyst)\n- [Contributing Guidelines](./CONTRIBUTING.md)\n- [Code of Conduct](./CODE_OF_CONDUCT.md)\n- [Security Policy](./SECURITY.md)\n- [Azure AI Discord](https://aka.ms/genai-discord?WT.mc_id=academic-105485-koreyst)\n- [Collection of Advanced Code Samples](https://aka.ms/genai-beg-code?WT.mc_id=academic-105485-koreyst)\n\n## Project-Specific Notes\n\n- This is an **educational repository** focused on learning, not production code\n- Examples are intentionally simple and focused on teaching concepts\n- Code quality is balanced with educational clarity\n- Each lesson is self-contained and can be completed independently\n- The repository supports multiple API providers: Azure OpenAI, OpenAI, Microsoft Foundry Models, and offline providers such as Foundry Local and Ollama\n- Content is multilingual with automated translation workflows\n- Active community on Discord for questions and support\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/microsoft/generative-ai-for-beginners/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md\n\n## Project Overview\n\nThis repository contains a comprehensive 21-lesson curriculum teaching Generative AI fundamentals and application development. The course is designed for beginners and covers everything from basic concepts to building production-ready applications.\n\n**Key Technologies:**\n- Python 3.9+ with libraries: `openai`, `python-dotenv`, `tiktoken`, `azure-ai-inference`, `pandas`, `numpy`, `matplotlib`\n- TypeScript/JavaScript with Node.js and libraries: `openai` (Azure OpenAI via the v1 endpoint + Responses API), `@azure-rest/ai-inference` (Microsoft Foundry Models)\n- Azure OpenAI Service, OpenAI API, and Microsoft Foundry Models (GitHub Models is retiring end of July 2026)\n- Jupyter Notebooks for interactive learning\n- Dev Containers for consistent development environment\n\n**Repository Structure:**\n- 21 numbered lesson directories (00-21) containing READMEs, code examples, and assignments\n- Multiple implementations: Python, TypeScript, and sometimes .NET examples\n- Translations directory with 40+ language versions\n- Centralized configuration via `.env` file (use `.env.copy` as template)\n\n## Setup Commands\n\n### Initial Repository Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/microsoft/generative-ai-for-beginners.git\ncd generative-ai-for-beginners\n\n# Copy environment template\ncp .env.copy .env\n# Edit .env with your API keys and endpoints\n```\n\n### Python Environment Setup\n\n```bash\n# Create virtual environment\npython3 -m venv venv\n\n# Activate virtual environment\n# On macOS/Linux:\nsource venv/bin/activate\n# On Windows:\nvenv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Node.js/TypeScript Setup\n\n```bash\n# Install root-level dependencies (for documentation tooling)\nnpm install\n\n# For individual lesson TypeScript examples, navigate to the specific lesson:\ncd 06-text-generation-apps/typescript/recipe-app\nnpm install\n```\n\n### Dev Container Setup (Recommended)\n\nThe repository includes a `.devcontainer` configuration for GitHub Codespaces or VS Code Dev Containers:\n\n1. Open repository in GitHub Codespaces or VS Code with Dev Containers extension\n2. Dev Container will automatically:\n   - Install Python dependencies from `requirements.txt`\n   - Run post-create script (`.devcontainer/post-create.sh`)\n   - Set up Jupyter kernel\n\n## Development Workflow\n\n### Environment Variables\n\nAll lessons requiring API access use environment variables defined in `.env`:\n\n- `OPENAI_API_KEY` - For OpenAI API\n- `AZURE_OPENAI_API_KEY` - For Azure OpenAI in Microsoft Foundry (Azure OpenAI Service is now part of Microsoft Foundry: https://ai.azure.com)\n- `AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint URL (Foundry resource endpoint)\n- `AZURE_OPENAI_DEPLOYMENT` - Chat completion model deployment name (course default: `gpt-5-mini`)\n- `AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT` - Embeddings model deployment name (course default: `text-embedding-3-small`)\n- `AZURE_OPENAI_API_VERSION` - API version (default: `2024-10-21`)\n- `HUGGING_FACE_API_KEY` - For Hugging Face models\n- `AZURE_INFERENCE_ENDPOINT` - Microsoft Foundry Models endpoint (multi-provider model catalog)\n- `AZURE_INFERENCE_CREDENTIAL` - Microsoft Foundry Models API key (replaces the retiring `GITHUB_TOKEN`)\n- `AZURE_INFERENCE_CHAT_MODEL` - A non-reasoning model (e.g. `Llama-3.3-70B-Instruct`) used by the `temperature` examples, since reasoning models don't support sampling controls\n\n### Model conventions (important)\n\n- **Default chat model is `gpt-5-mini`** - a current, non-deprecated **reasoning** model. As of 2026 the older temperature-capable \"mini\" models (`gpt-4o-mini`, `gpt-4.1-mini`) are *deprecating*, so the curriculum standardizes on the GPT-5 family.\n- **Reasoning models reject `temperature` and `top_p`**, and use `max_output_tokens` (Responses API) / `max_completion_tokens` (chat completions) instead of `max_tokens`. Do **not** add `temperature`/`top_p`/`max_tokens` to samples that call `gpt-5-mini`.\n- **To demonstrate `temperature`**, samples use a **Llama** model (`Llama-3.3-70B-Instruct`) via the Microsoft Foundry Models endpoint (`AZURE_INFERENCE_CHAT_MODEL`). Steer reasoning models with prompt engineering + reasoning controls instead of sampling knobs.\n- **Fine-tuning (lesson 18)** keeps `gpt-4.1-mini`: GPT-5 only supports reinforcement fine-tuning (RFT), not the supervised fine-tuning (SFT) shown there.\n- Lessons 20 (Mistral) and 21 (Meta) keep `temperature`/`max_tokens` because they target Mistral/Llama models, which support them.\n\n### Running Python Examples\n\n```bash\n# Navigate to lesson directory\ncd 06-text-generation-apps/python\n\n# Run a Python script\npython aoai-app.py\n```\n\n### Running TypeScript Examples\n\n```bash\n# Navigate to TypeScript app directory\ncd 06-text-generation-apps/typescript/recipe-app\n\n# Build the TypeScript code\nnpm run build\n\n# Run the application\nnpm start\n```\n\n### Running Jupyter Notebooks\n\n```bash\n# Start Jupyter in the repository root\njupyter notebook\n\n# Or use VS Code with Jupyter extension\n```\n\n### Working with Different Lesson Types\n\n- **\"Learn\" lessons**: Focus on README.md documentation and concepts\n- **\"Build\" lessons**: Include working code examples in Python and TypeScript\n- Each lesson has a README.md with theory, code walkthroughs, and links to video content\n\n## Code Style Guidelines\n\n### Python\n\n- Use `python-dotenv` for environment variable management\n- Import `openai` library for API interactions\n- Use `pylint` for linting (some examples include `# pylint: disable=all` for simplicity)\n- Follow PEP 8 naming conventions\n- Store API credentials in `.env` file, never in code\n\n### TypeScript\n\n- Use `dotenv` package for environment variables\n- TypeScript configuration in `tsconfig.json` for each app\n- Use the `openai` package for Azure OpenAI (point the client at the `/openai/v1/` endpoint and call `client.responses.create`); use `@azure-rest/ai-inference` for Microsoft Foundry Models\n- Use `nodemon` for development with auto-reload\n- Build before running: `npm run build` then `npm start`\n\n### General Conventions\n\n- Keep code examples simple and educational\n- Include comments explaining key concepts\n- Each lesson's code should be self-contained and runnable\n- Use consistent naming: `aoai-` prefix for Azure OpenAI, `oai-` for OpenAI API, `githubmodels-` for Microsoft Foundry Models (legacy prefix retained from the GitHub Models era)\n\n## Documentation Guidelines\n\n### Markdown Style\n\n- All URLs must be wrapped in `[text](url)` format with no extra spaces\n- Relative links must start with `./` or `../`\n- All links to Microsoft domains must include tracking ID: `?WT.mc_id=academic-105485-koreyst`\n- No country-specific locales in URLs (avoid `/en-us/`)\n- Images stored in `./images` folder with descriptive names\n- Use English characters, numbers, and dashes in file names\n\n### Translation Support\n\n- Repository supports 40+ languages via automated GitHub Actions\n- Translations stored in `translations/` directory\n- Do not submit partial translations\n- Machine translations are not accepted\n- Translated images stored in `translated_images/` directory\n\n## Testing and Validation\n\n### Pre-submission Checks\n\nThis repository uses GitHub Actions for validation. Before submitting PRs:\n\n1. **Check Markdown Links**:\n   ```bash\n   # The validate-markdown.yml workflow checks:\n   # - Broken relative paths\n   # - Missing tracking IDs on paths\n   # - Missing tracking IDs on URLs\n   # - URLs with country locale\n   # - Broken external URLs\n   ```\n\n2. **Manual Testing**:\n   - Test Python examples: Activate venv and run scripts\n   - Test TypeScript examples: `npm install`, `npm run build`, `npm start`\n   - Verify environment variables are configured correctly\n   - Check that API keys work with the code examples\n\n3. **Code Examples**:\n   - Ensure all code runs without errors\n   - Test with both Azure OpenAI and OpenAI API when applicable\n   - Verify examples work with Microsoft Foundry Models where supported\n\n### No Automated Tests\n\nThis is an educational repository focused on tutorials and examples. There are no unit tests or integration tests to run. Validation is primarily:\n- Manual testing of code examples\n- GitHub Actions for Markdown validation\n- Community review of educational content\n\n## Pull Request Guidelines\n\n### Before Submitting\n\n1. Test code changes in both Python and TypeScript when applicable\n2. Run Markdown validation (triggered automatically on PR)\n3. Ensure tracking IDs are present on all Microsoft URLs\n4. Check that relative links are valid\n5. Verify images are properly referenced\n\n### PR Title Format\n\n- Use descriptive titles: `[Lesson 06] Fix Python example typo` or `Update README for lesson 08`\n- Reference issue numbers when applicable: `Fixes #123`\n\n### PR Description\n\n- Explain what was changed and why\n- Link to related issues\n- For code changes, specify which examples were tested\n- For translation PRs, include all files for a complete translation\n\n### Contribution Requirements\n\n- Sign Microsoft CLA (automatic on first PR)\n- Fork repository to your account before making changes\n- One PR per logical change (don't combine unrelated fixes)\n- Keep PRs focused and small when possible\n\n## Common Workflows\n\n### Adding a New Code Example\n\n1. Navigate to the appropriate lesson directory\n2. Create example in `python/` or `typescript/` subdirectory\n3. Follow naming convention: `{provider}-{example-name}.{py|ts|js}`\n4. Test with actual API credentials\n5. Document any new environment variables in lesson README\n\n### Updating Documentation\n\n1. Edit README.md in the lesson directory\n2. Follow Markdown guidelines (tracking IDs, relative links)\n3. Update translations are handled by GitHub Actions (don't edit manually)\n4. Test all links are valid\n\n### Working with Dev Containers\n\n1. Repository includes `.devcontainer/devcontainer.json`\n2. Post-create script installs Python dependencies automatically\n3. Extensions for Python and Jupyter are pre-configured\n4. Environment is based on `mcr.microsoft.com/devcontainers/universal:2.11.2`\n\n## Deployment and Publishing\n\nThis is a learning repository - there is no deployment process. The curriculum is consumed by:\n\n1. **GitHub Repository**: Direct access to code and documentation\n2. **GitHub Codespaces**: Instant dev environment with pre-configured setup\n3. **Microsoft Learn**: Content may be syndicated to official learning platform\n4. **docsify**: Documentation site built from Markdown (see `docsifytopdf.js` and `package.json`)\n\n### Building Documentation Site\n\n```bash\n# Generate PDF from documentation (if needed)\nnpm run convert\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Python Import Errors**:\n- Ensure virtual environment is activated\n- Run `pip install -r requirements.txt`\n- Check Python version is 3.9+\n\n**TypeScript Build Errors**:\n- Run `npm install` in the specific app directory\n- Check Node.js version is compatible\n- Clear `node_modules` and reinstall if needed\n\n**API Authentication Errors**:\n- Verify `.env` file exists and has correct values\n- Check API keys are valid and not expired\n- Ensure endpoint URLs are correct for your region\n\n**Missing Environment Variables**:\n- Copy `.env.copy` to `.env`\n- Fill in all required values for the lesson you're working on\n- Restart your application after updating `.env`\n\n## Additional Resources\n\n- [Course Setup Guide](./00-course-setup/README.md?WT.mc_id=academic-105485-koreyst)\n- [Contributing Guidelines](./CONTRIBUTING.md)\n- [Code of Conduct](./CODE_OF_CONDUCT.md)\n- [Security Policy](./SECURITY.md)\n- [Azure AI Discord](https://aka.ms/genai-discord?WT.mc_id=academic-105485-koreyst)\n- [Collection of Advanced Code Samples](https://aka.ms/genai-beg-code?WT.mc_id=academic-105485-koreyst)\n\n## Project-Specific Notes\n\n- This is an **educational repository** focused on learning, not production code\n- Examples are intentionally simple and focused on teaching concepts\n- Code quality is balanced with educational clarity\n- Each lesson is self-contained and can be completed independently\n- The repository supports multiple API providers: Azure OpenAI, OpenAI, Microsoft Foundry Models, and offline providers such as Foundry Local and Ollama\n- Content is multilingual with automated translation workflows\n- Active community on Discord for questions and support\n","isInternal":false,"tokens":2827,"sizeBytes":12287},{"name":"cheat-sheet.md","path":".github/skills/azure-openai-to-responses/references/cheat-sheet.md","rawUrl":"https://raw.githubusercontent.com/microsoft/generative-ai-for-beginners/HEAD/.github/skills/azure-openai-to-responses/references/cheat-sheet.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Responses API Cheat Sheet (Python + Azure OpenAI)\n\n> All snippets assume `deployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]` and `client` is already initialized.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Client setup — API key\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\n## Client setup — EntraID (recommended)\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nfrom openai import OpenAI\n\ntoken_provider = get_bearer_token_provider(\n    DefaultAzureCredential(),\n    \"https://cognitiveservices.azure.com/.default\",\n)\nclient = OpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,\n)\n```\n\n## Async client setup\n\n```python\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,   # or api_key=os.environ[\"AZURE_OPENAI_API_KEY\"]\n)\n```\n\n## Basic request\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Full sync migration — before/after\n\nBefore (Chat Completions):\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\nresp = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n    max_tokens=500,\n)\nprint(resp.choices[0].message.content)\n```\n\nAfter (Responses API):\n```python\nfrom openai import OpenAI\ndeployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Multi-turn conversation\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a helpful coding assistant.\"},\n    {\"role\": \"user\", \"content\": \"Write a Python function to calculate factorial\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nmessages.append({\"role\": \"assistant\", \"content\": response.output_text})\nmessages.append({\"role\": \"user\", \"content\": \"Now optimize it with memoization\"})\nresponse2 = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nprint(response2.output_text)\n```\n\n## Streaming (sync)\n\n```python\nstream = client.responses.create(\n    model=deployment,\n    input=\"Explain streaming in simple terms\",\n    max_output_tokens=1000,\n    stream=True,\n)\nfor event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Streaming (async)\n\n```python\nstream = await client.responses.create(\n    model=deployment, input=\"...\", max_output_tokens=1000, stream=True,\n)\nasync for event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Structured output — JSON Schema\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"What is the capital of France?\",\n    max_output_tokens=500,\n    text={\n        \"format\": {\n            \"type\": \"json_schema\",\n            \"name\": \"Output\",\n            \"strict\": True,\n            \"schema\": {\n                \"type\": \"object\",\n                \"properties\": {\"answer\": {\"type\": \"string\"}},\n                \"required\": [\"answer\"],\n                \"additionalProperties\": False,\n            },\n        }\n    },\n    store=False,\n)\nimport json\ndata = json.loads(resp.output_text)\n```\n\n## Tools (flat Responses format)\n\n```python\ntools = [\n    {\n        \"type\": \"function\",\n        \"name\": \"lookup_weather\",\n        \"description\": \"Lookup the weather for a given city name.\",\n        \"parameters\": {\n            \"type\": \"object\",\n            \"properties\": {\"city_name\": {\"type\": \"string\", \"description\": \"The city name\"}},\n            \"required\": [\"city_name\"],\n            \"additionalProperties\": False,\n        },\n    }\n]\nresponse = client.responses.create(\n    model=deployment,\n    input=[\n        {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n        {\"role\": \"user\", \"content\": \"What's the weather in Berkeley?\"},\n    ],\n    tools=tools,\n    tool_choice=\"auto\",\n    store=False,\n)\n```\n\nTool call round-trip:\n```python\nimport json\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n    {\"role\": \"user\", \"content\": \"Is it sunny in Berkeley?\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\ntool_calls = [item for item in response.output if item.type == \"function_call\"]\nif tool_calls:\n    messages.extend(response.output)   # append the model's function_call items\n    for tc in tool_calls:\n        result = execute_tool(tc.name, json.loads(tc.arguments))\n        messages.append({\n            \"type\": \"function_call_output\",\n            \"call_id\": tc.call_id,\n            \"output\": json.dumps(result),\n        })\n    response = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\n    print(response.output_text)\n```\n\n> `openai.pydantic_function_tool()` still generates the old nested format and is **not** compatible with `responses.create()`. Define tool schemas manually.\n\n## Image input\n\nBefore (Chat): `{\"type\": \"image_url\", \"image_url\": {\"url\": \"...\"}}`\nAfter (Responses): `{\"type\": \"input_image\", \"image_url\": \"...\"}` (flat string — HTTPS URL or `data:image/...;base64,...`). Also `{\"type\": \"text\"}` → `{\"type\": \"input_text\"}`.\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What's in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.jpg\"},\n            ],\n        }\n    ],\n    max_output_tokens=500,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Reasoning models (o1, o3, o3-mini, o4-mini, GPT-5 family)\n\n| Chat Completions | Responses API | Notes |\n|---|---|---|\n| `max_completion_tokens` | `max_output_tokens` | Set high (4096+) |\n| `reasoning_effort` | `reasoning={\"effort\": ...}` | keep low/medium/high |\n| `temperature` | remove | GPT-5 rejects it outright (o-series only accepts `1`). To vary output, use a non-reasoning model such as `Llama-3.3-70B-Instruct` via Foundry Models. |\n| `top_p` | remove | not supported |\n| `seed` | remove | not supported |\n","isInternal":false,"tokens":1729,"sizeBytes":7044},{"name":"SKILL.md","path":".github/skills/azure-openai-to-responses/SKILL.md","rawUrl":"https://raw.githubusercontent.com/microsoft/generative-ai-for-beginners/HEAD/.github/skills/azure-openai-to-responses/SKILL.md","title":"azure-openai-to-responses","category":"anthropic-skill","format":"markdown","content":"---\nname: azure-openai-to-responses\ndescription: >-\n  Migrate Python apps from Azure OpenAI Chat Completions to the Responses API.\n  Covers AzureOpenAI/AsyncAzureOpenAI client migration to the v1 endpoint,\n  streaming, tools, structured output, multi-turn, EntraID auth, and model\n  compatibility checks. Python-focused, Azure OpenAI-specific.\n  USE FOR: migrate to responses API, switch from chat completions, openai responses,\n  upgrade openai SDK, responses API migration, move from completions to responses,\n  gpt-5 migration, azure openai python migration, chat completions to responses,\n  AzureOpenAI to OpenAI client, python azure openai upgrade.\n  DO NOT USE FOR: building new apps from scratch (start with responses directly),\n  Node/TypeScript/C#/Java/Go migrations (this skill is Python-only),\n  Azure infrastructure setup (use azure-prepare), deploying models (use microsoft-foundry).\nlicense: MIT\nsource: https://github.com/Azure-Samples/azure-openai-to-responses\n---\n\n# Migrate Python Apps from Azure OpenAI Chat Completions to Responses API\n\n> **AUTHORITATIVE GUIDANCE — FOLLOW EXACTLY**\n>\n> This skill migrates Python codebases using Azure OpenAI Chat Completions\n> to the unified Responses API. Follow these instructions precisely.\n> Do not improvise parameter mappings or invent API shapes.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Triggers\n\nActivate this skill when the user wants to:\n- Migrate a Python app from Azure OpenAI Chat Completions to Responses API\n- Upgrade Python OpenAI SDK usage to the latest API shape against Azure OpenAI\n- Prepare Python code for GPT-5 or newer models that require Responses on Azure\n- Switch from `AzureOpenAI`/`AsyncAzureOpenAI` to standard `OpenAI`/`AsyncOpenAI` client with the v1 endpoint\n- Fix deprecation warnings related to `AzureOpenAI` constructors or `api_version`\n\n## Why migrate\n\nGPT-5 and newer models require the Responses API. The new `/openai/v1/` endpoint\nuses the standard `OpenAI()` client instead of `AzureOpenAI()`, requires no\n`api_version` parameter, and works identically across OpenAI and Azure OpenAI.\n\n## What changes\n\n| Chat Completions (before) | Responses API (after) |\n| --- | --- |\n| `AzureOpenAI()` / `AsyncAzureOpenAI()` | `OpenAI(base_url=...)` / `AsyncOpenAI(base_url=...)` |\n| `azure_endpoint=...` | `base_url=f\"{endpoint.rstrip('/')}/openai/v1/\"` |\n| `api_version=\"2024-...\"` | Remove entirely — `/openai/v1/` is stable |\n| `azure_ad_token_provider=...` | `api_key=token_provider` |\n| `client.chat.completions.create(messages=...)` | `client.responses.create(input=...)` |\n| `resp.choices[0].message.content` | `resp.output_text` |\n| `max_tokens` | `max_output_tokens` (min 16 on Azure) |\n| `response_format` | `text={\"format\": {...}}` |\n| `seed` | **Remove** (not supported) |\n| tools nested `{\"type\":\"function\",\"function\":{...}}` | flat `{\"type\":\"function\",\"name\":...}` |\n| tool result `{\"role\":\"tool\",\"tool_call_id\":...}` | `{\"type\":\"function_call_output\",\"call_id\":...,\"output\":...}` |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` + `{\"url\": \"...\"}` | `content[].type: \"input_image\"` + flat `\"image_url\": \"...\"` |\n| streaming `chunk.choices[0].delta.content` | `event.type == \"response.output_text.delta\"` → `event.delta` |\n\n## Model compatibility — CHECK FIRST\n\nVerify the deployed model supports the Responses API before migrating. GPT-4o and\nGPT-4 support Responses for basic text/chat/streaming/tools but not all features.\nNewer models (gpt-4.1+, gpt-5.x) have full support. **GitHub Models\n(`models.github.ai`, `models.inference.ai.azure.com`) do NOT support the Responses\nAPI** — remove those code paths and switch to Azure OpenAI, OpenAI, or a compatible\nlocal endpoint.\n\nSmoke test:\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"ping\",\n    max_output_tokens=50,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Step 0: Client migration (prerequisite)\n\n`AzureOpenAI`/`AsyncAzureOpenAI` constructors are deprecated in `openai>=1.108.1`.\n\nBefore:\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\n```\n\nAfter:\n```python\nfrom openai import OpenAI\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\nCleanup: remove `api_version` args, remove `AZURE_OPENAI_API_VERSION` /\n`AZURE_OPENAI_VERSION` from `.env`/infra, rename `AZURE_OPENAI_CLIENT_ID` →\n`AZURE_CLIENT_ID`, ensure `openai>=1.108.1`.\n\n## Step 1: Detect legacy call sites\n\n```bash\nrg \"chat\\.completions\\.create\"        # legacy API calls\nrg \"ChatCompletion\\.create|Completion\\.create\"\nrg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"  # deprecated constructors\nrg \"choices\\[0\\]\\.message\\.content\"    # response access\nrg \"choices\\[0\\]\\.delta\\.content\"      # streaming access\nrg \"max_tokens\\b\"                      # rename to max_output_tokens\nrg \"['\\\"]seed['\\\"]\"                    # remove entirely\nrg \"response_format\"                   # → text.format\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"  # GitHub Models: remove\n```\n\n## Step 2: Apply migration\n\n- `client.chat.completions.create(messages=...)` → `client.responses.create(input=...)`\n- `resp.choices[0].message.content` → `resp.output_text`\n- `max_tokens` → `max_output_tokens` (min 16); remove `seed`\n- `response_format` → `text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`\n- Set `store=False` on every request (client-managed state)\n- Streaming: iterate events, handle `event.type == \"response.output_text.delta\"` (use `event.delta`) and `response.completed`\n- Tools: flat format, `tool_choice`, return results as `function_call_output` items; append `response.output` items for round-trips\n- Multi-turn: maintain conversation in an `input` array, or use `previous_response_id` (requires `store=True`)\n- Reasoning models (o-series, GPT-5): `max_completion_tokens` → `max_output_tokens` (4096+), `reasoning_effort` → `reasoning={\"effort\": ...}`, omit `temperature`/`top_p` (GPT-5 rejects `temperature` outright; to vary output use a non-reasoning model like `Llama-3.3-70B-Instruct` via Foundry Models)\n\n## Acceptance criteria (all must pass)\n\n- Zero matches for `chat.completions.create|ChatCompletion.create|Completion.create`\n- Zero matches for `AzureOpenAI(|AsyncAzureOpenAI(` — all use `OpenAI`/`AsyncOpenAI` + v1 endpoint\n- Zero matches for `models.github.ai|models.inference.ai.azure`\n- Zero matches for `choices[0]` — all access uses `resp.output_text` / Responses schema\n- No top-level `response_format`; structured output uses `text={\"format\": {...}}`\n- `openai>=1.108.1` in requirements; `store=False` on every call; no `api_version` in client construction\n- Tests updated (mocks use `kwargs.get(\"input\")`, snapshots use Responses shape); `pytest` passes\n\nSee [references/cheat-sheet.md](./references/cheat-sheet.md) for complete before/after code examples.\n\n## References\n\n- [Azure OpenAI Responses API docs](https://learn.microsoft.com/azure/ai-foundry/openai/how-to/responses)\n- [OpenAI Responses API reference](https://platform.openai.com/docs/api-reference/responses)\n- [Source skill: Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses)\n","frontmatter":{"name":"azure-openai-to-responses","description":"Migrate Python apps from Azure OpenAI Chat Completions to the Responses API. Covers AzureOpenAI/AsyncAzureOpenAI client migration to the v1 endpoint, streaming, tools, structured output, multi-turn, EntraID auth, and model compatibility checks. Python-focused, Azure OpenAI-specific. USE FOR: migrate to responses API, switch from chat completions, openai responses, upgrade openai SDK, responses API migration, move from completions to responses, gpt-5 migration, azure openai python migration, chat completions to responses, AzureOpenAI to OpenAI client, python azure openai upgrade. DO NOT USE FOR: building new apps from scratch (start with responses directly), Node/TypeScript/C#/Java/Go migrations (this skill is Python-only), Azure infrastructure setup (use azure-prepare), deploying models (use microsoft-foundry).","license":"MIT","source":"https://github.com/Azure-Samples/azure-openai-to-responses"},"isInternal":false,"tokens":2039,"sizeBytes":7796}],"systemPromptSnippet":"<yakaai_skills repo=\"microsoft/generative-ai-for-beginners\">\n<!-- File: AGENTS.md (Tokens: ~2827 | Category: root-instruction) -->\n# AGENTS.md\n\n## Project Overview\n\nThis repository contains a comprehensive 21-lesson curriculum teaching Generative AI fundamentals and application development. The course is designed for beginners and covers everything from basic concepts to building production-ready applications.\n\n**Key Technologies:**\n- Python 3.9+ with libraries: `openai`, `python-dotenv`, `tiktoken`, `azure-ai-inference`, `pandas`, `numpy`, `matplotlib`\n- TypeScript/JavaScript with Node.js and libraries: `openai` (Azure OpenAI via the v1 endpoint + Responses API), `@azure-rest/ai-inference` (Microsoft Foundry Models)\n- Azure OpenAI Service, OpenAI API, and Microsoft Foundry Models (GitHub Models is retiring end of July 2026)\n- Jupyter Notebooks for interactive learning\n- Dev Containers for consistent development environment\n\n**Repository Structure:**\n- 21 numbered lesson directories (00-21) containing READMEs, code examples, and assignments\n- Multiple implementations: Python, TypeScript, and sometimes .NET examples\n- Translations directory with 40+ language versions\n- Centralized configuration via `.env` file (use `.env.copy` as template)\n\n## Setup Commands\n\n### Initial Repository Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/microsoft/generative-ai-for-beginners.git\ncd generative-ai-for-beginners\n\n# Copy environment template\ncp .env.copy .env\n# Edit .env with your API keys and endpoints\n```\n\n### Python Environment Setup\n\n```bash\n# Create virtual environment\npython3 -m venv venv\n\n# Activate virtual environment\n# On macOS/Linux:\nsource venv/bin/activate\n# On Windows:\nvenv\\Scripts\\activate\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Node.js/TypeScript Setup\n\n```bash\n# Install root-level dependencies (for documentation tooling)\nnpm install\n\n# For individual lesson TypeScript examples, navigate to the specific lesson:\ncd 06-text-generation-apps/typescript/recipe-app\nnpm install\n```\n\n### Dev Container Setup (Recommended)\n\nThe repository includes a `.devcontainer` configuration for GitHub Codespaces or VS Code Dev Containers:\n\n1. Open repository in GitHub Codespaces or VS Code with Dev Containers extension\n2. Dev Container will automatically:\n   - Install Python dependencies from `requirements.txt`\n   - Run post-create script (`.devcontainer/post-create.sh`)\n   - Set up Jupyter kernel\n\n## Development Workflow\n\n### Environment Variables\n\nAll lessons requiring API access use environment variables defined in `.env`:\n\n- `OPENAI_API_KEY` - For OpenAI API\n- `AZURE_OPENAI_API_KEY` - For Azure OpenAI in Microsoft Foundry (Azure OpenAI Service is now part of Microsoft Foundry: https://ai.azure.com)\n- `AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint URL (Foundry resource endpoint)\n- `AZURE_OPENAI_DEPLOYMENT` - Chat completion model deployment name (course default: `gpt-5-mini`)\n- `AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT` - Embeddings model deployment name (course default: `text-embedding-3-small`)\n- `AZURE_OPENAI_API_VERSION` - API version (default: `2024-10-21`)\n- `HUGGING_FACE_API_KEY` - For Hugging Face models\n- `AZURE_INFERENCE_ENDPOINT` - Microsoft Foundry Models endpoint (multi-provider model catalog)\n- `AZURE_INFERENCE_CREDENTIAL` - Microsoft Foundry Models API key (replaces the retiring `GITHUB_TOKEN`)\n- `AZURE_INFERENCE_CHAT_MODEL` - A non-reasoning model (e.g. `Llama-3.3-70B-Instruct`) used by the `temperature` examples, since reasoning models don't support sampling controls\n\n### Model conventions (important)\n\n- **Default chat model is `gpt-5-mini`** - a current, non-deprecated **reasoning** model. As of 2026 the older temperature-capable \"mini\" models (`gpt-4o-mini`, `gpt-4.1-mini`) are *deprecating*, so the curriculum standardizes on the GPT-5 family.\n- **Reasoning models reject `temperature` and `top_p`**, and use `max_output_tokens` (Responses API) / `max_completion_tokens` (chat completions) instead of `max_tokens`. Do **not** add `temperature`/`top_p`/`max_tokens` to samples that call `gpt-5-mini`.\n- **To demonstrate `temperature`**, samples use a **Llama** model (`Llama-3.3-70B-Instruct`) via the Microsoft Foundry Models endpoint (`AZURE_INFERENCE_CHAT_MODEL`). Steer reasoning models with prompt engineering + reasoning controls instead of sampling knobs.\n- **Fine-tuning (lesson 18)** keeps `gpt-4.1-mini`: GPT-5 only supports reinforcement fine-tuning (RFT), not the supervised fine-tuning (SFT) shown there.\n- Lessons 20 (Mistral) and 21 (Meta) keep `temperature`/`max_tokens` because they target Mistral/Llama models, which support them.\n\n### Running Python Examples\n\n```bash\n# Navigate to lesson directory\ncd 06-text-generation-apps/python\n\n# Run a Python script\npython aoai-app.py\n```\n\n### Running TypeScript Examples\n\n```bash\n# Navigate to TypeScript app directory\ncd 06-text-generation-apps/typescript/recipe-app\n\n# Build the TypeScript code\nnpm run build\n\n# Run the application\nnpm start\n```\n\n### Running Jupyter Notebooks\n\n```bash\n# Start Jupyter in the repository root\njupyter notebook\n\n# Or use VS Code with Jupyter extension\n```\n\n### Working with Different Lesson Types\n\n- **\"Learn\" lessons**: Focus on README.md documentation and concepts\n- **\"Build\" lessons**: Include working code examples in Python and TypeScript\n- Each lesson has a README.md with theory, code walkthroughs, and links to video content\n\n## Code Style Guidelines\n\n### Python\n\n- Use `python-dotenv` for environment variable management\n- Import `openai` library for API interactions\n- Use `pylint` for linting (some examples include `# pylint: disable=all` for simplicity)\n- Follow PEP 8 naming conventions\n- Store API credentials in `.env` file, never in code\n\n### TypeScript\n\n- Use `dotenv` package for environment variables\n- TypeScript configuration in `tsconfig.json` for each app\n- Use the `openai` package for Azure OpenAI (point the client at the `/openai/v1/` endpoint and call `client.responses.create`); use `@azure-rest/ai-inference` for Microsoft Foundry Models\n- Use `nodemon` for development with auto-reload\n- Build before running: `npm run build` then `npm start`\n\n### General Conventions\n\n- Keep code examples simple and educational\n- Include comments explaining key concepts\n- Each lesson's code should be self-contained and runnable\n- Use consistent naming: `aoai-` prefix for Azure OpenAI, `oai-` for OpenAI API, `githubmodels-` for Microsoft Foundry Models (legacy prefix retained from the GitHub Models era)\n\n## Documentation Guidelines\n\n### Markdown Style\n\n- All URLs must be wrapped in `[text](url)` format with no extra spaces\n- Relative links must start with `./` or `../`\n- All links to Microsoft domains must include tracking ID: `?WT.mc_id=academic-105485-koreyst`\n- No country-specific locales in URLs (avoid `/en-us/`)\n- Images stored in `./images` folder with descriptive names\n- Use English characters, numbers, and dashes in file names\n\n### Translation Support\n\n- Repository supports 40+ languages via automated GitHub Actions\n- Translations stored in `translations/` directory\n- Do not submit partial translations\n- Machine translations are not accepted\n- Translated images stored in `translated_images/` directory\n\n## Testing and Validation\n\n### Pre-submission Checks\n\nThis repository uses GitHub Actions for validation. Before submitting PRs:\n\n1. **Check Markdown Links**:\n   ```bash\n   # The validate-markdown.yml workflow checks:\n   # - Broken relative paths\n   # - Missing tracking IDs on paths\n   # - Missing tracking IDs on URLs\n   # - URLs with country locale\n   # - Broken external URLs\n   ```\n\n2. **Manual Testing**:\n   - Test Python examples: Activate venv and run scripts\n   - Test TypeScript examples: `npm install`, `npm run build`, `npm start`\n   - Verify environment variables are configured correctly\n   - Check that API keys work with the code examples\n\n3. **Code Examples**:\n   - Ensure all code runs without errors\n   - Test with both Azure OpenAI and OpenAI API when applicable\n   - Verify examples work with Microsoft Foundry Models where supported\n\n### No Automated Tests\n\nThis is an educational repository focused on tutorials and examples. There are no unit tests or integration tests to run. Validation is primarily:\n- Manual testing of code examples\n- GitHub Actions for Markdown validation\n- Community review of educational content\n\n## Pull Request Guidelines\n\n### Before Submitting\n\n1. Test code changes in both Python and TypeScript when applicable\n2. Run Markdown validation (triggered automatically on PR)\n3. Ensure tracking IDs are present on all Microsoft URLs\n4. Check that relative links are valid\n5. Verify images are properly referenced\n\n### PR Title Format\n\n- Use descriptive titles: `[Lesson 06] Fix Python example typo` or `Update README for lesson 08`\n- Reference issue numbers when applicable: `Fixes #123`\n\n### PR Description\n\n- Explain what was changed and why\n- Link to related issues\n- For code changes, specify which examples were tested\n- For translation PRs, include all files for a complete translation\n\n### Contribution Requirements\n\n- Sign Microsoft CLA (automatic on first PR)\n- Fork repository to your account before making changes\n- One PR per logical change (don't combine unrelated fixes)\n- Keep PRs focused and small when possible\n\n## Common Workflows\n\n### Adding a New Code Example\n\n1. Navigate to the appropriate lesson directory\n2. Create example in `python/` or `typescript/` subdirectory\n3. Follow naming convention: `{provider}-{example-name}.{py|ts|js}`\n4. Test with actual API credentials\n5. Document any new environment variables in lesson README\n\n### Updating Documentation\n\n1. Edit README.md in the lesson directory\n2. Follow Markdown guidelines (tracking IDs, relative links)\n3. Update translations are handled by GitHub Actions (don't edit manually)\n4. Test all links are valid\n\n### Working with Dev Containers\n\n1. Repository includes `.devcontainer/devcontainer.json`\n2. Post-create script installs Python dependencies automatically\n3. Extensions for Python and Jupyter are pre-configured\n4. Environment is based on `mcr.microsoft.com/devcontainers/universal:2.11.2`\n\n## Deployment and Publishing\n\nThis is a learning repository - there is no deployment process. The curriculum is consumed by:\n\n1. **GitHub Repository**: Direct access to code and documentation\n2. **GitHub Codespaces**: Instant dev environment with pre-configured setup\n3. **Microsoft Learn**: Content may be syndicated to official learning platform\n4. **docsify**: Documentation site built from Markdown (see `docsifytopdf.js` and `package.json`)\n\n### Building Documentation Site\n\n```bash\n# Generate PDF from documentation (if needed)\nnpm run convert\n```\n\n## Troubleshooting\n\n### Common Issues\n\n**Python Import Errors**:\n- Ensure virtual environment is activated\n- Run `pip install -r requirements.txt`\n- Check Python version is 3.9+\n\n**TypeScript Build Errors**:\n- Run `npm install` in the specific app directory\n- Check Node.js version is compatible\n- Clear `node_modules` and reinstall if needed\n\n**API Authentication Errors**:\n- Verify `.env` file exists and has correct values\n- Check API keys are valid and not expired\n- Ensure endpoint URLs are correct for your region\n\n**Missing Environment Variables**:\n- Copy `.env.copy` to `.env`\n- Fill in all required values for the lesson you're working on\n- Restart your application after updating `.env`\n\n## Additional Resources\n\n- [Course Setup Guide](./00-course-setup/README.md?WT.mc_id=academic-105485-koreyst)\n- [Contributing Guidelines](./CONTRIBUTING.md)\n- [Code of Conduct](./CODE_OF_CONDUCT.md)\n- [Security Policy](./SECURITY.md)\n- [Azure AI Discord](https://aka.ms/genai-discord?WT.mc_id=academic-105485-koreyst)\n- [Collection of Advanced Code Samples](https://aka.ms/genai-beg-code?WT.mc_id=academic-105485-koreyst)\n\n## Project-Specific Notes\n\n- This is an **educational repository** focused on learning, not production code\n- Examples are intentionally simple and focused on teaching concepts\n- Code quality is balanced with educational clarity\n- Each lesson is self-contained and can be completed independently\n- The repository supports multiple API providers: Azure OpenAI, OpenAI, Microsoft Foundry Models, and offline providers such as Foundry Local and Ollama\n- Content is multilingual with automated translation workflows\n- Active community on Discord for questions and support\n\n<!-- File: .github/skills/azure-openai-to-responses/references/cheat-sheet.md (Tokens: ~1729 | Category: anthropic-skill) -->\n# Responses API Cheat Sheet (Python + Azure OpenAI)\n\n> All snippets assume `deployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]` and `client` is already initialized.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Client setup — API key\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\n## Client setup — EntraID (recommended)\n\n```python\nimport os\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nfrom openai import OpenAI\n\ntoken_provider = get_bearer_token_provider(\n    DefaultAzureCredential(),\n    \"https://cognitiveservices.azure.com/.default\",\n)\nclient = OpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,\n)\n```\n\n## Async client setup\n\n```python\nfrom openai import AsyncOpenAI\n\nclient = AsyncOpenAI(\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n    api_key=token_provider,   # or api_key=os.environ[\"AZURE_OPENAI_API_KEY\"]\n)\n```\n\n## Basic request\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Full sync migration — before/after\n\nBefore (Chat Completions):\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\nresp = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n    max_tokens=500,\n)\nprint(resp.choices[0].message.content)\n```\n\nAfter (Responses API):\n```python\nfrom openai import OpenAI\ndeployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=deployment,\n    input=\"Hello\",\n    max_output_tokens=1000,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Multi-turn conversation\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a helpful coding assistant.\"},\n    {\"role\": \"user\", \"content\": \"Write a Python function to calculate factorial\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nmessages.append({\"role\": \"assistant\", \"content\": response.output_text})\nmessages.append({\"role\": \"user\", \"content\": \"Now optimize it with memoization\"})\nresponse2 = client.responses.create(model=deployment, input=messages, max_output_tokens=400)\nprint(response2.output_text)\n```\n\n## Streaming (sync)\n\n```python\nstream = client.responses.create(\n    model=deployment,\n    input=\"Explain streaming in simple terms\",\n    max_output_tokens=1000,\n    stream=True,\n)\nfor event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Streaming (async)\n\n```python\nstream = await client.responses.create(\n    model=deployment, input=\"...\", max_output_tokens=1000, stream=True,\n)\nasync for event in stream:\n    if event.type == \"response.output_text.delta\":\n        print(event.delta, end=\"\", flush=True)\n    elif event.type == \"response.completed\":\n        print()\n```\n\n## Structured output — JSON Schema\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=\"What is the capital of France?\",\n    max_output_tokens=500,\n    text={\n        \"format\": {\n            \"type\": \"json_schema\",\n            \"name\": \"Output\",\n            \"strict\": True,\n            \"schema\": {\n                \"type\": \"object\",\n                \"properties\": {\"answer\": {\"type\": \"string\"}},\n                \"required\": [\"answer\"],\n                \"additionalProperties\": False,\n            },\n        }\n    },\n    store=False,\n)\nimport json\ndata = json.loads(resp.output_text)\n```\n\n## Tools (flat Responses format)\n\n```python\ntools = [\n    {\n        \"type\": \"function\",\n        \"name\": \"lookup_weather\",\n        \"description\": \"Lookup the weather for a given city name.\",\n        \"parameters\": {\n            \"type\": \"object\",\n            \"properties\": {\"city_name\": {\"type\": \"string\", \"description\": \"The city name\"}},\n            \"required\": [\"city_name\"],\n            \"additionalProperties\": False,\n        },\n    }\n]\nresponse = client.responses.create(\n    model=deployment,\n    input=[\n        {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n        {\"role\": \"user\", \"content\": \"What's the weather in Berkeley?\"},\n    ],\n    tools=tools,\n    tool_choice=\"auto\",\n    store=False,\n)\n```\n\nTool call round-trip:\n```python\nimport json\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are a weather chatbot.\"},\n    {\"role\": \"user\", \"content\": \"Is it sunny in Berkeley?\"},\n]\nresponse = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\ntool_calls = [item for item in response.output if item.type == \"function_call\"]\nif tool_calls:\n    messages.extend(response.output)   # append the model's function_call items\n    for tc in tool_calls:\n        result = execute_tool(tc.name, json.loads(tc.arguments))\n        messages.append({\n            \"type\": \"function_call_output\",\n            \"call_id\": tc.call_id,\n            \"output\": json.dumps(result),\n        })\n    response = client.responses.create(model=deployment, input=messages, tools=tools, store=False)\n    print(response.output_text)\n```\n\n> `openai.pydantic_function_tool()` still generates the old nested format and is **not** compatible with `responses.create()`. Define tool schemas manually.\n\n## Image input\n\nBefore (Chat): `{\"type\": \"image_url\", \"image_url\": {\"url\": \"...\"}}`\nAfter (Responses): `{\"type\": \"input_image\", \"image_url\": \"...\"}` (flat string — HTTPS URL or `data:image/...;base64,...`). Also `{\"type\": \"text\"}` → `{\"type\": \"input_text\"}`.\n\n```python\nresp = client.responses.create(\n    model=deployment,\n    input=[\n        {\n            \"role\": \"user\",\n            \"content\": [\n                {\"type\": \"input_text\", \"text\": \"What's in this image?\"},\n                {\"type\": \"input_image\", \"image_url\": \"https://example.com/image.jpg\"},\n            ],\n        }\n    ],\n    max_output_tokens=500,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Reasoning models (o1, o3, o3-mini, o4-mini, GPT-5 family)\n\n| Chat Completions | Responses API | Notes |\n|---|---|---|\n| `max_completion_tokens` | `max_output_tokens` | Set high (4096+) |\n| `reasoning_effort` | `reasoning={\"effort\": ...}` | keep low/medium/high |\n| `temperature` | remove | GPT-5 rejects it outright (o-series only accepts `1`). To vary output, use a non-reasoning model such as `Llama-3.3-70B-Instruct` via Foundry Models. |\n| `top_p` | remove | not supported |\n| `seed` | remove | not supported |\n\n<!-- File: .github/skills/azure-openai-to-responses/SKILL.md (Tokens: ~2039 | Category: anthropic-skill) -->\n---\nname: azure-openai-to-responses\ndescription: >-\n  Migrate Python apps from Azure OpenAI Chat Completions to the Responses API.\n  Covers AzureOpenAI/AsyncAzureOpenAI client migration to the v1 endpoint,\n  streaming, tools, structured output, multi-turn, EntraID auth, and model\n  compatibility checks. Python-focused, Azure OpenAI-specific.\n  USE FOR: migrate to responses API, switch from chat completions, openai responses,\n  upgrade openai SDK, responses API migration, move from completions to responses,\n  gpt-5 migration, azure openai python migration, chat completions to responses,\n  AzureOpenAI to OpenAI client, python azure openai upgrade.\n  DO NOT USE FOR: building new apps from scratch (start with responses directly),\n  Node/TypeScript/C#/Java/Go migrations (this skill is Python-only),\n  Azure infrastructure setup (use azure-prepare), deploying models (use microsoft-foundry).\nlicense: MIT\nsource: https://github.com/Azure-Samples/azure-openai-to-responses\n---\n\n# Migrate Python Apps from Azure OpenAI Chat Completions to Responses API\n\n> **AUTHORITATIVE GUIDANCE — FOLLOW EXACTLY**\n>\n> This skill migrates Python codebases using Azure OpenAI Chat Completions\n> to the unified Responses API. Follow these instructions precisely.\n> Do not improvise parameter mappings or invent API shapes.\n\nInstalled from [Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses) (MIT).\n\n## Triggers\n\nActivate this skill when the user wants to:\n- Migrate a Python app from Azure OpenAI Chat Completions to Responses API\n- Upgrade Python OpenAI SDK usage to the latest API shape against Azure OpenAI\n- Prepare Python code for GPT-5 or newer models that require Responses on Azure\n- Switch from `AzureOpenAI`/`AsyncAzureOpenAI` to standard `OpenAI`/`AsyncOpenAI` client with the v1 endpoint\n- Fix deprecation warnings related to `AzureOpenAI` constructors or `api_version`\n\n## Why migrate\n\nGPT-5 and newer models require the Responses API. The new `/openai/v1/` endpoint\nuses the standard `OpenAI()` client instead of `AzureOpenAI()`, requires no\n`api_version` parameter, and works identically across OpenAI and Azure OpenAI.\n\n## What changes\n\n| Chat Completions (before) | Responses API (after) |\n| --- | --- |\n| `AzureOpenAI()` / `AsyncAzureOpenAI()` | `OpenAI(base_url=...)` / `AsyncOpenAI(base_url=...)` |\n| `azure_endpoint=...` | `base_url=f\"{endpoint.rstrip('/')}/openai/v1/\"` |\n| `api_version=\"2024-...\"` | Remove entirely — `/openai/v1/` is stable |\n| `azure_ad_token_provider=...` | `api_key=token_provider` |\n| `client.chat.completions.create(messages=...)` | `client.responses.create(input=...)` |\n| `resp.choices[0].message.content` | `resp.output_text` |\n| `max_tokens` | `max_output_tokens` (min 16 on Azure) |\n| `response_format` | `text={\"format\": {...}}` |\n| `seed` | **Remove** (not supported) |\n| tools nested `{\"type\":\"function\",\"function\":{...}}` | flat `{\"type\":\"function\",\"name\":...}` |\n| tool result `{\"role\":\"tool\",\"tool_call_id\":...}` | `{\"type\":\"function_call_output\",\"call_id\":...,\"output\":...}` |\n| `content[].type: \"text\"` | `content[].type: \"input_text\"` |\n| `content[].type: \"image_url\"` + `{\"url\": \"...\"}` | `content[].type: \"input_image\"` + flat `\"image_url\": \"...\"` |\n| streaming `chunk.choices[0].delta.content` | `event.type == \"response.output_text.delta\"` → `event.delta` |\n\n## Model compatibility — CHECK FIRST\n\nVerify the deployed model supports the Responses API before migrating. GPT-4o and\nGPT-4 support Responses for basic text/chat/streaming/tools but not all features.\nNewer models (gpt-4.1+, gpt-5.x) have full support. **GitHub Models\n(`models.github.ai`, `models.inference.ai.azure.com`) do NOT support the Responses\nAPI** — remove those code paths and switch to Azure OpenAI, OpenAI, or a compatible\nlocal endpoint.\n\nSmoke test:\n\n```python\nimport os\nfrom openai import OpenAI\n\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\nresp = client.responses.create(\n    model=os.environ[\"AZURE_OPENAI_DEPLOYMENT\"],\n    input=\"ping\",\n    max_output_tokens=50,\n    store=False,\n)\nprint(resp.output_text)\n```\n\n## Step 0: Client migration (prerequisite)\n\n`AzureOpenAI`/`AsyncAzureOpenAI` constructors are deprecated in `openai>=1.108.1`.\n\nBefore:\n```python\nfrom openai import AzureOpenAI\nclient = AzureOpenAI(\n    api_version=os.environ[\"AZURE_OPENAI_API_VERSION\"],\n    azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n)\n```\n\nAfter:\n```python\nfrom openai import OpenAI\nclient = OpenAI(\n    api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n    base_url=f\"{os.environ['AZURE_OPENAI_ENDPOINT'].rstrip('/')}/openai/v1/\",\n)\n```\n\nCleanup: remove `api_version` args, remove `AZURE_OPENAI_API_VERSION` /\n`AZURE_OPENAI_VERSION` from `.env`/infra, rename `AZURE_OPENAI_CLIENT_ID` →\n`AZURE_CLIENT_ID`, ensure `openai>=1.108.1`.\n\n## Step 1: Detect legacy call sites\n\n```bash\nrg \"chat\\.completions\\.create\"        # legacy API calls\nrg \"ChatCompletion\\.create|Completion\\.create\"\nrg \"AzureOpenAI\\(|AsyncAzureOpenAI\\(\"  # deprecated constructors\nrg \"choices\\[0\\]\\.message\\.content\"    # response access\nrg \"choices\\[0\\]\\.delta\\.content\"      # streaming access\nrg \"max_tokens\\b\"                      # rename to max_output_tokens\nrg \"['\\\"]seed['\\\"]\"                    # remove entirely\nrg \"response_format\"                   # → text.format\nrg \"AZURE_OPENAI_API_VERSION|AZURE_OPENAI_VERSION\"\nrg \"models\\.github\\.ai|models\\.inference\\.ai\\.azure\"  # GitHub Models: remove\n```\n\n## Step 2: Apply migration\n\n- `client.chat.completions.create(messages=...)` → `client.responses.create(input=...)`\n- `resp.choices[0].message.content` → `resp.output_text`\n- `max_tokens` → `max_output_tokens` (min 16); remove `seed`\n- `response_format` → `text={\"format\": {\"type\": \"json_schema\", \"name\": \"Output\", \"strict\": True, \"schema\": {...}}}`\n- Set `store=False` on every request (client-managed state)\n- Streaming: iterate events, handle `event.type == \"response.output_text.delta\"` (use `event.delta`) and `response.completed`\n- Tools: flat format, `tool_choice`, return results as `function_call_output` items; append `response.output` items for round-trips\n- Multi-turn: maintain conversation in an `input` array, or use `previous_response_id` (requires `store=True`)\n- Reasoning models (o-series, GPT-5): `max_completion_tokens` → `max_output_tokens` (4096+), `reasoning_effort` → `reasoning={\"effort\": ...}`, omit `temperature`/`top_p` (GPT-5 rejects `temperature` outright; to vary output use a non-reasoning model like `Llama-3.3-70B-Instruct` via Foundry Models)\n\n## Acceptance criteria (all must pass)\n\n- Zero matches for `chat.completions.create|ChatCompletion.create|Completion.create`\n- Zero matches for `AzureOpenAI(|AsyncAzureOpenAI(` — all use `OpenAI`/`AsyncOpenAI` + v1 endpoint\n- Zero matches for `models.github.ai|models.inference.ai.azure`\n- Zero matches for `choices[0]` — all access uses `resp.output_text` / Responses schema\n- No top-level `response_format`; structured output uses `text={\"format\": {...}}`\n- `openai>=1.108.1` in requirements; `store=False` on every call; no `api_version` in client construction\n- Tests updated (mocks use `kwargs.get(\"input\")`, snapshots use Responses shape); `pytest` passes\n\nSee [references/cheat-sheet.md](./references/cheat-sheet.md) for complete before/after code examples.\n\n## References\n\n- [Azure OpenAI Responses API docs](https://learn.microsoft.com/azure/ai-foundry/openai/how-to/responses)\n- [OpenAI Responses API reference](https://platform.openai.com/docs/api-reference/responses)\n- [Source skill: Azure-Samples/azure-openai-to-responses](https://github.com/Azure-Samples/azure-openai-to-responses)\n</yakaai_skills>"}