mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
733748c925 | ||
|
|
12f6f82c18 | ||
|
|
91e3bbda83 |
@@ -47,7 +47,7 @@ body:
|
||||
attributes:
|
||||
label: Package Versions
|
||||
description: List the agent-framework-* packages and versions you are using
|
||||
placeholder: "e.g., agent-framework-core: 1.0.0, agent-framework-foundry: 1.0.0"
|
||||
placeholder: "e.g., agent-framework-core: 1.0.0, agent-framework-azure-ai: 1.0.0"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
#
|
||||
# Runs the .NET sample verification tool, which builds and executes sample projects
|
||||
# and verifies their output using deterministic checks and AI-powered verification.
|
||||
#
|
||||
# Results are displayed as a GitHub Job Summary and the CSV report is uploaded as an artifact.
|
||||
#
|
||||
|
||||
name: dotnet-verify-samples
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
category:
|
||||
description: "Sample category to run (blank for all)"
|
||||
required: false
|
||||
type: choice
|
||||
options:
|
||||
- ""
|
||||
- "01-get-started"
|
||||
- "02-agents"
|
||||
- "03-workflows"
|
||||
parallelism:
|
||||
description: "Max parallel sample runs"
|
||||
required: false
|
||||
default: "8"
|
||||
type: string
|
||||
schedule:
|
||||
- cron: "0 6 * * 1-5" # Weekdays at 6:00 UTC
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
verify-samples:
|
||||
runs-on: ubuntu-latest
|
||||
environment: 'integration'
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.
|
||||
.github
|
||||
dotnet
|
||||
workflow-samples
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v5.2.0
|
||||
with:
|
||||
global-json-file: ${{ github.workspace }}/dotnet/global.json
|
||||
|
||||
- name: Azure CLI Login
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: azure/login@v2
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
|
||||
- name: Run verify-samples
|
||||
id: verify
|
||||
working-directory: dotnet
|
||||
shell: bash
|
||||
run: |
|
||||
CATEGORY_ARG=""
|
||||
if [ -n "$CATEGORY_INPUT" ]; then
|
||||
CATEGORY_ARG="--category $CATEGORY_INPUT"
|
||||
fi
|
||||
|
||||
dotnet run --project eng/verify-samples -- \
|
||||
$CATEGORY_ARG \
|
||||
--parallel "$PARALLELISM" \
|
||||
--md results.md \
|
||||
--csv results.csv \
|
||||
--log results.log
|
||||
env:
|
||||
CATEGORY_INPUT: ${{ github.event.inputs.category || '' }}
|
||||
PARALLELISM: ${{ github.event.inputs.parallelism || '8' }}
|
||||
# OpenAI Models
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENAI_CHAT_MODEL_NAME: ${{ vars.OPENAI_CHAT_MODEL_NAME }}
|
||||
OPENAI_REASONING_MODEL_NAME: ${{ vars.OPENAI_REASONING_MODEL_NAME }}
|
||||
# Azure OpenAI Models
|
||||
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZURE_OPENAI_ENDPOINT }}
|
||||
# Azure AI Foundry
|
||||
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
|
||||
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZURE_AI_MODEL_DEPLOYMENT_NAME }}
|
||||
AZURE_AI_BING_CONNECTION_ID: ${{ vars.AZURE_AI_BING_CONNECTION_ID }}
|
||||
|
||||
- name: Write Job Summary
|
||||
if: always()
|
||||
working-directory: dotnet
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -f results.md ]; then
|
||||
cat results.md >> "$GITHUB_STEP_SUMMARY"
|
||||
else
|
||||
echo "⚠️ No results.md generated — verify-samples may have failed to start." >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
- name: Upload results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: verify-samples-results
|
||||
path: |
|
||||
dotnet/results.csv
|
||||
dotnet/results.log
|
||||
if-no-files-found: warn
|
||||
|
||||
- name: Fail if samples failed
|
||||
if: always() && steps.verify.outcome == 'failure'
|
||||
shell: bash
|
||||
run: exit 1
|
||||
@@ -37,6 +37,7 @@ ENFORCED_TARGETS: set[str] = {
|
||||
# Packages (sorted alphabetically)
|
||||
"packages.anthropic.agent_framework_anthropic",
|
||||
"packages.azure-ai-search.agent_framework_azure_ai_search",
|
||||
"packages.azure-ai.agent_framework_azure_ai",
|
||||
"packages.core.agent_framework",
|
||||
"packages.core.agent_framework._workflows",
|
||||
"packages.foundry.agent_framework_foundry",
|
||||
|
||||
@@ -60,8 +60,8 @@ jobs:
|
||||
environment: integration
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
@@ -95,8 +95,8 @@ jobs:
|
||||
environment: integration
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
@@ -201,15 +201,14 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
UV_PYTHON: "3.11"
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
|
||||
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
|
||||
FUNCTIONS_WORKER_RUNTIME: "python"
|
||||
@@ -256,14 +255,12 @@ jobs:
|
||||
environment: integration
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
|
||||
AZURE_AI_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
|
||||
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
|
||||
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
|
||||
FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }}
|
||||
FOUNDRY_AGENT_VERSION: ${{ vars.FOUNDRY_AGENT_VERSION }}
|
||||
FOUNDRY_MODELS_ENDPOINT: ${{ vars.FOUNDRY_MODELS_ENDPOINT || '' }}
|
||||
FOUNDRY_MODELS_API_KEY: ${{ secrets.FOUNDRY_MODELS_API_KEY || '' }}
|
||||
FOUNDRY_EMBEDDING_MODEL: ${{ vars.FOUNDRY_EMBEDDING_MODEL || '' }}
|
||||
FOUNDRY_IMAGE_EMBEDDING_MODEL: ${{ vars.FOUNDRY_IMAGE_EMBEDDING_MODEL || '' }}
|
||||
LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }}
|
||||
defaults:
|
||||
run:
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
azureChanged: ${{ steps.filter.outputs.azure }}
|
||||
miscChanged: ${{ steps.filter.outputs.misc }}
|
||||
functionsChanged: ${{ steps.filter.outputs.functions }}
|
||||
foundryChanged: ${{ steps.filter.outputs.foundry }}
|
||||
azureAiChanged: ${{ steps.filter.outputs.azure-ai }}
|
||||
cosmosChanged: ${{ steps.filter.outputs.cosmos }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@@ -75,10 +75,10 @@ jobs:
|
||||
functions:
|
||||
- 'python/packages/azurefunctions/**'
|
||||
- 'python/packages/durabletask/**'
|
||||
foundry:
|
||||
azure-ai:
|
||||
- 'python/packages/azure-ai/**'
|
||||
- 'python/packages/foundry/**'
|
||||
- 'python/samples/**/providers/foundry/**'
|
||||
- 'python/samples/02-agents/embeddings/foundry_embeddings.py'
|
||||
cosmos:
|
||||
- 'python/packages/azure-cosmos/**'
|
||||
# run only if 'python' files were changed
|
||||
@@ -139,8 +139,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: integration
|
||||
env:
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
@@ -192,8 +192,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: integration
|
||||
env:
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
@@ -330,15 +330,14 @@ jobs:
|
||||
environment: integration
|
||||
env:
|
||||
UV_PYTHON: "3.11"
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
|
||||
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
|
||||
FUNCTIONS_WORKER_RUNTIME: "python"
|
||||
@@ -393,11 +392,13 @@ jobs:
|
||||
github.event_name != 'pull_request' &&
|
||||
needs.paths-filter.outputs.pythonChanges == 'true' &&
|
||||
(github.event_name != 'merge_group' ||
|
||||
needs.paths-filter.outputs.foundryChanged == 'true' ||
|
||||
needs.paths-filter.outputs.azureAiChanged == 'true' ||
|
||||
needs.paths-filter.outputs.coreChanged == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
environment: integration
|
||||
env:
|
||||
AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
|
||||
AZURE_AI_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
|
||||
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
|
||||
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
|
||||
FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }}
|
||||
@@ -431,6 +432,11 @@ jobs:
|
||||
--timeout=120 --session-timeout=900 --timeout_method thread
|
||||
--retries 2 --retry-delay 5
|
||||
working-directory: ./python
|
||||
- name: Test Azure AI samples
|
||||
timeout-minutes: 10
|
||||
if: env.RUN_SAMPLES_TESTS == 'true'
|
||||
run: uv run pytest tests/samples/ -m "azure-ai"
|
||||
working-directory: ./python
|
||||
- name: Surface failing tests
|
||||
if: always()
|
||||
uses: pmeier/pytest-results-action@v0.7.2
|
||||
|
||||
@@ -66,13 +66,12 @@ jobs:
|
||||
# Azure OpenAI configuration
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME || vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }}
|
||||
# OpenAI configuration
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
# GitHub MCP
|
||||
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
@@ -98,12 +97,11 @@ jobs:
|
||||
echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env
|
||||
echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env
|
||||
echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env
|
||||
echo "AZURE_OPENAI_CHAT_COMPLETION_MODEL=$AZURE_OPENAI_CHAT_COMPLETION_MODEL" >> .env
|
||||
echo "AZURE_OPENAI_CHAT_MODEL=$AZURE_OPENAI_CHAT_MODEL" >> .env
|
||||
echo "AZURE_OPENAI_RESPONSES_MODEL=$AZURE_OPENAI_RESPONSES_MODEL" >> .env
|
||||
echo "AZURE_OPENAI_EMBEDDING_MODEL=$AZURE_OPENAI_EMBEDDING_MODEL" >> .env
|
||||
echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env
|
||||
echo "OPENAI_CHAT_COMPLETION_MODEL=$OPENAI_CHAT_COMPLETION_MODEL" >> .env
|
||||
echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env
|
||||
echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env
|
||||
echo "GITHUB_PAT=$GITHUB_PAT" >> .env
|
||||
|
||||
- name: Run sample validation
|
||||
@@ -124,8 +122,8 @@ jobs:
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: python
|
||||
@@ -144,8 +142,8 @@ jobs:
|
||||
run: |
|
||||
echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env
|
||||
echo "OPENAI_MODEL=$OPENAI_MODEL" >> .env
|
||||
echo "OPENAI_CHAT_COMPLETION_MODEL=$OPENAI_CHAT_COMPLETION_MODEL" >> .env
|
||||
echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env
|
||||
echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env
|
||||
|
||||
- name: Run sample validation
|
||||
run: |
|
||||
@@ -567,8 +565,8 @@ jobs:
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
# OpenAI configuration
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
defaults:
|
||||
run:
|
||||
@@ -591,8 +589,8 @@ jobs:
|
||||
echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env
|
||||
echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env
|
||||
echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env
|
||||
echo "OPENAI_CHAT_COMPLETION_MODEL=$OPENAI_CHAT_COMPLETION_MODEL" >> .env
|
||||
echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env
|
||||
echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env
|
||||
|
||||
- name: Run sample validation
|
||||
run: |
|
||||
@@ -612,18 +610,14 @@ jobs:
|
||||
env:
|
||||
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT || vars.AZURE_AI_PROJECT_ENDPOINT }}
|
||||
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
# Azure OpenAI configuration for AF
|
||||
# Azure OpenAI configuration
|
||||
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
|
||||
AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
|
||||
# Azure OpenAI configuration for SK
|
||||
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }}
|
||||
# OpenAI key
|
||||
# OpenAI configuration
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
|
||||
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
|
||||
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
|
||||
# OpenAI configuration for SK
|
||||
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
|
||||
# Copilot Studio
|
||||
COPILOTSTUDIOAGENT__ENVIRONMENTID: ${{ secrets.COPILOTSTUDIOAGENT__ENVIRONMENTID }}
|
||||
COPILOTSTUDIOAGENT__SCHEMANAME: ${{ secrets.COPILOTSTUDIOAGENT__SCHEMANAME }}
|
||||
@@ -650,8 +644,8 @@ jobs:
|
||||
echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env
|
||||
echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env
|
||||
echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env
|
||||
echo "OPENAI_CHAT_COMPLETION_MODEL=$OPENAI_CHAT_COMPLETION_MODEL" >> .env
|
||||
echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env
|
||||
echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env
|
||||
echo "COPILOTSTUDIOAGENT__ENVIRONMENTID=$COPILOTSTUDIOAGENT__ENVIRONMENTID" >> .env
|
||||
echo "COPILOTSTUDIOAGENT__SCHEMANAME=$COPILOTSTUDIOAGENT__SCHEMANAME" >> .env
|
||||
echo "COPILOTSTUDIOAGENT__TENANTID=$COPILOTSTUDIOAGENT__TENANTID" >> .env
|
||||
|
||||
@@ -230,6 +230,3 @@ local.settings.json
|
||||
# Database files
|
||||
*.db
|
||||
python/dotnet-ref
|
||||
|
||||
# Generated filtered solution files (created by eng/scripts/New-FilteredSolution.ps1)
|
||||
dotnet/filtered-*.slnx
|
||||
|
||||
@@ -28,7 +28,7 @@ Welcome to Microsoft's comprehensive multi-language framework for building, orch
|
||||
Python
|
||||
|
||||
```bash
|
||||
pip install agent-framework
|
||||
pip install agent-framework --pre
|
||||
# This will install all sub-packages, see `python/packages` for individual packages.
|
||||
# It may take a minute on first install on Windows.
|
||||
```
|
||||
@@ -90,7 +90,7 @@ Still have questions? Join our [weekly office hours](./COMMUNITY.md#public-commu
|
||||
Create a simple Azure Responses Agent that writes a haiku about the Microsoft Agent Framework
|
||||
|
||||
```python
|
||||
# pip install agent-framework
|
||||
# pip install agent-framework --pre
|
||||
# Use `az login` to authenticate with Azure CLI
|
||||
import os
|
||||
import asyncio
|
||||
|
||||
@@ -37,7 +37,7 @@ Key changes:
|
||||
4. **New `FoundryChatClient`** in azure-ai for Azure AI Foundry Responses API access, built on `RawFoundryChatClient(RawOpenAIChatClient)`.
|
||||
5. **All deprecated `AzureOpenAI*` classes** consolidated into a single file (`_deprecated_azure_openai.py`) in the azure-ai package for clean future deletion.
|
||||
6. **Core's `agent_framework.openai` and `agent_framework.azure` namespaces** become lazy-loading gateways, preserving backward-compatible import paths while removing hard dependencies.
|
||||
7. **Unified `model` parameter** replaces `model_id` (OpenAI), `deployment_name` (Azure OpenAI), and `model_deployment_name` (Azure AI) across all client constructors. The term `model` is intentionally generic: it naturally maps to an OpenAI model name *and* to an Azure OpenAI deployment name, making it straightforward to use `OpenAIChatClient` with either OpenAI or Azure OpenAI backends (via `AsyncAzureOpenAI`). Environment variables are similarly unified (e.g., `OPENAI_MODEL` instead of separate `OPENAI_CHAT_MODEL_ID` / `OPENAI_CHAT_COMPLETION_MODEL_ID`).
|
||||
7. **Unified `model` parameter** replaces `model_id` (OpenAI), `deployment_name` (Azure OpenAI), and `model_deployment_name` (Azure AI) across all client constructors. The term `model` is intentionally generic: it naturally maps to an OpenAI model name *and* to an Azure OpenAI deployment name, making it straightforward to use `OpenAIChatClient` with either OpenAI or Azure OpenAI backends (via `AsyncAzureOpenAI`). Environment variables are similarly unified (e.g., `OPENAI_MODEL` instead of separate `OPENAI_RESPONSES_MODEL_ID` / `OPENAI_CHAT_MODEL_ID`).
|
||||
8. **`FoundryAgent`** replaces the pattern of `Agent(client=AzureAIClient(...))` for connecting to pre-configured agents in Azure AI Foundry (PromptAgents and HostedAgents). The underlying `RawFoundryAgentChatClient` is an implementation detail — most users interact only with `FoundryAgent`. `AzureAIAgentClient` is separately deprecated as it refers to the V1 Agents Service API. See below for design rationale.
|
||||
|
||||
### Foundry Agent Design: `FoundryAgentClient` vs `FoundryAgent`
|
||||
|
||||
@@ -177,7 +177,7 @@ This feature ports the vector store abstractions, embedding generator abstractio
|
||||
**Goal:** Add embedding generators to all existing AF provider packages that have chat clients.
|
||||
**Mergeable:** Yes — each is independent, added to existing provider packages.
|
||||
|
||||
#### 2.1 — Foundry inference embedding (in `packages/foundry/`)
|
||||
#### 2.1 — Azure AI Inference embedding (in `packages/azure-ai/`)
|
||||
#### 2.2 — Ollama embedding (in `packages/ollama/`)
|
||||
#### 2.3 — Anthropic embedding (in `packages/anthropic/`)
|
||||
#### 2.4 — Bedrock embedding (in `packages/bedrock/`)
|
||||
|
||||
+1
-2
@@ -25,7 +25,7 @@ dotnet run --project eng/verify-samples -- Agent_Step02_StructuredOutput Agent_S
|
||||
dotnet run --project eng/verify-samples -- --parallel 8 --log results.log
|
||||
|
||||
# Combine options
|
||||
dotnet run --project eng/verify-samples -- --category 03-workflows --parallel 4 --log results.log --csv results.csv --md results.md
|
||||
dotnet run --project eng/verify-samples -- --category 03-workflows --parallel 4 --log results.log --csv results.csv
|
||||
```
|
||||
|
||||
### Required Environment Variables
|
||||
@@ -40,7 +40,6 @@ Individual samples require their own env vars (e.g., `AZURE_AI_PROJECT_ENDPOINT`
|
||||
|
||||
- `--log results.log` — detailed per-sample log with stdout/stderr, AI reasoning, and a summary
|
||||
- `--csv results.csv` — tabular summary with Sample, ProjectPath, Status, FailedChecks, and Failures columns
|
||||
- `--md results.md` — Markdown summary with results table and collapsible failure details (suitable for GitHub PR comments)
|
||||
|
||||
## Sample Categories
|
||||
|
||||
|
||||
+2
-3
@@ -29,14 +29,13 @@ using types like `IChatClient`, `FunctionInvokingChatClient`, `AITool`, `AIFunct
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- **Command output capture**: When running `dotnet build`, `dotnet test`, `dotnet format`, or similar commands, redirect output to a temp file first (e.g., `dotnet build --tl:off 2>&1 | Out-File $env:TEMP\build.log`), then analyze the file as needed. This avoids re-running expensive commands when the initial analysis misses something.
|
||||
- **Encoding**: All new files must be saved with UTF-8 encoding with BOM (Byte Order Mark). This is required for `dotnet format` to work correctly. When using PowerShell `Set-Content`, always pass `-Encoding UTF8BOM` to preserve the BOM (e.g., `Set-Content $file $content -NoNewline -Encoding UTF8BOM`).
|
||||
- **Encoding**: All new files must be saved with UTF-8 encoding with BOM (Byte Order Mark). This is required for `dotnet format` to work correctly.
|
||||
- **Copyright header**: `// Copyright (c) Microsoft. All rights reserved.` at top of all `.cs` files
|
||||
- **XML docs**: Required for all public methods and classes
|
||||
- **Async**: Use `Async` suffix for methods returning `Task`/`ValueTask`
|
||||
- **Private classes**: Should be `sealed` unless subclassed
|
||||
- **Config**: Read from environment variables with `UPPER_SNAKE_CASE` naming
|
||||
- **Tests**: Add Arrange/Act/Assert comments; use Moq for mocking; test methods returning `Task`/`ValueTask` must use the `Async` suffix.
|
||||
- **Tests**: Add Arrange/Act/Assert comments; use Moq for mocking
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleaseCandidate>false</IsReleaseCandidate>
|
||||
<IsReleased>false</IsReleased>
|
||||
<IsGenerallyAvailable>false</IsGenerallyAvailable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Aspire.* -->
|
||||
<PackageVersion Include="Anthropic" Version="12.11.0" />
|
||||
<PackageVersion Include="Anthropic" Version="12.8.0" />
|
||||
<PackageVersion Include="Anthropic.Foundry" Version="0.4.2" />
|
||||
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="13.0.0-preview.1.25560.3" />
|
||||
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireAppHostSdkVersion)" />
|
||||
@@ -19,13 +19,13 @@
|
||||
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="$(AspireAppHostSdkVersion)" />
|
||||
<PackageVersion Include="CommunityToolkit.Aspire.OllamaSharp" Version="13.0.0" />
|
||||
<!-- Azure.* -->
|
||||
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0" />
|
||||
<PackageVersion Include="Azure.AI.Projects" Version="2.0.0-beta.2" />
|
||||
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.10" />
|
||||
<PackageVersion Include="Azure.AI.OpenAI" Version="2.9.0-beta.1" />
|
||||
<PackageVersion Include="Azure.Identity" Version="1.20.0" />
|
||||
<PackageVersion Include="Azure.Identity" Version="1.19.0" />
|
||||
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
|
||||
<!-- Google Gemini -->
|
||||
<PackageVersion Include="Google.GenAI" Version="1.6.0" />
|
||||
<PackageVersion Include="Google.GenAI" Version="0.11.0" />
|
||||
<PackageVersion Include="Mscc.GenerativeAI.Microsoft" Version="2.9.3" />
|
||||
<!-- Microsoft.Azure.* -->
|
||||
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.54.0" />
|
||||
@@ -35,7 +35,7 @@
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.4" />
|
||||
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
|
||||
<PackageVersion Include="Microsoft.Bcl.Memory" Version="10.0.4" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.10.0" />
|
||||
<PackageVersion Include="System.ClientModel" Version="1.9.0" />
|
||||
<PackageVersion Include="System.CodeDom" Version="10.0.0" />
|
||||
<PackageVersion Include="System.Collections.Immutable" Version="10.0.1" />
|
||||
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_GoogleGemini/Agent_With_GoogleGemini.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_Ollama/Agent_With_Ollama.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_ONNX/Agent_With_ONNX.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIChatCompletion/Agent_With_OpenAIChatCompletion.csproj" />
|
||||
<Project Path="samples/02-agents/AgentProviders/Agent_With_OpenAIResponses/Agent_With_OpenAIResponses.csproj" />
|
||||
</Folder>
|
||||
@@ -106,9 +107,6 @@
|
||||
<File Path="samples/02-agents/AgentSkills/README.md" />
|
||||
<Project Path="samples/02-agents/AgentSkills/Agent_Step01_FileBasedSkills/Agent_Step01_FileBasedSkills.csproj" />
|
||||
<Project Path="samples/02-agents/AgentSkills/Agent_Step02_CodeDefinedSkills/Agent_Step02_CodeDefinedSkills.csproj" />
|
||||
<Project Path="samples/02-agents/AgentSkills/Agent_Step03_ClassBasedSkills/Agent_Step03_ClassBasedSkills.csproj" />
|
||||
<Project Path="samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj" />
|
||||
<Project Path="samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Agent_Step05_SkillsWithDI.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Samples/02-agents/AGUI/Step05_StateManagement/">
|
||||
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Client/Client.csproj" />
|
||||
|
||||
@@ -781,6 +781,19 @@ internal static class AgentsSamples
|
||||
SkipReason = "Requires local Ollama server.",
|
||||
},
|
||||
|
||||
new SampleDefinition
|
||||
{
|
||||
Name = "Agent_With_OpenAIAssistants",
|
||||
ProjectPath = "samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants",
|
||||
RequiredEnvironmentVariables = ["OPENAI_API_KEY"],
|
||||
OptionalEnvironmentVariables = ["OPENAI_CHAT_MODEL_NAME"],
|
||||
ExpectedOutputDescription =
|
||||
[
|
||||
"The output should contain a joke about a pirate from the OpenAI Assistants API.",
|
||||
"The output should not contain error messages or stack traces.",
|
||||
],
|
||||
},
|
||||
|
||||
new SampleDefinition
|
||||
{
|
||||
Name = "Agent_With_OpenAIChatCompletion",
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace VerifySamples;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a Markdown summary of sample verification results.
|
||||
/// </summary>
|
||||
internal static class MarkdownResultWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the results to a Markdown file at the specified path.
|
||||
/// </summary>
|
||||
public static async Task WriteAsync(
|
||||
string path,
|
||||
IReadOnlyList<VerificationResult> orderedResults,
|
||||
IReadOnlyList<(string Name, string Reason)> skipped,
|
||||
TimeSpan elapsed)
|
||||
{
|
||||
var passCount = orderedResults.Count(r => r.Passed);
|
||||
var failCount = orderedResults.Count(r => !r.Passed);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("# Sample Verification Results");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"**{passCount} passed, {failCount} failed, {skipped.Count} skipped** | Elapsed: {elapsed.Hours:D2}:{elapsed.Minutes:D2}:{elapsed.Seconds:D2}");
|
||||
sb.AppendLine();
|
||||
|
||||
// Results table
|
||||
sb.AppendLine("| Sample | Status | Failed Checks | Failures |");
|
||||
sb.AppendLine("|--------|--------|---------------|----------|");
|
||||
|
||||
foreach (var result in orderedResults)
|
||||
{
|
||||
var status = result.Passed ? "✅ PASSED" : "❌ FAILED";
|
||||
var failedChecks = result.Failures.Count;
|
||||
var failures = MdEscape(string.Join("; ", result.Failures));
|
||||
sb.AppendLine($"| {MdEscape(result.SampleName)} | {status} | {failedChecks} | {failures} |");
|
||||
}
|
||||
|
||||
foreach (var (name, reason) in skipped)
|
||||
{
|
||||
sb.AppendLine($"| {MdEscape(name)} | ⏭️ SKIPPED | 0 | {MdEscape(reason)} |");
|
||||
}
|
||||
|
||||
// Collapsible AI reasoning details for failures
|
||||
var failures2 = orderedResults.Where(r => !r.Passed && !string.IsNullOrEmpty(r.AIReasoning)).ToList();
|
||||
if (failures2.Count > 0)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("## Failure Details");
|
||||
sb.AppendLine();
|
||||
|
||||
foreach (var result in failures2)
|
||||
{
|
||||
sb.AppendLine($"<details><summary><strong>{HtmlEscape(result.SampleName)}</strong></summary>");
|
||||
sb.AppendLine();
|
||||
if (result.Failures.Count > 0)
|
||||
{
|
||||
foreach (var failure in result.Failures)
|
||||
{
|
||||
sb.AppendLine($"- {MdEscape(failure)}");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
sb.AppendLine("**AI Reasoning:**");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine(result.AIReasoning);
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("</details>");
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
await File.WriteAllTextAsync(path, sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes pipe characters and newlines for use inside Markdown table cells.
|
||||
/// </summary>
|
||||
private static string MdEscape(string value)
|
||||
{
|
||||
return value.Replace("|", "\\|").Replace("\n", " ").Replace("\r", "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes HTML special characters for use inside HTML tags.
|
||||
/// </summary>
|
||||
private static string HtmlEscape(string value)
|
||||
{
|
||||
return value.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", """);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
// dotnet run -- --parallel 16 # Run up to 16 samples concurrently
|
||||
// dotnet run -- --log results.log # Write sequential log to file
|
||||
// dotnet run -- --csv results.csv # Write CSV summary to file
|
||||
// dotnet run -- --md results.md # Write Markdown summary to file
|
||||
//
|
||||
// Required environment variables (for AI-powered samples):
|
||||
// AZURE_OPENAI_ENDPOINT
|
||||
@@ -91,13 +90,6 @@ try
|
||||
Console.WriteLine($"CSV written to: {options.CsvFilePath}");
|
||||
}
|
||||
|
||||
// Write Markdown summary
|
||||
if (options.MarkdownFilePath is not null)
|
||||
{
|
||||
await MarkdownResultWriter.WriteAsync(options.MarkdownFilePath, orderedResults, run.Skipped, stopwatch.Elapsed);
|
||||
Console.WriteLine($"Markdown written to: {options.MarkdownFilePath}");
|
||||
}
|
||||
|
||||
return orderedResults.Any(r => !r.Passed) ? 1 : 0;
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -17,11 +17,6 @@ internal sealed class VerifyOptions
|
||||
/// </summary>
|
||||
public string? CsvFilePath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to write a Markdown summary file, or <c>null</c> to skip.
|
||||
/// </summary>
|
||||
public string? MarkdownFilePath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to write a sequential log file, or <c>null</c> to skip.
|
||||
/// </summary>
|
||||
@@ -54,7 +49,6 @@ internal sealed class VerifyOptions
|
||||
var categoryFilter = ExtractArg(argList, "--category");
|
||||
var logFilePath = ExtractArg(argList, "--log");
|
||||
var csvFilePath = ExtractArg(argList, "--csv");
|
||||
var markdownFilePath = ExtractArg(argList, "--md");
|
||||
|
||||
int maxParallelism = 8;
|
||||
var parallelArg = ExtractArg(argList, "--parallel");
|
||||
@@ -104,7 +98,6 @@ internal sealed class VerifyOptions
|
||||
MaxParallelism = maxParallelism,
|
||||
LogFilePath = logFilePath,
|
||||
CsvFilePath = csvFilePath,
|
||||
MarkdownFilePath = markdownFilePath,
|
||||
Samples = samples,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
<PropertyGroup>
|
||||
<!-- Central version prefix - applies to all nuget packages. -->
|
||||
<VersionPrefix>1.0.0</VersionPrefix>
|
||||
<RCNumber>6</RCNumber>
|
||||
<RCNumber>5</RCNumber>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' == 'true'">$(VersionPrefix)-rc$(RCNumber)</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix).260402.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' == ''">$(VersionPrefix)-preview.260402.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleased)' == 'true'">$(VersionPrefix)</PackageVersion>
|
||||
<GitTag>1.0.0</GitTag>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' != ''">$(VersionPrefix)-$(VersionSuffix).260330.1</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsReleaseCandidate)' != 'true' AND '$(VersionSuffix)' == ''">$(VersionPrefix)-preview.260330.1</PackageVersion>
|
||||
<GitTag>1.0.0-rc5</GitTag>
|
||||
|
||||
<Configurations>Debug;Release;Publish</Configurations>
|
||||
<IsPackable>true</IsPackable>
|
||||
|
||||
<!-- Package validation. Baseline Version should be the latest version available on NuGet. -->
|
||||
<PackageValidationBaselineVersion>1.0.0-rc5</PackageValidationBaselineVersion>
|
||||
<PackageValidationBaselineVersion>1.0.0-rc4</PackageValidationBaselineVersion>
|
||||
<!-- Enable validation for RC packages and GA packages -->
|
||||
<EnablePackageValidation Condition="'$(IsReleaseCandidate)' == 'true' OR '$(IsReleased)' == 'true'">true</EnablePackageValidation>
|
||||
<EnablePackageValidation Condition="'$(IsReleaseCandidate)' == 'true' OR '$(IsGenerallyAvailable)' == 'true'">true</EnablePackageValidation>
|
||||
<!-- Validate assembly attributes only for Publish builds -->
|
||||
<NoWarn Condition="'$(Configuration)' != 'Publish'">$(NoWarn);CP0003</NoWarn>
|
||||
<!-- Do not validate reference assemblies -->
|
||||
|
||||
@@ -20,10 +20,10 @@ const string JokerName = "JokerAgent";
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
// Define the agent you want to create. (Prompt Agent in this case)
|
||||
var agentVersionCreationOptions = new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition(model: deploymentName) { Instructions = "You are good at telling jokes." });
|
||||
var agentVersionCreationOptions = new AgentVersionCreationOptions(new PromptAgentDefinition(model: deploymentName) { Instructions = "You are good at telling jokes." });
|
||||
// Azure.AI.Agents SDK creates and manages agent by name and versions.
|
||||
// You can create a server side agent version with the Azure.AI.Agents SDK client below.
|
||||
var createdAgentVersion = aiProjectClient.AgentAdministrationClient.CreateAgentVersion(agentName: JokerName, options: agentVersionCreationOptions);
|
||||
var createdAgentVersion = aiProjectClient.Agents.CreateAgentVersion(agentName: JokerName, options: agentVersionCreationOptions);
|
||||
|
||||
// Note:
|
||||
// agentVersion.Id = "<agentName>:<versionNumber>",
|
||||
@@ -34,15 +34,15 @@ var createdAgentVersion = aiProjectClient.AgentAdministrationClient.CreateAgentV
|
||||
FoundryAgent existingJokerAgent = aiProjectClient.AsAIAgent(createdAgentVersion);
|
||||
|
||||
// You can also create another AIAgent version by providing the same name with a different definition.
|
||||
ProjectsAgentVersion newJokerAgentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion newJokerAgentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
JokerName,
|
||||
new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition(model: deploymentName) { Instructions = "You are extremely hilarious at telling jokes." }));
|
||||
new AgentVersionCreationOptions(new PromptAgentDefinition(model: deploymentName) { Instructions = "You are extremely hilarious at telling jokes." }));
|
||||
FoundryAgent newJokerAgent = aiProjectClient.AsAIAgent(newJokerAgentVersion);
|
||||
|
||||
// You can also get the AIAgent latest version just providing its name.
|
||||
ProjectsAgentRecord jokerAgentRecord = await aiProjectClient.AgentAdministrationClient.GetAgentAsync(JokerName);
|
||||
AgentRecord jokerAgentRecord = await aiProjectClient.Agents.GetAgentAsync(JokerName);
|
||||
FoundryAgent jokerAgentLatest = aiProjectClient.AsAIAgent(jokerAgentRecord);
|
||||
ProjectsAgentVersion latestAgentVersion = jokerAgentRecord.GetLatestVersion();
|
||||
AgentVersion latestAgentVersion = jokerAgentRecord.GetLatestVersion();
|
||||
|
||||
// The AIAgent version can be accessed via the GetService method.
|
||||
Console.WriteLine($"Latest agent version id: {latestAgentVersion.Id}");
|
||||
@@ -55,4 +55,4 @@ Console.WriteLine(await jokerAgentLatest.RunAsync("Tell me a joke about a pirate
|
||||
Console.WriteLine(await jokerAgentLatest.RunAsync("Now tell me a joke about a cat and a dog using last joke as the anchor.", session));
|
||||
|
||||
// Cleanup by agent name removes both agent versions created.
|
||||
aiProjectClient.AgentAdministrationClient.DeleteAgent(existingJokerAgent.Name);
|
||||
aiProjectClient.Agents.DeleteAgent(existingJokerAgent.Name);
|
||||
|
||||
-6
@@ -6,14 +6,8 @@
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);MAAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// This sample shows how to create and use a simple AI agent with OpenAI Assistants as the backend.
|
||||
|
||||
// WARNING: The Assistants API is deprecated and will be shut down.
|
||||
// For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete - OpenAI Assistants API is deprecated but still used in this sample
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using OpenAI;
|
||||
using OpenAI.Assistants;
|
||||
|
||||
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
|
||||
var model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-4o-mini";
|
||||
|
||||
const string JokerName = "Joker";
|
||||
const string JokerInstructions = "You are good at telling jokes.";
|
||||
|
||||
// Get a client to create/retrieve server side agents with.
|
||||
var assistantClient = new OpenAIClient(apiKey).GetAssistantClient();
|
||||
|
||||
// You can create a server side assistant with the OpenAI SDK.
|
||||
var createResult = await assistantClient.CreateAssistantAsync(model, new() { Name = JokerName, Instructions = JokerInstructions });
|
||||
|
||||
// You can retrieve an already created server side assistant as an AIAgent.
|
||||
AIAgent agent1 = await assistantClient.GetAIAgentAsync(createResult.Value.Id);
|
||||
|
||||
// You can also create a server side assistant and return it as an AIAgent directly.
|
||||
AIAgent agent2 = await assistantClient.CreateAIAgentAsync(
|
||||
model: model,
|
||||
name: JokerName,
|
||||
instructions: JokerInstructions);
|
||||
|
||||
// You can invoke the agent like any other AIAgent.
|
||||
AgentSession session = await agent1.CreateSessionAsync();
|
||||
Console.WriteLine(await agent1.RunAsync("Tell me a joke about a pirate.", session));
|
||||
|
||||
// Cleanup for sample purposes.
|
||||
await assistantClient.DeleteAssistantAsync(agent1.Id);
|
||||
await assistantClient.DeleteAssistantAsync(agent2.Id);
|
||||
@@ -0,0 +1,16 @@
|
||||
# Prerequisites
|
||||
|
||||
WARNING: The Assistants API is deprecated and will be shut down.
|
||||
For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
|
||||
|
||||
Before you begin, ensure you have the following prerequisites:
|
||||
|
||||
- .NET 10 SDK or later
|
||||
- OpenAI API key
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
```powershell
|
||||
$env:OPENAI_API_KEY="*****" # Replace with your OpenAI API key
|
||||
$env:OPENAI_CHAT_MODEL_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
|
||||
```
|
||||
@@ -25,6 +25,7 @@ See the README.md for each sample for the prerequisites for that sample.
|
||||
|[Creating an AIAgent with GitHub Copilot](./Agent_With_GitHubCopilot/)|This sample demonstrates how to create an AIAgent using GitHub Copilot SDK as the underlying inference service|
|
||||
|[Creating an AIAgent with Ollama](./Agent_With_Ollama/)|This sample demonstrates how to create an AIAgent using Ollama as the underlying inference service|
|
||||
|[Creating an AIAgent with ONNX](./Agent_With_ONNX/)|This sample demonstrates how to create an AIAgent using ONNX as the underlying inference service|
|
||||
|[Creating an AIAgent with OpenAI Assistants](./Agent_With_OpenAIAssistants/)|This sample demonstrates how to create an AIAgent using OpenAI Assistants as the underlying inference service.</br>WARNING: The Assistants API is deprecated and will be shut down. For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration|
|
||||
|[Creating an AIAgent with OpenAI ChatCompletion](./Agent_With_OpenAIChatCompletion/)|This sample demonstrates how to create an AIAgent using OpenAI ChatCompletion as the underlying inference service|
|
||||
|[Creating an AIAgent with OpenAI Responses](./Agent_With_OpenAIResponses/)|This sample demonstrates how to create an AIAgent using OpenAI Responses as the underlying inference service|
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This sample demonstrates how to use **file-based Agent Skills** with a `ChatClie
|
||||
|
||||
- Discovering skills from `SKILL.md` files on disk via `AgentFileSkillsSource`
|
||||
- The progressive disclosure pattern: advertise → load → read resources → run scripts
|
||||
- Using the `AgentSkillsProvider` constructor with a skill directory path and script runner
|
||||
- Using the `AgentSkillsProvider` constructor with a skill directory path and script executor
|
||||
- Running file-based scripts (Python) via a subprocess-based executor
|
||||
|
||||
## Skills Included
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// This sample demonstrates how to define Agent Skills as C# classes using AgentClassSkill.
|
||||
// Class-based skills bundle all components into a single class implementation.
|
||||
|
||||
using System.Text.Json;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using OpenAI.Responses;
|
||||
|
||||
// --- Configuration ---
|
||||
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||
|
||||
// --- Class-Based Skill ---
|
||||
// Instantiate the skill class.
|
||||
var unitConverter = new UnitConverterSkill();
|
||||
|
||||
// --- Skills Provider ---
|
||||
var skillsProvider = new AgentSkillsProvider(unitConverter);
|
||||
|
||||
// --- Agent Setup ---
|
||||
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
|
||||
.GetResponsesClient()
|
||||
.AsAIAgent(new ChatClientAgentOptions
|
||||
{
|
||||
Name = "UnitConverterAgent",
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = "You are a helpful assistant that can convert units.",
|
||||
},
|
||||
AIContextProviders = [skillsProvider],
|
||||
},
|
||||
model: deploymentName);
|
||||
|
||||
// --- Example: Unit conversion ---
|
||||
Console.WriteLine("Converting units with class-based skills");
|
||||
Console.WriteLine(new string('-', 60));
|
||||
|
||||
AgentResponse response = await agent.RunAsync(
|
||||
"How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
|
||||
|
||||
Console.WriteLine($"Agent: {response.Text}");
|
||||
|
||||
/// <summary>
|
||||
/// A unit-converter skill defined as a C# class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Class-based skills bundle all components (name, description, body, resources, scripts)
|
||||
/// into a single class.
|
||||
/// </remarks>
|
||||
internal sealed class UnitConverterSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new(
|
||||
"unit-converter",
|
||||
"Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string Instructions => """
|
||||
Use this skill when the user asks to convert between units.
|
||||
|
||||
1. Review the conversion-table resource to find the factor for the requested conversion.
|
||||
2. Use the convert script, passing the value and factor from the table.
|
||||
3. Present the result clearly with both units.
|
||||
""";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
CreateResource(
|
||||
"conversion-table",
|
||||
"""
|
||||
# Conversion Tables
|
||||
|
||||
Formula: **result = value × factor**
|
||||
|
||||
| From | To | Factor |
|
||||
|-------------|-------------|----------|
|
||||
| miles | kilometers | 1.60934 |
|
||||
| kilometers | miles | 0.621371 |
|
||||
| pounds | kilograms | 0.453592 |
|
||||
| kilograms | pounds | 2.20462 |
|
||||
"""),
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
CreateScript("convert", ConvertUnits),
|
||||
];
|
||||
|
||||
private static string ConvertUnits(double value, double factor)
|
||||
{
|
||||
double result = Math.Round(value * factor, 4);
|
||||
return JsonSerializer.Serialize(new { value, factor, result });
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
# Class-Based Agent Skills Sample
|
||||
|
||||
This sample demonstrates how to define **Agent Skills as C# classes** using `AgentClassSkill`.
|
||||
|
||||
## What it demonstrates
|
||||
|
||||
- Creating skills as classes that extend `AgentClassSkill`
|
||||
- Bundling name, description, body, resources, and scripts into a single class
|
||||
- Using the `AgentSkillsProvider` constructor with class-based skills
|
||||
|
||||
## Skills Included
|
||||
|
||||
### unit-converter (class-based)
|
||||
|
||||
A `UnitConverterSkill` class that converts between common units. Defined in `Program.cs`:
|
||||
|
||||
- `conversion-table` — Static resource with factor table
|
||||
- `convert` — Script that performs `value × factor` conversion
|
||||
|
||||
## Running the Sample
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- .NET 10.0 SDK
|
||||
- Azure OpenAI endpoint with a deployed model
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
export AZURE_OPENAI_ENDPOINT="https://your-endpoint.openai.azure.com/"
|
||||
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
dotnet run
|
||||
```
|
||||
|
||||
### Expected Output
|
||||
|
||||
```
|
||||
Converting units with class-based skills
|
||||
------------------------------------------------------------
|
||||
Agent: Here are your conversions:
|
||||
|
||||
1. **26.2 miles → 42.16 km** (a marathon distance)
|
||||
2. **75 kg → 165.35 lbs**
|
||||
```
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);MAAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SubprocessScriptRunner.cs" Link="SubprocessScriptRunner.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Copy skills directory to output -->
|
||||
<ItemGroup>
|
||||
<None Include="skills\**\*.*">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// This sample demonstrates an advanced scenario: combining multiple skill types in a single agent
|
||||
// using AgentSkillsProviderBuilder. The builder is designed for cases where the simple
|
||||
// AgentSkillsProvider constructors are insufficient — for example, when you need to mix skill
|
||||
// sources, apply filtering, or configure cross-cutting options in one place.
|
||||
//
|
||||
// Three different skill sources are registered here:
|
||||
// 1. File-based: unit-converter (miles↔km, pounds↔kg) from SKILL.md on disk
|
||||
// 2. Code-defined: volume-converter (gallons↔liters) using AgentInlineSkill
|
||||
// 3. Class-based: temperature-converter (°F↔°C↔K) using AgentClassSkill
|
||||
//
|
||||
// For simpler, single-source scenarios, see the earlier steps in this sample series
|
||||
// (e.g., Step01 for file-based, Step02 for code-defined, Step03 for class-based).
|
||||
|
||||
using System.Text.Json;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using OpenAI.Responses;
|
||||
|
||||
// --- Configuration ---
|
||||
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
|
||||
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||
|
||||
// --- 1. Code-Defined Skill: volume-converter ---
|
||||
var volumeConverterSkill = new AgentInlineSkill(
|
||||
name: "volume-converter",
|
||||
description: "Convert between gallons and liters using a multiplication factor.",
|
||||
instructions: """
|
||||
Use this skill when the user asks to convert between gallons and liters.
|
||||
|
||||
1. Review the volume-conversion-table resource to find the correct factor.
|
||||
2. Use the convert-volume script, passing the value and factor.
|
||||
""")
|
||||
.AddResource("volume-conversion-table",
|
||||
"""
|
||||
# Volume Conversion Table
|
||||
|
||||
Formula: **result = value × factor**
|
||||
|
||||
| From | To | Factor |
|
||||
|---------|---------|---------|
|
||||
| gallons | liters | 3.78541 |
|
||||
| liters | gallons | 0.264172|
|
||||
""")
|
||||
.AddScript("convert-volume", (double value, double factor) =>
|
||||
{
|
||||
double result = Math.Round(value * factor, 4);
|
||||
return JsonSerializer.Serialize(new { value, factor, result });
|
||||
});
|
||||
|
||||
// --- 2. Class-Based Skill: temperature-converter ---
|
||||
var temperatureConverter = new TemperatureConverterSkill();
|
||||
|
||||
// --- 3. Build provider combining all three source types ---
|
||||
var skillsProvider = new AgentSkillsProviderBuilder()
|
||||
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills")) // File-based: unit-converter
|
||||
.UseSkill(volumeConverterSkill) // Code-defined: volume-converter
|
||||
.UseSkill(temperatureConverter) // Class-based: temperature-converter
|
||||
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
|
||||
.Build();
|
||||
|
||||
// --- Agent Setup ---
|
||||
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
|
||||
.GetResponsesClient()
|
||||
.AsAIAgent(new ChatClientAgentOptions
|
||||
{
|
||||
Name = "MultiConverterAgent",
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = "You are a helpful assistant that can convert units, volumes, and temperatures.",
|
||||
},
|
||||
AIContextProviders = [skillsProvider],
|
||||
},
|
||||
model: deploymentName);
|
||||
|
||||
// --- Example: Use all three skills ---
|
||||
Console.WriteLine("Converting with mixed skills (file + code + class)");
|
||||
Console.WriteLine(new string('-', 60));
|
||||
|
||||
AgentResponse response = await agent.RunAsync(
|
||||
"I need three conversions: " +
|
||||
"1) How many kilometers is a marathon (26.2 miles)? " +
|
||||
"2) How many liters is a 5-gallon bucket? " +
|
||||
"3) What is 98.6°F in Celsius?");
|
||||
|
||||
Console.WriteLine($"Agent: {response.Text}");
|
||||
|
||||
/// <summary>
|
||||
/// A temperature-converter skill defined as a C# class.
|
||||
/// </summary>
|
||||
internal sealed class TemperatureConverterSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new(
|
||||
"temperature-converter",
|
||||
"Convert between temperature scales (Fahrenheit, Celsius, Kelvin).");
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string Instructions => """
|
||||
Use this skill when the user asks to convert temperatures.
|
||||
|
||||
1. Review the temperature-conversion-formulas resource for the correct formula.
|
||||
2. Use the convert-temperature script, passing the value, source scale, and target scale.
|
||||
3. Present the result clearly with both temperature scales.
|
||||
""";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
CreateResource(
|
||||
"temperature-conversion-formulas",
|
||||
"""
|
||||
# Temperature Conversion Formulas
|
||||
|
||||
| From | To | Formula |
|
||||
|-------------|-------------|---------------------------|
|
||||
| Fahrenheit | Celsius | °C = (°F − 32) × 5/9 |
|
||||
| Celsius | Fahrenheit | °F = (°C × 9/5) + 32 |
|
||||
| Celsius | Kelvin | K = °C + 273.15 |
|
||||
| Kelvin | Celsius | °C = K − 273.15 |
|
||||
"""),
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
CreateScript("convert-temperature", ConvertTemperature),
|
||||
];
|
||||
|
||||
private static string ConvertTemperature(double value, string from, string to)
|
||||
{
|
||||
double result = (from.ToUpperInvariant(), to.ToUpperInvariant()) switch
|
||||
{
|
||||
("FAHRENHEIT", "CELSIUS") => Math.Round((value - 32) * 5.0 / 9.0, 2),
|
||||
("CELSIUS", "FAHRENHEIT") => Math.Round(value * 9.0 / 5.0 + 32, 2),
|
||||
("CELSIUS", "KELVIN") => Math.Round(value + 273.15, 2),
|
||||
("KELVIN", "CELSIUS") => Math.Round(value - 273.15, 2),
|
||||
_ => throw new ArgumentException($"Unsupported conversion: {from} → {to}")
|
||||
};
|
||||
|
||||
return JsonSerializer.Serialize(new { value, from, to, result });
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
# Mixed Agent Skills Sample (Advanced)
|
||||
|
||||
This sample demonstrates an **advanced scenario**: combining multiple skill types in a single agent using `AgentSkillsProviderBuilder`.
|
||||
|
||||
> **Tip:** For simpler, single-source scenarios, use the `AgentSkillsProvider` constructors directly — see [Step01](../Agent_Step01_FileBasedSkills/) (file-based), [Step02](../Agent_Step02_CodeDefinedSkills/) (code-defined), or [Step03](../Agent_Step03_ClassBasedSkills/) (class-based).
|
||||
|
||||
## What it demonstrates
|
||||
|
||||
- Combining file-based, code-defined, and class-based skills in one provider
|
||||
- Using `UseFileSkill` and `UseSkill` on the builder to register different skill types
|
||||
- Aggregating skills from all sources into a single provider with automatic deduplication
|
||||
|
||||
## When to use `AgentSkillsProviderBuilder`
|
||||
|
||||
The builder is intended for advanced scenarios where the simple `AgentSkillsProvider` constructors are insufficient:
|
||||
|
||||
| Scenario | Builder method |
|
||||
|----------|---------------|
|
||||
| **Mixed skill types** — combine file-based, code-defined, and class-based skills | `UseFileSkill` + `UseSkill` / `UseSkills` |
|
||||
| **Multiple file script runners** — use different script runners for different file skill directories | `UseFileSkill` / `UseFileSkills` with per-source `scriptRunner` |
|
||||
| **Skill filtering** — include/exclude skills using a predicate | `UseFilter(predicate)` |
|
||||
|
||||
## Skills Included
|
||||
|
||||
### unit-converter (file-based)
|
||||
|
||||
Discovered from `skills/unit-converter/SKILL.md` on disk. Converts miles↔km, pounds↔kg.
|
||||
|
||||
### volume-converter (code-defined)
|
||||
|
||||
Defined as `AgentInlineSkill` in `Program.cs`. Converts gallons↔liters.
|
||||
|
||||
### temperature-converter (class-based)
|
||||
|
||||
Defined as `TemperatureConverterSkill` class in `Program.cs`. Converts °F↔°C↔K.
|
||||
|
||||
## Running the Sample
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- .NET 10.0 SDK
|
||||
- Azure OpenAI endpoint with a deployed model
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
export AZURE_OPENAI_ENDPOINT="https://your-endpoint.openai.azure.com/"
|
||||
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
dotnet run
|
||||
```
|
||||
|
||||
### Expected Output
|
||||
|
||||
```
|
||||
Converting with mixed skills (file + code + class)
|
||||
------------------------------------------------------------
|
||||
Agent: Here are your conversions:
|
||||
|
||||
1. **26.2 miles → 42.16 km** (a marathon distance)
|
||||
2. **5 gallons → 18.93 liters**
|
||||
3. **98.6°F → 37.0°C**
|
||||
```
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
---
|
||||
name: unit-converter
|
||||
description: Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
When the user requests a unit conversion:
|
||||
1. First, review `references/unit-conversion-table.md` to find the correct factor
|
||||
2. Run the `scripts/convert-units.py` script with `--value <number> --factor <factor>` (e.g. `--value 26.2 --factor 1.60934`)
|
||||
3. Present the converted value clearly with both units
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
# Conversion Tables
|
||||
|
||||
Formula: **result = value × factor**
|
||||
|
||||
| From | To | Factor |
|
||||
|-------------|-------------|----------|
|
||||
| miles | kilometers | 1.60934 |
|
||||
| kilometers | miles | 0.621371 |
|
||||
| pounds | kilograms | 0.453592 |
|
||||
| kilograms | pounds | 2.20462 |
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
# Unit conversion script
|
||||
# Converts a value using a multiplication factor: result = value × factor
|
||||
#
|
||||
# Usage:
|
||||
# python scripts/convert-units.py --value 26.2 --factor 1.60934
|
||||
# python scripts/convert-units.py --value 75 --factor 2.20462
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Convert a value using a multiplication factor.",
|
||||
epilog="Examples:\n"
|
||||
" python scripts/convert-units.py --value 26.2 --factor 1.60934\n"
|
||||
" python scripts/convert-units.py --value 75 --factor 2.20462",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
parser.add_argument("--value", type=float, required=True, help="The numeric value to convert.")
|
||||
parser.add_argument("--factor", type=float, required=True, help="The conversion factor from the table.")
|
||||
args = parser.parse_args()
|
||||
|
||||
result = round(args.value * args.factor, 4)
|
||||
print(json.dumps({"value": args.value, "factor": args.factor, "result": result}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);MAAI001;CA1812</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,208 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
// This sample demonstrates how to use Dependency Injection (DI) with Agent Skills.
|
||||
// It shows two approaches side-by-side, each handling a different conversion domain:
|
||||
//
|
||||
// 1. Code-defined skill (AgentInlineSkill) — converts distances (miles ↔ kilometers).
|
||||
// Resources and scripts are inline delegates that resolve services from IServiceProvider.
|
||||
//
|
||||
// 2. Class-based skill (AgentClassSkill) — converts weights (pounds ↔ kilograms).
|
||||
// Resources and scripts are encapsulated in a class, also resolving services from IServiceProvider.
|
||||
//
|
||||
// Both skills share the same ConversionService registered in the DI container,
|
||||
// showing that DI works identically regardless of how the skill is defined.
|
||||
// When prompted with a question spanning both domains, the agent uses both skills.
|
||||
|
||||
using System.Text.Json;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OpenAI.Responses;
|
||||
|
||||
// --- Configuration ---
|
||||
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||
|
||||
// --- DI Container ---
|
||||
// Register application services that skill resources and scripts can resolve at execution time.
|
||||
ServiceCollection services = new();
|
||||
services.AddSingleton<ConversionService>();
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
// =====================================================================
|
||||
// Approach 1: Code-Defined Skill with DI (AgentInlineSkill)
|
||||
// =====================================================================
|
||||
// Handles distance conversions (miles ↔ kilometers).
|
||||
// Resources and scripts are inline delegates. Each delegate can declare
|
||||
// an IServiceProvider parameter that the framework injects automatically.
|
||||
|
||||
var distanceSkill = new AgentInlineSkill(
|
||||
name: "distance-converter",
|
||||
description: "Convert between distance units. Use when asked to convert miles to kilometers or kilometers to miles.",
|
||||
instructions: """
|
||||
Use this skill when the user asks to convert between distance units (miles and kilometers).
|
||||
|
||||
1. Review the distance-table resource to find the factor for the requested conversion.
|
||||
2. Use the convert script, passing the value and factor from the table.
|
||||
""")
|
||||
.AddResource("distance-table", (IServiceProvider serviceProvider) =>
|
||||
{
|
||||
var service = serviceProvider.GetRequiredService<ConversionService>();
|
||||
return service.GetDistanceTable();
|
||||
})
|
||||
.AddScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
|
||||
{
|
||||
var service = serviceProvider.GetRequiredService<ConversionService>();
|
||||
return service.Convert(value, factor);
|
||||
});
|
||||
|
||||
// =====================================================================
|
||||
// Approach 2: Class-Based Skill with DI (AgentClassSkill)
|
||||
// =====================================================================
|
||||
// Handles weight conversions (pounds ↔ kilograms).
|
||||
// Resources and scripts are encapsulated in a class. Factory methods
|
||||
// CreateResource and CreateScript accept delegates with IServiceProvider.
|
||||
//
|
||||
// Alternatively, class-based skills can accept dependencies through their
|
||||
// constructor. Register the skill class itself in the ServiceCollection and
|
||||
// resolve it from the container:
|
||||
//
|
||||
// services.AddSingleton<WeightConverterSkill>();
|
||||
// var weightSkill = serviceProvider.GetRequiredService<WeightConverterSkill>();
|
||||
|
||||
var weightSkill = new WeightConverterSkill();
|
||||
|
||||
// --- Skills Provider ---
|
||||
// Both skills are registered with the same provider so the agent can use either one.
|
||||
var skillsProvider = new AgentSkillsProvider(distanceSkill, weightSkill);
|
||||
|
||||
// --- Agent Setup ---
|
||||
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
|
||||
.GetResponsesClient()
|
||||
.AsAIAgent(
|
||||
options: new ChatClientAgentOptions
|
||||
{
|
||||
Name = "UnitConverterAgent",
|
||||
ChatOptions = new()
|
||||
{
|
||||
Instructions = "You are a helpful assistant that can convert units.",
|
||||
},
|
||||
AIContextProviders = [skillsProvider],
|
||||
},
|
||||
model: deploymentName,
|
||||
services: serviceProvider);
|
||||
|
||||
// --- Example: Unit conversion ---
|
||||
// This prompt spans both domains, so the agent will use both skills.
|
||||
Console.WriteLine("Converting units with DI-powered skills");
|
||||
Console.WriteLine(new string('-', 60));
|
||||
|
||||
AgentResponse response = await agent.RunAsync(
|
||||
"How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?");
|
||||
|
||||
Console.WriteLine($"Agent: {response.Text}");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Class-Based Skill
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// A weight-converter skill defined as a C# class that uses Dependency Injection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This skill resolves <see cref="ConversionService"/> from the DI container
|
||||
/// in both its resource and script functions. This enables clean separation of
|
||||
/// concerns and testability while retaining the class-based skill pattern.
|
||||
/// </remarks>
|
||||
internal sealed class WeightConverterSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new(
|
||||
"weight-converter",
|
||||
"Convert between weight units. Use when asked to convert pounds to kilograms or kilograms to pounds.");
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string Instructions => """
|
||||
Use this skill when the user asks to convert between weight units (pounds and kilograms).
|
||||
|
||||
1. Review the weight-table resource to find the factor for the requested conversion.
|
||||
2. Use the convert script, passing the value and factor from the table.
|
||||
3. Present the result clearly with both units.
|
||||
""";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
CreateResource("weight-table", (IServiceProvider serviceProvider) =>
|
||||
{
|
||||
var service = serviceProvider.GetRequiredService<ConversionService>();
|
||||
return service.GetWeightTable();
|
||||
}),
|
||||
];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
CreateScript("convert", (double value, double factor, IServiceProvider serviceProvider) =>
|
||||
{
|
||||
var service = serviceProvider.GetRequiredService<ConversionService>();
|
||||
return service.Convert(value, factor);
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Services
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Provides conversion rates between units.
|
||||
/// In a real application this could call an external API, read from a database,
|
||||
/// or apply time-varying exchange rates.
|
||||
/// </summary>
|
||||
internal sealed class ConversionService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a markdown table of supported distance conversions.
|
||||
/// </summary>
|
||||
public string GetDistanceTable() =>
|
||||
"""
|
||||
# Distance Conversions
|
||||
|
||||
Formula: **result = value × factor**
|
||||
|
||||
| From | To | Factor |
|
||||
|-------------|-------------|----------|
|
||||
| miles | kilometers | 1.60934 |
|
||||
| kilometers | miles | 0.621371 |
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Returns a markdown table of supported weight conversions.
|
||||
/// </summary>
|
||||
public string GetWeightTable() =>
|
||||
"""
|
||||
# Weight Conversions
|
||||
|
||||
Formula: **result = value × factor**
|
||||
|
||||
| From | To | Factor |
|
||||
|-------------|-------------|----------|
|
||||
| pounds | kilograms | 0.453592 |
|
||||
| kilograms | pounds | 2.20462 |
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Converts a value by the given factor and returns a JSON result.
|
||||
/// </summary>
|
||||
public string Convert(double value, double factor)
|
||||
{
|
||||
double result = Math.Round(value * factor, 4);
|
||||
return JsonSerializer.Serialize(new { value, factor, result });
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
# Agent Skills with Dependency Injection
|
||||
|
||||
This sample demonstrates how to use **Dependency Injection (DI)** with Agent Skills. It shows two approaches side-by-side, each handling a different conversion domain:
|
||||
|
||||
1. **Code-defined skill** (`AgentInlineSkill`) — converts **distances** (miles ↔ kilometers)
|
||||
2. **Class-based skill** (`AgentClassSkill`) — converts **weights** (pounds ↔ kilograms)
|
||||
|
||||
Both skills resolve the same `ConversionService` from the DI container. When prompted with a question spanning both domains, the agent uses both skills.
|
||||
|
||||
## What It Shows
|
||||
|
||||
- Registering application services in a `ServiceCollection`
|
||||
- Defining a **code-defined** skill (distance converter) with resources and scripts that resolve services from `IServiceProvider`
|
||||
- Defining a **class-based** skill (weight converter) with resources and scripts that resolve services from `IServiceProvider`
|
||||
- Passing the built `IServiceProvider` to the agent so skills can access DI services at execution time
|
||||
- Running a single prompt that exercises both skills to show they work together
|
||||
|
||||
## How It Works
|
||||
|
||||
1. A `ConversionService` is registered as a singleton in the DI container
|
||||
2. **Code-defined skill**: An `AgentInlineSkill` for distance conversions declares `IServiceProvider` as a parameter in its `AddResource` and `AddScript` delegates — the framework injects it automatically
|
||||
3. **Class-based skill**: A `WeightConverterSkill` class extends `AgentClassSkill` for weight conversions and uses `CreateResource`/`CreateScript` factory methods with `IServiceProvider` parameters
|
||||
4. Both skills resolve `ConversionService` from the provider — one for distance tables, the other for weight tables
|
||||
5. A single agent is created with both skills registered, and the service provider flows through to skill execution
|
||||
|
||||
> **Tip:** Class-based skills can also accept dependencies through their **constructor**. Register the skill class in the `ServiceCollection` and resolve it from the container instead of calling `new` directly. This is useful when the skill itself needs injected services beyond what the resource/script delegates use.
|
||||
|
||||
## How It Differs from Other Samples
|
||||
|
||||
| Sample | Skill Type | DI Support |
|
||||
|--------|------------|------------|
|
||||
| [Step02](../Agent_Step02_CodeDefinedSkills/) | Code-defined (`AgentInlineSkill`) | No — static resources |
|
||||
| [Step03](../Agent_Step03_ClassBasedSkills/) | Class-based (`AgentClassSkill`) | No — static resources |
|
||||
| **Step05 (this)** | **Both code-defined and class-based** | **Yes — DI via `IServiceProvider`** |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- .NET 10
|
||||
- An Azure OpenAI deployment
|
||||
|
||||
## Configuration
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `AZURE_OPENAI_ENDPOINT` | Your Azure OpenAI endpoint URL |
|
||||
| `AZURE_OPENAI_DEPLOYMENT_NAME` | Model deployment name (defaults to `gpt-4o-mini`) |
|
||||
|
||||
## Running the Sample
|
||||
|
||||
```bash
|
||||
dotnet run
|
||||
```
|
||||
|
||||
### Expected Output
|
||||
|
||||
```
|
||||
Converting units with DI-powered skills
|
||||
------------------------------------------------------------
|
||||
Agent: Here are your conversions:
|
||||
|
||||
1. **26.2 miles → 42.16 km** (a marathon distance)
|
||||
2. **75 kg → 165.35 lbs**
|
||||
```
|
||||
@@ -6,32 +6,19 @@ Samples demonstrating Agent Skills capabilities. Each sample shows a different w
|
||||
|--------|-------------|
|
||||
| [Agent_Step01_FileBasedSkills](Agent_Step01_FileBasedSkills/) | Define skills as `SKILL.md` files on disk with reference documents. Uses a unit-converter skill. |
|
||||
| [Agent_Step02_CodeDefinedSkills](Agent_Step02_CodeDefinedSkills/) | Define skills entirely in C# code using `AgentInlineSkill`, with static/dynamic resources and scripts. |
|
||||
| [Agent_Step03_ClassBasedSkills](Agent_Step03_ClassBasedSkills/) | Define skills as C# classes using `AgentClassSkill`. |
|
||||
| [Agent_Step04_MixedSkills](Agent_Step04_MixedSkills/) | **(Advanced)** Combine file-based, code-defined, and class-based skills using `AgentSkillsProviderBuilder`. |
|
||||
| [Agent_Step05_SkillsWithDI](Agent_Step05_SkillsWithDI/) | Use Dependency Injection with both code-defined (`AgentInlineSkill`) and class-based (`AgentClassSkill`) skills. |
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Skill Types
|
||||
### File-Based vs Code-Defined Skills
|
||||
|
||||
| Aspect | File-Based | Code-Defined | Class-Based |
|
||||
|--------|-----------|--------------|-------------|
|
||||
| Definition | `SKILL.md` files on disk | `AgentInlineSkill` instances in C# | Classes extending `AgentClassSkill` |
|
||||
| Resources | All files in skill directory (filtered by extension) | `AddResource` (static value or delegate-backed) | `CreateResource` factory methods |
|
||||
| Scripts | Supported via script runner delegate | `AddScript` delegates | `CreateScript` factory methods |
|
||||
| Discovery | Automatic from directory path | Explicit via constructor | Explicit via constructor |
|
||||
| Dynamic content | No (static files only) | Yes (factory delegates) | Yes (factory delegates) |
|
||||
| Sharing pattern | Copy skill directory | Inline or shared instances | Package in shared assemblies/NuGet |
|
||||
| DI support | No | Yes (via `IServiceProvider` parameter) | Yes (via `IServiceProvider` parameter) |
|
||||
| Aspect | File-Based | Code-Defined |
|
||||
|--------|-----------|--------------|
|
||||
| Definition | `SKILL.md` files on disk | `AgentInlineSkill` instances in C# |
|
||||
| Resources | All files in skill directory (filtered by extension) | `AddResource` (static value or delegate-backed) |
|
||||
| Scripts | Supported via script executor delegate | `AddScript` delegates |
|
||||
| Discovery | Automatic from directory path | Explicit via constructor |
|
||||
| Dynamic content | No (static files only) | Yes (factory delegates) |
|
||||
| Reusability | Copy skill directory | Inline or shared instances |
|
||||
|
||||
### `AgentSkillsProvider` vs `AgentSkillsProviderBuilder`
|
||||
For single-source scenarios, use the `AgentSkillsProvider` constructors directly. To combine multiple skill types, use the `AgentSkillsProviderBuilder`.
|
||||
|
||||
For single-source scenarios, use the `AgentSkillsProvider` constructors directly — they accept a skill directory path, a set of skills, or a custom source.
|
||||
|
||||
Use `AgentSkillsProviderBuilder` for advanced scenarios where simple constructors are insufficient:
|
||||
|
||||
- **Mixed skill types** — combine file-based, code-defined, and class-based skills in one provider
|
||||
- **Multiple file script runners** — use different script runners for different file skill directories
|
||||
- **Skill filtering** — include or exclude skills using a predicate
|
||||
|
||||
See [Agent_Step04_MixedSkills](Agent_Step04_MixedSkills/) for a working example.
|
||||
|
||||
+4
-4
@@ -44,10 +44,10 @@ ClientResult<VectorStore> vectorStoreCreate = await vectorStoreClient.CreateVect
|
||||
FileSearchTool fileSearchTool = new([vectorStoreCreate.Value.Id]);
|
||||
#pragma warning restore OPENAI001
|
||||
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
"AskContoso",
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.",
|
||||
Tools = { fileSearchTool }
|
||||
@@ -68,4 +68,4 @@ Console.WriteLine(await agent.RunAsync("What is the best way to maintain the Tra
|
||||
// Cleanup
|
||||
await fileClient.DeleteFileAsync(uploadResult.Value.Id);
|
||||
await vectorStoreClient.DeleteVectorStoreAsync(vectorStoreCreate.Value.Id);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
|
||||
|
||||
@@ -19,10 +19,10 @@ var deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYME
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
// Create a server side agent and expose it as an AIAgent.
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
"Joker",
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.",
|
||||
})
|
||||
|
||||
+4
-4
@@ -18,10 +18,10 @@ const string JokerName = "JokerAgent";
|
||||
AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential());
|
||||
|
||||
// Create a server-side agent version using the native SDK.
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
JokerName,
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: deploymentName)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: deploymentName)
|
||||
{
|
||||
Instructions = "You are good at telling jokes.",
|
||||
}));
|
||||
@@ -33,4 +33,4 @@ FoundryAgent agent = aiProjectClient.AsAIAgent(agentVersion);
|
||||
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
|
||||
|
||||
// Cleanup: deletes the agent and all its versions.
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(agent.Name);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
using Azure.AI.Extensions.OpenAI;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Agents;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
|
||||
@@ -31,10 +31,10 @@ var mcpTool = ResponseTool.CreateMcpTool(
|
||||
toolCallApprovalPolicy: new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.NeverRequireApproval));
|
||||
|
||||
// Create a server side agent with the mcp tool, and expose it as an AIAgent.
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
"MicrosoftLearnAgent",
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = "You answer questions by searching the Microsoft Learn content only.",
|
||||
Tools = { mcpTool }
|
||||
@@ -47,7 +47,7 @@ AgentSession session = await agent.CreateSessionAsync();
|
||||
Console.WriteLine(await agent.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", session));
|
||||
|
||||
// Cleanup for sample purposes.
|
||||
aiProjectClient.AgentAdministrationClient.DeleteAgent(agent.Name);
|
||||
aiProjectClient.Agents.DeleteAgent(agent.Name);
|
||||
|
||||
// **** MCP Tool with Approval Required ****
|
||||
// *****************************************
|
||||
@@ -61,10 +61,10 @@ var mcpToolWithApproval = ResponseTool.CreateMcpTool(
|
||||
toolCallApprovalPolicy: new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.AlwaysRequireApproval));
|
||||
|
||||
// Create an agent with the MCP tool that requires approval.
|
||||
ProjectsAgentVersion agentVersionWithApproval = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersionWithApproval = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
"MicrosoftLearnAgentWithApproval",
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = "You answer questions by searching the Microsoft Learn content only.",
|
||||
Tools = { mcpToolWithApproval }
|
||||
|
||||
@@ -58,9 +58,9 @@ public static class Program
|
||||
finally
|
||||
{
|
||||
// Cleanup the agents created for the sample.
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(frenchAgent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(spanishAgent.Name);
|
||||
await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(englishAgent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(frenchAgent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(spanishAgent.Name);
|
||||
await aiProjectClient.Agents.DeleteAgentAsync(englishAgent.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,10 @@ public static class Program
|
||||
AIProjectClient aiProjectClient,
|
||||
string model)
|
||||
{
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(
|
||||
$"{targetLanguage} Translator",
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(model: model)
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(model: model)
|
||||
{
|
||||
Instructions = $"You are a translation assistant that translates the provided text to {targetLanguage}.",
|
||||
}));
|
||||
|
||||
@@ -97,7 +97,7 @@ internal sealed class Program
|
||||
agentDescription: "Escalate agent for human support");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineSelfServiceAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineSelfServiceAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -144,7 +144,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineTicketingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static PromptAgentDefinition DefineTicketingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -208,7 +208,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineTicketRoutingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static PromptAgentDefinition DefineTicketRoutingAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -253,7 +253,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineWindowsSupportAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static PromptAgentDefinition DefineWindowsSupportAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -323,7 +323,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineResolutionAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static PromptAgentDefinition DefineResolutionAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -357,7 +357,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition TicketEscalationAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
private static PromptAgentDefinition TicketEscalationAgent(IConfiguration configuration, TicketingPlugin plugin) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -88,7 +88,7 @@ internal sealed class Program
|
||||
agentDescription: "Weather agent for DeepResearch workflow");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineResearchAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineResearchAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -114,13 +114,13 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefinePlannerAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefinePlannerAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions = // TODO: Use Structured Inputs / Prompt Template
|
||||
@@ -139,7 +139,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineManagerAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineManagerAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions = // TODO: Use Structured Inputs / Prompt Template
|
||||
@@ -225,7 +225,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineSummaryAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineSummaryAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -240,18 +240,18 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineKnowledgeAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineKnowledgeAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Tools =
|
||||
{
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineCoderAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineCoderAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -265,7 +265,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineWeatherAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineWeatherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -274,7 +274,7 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
ProjectsAgentTool.CreateOpenApiTool(
|
||||
AgentTool.CreateOpenApiTool(
|
||||
new OpenApiFunctionDefinition(
|
||||
"weather-forecast",
|
||||
BinaryData.FromString(File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "wttr.json"))),
|
||||
|
||||
@@ -67,9 +67,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
private static PromptAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
{
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
PromptAgentDefinition agentDefinition =
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -46,7 +46,7 @@ internal sealed class Program
|
||||
await CreateAgentsAsync(aiProjectClient, configuration);
|
||||
|
||||
// Ensure workflow agent exists in Foundry.
|
||||
ProjectsAgentVersion agentVersion = await CreateWorkflowAsync(aiProjectClient, configuration);
|
||||
AgentVersion agentVersion = await CreateWorkflowAsync(aiProjectClient, configuration);
|
||||
|
||||
string workflowInput = GetWorkflowInput(args);
|
||||
|
||||
@@ -86,7 +86,7 @@ internal sealed class Program
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<ProjectsAgentVersion> CreateWorkflowAsync(AIProjectClient agentClient, IConfiguration configuration)
|
||||
private static async Task<AgentVersion> CreateWorkflowAsync(AIProjectClient agentClient, IConfiguration configuration)
|
||||
{
|
||||
string workflowYaml = File.ReadAllText("MathChat.yaml");
|
||||
|
||||
@@ -114,7 +114,7 @@ internal sealed class Program
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -127,7 +127,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -68,7 +68,7 @@ internal sealed class Program
|
||||
agentDescription: "Chats with the user with location awareness.");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineLocationTriageAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineLocationTriageAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -79,7 +79,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineLocationCaptureAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineLocationCaptureAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -128,7 +128,7 @@ internal sealed class Program
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineLocationAwareAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineLocationAwareAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
// Parameterized instructions reference the "location" input argument.
|
||||
|
||||
@@ -63,9 +63,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
private static PromptAgentDefinition DefineMenuAgent(IConfiguration configuration, AIFunction[] functions)
|
||||
{
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
PromptAgentDefinition agentDefinition =
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -125,9 +125,9 @@ internal sealed class Program
|
||||
agentDescription: "Provides information based on search results");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineSearchAgent(IConfiguration configuration)
|
||||
private static PromptAgentDefinition DefineSearchAgent(IConfiguration configuration)
|
||||
{
|
||||
return new DeclarativeAgentDefinition(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
return new PromptAgentDefinition(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
"""
|
||||
|
||||
@@ -67,7 +67,7 @@ internal sealed class Program
|
||||
agentDescription: "Editor agent for Marketing workflow");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineAnalystAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineAnalystAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -79,13 +79,13 @@ internal sealed class Program
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(configuration[Application.Settings.FoundryGroundingTool])]))
|
||||
}
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineWriterAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineWriterAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -96,7 +96,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineEditorAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineEditorAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -62,7 +62,7 @@ internal sealed class Program
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineStudentAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
@@ -75,7 +75,7 @@ internal sealed class Program
|
||||
"""
|
||||
};
|
||||
|
||||
private static DeclarativeAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineTeacherAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
@@ -58,7 +58,7 @@ internal sealed class Program
|
||||
agentDescription: "Searches documents on Microsoft Learn");
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition DefineSearchAgent(IConfiguration configuration) =>
|
||||
private static PromptAgentDefinition DefineSearchAgent(IConfiguration configuration) =>
|
||||
new(configuration.GetValue(Application.Settings.FoundryModel))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
-1
@@ -6,7 +6,6 @@
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>$(NoWarn);MAAIW001</NoWarn> <!-- Handoff Orchestrations are Experimental -->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -20,7 +20,7 @@ internal static class HostAgentFactory
|
||||
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
|
||||
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
|
||||
|
||||
ProjectsAgentRecord agentRecord = await aiProjectClient.AgentAdministrationClient.GetAgentAsync(agentName);
|
||||
AgentRecord agentRecord = await aiProjectClient.Agents.GetAgentAsync(agentName);
|
||||
AIAgent agent = aiProjectClient.AsAIAgent(agentRecord, tools: tools);
|
||||
|
||||
AgentCard agentCard = agentType.ToUpperInvariant() switch
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.Agents.AI</RootNamespace>
|
||||
<NoWarn>$(NoWarn);MEAI001</NoWarn>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -25,8 +25,8 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
{
|
||||
private readonly ChatClientMetadata? _metadata;
|
||||
private readonly AIProjectClient _agentClient;
|
||||
private readonly ProjectsAgentVersion? _agentVersion;
|
||||
private readonly ProjectsAgentRecord? _agentRecord;
|
||||
private readonly AgentVersion? _agentVersion;
|
||||
private readonly AgentRecord? _agentRecord;
|
||||
private readonly ChatOptions? _chatOptions;
|
||||
private readonly AgentReference _agentReference;
|
||||
|
||||
@@ -56,34 +56,34 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
/// Initializes a new instance of the <see cref="AzureAIProjectChatClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">An instance of <see cref="AIProjectClient"/> to interact with Azure AI Agents services.</param>
|
||||
/// <param name="agentRecord">An instance of <see cref="ProjectsAgentRecord"/> representing the specific agent to use.</param>
|
||||
/// <param name="agentRecord">An instance of <see cref="AgentRecord"/> representing the specific agent to use.</param>
|
||||
/// <param name="chatOptions">An instance of <see cref="ChatOptions"/> representing the options on how the agent was predefined.</param>
|
||||
/// <remarks>
|
||||
/// The <see cref="IChatClient"/> provided should be decorated with a <see cref="AzureAIProjectChatClient"/> for proper functionality.
|
||||
/// </remarks>
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, ProjectsAgentRecord agentRecord, ChatOptions? chatOptions)
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, AgentRecord agentRecord, ChatOptions? chatOptions)
|
||||
: this(aiProjectClient, Throw.IfNull(agentRecord).GetLatestVersion(), chatOptions)
|
||||
{
|
||||
this._agentRecord = agentRecord;
|
||||
}
|
||||
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, ProjectsAgentVersion agentVersion, ChatOptions? chatOptions)
|
||||
internal AzureAIProjectChatClient(AIProjectClient aiProjectClient, AgentVersion agentVersion, ChatOptions? chatOptions)
|
||||
: this(
|
||||
aiProjectClient,
|
||||
CreateAgentReference(Throw.IfNull(agentVersion)),
|
||||
(agentVersion.Definition as DeclarativeAgentDefinition)?.Model,
|
||||
(agentVersion.Definition as PromptAgentDefinition)?.Model,
|
||||
chatOptions)
|
||||
{
|
||||
this._agentVersion = agentVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AgentReference"/> from an <see cref="ProjectsAgentVersion"/>.
|
||||
/// Creates an <see cref="AgentReference"/> from an <see cref="AgentVersion"/>.
|
||||
/// Uses the agent version's version if available, otherwise defaults to "latest".
|
||||
/// </summary>
|
||||
/// <param name="agentVersion">The agent version to create a reference from.</param>
|
||||
/// <returns>An <see cref="AgentReference"/> for the specified agent version.</returns>
|
||||
private static AgentReference CreateAgentReference(ProjectsAgentVersion agentVersion)
|
||||
private static AgentReference CreateAgentReference(AgentVersion agentVersion)
|
||||
{
|
||||
// If the version is null, empty, or whitespace, use "latest" as the default.
|
||||
// This handles cases where hosted agents (like MCP agents) may not have a version assigned.
|
||||
@@ -98,9 +98,9 @@ internal sealed class AzureAIProjectChatClient : DelegatingChatClient
|
||||
? this._metadata
|
||||
: (serviceKey is null && serviceType == typeof(AIProjectClient))
|
||||
? this._agentClient
|
||||
: (serviceKey is null && serviceType == typeof(ProjectsAgentVersion))
|
||||
: (serviceKey is null && serviceType == typeof(AgentVersion))
|
||||
? this._agentVersion
|
||||
: (serviceKey is null && serviceType == typeof(ProjectsAgentRecord))
|
||||
: (serviceKey is null && serviceType == typeof(AgentRecord))
|
||||
? this._agentRecord
|
||||
: (serviceKey is null && serviceType == typeof(AgentReference))
|
||||
? this._agentReference
|
||||
|
||||
@@ -38,7 +38,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="InvalidOperationException">The agent with the specified name was not found.</exception>
|
||||
/// <remarks>
|
||||
/// When instantiating a <see cref="ChatClientAgent"/> by using an <see cref="AgentReference"/>, minimal information will be available about the agent in the instance level, and any logic that relies
|
||||
/// on <see cref="AIAgent.GetService{TService}(object?)"/> to retrieve information about the agent like <see cref="ProjectsAgentVersion" /> will receive <see langword="null"/> as the result.
|
||||
/// on <see cref="AIAgent.GetService{TService}(object?)"/> to retrieve information about the agent like <see cref="AgentVersion" /> will receive <see langword="null"/> as the result.
|
||||
/// </remarks>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
@@ -67,7 +67,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="ProjectsAgentRecord"/>.
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="AgentRecord"/>.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||
/// <param name="agentRecord">The agent record to be converted. The latest version will be used. Cannot be <see langword="null"/>.</param>
|
||||
@@ -78,7 +78,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="aiProjectClient"/> or <paramref name="agentRecord"/> is <see langword="null"/>.</exception>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
AgentRecord agentRecord,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
@@ -100,7 +100,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="ProjectsAgentVersion"/>.
|
||||
/// Uses an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AIProjectClient"/> and <see cref="AgentVersion"/>.
|
||||
/// </summary>
|
||||
/// <param name="aiProjectClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||
/// <param name="agentVersion">The agent version to be converted. Cannot be <see langword="null"/>.</param>
|
||||
@@ -111,7 +111,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="aiProjectClient"/> or <paramref name="agentVersion"/> is <see langword="null"/>.</exception>
|
||||
public static FoundryAgent AsAIAgent(
|
||||
this AIProjectClient aiProjectClient,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
AgentVersion agentVersion,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
@@ -206,7 +206,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>Creates a <see cref="ChatClientAgent"/> with the specified options.</summary>
|
||||
private static ChatClientAgent CreateChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
AgentVersion agentVersion,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -249,7 +249,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with the specified ChatClientAgentOptions.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
AgentVersion agentVersion,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -258,7 +258,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with the specified ChatClientAgentOptions.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
AgentRecord agentRecord,
|
||||
ChatClientAgentOptions agentOptions,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
IServiceProvider? services)
|
||||
@@ -293,14 +293,14 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with a auto-generated ChatClientAgentOptions from the specified configuration parameters.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentVersion agentVersion,
|
||||
AIProjectClient AIProjectClient,
|
||||
AgentVersion agentVersion,
|
||||
IList<AITool>? tools,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
bool requireInvocableTools,
|
||||
IServiceProvider? services)
|
||||
=> AsChatClientAgent(
|
||||
aiProjectClient,
|
||||
AIProjectClient,
|
||||
agentVersion,
|
||||
CreateChatClientAgentOptions(agentVersion, new ChatOptions() { Tools = tools }, requireInvocableTools),
|
||||
clientFactory,
|
||||
@@ -308,21 +308,21 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
|
||||
/// <summary>This method creates an <see cref="ChatClientAgent"/> with a auto-generated ChatClientAgentOptions from the specified configuration parameters.</summary>
|
||||
private static ChatClientAgent AsChatClientAgent(
|
||||
AIProjectClient aiProjectClient,
|
||||
ProjectsAgentRecord agentRecord,
|
||||
AIProjectClient AIProjectClient,
|
||||
AgentRecord agentRecord,
|
||||
IList<AITool>? tools,
|
||||
Func<IChatClient, IChatClient>? clientFactory,
|
||||
bool requireInvocableTools,
|
||||
IServiceProvider? services)
|
||||
=> AsChatClientAgent(
|
||||
aiProjectClient,
|
||||
AIProjectClient,
|
||||
agentRecord,
|
||||
CreateChatClientAgentOptions(agentRecord.GetLatestVersion(), new ChatOptions() { Tools = tools }, requireInvocableTools),
|
||||
clientFactory,
|
||||
services);
|
||||
|
||||
/// <summary>
|
||||
/// This method creates <see cref="ChatClientAgentOptions"/> for the specified <see cref="ProjectsAgentVersion"/> and the provided tools.
|
||||
/// This method creates <see cref="ChatClientAgentOptions"/> for the specified <see cref="AgentVersion"/> and the provided tools.
|
||||
/// </summary>
|
||||
/// <param name="agentVersion">The agent version.</param>
|
||||
/// <param name="chatOptions">The <see cref="ChatOptions"/> to use when interacting with the agent.</param>
|
||||
@@ -334,12 +334,12 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
/// This method rebuilds the agent options from the agent definition returned by the version and combine with the in-proc tools when provided
|
||||
/// this ensures that all required tools are provided and the definition of the agent options are consistent with the agent definition coming from the server.
|
||||
/// </remarks>
|
||||
private static ChatClientAgentOptions CreateChatClientAgentOptions(ProjectsAgentVersion agentVersion, ChatOptions? chatOptions, bool requireInvocableTools)
|
||||
private static ChatClientAgentOptions CreateChatClientAgentOptions(AgentVersion agentVersion, ChatOptions? chatOptions, bool requireInvocableTools)
|
||||
{
|
||||
var agentDefinition = agentVersion.Definition;
|
||||
|
||||
List<AITool>? agentTools = null;
|
||||
if (agentDefinition is DeclarativeAgentDefinition { Tools: { Count: > 0 } definitionTools })
|
||||
if (agentDefinition is PromptAgentDefinition { Tools: { Count: > 0 } definitionTools })
|
||||
{
|
||||
// Check if no tools were provided while the agent definition requires in-proc tools.
|
||||
if (requireInvocableTools && chatOptions?.Tools is not { Count: > 0 } && definitionTools.Any(t => t is FunctionTool))
|
||||
@@ -395,7 +395,7 @@ public static partial class AzureAIProjectChatClientExtensions
|
||||
Description = agentVersion.Description,
|
||||
};
|
||||
|
||||
if (agentDefinition is DeclarativeAgentDefinition promptAgentDefinition)
|
||||
if (agentDefinition is PromptAgentDefinition promptAgentDefinition)
|
||||
{
|
||||
agentOptions.ChatOptions ??= chatOptions?.Clone() ?? new();
|
||||
agentOptions.ChatOptions.Instructions = promptAgentDefinition.Instructions;
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace Microsoft.Agents.AI.Foundry;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class wraps <see cref="ProjectsAgentTool"/> (Azure.AI.Projects.Agents) and <see cref="ResponseTool"/> (OpenAI SDK) factory methods,
|
||||
/// This class wraps <see cref="AgentTool"/> (Azure.AI.Projects.OpenAI) and <see cref="ResponseTool"/> (OpenAI SDK) factory methods,
|
||||
/// returning <see cref="AITool"/> directly — eliminating the need for manual casting and <c>.AsAITool()</c> calls.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Instead of writing:
|
||||
/// <c>((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(definition)).AsAITool()</c>
|
||||
/// <c>((ResponseTool)AgentTool.CreateOpenApiTool(definition)).AsAITool()</c>
|
||||
/// You can write:
|
||||
/// <c>FoundryAITool.CreateOpenApiTool(definition)</c>
|
||||
/// </para>
|
||||
@@ -37,7 +37,7 @@ public static class FoundryAITool
|
||||
/// <returns>An <see cref="AITool"/> wrapping the provided response tool.</returns>
|
||||
public static AITool FromResponseTool(ResponseTool responseTool) => responseTool.AsAITool();
|
||||
|
||||
// --- Azure.AI.Projects.OpenAI ProjectsAgentTool factories ---
|
||||
// --- Azure.AI.Projects.OpenAI AgentTool factories ---
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for OpenAPI tool invocations.
|
||||
@@ -45,7 +45,7 @@ public static class FoundryAITool
|
||||
/// <param name="definition">The OpenAPI function definition specifying the API endpoint, schema, and authentication.</param>
|
||||
/// <returns>An <see cref="AITool"/> that calls the specified OpenAPI endpoint.</returns>
|
||||
public static AITool CreateOpenApiTool(OpenApiFunctionDefinition definition)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(definition)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateOpenApiTool(definition)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Bing Grounding search.
|
||||
@@ -53,7 +53,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The Bing Grounding search configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Bing Grounding search.</returns>
|
||||
public static AITool CreateBingGroundingTool(BingGroundingSearchToolOptions options)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBingGroundingTool(options)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateBingGroundingTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Bing Custom Search.
|
||||
@@ -61,7 +61,7 @@ public static class FoundryAITool
|
||||
/// <param name="parameters">The Bing Custom Search configuration parameters.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Bing Custom Search.</returns>
|
||||
public static AITool CreateBingCustomSearchTool(BingCustomSearchToolOptions parameters)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBingCustomSearchTool(parameters)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateBingCustomSearchTool(parameters)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Microsoft Fabric data agent.
|
||||
@@ -69,7 +69,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The Fabric data agent configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Microsoft Fabric.</returns>
|
||||
public static AITool CreateMicrosoftFabricTool(FabricDataAgentToolOptions options)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateMicrosoftFabricTool(options)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateMicrosoftFabricTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for SharePoint grounding.
|
||||
@@ -77,7 +77,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">The SharePoint grounding configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for SharePoint grounding.</returns>
|
||||
public static AITool CreateSharepointTool(SharePointGroundingToolOptions options)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateSharepointTool(options)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateSharepointTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Azure AI Search.
|
||||
@@ -85,7 +85,7 @@ public static class FoundryAITool
|
||||
/// <param name="options">Optional Azure AI Search configuration options.</param>
|
||||
/// <returns>An <see cref="AITool"/> for Azure AI Search.</returns>
|
||||
public static AITool CreateAzureAISearchTool(AzureAISearchToolOptions? options = null)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateAzureAISearchTool(options)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateAzureAISearchTool(options)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for browser automation.
|
||||
@@ -93,7 +93,7 @@ public static class FoundryAITool
|
||||
/// <param name="parameters">The browser automation configuration parameters.</param>
|
||||
/// <returns>An <see cref="AITool"/> for browser automation.</returns>
|
||||
public static AITool CreateBrowserAutomationTool(BrowserAutomationToolOptions parameters)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateBrowserAutomationTool(parameters)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateBrowserAutomationTool(parameters)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for structured output capture.
|
||||
@@ -101,7 +101,7 @@ public static class FoundryAITool
|
||||
/// <param name="outputs">The structured output definition.</param>
|
||||
/// <returns>An <see cref="AITool"/> for structured output capture.</returns>
|
||||
public static AITool CreateStructuredOutputsTool(StructuredOutputDefinition outputs)
|
||||
=> ((ResponseTool)ProjectsAgentTool.CreateStructuredOutputsTool(outputs)).AsAITool();
|
||||
=> ((ResponseTool)AgentTool.CreateStructuredOutputsTool(outputs)).AsAITool();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AITool"/> for Agent-to-Agent (A2A) communication.
|
||||
@@ -110,7 +110,7 @@ public static class FoundryAITool
|
||||
/// <param name="agentCardPath">Optional path to the agent card.</param>
|
||||
/// <returns>An <see cref="AITool"/> for A2A communication.</returns>
|
||||
public static AITool CreateA2ATool(Uri baseUri, string? agentCardPath = null)
|
||||
=> ProjectsAgentTool.CreateA2ATool(baseUri, agentCardPath).AsAITool();
|
||||
=> AgentTool.CreateA2ATool(baseUri, agentCardPath).AsAITool();
|
||||
|
||||
// --- OpenAI SDK ResponseTool factories ---
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Compliance.Redaction;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.ClientModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
|
||||
namespace Microsoft.Agents.AI.Foundry;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
<NoWarn>$(NoWarn);OPENAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -2,36 +2,106 @@
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:OpenAI.Assistants.OpenAIAssistantClientExtensions</Target>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,System.String,System.String,System.String,System.Collections.Generic.IList{Microsoft.Extensions.AI.AITool},System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:OpenAI.Responses.OpenAIResponseClientExtensions.AsIChatClientWithStoredOutputDisabled(OpenAI.Responses.ResponsesClient)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ClientModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.DiagnosticIds;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace OpenAI.Assistants;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for OpenAI <see cref="AssistantClient"/>
|
||||
/// to simplify the creation of AI agents that work with OpenAI services.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These extensions bridge the gap between OpenAI SDK client objects and the Microsoft Agent Framework,
|
||||
/// allowing developers to easily create AI agents that leverage OpenAI's chat completion and response services.
|
||||
/// The methods handle the conversion from OpenAI clients to <see cref="IChatClient"/> instances and then wrap them
|
||||
/// in <see cref="ChatClientAgent"/> objects that implement the <see cref="AIAgent"/> interface.
|
||||
/// </remarks>
|
||||
[Experimental(DiagnosticIds.Experiments.AIOpenAIAssistants)]
|
||||
public static class OpenAIAssistantClientExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from a <see cref="ClientResult{Assistant}"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantClientResult">The client result containing the assistant.</param>
|
||||
/// <param name="chatOptions">Optional chat options.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
ClientResult<Assistant> assistantClientResult,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantClientResult is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClientResult));
|
||||
}
|
||||
|
||||
return assistantClient.AsAIAgent(assistantClientResult.Value, chatOptions, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from an <see cref="Assistant"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantMetadata">The assistant metadata.</param>
|
||||
/// <param name="chatOptions">Optional chat options.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
Assistant assistantMetadata,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantMetadata is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantMetadata));
|
||||
}
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
|
||||
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(assistantMetadata.Instructions) && chatOptions?.Instructions is null)
|
||||
{
|
||||
chatOptions ??= new ChatOptions();
|
||||
chatOptions.Instructions = assistantMetadata.Instructions;
|
||||
}
|
||||
|
||||
return new ChatClientAgent(chatClient, options: new()
|
||||
{
|
||||
Id = assistantMetadata.Id,
|
||||
Name = assistantMetadata.Name,
|
||||
Description = assistantMetadata.Description,
|
||||
ChatOptions = chatOptions
|
||||
}, services: services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AssistantClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The <see cref="AssistantClient"/> to create the <see cref="ChatClientAgent"/> with.</param>
|
||||
/// <param name="agentId"> The ID of the server side agent to create a <see cref="ChatClientAgent"/> for.</param>
|
||||
/// <param name="chatOptions">Options that should apply to all runs of the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant agent.</returns>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||
this AssistantClient assistantClient,
|
||||
string agentId,
|
||||
ChatOptions? chatOptions = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(agentId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
|
||||
}
|
||||
|
||||
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
|
||||
return assistantClient.AsAIAgent(assistantResponse, chatOptions, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from a <see cref="ClientResult{Assistant}"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantClientResult">The client result containing the assistant.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantClientResult"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
ClientResult<Assistant> assistantClientResult,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantClientResult is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClientResult));
|
||||
}
|
||||
|
||||
return assistantClient.AsAIAgent(assistantClientResult.Value, options, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ChatClientAgent"/> from an <see cref="Assistant"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The assistant client.</param>
|
||||
/// <param name="assistantMetadata">The assistant metadata.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantMetadata"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static ChatClientAgent AsAIAgent(
|
||||
this AssistantClient assistantClient,
|
||||
Assistant assistantMetadata,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null)
|
||||
{
|
||||
if (assistantMetadata is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantMetadata));
|
||||
}
|
||||
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (options is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
|
||||
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.ChatOptions?.Instructions) && !string.IsNullOrWhiteSpace(assistantMetadata.Instructions))
|
||||
{
|
||||
options.ChatOptions ??= new ChatOptions();
|
||||
options.ChatOptions.Instructions = assistantMetadata.Instructions;
|
||||
}
|
||||
|
||||
var mergedOptions = new ChatClientAgentOptions()
|
||||
{
|
||||
Id = assistantMetadata.Id,
|
||||
Name = options.Name ?? assistantMetadata.Name,
|
||||
Description = options.Description ?? assistantMetadata.Description,
|
||||
ChatOptions = options.ChatOptions,
|
||||
AIContextProviders = options.AIContextProviders,
|
||||
ChatHistoryProvider = options.ChatHistoryProvider,
|
||||
UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs
|
||||
};
|
||||
|
||||
return new ChatClientAgent(chatClient, mergedOptions, services: services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AssistantClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="assistantClient">The <see cref="AssistantClient"/> to create the <see cref="ChatClientAgent"/> with.</param>
|
||||
/// <param name="agentId"> The ID of the server side agent to create a <see cref="ChatClientAgent"/> for.</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the assistant agent.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="assistantClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="agentId"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||
this AssistantClient assistantClient,
|
||||
string agentId,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (assistantClient is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assistantClient));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(agentId))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
|
||||
}
|
||||
|
||||
if (options is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
|
||||
return assistantClient.AsAIAgent(assistantResponse, options, clientFactory, services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AI agent from an <see cref="AssistantClient"/> using the OpenAI Assistant API.
|
||||
/// </summary>
|
||||
/// <param name="client">The OpenAI <see cref="AssistantClient" /> to use for the agent.</param>
|
||||
/// <param name="model">The model identifier to use (e.g., "gpt-4").</param>
|
||||
/// <param name="instructions">Optional system instructions that define the agent's behavior and personality.</param>
|
||||
/// <param name="name">Optional name for the agent for identification purposes.</param>
|
||||
/// <param name="description">Optional description of the agent's capabilities and purpose.</param>
|
||||
/// <param name="tools">Optional collection of AI tools that the agent can use during conversations.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="ChatClientAgent"/> instance backed by the OpenAI Assistant service.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="client"/> or <paramref name="model"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this AssistantClient client,
|
||||
string model,
|
||||
string? instructions = null,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
IList<AITool>? tools = null,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
ILoggerFactory? loggerFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await client.CreateAIAgentAsync(model,
|
||||
new ChatClientAgentOptions()
|
||||
{
|
||||
Name = name,
|
||||
Description = description,
|
||||
ChatOptions = tools is null && string.IsNullOrWhiteSpace(instructions) ? null : new ChatOptions()
|
||||
{
|
||||
Tools = tools,
|
||||
Instructions = instructions,
|
||||
}
|
||||
},
|
||||
clientFactory,
|
||||
loggerFactory,
|
||||
services,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AI agent from an <see cref="AssistantClient"/> using the OpenAI Assistant API.
|
||||
/// </summary>
|
||||
/// <param name="client">The OpenAI <see cref="AssistantClient" /> to use for the agent.</param>
|
||||
/// <param name="model">The model identifier to use (e.g., "gpt-4").</param>
|
||||
/// <param name="options">Full set of options to configure the agent.</param>
|
||||
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="ChatClientAgent"/> instance backed by the OpenAI Assistant service.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="client"/> or <paramref name="model"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace.</exception>
|
||||
[Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this AssistantClient client,
|
||||
string model,
|
||||
ChatClientAgentOptions options,
|
||||
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||
ILoggerFactory? loggerFactory = null,
|
||||
IServiceProvider? services = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(client);
|
||||
Throw.IfNull(model);
|
||||
Throw.IfNull(options);
|
||||
|
||||
var assistantOptions = new AssistantCreationOptions()
|
||||
{
|
||||
Name = options.Name,
|
||||
Description = options.Description,
|
||||
Instructions = options.ChatOptions?.Instructions,
|
||||
};
|
||||
|
||||
// Convert AITools to ToolDefinitions and ToolResources
|
||||
var toolDefinitionsAndResources = ConvertAIToolsToToolDefinitions(options.ChatOptions?.Tools);
|
||||
if (toolDefinitionsAndResources.ToolDefinitions is { Count: > 0 } toolDefinitions)
|
||||
{
|
||||
toolDefinitions.ForEach(x => assistantOptions.Tools.Add(x));
|
||||
}
|
||||
if (toolDefinitionsAndResources.ToolResources is not null)
|
||||
{
|
||||
assistantOptions.ToolResources = toolDefinitionsAndResources.ToolResources;
|
||||
}
|
||||
|
||||
// Create the assistant in the assistant service.
|
||||
var assistantCreateResult = await client.CreateAssistantAsync(model, assistantOptions, cancellationToken).ConfigureAwait(false);
|
||||
var assistantId = assistantCreateResult.Value.Id;
|
||||
|
||||
// Build the local agent object.
|
||||
var chatClient = client.AsIChatClient(assistantId);
|
||||
if (clientFactory is not null)
|
||||
{
|
||||
chatClient = clientFactory(chatClient);
|
||||
}
|
||||
|
||||
var agentOptions = options.Clone();
|
||||
agentOptions.Id = assistantId;
|
||||
options.ChatOptions ??= new ChatOptions();
|
||||
options.ChatOptions!.Tools = toolDefinitionsAndResources.FunctionToolsAndOtherTools;
|
||||
|
||||
return new ChatClientAgent(chatClient, agentOptions, loggerFactory, services);
|
||||
}
|
||||
|
||||
private static (List<ToolDefinition>? ToolDefinitions, ToolResources? ToolResources, List<AITool>? FunctionToolsAndOtherTools) ConvertAIToolsToToolDefinitions(IList<AITool>? tools)
|
||||
{
|
||||
List<ToolDefinition>? toolDefinitions = null;
|
||||
ToolResources? toolResources = null;
|
||||
List<AITool>? functionToolsAndOtherTools = null;
|
||||
|
||||
if (tools is not null)
|
||||
{
|
||||
foreach (AITool tool in tools)
|
||||
{
|
||||
switch (tool)
|
||||
{
|
||||
case HostedCodeInterpreterTool codeTool:
|
||||
|
||||
toolDefinitions ??= [];
|
||||
toolDefinitions.Add(new CodeInterpreterToolDefinition());
|
||||
|
||||
if (codeTool.Inputs is { Count: > 0 })
|
||||
{
|
||||
foreach (var input in codeTool.Inputs)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HostedFileContent hostedFile:
|
||||
// If the input is a HostedFileContent, we can use its ID directly.
|
||||
toolResources ??= new();
|
||||
toolResources.CodeInterpreter ??= new();
|
||||
toolResources.CodeInterpreter.FileIds.Add(hostedFile.FileId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HostedFileSearchTool fileSearchTool:
|
||||
toolDefinitions ??= [];
|
||||
toolDefinitions.Add(new FileSearchToolDefinition
|
||||
{
|
||||
MaxResults = fileSearchTool.MaximumResultCount,
|
||||
});
|
||||
|
||||
if (fileSearchTool.Inputs is { Count: > 0 })
|
||||
{
|
||||
foreach (var input in fileSearchTool.Inputs)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HostedVectorStoreContent hostedVectorStore:
|
||||
toolResources ??= new();
|
||||
toolResources.FileSearch ??= new();
|
||||
toolResources.FileSearch.VectorStoreIds.Add(hostedVectorStore.VectorStoreId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
functionToolsAndOtherTools ??= [];
|
||||
functionToolsAndOtherTools.Add(tool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (toolDefinitions, toolResources, functionToolsAndOtherTools);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative;
|
||||
/// <param name="projectCredentials">The credentials used to authenticate with the Foundry project. This must be a valid instance of <see cref="TokenCredential"/>.</param>
|
||||
public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential projectCredentials) : ResponseAgentProvider
|
||||
{
|
||||
private readonly Dictionary<string, ProjectsAgentVersion> _versionCache = [];
|
||||
private readonly Dictionary<string, AgentVersion> _versionCache = [];
|
||||
private readonly Dictionary<string, AIAgent> _agentCache = [];
|
||||
|
||||
private AIProjectClient? _agentClient;
|
||||
@@ -99,7 +99,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
IDictionary<string, object?>? inputArguments,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
ProjectsAgentVersion agentVersionResult = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
|
||||
AgentVersion agentVersionResult = await this.QueryAgentAsync(agentId, agentVersion, cancellationToken).ConfigureAwait(false);
|
||||
AIAgent agent = await this.GetAgentAsync(agentVersionResult, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
ChatOptions chatOptions =
|
||||
@@ -133,10 +133,10 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ProjectsAgentVersion> QueryAgentAsync(string agentName, string? agentVersion, CancellationToken cancellationToken = default)
|
||||
private async Task<AgentVersion> QueryAgentAsync(string agentName, string? agentVersion, CancellationToken cancellationToken = default)
|
||||
{
|
||||
string agentKey = $"{agentName}:{agentVersion}";
|
||||
if (this._versionCache.TryGetValue(agentKey, out ProjectsAgentVersion? targetAgent))
|
||||
if (this._versionCache.TryGetValue(agentKey, out AgentVersion? targetAgent))
|
||||
{
|
||||
return targetAgent;
|
||||
}
|
||||
@@ -145,8 +145,8 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
|
||||
if (string.IsNullOrEmpty(agentVersion))
|
||||
{
|
||||
ProjectsAgentRecord agentRecord =
|
||||
await client.AgentAdministrationClient.GetAgentAsync(
|
||||
AgentRecord agentRecord =
|
||||
await client.Agents.GetAgentAsync(
|
||||
agentName,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -155,7 +155,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
else
|
||||
{
|
||||
targetAgent =
|
||||
await client.AgentAdministrationClient.GetAgentVersionAsync(
|
||||
await client.Agents.GetAgentVersionAsync(
|
||||
agentName,
|
||||
agentVersion,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
@@ -166,7 +166,7 @@ public sealed class AzureAgentProvider(Uri projectEndpoint, TokenCredential proj
|
||||
return targetAgent;
|
||||
}
|
||||
|
||||
private async Task<AIAgent> GetAgentAsync(ProjectsAgentVersion agentVersion, CancellationToken cancellationToken = default)
|
||||
private async Task<AIAgent> GetAgentAsync(AgentVersion agentVersion, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this._agentCache.TryGetValue(agentVersion.Id, out AIAgent? agent))
|
||||
{
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(RepoRoot)/dotnet/nuget/nuget-package.props" />
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Agents.AI.Workflows.Specialized;
|
||||
@@ -155,7 +154,6 @@ public static partial class AgentWorkflowBuilder
|
||||
/// The <see cref="AIAgent"/> must be capable of understanding those <see cref="AgentRunOptions"/> provided. If the agent
|
||||
/// ignores the tools or is otherwise unable to advertize them to the underlying provider, handoffs will not occur.
|
||||
/// </remarks>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public static HandoffWorkflowBuilder CreateHandoffBuilderWith(AIAgent initialAgent)
|
||||
{
|
||||
Throw.IfNull(initialAgent);
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Config`1</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.ConfigurationExtensions</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`1</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.Workflows.Configured`2</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.AgentWorkflowBuilder.CreateHandoffBuilderWith(Microsoft.Agents.AI.AIAgent)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.BindExecutor``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.Workflows.ExecutorBindingExtensions.ConfigureFactory``2(System.Func{Microsoft.Agents.AI.Workflows.Config{``1},System.String,System.Threading.Tasks.ValueTask{``0}},System.String,``1)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.Workflows.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
</Suppressions>
|
||||
@@ -23,8 +23,7 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
private readonly CancellationTokenSource _runLoopCancellation;
|
||||
private readonly bool _disableRunLoop;
|
||||
private Task? _runLoopTask;
|
||||
private volatile RunStatus _runStatus = RunStatus.NotStarted;
|
||||
|
||||
private RunStatus _runStatus = RunStatus.NotStarted;
|
||||
private int _completionEpoch; // Tracks which completion signal belongs to which consumer iteration
|
||||
|
||||
public StreamingRunEventStream(ISuperStepRunner stepRunner, bool disableRunLoop = false)
|
||||
@@ -128,7 +127,7 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
|
||||
// Wait for next input from the consumer
|
||||
// Works for both Idle (no work) and PendingRequests (waiting for responses)
|
||||
await this._inputWaiter.WaitForInputAsync(linkedSource.Token).ConfigureAwait(false);
|
||||
await this._inputWaiter.WaitForInputAsync(TimeSpan.FromSeconds(1), linkedSource.Token).ConfigureAwait(false);
|
||||
|
||||
// When signaled, resume running
|
||||
this._runStatus = RunStatus.Running;
|
||||
@@ -210,10 +209,7 @@ internal sealed class StreamingRunEventStream : IRunEventStream
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Get the current epoch - we'll only respond to completion signals from this epoch or later
|
||||
int currentEpoch = Volatile.Read(ref this._completionEpoch);
|
||||
|
||||
bool expectingFreshWork = this._stepRunner.HasUnprocessedMessages || this._runStatus == RunStatus.Running;
|
||||
int myEpoch = expectingFreshWork ? currentEpoch + 1 : currentEpoch;
|
||||
int myEpoch = Volatile.Read(ref this._completionEpoch) + 1;
|
||||
|
||||
// Use custom async enumerable to avoid exceptions on cancellation.
|
||||
NonThrowingChannelReaderAsyncEnumerable<WorkflowEvent> eventStream = new(this._eventChannel.Reader);
|
||||
|
||||
@@ -310,40 +310,22 @@ public abstract class Executor : IIdentified
|
||||
return result.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked once per superstep before any messages are delivered to the Executor.
|
||||
/// </summary>
|
||||
/// <param name="context">The workflow context.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
|
||||
/// The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
protected internal virtual ValueTask OnMessageDeliveryStartingAsync(IWorkflowContext context, CancellationToken cancellationToken = default) => default;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked once per superstep after all messages have been delivered to the Executor.
|
||||
/// </summary>
|
||||
/// <param name="context">The workflow context.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
|
||||
/// The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
protected internal virtual ValueTask OnMessageDeliveryFinishedAsync(IWorkflowContext context, CancellationToken cancellationToken = default) => default;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked before a checkpoint is saved, allowing custom pre-save logic in derived classes.
|
||||
/// </summary>
|
||||
/// <param name="context">The workflow context.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
|
||||
/// The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
protected internal virtual ValueTask OnCheckpointingAsync(IWorkflowContext context, CancellationToken cancellationToken = default) => default;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked after a checkpoint is loaded, allowing custom post-load logic in derived classes.
|
||||
/// </summary>
|
||||
/// <param name="context">The workflow context.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
|
||||
/// The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A ValueTask representing the asynchronous operation.</returns>
|
||||
protected internal virtual ValueTask OnCheckpointRestoredAsync(IWorkflowContext context, CancellationToken cancellationToken = default) => default;
|
||||
|
||||
/// <summary>
|
||||
|
||||
-10
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.Agents.AI.Workflows.Specialized;
|
||||
using Microsoft.Extensions.AI;
|
||||
@@ -10,21 +9,13 @@ using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.AI.Workflows;
|
||||
|
||||
internal static class DiagnosticConstants
|
||||
{
|
||||
public const string ExperimentalFeatureDiagnostic = "MAAIW001";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Obsolete("Prefer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed in a future release before GA.")]
|
||||
#pragma warning disable MAAIW001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||
public sealed class HandoffsWorkflowBuilder(AIAgent initialAgent) : HandoffWorkflowBuilderCore<HandoffsWorkflowBuilder>(initialAgent)
|
||||
#pragma warning restore MAAIW001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public sealed class HandoffWorkflowBuilder(AIAgent initialAgent) : HandoffWorkflowBuilderCore<HandoffWorkflowBuilder>(initialAgent)
|
||||
{
|
||||
}
|
||||
@@ -32,7 +23,6 @@ public sealed class HandoffWorkflowBuilder(AIAgent initialAgent) : HandoffWorkfl
|
||||
/// <summary>
|
||||
/// Provides a builder for specifying the handoff relationships between agents and building the resulting workflow.
|
||||
/// </summary>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
public class HandoffWorkflowBuilderCore<TBuilder> where TBuilder : HandoffWorkflowBuilderCore<TBuilder>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -182,9 +182,6 @@ public sealed class InProcessExecutionEnvironment : IWorkflowExecutionEnvironmen
|
||||
AsyncRunHandle runHandle = await this.ResumeRunAsync(workflow, fromCheckpoint, [], cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Run run = new(runHandle);
|
||||
await run.RunToNextHaltAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return run;
|
||||
return new(runHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,33 +249,17 @@ internal sealed class InProcessRunner : ISuperStepRunner, ICheckpointingHandle
|
||||
Executor executor = await this.RunContext.EnsureExecutorAsync(receiverId, this.StepTracer, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
this.StepTracer.TraceActivated(receiverId);
|
||||
|
||||
// TODO: #5084 - Add delivery-level activity (max one per step per executor) to capture non-message
|
||||
// specific invocations of executor logic.
|
||||
IWorkflowContext tracelessContext = this.RunContext.BindWorkflowContext(receiverId);
|
||||
|
||||
try
|
||||
while (envelopes.TryDequeue(out var envelope))
|
||||
{
|
||||
await executor.OnMessageDeliveryStartingAsync(tracelessContext, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
(object message, TypeId messageType) = await TranslateMessageAsync(envelope).ConfigureAwait(false);
|
||||
|
||||
while (envelopes.TryDequeue(out var envelope))
|
||||
{
|
||||
(object message, TypeId messageType) = await TranslateMessageAsync(envelope).ConfigureAwait(false);
|
||||
|
||||
await executor.ExecuteCoreAsync(
|
||||
message,
|
||||
messageType,
|
||||
this.RunContext.BindWorkflowContext(receiverId, envelope.TraceContext),
|
||||
this.TelemetryContext,
|
||||
cancellationToken
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await executor.OnMessageDeliveryFinishedAsync(tracelessContext, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await executor.ExecuteCoreAsync(
|
||||
message,
|
||||
messageType,
|
||||
this.RunContext.BindWorkflowContext(receiverId, envelope.TraceContext),
|
||||
this.TelemetryContext,
|
||||
cancellationToken
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
async ValueTask<(object, TypeId)> TranslateMessageAsync(MessageEnvelope envelope)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<NoWarn>$(NoWarn);MEAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<InjectSharedThrow>true</InjectSharedThrow>
|
||||
<InjectIsExternalInitOnLegacy>true</InjectIsExternalInitOnLegacy>
|
||||
<InjectExperimentalAttributeOnLegacy>true</InjectExperimentalAttributeOnLegacy>
|
||||
<InjectTrimAttributesOnLegacy>true</InjectTrimAttributesOnLegacy>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
@@ -32,7 +31,6 @@ internal sealed class HandoffAgentExecutorOptions
|
||||
public HandoffToolCallFilteringBehavior ToolCallFilteringBehavior { get; set; } = HandoffToolCallFilteringBehavior.HandoffOnly;
|
||||
}
|
||||
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal sealed class HandoffMessagesFilter
|
||||
{
|
||||
private readonly HandoffToolCallFilteringBehavior _filteringBehavior;
|
||||
@@ -42,7 +40,6 @@ internal sealed class HandoffMessagesFilter
|
||||
this._filteringBehavior = filteringBehavior;
|
||||
}
|
||||
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal static bool IsHandoffFunctionName(string name)
|
||||
{
|
||||
return name.StartsWith(HandoffWorkflowBuilder.FunctionPrefix, StringComparison.Ordinal);
|
||||
@@ -167,7 +164,6 @@ internal sealed class HandoffMessagesFilter
|
||||
}
|
||||
|
||||
/// <summary>Executor used to represent an agent in a handoffs workflow, responding to <see cref="HandoffState"/> events.</summary>
|
||||
[Experimental(DiagnosticConstants.ExperimentalFeatureDiagnostic)]
|
||||
internal sealed class HandoffAgentExecutor(
|
||||
AIAgent agent,
|
||||
HandoffAgentExecutorOptions options) : Executor<HandoffState, HandoffState>(agent.GetDescriptiveId(), declareCrossRunShareable: true), IResettableExecutor
|
||||
|
||||
@@ -2,176 +2,71 @@
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net10.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net10.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net472/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net472/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net8.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net8.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<Left>lib/net9.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/net9.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(Microsoft.Agents.AI.AgentInlineSkill[])</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProvider</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.AgentSkillsProvider.#ctor(System.Collections.Generic.IEnumerable{Microsoft.Agents.AI.AgentInlineSkill},Microsoft.Agents.AI.AgentSkillsProviderOptions,Microsoft.Extensions.Logging.ILoggerFactory)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.get_SimulateServiceStoredChatHistory</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Agents.AI.ChatClientAgentOptions.set_SimulateServiceStoredChatHistory(System.Boolean)</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Microsoft.Extensions.AI.ChatClientBuilderExtensions.UseServiceStoredChatHistorySimulation(Microsoft.Extensions.AI.ChatClientBuilder)</Target>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Microsoft.Agents.AI.FileAgentSkillsProviderOptions</Target>
|
||||
<Left>lib/netstandard2.0/Microsoft.Agents.AI.dll</Left>
|
||||
<Right>lib/netstandard2.0/Microsoft.Agents.AI.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<IsReleased>true</IsReleased>
|
||||
<IsReleaseCandidate>true</IsReleaseCandidate>
|
||||
<NoWarn>$(NoWarn);MEAI001;MAAI001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.AI;
|
||||
@@ -37,11 +36,6 @@ public abstract class AgentSkillScript
|
||||
/// </summary>
|
||||
public string? Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the JSON schema describing the parameters accepted by this script, or <see langword="null"/> if not available.
|
||||
/// </summary>
|
||||
public virtual JsonElement? ParametersSchema => null;
|
||||
|
||||
/// <summary>
|
||||
/// Runs the script with the given arguments.
|
||||
/// </summary>
|
||||
|
||||
@@ -117,24 +117,26 @@ public sealed partial class AgentSkillsProvider : AIContextProvider
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AgentSkillsProvider"/> class.
|
||||
/// Initializes a new instance of the <see cref="AgentSkillsProvider"/> class
|
||||
/// with one or more inline (code-defined) skills.
|
||||
/// Duplicate skill names are automatically deduplicated (first occurrence wins).
|
||||
/// </summary>
|
||||
/// <param name="skills">The skills to include.</param>
|
||||
public AgentSkillsProvider(params AgentSkill[] skills)
|
||||
: this(skills as IEnumerable<AgentSkill>)
|
||||
/// <param name="skills">The inline skills to include.</param>
|
||||
public AgentSkillsProvider(params AgentInlineSkill[] skills)
|
||||
: this(skills as IEnumerable<AgentInlineSkill>)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AgentSkillsProvider"/> class.
|
||||
/// Initializes a new instance of the <see cref="AgentSkillsProvider"/> class
|
||||
/// with inline (code-defined) skills.
|
||||
/// Duplicate skill names are automatically deduplicated (first occurrence wins).
|
||||
/// </summary>
|
||||
/// <param name="skills">The skills to include.</param>
|
||||
/// <param name="skills">The inline skills to include.</param>
|
||||
/// <param name="options">Optional provider configuration.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory.</param>
|
||||
public AgentSkillsProvider(
|
||||
IEnumerable<AgentSkill> skills,
|
||||
IEnumerable<AgentInlineSkill> skills,
|
||||
AgentSkillsProviderOptions? options = null,
|
||||
ILoggerFactory? loggerFactory = null)
|
||||
: this(
|
||||
|
||||
@@ -11,31 +11,15 @@ namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Fluent builder for constructing an <see cref="AgentSkillsProvider"/> backed by a composite source.
|
||||
/// Intended for advanced scenarios where the simple <see cref="AgentSkillsProvider"/> constructors are insufficient.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// For simple, single-source scenarios, prefer the <see cref="AgentSkillsProvider"/> constructors directly
|
||||
/// (e.g., passing a skill directory path or a set of skills). Use this builder when you need one or more
|
||||
/// of the following advanced capabilities:
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description><strong>Mixed skill types</strong> — combine file-based, code-defined (<see cref="AgentInlineSkill"/>),
|
||||
/// and class-based (<see cref="AgentClassSkill"/>) skills in a single provider.</description></item>
|
||||
/// <item><description><strong>Multiple file script runners</strong> — use different script runners for different
|
||||
/// file skill directories via per-source <c>scriptRunner</c> parameters on
|
||||
/// <see cref="UseFileSkill"/> / <see cref="UseFileSkills(IEnumerable{string}, AgentFileSkillsSourceOptions?, AgentFileSkillScriptRunner?)"/>.</description></item>
|
||||
/// <item><description><strong>Skill filtering</strong> — include or exclude skills using a predicate
|
||||
/// via <see cref="UseFilter"/>.</description></item>
|
||||
/// </list>
|
||||
/// <para>
|
||||
/// Example — combining file-based and code-defined skills:
|
||||
/// Use this builder to combine multiple skill sources into a single provider:
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// var provider = new AgentSkillsProviderBuilder()
|
||||
/// .UseFileSkills("/path/to/skills")
|
||||
/// .UseSkills(myInlineSkill1, myInlineSkill2)
|
||||
/// .UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
|
||||
/// .Build();
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Shared.DiagnosticIds;
|
||||
|
||||
namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class for defining skills as C# classes that bundle all components together.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Inherit from this class to create a self-contained skill definition. Override the abstract
|
||||
/// properties to provide name, description, and instructions. Use <see cref="CreateResource(string, object, string?)"/>,
|
||||
/// <see cref="CreateResource(string, Delegate, string?)"/>, and <see cref="CreateScript"/> to define
|
||||
/// inline resources and scripts.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class PdfFormatterSkill : AgentClassSkill
|
||||
/// {
|
||||
/// private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
/// private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
///
|
||||
/// public override AgentSkillFrontmatter Frontmatter { get; } = new("pdf-formatter", "Format documents as PDF.");
|
||||
/// protected override string Instructions => "Use this skill to format documents...";
|
||||
///
|
||||
/// public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
/// [
|
||||
/// CreateResource("template", "Use this template..."),
|
||||
/// ];
|
||||
///
|
||||
/// public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
/// [
|
||||
/// CreateScript("format-pdf", FormatPdf),
|
||||
/// ];
|
||||
///
|
||||
/// private static string FormatPdf(string content) => content;
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
[Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
|
||||
public abstract class AgentClassSkill : AgentSkill
|
||||
{
|
||||
private string? _content;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw instructions text for this skill.
|
||||
/// </summary>
|
||||
protected abstract string Instructions { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>
|
||||
/// Returns a synthesized XML document containing name, description, instructions, resources, and scripts.
|
||||
/// The result is cached after the first access. Override to provide custom content.
|
||||
/// </remarks>
|
||||
public override string Content => this._content ??= AgentInlineSkillContentBuilder.Build(
|
||||
this.Frontmatter.Name,
|
||||
this.Frontmatter.Description,
|
||||
this.Instructions,
|
||||
this.Resources,
|
||||
this.Scripts);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a skill resource backed by a static value.
|
||||
/// </summary>
|
||||
/// <param name="name">The resource name.</param>
|
||||
/// <param name="value">The static resource value.</param>
|
||||
/// <param name="description">An optional description of the resource.</param>
|
||||
/// <returns>A new <see cref="AgentSkillResource"/> instance.</returns>
|
||||
protected static AgentSkillResource CreateResource(string name, object value, string? description = null)
|
||||
=> new AgentInlineSkillResource(name, value, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a skill resource backed by a delegate that produces a dynamic value.
|
||||
/// </summary>
|
||||
/// <param name="name">The resource name.</param>
|
||||
/// <param name="method">A method that produces the resource value when requested.</param>
|
||||
/// <param name="description">An optional description of the resource.</param>
|
||||
/// <returns>A new <see cref="AgentSkillResource"/> instance.</returns>
|
||||
protected static AgentSkillResource CreateResource(string name, Delegate method, string? description = null)
|
||||
=> new AgentInlineSkillResource(name, method, description);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a skill script backed by a delegate.
|
||||
/// </summary>
|
||||
/// <param name="name">The script name.</param>
|
||||
/// <param name="method">A method to execute when the script is invoked.</param>
|
||||
/// <param name="description">An optional description of the script.</param>
|
||||
/// <returns>A new <see cref="AgentSkillScript"/> instance.</returns>
|
||||
protected static AgentSkillScript CreateScript(string name, Delegate method, string? description = null)
|
||||
=> new AgentInlineSkillScript(name, method, description);
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.DiagnosticIds;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
@@ -25,8 +27,8 @@ namespace Microsoft.Agents.AI;
|
||||
public sealed class AgentInlineSkill : AgentSkill
|
||||
{
|
||||
private readonly string _instructions;
|
||||
private List<AgentInlineSkillResource>? _resources;
|
||||
private List<AgentInlineSkillScript>? _scripts;
|
||||
private List<AgentSkillResource>? _resources;
|
||||
private List<AgentSkillScript>? _scripts;
|
||||
private string? _cachedContent;
|
||||
|
||||
/// <summary>
|
||||
@@ -75,7 +77,7 @@ public sealed class AgentInlineSkill : AgentSkill
|
||||
public override AgentSkillFrontmatter Frontmatter { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Content => this._cachedContent ??= AgentInlineSkillContentBuilder.Build(this.Frontmatter.Name, this.Frontmatter.Description, this._instructions, this._resources, this._scripts);
|
||||
public override string Content => this._cachedContent ??= this.BuildContent();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources;
|
||||
@@ -123,4 +125,91 @@ public sealed class AgentInlineSkill : AgentSkill
|
||||
(this._scripts ??= []).Add(new AgentInlineSkillScript(name, method, description));
|
||||
return this;
|
||||
}
|
||||
|
||||
private string BuildContent()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"<name>{EscapeXmlString(this.Frontmatter.Name)}</name>\n")
|
||||
.Append($"<description>{EscapeXmlString(this.Frontmatter.Description)}</description>\n\n")
|
||||
.Append("<instructions>\n")
|
||||
.Append(EscapeXmlString(this._instructions))
|
||||
.Append("\n</instructions>");
|
||||
|
||||
if (this.Resources is { Count: > 0 })
|
||||
{
|
||||
sb.Append("\n\n<resources>\n");
|
||||
foreach (var resource in this.Resources)
|
||||
{
|
||||
if (resource.Description is not null)
|
||||
{
|
||||
sb.Append($" <resource name=\"{EscapeXmlString(resource.Name)}\" description=\"{EscapeXmlString(resource.Description)}\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append($" <resource name=\"{EscapeXmlString(resource.Name)}\"/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("</resources>");
|
||||
}
|
||||
|
||||
if (this.Scripts is { Count: > 0 })
|
||||
{
|
||||
sb.Append("\n\n<scripts>\n");
|
||||
foreach (var script in this.Scripts)
|
||||
{
|
||||
JsonElement? parametersSchema = ((AgentInlineSkillScript)script).ParametersSchema;
|
||||
|
||||
if (script.Description is null && parametersSchema is null)
|
||||
{
|
||||
sb.Append($" <script name=\"{EscapeXmlString(script.Name)}\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(script.Description is not null
|
||||
? $" <script name=\"{EscapeXmlString(script.Name)}\" description=\"{EscapeXmlString(script.Description)}\">\n"
|
||||
: $" <script name=\"{EscapeXmlString(script.Name)}\">\n");
|
||||
|
||||
if (parametersSchema is not null)
|
||||
{
|
||||
sb.Append($" <parameters_schema>{EscapeXmlString(parametersSchema.Value.GetRawText(), preserveQuotes: true)}</parameters_schema>\n");
|
||||
}
|
||||
|
||||
sb.Append(" </script>\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("</scripts>");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes XML special characters: always escapes <c>&</c>, <c><</c>, <c>></c>,
|
||||
/// <c>"</c>, and <c>'</c>. When <paramref name="preserveQuotes"/> is <see langword="true"/>,
|
||||
/// quotes are left unescaped to preserve readability of embedded content such as JSON.
|
||||
/// </summary>
|
||||
/// <param name="value">The string to escape.</param>
|
||||
/// <param name="preserveQuotes">
|
||||
/// When <see langword="true"/>, leaves <c>"</c> and <c>'</c> unescaped for use in XML element content (e.g., JSON).
|
||||
/// When <see langword="false"/> (default), escapes all XML special characters including quotes.
|
||||
/// </param>
|
||||
private static string EscapeXmlString(string value, bool preserveQuotes = false)
|
||||
{
|
||||
var result = value
|
||||
.Replace("&", "&")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">");
|
||||
|
||||
if (!preserveQuotes)
|
||||
{
|
||||
result = result
|
||||
.Replace("\"", """)
|
||||
.Replace("'", "'");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Internal helper that builds XML-structured content strings for code-defined and class-based skills.
|
||||
/// </summary>
|
||||
internal static class AgentInlineSkillContentBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the complete skill content containing name, description, instructions, resources, and scripts.
|
||||
/// </summary>
|
||||
/// <param name="name">The skill name.</param>
|
||||
/// <param name="description">The skill description.</param>
|
||||
/// <param name="instructions">The raw instructions text.</param>
|
||||
/// <param name="resources">Optional resources associated with the skill.</param>
|
||||
/// <param name="scripts">Optional scripts associated with the skill.</param>
|
||||
/// <returns>An XML-structured content string.</returns>
|
||||
public static string Build(
|
||||
string name,
|
||||
string description,
|
||||
string instructions,
|
||||
IReadOnlyList<AgentSkillResource>? resources,
|
||||
IReadOnlyList<AgentSkillScript>? scripts)
|
||||
{
|
||||
_ = Throw.IfNullOrWhitespace(name);
|
||||
_ = Throw.IfNullOrWhitespace(description);
|
||||
_ = Throw.IfNullOrWhitespace(instructions);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"<name>{EscapeXmlString(name)}</name>\n")
|
||||
.Append($"<description>{EscapeXmlString(description)}</description>\n\n")
|
||||
.Append("<instructions>\n")
|
||||
.Append(EscapeXmlString(instructions))
|
||||
.Append("\n</instructions>");
|
||||
|
||||
if (resources is { Count: > 0 })
|
||||
{
|
||||
sb.Append("\n\n<resources>\n");
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
if (resource.Description is not null)
|
||||
{
|
||||
sb.Append($" <resource name=\"{EscapeXmlString(resource.Name)}\" description=\"{EscapeXmlString(resource.Description)}\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append($" <resource name=\"{EscapeXmlString(resource.Name)}\"/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("</resources>");
|
||||
}
|
||||
|
||||
if (scripts is { Count: > 0 })
|
||||
{
|
||||
sb.Append("\n\n<scripts>\n");
|
||||
foreach (var script in scripts)
|
||||
{
|
||||
var parametersSchema = script.ParametersSchema;
|
||||
|
||||
if (script.Description is null && parametersSchema is null)
|
||||
{
|
||||
sb.Append($" <script name=\"{EscapeXmlString(script.Name)}\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(script.Description is not null
|
||||
? $" <script name=\"{EscapeXmlString(script.Name)}\" description=\"{EscapeXmlString(script.Description)}\">\n"
|
||||
: $" <script name=\"{EscapeXmlString(script.Name)}\">\n");
|
||||
|
||||
if (parametersSchema is not null)
|
||||
{
|
||||
sb.Append($" <parameters_schema>{EscapeXmlString(parametersSchema.Value.GetRawText(), preserveQuotes: true)}</parameters_schema>\n");
|
||||
}
|
||||
|
||||
sb.Append(" </script>\n");
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("</scripts>");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes XML special characters: always escapes <c>&</c>, <c><</c>, <c>></c>,
|
||||
/// <c>"</c>, and <c>'</c>. When <paramref name="preserveQuotes"/> is <see langword="true"/>,
|
||||
/// quotes are left unescaped to preserve readability of embedded content such as JSON.
|
||||
/// </summary>
|
||||
/// <param name="value">The string to escape.</param>
|
||||
/// <param name="preserveQuotes">
|
||||
/// When <see langword="true"/>, leaves <c>"</c> and <c>'</c> unescaped for use in XML element content (e.g., JSON).
|
||||
/// When <see langword="false"/> (default), escapes all XML special characters including quotes.
|
||||
/// </param>
|
||||
private static string EscapeXmlString(string value, bool preserveQuotes = false)
|
||||
{
|
||||
var result = value
|
||||
.Replace("&", "&")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">");
|
||||
|
||||
if (!preserveQuotes)
|
||||
{
|
||||
result = result
|
||||
.Replace("\"", """)
|
||||
.Replace("'", "'");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ internal sealed class AgentInlineSkillScript : AgentSkillScript
|
||||
/// <summary>
|
||||
/// Gets the JSON schema describing the parameters accepted by this script, or <see langword="null"/> if not available.
|
||||
/// </summary>
|
||||
public override JsonElement? ParametersSchema => this._function.JsonSchema;
|
||||
public JsonElement? ParametersSchema => this._function.JsonSchema;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<object?> RunAsync(AgentSkill skill, AIFunctionArguments arguments, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -26,6 +26,7 @@ internal static class DiagnosticIds
|
||||
// We use the same IDs so consumers do not need to suppress additional diagnostics
|
||||
// when using the experimental OpenAI APIs.
|
||||
internal const string AIOpenAIResponses = "OPENAI001";
|
||||
internal const string AIOpenAIAssistants = "OPENAI001";
|
||||
|
||||
private const string MEAIExperiments = "MEAI001";
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@ namespace Shared.Foundry;
|
||||
|
||||
internal static class AgentFactory
|
||||
{
|
||||
public static async ValueTask<ProjectsAgentVersion> CreateAgentAsync(
|
||||
public static async ValueTask<AgentVersion> CreateAgentAsync(
|
||||
this AIProjectClient aiProjectClient,
|
||||
string agentName,
|
||||
ProjectsAgentDefinition agentDefinition,
|
||||
AgentDefinition agentDefinition,
|
||||
string agentDescription)
|
||||
{
|
||||
ProjectsAgentVersionCreationOptions options =
|
||||
AgentVersionCreationOptions options =
|
||||
new(agentDefinition)
|
||||
{
|
||||
Description = agentDescription,
|
||||
@@ -29,7 +29,7 @@ internal static class AgentFactory
|
||||
},
|
||||
};
|
||||
|
||||
ProjectsAgentVersion agentVersion = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(agentName, options).ConfigureAwait(false);
|
||||
AgentVersion agentVersion = await aiProjectClient.Agents.CreateAgentVersionAsync(agentName, options).ConfigureAwait(false);
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
try
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for versioned <see cref="FoundryAgent"/> creation via
|
||||
/// <c>AIProjectClient.AgentAdministrationClient.CreateAgentVersionAsync</c> and <c>AIProjectClient.AsAIAgent(ProjectsAgentVersion)</c>.
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentCreateTests
|
||||
{
|
||||
@@ -32,10 +32,10 @@ public class FoundryVersionedAgentCreateTests
|
||||
const string AgentInstructions = "You are an integration test agent";
|
||||
|
||||
// Act.
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions
|
||||
})
|
||||
@@ -53,17 +53,17 @@ public class FoundryVersionedAgentCreateTests
|
||||
Assert.Equal(AgentDescription, agent.Description);
|
||||
Assert.Equal(AgentInstructions, agent.GetService<ChatClientAgent>()!.Instructions);
|
||||
|
||||
var agentRecord = await this._client.AgentAdministrationClient.GetAgentAsync(agent.Name);
|
||||
var agentRecord = await this._client.Agents.GetAgentAsync(agent.Name);
|
||||
Assert.NotNull(agentRecord);
|
||||
Assert.Equal(AgentName, agentRecord.Value.Name);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(agentRecord.Value.GetLatestVersion().Definition);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(agentRecord.Value.GetLatestVersion().Definition);
|
||||
Assert.Equal(AgentDescription, agentRecord.Value.GetLatestVersion().Description);
|
||||
Assert.Equal(AgentInstructions, definition.Instructions);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,15 +95,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
var vectorStoreMetadata = await projectOpenAIClient.GetProjectVectorStoresClient().CreateVectorStoreAsync(options: new() { FileIds = { uploadedAgentFile.Id }, Name = "WordCodeLookup_VectorStore" });
|
||||
|
||||
// Act — create agent version with FileSearch tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateFileSearchTool(vectorStoreIds: [vectorStoreMetadata.Value.Id]) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await projectOpenAIClient.GetProjectVectorStoresClient().DeleteVectorStoreAsync(vectorStoreMetadata.Value.Id);
|
||||
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedAgentFile.Id);
|
||||
File.Delete(searchFilePath);
|
||||
@@ -149,15 +149,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
);
|
||||
|
||||
// Act — create agent version with CodeInterpreter tool via native SDK, then wrap with AsAIAgent.
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { ResponseTool.CreateCodeInterpreterTool(new CodeInterpreterToolContainer(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration([uploadedCodeFile.Id]))) }
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion);
|
||||
|
||||
@@ -171,7 +171,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
await projectOpenAIClient.GetProjectFilesClient().DeleteFileAsync(uploadedCodeFile.Id);
|
||||
File.Delete(codeFilePath);
|
||||
}
|
||||
@@ -252,14 +252,14 @@ public class FoundryVersionedAgentCreateTests
|
||||
Description = "Retrieve information about countries by currency code"
|
||||
};
|
||||
|
||||
var definition = new DeclarativeAgentDefinition(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new PromptAgentDefinition(model: TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = { (ResponseTool)ProjectsAgentTool.CreateOpenApiTool(openApiFunction) }
|
||||
Tools = { (ResponseTool)AgentTool.CreateOpenApiTool(openApiFunction) }
|
||||
};
|
||||
|
||||
ProjectsAgentVersionCreationOptions creationOptions = new(definition);
|
||||
ProjectsAgentVersion agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(AgentName, creationOptions);
|
||||
AgentVersionCreationOptions creationOptions = new(definition);
|
||||
AgentVersion agentVersion = await this._client.Agents.CreateAgentVersionAsync(AgentName, creationOptions);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -269,7 +269,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
// Assert the agent was created correctly and retains version metadata.
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal(AgentName, agent.Name);
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
Assert.NotNull(retrievedVersion);
|
||||
|
||||
// Step 3: Call RunAsync to trigger the server-side OpenAPI function.
|
||||
@@ -301,7 +301,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
finally
|
||||
{
|
||||
// Cleanup.
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(AgentName);
|
||||
await this._client.Agents.DeleteAgentAsync(AgentName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,15 +317,15 @@ public class FoundryVersionedAgentCreateTests
|
||||
|
||||
// Create agent version with the function tool registered in the server-side definition,
|
||||
// then wrap with AsAIAgent passing the local AIFunction implementation.
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
};
|
||||
definition.Tools.Add(weatherFunction.AsOpenAIResponseTool());
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
AgentName,
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
FoundryAgent agent = this._client.AsAIAgent(agentVersion, tools: [weatherFunction]);
|
||||
|
||||
@@ -342,7 +342,7 @@ public class FoundryVersionedAgentCreateTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
await this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
await this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Foundry.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration test fixture that creates versioned Foundry agents via
|
||||
/// <c>AIProjectClient.AgentAdministrationClient.CreateAgentVersionAsync</c> and wraps them
|
||||
/// with <c>AIProjectClient.AsAIAgent(ProjectsAgentVersion)</c>.
|
||||
/// <c>AIProjectClient.Agents.CreateAgentVersionAsync</c> and wraps them
|
||||
/// with <c>AIProjectClient.AsAIAgent(AgentVersion)</c>.
|
||||
/// </summary>
|
||||
public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
@@ -121,7 +121,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
string instructions = "You are a helpful assistant.",
|
||||
IList<AITool>? aiTools = null)
|
||||
{
|
||||
var definition = new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
var definition = new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = instructions
|
||||
};
|
||||
@@ -139,9 +139,9 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
}
|
||||
}
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName(name),
|
||||
new ProjectsAgentVersionCreationOptions(definition));
|
||||
new AgentVersionCreationOptions(definition));
|
||||
|
||||
return this._client.AsAIAgent(agentVersion, tools: aiTools).GetService<ChatClientAgent>()!;
|
||||
}
|
||||
@@ -150,15 +150,15 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
|
||||
var definition = new DeclarativeAgentDefinition(
|
||||
var definition = new PromptAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new ProjectsAgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
var agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
|
||||
@@ -169,7 +169,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
$"{baseName}-{Guid.NewGuid().ToString("N").Substring(0, 8)}";
|
||||
|
||||
public Task DeleteAgentAsync(ChatClientAgent agent) =>
|
||||
this._client.AgentAdministrationClient.DeleteAgentAsync(agent.Name);
|
||||
this._client.Agents.DeleteAgentAsync(agent.Name);
|
||||
|
||||
public async Task DeleteSessionAsync(AgentSession session)
|
||||
{
|
||||
@@ -201,7 +201,7 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
|
||||
if (this._client is not null && this._agent is not null)
|
||||
{
|
||||
return new ValueTask(this._client.AgentAdministrationClient.DeleteAgentAsync(this._agent.Name));
|
||||
return new ValueTask(this._client.Agents.DeleteAgentAsync(this._agent.Name));
|
||||
}
|
||||
|
||||
return default;
|
||||
@@ -211,10 +211,10 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
{
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
GenerateUniqueAgentName("HelpfulAssistant"),
|
||||
new ProjectsAgentVersionCreationOptions(
|
||||
new DeclarativeAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
new AgentVersionCreationOptions(
|
||||
new PromptAgentDefinition(TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = "You are a helpful assistant."
|
||||
}));
|
||||
@@ -227,15 +227,15 @@ public class FoundryVersionedAgentFixture : IChatClientAgentFixture
|
||||
this._client = new(new Uri(TestConfiguration.GetRequiredValue(TestSettings.AzureAIProjectEndpoint)), TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
options.Name ??= GenerateUniqueAgentName("HelpfulAssistant");
|
||||
|
||||
var definition = new DeclarativeAgentDefinition(
|
||||
var definition = new PromptAgentDefinition(
|
||||
options.ChatOptions?.ModelId ?? TestConfiguration.GetRequiredValue(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions = options.ChatOptions?.Instructions
|
||||
};
|
||||
|
||||
var agentVersion = await this._client.AgentAdministrationClient.CreateAgentVersionAsync(
|
||||
var agentVersion = await this._client.Agents.CreateAgentVersionAsync(
|
||||
options.Name,
|
||||
new ProjectsAgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
new AgentVersionCreationOptions(definition) { Description = options.Description });
|
||||
|
||||
this._agent = this._client.AsAIAgent(agentVersion, tools: options.ChatOptions?.Tools);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.AI.Projects.Memory;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Foundry;
|
||||
|
||||
+129
-129
@@ -187,7 +187,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentRecord) Tests
|
||||
#region AsAIAgent(AIProjectClient, AgentRecord) Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent throws ArgumentNullException when AIProjectClient is null.
|
||||
@@ -197,7 +197,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient? client = null;
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
@@ -217,20 +217,20 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
mockClient.Object.AsAIAgent((ProjectsAgentRecord)null!));
|
||||
mockClient.Object.AsAIAgent((AgentRecord)null!));
|
||||
|
||||
Assert.Equal("agentRecord", exception.ParamName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord creates a valid agent.
|
||||
/// Verify that AsAIAgent with AgentRecord creates a valid agent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecord_CreatesValidAgent()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -243,14 +243,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord and clientFactory applies the factory.
|
||||
/// Verify that AsAIAgent with AgentRecord and clientFactory applies the factory.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecord_WithClientFactory_AppliesFactoryCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
TestChatClient? testChatClient = null;
|
||||
|
||||
// Act
|
||||
@@ -267,7 +267,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentVersion) Tests
|
||||
#region AsAIAgent(AIProjectClient, AgentVersion) Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent throws ArgumentNullException when AIProjectClient is null.
|
||||
@@ -277,7 +277,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient? client = null;
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
@@ -297,20 +297,20 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentNullException>(() =>
|
||||
mockClient.Object.AsAIAgent((ProjectsAgentVersion)null!));
|
||||
mockClient.Object.AsAIAgent((AgentVersion)null!));
|
||||
|
||||
Assert.Equal("agentVersion", exception.ParamName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion creates a valid agent.
|
||||
/// Verify that AsAIAgent with AgentVersion creates a valid agent.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersion_CreatesValidAgent()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -323,14 +323,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion and clientFactory applies the factory.
|
||||
/// Verify that AsAIAgent with AgentVersion and clientFactory applies the factory.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersion_WithClientFactory_AppliesFactoryCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
TestChatClient? testChatClient = null;
|
||||
|
||||
// Act
|
||||
@@ -353,7 +353,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "test", "test_function", "A test function")
|
||||
@@ -375,7 +375,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act - should not throw even without tools when requireInvocableTools is false
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -439,7 +439,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region AsAIAgent(AIProjectClient, ProjectsAgentRecord) with tools Tests
|
||||
#region AsAIAgent(AIProjectClient, AgentRecord) with tools Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with additional tools when the definition has no tools does not throw and results in an agent with no tools.
|
||||
@@ -449,7 +449,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "test", "test_function", "A test function")
|
||||
@@ -463,9 +463,9 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var chatClient = agent.GetService<IChatClient>();
|
||||
Assert.NotNull(chatClient);
|
||||
var agentVersion = chatClient.GetService<ProjectsAgentVersion>();
|
||||
var agentVersion = chatClient.GetService<AgentVersion>();
|
||||
Assert.NotNull(agentVersion);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(agentVersion.Definition);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(agentVersion.Definition);
|
||||
Assert.Empty(definition.Tools);
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord, tools: null);
|
||||
@@ -502,7 +502,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
var agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Manually add tools to the definition to simulate inline tools
|
||||
if (agentVersion.Definition is DeclarativeAgentDefinition promptDef)
|
||||
if (agentVersion.Definition is PromptAgentDefinition promptDef)
|
||||
{
|
||||
promptDef.Tools.Add(ResponseTool.CreateFunctionTool("inline_tool", BinaryData.FromString("{}"), strictModeEnabled: false));
|
||||
}
|
||||
@@ -513,9 +513,9 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Act & Assert
|
||||
var agent = client.AsAIAgent(agentVersion, tools: [invocableInlineAITool, shouldBeIgnoredTool]);
|
||||
Assert.NotNull(agent);
|
||||
var version = agent.GetService<ProjectsAgentVersion>();
|
||||
var version = agent.GetService<AgentVersion>();
|
||||
Assert.NotNull(version);
|
||||
var definition = Assert.IsType<DeclarativeAgentDefinition>(version.Definition);
|
||||
var definition = Assert.IsType<PromptAgentDefinition>(version.Definition);
|
||||
Assert.NotEmpty(definition.Tools);
|
||||
Assert.NotNull(GetAgentChatOptions(agent));
|
||||
Assert.NotNull(GetAgentChatOptions(agent)!.Tools);
|
||||
@@ -535,7 +535,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
var tools = new List<AITool>
|
||||
{
|
||||
AIFunctionFactory.Create(() => "tool1", "param_tool_1", "First parameter tool"),
|
||||
@@ -550,7 +550,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var chatClient = agent.GetService<IChatClient>();
|
||||
Assert.NotNull(chatClient);
|
||||
var agentVersion = chatClient.GetService<ProjectsAgentVersion>();
|
||||
var agentVersion = chatClient.GetService<AgentVersion>();
|
||||
Assert.NotNull(agentVersion);
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public async Task CreateAIAgentAsync_WithResponseToolsInDefinition_CreatesAgentSuccessfullyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test instructions" };
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test instructions" };
|
||||
|
||||
var fabricToolOptions = new FabricDataAgentToolOptions();
|
||||
fabricToolOptions.ProjectConnections.Add(new ToolProjectConnection("connection-id"));
|
||||
@@ -577,33 +577,33 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Add tools to the definition
|
||||
definition.Tools.Add(ResponseTool.CreateFunctionTool("create_tool", BinaryData.FromString("{}"), strictModeEnabled: false));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBingCustomSearchTool(new BingCustomSearchToolOptions([new BingCustomSearchConfiguration("connection-id", "instance-name")])));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBrowserAutomationTool(new BrowserAutomationToolOptions(new BrowserAutomationToolConnectionParameters("id"))));
|
||||
definition.Tools.Add(ProjectsAgentTool.CreateA2ATool(new Uri("https://test-uri.microsoft.com")));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateBingGroundingTool(new BingGroundingSearchToolOptions([new BingGroundingSearchConfiguration("connection-id")])));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateMicrosoftFabricTool(fabricToolOptions));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateOpenApiTool(new OpenApiFunctionDefinition("name", BinaryData.FromString(OpenAPISpec), new OpenAPIAnonymousAuthenticationDetails())));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateSharepointTool(sharepointOptions));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateStructuredOutputsTool(structuredOutputs));
|
||||
definition.Tools.Add((ResponseTool)ProjectsAgentTool.CreateAzureAISearchTool(new AzureAISearchToolOptions([new AzureAISearchToolIndex() { IndexName = "name" }])));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBingCustomSearchTool(new BingCustomSearchToolOptions([new BingCustomSearchConfiguration("connection-id", "instance-name")])));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBrowserAutomationTool(new BrowserAutomationToolOptions(new BrowserAutomationToolConnectionParameters("id"))));
|
||||
definition.Tools.Add(AgentTool.CreateA2ATool(new Uri("https://test-uri.microsoft.com")));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateBingGroundingTool(new BingGroundingSearchToolOptions([new BingGroundingSearchConfiguration("connection-id")])));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateMicrosoftFabricTool(fabricToolOptions));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateOpenApiTool(new OpenApiFunctionDefinition("name", BinaryData.FromString(OpenAPISpec), new OpenAPIAnonymousAuthenticationDetails())));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateSharepointTool(sharepointOptions));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateStructuredOutputsTool(structuredOutputs));
|
||||
definition.Tools.Add((ResponseTool)AgentTool.CreateAzureAISearchTool(new AzureAISearchToolOptions([new AzureAISearchToolIndex() { IndexName = "name" }])));
|
||||
|
||||
// Generate agent definition response with the tools
|
||||
var definitionResponse = GeneratePromptDefinitionResponse(definition, definition.Tools.Select(t => t.AsAITool()).ToList());
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<FoundryAgent>(agent);
|
||||
var agentVersion2 = agent.GetService<ProjectsAgentVersion>()!;
|
||||
var agentVersion2 = agent.GetService<AgentVersion>()!;
|
||||
Assert.NotNull(agentVersion);
|
||||
if (agentVersion2.Definition is DeclarativeAgentDefinition promptDef)
|
||||
if (agentVersion2.Definition is PromptAgentDefinition promptDef)
|
||||
{
|
||||
Assert.NotEmpty(promptDef.Tools);
|
||||
Assert.Equal(10, promptDef.Tools.Count);
|
||||
@@ -624,19 +624,19 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
functionDescription: "Gets the user's name, as used for friendly address."
|
||||
);
|
||||
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definition.Tools.Add(functionTool);
|
||||
|
||||
// Generate response with the declarative function
|
||||
var definitionResponse = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definitionResponse = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definitionResponse.Tools.Add(functionTool);
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentName: "test-agent", agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -652,7 +652,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
using var testClient = CreateTestAgentClientWithHandler();
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
|
||||
// Create a declarative function (not invocable) using AIFunctionFactory.CreateDeclaration
|
||||
using var doc = JsonDocument.Parse("{}");
|
||||
@@ -661,10 +661,10 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Add to definition
|
||||
definition.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -679,7 +679,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public async Task AsAIAgent_WithDeclarativeFunctionInDefinition_AcceptsDeclarativeFunctionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var definition = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definition = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
|
||||
// Create a declarative function (not invocable) using AIFunctionFactory.CreateDeclaration
|
||||
using var doc = JsonDocument.Parse("{}");
|
||||
@@ -689,15 +689,15 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
definition.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
// Generate response with the declarative function
|
||||
var definitionResponse = new DeclarativeAgentDefinition("test-model") { Instructions = "Test" };
|
||||
var definitionResponse = new PromptAgentDefinition("test-model") { Instructions = "Test" };
|
||||
definitionResponse.Tools.Add(declarativeFunction.AsOpenAIResponseTool() ?? throw new InvalidOperationException());
|
||||
|
||||
using var testClient = CreateTestAgentClientWithHandler(agentName: "test-agent", agentDefinitionResponse: definitionResponse);
|
||||
|
||||
var options = new ProjectsAgentVersionCreationOptions(definition);
|
||||
var options = new AgentVersionCreationOptions(definition);
|
||||
|
||||
// Act
|
||||
var agentVersion = (await testClient.Client.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agentVersion = (await testClient.Client.Agents.CreateAgentVersionAsync("test-agent", options)).Value;
|
||||
var agent = testClient.Client.AsAIAgent(agentVersion);
|
||||
|
||||
// Assert
|
||||
@@ -758,7 +758,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
int factoryCallCount = 0;
|
||||
|
||||
// Act
|
||||
@@ -785,7 +785,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent1 = client.AsAIAgent(
|
||||
@@ -904,7 +904,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Arrange
|
||||
var aiProjectClient = new AIProjectClient(new Uri("https://test.openai.azure.com/"), new FakeAuthenticationTokenProvider(), new() { Transport = new HttpClientPipelineTransport(httpClient) });
|
||||
|
||||
var agentVersion = (await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync("test-agent", new ProjectsAgentVersionCreationOptions(new DeclarativeAgentDefinition("test-model") { Instructions = "Test instructions" }))).Value;
|
||||
var agentVersion = (await aiProjectClient.Agents.CreateAgentVersionAsync("test-agent", new AgentVersionCreationOptions(new PromptAgentDefinition("test-model") { Instructions = "Test instructions" }))).Value;
|
||||
|
||||
// Act
|
||||
var agent = aiProjectClient.AsAIAgent(agentVersion);
|
||||
@@ -1043,21 +1043,21 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetService<ProjectsAgentRecord> Tests
|
||||
#region GetService<AgentRecord> Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns ProjectsAgentRecord for agents created from ProjectsAgentRecord.
|
||||
/// Verify that GetService returns AgentRecord for agents created from AgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentRecord_ReturnsAgentRecord()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
var retrievedRecord = agent.GetService<ProjectsAgentRecord>();
|
||||
var retrievedRecord = agent.GetService<AgentRecord>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrievedRecord);
|
||||
@@ -1065,7 +1065,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for ProjectsAgentRecord when agent is created from AgentReference.
|
||||
/// Verify that GetService returns null for AgentRecord when agent is created from AgentReference.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentReference_ReturnsNullForAgentRecord()
|
||||
@@ -1076,7 +1076,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentReference);
|
||||
var retrievedRecord = agent.GetService<ProjectsAgentRecord>();
|
||||
var retrievedRecord = agent.GetService<AgentRecord>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(retrievedRecord);
|
||||
@@ -1084,21 +1084,21 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetService<ProjectsAgentVersion> Tests
|
||||
#region GetService<AgentVersion> Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns ProjectsAgentVersion for agents created from ProjectsAgentVersion.
|
||||
/// Verify that GetService returns AgentVersion for agents created from AgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentVersion_ReturnsAgentVersion()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrievedVersion);
|
||||
@@ -1106,7 +1106,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for ProjectsAgentVersion when agent is created from AgentReference.
|
||||
/// Verify that GetService returns null for AgentVersion when agent is created from AgentReference.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentReference_ReturnsNullForAgentVersion()
|
||||
@@ -1117,7 +1117,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentReference);
|
||||
var retrievedVersion = agent.GetService<ProjectsAgentVersion>();
|
||||
var retrievedVersion = agent.GetService<AgentVersion>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(retrievedVersion);
|
||||
@@ -1128,14 +1128,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
#region ChatClientMetadata Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from ProjectsAgentRecord.
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from AgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithAgentRecord_IsPopulatedCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1147,18 +1147,18 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata.DefaultModelId is set from DeclarativeAgentDefinition model property.
|
||||
/// Verify that ChatClientMetadata.DefaultModelId is set from PromptAgentDefinition model property.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithDeclarativeAgentDefinition_SetsDefaultModelIdFromModel()
|
||||
public void ChatClientMetadata_WithPromptAgentDefinition_SetsDefaultModelIdFromModel()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
var definition = new DeclarativeAgentDefinition("gpt-4-turbo")
|
||||
var definition = new PromptAgentDefinition("gpt-4-turbo")
|
||||
{
|
||||
Instructions = "Test instructions"
|
||||
};
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord(definition);
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord(definition);
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1172,14 +1172,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from ProjectsAgentVersion.
|
||||
/// Verify that ChatClientMetadata is properly populated for agents created from AgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ChatClientMetadata_WithAgentVersion_IsPopulatedCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1188,7 +1188,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
// Assert
|
||||
Assert.NotNull(metadata);
|
||||
Assert.NotNull(metadata.DefaultModelId);
|
||||
Assert.Equal((agentVersion.Definition as DeclarativeAgentDefinition)!.Model, metadata.DefaultModelId);
|
||||
Assert.Equal((agentVersion.Definition as PromptAgentDefinition)!.Model, metadata.DefaultModelId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1216,14 +1216,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from ProjectsAgentRecord.
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from AgentRecord.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentRecord_ReturnsAlsoAgentReference()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecord();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1235,14 +1235,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from ProjectsAgentVersion.
|
||||
/// Verify that GetService returns null for AgentReference when agent is created from AgentVersion.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void GetService_WithAgentVersion_ReturnsAlsoAgentReference()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1278,14 +1278,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
#region Empty Version and ID Handling Tests
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord handles empty version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with AgentRecord handles empty version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecordEmptyVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithEmptyVersion();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecordWithEmptyVersion();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecordWithEmptyVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1297,14 +1297,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion handles empty version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with AgentVersion handles empty version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersionEmptyVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithEmptyVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersionWithEmptyVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersionWithEmptyVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1316,14 +1316,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentRecord handles whitespace-only version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with AgentRecord handles whitespace-only version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentRecordWhitespaceVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithWhitespaceVersion();
|
||||
ProjectsAgentRecord agentRecord = this.CreateTestAgentRecordWithWhitespaceVersion();
|
||||
AgentRecord agentRecord = this.CreateTestAgentRecordWithWhitespaceVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentRecord);
|
||||
@@ -1335,14 +1335,14 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that AsAIAgent with ProjectsAgentVersion handles whitespace-only version by using "latest" as fallback.
|
||||
/// Verify that AsAIAgent with AgentVersion handles whitespace-only version by using "latest" as fallback.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentVersionWhitespaceVersion_CreatesAgentWithGeneratedId()
|
||||
{
|
||||
// Arrange
|
||||
AIProjectClient client = this.CreateTestAgentClientWithWhitespaceVersion();
|
||||
ProjectsAgentVersion agentVersion = this.CreateTestAgentVersionWithWhitespaceVersion();
|
||||
AgentVersion agentVersion = this.CreateTestAgentVersionWithWhitespaceVersion();
|
||||
|
||||
// Act
|
||||
var agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1364,11 +1364,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public void AsAIAgent_WithServerHostedTools_AddsToolsToAgentOptions()
|
||||
{
|
||||
// Arrange
|
||||
DeclarativeAgentDefinition definition = new("test-model") { Instructions = "Test" };
|
||||
PromptAgentDefinition definition = new("test-model") { Instructions = "Test" };
|
||||
definition.Tools.Add(new HostedWebSearchTool().GetService<ResponseTool>() ?? new HostedWebSearchTool().AsOpenAIResponseTool());
|
||||
|
||||
AIProjectClient client = this.CreateTestAgentClient();
|
||||
ProjectsAgentVersion agentVersion = ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson(agentDefinition: definition)))!;
|
||||
AgentVersion agentVersion = ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson(agentDefinition: definition)))!;
|
||||
|
||||
// Act - no tools provided, but requireInvocableTools is false when no tools param is passed
|
||||
FoundryAgent agent = client.AsAIAgent(agentVersion);
|
||||
@@ -1385,7 +1385,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with fake behavior.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse);
|
||||
}
|
||||
@@ -1395,7 +1395,7 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// Used for tests that exercise the protocol-method code path (CreateAgentVersion).
|
||||
/// The returned client must be disposed to clean up the underlying HttpClient/handler.
|
||||
/// </summary>
|
||||
private static DisposableTestClient CreateTestAgentClientWithHandler(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
private static DisposableTestClient CreateTestAgentClientWithHandler(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
var responseJson = TestDataUtil.GetAgentVersionResponseJson(agentName, agentDefinitionResponse, instructions, description);
|
||||
|
||||
@@ -1439,59 +1439,59 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentRecord for testing.
|
||||
/// Creates a test AgentRecord for testing.
|
||||
/// </summary>
|
||||
private ProjectsAgentRecord CreateTestAgentRecord(ProjectsAgentDefinition? agentDefinition = null)
|
||||
private AgentRecord CreateTestAgentRecord(AgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJson(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJson(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with empty version fields for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClientWithEmptyVersion(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClientWithEmptyVersion(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse, useEmptyVersion: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentRecord with empty version for testing hosted MCP agents.
|
||||
/// Creates a test AgentRecord with empty version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private ProjectsAgentRecord CreateTestAgentRecordWithEmptyVersion(ProjectsAgentDefinition? agentDefinition = null)
|
||||
private AgentRecord CreateTestAgentRecordWithEmptyVersion(AgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithEmptyVersion(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithEmptyVersion(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentVersion with empty version for testing hosted MCP agents.
|
||||
/// Creates a test AgentVersion with empty version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private ProjectsAgentVersion CreateTestAgentVersionWithEmptyVersion()
|
||||
private AgentVersion CreateTestAgentVersionWithEmptyVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithEmptyVersion()))!;
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithEmptyVersion()))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test AIProjectClient with whitespace-only version fields for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private FakeAgentClient CreateTestAgentClientWithWhitespaceVersion(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null)
|
||||
private FakeAgentClient CreateTestAgentClientWithWhitespaceVersion(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null)
|
||||
{
|
||||
return new FakeAgentClient(agentName, instructions, description, agentDefinitionResponse, versionMode: VersionMode.Whitespace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentRecord with whitespace-only version for testing hosted MCP agents.
|
||||
/// Creates a test AgentRecord with whitespace-only version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private ProjectsAgentRecord CreateTestAgentRecordWithWhitespaceVersion(ProjectsAgentDefinition? agentDefinition = null)
|
||||
private AgentRecord CreateTestAgentRecordWithWhitespaceVersion(AgentDefinition? agentDefinition = null)
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithWhitespaceVersion(agentDefinition: agentDefinition)))!;
|
||||
return ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(TestDataUtil.GetAgentResponseJsonWithWhitespaceVersion(agentDefinition: agentDefinition)))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentVersion with whitespace-only version for testing hosted MCP agents.
|
||||
/// Creates a test AgentVersion with whitespace-only version for testing hosted MCP agents.
|
||||
/// </summary>
|
||||
private ProjectsAgentVersion CreateTestAgentVersionWithWhitespaceVersion()
|
||||
private AgentVersion CreateTestAgentVersionWithWhitespaceVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithWhitespaceVersion()))!;
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJsonWithWhitespaceVersion()))!;
|
||||
}
|
||||
|
||||
private const string OpenAPISpec = """
|
||||
@@ -1525,11 +1525,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a test ProjectsAgentVersion for testing.
|
||||
/// Creates a test AgentVersion for testing.
|
||||
/// </summary>
|
||||
private ProjectsAgentVersion CreateTestAgentVersion()
|
||||
private AgentVersion CreateTestAgentVersion()
|
||||
{
|
||||
return ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson()))!;
|
||||
return ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(TestDataUtil.GetAgentVersionResponseJson()))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1547,11 +1547,11 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
/// </summary>
|
||||
private sealed class FakeAgentClient : AIProjectClient
|
||||
{
|
||||
public FakeAgentClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null, bool useEmptyVersion = false, VersionMode versionMode = VersionMode.Normal)
|
||||
public FakeAgentClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null, bool useEmptyVersion = false, VersionMode versionMode = VersionMode.Normal)
|
||||
{
|
||||
// Handle backward compatibility with bool parameter
|
||||
var effectiveVersionMode = useEmptyVersion ? VersionMode.Empty : versionMode;
|
||||
this.AgentAdministrationClient = new FakeAgentsClient(agentName, instructions, description, agentDefinitionResponse, effectiveVersionMode);
|
||||
this.Agents = new FakeAgentsClient(agentName, instructions, description, agentDefinitionResponse, effectiveVersionMode);
|
||||
}
|
||||
|
||||
public override ClientConnection GetConnection(string connectionId)
|
||||
@@ -1559,17 +1559,17 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
return new ClientConnection("fake-connection-id", "http://localhost", ClientPipeline.Create(), CredentialKind.None);
|
||||
}
|
||||
|
||||
public override AgentAdministrationClient AgentAdministrationClient { get; }
|
||||
public override AgentsClient Agents { get; }
|
||||
|
||||
private sealed class FakeAgentsClient : AgentAdministrationClient
|
||||
private sealed class FakeAgentsClient : AgentsClient
|
||||
{
|
||||
private readonly string? _agentName;
|
||||
private readonly string? _instructions;
|
||||
private readonly string? _description;
|
||||
private readonly ProjectsAgentDefinition? _agentDefinition;
|
||||
private readonly AgentDefinition? _agentDefinition;
|
||||
private readonly VersionMode _versionMode;
|
||||
|
||||
public FakeAgentsClient(string? agentName = null, string? instructions = null, string? description = null, ProjectsAgentDefinition? agentDefinitionResponse = null, VersionMode versionMode = VersionMode.Normal)
|
||||
public FakeAgentsClient(string? agentName = null, string? instructions = null, string? description = null, AgentDefinition? agentDefinitionResponse = null, VersionMode versionMode = VersionMode.Normal)
|
||||
{
|
||||
this._agentName = agentName;
|
||||
this._instructions = instructions;
|
||||
@@ -1601,44 +1601,44 @@ public sealed class AzureAIProjectChatClientExtensionsTests
|
||||
public override ClientResult GetAgent(string agentName, RequestOptions options)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson)));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson)));
|
||||
}
|
||||
|
||||
public override ClientResult<ProjectsAgentRecord> GetAgent(string agentName, CancellationToken cancellationToken = default)
|
||||
public override ClientResult<AgentRecord> GetAgent(string agentName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
}
|
||||
|
||||
public override Task<ClientResult> GetAgentAsync(string agentName, RequestOptions options)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return Task.FromResult<ClientResult>(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson))));
|
||||
return Task.FromResult<ClientResult>(ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200, BinaryData.FromString(responseJson))));
|
||||
}
|
||||
|
||||
public override Task<ClientResult<ProjectsAgentRecord>> GetAgentAsync(string agentName, CancellationToken cancellationToken = default)
|
||||
public override Task<ClientResult<AgentRecord>> GetAgentAsync(string agentName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentResponseJson();
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<AgentRecord>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
}
|
||||
|
||||
public override ClientResult<ProjectsAgentVersion> CreateAgentVersion(string agentName, ProjectsAgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
public override ClientResult<AgentVersion> CreateAgentVersion(string agentName, AgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentVersionResponseJson();
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
return ClientResult.FromValue(ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200));
|
||||
}
|
||||
|
||||
public override Task<ClientResult<ProjectsAgentVersion>> CreateAgentVersionAsync(string agentName, ProjectsAgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
public override Task<ClientResult<AgentVersion>> CreateAgentVersionAsync(string agentName, AgentVersionCreationOptions? options = null, string? foundryFeatures = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var responseJson = this.GetAgentVersionResponseJson();
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<ProjectsAgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
return Task.FromResult(ClientResult.FromValue(ModelReaderWriter.Read<AgentVersion>(BinaryData.FromString(responseJson))!, new MockPipelineResponse(200)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static DeclarativeAgentDefinition GeneratePromptDefinitionResponse(DeclarativeAgentDefinition inputDefinition, List<AITool>? tools)
|
||||
private static PromptAgentDefinition GeneratePromptDefinitionResponse(PromptAgentDefinition inputDefinition, List<AITool>? tools)
|
||||
{
|
||||
var definitionResponse = new DeclarativeAgentDefinition(inputDefinition.Model) { Instructions = inputDefinition.Instructions };
|
||||
var definitionResponse = new PromptAgentDefinition(inputDefinition.Model) { Instructions = inputDefinition.Instructions };
|
||||
if (tools is not null)
|
||||
{
|
||||
foreach (var tool in tools)
|
||||
|
||||
@@ -29,7 +29,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -42,7 +42,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -55,7 +55,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with empty version and ID fields for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJsonWithEmptyVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJsonWithEmptyVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -71,7 +71,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with empty version and ID fields in the latest version for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJsonWithEmptyVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJsonWithEmptyVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -87,7 +87,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent version response JSON with whitespace-only version and ID fields for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentVersionResponseJsonWithWhitespaceVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentVersionResponseJsonWithWhitespaceVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentVersionResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -103,7 +103,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the agent response JSON with whitespace-only version and ID fields in the latest version for testing hosted agents like MCP agents.
|
||||
/// </summary>
|
||||
public static string GetAgentResponseJsonWithWhitespaceVersion(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetAgentResponseJsonWithWhitespaceVersion(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_agentResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -119,7 +119,7 @@ internal static class TestDataUtil
|
||||
/// <summary>
|
||||
/// Gets the OpenAI default response JSON with optional placeholder replacements applied.
|
||||
/// </summary>
|
||||
public static string GetOpenAIDefaultResponseJson(string? agentName = null, ProjectsAgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
public static string GetOpenAIDefaultResponseJson(string? agentName = null, AgentDefinition? agentDefinition = null, string? instructions = null, string? description = null)
|
||||
{
|
||||
var json = s_openAIDefaultResponseJson;
|
||||
json = ApplyAgentName(json, agentName);
|
||||
@@ -138,7 +138,7 @@ internal static class TestDataUtil
|
||||
return json;
|
||||
}
|
||||
|
||||
private static string ApplyAgentDefinition(string json, ProjectsAgentDefinition? definition)
|
||||
private static string ApplyAgentDefinition(string json, AgentDefinition? definition)
|
||||
{
|
||||
return (definition is not null)
|
||||
? json.Replace(AgentDefinitionPlaceholder, ModelReaderWriter.Write(definition).ToString())
|
||||
|
||||
+1013
File diff suppressed because it is too large
Load Diff
@@ -1,382 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Agents.AI.UnitTests.AgentSkills;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="AgentClassSkill"/> and <see cref="AgentInMemorySkillsSource"/>.
|
||||
/// </summary>
|
||||
public sealed class AgentClassSkillTests
|
||||
{
|
||||
[Fact]
|
||||
public void Resources_DefaultsToNull_WhenNotOverridden()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new MinimalClassSkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Null(skill.Resources);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Scripts_DefaultsToNull_WhenNotOverridden()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new MinimalClassSkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Null(skill.Scripts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Resources_ReturnsOverriddenList_WhenOverridden()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new FullClassSkill();
|
||||
|
||||
// Act
|
||||
var resources = skill.Resources;
|
||||
|
||||
// Assert
|
||||
Assert.Single(resources!);
|
||||
Assert.Equal("test-resource", resources![0].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Scripts_ReturnsOverriddenList_WhenOverridden()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new FullClassSkill();
|
||||
|
||||
// Act
|
||||
var scripts = skill.Scripts;
|
||||
|
||||
// Assert
|
||||
Assert.Single(scripts!);
|
||||
Assert.Equal("TestScript", scripts![0].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResourcesAndScripts_CanBeLazyLoaded_AndCached()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new LazyLoadedSkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(0, skill.ResourceCreationCount);
|
||||
Assert.Equal(0, skill.ScriptCreationCount);
|
||||
|
||||
var firstResources = skill.Resources;
|
||||
var firstScripts = skill.Scripts;
|
||||
var secondResources = skill.Resources;
|
||||
var secondScripts = skill.Scripts;
|
||||
|
||||
Assert.Single(firstResources!);
|
||||
Assert.Single(firstScripts!);
|
||||
Assert.Same(firstResources, secondResources);
|
||||
Assert.Same(firstScripts, secondScripts);
|
||||
Assert.Equal(1, skill.ResourceCreationCount);
|
||||
Assert.Equal(1, skill.ScriptCreationCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Name_Content_ReturnClassDefinedValues()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new MinimalClassSkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal("minimal", skill.Frontmatter.Name);
|
||||
Assert.Contains("<instructions>", skill.Content);
|
||||
Assert.Contains("Minimal skill body.", skill.Content);
|
||||
Assert.Contains("</instructions>", skill.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_ReturnsSynthesizedXmlDocument()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new MinimalClassSkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Contains("<name>minimal</name>", skill.Content);
|
||||
Assert.Contains("<description>A minimal skill.</description>", skill.Content);
|
||||
Assert.Contains("<instructions>", skill.Content);
|
||||
Assert.Contains("Minimal skill body.", skill.Content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AgentInMemorySkillsSource_ReturnsAllSkillsAsync()
|
||||
{
|
||||
// Arrange
|
||||
var skills = new AgentClassSkill[] { new MinimalClassSkill(), new FullClassSkill() };
|
||||
var source = new AgentInMemorySkillsSource(skills);
|
||||
|
||||
// Act
|
||||
var result = await source.GetSkillsAsync(CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal("minimal", result[0].Frontmatter.Name);
|
||||
Assert.Equal("full", result[1].Frontmatter.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AgentClassSkill_InvalidFrontmatter_ThrowsArgumentException()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentException>(() => new AgentSkillFrontmatter("INVALID-NAME", "An invalid skill."));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkillWithOnlyResources_HasNullScripts()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new ResourceOnlySkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Single(skill.Resources!);
|
||||
Assert.Null(skill.Scripts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkillWithOnlyScripts_HasNullResources()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new ScriptOnlySkill();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Null(skill.Resources);
|
||||
Assert.Single(skill.Scripts!);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_ReturnsCachedInstance_OnRepeatedAccess()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new FullClassSkill();
|
||||
|
||||
// Act
|
||||
var first = skill.Content;
|
||||
var second = skill.Content;
|
||||
|
||||
// Assert
|
||||
Assert.Same(first, second);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_IncludesParametersSchema_WhenScriptsHaveParameters()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new FullClassSkill();
|
||||
|
||||
// Act
|
||||
var content = skill.Content;
|
||||
|
||||
// Assert — scripts with typed parameters should have their schema included
|
||||
Assert.Contains("parameters_schema", content);
|
||||
Assert.Contains("value", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_IncludesDerivedResources_WhenResourcesUseBaseTypeOverrides()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new DerivedResourceSkill();
|
||||
|
||||
// Act
|
||||
var content = skill.Content;
|
||||
|
||||
// Assert
|
||||
Assert.Contains("<resources>", content);
|
||||
Assert.Contains("custom-resource", content);
|
||||
Assert.Contains("Custom resource description.", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_IncludesDerivedScripts_WhenScriptsUseBaseTypeOverrides()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new DerivedScriptSkill();
|
||||
|
||||
// Act
|
||||
var content = skill.Content;
|
||||
|
||||
// Assert
|
||||
Assert.Contains("<scripts>", content);
|
||||
Assert.Contains("custom-script", content);
|
||||
Assert.Contains("Custom script description.", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Content_OmitsParametersSchema_WhenDerivedScriptDoesNotProvideOne()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new DerivedScriptSkill();
|
||||
|
||||
// Act
|
||||
var content = skill.Content;
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("parameters_schema", content);
|
||||
}
|
||||
|
||||
#region Test skill classes
|
||||
|
||||
private sealed class MinimalClassSkill : AgentClassSkill
|
||||
{
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("minimal", "A minimal skill.");
|
||||
|
||||
protected override string Instructions => "Minimal skill body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => null;
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => null;
|
||||
}
|
||||
|
||||
private sealed class FullClassSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("full", "A full skill with resources and scripts.");
|
||||
|
||||
protected override string Instructions => "Full skill body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
CreateResource("test-resource", "resource content"),
|
||||
];
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
CreateScript("TestScript", TestScript),
|
||||
];
|
||||
|
||||
private static string TestScript(double value) =>
|
||||
JsonSerializer.Serialize(new { result = value * 2 });
|
||||
}
|
||||
|
||||
private sealed class ResourceOnlySkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("resource-only", "Skill with resources only.");
|
||||
|
||||
protected override string Instructions => "Body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
CreateResource("data", "some data"),
|
||||
];
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => null;
|
||||
}
|
||||
|
||||
private sealed class ScriptOnlySkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("script-only", "Skill with scripts only.");
|
||||
|
||||
protected override string Instructions => "Body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => null;
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
CreateScript("ToUpper", (string input) => input.ToUpperInvariant()),
|
||||
];
|
||||
}
|
||||
|
||||
private sealed class DerivedResourceSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("derived-resource", "Skill with a derived resource type.");
|
||||
|
||||
protected override string Instructions => "Body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??=
|
||||
[
|
||||
new CustomResource("custom-resource", "Custom resource description."),
|
||||
];
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => null;
|
||||
}
|
||||
|
||||
private sealed class DerivedScriptSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("derived-script", "Skill with a derived script type.");
|
||||
|
||||
protected override string Instructions => "Body.";
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => null;
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??=
|
||||
[
|
||||
new CustomScript("custom-script", "Custom script description."),
|
||||
];
|
||||
}
|
||||
|
||||
private sealed class LazyLoadedSkill : AgentClassSkill
|
||||
{
|
||||
private IReadOnlyList<AgentSkillResource>? _resources;
|
||||
private IReadOnlyList<AgentSkillScript>? _scripts;
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; } = new("lazy-loaded", "Skill with lazily created resources and scripts.");
|
||||
|
||||
protected override string Instructions => "Body.";
|
||||
|
||||
public int ResourceCreationCount { get; private set; }
|
||||
|
||||
public int ScriptCreationCount { get; private set; }
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => this._resources ??= this.CreateResources();
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => this._scripts ??= this.CreateScripts();
|
||||
|
||||
private IReadOnlyList<AgentSkillResource> CreateResources()
|
||||
{
|
||||
this.ResourceCreationCount++;
|
||||
return [CreateResource("lazy-resource", "resource content")];
|
||||
}
|
||||
|
||||
private IReadOnlyList<AgentSkillScript> CreateScripts()
|
||||
{
|
||||
this.ScriptCreationCount++;
|
||||
return [CreateScript("LazyScript", () => "done")];
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CustomResource : AgentSkillResource
|
||||
{
|
||||
public CustomResource(string name, string? description = null)
|
||||
: base(name, description)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<object?> ReadAsync(IServiceProvider? serviceProvider = null, CancellationToken cancellationToken = default)
|
||||
=> Task.FromResult<object?>("resource-value");
|
||||
}
|
||||
|
||||
private sealed class CustomScript : AgentSkillScript
|
||||
{
|
||||
public CustomScript(string name, string? description = null)
|
||||
: base(name, description)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<object?> RunAsync(AgentSkill skill, Extensions.AI.AIFunctionArguments arguments, CancellationToken cancellationToken = default)
|
||||
=> Task.FromResult<object?>("script-result");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -851,61 +851,6 @@ public sealed class AgentSkillsProviderTests : IDisposable
|
||||
Assert.Contains("First instructions.", content!.ToString()!);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Constructor_ClassSkillsParams_ProvidesSkillsAsync()
|
||||
{
|
||||
// Arrange
|
||||
var skill = new TestClassSkill("class-a", "Class A", "Class instructions.");
|
||||
var provider = new AgentSkillsProvider(skill);
|
||||
var invokingContext = new AIContextProvider.InvokingContext(this._agent, session: null, new AIContext());
|
||||
|
||||
// Act
|
||||
var result = await provider.InvokingAsync(invokingContext, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.Instructions);
|
||||
Assert.Contains("class-a", result.Instructions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Constructor_ClassSkillsEnumerable_ProvidesSkillsAsync()
|
||||
{
|
||||
// Arrange
|
||||
var skills = new List<AgentClassSkill>
|
||||
{
|
||||
new TestClassSkill("enum-class-a", "Class A", "Instructions A."),
|
||||
new TestClassSkill("enum-class-b", "Class B", "Instructions B."),
|
||||
};
|
||||
var provider = new AgentSkillsProvider(skills);
|
||||
var invokingContext = new AIContextProvider.InvokingContext(this._agent, session: null, new AIContext());
|
||||
|
||||
// Act
|
||||
var result = await provider.InvokingAsync(invokingContext, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.Instructions);
|
||||
Assert.Contains("enum-class-a", result.Instructions);
|
||||
Assert.Contains("enum-class-b", result.Instructions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Constructor_ClassSkills_DeduplicatesAsync()
|
||||
{
|
||||
// Arrange — two class skills with the same name
|
||||
var skill1 = new TestClassSkill("dup-class", "First", "First instructions.");
|
||||
var skill2 = new TestClassSkill("dup-class", "Second", "Second instructions.");
|
||||
var provider = new AgentSkillsProvider(skill1, skill2);
|
||||
var invokingContext = new AIContextProvider.InvokingContext(this._agent, session: null, new AIContext());
|
||||
|
||||
// Act
|
||||
var result = await provider.InvokingAsync(invokingContext, CancellationToken.None);
|
||||
var loadSkillTool = result.Tools!.First(t => t.Name == "load_skill") as AIFunction;
|
||||
var content = await loadSkillTool!.InvokeAsync(new AIFunctionArguments(new Dictionary<string, object?> { ["skillName"] = "dup-class" }));
|
||||
|
||||
// Assert — only first occurrence survives
|
||||
Assert.Contains("First instructions.", content!.ToString()!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A test skill source that counts how many times <see cref="GetSkillsAsync"/> is called.
|
||||
/// </summary>
|
||||
@@ -927,23 +872,4 @@ public sealed class AgentSkillsProviderTests : IDisposable
|
||||
return Task.FromResult(this._skills);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TestClassSkill : AgentClassSkill
|
||||
{
|
||||
private readonly string _instructions;
|
||||
|
||||
public TestClassSkill(string name, string description, string instructions)
|
||||
{
|
||||
this.Frontmatter = new AgentSkillFrontmatter(name, description);
|
||||
this._instructions = instructions;
|
||||
}
|
||||
|
||||
public override AgentSkillFrontmatter Frontmatter { get; }
|
||||
|
||||
protected override string Instructions => this._instructions;
|
||||
|
||||
public override IReadOnlyList<AgentSkillResource>? Resources => null;
|
||||
|
||||
public override IReadOnlyList<AgentSkillScript>? Scripts => null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,13 +35,13 @@ internal abstract class AgentProvider(IConfiguration configuration)
|
||||
{
|
||||
Uri foundryEndpoint = new(this.GetSetting(TestSettings.AzureAIProjectEndpoint));
|
||||
|
||||
await foreach (ProjectsAgentVersion agent in this.CreateAgentsAsync(foundryEndpoint))
|
||||
await foreach (AgentVersion agent in this.CreateAgentsAsync(foundryEndpoint))
|
||||
{
|
||||
Console.WriteLine($"Created agent: {agent.Name}:{agent.Version}");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint);
|
||||
protected abstract IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint);
|
||||
|
||||
protected string GetSetting(string settingName) =>
|
||||
configuration[settingName] ??
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class FunctionToolAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
MenuPlugin menuPlugin = new();
|
||||
AIFunction[] functions =
|
||||
@@ -33,9 +33,9 @@ internal sealed class FunctionToolAgentProvider(IConfiguration configuration) :
|
||||
agentDescription: "Provides information about the restaurant menu");
|
||||
}
|
||||
|
||||
private DeclarativeAgentDefinition DefineMenuAgent(AIFunction[] functions)
|
||||
private PromptAgentDefinition DefineMenuAgent(AIFunction[] functions)
|
||||
{
|
||||
DeclarativeAgentDefinition agentDefinition =
|
||||
PromptAgentDefinition agentDefinition =
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+5
-5
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class MarketingAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -35,7 +35,7 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
agentDescription: "Editor agent for Marketing workflow");
|
||||
}
|
||||
|
||||
private DeclarativeAgentDefinition DefineAnalystAgent() =>
|
||||
private PromptAgentDefinition DefineAnalystAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -47,13 +47,13 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
""",
|
||||
Tools =
|
||||
{
|
||||
//ProjectsAgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
//AgentTool.CreateBingGroundingTool( // TODO: Use Bing Grounding when available
|
||||
// new BingGroundingSearchToolParameters(
|
||||
// [new BingGroundingSearchConfiguration(this.GetSetting(Settings.FoundryGroundingTool))]))
|
||||
}
|
||||
};
|
||||
|
||||
private DeclarativeAgentDefinition DefineWriterAgent() =>
|
||||
private PromptAgentDefinition DefineWriterAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -64,7 +64,7 @@ internal sealed class MarketingAgentProvider(IConfiguration configuration) : Age
|
||||
"""
|
||||
};
|
||||
|
||||
private DeclarativeAgentDefinition DefineEditorAgent() =>
|
||||
private PromptAgentDefinition DefineEditorAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests.Agents;
|
||||
|
||||
internal sealed class MathChatAgentProvider(IConfiguration configuration) : AgentProvider(configuration)
|
||||
{
|
||||
protected override async IAsyncEnumerable<ProjectsAgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
protected override async IAsyncEnumerable<AgentVersion> CreateAgentsAsync(Uri foundryEndpoint)
|
||||
{
|
||||
AIProjectClient aiProjectClient = new(foundryEndpoint, TestAzureCliCredentials.CreateAzureCliCredential());
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed class MathChatAgentProvider(IConfiguration configuration) : Agen
|
||||
agentDescription: "Teacher agent for MathChat workflow");
|
||||
}
|
||||
|
||||
private DeclarativeAgentDefinition DefineStudentAgent() =>
|
||||
private PromptAgentDefinition DefineStudentAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
@@ -41,7 +41,7 @@ internal sealed class MathChatAgentProvider(IConfiguration configuration) : Agen
|
||||
"""
|
||||
};
|
||||
|
||||
private DeclarativeAgentDefinition DefineTeacherAgent() =>
|
||||
private PromptAgentDefinition DefineTeacherAgent() =>
|
||||
new(this.GetSetting(TestSettings.AzureAIModelDeploymentName))
|
||||
{
|
||||
Instructions =
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user