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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.azure/
.git/
**/.env
**/.env.*
**/build/
**/bin/
**/obj/
01-MAF-Agent-CS/
02-MAF-Agent-CS-Hosted/
03-MAF-Agent-GO/
04-MAF-Agent-GO-Hosted/
docs/
*.md
*.slnx
93 changes: 93 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copilot instructions for this repository

## Terminology

Always say **"Microsoft Foundry"**. Never use "Azure AI Foundry" (the old
product name) in code, comments, docs, or commit messages — including in
new content you write and when fixing existing content that uses the old
name. This also applies to related product nouns: prefer "Foundry Project"
over "Azure AI Project" in prose (e.g. "calls a model deployment in a
Microsoft Foundry Project").

This rule applies to prose only — do NOT rename literal SDK/package/class
identifiers that happen to contain "AI" (e.g. the `Azure.AI.Projects` NuGet
package, the `AIProjectClient` class). Those are real, versioned API names
and must stay exactly as published upstream.

## What this repo is

A set of six small, independent sample apps showing Microsoft Agent Framework
(MAF) agents backed by Microsoft Foundry, across three languages (C#, Go,
C++) and two hosting styles (console app vs. hosted agent). There is no
shared runtime code between samples — each folder is self-contained with its
own dependency manifest, build system, and README.

## Foundry agent work

This project was built with the `microsoft-foundry` skill. Before working on
or answering questions about Foundry agents (deploy, invoke, evaluate,
troubleshoot, scaffold new agents, etc.), read that skill first — see
[AGENTS.md](/d:/azure-samples/microsoft-foundry-hosted-agents/AGENTS.md).

## Folder naming convention

Folders are numbered by build/complexity order and named
`NN-<Language>-Agent-<Tech>[-Hosted]`:

| Folder | Language | Type |
|---|---|---|
| [01-MAF-Agent-CS](/d:/azure-samples/microsoft-foundry-hosted-agents/01-MAF-Agent-CS) | C# | Console app |
| [02-MAF-Agent-CS-Hosted](/d:/azure-samples/microsoft-foundry-hosted-agents/02-MAF-Agent-CS-Hosted) | C# | Hosted agent |
| [03-MAF-Agent-GO](/d:/azure-samples/microsoft-foundry-hosted-agents/03-MAF-Agent-GO) | Go | Console app |
| [04-MAF-Agent-GO-Hosted](/d:/azure-samples/microsoft-foundry-hosted-agents/04-MAF-Agent-GO-Hosted) | Go | Hosted agent |
| [05-Foundry-Agent-CPP](/d:/azure-samples/microsoft-foundry-hosted-agents/05-Foundry-Agent-CPP) | C++ | Console app |
| [06-Foundry-Agent-CPP-Hosted](/d:/azure-samples/microsoft-foundry-hosted-agents/06-Foundry-Agent-CPP-Hosted) | C++ | Hosted agent |

The C++ folders intentionally use `Foundry-Agent-CPP` (not `MAF-Agent-CPP`)
because Microsoft Foundry / Microsoft Agent Framework do not provide a
first-party C++ agent SDK — the C++ samples are repository-owned adapters,
not MAF SDK usage. See
[docs/research/cpp-agents-with-microsoft-foundry.md](/d:/azure-samples/microsoft-foundry-hosted-agents/docs/research/cpp-agents-with-microsoft-foundry.md).

**Critical policy when renaming, moving, or refactoring folders:** folder
names, file paths, and prose/doc references may be changed freely, but the
following internal/deployed identifiers must NOT be changed just because a
folder was renamed, since changing them can break existing Foundry
deployments or violate language constraints:

- `name:` / service keys in each sample's `azure.yaml` (azd deployment
identifiers, e.g. `maf-agent-cs-02`, `maf-agent-go-04`, `maf-agent-cpp-06`)
- CMake `project(...)` names, target names, and `option(...)` names in
`CMakeLists.txt`
- `vcpkg.json` `name` fields
- Go module import paths (`go.mod`)
- C# `RootNamespace` in `.csproj` files (C# identifiers can't start with a
digit, so these stay like `MAF_Agent_CS_01`)

