Commit 73df0d7
Add C# toolbox-auth-paths hosted-agent sample (#402)
* Add C# toolbox auth-paths hosted-agent sample and wire cloud E2E
Add samples/csharp/hosted-agents/agent-framework/toolbox-auth-paths, an
Agent Framework hosted agent that loads a multi-tool Foundry Toolbox
demonstrating the authentication paths a toolbox MCP tool can use to
reach its upstream server: key-based (CustomKeys connection) and public
no-auth. Foundry resolves each tool credential server-side, so the agent
code carries no auth logic.
Wire the sample into hosted-agents-cloud-e2e.yml as a self-provisioning
cell. A guarded self_provision flag (set only for this sample) forces a
single matrix cell instead of the toolbox cartesian product, runs azd
provision so the connection and toolbox are created from the manifest
resources, sources the provisioning PAT from the GH_PAT secret, and
fails fast when no real PAT is configured. Teardown stays gated on
SKIP_PROVISION to match the shared project status quo.
Add the CI invoke payload under internal/tools/samples-hosted-agents and
list the sample in the agent-framework README sample index.
* Drop self-provision CI path and remove no-auth toolbox entry
Revert hosted-agents-cloud-e2e.yml to origin/main: the self_provision
flag was a net-new strategy with no precedent in CI. Toolbox samples run
with SKIP_PROVISION=true and consume a toolbox pre-registered in the
TOOLBOX_ENDPOINT repo variable (like langgraph-toolbox), so no PAT is
provisioned in CI.
Remove the public no-auth path from toolbox-auth-paths: an auth sample
should only demonstrate authenticated paths. Toolbox now exposes only the
key-based CustomKeys GitHub tool; Entra agent identity stays documented.
Rework the sample README to be developer-runnable (azd provision or manual
toolbox creation in your own project) and document the out-of-band CI
registration without naming individuals. Interacting section now uses
azd ai agent invoke --local. Trim payloads to the github prompts.
* Remove redundant test-payload.txt from toolbox-auth-paths sample
CI reads invoke prompts from internal/tools/samples-hosted-agents, and
the build context strips test-payload.txt, so the sample-dir copy is
unused. Drop it and fix the dangling README link.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rename github_pat secret parameter to gh_pat in toolbox-auth-paths
GitHub forbids creating secrets/variables whose names start with the
GITHUB_ prefix (case-insensitive), and azd resolves a manifest secret
parameter from an env var of the same name. The github_pat parameter
therefore could not be wired in the e2e Foundry project.
Rename the parameter (and its {{ }} placeholder) to gh_pat, matching the
existing GH_PAT secret already used by the cloud-e2e workflow. The
scaffold step now exports both github_pat (other toolbox samples) and
gh_pat. Docs updated; token-format mentions (github_pat_...) left intact.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix gh_pat secret resolution in cloud-e2e scaffold (uppercase env var)
azd ai agent init --no-prompt resolves a manifest secret parameter from an
env var named after the parameter UPPERCASED (gh_pat -> GH_PAT). The scaffold
step set a lowercase gh_pat env var, so azd could not find it and failed with
'unable to prompt for secret parameter gh_pat in no-prompt mode'.
Set GH_PAT (uppercase) instead and correct the explanatory comment. The
manifest parameter stays lowercase gh_pat; azd uppercases it to find GH_PAT.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use map form for gh_pat secret parameter so azd resolves it
azd ai agent init --no-prompt only binds a manifest secret parameter to an
env var when parameters use the map form (parameters: <name>:). The
toolbox-auth-paths manifest used the array form (parameters: properties:
- name:), where 'secret' is not a schema field, so azd recognized the
parameter name but never looked up its env var — failing with 'unable to
prompt for secret parameter gh_pat in no-prompt mode' regardless of the env
var set.
Switch to the map form (matching the browser-automation/langgraph-toolbox
samples). Also export a lowercase gh_pat env var alongside GH_PAT so azd
resolves the value whether it uppercases the parameter name or not.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Drop lowercase gh_pat env var (case-collides with GH_PAT)
GitHub rejects a workflow whose env block defines names differing only by
case (GH_PAT vs gh_pat) -> 'workflow file issue', no jobs run. Keep only the
uppercase GH_PAT, which is what azd resolves the gh_pat secret parameter from
(azd uppercases the parameter name).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Exclude toolbox-auth-paths x code-interpreter combo (known SDK bug)
The csharp code-interpreter combo triggers an 'invalid_payload' on
/tools/0/container (container serialized as null) — a known .NET Agent
Framework SDK bug in Microsoft.Agents.AI.Foundry.Hosting that cannot be
fixed from this repo. The matrix already excludes this combo for the
sibling foundry-toolbox-server-side sample; add the new toolbox-auth-paths
sample to the same exclusion so the matrix doesn't gate on the known defect.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rework toolbox-auth-paths to AddFoundryToolboxes (latest Hosting SDK)
The sample pinned Microsoft.Agents.AI.Foundry.Hosting 1.3.0-preview and used
GetToolboxToolsAsync() to pass the toolbox's tools to the agent as server-side
MCP tools. Those tools default to AlwaysRequire approval, so the model's tool
call returned an unhandled approval request and the hosted handler dropped it —
the agent responded with an empty output (silent), even though CI marked it
'completed'.
Bump to the latest 1.9.0-preview and adopt the AddFoundryToolboxes pattern
(matching the AF repo Hosted-Toolbox sample). The hosting layer now connects to
the toolbox MCP proxy at startup and exposes its tools as host-executed
functions — no server-side approval gate — so the agent actually calls the tool
and returns a real answer.
Verified locally against a Foundry project: POST /responses now returns
function_call + function_call_output + a text message (was output: []).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Derive toolset endpoint from project endpoint when not injected
The previous run revealed the CI hosted container does NOT inject
FOUNDRY_AGENT_TOOLSET_ENDPOINT, so AddFoundryToolboxes disabled toolbox
support and the agent answered from the model alone (a hallucinated, toolless
response that still passed CI). Derive FOUNDRY_AGENT_TOOLSET_ENDPOINT from
FOUNDRY_PROJECT_ENDPOINT (<project>/toolboxes) when the platform doesn't set
it, so the toolbox actually loads.
Verified locally: with only FOUNDRY_PROJECT_ENDPOINT set, the host derives the
toolset endpoint, discovers the toolbox tools, and POST /responses returns
function_call + function_call_output + a text message.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Work around toolbox token audience mismatch (cognitiveservices vs ai.azure.com)
CI showed the toolbox failing to connect with 401 'audience is incorrect
(https://ai.azure.com)'. The Hosting SDK's toolbox token handler requests a
https://cognitiveservices.azure.com token, but the Foundry toolbox MCP proxy
(both the test project and the CI project) requires https://ai.azure.com — so
the toolbox silently failed to load and the agent answered from the model alone.
Register a TokenCredential for the toolbox connection that maps the
cognitiveservices.azure.com audience to ai.azure.com. Verified locally against a
Foundry project: the toolbox now discovers its tools and POST /responses returns
function_call + function_call_output + a text message grounded in the tool.
This is a workaround for an SDK audience bug; the proper fix belongs in
Microsoft.Agents.AI.Foundry.Hosting.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Bump MAF Hosting to 1.10.0 and drop toolbox audience workaround
Microsoft.Agents.AI.Foundry.Hosting 1.10.0-preview.260610.1 requests the
correct https://ai.azure.com token audience for the Foundry toolbox MCP
proxy, so the FoundryToolsetCredential audience-rewrite workaround is no
longer needed. Removed the credential, its DI registration, and the now
unused Azure.Core using.
Verified locally against tao-foundry-prj: the toolbox discovers 51 tools
and the agent answers a GitHub search prompt end-to-end (function_call +
function_call_output + message), with no workaround.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 9194f85 commit 73df0d7
9 files changed
Lines changed: 345 additions & 2 deletions
File tree
- samples/csharp/hosted-agents/agent-framework
- toolbox-auth-paths
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | | - | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
20 | 27 | | |
21 | 28 | | |
22 | 29 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
Lines changed: 12 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
Lines changed: 88 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
Lines changed: 114 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
Lines changed: 60 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
Lines changed: 14 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
Lines changed: 20 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
0 commit comments