You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add content safety guardrail sample for the invocations protocol - #1019
samples/python/hosted-agents/agent-framework/invocations/02-content-safety-guardrail — the invocations counterpart to the existing responses guardrail sample.
Why
On the responses protocol the platform knows the payload shape, so attaching an RAI policy is enough. On invocations the request and response bodies are agent-defined, so a policy on its own screens nothing — it is attached and inert.
The sample shows the accompanying invocationsModeration block that tells the platform where the prompt and response text live:
Note textField: text is a field name, not a path expression. A $-prefixed value silently matches nothing and leaves streamed output unscreened; that footgun is fixed separately in Azure/azure-dev#9791 / Azure/azure-dev#10130, and this sample follows the corrected form.
responseMode: both declares a capability, not "input and output" — the agent answers buffered and streamed requests, and the platform picks exactly one gate at runtime from the response Content-Type.
Dockerfile is the uv template used by the sibling guardrail sample, so codeConfiguration.runtime: python_3_13 and the image base agree.
test-spec.yml, the preferred behavior contract, rather than the legacy test-payload.txt.
The contract asserts that benign traffic still flows through both gates untouched. It deliberately does not assert blocking: that needs a real RAI policy, and the sample ships a placeholder ID. Benign pass-through is the deterministic signal that regresses if the moderation wiring is wrong.
Validation run locally
Check
Result
check_hosted_agent_contracts.py --base <merge-base> --head HEAD
Validated behavior contracts for 1 new hosted-agent sample(s).
hosted_agent_test_spec.py plan --protocol invocations
plan generated, test applicable
uv lock --check (uv 0.11.7)
resolved, lock current
ruff check / black --check
clean
The end-to-end guardrail behavior this sample documents was separately verified against a hosted agent in canadacentral prod: with textField set to the frame's field name a violating response is blocked with content_filter, and a control run without invocationsModeration was not blocked.
Note on venue
I originally raised this against the private staging repo (foundry-samples-pr#1042) before re-reading CONTRIBUTING.md, which states publishable changes should come through a public same-repository pull request rather than an internal publication workflow. This PR supersedes it; I'll close that one.
Adds samples/python/hosted-agents/agent-framework/invocations/02-content-safety-guardrail,
the invocations counterpart to the existing responses guardrail sample.
On the invocations protocol the request and response bodies are agent-defined, so
attaching an RAI policy alone screens nothing. The sample shows the accompanying
invocationsModeration block that tells the platform where the prompt and response
text live, including the stream selector used for streamed frames.
Uses uv (pyproject.toml + uv.lock + uv.toml) per the Python hosted-agent dependency
policy, and registers a test-spec.yml behavior contract.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d91d7b94-da15-4dac-b0d4-195fad8fa01b
Re-verified the sample end to end after converting it from requirements.txt to uv, since that change swapped both the resolver and the base image (python:3.12-slim → python:3.13-slim).
Functional
Ran the locked environment against a real Foundry project (agents-model-validation-e2e-tests-swedencentral, gpt-4.1-mini):
Buffered:{"response":"Understood. INVOCATIONS-GUARDRAIL-OK"} — matches the declared outputPaths: [$.response], and satisfies the test-spec.yml assertion.
Streamed: frames are exactly what streamSelectors declares —
eventType: message.delta matches the frame's type value and textField: text is the bare field name, so every text-bearing frame is screened and the terminal message.done is correctly ignored.
Container: builds and serves; the credential-free path ({"stream":false} with no message) returns 400, confirming the handler is reached through the uv-built venv.
All imports resolve from the lock — python-dotenv, starlette, and azure-ai-agentserver-invocations come in transitively (108 packages).
Latency
Three cold starts per variant, docker run → first accepted request:
Variant
Image size
Cold start
Original pip / py3.12
497 MB
1.94 / 2.10 / 3.09 s
This PR (uv / py3.13)
508 MB
1.92 / 1.97 / 2.18 s
No regression — the uv conversion is latency-neutral.
While measuring I found that the shared uv template ships the 56 MB uv binary in the runtime image even though CMD never uses it; confining uv to a build stage takes this sample from 508 MB to 418 MB with identical startup. That affects 20 samples, so I raised it as #1020 rather than diverging this one — the Dockerfile here intentionally stays identical to its siblings.
- Add the repository's established azd: '>=1.27.1' floor to requiredVersions;
this manifest was the only Python Agent Framework sample missing it (25/26).
- Describe inputPaths/outputPaths as selector expressions rather than JSONPath,
and document the supported subset plus the textField field-name contract.
- Use the {"message": "..."} payload form for azd ai agent invoke in README.md
and AGENTS.md; the handler parses JSON and requires a message property, so the
bare-string form fails.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d91d7b94-da15-4dac-b0d4-195fad8fa01b
The only turn leaves stream false, so this contract exercises the buffered outputPaths gate but never the streaming branch or its streamSelectors, which are the defining additions of this sample. A benign buffered response would still pass if the streaming wiring were broken or absent; add a second benign turn with stream: true and assert its streamed output as well.
The inline environmentVariables list is the deprecated shape; azd still reads
it and still expands ${...} in it, but it is retained only for mid-migration
compatibility. This sample was the only one of 87 hosted-agent manifests still
using it. Switch to the service-level env mapping so the manifest matches the
rest of the repository.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d91d7b94-da15-4dac-b0d4-195fad8fa01b
This contract only sends the default buffered request because stream is omitted, so it never exercises the structured SSE path or the new streamSelectors configuration. Add a second turn (or separate test) with stream: true and the same marker so the claimed streaming gate is covered as well.
* feat(langchain): add custom store sample
* chore: update sdk version
* add test spec
* chore: refine readme and remove unused files
* align agents and README structure with the template
* fix previous_respond_id vs conversation id in the document
* fix: add the limitations section
* simplify wording
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
samples/python/hosted-agents/agent-framework/invocations/02-content-safety-guardrail— the invocations counterpart to the existing responses guardrail sample.Why
On the responses protocol the platform knows the payload shape, so attaching an RAI policy is enough. On invocations the request and response bodies are agent-defined, so a policy on its own screens nothing — it is attached and inert.
The sample shows the accompanying
invocationsModerationblock that tells the platform where the prompt and response text live:Note
textField: textis a field name, not a path expression. A$-prefixed value silently matches nothing and leaves streamed output unscreened; that footgun is fixed separately in Azure/azure-dev#9791 / Azure/azure-dev#10130, and this sample follows the corrected form.responseMode: bothdeclares a capability, not "input and output" — the agent answers buffered and streamed requests, and the platform picks exactly one gate at runtime from the responseContent-Type.Conventions followed
requirements.txt— shipspyproject.toml+uv.lock+uv.tomlper DEPENDENCY_POLICY.md, matching the sibling samples migrated in Migrate some Python Agent Framework samples to uv #992. Lock generated with the CI-pinneduv==0.11.7(revision = 3).codeConfiguration.runtime: python_3_13and the image base agree.test-spec.yml, the preferred behavior contract, rather than the legacytest-payload.txt.The contract asserts that benign traffic still flows through both gates untouched. It deliberately does not assert blocking: that needs a real RAI policy, and the sample ships a placeholder ID. Benign pass-through is the deterministic signal that regresses if the moderation wiring is wrong.
Validation run locally
check_hosted_agent_contracts.py --base <merge-base> --head HEADValidated behavior contracts for 1 new hosted-agent sample(s).check-hosted-agent-python-requirements.py --resolvePython Hosted Agent dependency-policy check passed.hosted_agent_test_spec.py validateValid hosted-agent test spechosted_agent_test_spec.py plan --protocol invocationsapplicableuv lock --check(uv 0.11.7)ruff check/black --checkThe end-to-end guardrail behavior this sample documents was separately verified against a hosted agent in
canadacentralprod: withtextFieldset to the frame's field name a violating response is blocked withcontent_filter, and a control run withoutinvocationsModerationwas not blocked.Note on venue
I originally raised this against the private staging repo (
foundry-samples-pr#1042) before re-readingCONTRIBUTING.md, which states publishable changes should come through a public same-repository pull request rather than an internal publication workflow. This PR supersedes it; I'll close that one.