The only path-like references inside those same files that DO need to track
a rename are hard functional dependencies, e.g. `entryPoint` (dll filename)
in `azure.yaml`, the source-path argument of `add_subdirectory(...)` in
CMakeLists.txt, Dockerfile `COPY`/`WORKDIR` paths, and CI workflow matrix
values / cache-key globs in
[.github/workflows/build.yml](/d:/azure-samples/microsoft-foundry-hosted-agents/.github/workflows/build.yml).

Historical/dated docs (e.g. research reports with footnote links pinned to a
specific commit SHA) should be left as frozen snapshots, not rewritten to
match current folder names.

## Build, run, test

- **.NET**: `dotnet build .\MAF-Agents-Samples.slnx` builds both C# samples.
- **Go**: each Go sample is built/tested independently from its own folder
(`go build ./...`, `go test ./...`); there is no top-level Go workspace.
- **C++**: each C++ sample uses its own `CMakePresets.json` (`debug` preset)
with vcpkg for dependencies; `06-Foundry-Agent-CPP-Hosted` depends on
`05-Foundry-Agent-CPP` via `add_subdirectory`, so `05` must be buildable on
its own first.
- CI (`.github/workflows/build.yml`) runs all three toolchains on every push
and PR to `main` without needing Foundry credentials — it only validates
that code compiles and unit tests pass, not live Foundry calls.

See the root [README.md](/d:/azure-samples/microsoft-foundry-hosted-agents/README.md) for prerequisites (Foundry project endpoint, model
deployment name, tooling versions) and per-sample READMEs for
language-specific details.
38 changes: 37 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
module: [MAF-Agent-GO-03, MAF-Agent-GO-04]
module: [03-MAF-Agent-GO, 04-MAF-Agent-GO-Hosted]
steps:
- uses: actions/checkout@v4

Expand All @@ -42,3 +42,39 @@ jobs:
- name: Test
working-directory: ${{ matrix.module }}
run: go test ./...

cpp-build:
name: Build and test C++ samples
runs-on: ubuntu-latest
strategy:
matrix:
module: [05-Foundry-Agent-CPP, 06-Foundry-Agent-CPP-Hosted]
steps:
- uses: actions/checkout@v4

- name: Install build tools
run: sudo apt-get update && sudo apt-get install -y ninja-build

- name: Bootstrap vcpkg
run: |
git clone https://github.com/microsoft/vcpkg "$HOME/vcpkg"
"$HOME/vcpkg/bootstrap-vcpkg.sh" -disableMetrics
echo "VCPKG_ROOT=$HOME/vcpkg" >> "$GITHUB_ENV"

- name: Cache vcpkg binaries
uses: actions/cache@v4
with:
path: ~/.cache/vcpkg/archives
key: ${{ runner.os }}-vcpkg-${{ hashFiles('0[56]-*CPP*/vcpkg.json', '0[56]-*CPP*/vcpkg-configuration.json') }}

- name: Configure
working-directory: ${{ matrix.module }}
run: cmake --preset debug

- name: Build
working-directory: ${{ matrix.module }}
run: cmake --build --preset debug

- name: Test
working-directory: ${{ matrix.module }}
run: ctest --preset debug
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,11 @@ vendor/
.env.*
!.env.example
.azure/

# CMake and vcpkg artifacts
build/
vcpkg_installed/
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
CTestTestfile.cmake
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
codeConfiguration:
dependencyResolution: bundled
entryPoint: MAF-Agent-CS-02.dll
entryPoint: 02-MAF-Agent-CS-Hosted.dll
runtime: dotnet_10
container:
resources:
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion MAF-Agent-GO-03/README.md → 03-MAF-Agent-GO/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MAF-Agent-GO-03
# 03-MAF-Agent-GO

This console sample uses the Microsoft Agent Framework for Go with a Microsoft Foundry project-backed agent.

Expand Down
File renamed without changes.
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MAF-Agent-GO-04
# 04-MAF-Agent-GO-Hosted

This sample hosts a Microsoft Agent Framework Go agent as a containerized Microsoft Foundry Hosted Agent. It exposes `/invocations` for plain-text chat prompts and provides `/readiness` for platform health checks. The same endpoint also supports optional Agent Framework Go AG-UI JSON requests with Server-Sent Events (SSE) responses.

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions 05-Foundry-Agent-CPP/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FOUNDRY_PROJECT_ENDPOINT=
AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-5-mini
61 changes: 61 additions & 0 deletions 05-Foundry-Agent-CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.25)

project(maf_agent_cpp_05 VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(azure-core-cpp CONFIG REQUIRED)
find_package(azure-identity-cpp CONFIG REQUIRED)
find_package(CURL REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)

add_library(foundry_agent STATIC
src/agent.cpp
src/config.cpp
src/http_transport.cpp
)
add_library(FoundryAgent::foundry_agent ALIAS foundry_agent)

target_include_directories(foundry_agent
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
target_link_libraries(foundry_agent
PUBLIC
Azure::azure-core
Azure::azure-identity
CURL::libcurl
nlohmann_json::nlohmann_json
)
target_compile_features(foundry_agent PUBLIC cxx_std_20)

if(MSVC)
target_compile_options(foundry_agent PRIVATE /W4 /permissive-)
else()
target_compile_options(foundry_agent PRIVATE -Wall -Wextra -Wpedantic)
endif()

add_executable(maf_agent_cpp_05 src/main.cpp)
target_link_libraries(maf_agent_cpp_05 PRIVATE FoundryAgent::foundry_agent)

option(MAF_CPP05_BUILD_TESTS "Build MAF-Agent-CPP-05 tests" ON)
if(MAF_CPP05_BUILD_TESTS)
include(CTest)
find_package(Catch2 3 CONFIG REQUIRED)

add_executable(maf_agent_cpp_05_tests
tests/agent_tests.cpp
tests/config_tests.cpp
)
target_include_directories(maf_agent_cpp_05_tests PRIVATE tests)
target_link_libraries(maf_agent_cpp_05_tests
PRIVATE
FoundryAgent::foundry_agent
Catch2::Catch2WithMain
)

include(Catch)
catch_discover_tests(maf_agent_cpp_05_tests)
endif()
55 changes: 55 additions & 0 deletions 05-Foundry-Agent-CPP/CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 0
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "debug",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"MAF_CPP05_BUILD_TESTS": "ON"
}
},
{
"name": "release",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"MAF_CPP05_BUILD_TESTS": "OFF"
}
}
],
"buildPresets": [
{
"name": "debug",
"configurePreset": "debug"
},
{
"name": "release",
"configurePreset": "release"
}
],
"testPresets": [
{
"name": "debug",
"configurePreset": "debug",
"output": {
"outputOnFailure": true
}
}
]
}
64 changes: 64 additions & 0 deletions 05-Foundry-Agent-CPP/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 05-Foundry-Agent-CPP

This C++20 console sample calls a model deployment in a Microsoft Foundry Project, prints one answer, and exits. It mirrors the local C# and Go samples.

Microsoft does not currently provide a Foundry agent SDK for C++. This sample uses first-party [`azure-identity-cpp`](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/identity/azure-identity) for `DefaultAzureCredential`, then uses a small repository-owned libcurl client for the project-scoped OpenAI Responses endpoint. See the [C++ research report](../docs/research/cpp-agents-with-microsoft-foundry.md) for alternatives and support boundaries.

## Prerequisites

- CMake 3.25 or later
- Ninja
- A C++20-capable compiler
- [vcpkg](https://vcpkg.io), with `VCPKG_ROOT` set
- Azure CLI signed in with `az login`, or another `DefaultAzureCredential` source
- A Foundry Project with a deployed model

## Configure

```powershell
$env:FOUNDRY_PROJECT_ENDPOINT = "https://<resource>.services.ai.azure.com/api/projects/<project>"
$env:AZURE_AI_MODEL_DEPLOYMENT_NAME = "gpt-5-mini"
```

The model deployment variable is optional and defaults to `gpt-5-mini`. The project endpoint must use HTTPS and retain `/api/projects/<project>`.

## Build and test

From this directory:

```powershell
cmake --preset debug
cmake --build --preset debug
ctest --preset debug
```

The tests inject both the credential and HTTP transport, so they do not require Azure access.

## Run

Windows:

```powershell
.\build\debug\maf_agent_cpp_05.exe
```

Linux or macOS:

```bash
./build/debug/maf_agent_cpp_05
```

The request uses token scope `https://ai.azure.com/.default` and posts to:

```text
<FOUNDRY_PROJECT_ENDPOINT>/openai/v1/responses
```

## Initial limitations

- Non-streaming
- No tools
- No conversation state
- Repository-owned Foundry REST adapter, with no first-party C++ SDK support commitment

This sample has unit coverage designed for offline execution. A live Foundry call must be validated against your own project and permissions.
Loading
Loading